Pull Request Nedir? Nasıl Yapılır?

Herkese Merhaba,
Bu yazımızda başlığımızdan da anlaşılacağı üzere pull-request kavramını ele alacağız. Yazımız genel hatlarıyla: Pull Request nedir? ve Pull Request kaç farklı yol ile yapılır? sorularını yanıtlamaktadır. Yazıda pull request yaklaşımı Git ve GitHub servisleri ile açıklandığı için en başta bunların neler oldukları hakkında kısaca bilgi sahibi olalım ve yazımızın ana konusuna geçelim.


git logo.png

Günümüz sistemler arasında popülerliğini ve yerini sabitlemiş Git, kullanıcılara ücretsiz sunulan açık kaynaklı bir versiyon kontrol sistemidir. Git sistemi, sağladığı farklı komut yordamlarıyla — revert, push, pull, cherry-pick, rebase gibi — terminal (command line) üzerinden (açık kaynaklı) projelerde zamanla meydana gelmiş değişimleri kullanıcı işlemleyerek (commit) projelerin versiyonlar/aşamalar halinde evrimleşip geliştiğini gösteren bir yol haritası bizlere oluşturmaktadır.

Başka bir bağımlılığa ihtiyaç duymadan bir işletim sistemi üzerinde rahatlıkla kullanılan Git ayrıca lokal Git olarak da tanımlanabilir, çünkü bu sistem sadece lokal olarak geliştiricinin makinesinde terminal aracılığıyla çalışarak başka bir geliştiricinin çalıştığınız mevcut bölüme müdehalesine maruz kalmadan işlemlerinizi yapmanıza imkan sağlamaktadır. Bu yüzden Git, her bir geliştiriciye dağıtık bir şekilde sunulmaktadır. Peki lokalde Git ile işleme koyduğunuz projelerinizi dünyaya nasıl duyuracaksınız ya da nasıl başka geliştiricilerin de ilgilenmesini sağlayacaksınız? Birden çok geliştiricinin destek verdiği bir proje düşünün, bir geliştiricinin lokalde yaptığı işlerden diğerlerinin de haberdar olması ve yapılanlar hakkında iletişim haline geçmesi gerekebilir. Bunun için projenin global bir alanda herkes tarafından erişilebilecek bir merkez sunucuda birleşmesi gerekmektedir. Bu tür önemli gereksinimleri bir çatı altında toplamak adına, GitHub Web Servisi, hizmete sunulmuştur.


github logo.png

Yukarıda açıkladığımız ile söylemek istediğimiz aslında GitHub‘ın bir Git sistemi olmadığıdır. Git için yapılmış web tabanlı bir servis olan GitHub, Git depolarınızı (repository) yayınlayacağınız (push/publish) ve diğer geliştiriciler ile işbirliği içerisinde depoların gelişmesini ve yayılmasını sağlayacağınız imkanları sunmaktadır. Şekil 1, 3 ayrı geliştiricinin bir Git deposuna GitHub üzerinden bağlanarak aralarındaki iletişimi nasıl kurduklarını açıkça göstermektedir. GitHub servisi geliştiriciye:

  1. Her bir proje için varsayılan olarak GitHub Issue Tracker özelliği sunmaktadır. Projeler hakkında farklı konuları — yeni fikirler, bug bildirme, soru sorma vb. — tek bir bölümde toplamaktadır. Açılan konular etiketler ( tag) ile kategorize edilebilir ve projenlerin versiyonlarına göre aşamalarını (milestone) bölümlendirebilirsiniz. Ayrıca, bu bölüm projenin özelliklerinden kapatılabilir.
  2. Her bir proje için varsayılan ve zorunlu olan Pull Request işbirlikçi aracı sunmaktadır. Bu bölümü yazımızda daha detaylandıracağız.
  3. Her bir projeyi ücretsiz (genel durum – public) barındırma hakkı vermektedir. GitHub ayrıca hem tekil projeler hem de organizasyonlar için farklı ücretler karşılığında özel depo alanları da sunmaktadır.
Github2.png
Şekil 1. GitHub ve Git İletişimi
GitHub şu an kısıtlı olsa da bazı Git özelliklerini belirli durumlar için barındırmaktadır.

Pull Request

Pull Request (PR) ne Git ne de GitHub ile gelen spesifik bir yaklaşımdır. Bir PR temelinde, yapılan katkıların bir geliştirime açık projeye sunulması tekniğidir. PR yordamının sağlıklı işlenebilmesi için Git gibi versiyon kontrol sistemlerine başvurulmaktadır. Yalnız şunun altını çizmeliyiz pull request Git türü servislerin özelliği değildir. Bu yaklaşım birden çok servisin kullanılmasıyla yapılmaktadır (Örneğin: Git ve GitHub). PR durumu birden çok işlem (commit) akışından oluşabileceği gibi tek bir işlem ile de bir projeye sunulabilir. Bir PR meydana geldiğinde aslında şunu anlamaktayız, bu işlem başka bir yerde hedef projenin kopyasının üzerinde değişimler gerçekleştirilerek yapılmış ve tekrar hedefteki projenin geliştiricilerine bu değişimlerin değerlendirilmesi istenmiştir. Bir projenin bakımını üstlenen(ler) dışında başka geliştiricilerin işbirliği içerisinde projenin gelişmesi pull request döngüsüyle gerçekleşmektedir. Ayrıca bazı projelerin karakterine göre PR oranındaki artış gelişimleriyle doğru orantıda olabilir. Git servisi ile hazırlanan iş akışının GitHub tarafına yollanarak PR konseptinin oluşturulması son derece kolay hale gelmiştir. Bunun yanında, Git sistemi de bu konsepti GitHub tarafında PR aracına gerek duymadan farklı bir açıdan desteklemektedir. İlk olarak GitHub tarafında bu işlem nasıl yapılmakta onu ele alıp daha sonra Git tarafına geçeceğiz.

GitHub Pull Request

GitHub tarafında pull request yöntemi fork ve pull modeli ile gerçekleşmektedir. Yapılan katkıların bir projeye çekilmesi için gerekli proje ilk önce GitHub üzerinden fork (çatallama) işlemine tabi tutulmalıdır. Kopyalanan (fork’lanan) proje diğer geliştiricinin hesabında oluştuktan sonra yapılacak katkının önemliliğine göre projeyle lokalde çalışılması için kendi makinesine bunu klonlaması gerekmektedir. Yapılan geliştirimler ile oluşan işlem akışı Git aracılığıyla öncelikle kendi projesine (origin) gönderilir daha sonra GitHub servisiyle asıl projeye (upstream) katkıların çekilmesi isteği ile sonlanır.

GitHub üzerinde projenin bir kopyasının elde edilmesine fork, bir deponun kopyasının lokal makineye alınmasına clone işlemi denmektedir.

GitHub web servisi bu yaklaşımı ismiyle özdeşleşen bir araç ile her projede daim kılmaktadır. GitHub PR aracı katkıda bulunanları baz alarak her PR isteği için ayrı başlık açmaktadır. Eğer bir geliştiricinin PR isteği (esas projede) kapatılmadıysa, kopya projede (origin) yapacağı işlemler direkt açık olan başlık içerisinde gözükecektir.

Bunların yanında GitHub
  1. Projeyi izleyenlere (watch özelliği ile) otomatik olarak hem mail hem de servisin içerisinde bilgilendirme
  2. Projede diğer geliştiricilerin ayrıntılı olarak değişiklikleri inceleme
  3. Değişiklikler içerisinde herkesin satırlara özel yorum yapabilme
  4. Her bir PR içerisinde meydana gelmiş konuşmaların kayda geçirilme
  5. Proje geliştiricilerinin ek istekleri doğrultusunda açık olan PR üzerinde yeni çalışmaları takip edebilme

olanağı sağlamaktadır.

Biz de bu yöntemi GitHub ile örnek bir senaryo üzerinde deneyelim. Bir Y geliştiricisi X geliştiricisinin github.com/X/ABC adresindeki ABC ismindeki projesine katkıda bulunmak istesin. Şu adımları takip ederek PR işlemini yerine getirebilir Y geliştiricisi:

  1. Y ilk önce ABC projesini GitHub üzerinde kendisine kopyalıyor. Bu işlemi ABC deposuna girerek sağ üstte beliren fork.png butonuna basarak gerçekleştirmektedir. Y geliştiricisi başka bir organizasyona bağlı olmadığından kopyalanacak yer ile ilgili ekstra bir ekran bu işlem sırasında belirmemektedir.
  2. Y, fork’lu projenin lokal kopyasını yapmakta, projede gerekli 3 değişikliği 3 ayrı iş akışı şeklinde düzenlemekte ve tekrar forklu projeye bunları aktarmaktadır. Bu işlemi terminalden gerekli adresi (https://github.com/Y/ABC.git:origin) kendi makinesine klonlayarak gerçekleştiriyor ve daha sonra gerekli değişiklikleri işlemliyor ve origin yani kopya depoya yerleştiriyor. Yapılan değişikler ana kısım/dal (master branch) da yapılıyor (PR işlemlerinde ayrı branch açıp işlemleri orada yapmak daha sağlıklı olmaktadır):
    $ git clone https://github.com/Y/ABC.git
    $ cd ABC
    $ 1. değişiklik...
    $ git add README.adoc;
    $ git commit -m "1. Değişiklik"
    $ 2. değişiklik...
    $ git add .travis.yml
    $ git commit -m "2. Değişiklik"
    $ 3. değişiklik...
    $ git add package.json
    $ git commit -m "3. Değişiklik"
    $ git log --pretty=oneline -3
    4c9601222d2cfc057cba80f888519dfc7c99dae7 3. Değişiklik
    bf9fac5122b3a7a675074b60d2deeee67797883a 2. Değişiklik
    8a72a8df37871167e7d6b29ec460185f92b0b0a5 1. Değişiklik
    $ git push origin
  3. Lokal tarafta artık Y geliştiricisinin işi bitmiştir. Eğer PR meydana geldikten sonra X tarafından başka düzenlemeler istenirse Y bunları da lokalde yapacaktır.
  4. Şu an, esas projede bir ilerleme olmadığını düşünürsek, kopya ABC artık 3 commit ilerisindedir esas projenin. Y, değişikliğe uğramış projenin GitHub sayfasından pr.png butonuna tıklayarak 2 proje arasındaki farkın özetini master branch üzerinden oluşturarak katkıda bulunduğu bölgeleri esas projeye yollanmak üzere PR işlemini tetiklemektedir.
  5. Bu işlemi X geliştiricisi GitHub aracılığıyla bilgilendirildikten sonra projenin PR panosundan isteğe erişerek değişiklikleri inceler ve kabul eder.
  6. Git ve GitHub işbirliği içerisinde PR yaklaşımları bu ve benzeri senaryolarla gerçekleşebilir.
Esas Projeden değişiklikleri çekmek

Peki farklı bir senaryo düşünelim, yukarıdaki senaryoya göre X kullanıcısının ABC deposunu Y GitHub üzerinden fork işlemiyle kendi sistemine alıp bunu kendi makinesine klonladıktan sonra değişiklikleri yapmaya başlıyordu. Diyelim ki 2. değişikliği yapacağı sırada ana projenin yani X kullanıcısındaki bu projede .travis.yml dosyasında bir değişiklik yapılmış olsun. Bu yapılan değişiklikliğin üzerine kendi değişikliklerini artık yapması gerekecek. Ana projedeki bu yapılan son değişikliği Y kullanıcısı lokaline nasıl alabilir?

Eğer Y, git remote -v komutunu koşturursa, sadece kendi hesabına ait GitHub bağlantısı origin ismiyle gözüküyor görecek:

$ git remote -v
origin  https://github.com/Y/ABC.git (fetch)
origin  https://github.com/Y/ABC.git (push)

İlk önce remote içerisine ana/esas projenin bağlantı yolunun eklenmesi gerekiyor. Y, bu proje bağlantısına bir isim vererek (upstream denmekte genelde) ekleme işlemini yerine getirmesi gerekir:

X kullanıcısının esas depo yolu ekleniyor:
git remote add upstream https://github.com/X/ABC.git

Tekrar bir önceki komutu çalıştırdığımızda artık upstream olarak ana projenin de GitHub bağlantısı eklenmiş olmakta. fetch ve eğer yetkiniz varsa uzaktaki depoya push işlemlerini yapılabilecek seviyedeyiz. Ama bizim senaryomuzda uzaktaki depoya erişimimiz direkt olmadığı düşünülürse Y kullanıcısı sadece fetch işlemini kullanarak uzakta yapılan değişiklikleri lokaline çekerek, yapacağı değişikliklere kaldığı yerden devam edebilir.

$ git remote -v
origin  https://github.com/Y/ABC.git (fetch)
origin  https://github.com/Y/ABC.gitt (push)
upstream        https://github.com/X/ABC.git (fetch)
upstream        https://github.com/X/ABC.git (push)

master dalında olduğumuza emin olarak, ilk, uzak (upstream) depodaki tüm değişiklikleri/bilgileri/verileri çekiyoruz ve localdeki master dalıyla upstream deki master (kök) dalını birleştiriyoruz. Bunu yaparak artık hem uzak hem de lokal proje son bilgileri tutmuş yani eşitlenmiş oluyor.

git checkout master # master dalına geçiliyor
git fetch upstream # uzaktaki projenin tüm verileri çekiliyor
git merge upstream/master # uzak depodaki master dalındaki değişiklikler birleştiriliyor.

Git Pull Request

Git farklı açıdan pull request yöntemini desteklediğini belirtmiştik. Açıkcası Git PR yöntemini tam olarak desteklememektedir. Pull Request konsepti Git tarafında tamamiyle farklı bir yaklaşım izlemektedir. Git, request-pull komutuyla yapılan değişikliklerin çıktısını sunmaktadır. Terminalden otomatik olarak oluşturulan bu istek, GitHub tarafında pr.png butonuna basılarak gerçekleştirilen değişikliklerin karşılaştırılmasının metne dökülmüş halidir. request-pull komutunu destek veren geliştirici değişiklikleri yapıp çalıştırdığında, otomatik bir istek oluşturmakta ve değişiklikleri karşılaştırarak bunların neler olduklarını metinde anlatmaktadır. Bu metin daha çok mail aracılığıyla katkıda bulunulan projenin asıl geliştiricisine yollanarak PR işleminin bu geliştirici tarafından metinde yazılı bağlantıya giderek yapması istenmektedir. GitHub servisinin sağladığı maddeleri burada görememekteyiz ve hedef projenin (upstream) geliştiricisine bir şekilde bu iletilmezse yapılan katkıdan haberi olamayacağı gibi bu değişimler de istenen projeye çekilemeyecektir.

git (request to pull) komutu
git request-pull [-p]   (1)
                <start> (2)
                <url>   (3)
                [<end>] (4)
1 Opsiyonel olarak koyulabilen komut, yapılan değişikliklerin içeriğini git diff yaklaşımıyla göstermektedir.
2 Değişikliklerin hangi noktada başladığını bildirmek gerekmektedir. Başlangıç noktası bir commit (SHA-1 değerinin ilk 7 basamağı yeterli olmakta, ör: 5ee006d ) değeri ya da etiket (ör. v2.2.2: versiyon 2.2.2’ye işaret eden commit değeri dikkate alınır) olabilir.
3 Bu noktada hedef projenin kopyası bağlantıda tanımlanmalıdır. Asıl geliştirici bu adrese giderek manuel olarak değişikleri projeye çekecek. GitHub tarafında bu, fork işlemiyle kopyalanan projenin bağlantısı olabilir (ör: https://github.com/Y/ABC.git ).
4 Son olarak bitiş opsiyonel olarak verilebilir. Kısıtlı aralıkların sadece çekileceğini göstermek açısından da bu işlem gerekebilir. Eğer bir bitiş noktası verilmez ise bu <url> kısmında public olarak gözüken deponun master değeri otomatik algılanır.

Örneğin, bir geliştirici (Y), master işaretçisinin 5ee006d değerine sahip olan esas projeyi kopyalayarak (projenin bağlantısı gene github.com/X/ABC olsun) bu noktadan sonra yaptığı katkıların tekrar esas projenin geliştiricisi (X) tarafından çekilmesi için terminalde bir istek oluşturmak istesin:

$ git request-pull 5ee006d https://github.com/Y/ABC.git master (1)
1 5ee006d SHA-1 hash değerine sahip commit başlangıç olarak yazılmış ki bu hedef projenin şu anki master noktasıdır. Değişiklikler https://github.com/Y/ABC.git adresinde bulunan kopya projeden çekilecek ve değişikliklerin olduğu aralık bu deponun master işaretçinin commit değerine kadar yapılan değişiklikler gözlemlenir (master işaretçisinin commit değeri: 93435e9 olsun).

Yukarıdaki örneğin terminalde oluşacak çıktısı şu şekildedir:

The following changes since commit 5ee006d08c71b270963ac7374b262e8875c5477a: (1)
  1. Update the README file by X (2014-02-18 15:13:33 +0100)
are available in the git repository at:
  https://github.com/Y/ABC.git master                                        (2)
for you to fetch changes up to 93435e9f8f706f109fd488a56bcb1292ab10c9e5:     (3)
  2. Update the README file by Y (2015-02-27 16:39:55 +0200)
----------------------------------------------------------------
Y (1):                                                                     (4)
      Some minor chages
 README.adoc | 4 ----
 1 file changed, 4 deletions(-)
1 Komutta gösterilen commit değerinin tam hali bu noktada gösterilip başlangıç noktasında meydana gelen commit açıklaması koyulmuştur. Bu değer, 5ee006d, asıl projede master işaretçisinin bulunduğu noktayı göstermektedir.
2 URL GitHub üzerinde bulunan kopya projeyi göstermekte ve başlangıç değeri de burada bulunduğu anlatılıyor.
3 master işaretçisi karşılaştırılacak bölgenin aralığını belirterek, ona denk düşen commit değeri (93435e9…​) belirtilmiştir.
4 Bu aralıklar içerisinde sadece 1 değişikliğin README.adoc dosyasında 4 satırda yapılan silme işlemi olduğu gösteriliyor. Bu işlemler Y geliştiricisi tarafından yapıldığıda belirtilmektedir. Eğer -p opsiyonunu da ekleseydik burada silinen ifadeleri de görebilirdik.

Yukarıda gösterilen açıklamalı metni mail ya da başka bir aracıyla hedefdeki geliştiriciye ulaştırılması gerekmektedir. Bu metni analizleyen geliştirici (X) bağlantıda gösterilen projeye giderek manuel olarak gösterilen aralıklardaki değişimleri (Y tarafından yapılan) hedef projeye böylelikle çekebilir.

Unutulmaması gereken nokta, lokelde yapılan işlemler/değişimler global depoya (yani kopya projeye) gönderilmesi gerekir ki X bunları oradan çekebilsin.

Git ve GitHub PR yöntemini nasıl desteklediği böylelikle görmüş olduk. Hangi yolu seçeceğiniz siz geliştiricilere kalmış (:

4 Comments

Post a Comment

Comment
Name
Email
Website