Bu yazıda, bir yazılım ekibiyle proje geliştirirken sıklıkla kullandığımız Git komutların anlamlarını ve yazım şeklini inceleyeceğim.
Git, yazılım geliştirme projelerinde çalışan geliştiricilere ve ekiplere sayısız fayda sağlayan ve yaygın olarak kullanılan bir sürüm kontrol sistemidir. Peki sürüm kontrol sistemi nedir ve ne işe yarar?
Sürüm kontrol sistemi (VCS: Version Control System), yazılım geliştirme sürecinde dosya ve kod değişikliklerinin yönetilmesini sağlayan bir sistemdir. Bir projenin farklı sürümlerinin oluşturulmasını, takibini, geri alınmasını ve gerektiğinde geçmiş sürümlere dönülmesini sağlar. Ayrıca, birden fazla geliştiricinin aynı projede çalışmasını kolaylaştırır ve projenin farklı kısımlarında geliştirilen kodların birbiriyle çakışması durumunda bizi bilgilendirerek, çakışmaları çözmemizi kolaylaştrırır.
Birazdan anlatacağım Git komutlarının nasıl çalıştığını ve nasıl bir amaca hizmet ettiğini daha rahat anlayabilmeniz için öncelikle Git projelerindeki dalllandırma yapısından genel olarak bahsetmek gerekmektedir. Farklı kurum ve kuruluşlarda dallandırma veya dal isimlendirmede farklı mentaliteler uygulanmakla birlikte ana hatlarıyla olarak bir Git projesinin dal yapısı şöyledir:
main: Projenin canlıdaki halini içeren, test edilmiş ve güvenilir sürümdür. Bu dalda kesinlikle geliştirme yapılmaz, tüm testleri geçip emin olunmadıkça, diğer dallardan birleştirme yapılmaz. Eskiden genellikle "master" adı verilen bu dala artık "main" adı verilmesi daha uygun bulunmaktadır.
develop: Projenin, üzerinde geliştirme ve testlerin yapıldığı, en güncel halini barındıran daldır. Yeni açılan dallar bu daldan çatallanır ve yeni eklenen özellikler (features) bu dala birleştirilerek bütüncül olarak test edilir. Bazen "dev","next" veya projenin geliştirilmekte olan sürümünün adı verilir (ör. php8.2 veya bootstrap5.2 gibi; böylece bir ekip mevcut sürümü bakım verirken, bir başka ekip bir sonraki sürümü geliştirir).
feature: Projeye eklenecek yeni özelliklerin geliştirildiği daldır. Birden fazla özellik dalı bulunması durumda, özelliğe matuf bir isim verilir (ör. online-payment veya live-chat gibi).
bugfix: Geliştirme yapılarken oluşan veya farkedilen hataların düzeltilmesi için açılmış kısa ömürlü dallardır. İsimleri çözmeleri beklenen soruna ithafen belirlenir (ör. broken-link-fix veya db-connection-failure gibi). Hata düzeltilip, testler başarıyla sonuçlandırıldıktan sonra silinirler.
Bunun dışında, bir de kısaca projelerin geliştirme aşamalarına değinerek, hangi aşamada hangi komutların daha sık kullanıldığını görstermek ve komutların amacını daha iyi anlamanıza yardımcı olmak istiyorum. Temel olarak bir Git projesinin aşamaları şöyledir:
Proje dosyası hazırlanır
git init (yeni proje)
git clone <repo-adı> (mevcut proje)
Yeni bir dal oluşturulup buraya geçilir
git branch feature
git checkout feature
Geliştirme sürecinde dosyalar eklenir/çıkarılır/değiştirilir ve bu katkılar işlenir
git add .
git commit -m "katkı-mesajı"
Uzak ve yerel repolar geliştirme boyunca sık sık güncellenir
Tanım: Uzak repodaki değişiklikleri yakalayıp, bilgisayarımıza getirmemizi sağlar. Öncelikle, git checkout komutuyla, değişiklikleri işlemek istediğimiz dala geçiş yaparız. Ardından git fetch komutuyla, uzak reponun origin/develop dalındaki değişiklikleri kendi dalımıza getiririz.
Yazım: git fetch origin develop
git merge
Tanım: Başka bir daldaki değişiklikleri, üzerinde bulunduğumuz dala birleştirmemizi sağlar.
Örnek: Şu an develop dalı üstündeyiz ve feature dalındaki değişiklikleri buraya birleştirmek istiyoruz
Yazım: git merge originfeature
git pull
Tanım: Uzak repodan git fetch ile yakalanan değişiklikleri, yerel dalımıza birleştirmemizi sağlar. Öncelikle, git checkout komutuyla, değişiklikleri birleştirmek istediğimiz dala geçiş yaparız. Ardından git merge komutuyla, uzak reponun origin/develop dalındaki değişiklikleri kendi dalımıza birleştiririz.
Yazım: git pull origin develop
git status
Tanım: Yerel reponuzla uzak reponuzu karşılaştırarak projenizin mevcut durumunu (eklenen, çıkarılan, izlemde olmayan dosyalar, vs) gösterir. Böylece katkı işlemeden önce neler yapmanız gerektiğine karar verebilirsiniz.
Yazım: git status
git add
Tanım: Dosya ve klasördeki değişiklikleri izleme (stage) alır ve bir sonraki katkıyı (commit) işlemek için hazırlar.
git add . (çalışma dizinindeki tüm dosyalardaki değişiklikleri izleme alır)
git add -A (çalışma ağacımızdaki tüm değişiklikleri kökünden itibaren izleme alır)
git commit
Tanım: İzleme (stage) aldığınız değişiklikleri katkı (commit) olarak işler.
Yazım:
git commit -m "katkı mesajı" (işlediğiniz katkı ile ilgili kısa bilgi başlığı)
Katkı mesajları 50 karakteri geçmeyecek şekilde, fiille başlayan, emir kipinde, kısa ve net bir bilgi içermelidir. Sonunda nokta kullanılmaz ve eğer bir iş paketi atanmışsa mesaj sonuna verilen görevin referans numarası eklenir.
Ör. "add main.js ref.2415", "fix bug in db connection ref.2416" veya "update style.css #2417" gibi.
git log
Tanım: Katkı geçmişinizi ekrana getirir. Katkınızın işlendiğinden emin olmak veya belli bir katkıyı aramak istediğinizde, özellikle kullanışlıdır.
Yazım: git log
git push
Tanım: Yerel repomuzdaki yaptığımız değişiklikleri uzak repoya yüklememizi sağlar. Değişiklikleri yaptığımız dalda olduğumuzdan emin olmalıyız. Bunun için git checkout komutunu kullanabiliriz.
Yazım: git push origin <dal-adı>
git request-pull
Tanım: Bir e-posta isteği için bekleyen değişikliklerin özetini oluşturur. Bir dal veya çatalda yapılan değişiklikleri, üst-akım (upstream) repo yürütücüsüne iletir.
Yazım: git request-pull origin/main <çatal_adı veya dal_adı>
git rerere
Tanım: Önceden çözülmüş birleştirme çatışmalarının kaydedilmiş çözümlerini yeniden kullanır. git rerere komutunun çalışması için rerere.enabled yapılandırma seçeneğinin "true" olarak ayarlanması gerekmektedir (git config --global rerere.enabled true). Ayrıca, git rerere yalnızca aynı dal ve katkı kullanılarak çözülen çatışmalara uygulanabilir.
Yazım: git rerere
git diff
Tanım: Katkılar arasındaki ve katkı ile çalışma ağacı arasındaki değişiklikleri gösterir. Ayrıca dalları karşılaştırır.
Yazım:
git diff (çalışma dizini ile son işlem arasındaki farkı gösterir))
git diff HEAD~1 HEAD (sonuncu ve sondan ikinci katkı arasındaki farkı gösterir))
git diff <dal-1> <dal-2> (verilen dallar arasındaki farkı gösterir)
git revert
Tanım: En son işlediğiniz katkının (silmeksizin) tüm izlerini geri alacak yeni bir katkı işler. Böylece son katkı işlenmemiş gibi olur.
Yazım: git revert
git reset
Tanım: Çalışma dizinindeki değişiklikleri siler ve bir önceki katkı (commit) anındaki durumuna geri getirir. Eğer "-hard HEAD" seçeneğiyle kullanılırsa, çalışma dizini ve izlemi boşaltarak, repoyu en son katkı işlendiği andaki poza (snapshot) dönüştürür.
Yazım:
git reset
git reset –hard HEAD (son katkıyı izlemi boşaltarak siler)
git reset –soft HEAD (son katkıyı izlemi boşaltmadan siler)