- Git’te bir hatanın adını bilmiyorsanız çözümü aramak zor olduğundan, yaygın kurtarma senaryolarına göre komutları hızlıca bulup kullanmaya yarayan bir kaynak
- Depoyu ciddi biçimde bozduğunuzda ya da silme/birleştirme hatalarını geri almak istediğinizde
git reflog ile işlem geçmişini bulup git reset HEAD@{index} ile önceki duruma dönebilirsiniz
- Son commit’teki küçük düzeltmeleri veya mesaj değişikliğini
git commit --amend ile hızlıca yapın; ancak bunu zaten açık/paylaşılan bir branch’e push edilmiş commit’lerde kullanmayın
- Yanlış branch’e commit yaptıysanız değişikliği
reset, stash, checkout, stash pop akışıyla veya cherry-pick ile taşıyabilirsiniz; ancak güvenli yöntem push edilip edilmediğine göre değişir
- Uzak depo durumuna zorla dönmek için kullanılan
reset --hard ve git clean -d --force, izlenmeyen dosyaları da silebileceğinden çalıştırmadan önce kontrol etmek gerekir
Git hatalarını kurtarmanın zor olmasının nedeni
- Git’te hata yapmak kolaydır ve sorunu düzeltmek için çoğu zaman arama yapabilmek adına gerekli kavramın adını zaten bilmeniz gerekir
- Bu kaynak, Git’te sık yaşanan kötü durumları sade İngilizce ve komut örnekleriyle derler
- Eksiksiz bir referans değildir; aynı işi yapmanın başka yolları da olabilir
Depoyu geçmiş bir duruma döndürmek
- Depoyu ciddi biçimde bozduysanız veya sildiğiniz içeriği geri getirmek istiyorsanız işlem geçmişini görmek için
git reflog kullanın
git reflog
# Tüm branch’lerdeki Git işlemlerinin listesini görebilirsiniz
# Her öğe HEAD@{index} biçiminde bir indekse sahiptir
git reset HEAD@{index}
reflog şu durumlarda kullanılabilir
- Yanlışlıkla silinen içeriği kurtarma
- Depoyu bozan denemeleri kaldırma
- Kötü bir merge sonrası kurtarma
- Gerçekten çalıştığı ana geri dönme
Son commit’i düzeltme yolu
- Son commit’in hemen ardından küçük bir düzeltme eklemeniz gerekiyorsa
git commit --amend --no-edit kullanın
# Değişiklikten sonra
git add . # veya tek tek dosya ekleyin
git commit --amend --no-edit
- Bu komut yeni değişikliği son commit’e dahil eder
- Aynı işi yeni bir commit oluşturup
rebase -i ile birleştirerek de yapabilirsiniz, ancak amend çok daha hızlıdır
- Zaten açık/paylaşılan bir branch’e push edilmiş commit’lerde
amend kullanmamalısınız
- Yalnızca son commit mesajını değiştirmek için şu komutu kullanın
git commit --amend
# Yönergeleri izleyerek commit mesajını değiştirin
Yanlış branch’e commit yaptığınızda
- Yanlışlıkla
master’a commit yaptıysanız ama bunun yeni bir branch’te olması gerekiyorsa, mevcut durumdan yeni bir branch oluşturup master’ın son commit’ini kaldırın
git branch some-new-branch-name
git reset HEAD~ --hard
git checkout some-new-branch-name
- Bu yöntem, zaten açık/paylaşılan bir branch’e push edilmiş commit’ler için uygun değildir
- Önce başka denemeler yaptıysanız
HEAD~ yerine HEAD@{number-of-commits-back} biçimini kullanmanız gerekebilir
- Tamamen yanlış branch’e commit yaptıysanız
reset --soft, stash, checkout, stash pop akışıyla taşıyabilirsiniz
git reset HEAD~ --soft
git stash
git checkout name-of-the-correct-branch
git stash pop
git add . # veya tek tek dosya ekleyin
git commit -m "your message here"
- Aynı durumda
cherry-pick kullanmanın bir yolu da vardır
git checkout name-of-the-correct-branch
git cherry-pick master
git checkout master
git reset HEAD~ --hard
Değişiklikleri ve eski commit’leri geri almak
- Bir dosyayı değiştirdiyseniz ama
git diff boş görünüyorsa değişikliği zaten staging’e almış olabilirsiniz; bu durumda --staged bayrağı gerekir
git diff --staged
- Birkaç commit önceki değişikliği geri almak için
git log ile hash’i bulun ve git revert çalıştırın
git log
git revert [saved hash]
git revert, ilgili commit’i geri alan yeni bir commit oluşturur
- Tüm commit’i değil yalnızca belirli bir dosyayı geri almak için dosyanın eski sürümünü indekse alıp commit etme akışını kullanın
git log
git checkout [saved hash] -- path/to/file
git commit -m "Wow, you don't have to copy-paste to undo"
Uzak depo durumuna zorla dönmek
- Depoyu silip yeniden clone etmek yerine, uzak depo durumuyla eşitleyen Git komutlarını kullanabilirsiniz
git fetch origin
git checkout master
git reset --hard origin/master
git clean -d --force
git reset --hard origin/master, branch’i uzak master durumuna getirir
git clean -d --force, izlenmeyen dosya ve dizinleri siler
- Bozulmuş her branch için
checkout, reset, clean işlemlerini tekrarlamanız gerekir
- Bu işlemler yıkıcıdır ve geri alınamaz; bu yüzden çalıştırmadan önce dikkatli olun
Kapsam ve katkı
- Bu kaynak eksiksiz bir Git referansı değil, deneme yanılmayla bulunan pratik kurtarma prosedürleri derlemesidir
- Çeviri eklemeye yardımcı olmak istiyorsanız GitHub’a PR gönderebilirsiniz
1 yorum
Hacker News görüşleri
Değiştirmek istediğim birkaç nokta var: her zaman
git checkoutyerinegit switchkullanır vereset --hardkullanımından mümkün olduğunca kaçınırdımÖrneğin “yeni branch'te olması gereken commit'i yanlışlıkla master'a attıysanız”, bunu
git branch some-new-branch-name,git switch -d HEAD~,git switch -C master,git switch some-new-branch-namesırasıyla halledebilirsiniz“Yanlış branch'e commit attıysanız”, önce doğru branch'e
git switchyapıp ardındangit cherry-pick master,git switch -d master~,git switch -C masterile çözerdim“Her şeyi bırakıp uzak depo durumuna geri dönmek” için de
git fetch origin,git restore -WS .,git clean -d --force,git switch -d origin/master,git switch -C mastergibi bir akış kurardımGit modelini iyi anlasanız bile bu tarifler sezgisel değil ve her komutun kendine özgü tuhaf davranışlarını da bilmeniz gerekiyor
Örneğin
git switch -c some-new-branch-namezaten var, ama sadece branch'i başka bir commit'e taşıyangit move-branch master HEAD~gibi bir komut daha sezgisel olurdugit checkoutyerinegit switchvegit restorekullanılmasına karşı çıkmaya çalışmıyorum, ancak bu komutlar Git v2.23 ile geldi ve o sürüm yaklaşık 5 yıl önce çıktıYardım sayfasında hâlâ
THIS COMMAND IS EXPERIMENTAL. THE BEHAVIOR MAY CHANGE.uyarısı yer alıyorElbette bu uyarı komutların çıktığı neredeyse ilk günden beri vardı ve 5 yıl sonra artık buna deneysel dememek gerekir gibi görünüyor
Yine de
git checkoutgeriye dönük uyumluluk açısından daha iyi ve bu web sitesinin ilk yapıldığı dönemin Git kullanımını yansıttığı da söylenebilirhttps://github.com/git/git/blob/757161efcca150a9a96b312d9e78...
https://github.com/git/git/releases/tag/v2.23.0
https://github.com/git/git/commit/4e43b7ff1ea4b6f16b93a432b6...
git add .öğretmek pek iyi değilBelirli dosyaları açıkça eklemeyi öğretmek, sonradan “eyvah” deme ihtimalini azaltır
switch'incheckout'tan neden daha iyi olduğunu ve nedenreset --hardkullanmamak gerektiğini bilmek isterimreset --hardtan kaçının” ifadesinin ne anlama geldiğini anlayamıyorumPratikte neden yeterli olmadığını gerçekten merak ediyorum; ben bunu
alias git-restore-file='git restore --source=HEAD --'ile birlikte epey sık kullanıyorum ve iyi çalışıyor gibi görünüyorGit öğrenirken varsayılan yol olarak GUI istemcileri önermeye başlamalıyız
Böylece bu sorunların üçte biri çözülür, bir başka üçte biri de en baştan hiç ortaya çıkmaz
Daha sonra komut satırının daha hızlı olduğuna karar verirlerse o zaman kullanırlar; ama önce insanların ağaçla nasıl etkileşime girdiğini görsel olarak görmesi gerekiyor
Ben şahsen fork.dev'i seviyorum, ama bugünlerde istemcilerin çoğu aşağı yukarı benzer
Magit kullanınca “cherry-pick'i iptal et” gibi işlemler arayüz içinde keşfedilebilir oluyor ve diğer “X'i iptal et” işlemleriyle aynı kısayolu kullanıyor
Yalnızca Git komut satırını kullanmak zorunda olsaydım nereden başlayacağım hakkında hiçbir fikrim olmazdı
Etkileşimli rebase sırasında silmemem gereken commit'leri sildiğim de oldu, ama her rebase başlangıç noktasında reflog üzerinden erişilebilen bir anlık görüntü oluştuğu için hatalı bir rebase'i geri almak güvenli oluyor
Magit'in reflog arayüzü log arayüzüyle aynı olduğu için ilk kez gördüğümde bile kaybolmadım; ama Git CLI olsaydı ne olduğunu anlamamam çok olasıydı
jjkomutunu parametresiz çalıştırınca commit ağacının ilgili bölümünü ve şu an nerede olduğunuzu göstermesi hoşuma gidiyorO an üzerinde çalıştığınız commit'i, bağlı branch'leri ve geçmişi, depodaki diğer aktif branch'leri, her commit'in mesajını ve değişiklik durumunu tek bakışta görebiliyorsunuz; bu da yönünüzü yeniden bulmak için harika
Ama neredeyse kimse dinlemiyor; sonra CLI'da sürünüyor, branch'leri bozuyor, main'in gerisinde kalıyor ve rebase'den korkar hale geliyorlar
UI'de sürükle-bırak ya da benzeri yollarla çözülebilecek pek çok şeyi, adeta bir tür kendine eziyet gibi, komut satırında yapmaya çalışıyorlar
Arayüz ne kadar kötü olursa olsun, ekipteki diğer insanların kullandığı arayüzün aynısını kullanmak iletişim açısından daha kolaydı; ayrıca internetteki sorun giderme kaynakları da çoğunlukla “standart yöntem”i varsaydığından daha işe yarıyordu
Nisan 2025'te Git'in 20. yılı olacak olması kulağa oldukça tuhaf geliyor
O dönemde işin içindeydim ve SVN ya da CVS'nin yerine git, darcs, bazaar arasından hangisini öğrenmem gerektiğini düşündüğümü hatırlıyorum
Mercurial'i de denedim mi bilmiyorum
“GitHub etkisi”nin sürüm kontrol sistemi alanında yeni oyunculara duyulan ihtiyacı fiilen öldürüp öldürmediğini merak ediyorum
Belki de bir noktada yeterince yak tıraşı yapılmıştır
Tamamen jj'ye geçtim ve Git uyumluluğu olduğu için başkalarının da birlikte geçmesini beklemem gerekmiyor
GitHub'ın çeşitli yönleri beni giderek daha fazla hayal kırıklığına uğratıyor; bir gün herkesin onu da aşmasını umuyorum, ama o tarafa giden yolun o kadar basit olduğu pek söylenemez
SVN sezgisel ve vakaların %99'unda yeterince iyi çalışıyor, bu yüzden insanlara ayrıca “öğretmek” gerekmiyor
Hepimiz 1337 hacker taklidi yapmayı bırakıp Git'in çoğu insan için gereğinden fazla bir araç olduğunu kabul etsek keşke
Git'in ne yaptığına dair zihinsel modelimin oldukça iyi olduğunu düşünüyorum, ama komut biraz karmaşıklaşınca argümanları hatırlayamıyorum
Komutlar ne keşfedilebilir ne de ezberlemesi kolay
Sorun metin tabanlı arayüzün kötü olması mı, yoksa ağaçları manipüle etmeyi metinle anlatmanın kendisinin zor olması mı bilmiyorum
Karmaşık ağaçları metinle manipüle etmek kolay değil ve metin tabanlı arayüz de nesnel olarak kötü: https://stevelosh.com/blog/2013/04/git-koans/
Bu başlıkta hg ve Mercurial arama sonuçlarını görmek hoşuma gitti
Mercurial'in dağıtık sürüm kontrol savaşını kaybetmiş olmasına hâlâ inanamıyorum; bence daha iyi araçtı
Kullanılabilir, kararlı, sahada kendini kanıtlamış ve aktif olarak destekleniyor
“Görmek istediğin değişim ol” anlayışına yakın, o yüzden sadece kullanmak yeterli
Kaybetti gibi ifadeler ters etki yaratıyor ve bu sözlerin taşıdığı örtük caydırıcılık Mercurial benimsenmesini düşük tutuyor
Barındırma en azından Sourcehut ve heptapod.host üzerinde mümkün
Ben de kişisel bir Heptapod instance'ı işletiyorum; Gitlab fork'una Mercurial için doğrudan destek eklenmiş hali ve gayet iyi çalışıyor
Git, birçok açıdan sezgiyi takip etmediği için kafama tam oturmayan teknolojilerden biri oldu
Uzun süredir kullanmıyorsanız, neredeyse her işlem için Google'a bakmanız ya da man sayfasını açmanız gerekebilir
Özellikle büyük bir kod tabanını SVN'de çok sayıda branch ile yönetip sonra yeniden birleştirme kabusunu yaşadıysanız, Git'in bu konuda inanılmaz derecede daha iyi olduğunu görüyorsunuz
Git'e en baştan başlayan biri için öğrenme eğrisi çok daha dik olabilir, ama insanların tam olarak nerede takıldığını anlamak yine de bazen zor geliyor
Yerleşik yöntem olan
filter-branchkullanılırsa uzun bir gecikmenin ardından Control+C'ye basıpfilter-repoadlı üçüncü taraf bir Python betiğini indirmenizi söyleyen bir uyarı çıkıyorGurur duymuyorum ama en sık başvurduğum “mahvettim” Git çözümü, yerel depoyu silip yeniden clone etmek ve sonra değişiklikleri tekrar uygulamak
Vakaların %95'inde harika çalışıyor, geri kalanında ise DevOps sorumlusundan yardım istiyorum
cp -R .git ../git-backupgibi bir şey yapıyorumÇünkü çok kötü bozarsam tüm
.gitdizinini eski kopyayla değiştirebiliyorumBu, belirli bir işlemi ya da işlem grubunu doğru şekilde geri almanın yolunu bulmaya çalışmaktan çok daha hızlı
İnsanların Git hakkında gerçekten içselleştirmesini istediğim şey, Git'in yalnızca eklemeli bir veri deposu olduğudur
Çalışmanızı depoya koymak için commit etmeniz yeterlidir ve bir kez içeri girdikten sonra bu çalışmayı Git komutlarıyla kaldıramazsınız
reflog da bu ilkeye göre çalışır
Ne yaparsanız yapın, önceki branch durumuna dönüp veri deposundaki çalışmayı geri getirebilirsiniz
Ama commit etmezseniz Git yardımcı olamaz, o yüzden sadece commit etmek gerekir
Her zaman commit edin; bu size fazla yük geliyorsa ya da sürekli unutuyorsanız, aracı düzeltmeniz gerekir
Bütün gün kod yazıyorsanız genel olarak en az saatte bir kez commit etmelisiniz
Küçük bir şey ama
git refloggördüğüm her seferinde bana re-flog gibi görünüyorBelki de bu yüzden bu komutu doğru düzgün ezberleyemiyorum; bilinçaltımda bunu “reference log” olarak düşünmüyor gibiyim
Onun yerine, sanki Git'e bir şeyi yeniden ucuza satmasını söylüyormuşum gibi geliyor
Git kullanıcısı değilim ama böyle şeyleri görünce
git commitişleminin kendi başına pek bir anlamı olmadığını, asıl önemli olanın commit’in push edildiği veya merge edildiği an olduğunu daha güçlü düşünüyorumBu, metin dosyası kaydetmeye benziyor
Bir dosyayı her kaydettiğimizde kısa bir mesaj yazmadığımız için, bunu da öyle geçebiliriz
Kısa değil; değişiklik ne kadar küçükse açıklama bazen o kadar uzun olur
Etkisi büyük olan 2-3 satırlık bir değişiklik için 2-3 paragraf yazdığım da oldu
Yerel commit, her şeyin derlendiği ve çalıştığı noktada bir kontrol noktası oluşturma yöntemidir
Böylece değişiklikleri stash edebilir veya bir şeyi bozduğunda çalışan duruma geri dönebilirsin
Push etmeden önce
resetile bunları uygun commit’lere bölersen uzak geçmiş temiz kalır ve birwipyığınına dönüşmezYa da PR’ı squash merge ederek iki tarafın avantajını da elde edebilirsin
Yine de
more fixesgibi anlamsız mesajlar girmeye gerek yokGenelde
(WIP) özellik adıgibi bir ilk commit oluşturup memnun kalana kadar commit’i sürekli amend eder, sonra da en sonda mesajdan(WIP)ifadesini kaldırırımGit revision log’unu da buna benzer bir günlük olarak görüyorum
Ayrı bir TODO belgesinden daha düzenlidir ve zaten yapılmış işi okunması kolay bir biçimde anlatmaya teşvik eder
Ne kadar geri alınacağına karar verirken o zamanki commit’te ne düşündüğünü bilmek faydalı olabilir; yaklaşım yanlışsa sonradan yapılan analiz için de yardımcı olur
Merge veya push edilmemiş işler hedefi olan ayrı değişiklikler halinde düzenlenmişse, bunların bir kısmı iyi bir kısmı kötüyken iyi olan bölümleri korumak çok daha kolay olur
Yine de teknik olarak commit’ler anlamsız değildir
Commit yoksa push veya merge edilecek bir şey de yoktur
Teknik olmayan açıdan da neden bir şeyi değiştirdiğini düz metinle kaydetmek çok faydalıdır
Böyle açıklamaları fazla sık yazmak zorunda kalıyorsan, “değişiklik” birimini daha küçük tutmalı ya da aynı anda dokunduğun işleri daha seçici belirlemelisin
Git kullanmıyorsan sürüm kontrolünü ve değişiklik yönetimini neyle yaptığını merak ediyorum