Git
Chapters ▾ 2nd Edition

5.3 Dağıtık Git - Bir Projeyi Yürütme

Bir Projeyi Yürütme

Projeye katkı sağlamanın yanı sıra genellikle bilmeniz gereken bir diğer beceri de Bir projeyi etkili bir şekilde yürütmektir. Bu format-patch ile oluşturulan ve size e-posta yoluyla gönderilen yamaları kabul etmek ve uygulamak veya eklediğiniz uzak dallardaki değişiklikleri projenize birleştirmekten oluşabilir. İster klasik bir repoyu yürütüyor olun, ister yamaları doğrulayarak veya onaylayarak projeye yardımcı olun; diğer katkıda bulunanlar için en açık ve sizin için uzun vadede en sürdürülebilir kabul yöntemini bilmeniz gerekir.

Tematik Dallarda Çalışma

Yeni bir çalışmayı birleştirmeyi düşündüğünüzde, sırf bunu denemek için geçici bir tematik dal oluşturmak iyi bir fikirdir. Bu şekilde, bir yamanın detaylarını bireysel olarak ayarlamak ve işe yaramıyorsa daha sonra geri dönmek üzere bir kenara ayırmak için zamanınız olur. Denemeyi yapacağınız işin konusuna dayanan basit ve açıklayıcı bir dal adı oluşturursanız (ör. ruby_client vb); bir süre terk edip daha sonra geri dönmek zorunda kalırsanız, kolaylıkla hatırlayabilirsiniz.

Git projesinin yürütücüsü de genellikle bu dalları isimlendirir (ör. sc/ruby_client. Surada sc çalışmayı ekleyen kişinin kısaltmasıdır). Hatırlayacağınız gibi, bunu master dalınızdan şu şekilde oluşturabilirsiniz:

$ git branch sc/ruby_client master

Veya doğrudan o dala geçmek istiyorsanız, checkout -b seçeneğini kullanabilirsiniz:

$ git checkout -b sc/ruby_client master

Şimdi aldığınız çalışmayı bu tematik dala eklemeye hazırsınız ve onu daha uzun vadeli dallarınıza birleştirip birleştirmeyeceğinize karar verebilirsiniz.

E-Postadan gelen Yamaları Uygulamak

E-posta yoluyla alınan bir yamayı projenize birleştirmeniz gerekiyorsa, yamayı test etmek için tematik dalınıza uygulamanız gerekir. E-postayla gönderilen bir yamayı uygulamanın iki yolu vardır: git apply ve git am.

Bir Yamayı apply ile Uygulamak

Eğer birisi yamayı git diff veya Unix’un diff komutunun bir türevi ile oluşturduysa (ki bir sonraki bölümde göreceğiniz üzere bu önerilmez), yamayı git apply komutu ile uygulayabilirsiniz. Yamayı /tmp/patch-ruby-client.patch dosyasına kaydettiğinizi farzedersek, şu şekilde uygulayabilirsiniz:

$ git apply /tmp/patch-ruby-client.patch

Bu, çalışma dizininizdeki dosyaları değiştirir. Bir yama uygulamak için patch -p1 komutunu çalıştırmakla neredeyse aynıdır; ancak daha paranoiddir ve patch’e göre daha az belirsiz eşleşme (fuzzy match) kabul eder. Ayrıca, git diff formatında açıklanmış dosya ekleme, silme ve yeniden adlandırma işlemlerini, patch 'in yapmayacağı şekilde ele alır. Son olarak, git apply uygulamanızda "tümünü uygula" veya "hiçbirini uygulama" kararını vermeniz gereken bir modelidir: patch ise yamaları kısmen uygulayabilir ve çalışma dizenizi tuhaf bir durumda bırakabilir. git apply genel olarak patch 'den çok daha katı davranır. Size bir katkı kaydı oluşturmaz: çalıştırdıktan sonra, değişiklikleri elle aşamalandırmanız ve katkı işlemeniz gerekir.

git apply komutunu, bir yamayı gerçekten uygulamadan önce, düzgün bir şekilde uygulanıp uygulanamayacağını kontrol etmek için de kullanabilirsiniz. Bunun için git apply --check komutu yamayla birlikte çalıştırabilirsiniz.

$ git apply --check 0001-seeing-if-this-helps-the-gem.patch
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply

Eğer çıktı yoksa, yama temiz bir şekilde uygulanabilir demektir. Bu komut ayrıca, kontrolün başarısız olduğu durumlarda da sonucu sıfır olmayan bir durumla (non-zero status) çıkar, bu nedenle isterseniz bu komutu betiklerde de kullanabilirsiniz.

git am Komutuyla Yama Uygulama

Eğer geliştirici yamasını oluşturmak için format-patch komutunu kullanacak tecrübede bir Git kullanıcısıysa; yama yazar bilgisi ve bir katkı mesajı da içereceği için, işiniz daha kolay olur. Mümkünse, geliştiricilerinizi yamalarını oluşturmak için diff yerine format-patch kullanmaları yönünde teşvik edin. Yalnızca eski yamalar (legacy patch) ve benzeri durumlar için git apply kullanmanız gerekir.

format-patch ile oluşturulan bir yamayı uygulamak için git am ("bir posta kutusundan bir dizi yamayı uygulamak" için bu komut kullanıldığından am olarak adlandırılır) kullanılır. git am komutu teknik olarak, bir veya daha fazla e-posta mesajını tek bir metin dosyasında depolamak için oluşturulan basit bir düz-metin biçimi olan "mbox" dosyasını okumak amacıyla oluşturulmuştur. Ve şuna benzer:

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

Bu, önceki bölümde gördüğünüz git format-patch komutunun çıktısının başlangıcıdır; aynı zamanda geçerli bir mbox e-posta biçimini temsil eder. Eğer biri size yamayı git send-email komutunu kullanarak düzgün şekilde e-posta ile gönderdiyse; ve siz de bunu mbox biçiminde indirir ve git am 'i o mbox dosyasına işaret edecek şekilde ayarlarsanız; gördüğü tüm yamaları uygulamaya başlayacaktır. Eğer bir mbox formatında birkaç e-postayı kaydedebilen bir posta istemcisi çalıştırıyorsanız, tüm yama serilerini bir dosyaya kaydedip, bunların hepsini tek seferde uygulamak için git am 'i kullanabilirsiniz.

Ancak, birisi git format-patch kullanarak oluşturulan bir yama dosyasını bir bilet sistemi veya benzer bir yere yüklediyse; bu dosyayı yerel olarak kaydedip, ardından diskte kaydedilen bu dosyayı uygulamak için git am 'e iletebilirsiniz:

$ git am 0001-limit-log-function.patch
Applying: add limit to log function

Gördüğünüz gibi, temiz bir şekilde uygulandı ve otomatik olarak yeni bir katkı oluşturuldu. Yazar bilgileri, e-postanın From (gönderici) ve Date (tarih) başlıklarından; katkı mesajı, e-postanın Subject (konu) ve yamadan önceki gövde kısmından alınır. Örneğin, yukarıdaki mbox örneğinden uyarlanan bir yama için oluşturulan katkı şöyle görünecektir:

$ git log --pretty=fuller -1
commit 6c5e70b984a60b3cecd395edd5b48a7575bf58e0
Author:     Jessica Smith <jessica@example.com>
AuthorDate: Sun Apr 6 10:17:23 2008 -0700
Commit:     Scott Chacon <schacon@gmail.com>
CommitDate: Thu Apr 9 09:19:06 2009 -0700

   add limit to log function

   Limit log functionality to the first 20

Commit (katkı) bilgileri yamayı uygulayan kişiyi ve uygulanma zamanını gösterir. Author (yazar) bilgileri ise özgün yamayı oluşturan kişiyi ve ne zaman oluşturduğunu gösterir.

Ama yamanın temiz bir şekilde uygulanamaması ihtimal dahilindedir. Belki ana dalınız, yamanın oluşturulduğu daldan çok uzaklaşmıştır veya yama henüz uygulamadığınız başka bir yamaya bağlıdır. Bu durumda, git am işlemi başarısız olacak ve ne yapmak istediğinizi size soracaktır:

$ git am 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Patch failed at 0001.
When you have resolved this problem run "git am --resolved".
If you would prefer to skip this patch, instead run "git am --skip".
To restore the original branch and stop patching run "git am --abort".

Bu komut, sorun yaşadığı dosyalara "çatışan birleştirme" veya "yeniden temelleme işlemi" gibi çatışma işaretçileri koyar. Bu sorunu çözmenin yolu neredeyse aynıdır: dosyayı çatışmayı çözecek şekilde düzenleyin, yeni dosyayı hazırlayın ve ardından bir sonraki yamaya devam etmek için git am --resolved komutunu çalıştırın:

$ (fix the file)
$ git add ticgit.gemspec
$ git am --resolved
Applying: seeing if this helps the gem

Eğer Git’in çatışmayı biraz daha akıllıca çözmesini istiyorsanız -3 seçeneğini kullanarak, Git’in üç yollu bir birleştirme yapmayı denemesini sağlarsınız. Yama üzerindeki işlenecek olan katkı, sizin reposunuzda bulunmuyorsa çalışmayacağı için, bu seçenek varsayılan olarak etkinleştirilmemiştir. Eğer o katkı sizin reposunuzda mevcutsa (eğer yama bir halka açık katkıya dayanıyorsa), o zaman -3 seçeneği genellikle bir çatışmalı yamanın uygulanması konusunda daha akıllıdır:

$ git am -3 0001-seeing-if-this-helps-the-gem.patch
Applying: seeing if this helps the gem
error: patch failed: ticgit.gemspec:1
error: ticgit.gemspec: patch does not apply
Using index info to reconstruct a base tree...
Falling back to patching base and 3-way merge...
No changes -- Patch already applied.

Yukarıdaki durumda -3 seçeneği olmasaydı, yama bir çatışma olarak kabul edilirdi. -3 seçeneği kullanıldığı için temiz bir şekilde uygulandı.

Eğer bir mbox’tan bir dizi yama uyguluyorsanız; her bulduğu yamada durup, onu uygulamak isteyip istemediğinizi soran, etkileşimli am komutunu da çalıştırabilirsiniz:

$ git am -3 -i mbox
Commit Body is:
--------------------------
seeing if this helps the gem
--------------------------
Apply? [y]es/[n]o/[e]dit/[v]iew patch/[a]ccept all

Eğer kaydedilmiş birkaç yamanız varsa ve hangilerini zaten uyguladığınızı veya uygulayacağınızı hatırlayamıyorsanız; öncesinde yamayı görmenize olanak sağladığı için, bu özellik oldukça kullanışlıdır.

Bir tema için tüm yamalar uygulandığında ve dalınıza katkı olarak işlendiğinde, bunları uzun vadeli çalışan bir dala birleştirip birleştirmeyeceğinizi veya nasıl birleştireceğinizi seçebilirsiniz.

Uzak Dallara Geçmek

Eğer bu katkı; kendi reposunu kuran, bir dizi değişiklik yapıp, buraya iten ve ardından değişikliklerin URL’sini ve değişikliklerin bulunduğu uzak dalın adını size gönderen bir Git kullanıcısından geldiyse, onları bir uzak repo olarak ekleyebilir ve yerel olarak birleştirebilirsiniz.

Örneğin, Jessica size kendi reposunun ruby-client dalında harika bir yeni özellik olduğunu söyleyen bir e-posta gönderirse; onun uzak reposunu ekleyip, bu yerelde dala geçiş yaparak, bu özelliği test edebilirsiniz:

$ git remote add jessica git://github.com/jessica/myproject.git
$ git fetch jessica
$ git checkout -b rubyclient jessica/ruby-client

Daha sonra, size başka bir harika özelliğe sahip başka bir dalı içeren yeni bir e-posta gönderirse, zaten uzak sunucuyu kurduğunuz için doğrudan fetch ve checkout yapabilirsiniz.

Biriyle sürekli birlikte çalışıyorsanız en kullanışlı olan yöntem budur. Eğer birisi arada bir ve sadece tek bir yama eklemek istiyorsa, o zaman bu değişiklikleri e-posta yoluyla kabul etmek, herkesin kendi sunucusunu çalıştırmasından ve birkaç yama almak için sürekli olarak uzak sunucular ekleyip, kaldırmasından daha tasarruflu bir zaman yönetimidir. Ayrıca, muhtemelen yalnızca bir veya iki yama sağlayan herkes için yüzlerce uzak sunucu eklemek istemezsiniz. Her ne kadar, betikler ve barındırılan hizmetler bu işi kolaylaştırabilse de, bu büyük ölçüde sizin ve katkı sağlayan geliştiricilerin nasıl geliştirme yaptığına bağlıdır.

Bu yaklaşımın bir diğer avantajı ise geçmişini de almanızdır. Geçerli birleştirme sorunlarına sahip olabilseniz dahi, bu çalışmalarının geçmişinizde nerede olduğunu bilirsiniz. Varsayılan olarak sağlanan düzgün bir üç yollu birleştirme, -3 sağlamak zorunda kalmaktan ve yamanın erişiminiz olan herkese açık bir katkıya dayanmasını ummaktan iyidir.

Eğer sürekli olarak bir kişiyle çalışmıyor ama yine de yamayı onlardan bu şekilde çekmek istiyorsanız, git pull komutuna uzak repo URL’sini girebilirsiniz. Bu, tek seferlik bir çekme işlemi yapar ama URL’yi uzak bir referans olarak kaydetmez:

$ git pull https://github.com/onetimeguy/project
From https://github.com/onetimeguy/project
 * branch            HEAD       -> FETCH_HEAD
Merge made by the 'recursive' strategy.

Katkıları Tanımlamak

Şimdi, üzerinde katkı yapılan bir tematik dalınız var. Bu noktada, onunla ne yapmak istediğinizi belirleyebilirsiniz. Bu bölümde, ana dalınıza bir yamayı birleştirdiğinizde, tam olarak neyi tanıtacağınızı incelemek için birkaç komutu tekrar ele alacağız.

Tematik dalda olan, ancak ana dalınızda olmayan tüm katkıların gözden geçirilmesinde fayda vardır. Ana dalınızda bulunan katkıları bundan hariç tutmak için --not seçeneğini dal adının önüne ekleyebilirsiniz. Bu, daha önce kullandığımız master..contrib biçimiyle aynı işlemi yapar. Örneğin, katkılayıcınız size iki yama gönderirse ve siz contrib adında bir dal oluşturup bunları oraya uygularsanız, şunu çalıştırabilirsiniz:

$ git log contrib --not master
commit 5b6235bd297351589efc4d73316f0a68d484f118
Author: Scott Chacon <schacon@gmail.com>
Date:   Fri Oct 24 09:53:59 2008 -0700

    seeing if this helps the gem

commit 7482e0d16d04bea79d0dba8988cc78df655f16a0
Author: Scott Chacon <schacon@gmail.com>
Date:   Mon Oct 22 19:38:36 2008 -0700

    updated the gemspec to hopefully work better

Hatırlayacağınız üzere her katkının hangi değişiklikleri içerdiğini görmek için, git log komutuna -p seçeneğini ekleyebilirsiniz. Ayrıca her katkıyla gelen fark da gösterilecektir.

Ana dal ve tematik dalı birleştirirseniz kodda ne gibi farklılıklar olacağının tam bir resmini görmek isterseniz, doğru sonuçları elde etmek için garip bir hile kullanmanız gerekebilir. Şunu çalıştırmayı düşünebilirsiniz:

$ git diff master

Bu komut size bir fark gösterir, ancak sonuç yanıltıcı olabilir. Eğer master dalınız, tematik dalınızı oluşturduğunuzdan bu yana ilerlemişse, çok garip sonuçlar elde edebilirsiniz. Bunun sebebi, Git’in üzerinde bulunduğunuz tema dalındaki son katkının pozuyla, master dalındaki son katkının pozunu doğrudan karşılaştırmasıdır. Örneğin, master dalındaki bir dosyaya bir satır eklerseniz; pozların doğrudan karşılaştırılması, tematik dalın bu satırı kaldıracakmış gibi görünmesine neden olur.

Eğer master dalı tematik dalınızın doğrudan bir atası ise, bu bir sorun değildir; ancak eğer iki geçmiş ayrıldıysa, fark master dalına özgü olan her şeyi kaldırıyor ve tema dalınızdaki tüm yeni şeyleri ekliyormuş gibi görünecektir.

Gerçekte görmek istediğiniz şey, konu dalına eklenen değişikliklerdir, yani bu dalı ana dala birleştirdiğinizde getireceğiniz çalışma. Bunu görmek için, Git’in tema dalınızın son katkısını, master üzerindeki ilk ortak atasıyla karşılaştırması neticesinde görebilirsiniz.

Teknik olarak bunu yapmanın yolu: ortak atayı açıkça bulup ardından diff’i üzerinde çalıştırmaktır:

$ git merge-base contrib master
36c7dba2c95e6bbb78dfa822519ecfec6e1ca649
$ git diff 36c7db

or, more concisely:

$ git diff $(git merge-base contrib master)

Yine de bunlar özellikle kullanışlı yöntemler değil, bu yüzden Git aynı işi yapmak için başka bir kısaltma sağlar: üç nokta sözdizimi. git diff komutu bağlamında: diff yapmak için üzerinde bulunduğunuz dalın son katkısı ile başka bir dalın son ortak atası arasına üç nokta (…​) koyabilirsiniz:

$ git diff master...contrib

Bu komut, mevcut tema dalınızın, master ile ortak atasından bu yana getirdiği çalışmayı gösterir. Bu akılda tutmaya değer ve çok kullanışlı bir sözdizimidir.

Katkılanan İşi Birleştirmek

Tema dalınızdaki tüm çalışma, ana dala daha yakın bir dala birleştirilmeye hazır olduğunda, sıradaki soru bunun nasıl yapılacağıdır. Bunun da ötesinde, projenizi yürütmek için hangi genel iş akışını kullanmak istiyorsunuz? Şimdi elinizdeki pek çok seçenekten birkaçını ele alacağız.

İş Akışlarını Birleştirmek

En temel iş akışı, tüm çalışmayı doğrudan master dalınıza birleştirmektir. Bu senaryoda, kararlı kodu içeren bir master dalınız bulunmaktadır. Tematik dalda tamamlandığını düşündüğünüz veya bir başkasının katkıda bulunduğu ama sizin onayladığınız bir çalışma varsa, bunu ana dalınıza birleştirir ve artık ihtiyaç duymadığınız tema dalını silersiniz. Bu süreci her defasında tekrar edersiniz.

Örneğin, ruby_client ve php_client adlı iki dalında çalışma yapılan Bir kaç tematik dallı bir geçmiş. gibi bir repomuz olduğunu varsayalım. Eğer, önce ruby_client ve ardından da php_client dalını birleştirirsek, geçmişiniz Bir tema dalını birleştirdikten sonrası. gibi görünecektir.

Bir kaç tematik dallı bir geçmiş.
Görsel 73. Bir kaç tematik dallı bir geçmiş.
ABir tema dalını birleştirdikten sonrası.
Görsel 74. Bir tema dalını birleştirdikten sonrası.

Bu muhtemelen en basit iş akışıdır; ancak neyi değiştirdiğinize çok dikkat ettiğiniz, daha büyük ve istikrarlı projelerle uğraşıyorsanız, sorun yaşayabilirsiniz.

Daha önemli bir projeniz varsa, iki aşamalı bir birleştirme döngüsü kullanmak isteyebilirsiniz. Bu senaryoda, sadece çok kararlı bir sürüm çıktığında güncellenecek olan master ve her yeni kodunuzu üzerinde geliştirip denediğiniz develop adında, iki adet uzun ömürlü dalınız var:

Her iki dalı da düzenli olarak açık reponuza (public repository) itiyorsunuz. Birleştirilecek yeni bir tema dalınız olduğunda (Tema dalı birleşmesi öncesi.), bunu develop dalına birleştirirsiniz (Tema dalı birleşmesi sonrası.); ardından, yeni bir sürüm etiketlediğinizde, master dalını ileri sararak (fast-forward) şu anda istikrarlı olan develop dalını bulunduğu yere getirirsiniz (Yeni sürüm sonrası.).

Tema dalı birleşmesi öncesi.
Görsel 75. Tema dalı birleşmesi öncesi.
Tema dalı birleşmesi sonrası.
Görsel 76. Tema dalı birleşmesi sonrası.
Yeni sürümü sonrası.
Görsel 77. Yeni sürüm sonrası.

Bu şekilde, insanlar reponuzu kopyaladığında; ya en son "kararlı" sürümü derlemek ve bunu kolayca güncellemek için master dalına geçebilir ya da daha en "güncel" içeriği içeren develop dalına. Ayrıca, tüm çalışmaların birleştirildiği bir integrate dalı oluşturarak bu anlayışı genişletebilirsiniz. Bu dal üzerindeki kod tabanı kararlı hale gelip, testleri geçtiğinde, bunu bir develop dalına birleştirebilirsiniz; ve burada kararlı durumu kanıtlandığında, master dalınızı bu noktaya doğru ileri sararsınız.

Büyük Birleştirme İş Akışı

Bu Git projesinde dört uzun ömürlü dal bulunmaktadır: master, next, yeni güncellemeler için pu (proposed updates) ve bakım geri portları için maint (maintenance). Yeni çalışma görücüye çıktığında, bunlar daha önce anlatılana benzer şekilde (bkz Çoklu paralel tema dallarının karmaşıklığını yönetmek.) yürütücünün reposundaki tema dallarına toplanır (bkz. Çoklu paralel tema dallarının karmaşıklığını yönetmek.). Bu noktada, çalışmalar, "güvenilir ve canlıya çıkmaya hazır mı, yoksa üzerinde biraz daha çalışılması mı gerekiyor" kararı verilmek üzere değerlendirilirler. Güvenilir olanlar next dalına birleştirilir ve bu dal herkesin deneyebilmesi için yukarı itilir.

Çoklu paralel tema dallarının karmaşıklığını yönetmek.
Görsel 78. Çoklu paralel tema dallarının karmaşıklığını yönetmek.

Eğer konular halen geliştirilmeye ihtiyaç duyuyorsa, bunlar next yerine pu dalına birleştirilir. Tamamen istikrarlı oldukları belirlendiğinde, yeniden master dalına birleştirilirler. next ve pu dalları daha sonra master dalından yeniden inşa edilir. Bu, master dalının neredeyse her zaman ileri gitmesi, next dalının zaman zaman yeniden temellenmesi (rebase) ve pu dalının daha da sık yeniden temellenmesi, anlamına gelir:

Katkı sağlanan tema dallarını uzun ömürlü birleşim dallarına birleştirmek.
Görsel 79. Katkı sağlanan tema dallarını uzun ömürlü birleşim dallarına birleştirmek.

Bir tema dalı nihayet master dalına birleştirildiğinde, artık repodan kaldırılır. Git projesinin ayrıca son sürümden çatallanmış maint adlı bir bakım dalı vardır. Bu dal, bir bakım sürümü gerektiğinde geriye dönük yamalar sağlamak için kullanılır.

Bu sistemde, yürütücünün yeni katkıları değerlendirmesine yardımcı olmak için yapılandırılmış özelleştirilmiş bir iş akışı vardır. Git reposunu kopyaladığınızda, projeye nasıl katkıda bulunmak istediğinize veya geliştirme döngüsünde ne kadar ilerlemek istediğinize bağlı olarak; projenin farklı gelişim aşamalarını gözlemlemek amacıyla geçiş yapabileceğiniz, dört farklı dalınız olur. Bu iş akışını daha iyi anlamak için Git Yürütücü Kılavuzu'nu inceleyebilirsiniz.

Temelleme ve Ayıklama (Cherry-Picking) İş Akışları

Diğer yürütücüler, doğrusal bir geçmişe sahip olmak için genellikle için katkılanan çalışmaları master dalının üstüne yeniden temellemeyi (rebase) veya ayıklamayı tercih ederler. Bir tema dalında birleştirmek istediğiniz bir çalışmanız varsa, o dala geçer ve değişiklikleri mevcut master (veya develop, vb.) dalı üstüne yeniden inşa etmek için temelleme (rebase) komutunu çalıştırırsınız. Bu işlem sorunsuz tamamlanırsa, master dalınızı ileri sarabilir ve sonuçta doğrusal bir proje geçmişine sahip olursunuz.

Tanıtılan bir çalışmayı bir daldan başka bir dala taşımanın bir diğer yolu da onu ayıklamaktır. Git’te ayıklama işlemi, bir tek katkı için bir yeniden temelleme gibidir. Bir katkıyla yapılan değişiklikleri alır ve bunları şu anda bulunduğunuz dala tekrar uygulamaya çalışır. Bir tema dalında birkaç katkımız varsa ve bunları ayıklayıp yalnızca birini almak istiyorsanız veya bir tema dalında yalnızca bir katkınız varsa ve yeniden temellemek yerine bunu tercih etmek istiyorsanız, bu özellik kullanışlıdır. Örneğin, şöyle bir projeniz olduğunu varsayalım:

Ayıklama öncesi örnek geçmiş.
Görsel 80. Ayıklama öncesi örnek geçmiş.

Eğer e43a6 katkısını ana dalınıza çekmek istiyorsanız, şunu çalıştırabilirsiniz:

$ git cherry-pick e43a6
Finished one cherry-pick.
[master]: created a0a41a9: "More friendly message when locking the index fails."
 3 files changed, 17 insertions(+), 3 deletions(-)

Bu, e43a6 ile tanıtılan değişikliği çeker, ancak uygulanan tarihi farklı olduğu için yeni bir katkı SHA-1 değeri alırsınız. Artık geçmişiniz şöyle görünür:

Tema dalındaki katkı ayıklandıktan sonra geçmiş.
Görsel 81. Tema dalındaki katkı ayıklandıktan sonra geçmiş.

Şimdi tema dalınızı kaldırabilir ve içe almak istemediğiniz katkıları atabilirsiniz.

Rerere

Eğer çok sayıda birleştirme ve yeniden temelleme yapıyorsanız veya uzun ömürlü bir tema dalını sürdürüyorsanız; Git’in rerere olarak adlandırılan yardımcı bir özelliği vardır.

Rerere, "reuse recorded resolution" (kaydedilmiş çözümü yeniden kullan) anlamına gelir ve çakışmaları manuel olarak çözmeniz gerektiğinde kullanabileceğiniz kestirme bir yoldur. Rerere etkinleştirildiğinde, Git başarılı birleştirmelerin öncel ve ardıl pozlar kümesini saklar; ve eğer daha önce düzelttiğiniz bir çakışma ile tam olarak aynı görünen yeni bir çakışma fark ederse, sizi bununla meşgul etmeden, daha önceki çözümü kullanır.

Bu özellik iki kısımdan oluşur: bir yapılandırma ayarı ve bir komut. Yapılandırma ayarı rerere.enabled şeklindedir ve genel yapılandırmanıza eklemek oldukça kullanışlıdır:

$ git config --global rerere.enabled true

Böylece, çakışmaları çözen bir birleştirme yaptığınızda, bu çözüm gelecekte ihtiyaç duymanız ihtimaline binaen önbelleğe kaydedilecektir.

İhtiyacınız olduğunda, git rerere komutunu kullanarak rerere önbelleğiyle etkileşime geçebilirsiniz. Tek başına çağrıldığında; Git, çözümler veritabanını kontrol ederek, mevcut birleştirme çatışmasıyla bir eşleşme bulmaya ve bunu çözmeye çalışır (rerere.enabled yapılandırması true olarak ayarlandıysa, bu işlem otomatik olarak yapılır). Kaydedilecek ögeleri görmek, önbellekten belirli bir çözümü silmek veya tüm önbelleği temizlemek için kullanılabilecek, alt komutlar da vardır. rerere komutunu Rerere bölümünde daha detaylı olarak ele alacağız.

Sürümü Etiketlemek

Bir sürüm yayımlamaya karar verdiğinizde, bu sürümü gelecekte yeniden oluşturabilmek için etiketlemek isteyebilirsiniz. Yeni bir etiketi Git Temelleri bölümünde anlatıldığı gibi oluşturabilirsiniz. Eğer etiketi yürütücü olarak imzalamaya karar verirseniz, etiketleme işlemi şöyle görünebilir:

$ git tag -s v1.5 -m 'my signed 1.5 tag'
You need a passphrase to unlock the secret key for
user: "Scott Chacon <schacon@gmail.com>"
1024-bit DSA key, ID F721C45A, created 2009-02-09

Etiketlerinizi imzalarsanız, etiketlerinizi imzalamak için kullandığınız genel PGP anahtarını dağıtma sorunuyla karşılaşabilirsiniz. Git proje yürütücüsü, genel anahtarlarını repoya bir blob olarak dahil edip, ardından doğrudan bu içeriğe işaret eden bir etiket ekleyerek bu sorunu çözmüştür. Bunu yapmak için, gpg --list-keys komutunu çalıştırarak hangi anahtarı kullanmak istediğinizi belirleyebilirsiniz:

$ gpg --list-keys
/Users/schacon/.gnupg/pubring.gpg
---------------------------------
pub   1024D/F721C45A 2009-02-09 [expires: 2010-02-09]
uid                  Scott Chacon <schacon@gmail.com>
sub   2048g/45D02282 2009-02-09 [expires: 2010-02-09]

Daha sonra, anahtarı dışa aktarıp, bu içeriği git hash-object üzerinden yönlendirerek, anahtarı doğrudan Git veritabanına aktarabilirsiniz. Bu şekilde Git, bu içeriğe sahip yeni bir blob oluşturur ve blob’un SHA-1 değerini size geri verir:

$ gpg -a --export F721C45A | git hash-object -w --stdin
659ef797d181633c87ec71ac3f9ba29fe5775b92

Artık anahtar içeriğiniz Git’te olduğuna göre, hash-object komutunun size verdiği yeni SHA-1 değerini belirterek doğrudan ona işaret eden bir etiket oluşturabilirsiniz:

$ git tag -a maintainer-pgp-pub 659ef797d181633c87ec71ac3f9ba29fe5775b92

git push --tags komutunu çalıştırırsanız, maintainer-pgp-pub etiketi herkesle paylaşılacaktır. Bir etiketi doğrulamak isteyen biri; PGP anahtarınızı doğrudan içe aktarmak için, blob’u veritabanından çekip, GPG’ye aktarabilir:

$ git show maintainer-pgp-pub | gpg --import

Bu anahtar, imzalı tüm etiketlerinizi doğrulamak için kullanabilir. Ayrıca, etiket mesajında talimatlar eklerseniz; git show <etiket> komutuyla son kullanıcıya etiket doğrulaması hakkında daha belirli yönergeler verebilirsiniz.

Yapı Numarası Oluşturma

Git’in her katkıyla tekdüze olarak artan, v123 gibi numaraları veya benzer bir şeyi olmadığından; bir katkıyı insanlar tarafından okunabilir bir isimle eşleştirmek için, o katkı üzerinde git describe komutunu çalıştırabilirsiniz. Bunun sonucunda, Git; o katkıdan önceki en son etiketin adını, arkasından bu etiketten bu katkıya kadar işlenen katkı sayısını ve en arkaya da tanımlanan katkının kısmi SHA-1 değerini içeren bir dize oluşturur (en başa Git’i simgeleyen "g" harfi eklenir):

$ git describe master
v1.6.2-rc1-20-g8c5b85c

Bu şekilde, bir poz veya derleme oluşturup okunaklı bir isim verebilirsiniz. Aslında, eğer Git’i kendi reposundan kopyaladığınız kaynak kodundan derlemişseniz, git --version komutu size şuna benzeyen bir çıktı verir. Eğer doğrudan etiketlediğiniz bir katkıyı tanımlıyorsanız, size sadece etiket adını verir.

git describe komutu, varsayılan olarak, (-a veya -s bayrağı ile oluşturulan) dipnotlu etiketlere ihtiyaç duyar. Eğer hafif (dipnotsuz) etiketlerden de faydalanmak istiyorsanız, komuta --tags seçeneğini ekleyin. Bu dizeyi git checkout veya git show komutunun hedefi olarak da kullanabilirsiniz, ancak sonundaki kısaltılmış SHA-1 değerine dayansa da sonsuza kadar geçerli olmayabilir. Örneğin, Linux çekirdeği son zamanlarda SHA-1 nesne benzersizliğini sağlamak için 8’den 10 karaktere geçti, bu nedenle eski git describe çıktı adları geçersiz hale geldi.

Bir Sürüm Hazırlama

Diyelimk ki şimdi bir sürüm yayımlamak istiyorsunuz. Bunun için yapmanız gerekenlerden biri, Git’i kullanmayan garibanlar için kodunuzun en son pozunun bir arşivini oluşturmaktır. Bunun için git archive komutunu kullanmalısınız:

$ git archive master --prefix='project/' | gzip > `git describe master`.tar.gz
$ ls *.tar.gz
v1.6.2-rc1-20-g8c5b85c.tar.gz

Eğer birisi bu sıkıştırılmış tar dosyasını açarsa, projenizin en son pozunu bir proje dizini altına almış olur. Aynı şekilde bir zip arşivi de oluşturabilirsiniz, ancak bunu git archive komutuna --format=zip seçeneğini bağlayarak yapabilirsiniz:

$ git archive master --prefix='project/' --format=zip > `git describe master`.zip

Artık projenizin sürümünün, web sitenize yükleyebileceğiniz veya birilerine e-posta ile gönderebileceğiniz, güzel bir tar dosyası ve zip arşivi vardır.

Kısa Günlük

Artık, projenizdeki son değişiklikler hakkında bilgi sahibi olmak isteyenlere bir e-posta gönderme zamanı geldi. Son sürüm veya e-postanızdan bu yana projenizde yapılan değişiklikleri tutan değişim günlüğünü hızlıca elde etmek için git shortlog komutunu kullanabilirsiniz. Bu komut, veerdiğiniz aralıktaki tüm katkıları özetler. Örneğin, son sürümünüz v1.0.1 ise, aşağıdaki komut size son sürümünüzden bu yana yapılan tüm katkıların bir özetini verir:

$ git shortlog --no-merges master --not v1.0.1
Chris Wanstrath (6):
      Add support for annotated tags to Grit::Tag
      Add packed-refs annotated tag support.
      Add Grit::Commit#to_patch
      Update version and History.txt
      Remove stray `puts`
      Make ls_tree ignore nils

Tom Preston-Werner (4):
      fix dates in history
      dynamic version method
      Version bump to 1.0.2
      Regenerated gemspec for version 1.0.2

v1.0.1’den bu yana yapılan tüm katkıların yazarlarına göre gruplandırılmış temiz bir özet elde eder ve ardından bu özeti listenize e-posta olarak gönderebilirsiniz.

scroll-to-top