Karşılaştırma

git fetch ve git pull: farkı nedir ve hangisini seçmeli?

Güncellendi: · Skillaria.Top

git fetch yalnızca sunucudaki yeni commit'leri indirir ve origin/main gibi uzak branch referanslarını günceller; dosyalarınıza ve yerel branch'lerinize dokunmaz. git pull aynısını yapar ve ardından indirilenleri merge ya da rebase ile mevcut branch'inize hemen ekler. Fetch her zaman güvenlidir; pull ise başkalarının değişikliklerini hemen kabul etmeye hazır olduğunuzda kullanışlıdır.

Kısa cevap

git fetch, sunucudaki yeni commit'leri indirir ve uzak branch referanslarını (origin/main, origin/feature-x) günceller; ama ne mevcut branch'inize ne de çalışma dizinindeki dosyalarınıza dokunur. git pull ise bir git fetch ve ardından indirilenleri mevcut branch'e hemen katmak demektir: varsayılan olarak merge ile, isterseniz rebase ile.

Bundan pratik bir kural çıkar: fetch'i istediğiniz zaman çalıştırabilirsiniz, hiçbir şeyi bozmaz. Pull ise branch'inizi değiştirir ve çakışmayla sonuçlanabilir; bu yüzden çalışma dizininiz temizken ve neyin geleceğini bilerek çalıştırın.

Uzak branch'ler nerede duruyor

Farkı netleştirmek için yerel depoda iki tür branch olduğunu bilmek gerekir. Yerel branch'ler — main, feature-x — kendi commit'lerinizle ilerler. Uzak izleme branch'leri — origin/main — ise «son senkronizasyon anında sunucunun durumu» işaretleridir. Bunları elle taşıyamazsınız; yalnızca sunucuyla iletişim (fetch, pull ve push) günceller.

git branch -a
* main
  remotes/origin/HEAD -> origin/main
  remotes/origin/main
  remotes/origin/feature-x

git status, branch'inizi canlı sunucuyla değil, origin/main işaretiyle karşılaştırır. Bu yüzden «Your branch is up to date with 'origin/main'» mesajı yanıltıcı olabilir: uzun süredir fetch yapmadıysanız Git, ekip arkadaşlarınızın yeni commit'lerinden habersizdir.

git fetch ne yapar

$ git fetch
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
Unpacking objects: 100% (4/4), done.
From github.com:team/project
   3f2a1c9..8b7d4e2  main       -> origin/main

Son satır esas bilgiyi verir: origin/main işaretçisi 3f2a1c9'dan 8b7d4e2'ye ilerledi. Sizin main'iniz yerinde duruyor. Artık gelenlere sakince bakabilirsiniz:

git status                       # Your branch is behind 'origin/main' by 2 commits
git log main..origin/main --oneline   # sizde olmayan commit'ler
git diff main origin/main        # dosyalarda ne değişecek

Fetch'in kullanışlı seçenekleri:

  • git fetch --all — tüm remote'lardan değişiklik al (bir fork'ta hem origin hem upstream varsa önemli);
  • git fetch --prune (-p) — sunucuda artık bulunmayan uzak branch işaretlerini yerelden sil;
  • git fetch origin main — yalnızca tek bir branch'i al;
  • git fetch --tags — ek olarak tüm etiketleri de al.

Budamanın (prune) her zaman çalışmasını istiyorsanız bir kez açın: git config --global fetch.prune true.

git pull ne yapar

git pull arka arkaya iki adım çalıştırır. Önce mevcut branch'in upstream'i için fetch yapar, sonra origin/<branch> ile sizin branch'inizi birleştirir. Kelimesi kelimesine bu şuna eşdeğerdir:

git fetch origin
git merge origin/main      # ya da pull --rebase ise git rebase origin/main

Birleştirmenin sonucu geçmişlerin nasıl ayrıldığına bağlıdır:

  • Sizin yeni commit'iniz yoksa — fast-forward olur, branch yalnızca ileri sarılır;
  • Hem sizde hem sunucuda yeni commit'ler varsa — merge'de bir birleştirme commit'i oluşur, rebase'de sizin commit'leriniz sunucudakilerin üzerine yeniden yazılır;
  • Aynı satırlar iki tarafta da değiştiyse — elle çözmeniz gereken çakışma çıkar.

git fetch ve git pull karşılaştırması

git fetchgit pull
Commit'leri indirirEvetEvet
origin/* referanslarını güncellerEvetEvet
Mevcut branch'i değiştirirHayırEvet
Çalışma dizinindeki dosyaları değiştirirHayırEvet
Çakışma yaratabilirHayırEvet
Temiz çalışma dizini gerektirirHayırTercihen evet
Diğer branch'leri etkilerTüm izlenen uzak işaretleri güncellerYalnızca mevcut branch'e birleştirir
Ne zaman kullanılırNeyin değiştiğine bakmak; rebase öncesi; betiklerdeKendi branch'inizi hızlıca sunucuya yetiştirmek için

git pull: merge mi, rebase mi

Git 2.27 ile birlikte, geçmişler ayrıldığında ve bir ayar yapılmamışsa pull bir uyarı verir; yeni sürümlerde ise sessizce merge yapmak yerine «Need to specify how to reconcile divergent branches» hatasıyla durur. Git sizden stratejiyi bir kez seçmenizi ister:

git config --global pull.rebase false   # merge (eski varsayılan davranış)
git config --global pull.rebase true    # rebase
git config --global pull.ff only        # yalnızca fast-forward, yoksa hata

Merge geçmişi olduğu gibi korur ve «Merge branch 'main' of github.com:...» biçiminde bir birleştirme commit'i ekler. Her gün yerel commit'lerle olan bir branch'e pull yaparsanız geçmiş bu teknik birleştirmelerle dolar.

Rebase, göndermediğiniz commit'lerinizi sunucudakilerin üzerine yeniden uygular. Geçmiş doğrusal kalır ve çakışmalar commit commit çözülür. Yayımlanmamış yerel commit'ler için genellikle en iyi seçimdir. Rebase yalnızca başkalarının üzerine iş kurduğu, zaten gönderilmiş commit'ler için tehlikelidir.

ff only en katı moddur: pull yalnızca kendi commit'iniz yoksa çalışır. Geçmişler ayrıldıysa ne yapacağınıza siz açıkça karar verirsiniz. Birçok deneyimli geliştirici ana branch'ler için tam bunu kullanır.

Çalışma dizininizde commit edilmemiş değişiklikler varken pull'a hemen ihtiyacınız varsa git pull --rebase --autostash işinizi görür: Git değişiklikleri saklar, rebase yapar ve sonra geri getirir.

Tipik senaryo: önce fetch, bak, sonra birleştir

«Önce fetch» yaklaşımı, branch'inize neyin gireceği üzerinde kontrol sağlar. Özellikle pull request göndermeden önce ve uzun bir aradan sonra işe yarar.

git fetch
git log --oneline --graph HEAD origin/main   # branch'ler nasıl ayrılmış
git rebase origin/main                       # ya da git merge origin/main
git push

Bir başka sık durum, feature branch'inizi başka bir branch'e geçmeden güncel main ile yenilemektir:

git switch feature-x
git fetch
git rebase origin/main

Burada pull uygun değildir: feature branch'inde git pull, branch'in kendi upstream'ini (origin/feature-x) çeker, ana branch'i değil. git pull --rebase origin main yazmak da mümkündür, ama fetch'li yöntem daha açık ve anlaşılırdır.

Sunucuyla eşitleme: branch'i güncel tutmak

«git sync» denince genellikle «başkalarının işini al, benimkini gönder» döngüsü kastedilir. Saf Git'te ayrı bir sync komutu yoktur. IDE'lerde ve GUI istemcilerinde «Sync» düğmesi ise içeride pull, sonra push yapar. Elle güvenilir döngü şöyledir:

  1. git status — her şeyin commit edildiğinden ya da git stash ile saklandığından emin olun;
  2. git pull --rebase — değişiklikleri alın ve kendi commit'lerinizi en üste taşıyın;
  3. Varsa çakışmaları çözün: dosyaları düzeltin, git add, git rebase --continue;
  4. Testleri çalıştırın;
  5. git push.

Bir fork'u asıl depoyla eşitlemek için:

git remote add upstream https://github.com/original/project.git
git fetch upstream
git switch main
git merge --ff-only upstream/main
git push origin main

git pull ile sık karşılaşılan sorunlar

Your local changes would be overwritten by merge

Pull, sizin düzenlediğiniz ama commit etmediğiniz dosyaları değiştirmek istiyor. Seçenekler: commit etmek, saklamak (git stash, sonra pull ve git stash pop) ya da --autostash kullanmak. Pull için değişiklikleri silmenize gerek yok.

Pull sonrası çakışma

Git durur ve git status içinde çakışan dosyaları gösterir. Dosyayı açın, <<<<<<< ile >>>>>>> arasında doğru seçimi bırakın, sonra git add ve merge ise git commit, rebase ise git rebase --continue çalıştırın. Vazgeçtiyseniz git merge --abort ya da git rebase --abort pull öncesindeki duruma döndürür.

There is no tracking information for the current branch

Branch'in upstream'i ayarlanmamış ve Git nereden çekeceğini bilmiyor. Açıkça belirtin: git pull origin main; ya da bağlantıyı bir kez kurun: git branch --set-upstream-to=origin/main.

refusing to merge unrelated histories

Yerel ve uzak depolar bağımsız oluşturulmuş, örneğin sunucuda depo oluşturulurken README eklenmiş. Birleştirmek istediğinizden eminseniz: git pull origin main --allow-unrelated-histories.

Hatalı pull'u geri alma

Pull'dan sonra merge tamamlandıysa ve sonuç istediğiniz gibi değilse, branch'i öncesine döndürün: git reset --hard ORIG_HEAD. Komut commit edilmemiş değişiklikleri siler, bu yüzden önce git status'a bakın. Son çare olarak branch'in eski konumu git reflog içinde bulunur.

Hangisini seçmeli

  • Hiçbir şey değiştirmeden neyin yeni olduğunu öğrenmek istiyorsanız — git fetch.
  • Kendi branch'inizde çalışıyor ve sunucuya yetişmek istiyorsanız — git pull --rebase (ya da pull.rebase true ayarlıysa pull).
  • Ana branch'i, kendi commit'iniz olmadan güncelliyorsanız — git pull --ff-only.
  • Feature branch'e main'i katmanız gerekiyorsa — git fetch, ardından git rebase origin/main ya da git merge origin/main.
  • Betik ya da CI yazıyorsanız — fetch ve açık komutlar, pull değil.

Commit grafiğinde bu nasıl görünür

Siz ve bir meslektaşınız C commit'inden başladığınızı düşünün. Siz yerelde D commit'ini yaptınız, meslektaşınız sunucuya E commit'ini gönderdi. git fetch sonrası deponuz iki çizgiyi de bilir: main D'yi, origin/main E'yi gösterir ve ortak atası C'dir.

          D   <- main (HEAD)
         /
A---B---C
         \
          E   <- origin/main

Bundan sonra birleştirme yöntemi belirleyicidir. git merge origin/main, iki ebeveyni olan D ve E ile M birleştirme commit'ini oluşturur. git rebase origin/main, D'yi E'nin üstüne farklı bir hash'li yeni bir D' commit'i olarak kopyalar ve geçmiş düz bir çizgi olur. git pull bu adımları aralarında durmadan otomatik çalıştırır. Asıl değer, ayrı bir fetch ile birleştirmeden önce grafiğe bakabilmenizdedir.

IDE'lerde fetch ve pull

VS Code, IntelliJ IDEA ve diğer editörlerde düğmelerin adları farklı olsa da altında aynı komutlar vardır. «Fetch» — git fetch; «Pull» ya da «Update Project» — ayarlarda seçilen stratejiyle (merge ya da rebase) pull; «Sync Changes» — pull ve ardından push. Ortak bir branch'te Sync düğmesine basmadan önce hangi stratejinin seçili olduğunu bilmek faydalıdır; yoksa geçmişte beklenmedik birleştirme commit'leri görürsünüz. Birçok IDE gelen commit sayacını arka planda fetch ile güncel tutar.

Kısaca

git fetch sunucu hakkındaki bilginizi günceller, git pull ise bu bilgiyi mevcut branch'e uygular. Fetch her an güvenlidir; pull kullanışlıdır ama branch'i değiştirir ve çakışma getirebilir. Bu yüzden stratejinizi bir kez ayarlayın ve çalışma dizinini temiz tutun. Push, pull, fetch ve uzak depolarla çalışma, GitHub ile birlikte Git kursunda uygulamalı olarak anlatılmaktadır.

Sık sorulan sorular

git pull'dan önce git fetch çalıştırmam gerekir mi?

Hayır, pull ilk adım olarak kendisi fetch yapar. Ayrı bir fetch, değişiklikleri önce görüp sonra nasıl birleştireceğinize karar vermek istediğinizde gerekir.

git fetch değişikliklerimi silebilir mi?

Hayır. Fetch yalnızca origin/main gibi uzak referansları değiştirir; yerel branch'lere, indekse ve çalışma dizinine dokunmaz.

git pull tüm branch'leri günceller mi?

Hayır, pull değişiklikleri yalnızca mevcut branch'e katar. Diğer branch'lerin origin/* işaretleri fetch sayesinde güncellenir, ama yerel branch'leriniz yerinde kalır.

git fetch ne sıklıkla yapılmalı?

Çalışmaya başlamadan önce, pull request açmadan önce ve push'tan önce. Birçok IDE fetch'i arka planda otomatik yapar; bu güvenlidir.

FETCH_HEAD nedir?

Fetch'in en son indirdiği commit'i yazdığı geçici bir referanstır. Örneğin git fetch origin main'den sonra git merge FETCH_HEAD çalıştırabilirsiniz.

Bu konuyu videoyla öğrenin

Bu konu “Sıfırdan Güvenilir Geliştiriciye Git” kursunda uygulamalı olarak ayrıntılı işleniyor.

Kursa git