Uygulama geliştirirken bazen işler istediğimiz gibi gitmez ve bu durumda favori versiyon kontrol sistemine güveniriz. Yaptığımız değişiklikleri geri almamız ya da eski revizyonları kontrol etmemiz gerekebilir.

Aklıma gelen muhtemel panik senaryoları ve kendimizi nasıl kurtarabileceğimize bakalım..

Başlangıç olarak:

git init
touch davet.md
git add davet.md
git commit -m "İlk commit"
git log --oneline
8d123a1 İlk commit

Şeklinde commit tarihimizi başlatalım.

Yanlış dosyayı git add ile ekledim ne yapmalıyım?

git add komutu yerel repomuzdaki değişiklikleri, sıradaki commit‘e eklemek üzere staging dediğimiz indekse yüklemek için kullanılır.

touch ceviz.md
git add .

Ups. ceviz.md dosyasını staging‘e ekledik ama -eklememiz- gerekiyordu.

Panik Yok!

Çözümü çok basit.

git reset HEAD ceviz.md

İşte bu kadar. Artık dosyamız git status ile kontrol ettiğimizde orada olmayacak.

En son commit’i nasıl geri alırım?

Aşağıdaki gibi commit eklediğimizi varsayarsak?

git add .
git commit -m "Ceviz Ekle"
git log --oneline
ce17f4d Ceviz ekle
8d123a1 İlk commit

Aslında git ile commit geri almanın zilyon tane yolu var. En basitlerinden bazılarını açıklayalım.

git revert

git revert HEAD

Bunu yaptığınız da editörünüz açılacak ve sizden bir commit mesajı girmenizi isteyecektir. Ve en son committe yaptığımız değişikleri geri alan yeni bir commit oluşturacaktır.

Tabi ki bu yöntemin avantajları olduğu gibi dezavantajları da olacaktır. En önemli avantajı son derece güvenli olması yan etkilerinin kolaylıkla geri alınabilmesidir.

Neler olduğuna şöyle bir göz atarsak:

git log --oneline
e5f4c85 Revert "Ceviz ekle"
ce17f4d Ceviz ekle
8d123a1 İlk commit

Çıktıdan anladığımız kadarıyla revert komutu, aslında gerçek anlamda geri alma işlemi yapmıyor, aksine bir commitin etkilerini geri alan yeni bir commit oluşturuyor.

Burada dikkat etmemiz gereken can alıcı nokta; git revert ile commit tarihi değişmedi ve aynen duruyor. Bu yaklaşım public olmuş branch’lar için başka kullanıcıların değişikliklerini yıkmamak adına ve proje tarihini takip edebilmek için oldukça mantıklı. Ancak lokal bir branch’ta çalışıyorsanız ve değişiklikleriniz henüz başkalarıyla paylaşılmamışsa aynı dosyalarla ilgili değişiklikleri içeren ekstra bir commit oldukça mantıksız olacaktır.

git reset

git reset, revert’e göre daha tehkileli bir yöntem. reset ile yaptığınız bazı işlemleri geri alamayabilirsiz.

Şimdi senaryomuza geri dönelim ve lokal branchta çalışırken revert’in oluşturduğu ekstra committen duyduğumuz memnuniyetsizlikle son commit’i geri alalım.

git reset HEAD~1
ce17f4d Ceviz ekle
8d123a1 İlk commit

Gördüğünüz gibi revert komutunun oluşturduğu commit ve etkileri gitti. HEAD~1 diyerek kafayı bir commit geri çekmiş olduk, git reset HEAD~2 deseydik doğrudan İlk Commit’e gelmiş olurduk. git status ile kontrol edersek revert commitinin yaptığı değişikliğin staging’e eklenmemiş olduğunu görürüz. Bu durum aslında git reset komutunun default davranışı ile alakalı bir durum.

git reflog komutu ile çıktıyı kontrol edin. Göreceksiniz ki git, yaptığımız her hareketi kayıt almış. Çalışma dizinimizi HEAD@{n} şeklinde ifade edilen konumlara resetleyebiliriz. bunun için e5f4 ile başlayan git revert işlemini yaptığımız kısma dönelim.

git reset HEAD@{1}
git log --oneline
e5f4c85 Revert "Ceviz ekle"
ce17f4d Ceviz ekle
8d123a1 İlk commit

Şimdi git reset kısmını farklı türlü denemek için git reset HEAD~1 yapmadan önceki konumumuza geri döndük. git reset komutunu farklı bir parametre ile deneyelim.

git reset --hard HEAD~1
git log --oneline
ce17f4d Ceviz ekle
8d123a1 İlk commit

Ve git status komutunu daha önce verdiğimizde ceviz.md dosyasının silinmek üzere staging’de beklediğini görmüştük. Şimdi tekrar kontrol ettiğimizde staging temiz ve ceviz.md olması gerektiği gibi dizinimizde duruyor ama daha önce stagingdeki değişikler uçmuş. Peki ne değişti?

git reset‘in farklı çalışma modları vardır ve bu modlardan ön tanımlı olan –mixed modunu ilk reset işleminde mod parametresi belirlemeyerek test etmiş olduk. Daha sonra ise –hard parametresini de ekleyerek tekrar denedik aradaki farkı anlamaya çalıştık. git help reset ile diğer modları kontrol ettiğimizde –mixed, –hard, –soft, –keep ve –merge olmak üzere 5 adet olduklarını görürüz. Bunlardan ilk üçünü daha sıklıkla kullanıldığı için açıklamaya çalışacağım.

  • –mixed, git reset –mixed HEAD~1 : git reset komutunun öntanımlı davranışıdır ve geri aldığımızda değişikler staging’e otomatik eklenmemiştir. git status komutu ile dosyaların eklenmek üzere olduklarını görürüz.

  • –soft, git reset –soft HEAD~1 : –mixed moduna çok benzer aradaki fark, değişiklikleri git status ile kontrol ettiğimizde, staginge eklendiklerini ve commit etmek için beklediklerini görürüz.

  • –hard, git reset –hard HEAD~1 : Bu modun denemesini beraber yapmıştık. Değişikler stagingde değil doğru kaybolmuş olurlar.

NOT: Public olmuş branchlarda reset kullanmayın. Aksine revert kullanmayı tercih edin.

Eyvah! commit mesajını yanlış girdim

Bu çok olur. Saçma bir imla hatası ya da anlam kayması her ne sebepten olursa olsun commit mesajını yenilemek gerekebilir.

git commit --amend

Bu sayede commit mesajlarını düzenlediğiniz editör açılır ve siz commit mesajının yeni halini tekrar yayınlarsınız.

Tek satırda halledebilmek için -m parametresini eklemek.

git commit --amend -m "Ceviz eklendi"
git status
719c938 Ceviz eklendi
8d123a1 İlk commit

Gördüğünüz commit kodu değişmiş. Bu da demek oluyor ki commit tarihine müdahale etmişiz. Commit tarihini değiştiren bir komut olduğu için paylaşılan branchlarda commit –amend kullanmayın.

Ben bu commit’e başka bir dosya daha ekleyecektim!

Panik yapmanın alemi yok. Olur böyle şeyler. :) –amend komutu en son commit’te değişiklikler yapmamızı sağlıyordu. Yine yardımcı olabilir.

touch foo.md
touch bar.md
git add foo.md
git commit -m "foo ve bar ekle"
git status

İyi de foo ve bar ekledik ama sadece foo ekledik bar olduğu gibi duruyor.

git add bar.md
git commit --amend --no-edit
git status

Görüldüğü üzere –no-edit ekleyerek commit mesajına dokunmadan eksik kalan dosyayı da ekleyerek son commit güncellendi.

Gerilerde öyle bir commit var resmen yüz karası. Derhal kurtulmalıyım!

git ile tarihi baştan yazabileceğiniz çok önemli bir yardımcıya kavuşursunuz. O yardımcının adı rebase. –interactive veya kısaca -i parametresi ekleyerek geçmişe gidebilir, commit birleştirebilir, bölebilir, silebilir hatta yer değiştirebilirsiniz.

Diyelim ki foo ve bar’ın projede yeri olmadığına ve tamamen gitmeleri gerektiğine karar verdiniz.

git rebase -i HEAD~3
pick 719c938 Ceviz eklendi
pick e1317b5 foo ve bar ekle 
pick ba51761 Ceviz başlık eklendi

Açılan editöre bir takım ayarlar yapmalıyız. foo ve barı kaldıracağız ve ceviz dosyasını oluşturmak ve başlık eklemek için ayrı commitler olması da anlamsız. Şimdi düzenleyerek aşağıdaki hale getirelim:

pick 719c938 Ceviz eklendi
squash ba51761 Ceviz başlık eklendi

Commit mesajının ne olacağını sorduğunda “Ceviz eklendi” olanı seçiyoruz yani diğerini # ile yorum satırı yapıyoruz.

git log --oneline

Açıkçası bayağı bir temizlik olmuş gibi :)

549826e Ceviz eklendi
8d123a1 İlk commit
cat ceviz.md

ekranda “ceviz” çıktısını aldıysak herşey istediğimiz gitmiş başlık eklediğimiz commit ceviz oluşturduğumuz commit ile birleşmiş demektir.

Çok sıkıntılı işlem yaptım geçmişe dönmem gerek

Git, bizim için yaptığımız işlemlere referans kaydı tutuyor. Yukarıda revert komutunu geri alırken kullandığımız gibi. git reflog ile HEAD@{n} ‘i takiben yapılan işlemle de ilgili açıklamalar. Tarihten bu kesitlere istediğiniz gibi ışınlanabilirsiniz tek yapmanız gereken git reset HEAD@{n} ile istediğiniz noktaya gidebiliriz.

Örneğin:

git reset HEAD@{1}

En temel panik yönetimi yöntemlerinden bahsetmiş olduk. Başka bir yazıda görüşmek üzere.

NOT: Hata bulursanız ya da eklemek istediğiniz birşeyler olursa yorum bırakmayı unutmayın.

Görüşmek üzere…