Git SCM’nin çok faydasını görüyoruz, çok kritik anlarda durumu kurtardığına defalarca şahit oldum. Fakat büyük güçle birlikte büyük sorumluluk da gelir. Git aracını kullanırken sorumlu şekilde davranmak ve diğer yazılımcılarla birlikte çalışma sürecine zarar vermemeye dikkat edilmelidir.
1. İsim, soyisim ve email adresi tanımlamalarını yapmamak.
Git kullanmaya başlamadan önce mutlaka kullanıcı bilgilerinin tanımlanması gerekmektedir.
git config --global user.name "Your Name"
git config --global user.email you@example.com
Bu tanımlamalar yapılmadığı durumda Git sistem tanımlamalarına bakarak commit’i yapan kişiyi tanımlamaya çalışır ve bu bilgilerle commit’i yapar. Bu bilgilerde de herhangi bir tutarsızlık var ise hiçbirşeye karışmaz:
git log
commit a2e472f2238f1ae84bf7de5501252f5c8b78ff53
Author: Laptopun sahibi <amiroff@Metins-MacBook-Pro.local>
Date: Sun Nov 24 11:41:40 2013 +0200
Kullanım hatalarına ekleme yapıldı
commit d8bb2f8967b24daba0908f11f0a671de48572bfa
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 11:38:44 2013 +0200
README dosyası eklendi
Fakat Github gibi repo yönetim hizmetlerini kullanıyorsanız, Git’in keşfettiği kullanıcı bilgileri hizmet sağlayıcı üzerindekiler ile eşleşmeyecek, sonucunda ya garip anonim commit’ler göreceksiniz, ya da commit’i yapan kişiye ilişkin gerçek istatistikleri göremeyeceksiniz. Neyse ki son Git sürümlerinde herhangi bir tanımlama yapılmadan commit’e kalkışılırsa alttaki gibi bilgilendirme mesajı çıkmaktadır:
git commit --am "Kullanım hatalarına ekleme yapıldı"
[master a2e472f] Kullanım hatalarına ekleme yapıldı
Committer: Laptopun sahibi <amiroff@Metins-MacBook-Pro.local>
Your name and email address were configured automatically based
on your username and hostname. Please check that they are accurate.
You can suppress this message by setting them explicitly:
git config --global user.name "Your Name"
git config --global user.email you@example.com
After doing this, you may fix the identity used for this commit with:
git commit --amend --reset-author
1 file changed, 2 insertions(+), 1 deletion(-)
2. Aşırı derecede alias tanımlamak.
İtiraf etmeliyim ki, ben de bu hastalıktan muzdariptim. Git komut satırında komutları uzun uzadıya yazmamak için kısa aliaslar belirleyip kullanırız. Fakat çoğu geliştiricinin bilmediği bir kon�gursyon ile verdiğiniz komuta en yakını varsayılan olarak uygulanır. Eğer kısaltma birden fazla komuta denk geliyor ise, herhangi bir aksiyon alınmaz. Bu ayar aynı zamanda komutta ufak bir hata yaptığınızda da sizi kurtarır.
git config --global help.autocorrect 1
Bu ayar sonrasında artık biraz pratikle tek git komutuna denk gelecek harf kısatmalarını kullanabiliriz:
git status
WARNING: You called a Git command named 'stus', which does not exist. Continuing under the assumption that you meant 'status'
in 0.1 seconds automatically...
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: README.md
#
no changes added to commit (use "git add" and/or "git commit -a")
Benzer şekilde:
git cmt -am "Aliasis'in önlenmesi"
WARNING: You called a Git command named 'cmt', which does not exist.
Continuing under the assumption that you meant 'commit' in 0.1 seconds automatically...
[master 392a8bc] Aliasis\'in önlenmesi
1 file changed, 2 insertions(+), 1 deletion(-)
Kesinlikle faydalı, fakat alias’ların yerini tam olarak almadığının altını da çizelim.
3. Master/main branşını feature branşa merge etmek.
Aslında bir antipattern olmamasına rağmen, bu yaklaşımı sevmiyorum. Nedeni de, branş tarihçesini kirletmesidir. Feature, yani özelliği geliştirdiğimiz branşta iken master’ı merge edelim:
git checkout bomba-ozellik
Switched to branch 'bomba-ozellik'
git merge master
Auto-merging README.md
Merge made by the 'recursive' strategy.
README.md | 4 ++--
1 file changed, 2 insertions(+), 2 deletions(-)
Log’a ve geçmişe göz atalım:
git log
commit 9d5e7e5b8ef0239677847ed32af97f36e0988a3c
Merge: bf2dff8 0185e0c
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:24:20 2013 +0200
Merge branch 'master' into bomba-ozellik # Oops!
commit 0185e0cd03045c8a11f1e485b6c418d0f3574989
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:23:56 2013 +0200
Baslık düzenlendi
commit bf2dff814efaf38edb4fcd4951327240cbf8a15b
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:23:31 2013 +0200
Bomba ozellik gelistirildi
Bu commit mesajlarından 1-2 tane olsa neyse, fakat bundan fazlası gerçekten geçmiş incelemesini üçüncü kişiler için çok zorlaştırıyor. Yerine rebase kullanılabilir:
git rebase master
First, rewinding head to replay your work on top of it...
Applying: Bomba ozellik gelistirildi
Using index info to reconstruct a base tree...
M README.md
Falling back to patching base and 3-way merge...
Auto-merging README.md
Şimdi log’a göz atalım:
git log
commit 2822ef3e066ad00b76ec965cc3a85d537742d7b8
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:23:31 2013 +0200
Bomba ozellik gelistirildi # cok daha iyi!
commit 0185e0cd03045c8a11f1e485b6c418d0f3574989
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:23:56 2013 +0200
Baslık düzenlendi
Bu iki farklı yolun kullanımını şu şekilde anlatabiliriz: Evde oyuncaklarınızı yere dökmüş, oynuyorsunuz. Anneniz ise yere halı sermek istiyor. Master merge usülü bodoslama halıyı oyuncakların üzerine sermek gibi olur, etraf karışır. Rebase usülünü izlerseniz ise, önce yerdeki oyuncakların tümünü elinize alırsınız, anneniz halıyı serer, siz de üzerinden oyuncakları geri koyarsınız. Hayat kaldığı yerden devam eder.
Yalnız, rebase kullanımında gözden kaçırılmaması gereken önemli bir husus, git geçmişinin yeniden yazılması, dolayısı ile tüm commit’lerin hash değerlerinin değişeceğidir. Feature branş üzerinde yalnız çalışıyorsanız, hiç sorun değil, normalde hiç önerilmeyen force push ile branşınızı push edebilirsiniz. Fakat, branşın rebase önceki halini başka geliştiriciler de kullanıyor ise, bu yöntem kesinlikle kullanılmamalıdır. Gerçek hayattaki analojiden örnel verirsek, yere oyuncaklar serilmiş şekilde çekilmiş fotonuz ile oyuncakların altında halı varken çekilmiş foto birbirinden tamamen farklı görünümlü ve uyumsuz olacaktır.
Özellikle diğer yazılımcılar ile birlikte aynı branş üzerinde çalışma durumu söz konusu olduğunda da, uzak repodaki branştaki güncellemeleri almak için git pull
yerine git pull --rebase
kullanımı tercih edilmelidir.
4. Rebase edilmemiş, master’daki güncel düzenlemeleri içermeyen branşı code review veya pull request’e göndermek.
Merge işlemi sırasında conflict yaşanması sürüm yönetimini yapan kişinin en nefret ettiği durumdur. Ve çoğu durumda geliştiriciye, rebase edilmek üzere aynen iade edilir. Bu git-gel’leri en aza indirmek için, branşınızın merge’e hazır halinin güncel master’daki güncellemeleri de kapsamasına yukarıda açıklanan yolu izleyerek (tercihen rebase yardımı ile) özen gösteriniz.
5. Net olmayan, bulanık ve eksik commit mesajları.
Commit mesajlarının önemi geçmişi inceleyerek belirli bir commit’i bulmaya çalışırken anlaşılır. Genellikle, zamandan kazanmak için kısa ve net olmayan commit mesajı veririz. Yapmamak lazım. Alttaki iki logu karşılaştırıp, hangisinde bir commit’i bulmanın kolay olacağını veya geliştiricinin ne yapmak istediğini anlamanın daha kolay olduğuna bakalım:
git log
commit c7d9b7d6bdca7c41a60bfe991a087fe5f46f829d
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:53:48 2013 +0200
quickfix
commit 3ebe892bbf2b659a2013c4fd46bf522259ae3a1a
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:53:27 2013 +0200
son ekleme
commit 1a92f42238bf3d35161fd807b8bc500da6a7dd21
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:53:10 2013 +0200
güncelleme
… ve:
git log
commit 3d493ee88f82c5aec8af3f5d8d8f12e79197c4d9
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:59:31 2013 +0200
JIRA-4323 : İşletim sistemine özel gizli dosyaların repoda tutulmaması
MacOS, Windows, Linux altındaki dosya yöneticileri tarafından otoma
tik olarak oluşturulan dosyaların .gitignore\'a eklenerek takip edilme
mesi sağlandı
commit 624c8adb50b9b7f2d1369ca4ed6c106bd7623984
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:58:02 2013 +0200
JIRA - 4322 : Memcache süresinin uzatılması
Anasayfada kullanılan sorguların memcache\'te tutulma süresi x san
iyeden y saniyeye çıkarıldı
commit 8fb6c632ad7c162e9bbe06f6870d381dff2847bd
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 12:55:02 2013 +0200
JIRA-4321 : Formlara CSRF desteğinin eklenmesi
Site üzerindeki tüm veri alımına açık formlar için CSRF koruması
desteği eklendi.
Siz olsanız bu commit mesajlarını gördükten sonra hangi yazılımcıyı işe alırdınız?
6. Yanlışlıkla master/main’a commit etme.
Çok sık yapılan bir hatadır, master’da iken bir özellik geliştirilir, ve başka branşa geçiş yapmadan commit edilir. Daha sonra, tüh, branşa almayı unuttuk deyip geçilir. Halbuki, bunun yaşanmaması için o kadar çok çözüm var ki… Bunlardan ikisini inceleyelim:
a. Henüz master’a commit yapılmamışsa, yeni branş oluşturup, branşa geçiş yapıp commit’i orada gerçekleştirebiliriz:
git status # On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: README.md
#
no changes added to commit (use "git add" and/or "git commit -a")
git checkout -b ozellik M README.md
Switched to a new branch 'ozellik'
git status
# On branch ozellik
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: README.md
#
no changes added to commit (use "git add" and/or "git commit -a")
b. Master’a commit yapılmış ise ve push yapılmamışsa mevcut durumdaki tüm commit’leri kapsayan branş açıp onu push’larız. master’ımızı ise origin’deki (github vs..) ile eşitleştiririz:
git commit -am "Master'a merge etmece"
[master 0814505] Master\'a merge etmece
1 file changed, 1 insertion(+), 1 deletion(-)
git checkout -b yepyeni-brans
Switched to a new branch 'yepyeni-brans'
git log -1
commit 081450545e594e1f79bd946bd61e289827c5ca6c
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:33:24 2013 +0200
Master\'a merge etmece
git push -u origin yepyeni-brans
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 282 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://git@bitbucket.org/amiroff/git-practices.git
* [new branch] yepyeni-brans -> yepyeni-brans
Branch yepyeni-brans set up to track remote branch yepyeni-brans from origin.
git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 1 commit.
(use "git push" to publish your local commits)
git reset --hard origin/master
HEAD is now at 30fb537 JIRA-4323 : İşletim sistemine özel gizli dosya ların repoda tutulmaması
Master’a commit yapılıp push yapıldıysa, maalesef revert
islemi disinda alınabilecek pek bir aksiyon yok.
7. Gereksiz (noise) commitlerle review’a çıkılması.
Sürüm kontrol sistemi kullanımında “Commit early, commit often” felsefesi geçerlidir. Yani, geliştirilecek tüm özellik tamamlanınca tek commit yapmak yerine, özelliğin en ufak bir parçasında gelişme oldukça onu commit ile sabitleme yolu tercih edilmelidir. Bu şekilde geri dönme imkanı ve mevcut ile karşılaştırma noktalarının sayısı çok olacaktır.
Fakat üzerinde bir çok kişinin geliştirme yaptığı ortak branşlarda ve eninde sonunda master’a merge edilecek olan branşlarda commit sayısının fazla olması ve en ince detayların her birisinin birer commit olması commitleri inceleyecekler açısından pek istenen bir durum değildir.
Dolayısıyla code review veya pull request’e göndermeden önce lokal branşınızda mutlaka interactive rebase
yaparak noise niteliğindeki commit’leri esas milestone commitleri ile birleştiriniz. Şimdi noise commitlerle birlikte geçmişimizi doğru dürüst hale getirelim. Interactive rebase öncesi branşımızın olası geçmişi:
git log -5
commit ae1308dabf7fe16004c3e699b732468374b2ab21
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:54:01 2013 +0200
JIRA - 4323 : SQL -> ORM migrasyonu gerçekleştirildi
commit 7764737d68080b6a408b8d1f6812f647e9f18368
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:53:19 2013 +0200
ORM migrasyonu son dokunuşlar
commit 7e97fca525fb610357db88115461caed2961b4fd
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:52:47 2013 +0200
Ooops! Typo.
commit d23ef867459c83084d35bf06e1fc7acca4f8a29b
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:52:24 2013 +0200
ORM todo\'da güncelleme
commit 605e31ba322642c4135f9a85d5c9654f0ac52f05
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:52:01 2013 +0200
ORM migrasyonu todo listesi cikarildi
Yukarıdaki geçmişe baktığımızda diğerleri açısından en az üç noise niteliği taşıyan commit görebiliyoruz. Tüm bu commit’leri branşta yapılanların özeti olarak iki ana commit
, birisi TODO listesinin çıkarılması, diğeri de SQL->ORM migrasyonu şeklinde özetleyebiliriz. Şimdi interaktif rebase ile son 5 commitimizi mantıklı commit’lere ayıralım:
git rebase --interactive HEAD~5
Bu komut sonucunda git özel bir ekran çıkarır, işin interaktivitesi burada. Bu listede tüm commitler sıralanır ve her birisi ile ne yapılacağı konusunda bizden karar vermemiz beklenir. Bu kararların her birinin açıklaması altta yorum olarak da yardım amacıyla gösterilir.
pick 605e31b ORM migrasyonu todo listesi cikarildi
pick d23ef86 ORM todo\'da güncelleme
pick 7e97fca Ooops! Typo.
pick 7764737 ORM migrasyonu son dokunuşlar
pick ae1308d JIRA - 4323 : SQL -> ORM migrasyonu gerçekleştirildi
# Rebase 30fb537..ae1308d onto 30fb537
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#
# Note that empty commits are commented out
Kararımızı sadece iki commit’i olduğu gibi bırakıp (pick), diğerlerini bir önceki ile commit mesajını tutmadan birleştirmesi (f) yönünde kullanıyoruz:
pick 605e31b ORM migrasyonu todo listesi cikarildi
f d23ef86 ORM todo\'da güncelleme
f 7e97fca Ooops! Typo.
f 7764737 ORM migrasyonu son dokunuşlar
pick ae1308d JIRA - 4323 : SQL -> ORM migrasyonu gerçekleştirildi
Editörü kaydedip çıkıyoruz ve git rebase işleminin bittiğini söylüyor:
git rebase --interactive HEAD~5
[detached HEAD 8f4a002] ORM migrasyonu todo listesi cikarildi
1 file changed, 2 insertions(+), 1 deletion(-)
Successfully rebased and updated refs/heads/orm.
Sonuçları inceliyoruz:
git log -3
commit 0ab988916640a84d4b3c53dacb4a69a7c0080fe0
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:54:01 2013 +0200
JIRA - 4323 : SQL -> ORM migrasyonu gerçekleştirildi
commit 8f4a0029518d240ed0a26e4a8c5b27533a890105
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:52:01 2013 +0200
ORM migrasyonu todo listesi cikarildi
commit 30fb53716aa01da32e2c1e44f39eebee6a44daf3
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:28:00 2013 +0200
Master'a merge etmece
Artık gereksiz commitler yüzünden utanç duymadan branşı push edip review isteyebiliriz.
8. Birden fazla ana işin tek branşta halledilmesi.
Bazen bir çözüm üzerinde çalışırken, kodun bambaşka bir yerinde, alakasız bir düzenleme yaparız. Bu gördüğümüz bir imla hatası, önemli bir düzenleme, veya basit bir yorum ekleme işi bile olabilir. Hatta öğre yemeği öncesi ne üzerinde çalıştığımızı hatırlamazsak kendi başına bir özelliği de implemente etmiş olabiliriz…
git log -2
commit a828ef7d74d4fc6dc51719b57e1c82c8f3c514c6
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 14:55:27 2013 +0200
JIRA - 4325 : BKM Express entegrasyonu geliştirildi
commit ac5504e49ce44d2f988366d0d628d54898feafa9
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 14:26:55 2013 +0200
JIRA - 4324 : Uygulama genelinde Newforms migrasyonu
Hay aksi, BKM entegrasyonu yanlış branşta commit etmişiz. Bu durumda izlenebilecek en güzel yol master’dan BKM’ye özel branş açıp, ilgili commit’i oraya alıp, newforms-migration branşını kendi ile ilişkili commit’e hard reset yapmak:
git checkout master
Switched to branch 'master'
git checkout -b bkm-express
Switched to a new branch 'bkm-express'
git cherry-pick a828ef7d74d4
[bkm-express c1a54da] JIRA - 4325 : BKM Express entegrasyonu geliştirildi
1 file changed, 3 insertions(+), 1 deletion(-)
git log -2
commit c1a54da1b824cccb24acd48d28348e87452b0a45
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 14:55:27 2013 +0200
JIRA - 4325 : BKM Express entegrasyonu geliştirildi
commit 30fb53716aa01da32e2c1e44f39eebee6a44daf3
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:28:00 2013 +0200
Master\'a merge etmece
git checkout newforms-migration
Switched to branch 'newforms-migration'
git reset --hard ac5504e49ce44d 2f9
HEAD is now at ac5504e JIRA - 4324 : Uygulama genelinde Newforms migr asyonu
git log -2
commit ac5504e49ce44d2f988366d0d628d54898feafa9
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 14:26:55 2013 +0200
JIRA - 4324 : Uygulama genelinde Newforms migrasyonu
commit 30fb53716aa01da32e2c1e44f39eebee6a44daf3
Author: Metin Emiroğlu <amiroff@gmail.com>
Date: Sun Nov 24 13:28:00 2013 +0200
Master\'a merge etmece
Böylece, artık her branş sadece içermesi gerektiği commit’leri içermektedir.
Daha kötü bir senaryoda ise, newforms branşında önce BKM commit’i, sonra ise newforms commitinin gelmesi durumunda, izleyeceğimiz yol biraz farklı olacaktır. Çünkü bir şekilde bu branştan BKM commit’ini sıyırıp çıkarmamız gerekiyor. Burada yardımıza eski arkadaş, interaktif rebase gelecektir. Önce newforms branşında iken bkm branşı oluşturalım, bu şekilde bu iki branş birebir aynı commit’leri içeriyor olacaktır. Daha sonra ise her bir branşa geçerek
git rebase -i master
komutuyla branşta istemediğimiz commit’lerin satırlarını silmemiz yeterli olacaktır. İnteraktif rebase silinmiş commit satırlarını hiç olmamış gibi kabul edip yoluna devam edecektir.
9. Her push sırasında uzak branşın adının verilmesi.
Çok sık karşılaştığım durumlardan birisi de, branşı origin’e göndermek için her defasında
git push origin BKM
şeklinde uzakta oluşturulacak branşın adının verilmediği müddetçe git’in ağlaması durumu:
git push
warning: push.default is unset; its implicit value is changing in Git 2.0 from 'matching' to 'simple'.
To squelch this message
and maintain the current behavior after the default changes, use:
git config --global push.default matching
To squelch this message and adopt the new behavior now, use:
git config --global push.default simple
See 'git help config' and search for 'push.default' for further infor
mation.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of
Git)
Everything up-to-date
Bu sorunun çözümü için aslında git yukarıdaki mesajda ipucu veriyor.
git config --global push.default simple
konfigurasyon komutu ile varsayılan olarak uzaktaki birebir aynı isimdeki branşa push edilmesi sağlanır. Bunu konfigurasyon yapmadan sağlamanın bir başka yolu da
git push -u origin BKM
şeklinde bir kereye mahsus uzaktaki branş adını belirtmektir. Daha sonraki push işlemlerinde ilişkili branş adı bilindiği için sorun çıkmayacaktır:
git push
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 271 bytes | 0 bytes/s, done. Total 3 (delta 1), reused 0 (delta 0)
To ssh://git@bitbucket.org/amiroff/git-practices.git
10ac333..229a9b7 BKM -> BKM
10. Public bir commit’i geri almak için harcanan çaba.
Çoğu zaman yayına bir commit alırız, arkasından bir şeyler ters gider ve commit’teki değişikliklerin hızlıca geri alınması gündeme gelir. İnsan ister istemez aynı değişiklikleri bir de ters yönde yapıp yeni bir commit oluşturmak ister. Fakat bu işlemi yaparken hem zaman harcar, hem de yeni hatalar da yapabilir. Bazı yerleri düzenlemeyi de tamamen gözden kaçırmış olabilir. Git zaten kendisi tüm değişiklikleri izlediği için, benzer durumda bu ağır işi bizim yerimize yapar:
git commit -am ".htaccess ve mod_rewrite düzenlemesi"
[master fb13f67] .htaccess ve mod_rewrite düzenlemesi
1 file changed, 2 insertions(+), 1 deletion(-)
git push
Counting objects: 5, done.
Delta compression using up to 8 threads. Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 312 bytes | 0 bytes/s, done.
Total 3 (delta 1), reused 0 (delta 0)
To ssh://git@bitbucket.org/amiroff/git-practices.git
30fb537..fb13f67 master -> master
Oops! Hemen düzenlemeyi geri alalım!
git revert fb13f67
[master b062213] Revert ".htaccess ve mod_rewrite düzenlemesi"
1 file changed, 1 insertion(+), 2 deletions(-)
veya
git revert HEAD
[master b062213] Revert ".htaccess ve mod_rewrite düzenlemesi"
1 file changed, 1 insertion(+), 2 deletions(-)
Geriye kalan sadece güncellemeyi göndermek:
git push
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 319 bytes | 0 bytes/s, done. Total 3 (delta 1), reused 0 (delta 0)
To ssh://git@bitbucket.org/amiroff/git-practices.git
fb13f67..b062213 master -> master
Çok şükür ucuz atlattık!
11. Public olmayan commit’ten öncesine dönmek.
Repoya birşeyler commit ettik, sonra commit için daha erken olduğuna karar verdik, ya da mesajı değiştirmek istedik, veyahut bir kaç dosyayı stage’e ekleyip, bir kaçını stage’den çıkarmak istedik. Belki de son commit hayatımızdan tamamen çıksın istedik. Bu durumda git reset komutu en yakın dostumuz olacaktır:
git status
# On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: README.md
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# index.html
no changes added to commit (use "git add" and/or "git commit -a")
Bir dosyada güncelleme var, bir tane de stage’e alınmamış yeni dosya var.
git commit -am "Anasayfa çalışması tamamlandı"
[master a921b95] Anasayfa çalışması tamamlandı
1 file changed, 2 insertions(+), 1 deletion(-)
1 file mı? Neden?
git status
# On branch master
# Your branch is ahead of 'origin/master' by 1 commit.
# (use "git push" to publish your local commits)
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# index.html
nothing added to commit but untracked files present (use "git add" to track)
Haydaa, index.html’yi eklemeyi unutmuşuz. Hemen commit öncesine dönelim ve durumu kontrol edelim:
git reset --soft HEAD^
git status
# On branch master
# Changes to be committed:
# (use "git reset HEAD <file>..." to unstage)
#
# modified: README.md
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# index.html
Az önceki durum ile birebir aynı pozisyondayız, artık bu defa index.html’yi stage’e eklemeden commit etmeyiz.
--soft
anahtarı commit öncesi düzenlemeleri aynen bırakırken --hard
stage’te olmayan dosyalar hariç tüm düzenlemeleri uçurur:
git status # On branch master
# Changes not staged for commit:
# (use "git add <file>..." to update what will be committed)
# (use "git checkout -- <file>..." to discard changes in working directory)
#
# modified: README.md
#
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# index.html
no changes added to commit (use "git add" and/or "git commit -a")
Yaptığımız tüm düzenlemeler hayatımızdan çıksın!
git reset --hard
HEAD is now at b062213 Revert ".htaccess ve mod_rewrite düzenlemesi"
git status
# On branch master
# Untracked files:
# (use "git add <file>..." to include in what will be committed)
#
# index.html
nothing added to commit but untracked files present (use "git add" to track)
Dikkat edelim, README dosyasındaki tüm düzenlemeler kaybolurken, index.html dosyası aynen duruyor.
12. Birden fazla platformun kullanıldığı yerlerde satır sonu ayarının yapılmaması.
Farklı işletim sistemleri satır sonu işaretlerini farklı koyar. Linux ve MacOS LF şeklinde kullanırken, Windows CRLF şeklinde kullanmaktadır. Tüm yazılımcılar aynı işletim sistemini kullanıyorsa, bu herhangi bir sorun teşkil etmez, fakat kullanılan sistemler farklılık gösterirse, satır sonu işaretlerinde çakışmalar Git’in kafasını karıştıracaktır.
Söz konusu davranışın engellenmesi için Linux ve MacOS altında:
git config --global core.autocrlf input
Windows altında ise:
git config --global core.autocrlf true
şeklinde ayar yapılmalıdır. input değeri CRLF şeklindeki satır sonlarının otomatik olarak LF şekline dönüştürümlesi sağlar, fakat tam ters yönde dönüştürme yapmaz. true değeri ise git veritabanına kaydederken tüm CRLF satır sonlarının LF’ye dönüştürülmesini, çalışma dizinine (working directory) okurken ise tam ters işlemin yaıplmasını sağlar. Daha modern bir çözüm için ise, tüm bu ayarlara gerek kalmaması için repo’da içeriği aşağıdaki gibi olan .gitattributes
isimli dosyanın eklenmesi yeterli olacaktır:
# Set default behaviour, in case users don't have core.autocrlf set.
* text=auto
Git’i daha verimli kullanabilmek için, tamamen ücretsiz dağıtılan Pro Git kitabını herkese şiddetle tavsiye ederim.
Genel olarak Git’i öğrenip kullanmak isteyenlere ilk önerim ise, görsel araçlarla kesinlikle başlamamaları yönündedir, önce komut satırından temel kullanımı ve prensipleri öğrenilip, daha sonra görsel araç kullanımına geçilebilir.
13. İnternet bağlantısı yokken kodu paylaşamamak.
Git kullanılan bir çok şirkette genellikle branch’lerin push edilerek yedeklendiği ve yayına alma işlemi için kullandığı merkezi bir repo mevcuttur. Bu yapı çevik geliştirme ortamı sunarken, söz konusu reponun şirket dışında (örneğin, Github üzerinde) bulunması, olası internet bağlantısı kopukluğunda kaosa neden olabilmektedir. Git’in en başlıca özelliklerinden birisi, merkezcil olmamasıdır (decentralized). Bu, git ile geliştirme yapmak, kod paylaşmak veya yayına almak için bir merkezi sunucuya gereksinim olmadığı anlamına gelmektedir. Ekipteki her yazılımcıda bulunan repo kopyası bir node (nokta) görevi gördüğü için bu noktalar arasında çapraz veri alışverişi rahatlıkla yapılabilir. Birden fazla yazılımcı tek proje üzerinde çalışıyor ise bilgisayarlarının aynı ağda olması ve aralarında ssh bağlantısının sağlanabiliyor olması kaydıyla, alttaki prosedürler izlenerek kod paylaşımı sağlanabilir.
Örneğimizde, önce ahmet kullanıcısının bilgisayarının adresi ve reponun bulunduğu dizin kod düzenlemesini paylaşmak isteyen diğer yazılımcının bilgisayarındaki repoya remote olarak eklenir:
git remote add ahmet ssh://ahmet@192.168.0.145/Users/ahmet/Code/myrepo
Daha sonra paylaşılmak isteen branch söz konusu remote’a push edilir:
git push ahmet image-fix
Password: #(ahmet'in ssh sifresi girilir)
Counting objects: 66, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (7/7), done.
Writing objects: 100% (7/7), 719 bytes | 0 bytes/s, done.
Total 7 (delta 4), reused 0 (delta 0)
To ssh://ahmet@192.168.0.145/Users/ahmet/Code/myrepo
* [new branch] image-fix -> image-fix
Tebrikler! Az önce git branch’ınızı internet üzerindeki bir node kullanmadan paylaştınız. Bunun ardından ahmet kullanıcısı bu branch’ı istediği gibi inceleyip kendi reposuna merge edebilir veya üzerinden işlem yapabilir:
git merge image-fix
SSH dışında git bir çok protokolü de desteklemektedir. Bunların içinde file://, git://, ve https:// yer almaktadır. SSH bağlantısı imkanı olmadığı durumlarda bu protokoller üzerinden de paylaşım işlemi yapılabilir.