Git
Chapters ▾ 2nd Edition

5.2 Distributed Git - Projenin Gelişiminde Rol Almak

Projenin Gelişiminde Rol Almak

Proje gelişiminde alınabilecek rolleri tanımlamanın temel zorluğu, bunu yapmanın birçok farklı yolunun olmasıdır. Git çok esnek olduğundan, insanlar bir proje üzerinde birçok farklı şekilde birlikte çalışabilirler ve her proje birbirinden farklı olduğu için, size projenin gelişiminde nasıl rol almanız gerektiğini dikte etmek yanlış olur. Aktif katkıcı sayısı, seçilen iş akışı, sizin işlenen katkılara erişiminiz ve muhtemel dış katkı yöntemi gibi bazı değişkenler bu süreci etkiler.

İlk değişken aktif katkıcı sayısıdır: bu projeye kaç aktif katkıcı, ne sıklıkta, kod katkısında bulunuyor? Çoğu zaman, günde birkaç katkı işleyen, iki veya üç geliştirici olabilir hatta bazı durağan projeler için daha azdır. Daha büyük şirketler veya projeler için, binlerce geliştirici olabilir ve her gün yüzlerce veya binlerce katkı işlenebilir. Katkıda bulunan geliştirici sayısı arttıkça, kodunuzun temiz şekilde uygulanması veya kolayca birleştirilebilmesi konusunda daha fazla sorunla karşılaşırsınız. Gönderdiğiniz değişiklikler, siz çalışırken veya değişiklikleriniz onaylanmayı ve uygulanmayı beklerken, birleştirilen çalışmalar nedeniyle artık uyumsuz hale gelebilir veya ciddi şekilde bozulabilir.

Sonraki değişken: projenin kullandığı iş akışıdır. Her geliştiricinin ana kod satırına eşit yazma erişimine sahip olduğu iş akışı, merkezi mi yoksa dağıtık mıdır? Projede, tüm yamaları kontrol eden bir bakım veya birleştirme yöneticisi var mı? Tüm yamalar gözden geçirilip ve onaylanıyor mu? Bu süreçte yer alıyor musunuz? Diktatör-yaver sistemi var mı ve çalışmanızı önce onlara sunmanız mı gerekiyor?

Tüm bu sorular, bir projeye nasıl etkili bir şekilde katkıda bulunacağınızı ve sizin için tercih edilen veya uygulanabilir olan iş akışlarının neler olduğunu etkileyebilir. Bu soruların bazı yönlerini, basitten daha karmaşığa doğru bir dizi kullanım durumuyla ele alacağız. Bu örneklerden yola çıkarak, ihtiyacınız olan belirli iş akışlarını oluşturabileceğinizi umuyoruz.

Katkı Rehberi

Özel kullanım durumlarını incelemeye başlamadan önce, katkı mesajları hakkında kısa bir not verelim. Katkı oluşturmak için iyi bir kılavuza sahip olmak ve ona uygun davranmak, Git ile çalışmayı ve başkalarıyla işbirliği yapmayı çok daha kolay hale getirir. Git projesi, yama göndermek amacıyla nasıl iyi bir katkı oluşturacağınız hakkında kullanışlı ipuçları sunan kullanışlı bir belgeye sahiptir. Onu Git kaynak kodunda Documentation/SubmittingPatches dosyasında bulabilirsiniz.

Öncelikle, gönderilerinizde boşluk (whitespace) hataları olmamalıdır. Git, bunu kontrol etmek için kolay bir yol sağlar: Git’in olası boşluk hataların tanımlayıp size listelemesi için, katkılamadan önce git diff --check komutunu çalıştırın.

`git diff --check` çıktısı.
Görsel 57. git diff --check çıktısı.

Eğer bunu katkılamadan önce çalıştırırsanız, diğer geliştiricileri rahatsız edebilecek boşluk sorunlarını katkılamak üzere olduğunuzu görebilirsiniz.

Sonraki adım, her bir katkıyı mantıksal olarak ayrı bir değişim seti olarak ayarlamaktır. Mümkünse, değişikliklerinizi sindirilebilir hale getirmeye çalışın: bütün hafta sonu beş farklı sorun üzerinde kod yazıp, Pazartesi günü hepsini tek bir devasa katkı olarak göndermeyin. Hafta sonu boyunca hiç katkı işlemeseniz bile, pazartesi günü çalışmanızı her konuya (iş paketine) -faydalı bir katkı mesajı da içeren- en az bir katkı olacak şekilde ayırın. Değişikliklerden bazıları aynı dosyayı değiştiriyorsa, dosyaları kısmen aşamalandırmak için git add --patch kullanmaya çalışın (Etkileşimli İzlemleme (Staging) bölümünde detaylı olarak ele alınmıştır). Tüm değişiklikler bir şekilde eklendikten sonra, ister tek katkıda işleyin ister beş, dalın ucu üzerinde yer alan nihai proje pozu aynıdır. Bu yüzden değişikliklerinizi inceleyen diğer geliştiricilerin işlerini kolaylaştırmaya çalışın.

Bu yaklaşım, daha sonra bir değişiklik setini çıkarmak veya geri almak istediğinizde de işleriniz büyük ölçüde kolaylaştırır. Geçmişi Yeniden Yazma bölümünde geçmişi değiştirme ve dosyaları etkileşimli olarak aşamalamayla ilgili birçok faydalı ipucu bulabilirsiniz. Bu araçları kullanarak, çalışmanızı başka birine göndermeden önce, temiz ve anlaşılabilir bir katkı geçmişi oluşturmaya yardımcı olun.

Akılda tutulması gereken son şey ise katkı mesajıdır. Kaliteli bir katkı mesajı oluşturma alışkanlığı, Git’i kullanmayı ve işbirliği yapmayı çok daha kolay hale getirir. Genel bir kural olarak mesajlarınız: 50 karakteri geçmeyecek şekilde, değişiklik setini özetleyen tek bir satırla başlamalı ve bir satır boşluk bıraktıktan sonra daha ayrıntılı bir açıklama içermelidir. Ayrıntılı açıklamada: değişikliğinizi neden yaptığınızı, ve uygulamanızın önceki davranışla nasıl farklılıklar içerdiğini açıklamanız gerekir. Bu takip edebileceğiniz sağlam bir yönergedir. Katkı mesajınızı emir kipiyle yazın: "Hata düzeltildi" veya "Düzeltilmiş Hata" yerine "Hata düzelt" gibi. Tim Pope tarafından yazılan şablonu inceleyebilirsiniz:

Büyük harfle başlayan, kısa (50 karakterden az) özet

Gerekirse, daha detaylı açıklayıcı metin.
Yaklaşık 72 civarı karakterle anlatın.
Bazı bağlamlarda, ilk satır aynı bir e-postadaki konu kısmı ve geri kalan kısım da mesaj gövdesi gibi kabul edilir.
Özet ile detay arasındaki boş satır (açıklamayı tamamen atlamazsanız) kritik önemdedir.
Eğer ikisini birleştirirseniz "rebase" gibi araçlar karışıklık yaşayabilir.

Katkı mesajınızı emir kipiyle yazın: "Hata düzeltildi" veya "Hatayı önlüyor" yerine "Hataları düzelt" gibi ifadeler kullanın.
Bu kural, `git merge` ve `git revert` gibi komutlarla oluşturulan katkı mesajlarıyla eşleşir.

Daha ileri açıklamalar boş satırlardan sonra gelir.

- Madde işaretleri (-, *, vb) uygundur

- Genellikle madde işareti olarak tire (-) veya yıldız (*) kullanılır, ardından tek bir boşluk bırakılır ve maddeler arasında boş       satırlar bulunur. (Bu kısımda anlatılan kurallar ortak görüşe göre değişebilir.)

- Aynı maddede ikinci satıra geçerken bir girinti kullanılır.

Eğer tüm katkı mesajlarınız bu modele uygunsa, işbirliği yaptığınız geliştiriciler ve sizin için her şey çok daha kolay olacaktır. Git projesinin düzgün biçimlendirilmiş katkı mesajları bulunmaktadır (ne kadar güzel biçimlendirilmiş bir proje-katkı geçmişine sahip olduğunuzu görmek için git log --no-merges komutunu çalıştırabilirsiniz).

Örnek 10. Dediğimizi yap, yaptığımızı değil!

Bu kitaptaki birçok örnekte olduğu gibi, sırf kısa kesmek adına, böyle güzel biçimlendirilmiş katkı mesajları yazmamış olabiliriz. Uzun ve güzel mesajlar yazmak yerine, hemen git commit komutuna -m bayrağını ekleyip kullandık.

Yani: dediğimi yapın, yaptığımı yapmayın!

Küçük Özel Ekipler

Muhtemelen karşılaşacağınız en basit kurulum, sadece birkaç geliştiriciyle yapacağınız özel bir projedir. Bu bağlamda "özel", kapalı kaynaklı anlamına gelir, yani dış dünyadan erişilemez. Siz ve diğer geliştiricilerin hepsi repoya itme erişimine sahipsiniz.

Bu geliştirme ortamında, Subversion veya başka bir merkezi sistem kullandığınızdaki gibi bir iş akışı takip edebilirsiniz. Çevrimdışı katkı işleme ve çok daha basit dallandırma ve birleştirme gibi avantajlara sahip olursunuz, ancak iş akışı yine de çok benzerdir. Temel fark, birleştirmelerin sunucu üzerinde ve katkı anında olması yerine, istemci tarafında gerçekleşmesidir. İki geliştiricinin paylaşılan bir repoda birlikte çalışmaya başladığı durumun nasıl görüneceğine bakalım. İlk geliştirici, John, repoyu kopyalar, bir değişiklik yapar ve yerel olarak katkı işler. (Örnekleri kısaltmak için, protokol mesajları ... şeklinde yazılmıştır.)

# John's Machine
$ git clone john@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim lib/simplegit.rb
$ git commit -am 'remove invalid default value'
[master 738ee87] remove invalid default value
 1 files changed, 1 insertions(+), 1 deletions(-)

İkinci geliştirici, Jessica, aynı şeyi yapar: repoyu koypalar ve bir değişiklik katkılar:

# Jessica's Machine
$ git clone jessica@githost:simplegit.git
Cloning into 'simplegit'...
...
$ cd simplegit/
$ vim TODO
$ git commit -am 'add reset task'
[master fbff5bc] add reset task
 1 files changed, 1 insertions(+), 0 deletions(-)

Şimdi Jessica çalışmasını sorunsuz bir şekilde sunucuya gönderiyor:

# Jessica's Machine
$ git push origin master
...
To jessica@githost:simplegit.git
   1edee6b..fbff5bc  master -> master

Yukarıdaki çıktının son satırı, itme işlemi ardından yararlı bir dönüş mesajı gösterir. Temel format, <oldref>..<newref> fromref -> toref şeklindedir, burada oldref eski referansı, newref yeni referansı, fromref gönderilen yerel referansın adını ve toref güncellenen uzak referansın adını ifade eder. İleride de benzer çıktılar göreceğiniz için, bu mevzuda temel kavrayışınızın olması, repoların çeşitli durumlarını anlamanıza yardımcı olacaktır. git-itme linkinde daha fazla ayrıntı bulunmaktadır.

Örneğimize devam edersek, bir süre sonra John bazı değişiklikler yapar, bunları yerel reposuna kaydeder ve aynı sunucuya göndermeye çalışır:

# John's Machine
$ git push origin master
To john@githost:simplegit.git
 ! [rejected]        master -> master (non-fast forward)
error: failed to push some refs to 'john@githost:simplegit.git'

Bu durumda, John’un gönderimi, Jessica’nın kendi değişikliklerini önceden göndermesinden dolayı başarısız olur. Eğer Subversion kullanıyorsanız bu özellikle önemlidir, çünkü iki geliştiricinin aynı dosyayı düzenlemediğini fark edeceksiniz. Subversion’da farklı dosyalar düzenlenirse sunucu otomatik olarak böyle bir birleştirme yapar, ancak Git’te öncelikle geliştiricilerin yerel olarak birleştirme yapmaları gerekir. Yani, John’un önce Jessica’nın yukarı akış (upstream) değişikliklerini alıp bunları yerel reposuna birleştirmesi gerekmektedir.

İlk adım olarak, John Jessica’nın çalışmasını alır (fetch sadece Jessica’nın yukarı akış çalışmasını alır, henüz John’un çalışmasına birleştirmez):

$ git fetch origin
...
From john@githost:simplegit
 + 049d078...fbff5bc master     -> origin/master

Bu noktada, John’un yerel reposu şuna benzer:

John’un ayrık geçmişi.
Görsel 58. John’un ayrık geçmişi.

Şimdi John, çektiği Jessica’nın çalışmasını kendi yerel çalışmasına birleştirebilir:

$ git merge origin/master
Merge made by the 'recursive' strategy.
 TODO |    1 +
 1 files changed, 1 insertions(+), 0 deletions(-)

Eğer bu yerel birleştirme sorunsuz bir şekilde gerçekleşirse, John’ın güncellenmiş geçmişi artık şöyle görünecektir:

`origin/master’a birleştirme sonrası John’un reposu.
Görsel 59. origin/master'a birleştirme sonrası John’un reposu.

Bu noktada, Jessica’nın çalışmalarının kendisininkini etkilemediğinden emin olmak için, John bu yeni kodu test etmek isteyebilir ve her şeyin yolundaysa, sonunda birleştirilmiş yeni çalışmasını sunucuya itebilir:

$ git push origin master
...
To john@githost:simplegit.git
   fbff5bc..72bbc59  master -> master

Sonuçta, John’ın katkı geçmişi şöyle görünecektir:

`origin` sunucusuna ittikten sonra John’un katkı geçmişi.
Görsel 60. origin sunucusuna ittikten sonra John’un katkı geçmişi.

Bu arada, Jessica issue54 adında yeni bir tematik dal oluşturdu ve bu dala üç katkı işledi. Henüz John’un değişikliklerini çekmediği için, katkı geçmişi şöyle görünüyor:

Jessica’nın tematik dalı.
Görsel 61. Jessica’nın tematik dalı.

Jessica birden John’ın sunucuya yeni bir değişiklik ittiğini öğrenir ve ona bir göz atmak ister: böylece henüz sahip olmadığı tüm yeni içerikleri sunucudan alabilecektir:

# Jessica's Machine
$ git fetch origin
...
From jessica@githost:simplegit
   fbff5bc..72bbc59  master     -> origin/master

Bu komutla, John’ın en son yüklediği çalışmayı indirir. Jessica’nın geçmişi şimdi şöyle görünmektedir:

John’un değişikliklerini yakaladıktan sonra Jessica’nın geçmişi.
Görsel 62. John’un değişikliklerini yakaladıktan sonra Jessica’nın geçmişi.

Jessica tematik dalının hazır olduğunu düşünüyor, ancak itme yapabilmek için, John’dan aldığı hangi bölümü kendi çalışmasına birleştirmesi gerektiğini öğrenmek istiyor. Bunu öğrenmek için git log komutunu çalıştırır:

$ git log --no-merges issue54..origin/master
commit 738ee872852dfaa9d6634e0dea7a324040193016
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 16:01:27 2009 -0700

   remove invalid default value

issue54..origin/master sözdizimi, Git’e sadece ikinci dalda (origin/master) bulunan ve ilk dalda (issue54) bulunmayan katkıları göstermesini isteyen bir günlük (log kaydı) süzgecidir. Bu sözdizimini Katkı Aralığı bölümünde detaylı olarak ele alacağız.

Yukarıdaki çıktıdan, John’un işlediği ama Jessica’nın yerel çalışmasına birleştirmediği tek bir katkı olduğunu görebiliriz. Eğer Jessica origin/master'a birleştirirse, bu onun yerel çalışmasını değiştirecek olan tek katkı olacaktır.

Jessica artık tematik çalışmasını ana dalına birleştirip, John’un çalışmasını (origin/master) da ana dalına birleştirdikten sonra tekrar sunucuya gönderebilir.

Jessica issue54 tematik dalındaki tüm çalışmalarını katkıladıktan sonra, bütün bu çalışmaları birleştirmek için ana dalına (master) geçiş yapar:

$ git checkout master
Switched to branch 'master'
Your branch is behind 'origin/master' by 2 commits, and can be fast-forwarded.

Jessica önce origin/master veya issue54 'ü birleştirebilir: ikisi de kökdalda olduğu için sıra önemli değildir. Hangi sırayı seçerse seçsin, son poz aynı olmalıdır (sadece tarih farklı olacaktır). Jessica, önce issue54 dalını birleştirmeyi tercih eder:

$ git merge issue54
Updating fbff5bc..4af4298
Fast forward
 README           |    1 +
 lib/simplegit.rb |    6 +++++-
 2 files changed, 6 insertions(+), 1 deletions(-)

Herhangi bir sorun yoktur ve gördüğünüz gibi, bu normal bir "ileri sarma" birleştirmesidir. Jessica şimdi John’ın önceden alınmış ve origin/master dalında beklemekte olan çalışmasını birleştirme sürecini tamamlar:

$ git merge origin/master
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

Her şey temiz bir şekilde birleştirildi ve Jessica’nın geçmişi şimdi şöyle görünüyor:

John’un değişikliklerini birleştirdikten sonra Jessica’nın geçmişi.
Görsel 63. John’un değişikliklerini birleştirdikten sonra Jessica’nın geçmişi.

Artık origin/master Jessica’nın master dalından erişilebilir durumda olduğuna göre Jessica değişikliklerini itebilir durumda olmalı (tabi John bu arada daha fazla değişiklik yapıp itmemişse):

$ git push origin master
...
To jessica@githost:simplegit.git
   72bbc59..8059c15  master -> master

Her geliştirici birkaç kez katkı işlemiş ve birbirlerinin çalışmasını başarılı bir şekilde birleştirmiştir.

Tüm değişiklikleri sunucuya geri iten Jessica’nın geçmişi.
Görsel 64. Tüm değişiklikleri sunucuya geri iten Jessica’nın geçmişi.

Bu, en basit iş akışlarından biridir. Bir süre çalışırsınız (genellikle bir tematik dalda) ve calışmanız birleştirilmeye hazır olduğunda bunu master dalınıza birleştirirsiniz. Bu çalışmayı paylaşmak isterseniz, yeni bir değişiklik varsa master dalınızı origin/master üzerinden çekip (fetch) birleştirirsiniz (merge) ve son olarak sunucudaki master dala itersiniz. Bu işlem genellikle şöyle olur:

Basit bir çok geliştiricili Git iş akışı için genel olaylar dizisi.
Görsel 65. Basit bir çok geliştiricili Git iş akışı için genel olaylar dizisi.

Özel Yönetilen Ekipler

Sıradaki senaryoda, daha büyük bir özel grupta projede yer alanların rollerini inceleyeceğiz. Küçük ekiplerden her birinin, büyük bir projenin sadece bir kısmı (mesela bir uygulamanın tek bir özelliği) üzerinde işbirliği yaptığı ve sonra bu ekip bazlı çalışmaların üçüncü bir tarafça birleştirildiği ortamlarda nasıl çalışacağınızı öğreneceksiniz.

Diyelim ki John ve Jessica bir özellik (bunu featureA olarak adlandıralım) üzerinde birlikte çalışırken, Jessica aynı zamanda Josie adındaki üçüncü bir geliştirici ile birlikte, ikinci bir özellik (bu da featureB olsun) üzerinde de çalışıyor. Bu senaryoda şirket, birim ekiplerce geliştirilen çalışmaların sadece belirli bazı mühendisler tarafından birleştirilebildiği bir birleşim-yöneticisi ağ akışı kullanıyor ve ana reponun master dalı sadece bu mühendisler tarafından güncellenebiliyor. Burada, tüm çalışmalar ekip temelli dallarda yapılır ve daha sonra birleştiriciler tarafından bir araya getirilebilir.

Hadi her iki özellik üzerinde ve iki farklı geliştiriciyle eşzamanlı çalışırken Jessica’nın iş akışını takip edelim. Varsayalım ki reposunu zaten kopyalamış ve ilk olarak featureA üzerinde çalışmaya karar vermiş olsun. Özelliğe yeni bir dal oluşturur ve burada bazı çalışmalar yapar:

Önce featureA için yeni bir dal oluşturur ve orada bazı çalışmalar yapar:

# Jessica's Machine
$ git checkout -b featureA
Switched to a new branch 'featureA'
$ vim lib/simplegit.rb
$ git commit -am 'add limit to log function'
[featureA 3300904] add limit to log function
 1 files changed, 1 insertions(+), 1 deletions(-)

Bu noktada, çalışmalarını John ile paylaşması gerektiği için featureA dalındaki katkıların sunucuya iter. Jessica’nın master dalına itme erişimi olmadığından (yalnızca birleştiricilerin yetkisi vardı), John ile işbirliği yapabilmek için çalışmalarını başka bir dala itmesi gerekiyor:

$ git push -u origin featureA
...
To jessica@githost:simplegit.git
 * [new branch]      featureA -> featureA

Jessica John’a: çalışmalarını featureA adında bir dalda ittiğini ve isterse bakabileceğini söylemek için bir e-posta gönderir. Jessica John’dan geri bildirim beklerken, Josie ile featureB üzerinde çalışmasına başlamaya karar verir. Başlamak için, sunucunun master dalından temelleyerek tematik bir dal açar:

# Jessica's Machine
$ git fetch origin
$ git checkout -b featureB origin/master
Switched to a new branch 'featureB'

Ardından featureB dalında birkaç katkı işler:

$ vim lib/simplegit.rb
$ git commit -am 'made the ls-tree function recursive'
[featureB e5b0fdc] made the ls-tree function recursive
 1 files changed, 1 insertions(+), 1 deletions(-)
$ vim lib/simplegit.rb
$ git commit -am 'add ls-files'
[featureB 8512791] add ls-files
 1 files changed, 5 insertions(+), 0 deletions(-)

Jessica’nın reposu artık şöyle görünüyor:

Jessica’nın ilk katkı geçmişi.
Görsel 66. Jessica’nın ilk katkı geçmişi.

Jessica çalışmasını itmeye hazırdır, ancak Josie’den, içinde öncel featureB çalışmalarını barındıran featureBee adında bir dalın, daha önceden sunucuya itilmiş olduğunu bildiren e-posta alır. Jessica’nın kendi çalışmasını sunucuya göndermeden önce bu değişiklikleri kendi mevcut çalışmasıyla birleştirmesi gerekmektedir. Jessica önce Josie’nin değişikliklerini git fetch komutu kullanarak getirir:

$ git fetch origin
...
From jessica@githost:simplegit
 * [new branch]      featureBee -> origin/featureBee

Jessica’nın halen featureB dalında olduğunu varsayarsak, Josie’nin çalışmasını bu dal ile git merge kullanarak hemen birleştirebilir:

$ git merge origin/featureBee
Auto-merging lib/simplegit.rb
Merge made by the 'recursive' strategy.
 lib/simplegit.rb |    4 ++++
 1 files changed, 4 insertions(+), 0 deletions(-)

Jessica şimdi bu birleştirilmiş "featureB" çalışmasını hepsini sunucuya geri itmeyi düşünüyor, ancak kendi featureB dalını doğrudan itmek istemiyor. Zaten Josie’nin bir kökdal olarak başlattığı featureBee mevcut olduğundan, Jessica oraya itmek istiyor. Ve bunu şöyle yapıyor:

$ git push -u origin featureB:featureBee
...
To jessica@githost:simplegit.git
   fba9af8..cd685d1  featureB -> featureBee

Bu, bir refspec olarak adlandırılır. Git refspec’lerin detaylı bir incelemesi ve onunla daha başka neler yapılacağını görmek için The Refspec bağlantısına bakabilirsiniz. Ayrıca -u bayrağına da dikkat edin: bu --set-upstream` ifadesinin kısaltmasıdır ve dalları daha kolay itme ve çekme işlemleri için yapılandırır.

Jessica ansızın John’dan, beraber çalıştıkları featureA dalında, bazı değişiklikler yaptığını belirten bir e-posta alır ve Jessica’dan bunlara bakmasını ister. Jessica tekrardan John’un en son çalışmasını da içeren sunucudan tüm yeni içeriği getirmek için basit bir git fetch komutu çalıştırır:

$ git fetch origin
...
From jessica@githost:simplegit
   3300904..aad881d  featureA   -> origin/featureA

Jessica, yeni alınan featureA dalının içeriğini kendi yerel kopyasıyla karşılaştırarak, John’un yeni çalışmasının günlüğünü görüntüleyebilir:

$ git log featureA..origin/featureA
commit aad881d154acdaeb2b6b18ea0e827ed8a6d671e6
Author: John Smith <jsmith@example.com>
Date:   Fri May 29 19:57:33 2009 -0700

    changed log output to 30 from 25

Jessica gördüğü işi beğenir ve John’un yeni çalışmasını yerel featureA dalına birleştirmek ister:

$ git checkout featureA
Switched to branch 'featureA'
$ git merge origin/featureA
Updating 3300904..aad881d
Fast forward
 lib/simplegit.rb |   10 +++++++++-
1 files changed, 9 insertions(+), 1 deletions(-)

Son olarak, Jessica muhtemelen tüm bu birleştirilen içeriğe birkaç küçük değişiklik eklemek isteyecektir. Bu yüzden, gerekli değişiklikleri yapar, bunları yerel featureA dalına katkılar ve sonucu sunucuya geri iter.

$ git commit -am 'small tweak'
[featureA 774b3ed] small tweak
 1 files changed, 1 insertions(+), 1 deletions(-)
$ git push
...
To jessica@githost:simplegit.git
   3300904..774b3ed  featureA -> featureA

Jessica’nın katkı geçmişi şöyle görünmektedir:

feature dalına katkıladıktan sonra Jessica’nın geçmişi.
Görsel 67. feature dalına katkıladıktan sonra Jessica’nın geçmişi.

Jessica, Josie ve John, birleşim yöneticilerine, featureA ve featureBee adlı dalların ana gövdeye birleştirilmeye hazır olduğunu bildirirler. Bu dallar ana gövdeye birleştirildikten sonra yapılacak bir çekme işlemi, yeni birleştirme katkısın indirecek ve geçmiş şu şekilde görünecektir:

Her iki tematik dalı birleştirdikten sonra Jessica’nın geçmişi.
Görsel 68. Her iki tematik dalı birleştirdikten sonra Jessica’nın geçmişi.

Birçok ekibin Git’e geçme sebebi, paralel işleyen farklı dallar üzerindeki eşzamanlı çalışmaları sürecin sonunda rahatça birleştirme yeteneğidir. Bir takımın daha küçük alt gruplarının, tüm ekibi dâhil etmek veya engellemek zorunda kalmadan uzak dallar aracılığıyla işbirliği yapabilme yeteneği, Git’in büyük bir avantajıdır. Burada gördüğünüz iş akışı bunu göstermektedir:

Yönetilen ekip iş akışının temel sıralaması.
Görsel 69. Yönetilen ekip iş akışının temel sıralaması.

Çatallanmış Açık Projeler

Açık (herkese açık kaynak kodlu) projelere katkı sağlamak biraz farklıdır. Projedeki dalları doğrudan güncelleme izniniz olmadığı için, çalışmanızı yürütücülere (maintainer) başka bir şekilde ulaştırmalısınız. Bu ilk örnek, çatal oluşturma imkanı sunan Git barındırma siteleri üzerinden katkı sağlama sürecini açıklar. GitHub, BitBucket, repo.or.cz ve benzeri birçok barındırma sitesi bunu destekler ve birçok proje yürütücüsü bu tarz bir katkı bekler. Sonraki bölüm, katkı sağlanan yamaların e-posta aracılığıyla kabul edildiği projeleri ele alır.

İlk olarak ana repoyu kopyalamanız gerekmektedir. Ardından katkıda bulunmayı planladığınız yama veya yama dizisi için bir tematik dal oluşturacak ve çalışmanızı burada yapacaksınız. Temel olarak bu sıralama şöyle görünür:

$ git clone <url>
$ cd project
$ git checkout -b featureA
  ... work ...
$ git commit
  ... work ...
$ git commit

İşinizi tek katkı işleyecek şekilde sıkıştırmak veya yamayı inceleyecek bakım görevlisinin işini kolaylaştırmak amacıyla işi katkılar halinde yeniden düzenlemek için rebase -i komutunu kullanmak isteyebilirsiniz. Etkileşimli temelleme (interactive rebasing) hakkında daha fazla bilgi için Geçmişi Yeniden Yazma bölümüne bakabilirsiniz.

Daldaki çalışmanız bittiğinde ve bunu yürütücülere katkı olarak göndermeye hazır olduğunuzda, orijinal proje sayfasına gidin ve "Fork" düğmesine tıklayarak, kendi yazılabilir çatalınızı oluşturun. Ardından, bu repo URL’sini yerel reponuzun yeni bir uzak reposu olarak eklemelisiniz. Hadi ona myfork adını verelim:

$ git remote add myfork <url>

Sonra, yeni çalışmanızı bu repoya göndermeniz gerekir. Çalıştığınız tematik dalınızı çatallamış olduğunuz depoya göndermek, onu master dalınıza birleştirip ardından da itmekten daha kolaydır. Bunun nedeni, çalışmanızın kabul edilmemesi veya ayıklanması (cherry-pick) durumunda ana dalınızı geri sarmanız gerekmemesidir (Git cherry-pick işlemi Temelleme ve Ayıklama (Cherry-Picking) İş Akışları bölümünde daha ayrıntılı olarak ele alınmıştır). Eğer yürütücüler çalışmanızı birleştirir, yeniden temeller veya ayıklarsa, çalışmanızı onların reposundan çekerek alabilirsiniz.

Her durumda, çalışmanızı şu şekilde itebilirsiniz:

$ git push -u myfork featureA

Çalışmanız reponun size ait çatalına itildikten sonra, orjinal projenin yürütücülerini çalışmanızı birleştirmelerini istediğinize dair bilgilendirmelisiniz. Bu genellikle bir çekme isteği (pull request) olarak adlandırılır ve genellikle web sitesi üzerinden oluşturulur (GitHub’ın kendi "Çekme İsteği" mekanizması vardır, bu konuyu GitHub bölümünde ele alacağız) ya da git request-pull komutunu çalıştırıp ardından üretilen çıktıyı proje yürütücüsüno manuel olarak e-posta yoluyla gönderebilirsiniz.

git request-pull komutu, tematik dalınızı çekmek istediğiniz temel dalı ve çekilmesini istediğiniz Git deposunun URL’sini alır ve çekilecek tüm değişikliklerin bir özetini üretir. Örneğin, Jessica’nın John’a bir çekme isteği göndermek istediğini ve yeni gönderdiği tema dalında iki değişiklik yaptığını varsayalım, bu durumda şunu çalıştırabilir:

$ git request-pull origin/master myfork
The following changes since commit 1edee6b1d61823a2de3b09c160d7080b8d1b3a40:
Jessica Smith (1):
        added a new function

are available in the git repository at:

  git://githost/simplegit.git featureA

Jessica Smith (2):
      add limit to log function
      change log output to 30 from 25

 lib/simplegit.rb |   10 +++++++++-
 1 files changed, 9 insertions(+), 1 deletions(-)

Katkıların özetini gösteren, çalışmanın nereden dallandığını ve yeni çalışmanın nereden çekileceğini belirten bu çıktı, yürütücüye gönderilebilir.

Yürütücü olmadığınız bir projede, genellikle origin/master ı izleyen master gibi bir dalın bulunması ve çalışmanızı, reddedilmesi durumunda kolayca silebileceğiniz, tematik dallar üzerinde yapmanız daha kolay olur. İş paketlerinin tematik dallara — kök daldan izole şekilde — kısıtlanması, çalıştığınız süre zarfında ana repo ucunun ilerlemiş olması ve sizin katkılarınızın artık temiz bir şekilde uygulanamaması durumunda da işinizi yeniden düzenlemenizi kolaylaştırır. Örneğin, projeye ikinci bir iş başlığı göndermek istiyorsanız, zaten yukarı itilmiş olan tematik dalda çalışmaya devam etmeyin; ana repo master dalından tekrar başlayın:

$ git checkout -b featureB origin/master
  ... work ...
$ git commit
$ git push myfork featureB
$ git request-pull origin/master myfork
  ... email generated request pull to maintainer ...
$ git fetch origin

Artık her bir başlığımız, yama kuyruğunda (patch queue) olduğu gibi: yeniden yazabileceğiniz, temelleyebileceğiniz ve başka konu başlıklarından bağımsız ve birbirini etkilemeden değiştirebileceğiniz bir iş ambarı içinde bulunuyor. Şunun gibi:

`featureB` çalışmasının öncel katkı geçmişi.
Görsel 70. featureB çalışmasının öncel katkı geçmişi.

Diyelim ki, yürütücü birçok başka yamayı çekmiş ve sizin ilk dalınızı çekmeyi de denemiş, ancak artık temiz bir şekilde birleşmiyor. Bu durumda, bu dalı origin/master'ın üzerine temellemeyi deneyebilir ve yürütücü için çatışmaları çözüp, ardından değişikliklerinizi yeniden gönderebilirsiniz.

$ git checkout featureA
$ git rebase origin/master
$ git push -f myfork featureA

Bu, şimdi geçmişinizi featureA çalışmasından sonra katkı geçmişi. gibi yeniden yazar.

`featureA` çalışmasından sonra katkı geçmişi.
Görsel 71. featureA çalışmasından sonra katkı geçmişi.

Dalı yeniden temellendirdiniz; bu yüzden sunucudaki featureA dalını, kendi soyundan gelmeyen bir katkıyla değiştirebilmek için itme komutunuza -f bayrağı eklemelisiniz. Başka bir alternatif ise, bu yeni çalışmayı sunucuda farklı (mesela featureAv2 olarak adlandırılmış) bir dala itmektir.

Bir başka olası senaryoya bir göz atalım: yürütücü ikinci dalınızdaki çalışmayı inceledi ve yaklaşımınızı beğendi, ancak uygulamadi bir detayı değiştirmenizi istiyor. Bu fırsatı, çalışmanın projenin mevcut master dalına dayandırılmasını sağlamak için de kullanacaksınız. Mevcut origin/master dalına dayanan yeni bir dal başlatırsınız; burada featureB değişikliklerini birleştirir, çatışmaları çözer, uygulama değişikliğini yapar ve ardından bunu yeni bir dal olarak itersiniz:

$ git checkout -b featureBv2 origin/master
$ git merge --squash featureB
  ... change implementation ...
$ git commit
$ git push myfork featureBv2

--squash seçeneği birleştirilen dal üzerindeki tüm çalışmayı alır ve bunu bir birleştirme katkısı oluşturmadan - ama gerçek bir birleştirme gerçekleştiğinde oluşan bir repo durumu üretecek şekilde - bir değişiklik kümesine sıkıştırır. Bunun anlamı, gelecekteki birleştirme katkınızın yalnızca bir önceli olmasıdır. Ayrıca, diğer dalın tüm değişikliklerini tanıtmanıza ve ardından yeni bir katkı işlemine geçmeden önce daha fazla değişiklik yapmanıza izin verir Ek olarak, varsayılan birleştirme işlemi durumunda, birleştirme katkısını geciktirmek için --no-commit seçeneğini kullanabilirsiniz.

Bu noktada, istenen değişiklikleri yaptığınızı ve bu değişikliklere featureBv2 dalından ulaşabileceklerini proje yürütücüsüne bildirebilirsiniz.

`featureBv2` çalışmasının ardından katkı geçmişi.
Görsel 72. featureBv2 çalışmasının ardından katkı geçmişi.

E-posta Üzerinden Açık Projeler

Çok sayıda proje, yamaları kabul etmek için belirlenmiş yönergeler kullanır. Bunlar birbirinden farklılık göstereceği için, her proje için bu yönergeleri kontrol etmeniz gerekecektir. Yamaları geliştirici posta listesi üzerinden kabul eden birkaç eski ve büyük proje olduğundan, şimdi bir örnekle bunu ele alacağız.

Bu iş akışı, bir önceki kullanım durumuna benzer; üzerinde çalıştığınız her yama serisi için tematik dallar oluşturursunuz. Fark, onları projeye nasıl gönderdiğinizdedir. Projeyi çatallayıp kendi yazılabilir sürümünüze itmek yerine, her bir katkı serisinin e-posta sürümlerini oluşturur ve geliştirici posta listesine e-posta olarak gönderirsiniz:

$ git checkout -b topicA
  ... work ...
$ git commit
  ... work ...
$ git commit

Şimdi posta listesine göndermek istediğiniz iki katkınız var. Geliştirici listesine e-posta olarak gönderebileceğiniz mbox biçimli dosyalar oluşturmak için git format-patch komutu kullanırsınız. Bu komut her katkıyı; ilk satırı e-postanın başlık kısmına ve geri kalan mesaj ve yama da e-postanın gövde kısmına denk düşen bir e-posta’ya dönüştürür. Bu yöntemin güzel yanı: format-patch ile oluşturulan bir e-postadan yama uygulayarak, tüm katkı bilgilerinin düzgün bir şekilde korunmasıdır.

$ git format-patch -M origin/master
0001-add-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch

format-patch komutu oluşturduğu yama dosyalarının isimlerini yazdırır. -M bayrağı Git’e yeniden adlandırmaları aramasını söyler. Dosyalar en sonda şöyle görünür:

$ cat 0001-add-limit-to-log-function.patch
From 330090432754092d704da8e76ca5c05c198e71a8 Mon Sep 17 00:00:00 2001
From: Jessica Smith <jessica@example.com>
Date: Sun, 6 Apr 2008 10:17:23 -0700
Subject: [PATCH 1/2] add limit to log function

Limit log functionality to the first 20

---
 lib/simplegit.rb |    2 +-
 1 files changed, 1 insertions(+), 1 deletions(-)

diff --git a/lib/simplegit.rb b/lib/simplegit.rb
index 76f47bc..f9815f1 100644
--- a/lib/simplegit.rb
+++ b/lib/simplegit.rb
@@ -14,7 +14,7 @@ class SimpleGit
   end

   def log(treeish = 'master')
-    command("git log #{treeish}")
+    command("git log -n 20 #{treeish}")
   end

   def ls_tree(treeish = 'master')
--
2.1.0

Ayrıca, katkı mesajında görünmesini istemediğiniz e-posta listesi için daha fazla bilgi ekleyerek bu yama dosyalarını düzenleyebilirsiniz. Eğer --- satırı ve yama başlangıcı (diff --git satırı) arasına metin eklerseniz, geliştiriciler bunu okuyabilir; ancak bu içerik yamalama işlemi tarafından yok sayılır.

Bir posta listesine e-posta göndermek için, ya dosyayı e-posta içeriğinize kopyala-yapıştır yoluyla ekler ya da komut satırı aracılığıyla gönderebilirsiniz. Metni yapıştırmak - özellikle yeni satır ve diğer boşlukları uygun şekilde korumayan "akıllı" istemcilerde - biçimlendirme sorunlarına neden olabilir. Neyse ki Git’in sağladığı, doğru biçimlendirilmiş yamaları IMAP aracılığıyla göndermenize yardımcı olacak bir araç, size kolaylık sağlayabilir. En iyi bildiğimiz e-posta aracısı olan Gmail üzerinden bir yamanın nasıl gönderileceğini size göstereceğiz. Git kaynak kodunda yer alan Documentation/SubmittingPatches dosyasının sonunda, farklı e-posta programları için yazılmış detaylı yönergeleri okuyabilirsiniz.

İlk olarak, ~/.gitconfig dosyanızdaki imap bölümünü yapılandırmanız gerekir. Her bir değeri ayrı ayrı git config komutlarıyla ayarlayabilir veya bunları manuel olarak ekleyebilirsiniz; ancak sonunda yapılandırma dosyanız şuna benzer bir şekilde olmalıdır:

[imap]
  folder = "[Gmail]/Drafts"
  host = imaps://imap.gmail.com
  user = user@gmail.com
  pass = YX]8g76G_2^sFbd
  port = 993
  sslverify = false

IMAP sunucunuz SSL kullanmıyorsa, muhtemelen son iki satıra ihtiyacınız olmayacak ve host değeri imap:// yerine imaps:// olacaktır. Bunu ayarladıktan sonra, git imap-send komutunu kullanarak belirtilen IMAP sunucusunun Taslaklar klasörüne yama serisini yerleştirebilirsiniz:

$ cat *.patch |git imap-send
Resolving imap.gmail.com... ok
Connecting to [74.125.142.109]:993... ok
Logging in...
sending 2 messages
100% (2/2) done

Bu aşamada, Taslaklar klasörüne giderek, "Alıcı" alanını gönderdiğiniz yama serisinin e-posta listesine göre ayarlayabilir ve gerekirse proje yürütücüsünü veya ilgili kişiyi "CC" olarak ekleyebilirsiniz. Artık e-postanızı göndermeye hazırsınız.

Ayrıca yamaları bir SMTP sunucusu aracılığıyla da gönderebilirsiniz. Aynı yukarıda olduğu gibi, her değeri ayrı ayrı git config komutlarıyla ayarlayabilir veya ~/.gitconfig dosyanızdaki "sendemail" bölümüne manuel olarak ekleyebilirsiniz:

[sendemail]
  smtpencryption = tls
  smtpserver = smtp.gmail.com
  smtpuser = user@gmail.com
  smtpserverport = 587

Bunu yaptıktan sonra, yamalarınızı göndermek için git send-email komutunu kullanabilirsiniz:

$ git send-email *.patch
0001-added-limit-to-log-function.patch
0002-changed-log-output-to-30-from-25.patch
Who should the emails appear to be from? [Jessica Smith <jessica@example.com>]
Emails will be sent from: Jessica Smith <jessica@example.com>
Who should the emails be sent to? jessica@example.com
Message-ID to be used as In-Reply-To for the first email? y

Sonra, Git gönderdiğiniz her bir yaman için şöyle bir günlük bilgisi çıkarır:

(mbox) Adding cc: Jessica Smith <jessica@example.com> from
  \line 'From: Jessica Smith <jessica@example.com>'
OK. Log says:
Sendmail: /usr/sbin/sendmail -i jessica@example.com
From: Jessica Smith <jessica@example.com>
To: jessica@example.com
Subject: [PATCH 1/2] added limit to log function
Date: Sat, 30 May 2009 13:29:15 -0700
Message-Id: <1243715356-61726-1-git-send-email-jessica@example.com>
X-Mailer: git-send-email 1.6.2.rc1.20.g8c5b.dirty
In-Reply-To: <y>
References: <y>

Result: OK

Özet

Bu bölüm, karşılaşabileceğiniz birkaç farklı Git projesi türüyle başa çıkmanın yaygın iş akışlarını anlattı ve bu süreci yönetmenize yardımcı olacak birkaç yeni aracı tanıttı. Şimdi, işin diğer yüzüyle nasıl çalışılacağını göreceksiniz: Bir Git projesini yürütmek. Bir hayırsever diktatör veya birleştirme yöneticisi olmayı öğreneceksiniz.

scroll-to-top