git checkout, switch ve restore: ne zaman hangisi?
git checkout iki farklı iş yapar: branch değiştirir ve dosyaları geri yükler. Bu yüzden Git 2.23 ile görevleri git switch (branch) ve git restore (dosyalar) komutlarına ayrıldı. Branch değiştirmek için git switch adı, commit edilmemiş bir dosya değişikliğini geri almak için git restore dosya kullanın; checkout'u eski betikler ve alışkanlıklar için bırakın.
git checkout neden iki farklı işi yapıyor
git checkout tarihsel olarak iki temelde farklı işlem yapar. Bir branch adıyla kullanıldığında HEAD'i değiştirir ve çalışma dizinini günceller. Bir dosya yoluyla kullanıldığında ise dosyanın sürümünü index'ten ya da bir commit'ten alır ve yaptığınız değişiklikleri sessizce üzerine yazar. Aynı komut bir yandan branch'ler arasında güvenle geçiş yaparken, bir yandan da kaydedilmemiş işinizi geri dönüşü olmadan silebilir.
Bu yüzden Git 2.23 sürümünde iki ayrı komut eklendi: branch'ler için git switch, dosyalar için git restore. Checkout kaldırılmadı, tamamen çalışır durumda; ama yeni kodda, dokümantasyonda ve Git'in kendi ipuçlarında switch ve restore kullanılıyor. Yeni öğreniyorsanız bunlarla başlayın; yine de checkout'u bilmeniz gerekir, çünkü talimatlarda, betiklerde ve mülakatlarda karşınıza çıkar.
Komutların karşılığı
| Görev | git checkout | Yeni komut |
|---|---|---|
| Bir branch'e geçmek | git checkout main | git switch main |
| Branch oluşturup geçmek | git checkout -b feature | git switch -c feature |
| Branch'i oluşturmak veya sıfırlamak | git checkout -B feature | git switch -C feature |
| Önceki branch'e dönmek | git checkout - | git switch - |
| Bir commit'e geçmek (detached HEAD) | git checkout 3f2a1c9 | git switch --detach 3f2a1c9 |
| Dosyadaki değişiklikleri geri almak | git checkout -- app.js | git restore app.js |
| Dosyayı index'ten çıkarmak | git reset HEAD app.js | git restore --staged app.js |
| Dosyayı başka bir branch'ten veya commit'ten almak | git checkout main -- app.js | git restore --source=main --staged --worktree app.js |
| Klasördeki tüm değişiklikleri geri almak | git checkout -- . | git restore . |
Checkout komutlarındaki -- işaretine dikkat edin. Bu, «bundan sonra gelenler yol (path) adıdır» anlamına gelen ayırıcıdır. Dosya ile branch aynı adı taşıdığında belirsizliği önler. Restore'da böyle bir sorun yoktur, çünkü komut yalnızca dosyalarla çalışır.
Branch'ler için git checkout
git checkout feature/login # geçiş yap
git checkout -b feature/login # mevcut commit'ten oluştur ve geç
git checkout -b hotfix origin/main # uzak branch'ten oluştur
git checkout -t origin/feature/x # uzak branch'i izleyen yerel branch
Yerelde branch yoksa ama sunucuda aynı adda bir branch varsa, git checkout feature/x (tıpkı git switch feature/x gibi) yerel branch'i kendisi oluşturur ve izlemeyi ayarlar. Bunun için önce git fetch gerekir; aksi halde Git yeni uzak branch'ten haberdar olmaz.
Branch değiştirmek kaydedilmemiş değişiklikleri kaybettirmez: bunlar, diğer branch ile çakışmadıkça yeni branch'e taşınır. Çakışma varsa Git işlemi reddeder ve değişikliklerinizi commit etmenizi ya da git stash ile saklamanızı önerir. -f (--force) bayrağı yerel değişiklikleri atarak branch'i değiştirir; bu artık tehlikeli bir işlemdir.
git switch: yalnızca branch'ler
Switch, checkout'un branch kısmını daha katı kurallarla yeniden yapar. Asıl fark şudur: açıkça --detach yazmadan bir commit'e ya da etikete geçmez. git switch v1.0 komutu, fark edilmeden detached HEAD durumuna düşmek yerine hata verir; bu yüzden yanlışlıkla branch dışına çıkmak zorlaşır.
git switch main
git switch -c feature/cart
git switch -c feature/cart origin/main
git switch --detach v1.0
git switch - # önceki branch
git switch -m main # değişiklikleri üçlü birleştirmeyle taşı
git restore: dosyalar için geri alma düğmesi
Restore, dosyaları kaydedilmiş bir duruma döndürür ve commit geçmişine hiç dokunmaz. Onu güvenle kullanmak için Git'in üç alanını hatırlamanız gerekir: çalışma dizini (editörde gördükleriniz), index (git add ile hazırlananlar) ve commit'ler.
git add öncesi dosyadaki değişikliği geri almak
git restore app.js # index'teki sürümü geri yükle
git restore src/ # klasördeki tüm dosyalar
git restore . # projedeki tüm değiştirilmiş dosyalar
Bayrak olmadan restore, çalışma dizinini index'ten geri yükler. Dosya son commit'ten sonra index'e eklenmediyse, bu son commit'teki sürümle aynıdır. Değişiklikler iz bırakmadan kaybolur ve geri dönüşüm kutusuna düşmez; bu yüzden git restore . komutundan önce git diff ile bakın.
git add sonrası dosyayı index'ten çıkarmak
git restore --staged app.js
Dosya commit için hazırlanmış olmaktan çıkar, ama içindeki değişiklikleriniz yerinde kalır. Bu, restore'un en güvenli biçimidir: hiçbir şey kaybolmaz. git status çıktısındaki «Changes to be committed» bölümü de tam olarak bu komutu önerir.
Hem index'te hem dosyada her şeyi geri almak
git restore --staged --worktree app.js
# kısa biçim
git restore -SW app.js
Dosyayı başka bir commit'ten veya branch'ten geri getirmek
git restore --source=HEAD~2 app.js # iki commit öncesi sürüm
git restore --source=main config.yml # main branch'indeki sürüm
git restore --source=3f2a1c9 -- docs/ # bir commit'teki tüm klasör
Varsayılan olarak --source ile yalnızca çalışma dizini değişir. Değişikliği aynı anda commit için hazırlamak istiyorsanız --staged ekleyin. Eski yöntem olan git checkout main -- app.js her zaman hem index'i hem çalışma dizinini değiştirir.
Silinmiş bir dosyayı geri yüklemek
git restore deleted.txt # silindi ama commit edilmedi
git restore --source=HEAD~1 deleted.txt # silme zaten commit edildi
Dosyanın hangi commit'te silindiğini bilmiyorsanız bulun: git log --oneline -- deleted.txt. Listenin en üstündeki commit dosyanın silindiği yerdir; dosyayı onun bir önceki commit'inden geri almanız gerekir: git restore --source=<hash>~1 deleted.txt.
restore, reset ve revert: karıştırmayın
Üç komutun da «geri alma» işlevi var, ama farklı derinliklerde çalışırlar:
- restore — çalışma dizinindeki ve index'teki dosyalarla çalışır, geçmişi değiştirmez. Ekip için güvenlidir.
- reset — branch işaretçisini geriye taşır ve geçmişi yeniden yazar.
--softdeğişiklikleri index'te bırakır,--mixed(varsayılan) çalışma dizinine taşır,--hardise onları siler. Ortak branch'lerde zaten gönderilmiş commit'ler için tehlikelidir. - revert — belirtilen commit'in tersini içeren yeni bir commit oluşturur. Geçmiş yeniden yazılmaz; bu yüzden sunucuda olan bir commit'i geri almanın doğru yoludur.
Basit bir kural: değişiklik henüz commit edilmediyse restore; commit yalnızca sizin yerelinizdeyse reset; commit zaten ekip arkadaşlarınızdaysa revert.
checkout sonrası detached HEAD
git checkout 3f2a1c9 ya da git checkout v1.0 komutundan sonra «You are in 'detached HEAD' state» uyarısının uzun metnini görürsünüz. HEAD artık bir branch'i değil, bir commit'i gösterir. Eski bir sürüme bakmak ya da o sürümde testleri çalıştırmak için bu kullanışlıdır.
Bu durumda commit yapabilirsiniz, ama yeni commit'ler hiçbir branch'e bağlanmaz. Bir şey değiştirdiyseniz ve kaydetmek istiyorsanız:
git switch -c fix-for-v1
Sadece bakıp geçtiyseniz geri dönün: git switch - ya da git switch main. Branch oluşturmayı unutup ayrıldıysanız commit'ler git reflog ile hâlâ erişilebilirdir: hash'i bulun ve git branch rescue <hash> komutunu çalıştırın.
Tipik hatalar
error: pathspec 'feature' did not match any file(s) known to git
Git bu adda ne bir branch ne de bir dosya buldu. Genellikle branch yalnızca sunucudadır ve git fetch yapılmamıştır. git fetch çalıştırıp tekrar deneyin. Yazımı da kontrol edin: branch adları büyük/küçük harfe duyarlıdır.
checkout -- veya restore ile değişiklikleri yanlışlıkla attım
Index'e hiç eklenmemiş, commit edilmemiş değişiklikleri Git saklamaz ve Git araçlarıyla geri getirmek mümkün değildir. Geriye editörünüzün ya da IDE'nizin yerel geçmişi kalır. Dosya git add ile eklenmişse içeriği nesne veritabanında «sahipsiz» bir nesne olarak durur ve git fsck --lost-found ile bulunabilir.
Aynı adı taşıyan dosya ve branch
test adında bir branch ve bir test klasörü varken git checkout test belirsizlik uyarısı verir. Branch için git switch test, dosyalar için git restore test (ya da git checkout -- test) kullanın.
Günlük çalışma senaryoları
Sık karşılaşılan durumlar ve her biri için doğru komut:
- Bir dosyayı düzenlemeye başladınız ve yanlış yola girdiğinizi fark ettiniz —
git restore dosya. - Commit'ten önce yanlışlıkla fazla dosyayı index'e eklediniz —
git restore --staged dosya. - Çalışmanın ortasında acilen başka bir göreve geçmeniz gerekiyor —
git stash, sonragit switch branch; dönüncegit switch -vegit stash pop. - Yan branch'teki bir dosyayı, branch'in tamamını birleştirmeden almak istiyorsunuz —
git restore --source=feature/x --staged --worktree yol. - Bu hatanın eski sürümde de olup olmadığını kontrol etmek istiyorsunuz —
git switch --detach v1.0, kontrol, sonragit switch -. - Bir dosyadaki değişikliklerin yalnızca bir kısmını geri almak istiyorsunuz —
git restore -p dosya: Git her parçayı gösterir ve geri alınıp alınmayacağını sorar.
Etkileşimli -p (--patch) modu özellikle kullanışlıdır: hem checkout'ta hem restore'da vardır ve aynı dosyada faydalı değişiklikleri koruyup hata ayıklama çıktısını atmanızı sağlar.
Geri almadan önce sonucu kontrol edin
Yol belirterek kullanılan restore ve checkout, değişiklikleri onay istemeden siler; bu yüzden önce neyin kaybolacağına bakmak iyi bir alışkanlıktır. git diff çalışma dizinindeki değişiklikleri index'e göre, git diff --staged commit için hazırlananları, git diff main -- app.js ise dosyanın başka bir branch'teki sürümden farkını gösterir. Emin değilseniz mevcut durumu git stash ile saklayın: restore'un aksine, değişiklikleri her zaman oradan geri getirebilirsiniz.
Kısaca
git checkout branch değiştirmeyi ve dosyaları geri yüklemeyi tek komutta birleştirir; tehlikeli olan da budur. Branch'ler için git switch, dosyalar için git restore kullanın: biri yalnızca HEAD'in konumunu, diğeri yalnızca dosya içeriklerini değiştirir. Branch'ler, restore, reset ve revert'in doğru ve yanlış kullanım senaryoları, Git kursunda uygulamalı olarak ele alınmaktadır.
Sık sorulan sorular
git checkout eskimiş mi?
Hayır, kullanımdan kaldırılmış ilan edilmedi ve çalışmaya devam edecek. Günlük iş için daha dar ve güvenli olan git switch ve git restore önerilir.
switch ve restore hangi Git sürümünden beri var?
Her iki komut da Git 2.23 sürümüyle (2019) geldi. Sürümünüzü git --version ile kontrol edebilirsiniz.
git restore ile yapılan geri almayı geri alabilir miyim?
Çalışma dizini geri yüklendiyse atılan değişiklikleri Git saklamadığı için geri getirilemez. git restore --staged güvenlidir: değişiklikler dosyada kalır, git add ile yeniden hazırlayabilirsiniz.
Ekip arkadaşımın branch'ine nasıl geçerim?
Önce git fetch, sonra git switch branch-adi çalıştırın. Git, origin/branch-adi ile bağlı yerel bir branch oluşturur.
git checkout . ile git reset --hard arasındaki fark nedir?
git checkout . (ya da git restore .) değiştirilmiş dosyaları index'teki sürüme döndürür, index'e ve geçmişe dokunmaz. git reset --hard ise hem index'i hem çalışma dizinini bir commit'e sıfırlar ve commit belirtilmişse branch'i de taşır.
Bu konu “Sıfırdan Güvenilir Geliştiriciye Git” kursunda uygulamalı olarak ayrıntılı işleniyor.
- Dallar: Kodunuzun Paralel Gerçekliği
- Hataları Geri Alıyoruz: restore, reset, revert — Doğru ve Tehlikeli Kullanımları