Git
Chapters ▾ 2nd Edition

9.1 Git ve Diğer Sistemler - İstemci Olarak Git

Dünya malesef mükemmel değil. Genellikle, dokunduğunuz her projeyi hemen Git’e geçiremezsiniz. Bazen başka bir VCS kullanan bir projede sıkışıp kalırsınız ve onun Git olmasını dilersiniz. Bu bölümün ilk kısmında, üzerinde çalıştığınız proje başka bir sistemde barındırıldığında, Git’i istemci olarak nasıl kullanabileceğiniz hakkında bilgi edineceksiniz.

Bir noktada, mevcut projenizi Git’e dönüştürmek isteyebilirsiniz. Bu bölümün ikinci kısmı, projenizi birkaç belirli sistemden Git’e nasıl taşıyacağınızı kapsar. Ayrıca önceden yapılandırılmış bir içe aktarma aracı mevcut değilse kullanabileceğiniz bir yöntemi de içerir.

İstemci Olarak Git

Geliştiriciler için Git, o kadar güzel bir deneyim sunar ki, birçok insan ekibin geri kalanının tamamen farklı bir VCS kullandığı durumlarda bile onu kendi çalışma istasyonlarında nasıl kullanacaklarını bulmuştur. Bu bağdaştırıcılardan bazılarına "köprüler" denir ve sayıları pek çoktur. Burada vahşi doğada karşılaşmanız en olası olanları ele alacağız.

Git ve Subversion

Subversion, kaynak kodlarını yönetmek için çoğu açık kaynak geliştirme projesin ve birçok kurumsal proje tarafından kullanılmaktadır. On yıldan fazla bir süredir mevcuttur ve çoğu zaman açık kaynak projeleri için de facto VCS seçimi olmuştur. Ayrıca, CVS öncesi kaynak kontrol dünyasının büyük oyuncusu olan CVS ile birçok açıdan benzerdir.

Git’in harika özelliklerinden biri, git svn olarak adlandırılan Subversion’a iki yönlü bir köprüdür. Bu araç, Git’i bir Subversion sunucusuna geçerli bir istemci olarak kullanmanızı sağlar, böylece Git’in tüm yerel özelliklerini kullanabilir ve ardından sanki yerel olarak Subversion kullanıyormuş gibi bir Subversion sunucusuna gönderebilirsiniz. Bunun anlamı iş arkadaşlarınızın karanlık ve eski yöntemlerle çalışmaya devam ederken, sizin yerel dal oluşturma, birleştirme, izleme alanı kullanma, yeniden temelleme ve cherry-picking gibi işlemleri yapabilmenizdir. Bu Git’i kurumsal ortamınıza sızdırmanın ve altyapının tamamen Git’i destekleyecek şekilde değiştirilmesi için lobi yaparken, diğer geliştiricilerinizi daha verimli hale getirmenin iyi bir yoludur. Subversion köprüsü, DVCS dünyasına giriş ilacıdır.

git svn

Git’in tüm Subversion köprüleme komutları için temel komutu git svn 'dir. Birkaç basit iş akışını incelerken en yaygın olanlarını göstereceğiz.

git svn kullanırken, Git’ten çok farklı bir çalışma sistemine sahip olan Subversion ile etkileşimde bulunduğunuzu unutmamalısınız. Yerel dal oluşturup birleştirebilirsiniz, ancak genellikle çalışmanızı yeniden temelleyerek mümkün olduğunca çizgisel tutmak ve bir Git uzak deposuyla eş zamanlı etkileşimde bulunmaktan kaçınmak en iyisidir.

Geçmişinizi yeniden yazıp, tekrar göndermeye çalışmayın ve bir Git reposuna başka geliştiricilerle eş zamanlı itmeye çalışmayın. Subversion yalnızca tek bir çizgisel geçmişe sahip olabilir ve onun kafasını karıştırmak çok kolaydır. Bir ekip ile çalışıyorsanız ve bazıları SVN kullanırken diğerleri Git kullanıyorsa, herkesin işbirliği yapmak için SVN sunucusunu kullandığından emin olun (bu hayatınızı kolaylaştıracaktır).

Kurulum

Bu işlevselliği göstermek için yazma erişiminiz olan tipik bir SVN reposuna ihtiyacınız var. Bu örnekleri kopyalamak istiyorsanız, yazılabilir bir SVN test reposunun bir kopyasını oluşturmanız gerekecektir. Bunu kolayca yapmak için, Subversion ile birlikte gelen svnsync adlı bir aracı kullanabilirsiniz.

Takip edebilmek için önce yeni bir yerel Subversion reposu oluşturmanız gerekiyor:

$ mkdir /tmp/test-svn
$ svnadmin create /tmp/test-svn

Sonra, tüm kullanıcıların revprops’ları değiştirmesine izin verin: kolay yol, her zaman 0 (sıfır) çıkışlı bir pre-revprop-change betiği eklemektir:

$ cat /tmp/test-svn/hooks/pre-revprop-change
#!/bin/sh
exit 0;
$ chmod +x /tmp/test-svn/hooks/pre-revprop-change

Şimdi svnsync init komutunu "to" ve "from" repolarıyla kullanarak bu projeyi yerel makinenize senkronize edebilirsiniz.

$ svnsync init file:///tmp/test-svn \
  http://your-svn-server.example.org/svn/

Bu komut senkronizasyonu çalıştırmak için özellikleri ayarlar. Kodu kopyalamak için şunu çalıştırabilirsiniz:

$ svnsync sync file:///tmp/test-svn
Committed revision 1.
Copied properties for revision 1.
Transmitting file data .............................[...]
Committed revision 2.
Copied properties for revision 2.
[…]

Bu işlem normalde sadece birkaç dakika sürmesine rağmen, eğer orijinal repoyu başka bir uzak repoya kopyalamaya çalışırsanız, neredeyse bir saat sürecektir (100’den az katkı olsa bile). Subversion her bir revizyonu tek tek kopyalamak ve ardından başka bir repoya geri itmek zorundadır. Gülünç derecede verimsiz olmasına rağmen, bunu yapmanın tek kolay yolu budur.

Başlarken

Şimdi yazma erişimimiz olan bir Subversion reposuna sahip olduğumuza göre, tipik bir iş akışının üzerinden geçebiliriz. Bir Subversion reposunu yerel bir Git reposuna aktaran git svn clone komutuyla başlayacağız. Eğer canlıda olan gerçek bir Subversion reposundan içe aktarıyorsanız, buradaki file:///tmp/test-svn 'yi Subversion reposunuzun URL’siyle değiştirmeyi unutmayın:

$ git svn clone file:///tmp/test-svn -T trunk -b branches -t tags
Initialized empty Git repository in /private/tmp/progit/test-svn/.git/
r1 = dcbfb5891860124cc2e8cc616cded42624897125 (refs/remotes/origin/trunk)
    A	m4/acx_pthread.m4
    A	m4/stl_hash.m4
    A	java/src/test/java/com/google/protobuf/UnknownFieldSetTest.java
    A	java/src/test/java/com/google/protobuf/WireFormatTest.java
…
r75 = 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae (refs/remotes/origin/trunk)
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/my-calc-branch, 75
Found branch parent: (refs/remotes/origin/my-calc-branch) 556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae
Following parent with do_switch
Successfully followed parent
r76 = 0fb585761df569eaecd8146c71e58d70147460a2 (refs/remotes/origin/my-calc-branch)
Checked out HEAD:
  file:///tmp/test-svn/trunk r75

Bu girdiğiniz URL üzerinde git svn init ve ardından git svn fetch komutlarının eşdeğerini çalıştırır. İşlemin gerçekleşmesi biraz zaman alabilir. Örneğin, test projesinde yaklaşık 75 katkı varsa ve kod tabanı çok büyük değilse, Git yine de her sürümü tek tek kontrol etmeli ve bunu bireysel olarak katkılamaladır. Yüzlerce veya binlerce katkı içeren bir proje için, bunun tamamlanması gerçekten saatler, hatta günler alabilir.

-T trunk -b branches -t tags kısmı, bu Subversion reposunun temelleme ve etiketleme kurallarını takip ettiğini Git’e belirtir. Eğer ana dalınızı (trunk), dallarınızı veya etiketlerinizi farklı adlandırırsanız, bu seçenekleri değiştirebilirsiniz. Bu çok yaygın olduğu için, ilgili kısmı -s ile değiştirebilirsiniz: bu standart düzeni ima eder ve tüm bu seçenekleri içerir. Aşağıdaki komuta eşdeğerdir:

$ git svn clone file:///tmp/test-svn -s

Bu noktada, dallarınızı ve etiketlerinizi içe aktarmış geçerli bir Git reponuz olmalıdır:

$ git branch -a
* master
  remotes/origin/my-calc-branch
  remotes/origin/tags/2.0.2
  remotes/origin/tags/release-2.0.1
  remotes/origin/tags/release-2.0.2
  remotes/origin/tags/release-2.0.2rc1
  remotes/origin/trunk

Bu aracın Subversion etiketlerini uzak referanslar olarak nasıl yönettiğine dikkat edin. Git tesisat (plumbing) komutu show-ref ile daha yakından inceleyelim:

$ git show-ref
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/heads/master
0fb585761df569eaecd8146c71e58d70147460a2 refs/remotes/origin/my-calc-branch
bfd2d79303166789fc73af4046651a4b35c12f0b refs/remotes/origin/tags/2.0.2
285c2b2e36e467dd4d91c8e3c0c0e1750b3fe8ca refs/remotes/origin/tags/release-2.0.1
cbda99cb45d9abcb9793db1d4f70ae562a969f1e refs/remotes/origin/tags/release-2.0.2
a9f074aa89e826d6f9d30808ce5ae3ffe711feda refs/remotes/origin/tags/release-2.0.2rc1
556a3e1e7ad1fde0a32823fc7e4d046bcfd86dae refs/remotes/origin/trunk

Git, bir Git sunucusundan kopyaladığında bunu yapmaz; işte taze bir kopya sonrası etiketlere sahip bir reponun görüntüsü:

$ git show-ref
c3dcbe8488c6240392e8a5d7553bbffcb0f94ef0 refs/remotes/origin/master
32ef1d1c7cc8c603ab78416262cc421b80a8c2df refs/remotes/origin/branch-1
75f703a3580a9b81ead89fe1138e6da858c5ba18 refs/remotes/origin/branch-2
23f8588dde934e8f33c263c6d8359b2ae095f863 refs/tags/v0.1.0
7064938bd5e7ef47bfd79a685a62c1e2649e2ce7 refs/tags/v0.2.0
6dcb09b5b57875f334f61aebed695e2e4193db5e refs/tags/v1.0.0

Git etiketleri uzak dallar gibi işlemek yerine doğrudan refs/tags içine çeker.

Katkıları Subversion’a İşlemek

Artık bir çalışma dizininiz olduğuna göre, Git’i bir SVN istemcisi olarak etkili bir şekilde kullanarak proje üzerinde biraz çalışabilir ve katkılarınızı üst-akıma itebilirsiniz. Dosyalardan birini düzenleyip katkılarsanız, Git’te yerel olarak işlenmiş ancak henüz Subversion sunucusunda bulunmayan bir katkıya sahip olursunuz:

$ git commit -am 'Adding git-svn instructions to the README'
[master 4af61fd] Adding git-svn instructions to the README
 1 file changed, 5 insertions(+)

Sonraki adım, değişikliklerinizi yukarı akıma itmektir. Subversion ile çalışma şeklinizin değiştiğine dikkat edin: çevrimdışı olarak birkaç katkı yapabilir ve ardından hepsini aynı anda Subversion sunucusuna itebilirsiniz. Bir Subversion sunucusuna itmek için git svn dcommit komutunu çalıştırırsınız:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r77
    M	README.txt
r77 = 95e0222ba6399739834380eb10afcd73e0670bc5 (refs/remotes/origin/trunk)
No changes between 4af61fd05045e07598c553167e0f31c84fd6ffe1 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Bu, Subversion sunucusu kodunun üstüne yaptığınız tüm katkıları alır, her biri için bir Subversion katkısı yapar ve ardından yerel Git katkınızı benzersiz bir kimlik içerecek şekilde yeniden yazar. Bu tüm katkılarınızın SHA-1 kontrol toplamlarının değiştiği anlamına gelmesi yönünden önemlidir. Kısmen bu nedenle, eşzamanlı olarak projelerinizin Git tabanlı uzak sürümleriyle ve bir Subversion sunucusuyla çalışmak iyi bir fikir değildir. Son katkıya baktığınızda, eklenen yeni `git-svn-id`yi görebilirsiniz:

$ git log -1
commit 95e0222ba6399739834380eb10afcd73e0670bc5
Author: ben <ben@0b684db3-b064-4277-89d1-21af03df0a68>
Date:   Thu Jul 24 03:08:36 2014 +0000

    Adding git-svn instructions to the README

    git-svn-id: file:///tmp/test-svn/trunk@77 0b684db3-b064-4277-89d1-21af03df0a68

İlk olarak katkıladığınız 4af61fd ile başlayan SHA-1 kontrol toplamının şimdi 95e0222 ile başladığını görüyorsunuz. Eğer hem bir Git sunucusuna hem de bir Subversion sunucusuna itmek istiyorsanız, katkı verilerinizin değişmesi nedeniyle önce Subversion sunucusuna (dcommit) itmelisiniz.

Yeni Değişiklikleri Çekmek

Diğer geliştiricilerle çalışıyorsanız, o zaman biriniz bir noktada kodunu itecek ve ardından diğeri öbürüyle çakışan bir değişiklik itmeye çalışacaktır. Bu değişiklik, siz onların çalışmasını kendinizinkiyle birleştirmedikçe reddedilecektir. git svn 'de durum şöyle görünür:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: d5837c4b461b7c0e018b49d12398769d2bfc240a and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 f414c433af0fd6734428cf9d2a9fd8ba00ada145 c80b6127dd04f5fcda218730ddf3a2da4eb39138 M	README.txt
Current branch master is up to date.
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

Bu durumu çözmek için git svn rebase komutunu çalıştırabilirsiniz. Bu komut, sunucudaki henüz sahip olmadığınız tüm değişiklikleri indirir ve yaptığınız çalışmayı sunucudaki mevcut durumun üstüne yerleştirir:

$ git svn rebase
Committing to file:///tmp/test-svn/trunk ...

ERROR from SVN:
Transaction is out of date: File '/trunk/README.txt' is out of date
W: eaa029d99f87c5c822c5c29039d19111ff32ef46 and refs/remotes/origin/trunk differ, using rebase:
:100644 100644 65536c6e30d263495c17d781962cfff12422693a b34372b25ccf4945fe5658fa381b075045e7702a M	README.txt
First, rewinding head to replay your work on top of it...
Applying: update foo
Using index info to reconstruct a base tree...
M	README.txt
Falling back to patching base and 3-way merge...
Auto-merging README.txt
ERROR: Not all changes have been committed into SVN, however the committed
ones (if any) seem to be successfully integrated into the working tree.
Please see the above messages for details.

Şimdi, tüm çalışmanız Subversion sunucusundaki durumun üstüne yerleşmiş olduğu için, başarıyla dcommit yapabilirsiniz:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	README.txt
Committed r85
    M	README.txt
r85 = 9c29704cc0bbbed7bd58160cfb66cb9191835cd8 (refs/remotes/origin/trunk)
No changes between 5762f56732a958d6cfda681b661d2a239cc53ef5 and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Kodunuzu itmeden önce henüz sahip olmadığınız değişikleri yukarı akımdan çekmenizi gerektiren Git’in aksine, git svn bunu ancak değişiklikler çakıştığında yapmanızı gerektirir (Subversion’ın çalışma şekli gibi). Birisi bir dosyaya bir değişiklik yaptıktan sonra siz de başka bir dosyada bir değişiklik yaparsanız, dcommit sorunsuz çalışacaktır:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	configure.ac
Committed r87
    M	autogen.sh
r86 = d8450bab8a77228a644b7dc0e95977ffc61adff7 (refs/remotes/origin/trunk)
    M	configure.ac
r87 = f3653ea40cb4e26b6281cec102e35dcba1fe17c4 (refs/remotes/origin/trunk)
W: a0253d06732169107aa020390d9fefd2b1d92806 and refs/remotes/origin/trunk differ, using rebase:
:100755 100755 efa5a59965fbbb5b2b0a12890f1b351bb5493c18 e757b59a9439312d80d5d43bb65d4a7d0389ed6d M	autogen.sh
First, rewinding head to replay your work on top of it...

Kodunuzu ittiğinizde herhangi birinizin bilgisayarında var olmayan bir proje durumu elde edeceğiniz için bu önemlidir. Değişiklikler ister uyumsuz olsun ister çakışmasın, teşhis etmesi zor sorunlarla karşılaşabilirsiniz. Bu bir Git sunucusu kullanmaktan farklıdır: Git’te, yayınlamadan önce istemcinizdeki durumu tamamen test edebilirsiniz, SVN’de ise katkı öncesi ve sonrası durumların aynı olduğundan kesinlikle emin olamazsınız.

Kendiniz katkı işlemeye hazır olmasanız bile, bu komutu Subversion sunucusundan değişiklikleri çekmek için çalıştırmalısınız. Yeni verileri almak için git svn fetch komutunu çalıştırabilirsiniz ancak git svn rebase hem çekme yapar hem de yerel katkılarınızı günceller.

$ git svn rebase
    M	autogen.sh
r88 = c9c5f83c64bd755368784b444bc7a0216cc1e17b (refs/remotes/origin/trunk)
First, rewinding head to replay your work on top of it...
Fast-forwarded master to refs/remotes/origin/trunk.

Arada bir git svn rebase 'i çalıştırmak kodunuzun her zaman güncel olmasını sağlar. Ancak bunu çalıştırdığınızda çalışma dizininizin temiz olduğundan emin olmalısınız. Yerel değişiklikleriniz varsa, git svn rebase 'i çalıştırmadan önce çalışmanızı saklamanız veya geçici olarak kaydetmeniz gerekir; aksi takdirde, rebase’in birleştirme çakışmasına yol açacağını görürse komut duracaktır.

Git Dallanma Sorunları

Git iş akışına alıştığınızda, muhtemelen konu dalları oluşturacak, bunlar üzerinde çalışacak ve sonra bunları birleştireceksiniz. Eğer bir Subversion sunucusuna git svn yoluyla itiyorsanız, dalları birleştirmek yerine çalışmanızı her seferinde tek bir dal üzerinde yeniden temellemek isteyebilirsiniz. Yeniden temellemeyi tercih etmenin nedeni, Subversion’un doğrusal bir geçmişe sahip olması ve Git gibi birleştirmelerle ilgilenmemesidir. Dolayısıyla git svn, anlık pozları Subversion katkılarına dönüştürürken yalnızca ilk önceli takip eder.

Geçmişinizin şuna benzediğini varsayalım: bir experiment dalı oluşturdunuz, iki katkı işlediniz ve ardından bunları tekrar master olarak birleştirdiniz. Dcommit yaptığınızda şöyle bir çıktı görürsünüz:

$ git svn dcommit
Committing to file:///tmp/test-svn/trunk ...
    M	CHANGES.txt
Committed r89
    M	CHANGES.txt
r89 = 89d492c884ea7c834353563d5d913c6adf933981 (refs/remotes/origin/trunk)
    M	COPYING.txt
    M	INSTALL.txt
Committed r90
    M	INSTALL.txt
    M	COPYING.txt
r90 = cb522197870e61467473391799148f6721bcf9a0 (refs/remotes/origin/trunk)
No changes between 71af502c214ba13123992338569f4669877f55fd and refs/remotes/origin/trunk
Resetting to the latest refs/remotes/origin/trunk

Git proje geçmişinize bakmadığınız sürece birleştirilmiş geçmişe sahip bir dalda dcommit çalıştırmak sorunsuz çalışır. Ancak experiment dalında yaptığınız katkıların hiçbirinin yeniden yazmılamış, bunun yerine tüm bu değişikliklerin SVN sürücüsünde tek bir birleştirme katkısının altında toplanmış olduğunu görürsünüz.

Başka biri bu çalışmayı kopyaladığında, sanki git merge --squash çalıştırmışsınız gibi, tüm çalışmaların içine sıkıştırıldığı birleştirme katkısını görürler. Bunların nereden geldiğine veya ne zaman işlendiğine ilişkin katkı verilerini göremezler.

Subversion’da Dallandırma

Subversion’daki dallanma Git’tekiyle aynı değildir: en iyisi, onu çok fazla kullanmaktan kaçınmaktır. Ancak Subversion’da git svn kullanarak dallar oluşturabilir ve bunlara katkı işleyebilirsiniz.

Yeni Bir SVN Dalı Oluşturma

Subversion’da yeni bir dal oluşturmak için git svn Branch [new-branch] komutunu çalıştırın:

$ git svn branch opera
Copying file:///tmp/test-svn/trunk at r90 to file:///tmp/test-svn/branches/opera...
Found possible branch point: file:///tmp/test-svn/trunk => file:///tmp/test-svn/branches/opera, 90
Found branch parent: (refs/remotes/origin/opera) cb522197870e61467473391799148f6721bcf9a0
Following parent with do_switch
Successfully followed parent
r91 = f1b64a3855d3c8dd84ee0ef10fa89d27f1584302 (refs/remotes/origin/opera)

Bu, Subversion’daki svn copy trunk Branch/Opera komutunun eşdeğerini yapar ve Subversion sunucusunda çalışır. Sizi o dala geçirmediğini akılda tutmak önemlidir; eğer bu noktada katkıda bulunursanız, bu katkı sunucudaki opera 'ya değil trunk 'a gidecektir.

Aktif Dalları Değiştirme

Git geçmişinizdeki herhangi bir Subversion dalınızın ipucunu arayarak dcommit'lerinizin hangi şubeye gittiğini belirler. Yalnızca bir taneye sahip olmalısınız ve bu, mevcut dal geçmişinizde git-svn-id 'ye sahip son dal olmalıdır.

Aynı anda birden fazla dal üzerinde çalışmak istiyorsanız, yerel dalları belirli Subversion şubelerine dcommit edecek şekilde ayarlayabilirsiniz. Bunları o dal için içe aktarılan Subversion işleminde başlatabilirsiniz. Ayrı ayrı çalışabileceğiniz bir opera dalı istiyorsanız aşağıdaki komutu çalıştırabilirsiniz.

$ git branch opera remotes/origin/opera

Şimdi, eğer opera dalınızı trunk (master dalınız) ile birleştirmek istiyorsanız, bunu normal bir git merge ile yapabilirsiniz. Ancak (-m aracılığıyla) açıklayıcı bir katkı mesajı girmeniz gerekir, aksi takdirde birleştirme, yararlı bir şey yerine "opera dalını birleştir" diyecektir.

Bu işlemi gerçekleştirmek için git merge kullanıyor olsanız ve (Git sizin için uygun birleştirme tabanını otomatik olarak algılayacağı için) birleştirme muhtemelen Subversion’dakinden çok daha kolay olsa da, bunun normal bir birleştirme işlemi olmadığını unutmayın. Bu verileri, birden fazla önceli olan bir katkıyı işleyemeyen bir Subversion sunucusuna geri göndermeniz gerekir. Yani onu üst akıma ittikten sonra, başka bir dalın tüm çalışmalarını tek bir katkı altında sıkıştıran bir katkı gibi görünecektir. Bir dalı diğeriyle birleştirdikten sonra, Git’te normalde yaptığınız gibi kolayca geri dönüp o dal üzerinde çalışmaya devam edemezsiniz. Çalıştırdığınız dcommit komutu, hangi dalın birleştirildiğini belirten tüm bilgileri siler, dolayısıyla daha sonraki birleştirme temeli hesaplamaları yanlış olur (dcommit komutu sizin git merge sonucunuzu sanki git merge --squash komutunu çalıştırmışsınız gibi görünmesini sağlar).

Ne yazık ki, bu durumu önlemenin iyi bir yolu yoktur (Subversion bu bilgiyi saklayamadığı için, onu sunucunuz olarak kullanırken her zaman sınırlamalarından dolayı bazı şeyler eksik kalacaktır). Sorunları önlemek için, yerel dalı (burada opera) ana dalla birleştirdikten sonra silmelisiniz.

Subversion Komutları

git svn araç seti Subversion’da sahip olduğunuza benzer bazı işlevler sağlayarak, Git’e geçişi kolaylaştırmaya yardımcı olacak bir dizi komut sunar. Subversion’un eskiden ne yaptığını size veren birkaç komut:

SVN Geçmiş Stili

Subversion’a alışkınsanız ve geçmişinizi SVN çıktı tarzında görmek istiyorsanız, katkı geçmişinizi SVN formatında görüntülemek için git svn log komutunu çalıştırabilirsiniz:

$ git svn log
------------------------------------------------------------------------
r87 | schacon | 2014-05-02 16:07:37 -0700 (Sat, 02 May 2014) | 2 lines

autogen change

------------------------------------------------------------------------
r86 | schacon | 2014-05-02 16:00:21 -0700 (Sat, 02 May 2014) | 2 lines

Merge branch 'experiment'

------------------------------------------------------------------------
r85 | schacon | 2014-05-02 16:00:09 -0700 (Sat, 02 May 2014) | 2 lines

updated the changelog

git svn log hakkında iki önemli şeyi bilmelisiniz: İlk olarak, Subversion sunucusundan veri isteyen gerçek svn log komutunun aksine çevrimdışı çalışır. İkincisi, yalnızca Subversion sunucusuna işlenen edilen katkıları gösterir. dcommit yapmadığınız yerel katkılar görünmediği gibi, bu arada başkalarının Subversion sunucusuna gönderdiği katkılar da görünmez. Daha ziyade Subversion sunucusundaki katkıların bilinen son durumuna benzer.

SVN Ek Açıklaması

git svn log komutu svn log komutunu çevrimdışı olarak simüle ettiği gibi, git svn blame [DOSYA] komutunu çalıştırarak svn annotate in eşdeğerini elde edebilirsiniz. Çıktıtı aşağıdaki gibi görünür:

$ git svn blame README.txt
 2   temporal Protocol Buffers - Google's data interchange format
 2   temporal Copyright 2008 Google Inc.
 2   temporal http://code.google.com/apis/protocolbuffers/
 2   temporal
22   temporal C++ Installation - Unix
22   temporal =======================
 2   temporal
79    schacon Committing in git-svn.
78    schacon
 2   temporal To build and install the C++ Protocol Buffer runtime and the Protocol
 2   temporal Buffer compiler (protoc) execute the following:
 2   temporal

Yine Git’te yerel olarak yaptığınız veya geçen zamanda Subversion’a aktarılan katkıları göstermez.

SVN Sunucu Bilgileri

Ayrıca svn info 'nun size sağladığı bilgilerin aynısını git svn info 'yu çalıştırarak da alabilirsiniz:

$ git svn info
Path: .
URL: https://schacon-test.googlecode.com/svn/trunk
Repository Root: https://schacon-test.googlecode.com/svn
Repository UUID: 4c93b258-373f-11de-be05-5f7a86268029
Revision: 87
Node Kind: directory
Schedule: normal
Last Changed Author: schacon
Last Changed Rev: 87
Last Changed Date: 2009-05-02 16:07:37 -0700 (Sat, 02 May 2009)

Bu kod blame ve log gibi çevrimdışı çalışır ve en son Subversion sunucusuyla iletişim kurduğunuz zaman kadar günceldir.

Subversion’ın Yoksaydığı Şeyleri Yoksaymak

Eğer herhangi bir yerde svn:ignore özellikleri ayarlanmış bir Subversion reposunu kopyalarsanız, muhtemelen göndermemeniz gereken dosyaları yanlışlıkla göndermemek için .gitignore dosyalarını ayarlamak istersiniz.

Bu sorunu çözmeye yardımcı olan iki git svn komutu vardır:

Bunlardan ilki, bir sonraki işleminizin bunları içerebilmesi için otomatik olarak ilgili .gitignore dosyalarını sizin için oluşturan git svn create-ignore` komutudur.

İkinci komut ise git svn show-ignore olup, çıktıyı proje hariç tutma (ignore) dosyanıza yeniden yönlendirebilmeniz için bir .gitignore dosyasına koymanız gereken satırları stdout olarak yazdırır:

$ git svn show-ignore > .git/info/exclude

Bu şekilde, projeyi .gitignore dosyalarıyla kirletmemiş olursunuz. Bu Subversion ekibinde tek Git kullanıcısı olduğunuz ve ekip arkadaşlarınızın projede .gitignore dosyalarını istemediği durumlar için iyi bir seçenektir.

Özet Olarak Git-Svn

git svn araçları bir Subversion sunucusunda sıkışıp kaldıysanız veya başka bir geliştirme ortamında bir Subversion sunucusunu çalıştırmanız gerekiyorsa faydalıdır. Ancak bu araçları kısıtlı Git olarak düşünmelisiniz, aksi takdirde sizin ve ekip arkadaşlarınızın kafasını karıştıracak çeviri sorunlarıyla karşılaşabilirsiniz.

Sorun yaşamamak için şu kuralları izlemeye çalışın:

  • git merge ile yapılan birleştirme işlemleri içermeyen çizgisel bir Git geçmişi tutun. Ana dalınız dışındaki herhangi bir işi birleştirmek yerine anadala geri dönerek yeniden temmelleyin.

  • Ayrı bir Git sunucusu kurmayın ve üzerinde işbirliği yapmayın. Yeni geliştiriciler için kopyalamaları hızlandırmak için bir taneniz olabilir, ancak git-svn-id girişi olmayan hiçbir şeyi itmek için kullanmayın. Her bir katkı mesajını git-svn-id için kontrol ederek, mesajı olmayan katkıları reddecek bir pre-receive kancası dahi ekleyebilirsiniz.

Bu kuralları izlerseniz, bir Subversion sunucusu ile çalışmak daha katlanılabilir bir hale gelir. Ancak, mümkünse gerçek bir Git sunucusuna geçmek, takımınıza çok daha fazla fayda sağlayabilir.

Git ve Mercurial

DVCS evreni yalnızca Git’ten ibaret değildir. Aslında bu alanda, dağıtılmış sürüm kontrolünün doğru şekilde nasıl yapılacağı konusunda her birinin kendi bakış açısı olan birçok sistem daha vardır. Git’ten sonra en popüler olanı Mercurial’dır ve bu ikisi birçok yönden çok benzer.

Git’in istemci tarafı davranışını tercih ediyorsanız ancak kaynak kodu Mercurial tarafından kontrol edilen bir projeyle çalışıyorsanız; iyi haber, Git’i Mercurial tarafından barındırılan bir reponun istemcisi olarak kullanmanın bir yolu vardır. Git’in sunucu repolarıyla iletişim kurma şekli uzak repolar aracılığıyla olduğu için, bu köprünün bir uzak yardımcı olarak uygulandığı şaşırtıcı olmamalıdır. Projenin adı git-remote-hg’dir ve https://github.com/felipec/git-remote-hg adresinde bulunabilir.

git-remote-hg

Öncelikle git-remote-hg’yi kurmanız gerekiyor. Bu, temel olarak dosyasını yolunuzun üzerinde bir yere bırakmayı gerektirir:

$ curl -o ~/bin/git-remote-hg \
  https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg
$ chmod +x ~/bin/git-remote-hg

~/bin öğesinin $PATH dizininizde olduğunu varsayıyoruz. Git-remote-hg’nin başka bir bağımlılığı daha var: Python için "Mercurial" kütüphanesi. Python’u yüklediyseniz, bu şu kadar basittir:

$ pip install mercurial

(Python yüklü değilse https://www.python.org/ adresini ziyaret edin ve önce onu kurun.)

İhtiyacınız olan son şey Mercurial istemcisidir. https://www.mercurial-scm.org/ adresine gidin ve henüz yapmadıysanız yükleyin.

Artık dansa hazırsınız. İhtiyacınız olan tek şey, itebileceğiniz bir Mercurial reposudur. Neyse ki, her Mercurial reposu bu şekilde davranır, bu nedenle herkesin Mercurial’ı öğrenmek için kullandığı "merhaba dünya" reposunu kullanacağız:

$ hg clone http://selenic.com/repo/hello /tmp/hello

Başlarken

Artık uygun bir “sunucu tarafı” repomuz olduğuna göre, tipik bir iş akışını gerçekleştirebiliriz. Göreceğiniz üzere, bu iki sistem fazla sürtünme olmayacak kadar benzerdir.

Git’te her zaman olduğu gibi önce repoyu kopyalarız:

$ git clone hg::/tmp/hello /tmp/hello-git
$ cd /tmp/hello-git
$ git log --oneline --graph --decorate
* ac7955c (HEAD, origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master, master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Mercurial reposuyla çalışmanın standart "git clone" komutunu kullandığını fark edeceksiniz. Bunun nedeni, git-remote-hg’nin Git’in HTTP/S protokolünün uygulanmasına (uzaktan yardımcılar) benzer bir mekanizma kullanarak oldukça düşük bir düzeyde çalışmasıdır. Git ve Mercurial’ın her ikisi de her kullanıcının repo geçmişinin tam bir kopyasına sahip olması için tasarlandığından, bu komut tüm projenin geçmişini içeren tam bir kopya oluşturur ve bunu çok hızlı bir şekilde yapar.

Log komutu, en sonuncusu bir dizi referans tarafından işaret edilen iki işlemi gösterir. Bunlardan bazılarının aslında orada olmadığı ortaya çıktı. .git dizininde gerçekte ne olduğuna bir bakalım:

$ tree .git/refs
.git/refs
├── heads
│   └── master
├── hg
│   └── origin
│       ├── bookmarks
│       │   └── master
│       └── branches
│           └── default
├── notes
│   └── hg
├── remotes
│   └── origin
│       └── HEAD
└── tags

9 directories, 5 files

Git-remote-hg işleri daha deyimsel olarak Git benzeri hale getirmeye çalışır, ancak aslında birbirinden biraz farklı iki sistem arasındaki kavramsal eşlemeyi yönetir. refs/hg dizini gerçek uzak referansların saklandığı yerdir. Örneğin, "refs/hg/origin/branches/default", "master"ın işaret ettiği katkı olan "ac7955c" ile başlayan SHA-1’i içeren bir Git ref dosyasıdır. Yani refs/hg dizini bir nevi sahte refs/remotes/Origin gibidir, ancak yer imleri ve dallar arasında ek bir ayrım vardır.

notes/hg dosyası, git-remote-hg’nin Git katkı karmalarını Mercurial değişiklik kümesi kimlikleriyle nasıl eşlediğinin başlangıç noktasıdır. Hadi biraz araştıralım:

$ cat notes/hg
d4c10386...

$ git cat-file -p d4c10386...
tree 1781c96...
author remote-hg <> 1408066400 -0800
committer remote-hg <> 1408066400 -0800

Notes for master

$ git ls-tree 1781c96...
100644 blob ac9117f...	65bb417...
100644 blob 485e178...	ac7955c...

$ git cat-file -p ac9117f
0a04b987be5ae354b710cefeba0e2d9de7ad41a9

Yani refs/notes/hg, Git nesne veritabanında adları olan diğer nesnelerin listesi olan bir ağaca işaret eder. git ls-tree bir ağacın içinde yer alan öğeler için: mod, tür, nesne karması ve dosya adını verir. Ağaç öğelerinden birini incelediğimizde, içinde “ac9117f” ("master" ile gösterilen katkının SHA-1 karması) adında ve “0a04b98” içeriğine sahip bir blob olduğunu görürüz (bu, varsayılan dalın ucundaki Mercurial değişiklik kümesinin kimliğidir).

Güzel olan şu ki, çoğunlukla tüm bunlar için endişelenmemize gerek yoktur. Tipik iş akışı Git uzaktan reposuyla çalışmaktan çok farklı olmayacaktır.

Devam etmeden önce ilgilenmemiz gereken bir şey daha var: yoksayılanlar. Mercurial ve Git bunun için çok benzer bir mekanizma kullanır, ancak muhtemelen bir .gitignore dosyasını Mercurial reposuna işlemek istemezsiniz. Neyse ki Git’in diskteki bir repoda yerel olan dosyaları yok saymanın bir yolu var ve bu Mercurial formatı Git ile uyumludur; dolayısıyla onu kopyalamanız yeterli:

$ cp .hgignore .git/info/exclude

.git/info/exclude dosyası tıpkı .gitignore gibi davranır ancak katkılara dahil edilmez.

İş Akışı

Diyelim ki master dalında bazı değişiklikler yaptık ve bazı katkılar işledik ve siz de bunu uzak repoya göndermeye hazırsınız. Repomuz şu anda şöyle görünüyor:

$ git log --oneline --graph --decorate
* ba04a2a (HEAD, master) Update makefile
* d25d16f Goodbye
* ac7955c (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Create a makefile
* 65bb417 Create a standard "hello, world" program

Bizim master dalımız, Origin/master 'dan iki katkı ileridedir, ancak bu iki katkı yalnızca yerel makinemizde mevcuttur. Bakalım aynı anda, başka biri de önemli işler yapıyor mu:

$ git fetch
From hg::/tmp/hello
   ac7955c..df85e87  master     -> origin/master
   ac7955c..df85e87  branches/default -> origin/branches/default
$ git log --oneline --graph --decorate --all
* 7b07969 (refs/notes/hg) Notes for default
* d4c1038 Notes for master
* df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
| * ba04a2a (HEAD, master) Update makefile
| * d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

--all bayrağını kullandığımız için, git-remote-hg tarafından dahili olarak kullanılan ``notes`` referanslarını görüyoruz, ancak onları görmezden gelebiliriz. Gerisi beklediğimiz gibidir; Origin/master tek bir katkı ilerledi ve artık geçmişimiz ayrıştı. Bu bölümde üzerinde çalıştığımız diğer sistemlerden farklı olarak; Mercurial, birleştirme işlemlerini gerçekleştirebilir, dolayısıyla havalı bir şey yapmayacağız.

$ git merge origin/master
Auto-merging hello.c
Merge made by the 'recursive' strategy.
 hello.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git log --oneline --graph --decorate
*   0c64627 (HEAD, master) Merge remote-tracking branch 'origin/master'
|\
| * df85e87 (origin/master, origin/branches/default, origin/HEAD, refs/hg/origin/branches/default, refs/hg/origin/bookmarks/master) Add some documentation
* | ba04a2a Update makefile
* | d25d16f Goodbye
|/
* ac7955c Create a makefile
* 65bb417 Create a standard "hello, world" program

Mükemmel. Testleri yapıyoruz ve her şey başarılı oluyor, böylece çalışmalarımızı ekibin geri kalanıyla paylaşmaya hazırız:

$ git push
To hg::/tmp/hello
   df85e87..0c64627  master -> master

Bu kadar! Mercurial reposuna bakarsanız, bunun beklediğimiz şeyi yaptığını göreceksiniz:

$ hg log -G --style compact
o    5[tip]:4,2   dc8fa4f932b8   2014-08-14 19:33 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   64f27bcefc35   2014-08-14 19:27 -0700   ben
| |    Update makefile
| |
| o  3:1   4256fc29598f   2014-08-14 19:27 -0700   ben
| |    Goodbye
| |
@ |  2   7db0b4848b3c   2014-08-14 19:30 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

2 numaralı değişiklik seti Mercurial tarafından, 3 ve 4 numaralı değişiklik seti ise Git-remote-hg tarafından Git ile yapılan katkıların itilmesiyle yapıldı.

Dallar ve Yer İmleri (Bookmarks)

Git’in yalnızca tek bir tür dalı vardır: katkılar işlendiğinde hareket eden bir referans. Mercurial’da bu tür bir referansa ``yer imi`` (bookmark) adı verilir ve Git dalıyla hemen hemen aynı şekilde davranır.

Mercurial’ın ``dal`` kavramı daha ağırdır. Değişiklik kümesinin yapıldığı dal, değişiklik kümesiyle birlikte kaydedilir. Bu da her zaman repo geçmişinde yeralacağı anlamına gelir. develop dalında yapılan bir katkı örneği:

$ hg log -l 1
changeset:   6:8f65e5e02793
branch:      develop
tag:         tip
user:        Ben Straub <ben@straub.cc>
date:        Thu Aug 14 20:06:38 2014 -0700
summary:     More documentation

``branch`` ile başlayan satıra dikkat edin. Git bunu gerçekten kopyalayamaz (her iki dal türü de Git referansı olarak temsil edilebildiği için gerek de yoktur zaten), ancak Mercurial bunu önemsediği için git-remote-hg’nin farkı anlaması gereklidir.

Mercurial yer imleri oluşturmak Git dalları oluşturmak kadar kolaydır. Git tarafında:

$ git checkout -b featureA
Switched to a new branch 'featureA'
$ git push origin featureA
To hg::/tmp/hello
 * [new branch]      featureA -> featureA

Hepsi bu kadardır. Mercurial tarafında ise şöyle görünür:

$ hg bookmarks
   featureA                  5:bd5ac26f11f9
$ hg log --style compact -G
@  6[tip]   8f65e5e02793   2014-08-14 20:06 -0700   ben
|    More documentation
|
o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
|\     Merge remote-tracking branch 'origin/master'
| |
| o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| |    update makefile
| |
| o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |    goodbye
| |
o |  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

Revizyon 5’teki yeni [featureA] etiketine dikkat edin. Bunlar, bir istisna dışında Git tarafındaki Git dalları gibi davranır (Git tarafından bir yer işaretini silemezsiniz: bu, uzak yardımcılara yönelik bir sınırlamadır).

Ayrıca “ağır” bir Mercurial dalı üzerinde de çalışabilirsiniz: ``branches`` ad alanına (namespace) bir dal koymanız yeterlidir:

$ git checkout -b branches/permanent
Switched to a new branch 'branches/permanent'
$ vi Makefile
$ git commit -am 'A permanent change'
$ git push origin branches/permanent
To hg::/tmp/hello
 * [new branch]      branches/permanent -> branches/permanent

Mercurial tarafın şöyle görünür:

$ hg branches
permanent                      7:a4529d07aad4
develop                        6:8f65e5e02793
default                        5:bd5ac26f11f9 (inactive)
$ hg log -G
o  changeset:   7:a4529d07aad4
|  branch:      permanent
|  tag:         tip
|  parent:      5:bd5ac26f11f9
|  user:        Ben Straub <ben@straub.cc>
|  date:        Thu Aug 14 20:21:09 2014 -0700
|  summary:     A permanent change
|
| @  changeset:   6:8f65e5e02793
|/   branch:      develop
|    user:        Ben Straub <ben@straub.cc>
|    date:        Thu Aug 14 20:06:38 2014 -0700
|    summary:     More documentation
|
o    changeset:   5:bd5ac26f11f9
|\   bookmark:    featureA
| |  parent:      4:0434aaa6b91f
| |  parent:      2:f098c7f45c4f
| |  user:        Ben Straub <ben@straub.cc>
| |  date:        Thu Aug 14 20:02:21 2014 -0700
| |  summary:     Merge remote-tracking branch 'origin/master'
[...]

``permanent`` (kalıcı) dal adı, 7 işaretli değişiklik kümesiyle kaydedildi.

Git açısından bakıldığında, bu dal stillerinden herhangi biriyle çalışmak aynıdır: normalde yaptığınız gibi yalnızca geçiş yapın, kaydedin, getirin, birleştirin, çekin ve itin. Bilmeniz gereken bir şey de Mercurial’ın tarihin yeniden yazılmasını desteklememesidir. Ona yalnızca ekleme yapabilirsiniz. Etkileşimli bir yeniden temelleme (rebase) ve zorla itme (forced push) sonrasında Mercurial repomuz şu şekilde görünür:

$ hg log --style compact -G
o  10[tip]   99611176cbc9   2014-08-14 20:21 -0700   ben
|    A permanent change
|
o  9   f23e12f939c3   2014-08-14 20:01 -0700   ben
|    Add some documentation
|
o  8:1   c16971d33922   2014-08-14 20:00 -0700   ben
|    goodbye
|
| o  7:5   a4529d07aad4   2014-08-14 20:21 -0700   ben
| |    A permanent change
| |
| | @  6   8f65e5e02793   2014-08-14 20:06 -0700   ben
| |/     More documentation
| |
| o    5[featureA]:4,2   bd5ac26f11f9   2014-08-14 20:02 -0700   ben
| |\     Merge remote-tracking branch 'origin/master'
| | |
| | o  4   0434aaa6b91f   2014-08-14 20:01 -0700   ben
| | |    update makefile
| | |
+---o  3:1   318914536c86   2014-08-14 20:00 -0700   ben
| |      goodbye
| |
| o  2   f098c7f45c4f   2014-08-14 20:01 -0700   ben
|/     Add some documentation
|
o  1   82e55d328c8c   2005-08-26 01:21 -0700   mpm
|    Create a makefile
|
o  0   0a04b987be5a   2005-08-26 01:20 -0700   mpm
     Create a standard "hello, world" program

8, 9 ve 10 değişiklik kümeleri oluşturuldu ve permanent dalına aitler, ancak eski değişiklik kümeleri hâlâ duruyor. Bu, Mercurial kullanan takım arkadaşlarınız için çok kafa karıştırıcı olabilir, bu yüzden bundan kaçınmaya çalışın.

Özetle Mercurial

Git ve Mercurial, sınırın ötesinde çalışmanın oldukça sancısız olmasını sağlayacak kadar benzerdir. (Genellikle önerildiği üzere) makinenizden kalan geçmişi değiştirmekten kaçınırsanız, diğer ucun Mercurial olduğunun farkına bile varmazsınız.

Git ve Bazaar

Dağıtık versiyon kontrol sistemleri arasında, bir diğeri Bazaar olarak bilinir. Bazaar, özgür ve açık kaynaklıdır ve GNU Projesi'nin bir parçasıdır. Git’ten oldukça farklı davranır. Git ile aynı şeyi yapabilmek için bazen farklı bir anahtar kelime kullanmanız gerekebilir ve bazı yaygın anahtar kelimelerin aynı anlamı taşımadığı görülebilir. Özellikle, dalların yönetimi çok farklıdır ve Git evreninden gelen birisi için özellikle kafa karıştırıcı olabilir. Bununla birlikte, bir Git reposunda bir Bazaar reposunda çalışmak mümkündür.

Git’i bir Bazaar istemcisi olarak kullanmanıza izin veren birçok proje bulunmaktadır. Burada, Felipe Contreras’in projesini kullanacağız ve bu projeyi şurada bulabilirsiniz: https://github.com/felipec/git-remote-bzr. Kurulum için, sadece git-remote-bzr dosyasını $PATH içeren bir klasöre indirmeniz yeterlidir:

$ wget https://raw.github.com/felipec/git-remote-bzr/master/git-remote-bzr -O ~/bin/git-remote-bzr
$ chmod +x ~/bin/git-remote-bzr

Ayrıca Bazaar’ın da kurulu olması gerekmektedir. Hepsi bu kadar!

Bazaar Reposundan Bir Git Reposu Oluşturmak

Kullanımı oldukça basittir. Bir Bazaar reposunu kopyalamak için onu bzr:: önekiyle kopyalamak yeterlidir. Hem Git hem de Bazaar, makinanıza tam kopyalar yapar; bu nedenle bir Git kopyasını yerel Bazaar kopyanıza bağlamak mümkündür, ancak önerilmez. Git kopyanızı doğrudan Bazaar kopyanızın bağlı olduğu yere (merkezi repo) bağlamak çok daha kolaydır.

Varsayalım ki bzr+ssh://developer@mybazaarserver:myproject adresinde bir uzak repo ile çalıştınız. O zaman onu şu şekilde kopyalamalısınız:

$ git clone bzr::bzr+ssh://developer@mybazaarserver:myproject myProject-Git
$ cd myProject-Git

Bu noktada, Git reposu oluşturulmuş olsa da, disk kullanımı için optimize edilmiş değildir. Bu yüzden, özellikle büyük bir repo ise, Git reposunuzu temizlemeniz ve sıkıştırmanız gerekmektedir:

$ git gc --aggressive

Bazaar Dalları

Bazaar sadece dalları kopyalamanıza izin verir, ancak bir repo birden çok dal içerebilir ve git-remote-bzr her ikisini de kopyalayabilir. Örneğin, bir dalı kopyalamak için:

$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs/trunk emacs-trunk

Ve tüm repoyu kopyalamak için:

$ git clone bzr::bzr://bzr.savannah.gnu.org/emacs emacs

İkinci komut, emacs reposunda bulunan tüm dalları kopyalar; yine de, belirli bazı dalları işaretlemek mümkündür:

$ git config remote-bzr.branches 'trunk, xwindow'

Bazı uzak repolar, dallarını listeleme izni vermez; bu durumda onları manuel olarak belirtmeniz gerekir. Kpyalama komutunda yapılandırmayı belirtmenize rağmen, bu yöntemi daha kolay bulabilirsiniz:

$ git init emacs
$ git remote add origin bzr::bzr://bzr.savannah.gnu.org/emacs
$ git config remote-bzr.branches 'trunk, xwindow'
$ git fetch

.bzrignore dosyasında neyin yok sayılacağını yoksayın.

Bazaar tarafından yönetilen bir projede çalıştığınızdan, .gitignore dosyası oluşturmamalısınız. Çünkü yanlışlıkla sürüm kontrolü altına alabilirsiniz ve Bazaar ile çalışan diğer kişiler bundan rahatsız olabilir. Çözüm, simgesel bir bağ olarak veya düzenli bir dosya olarak .git/info/exclude dosyasını oluşturmaktır. Bu sorunu nasıl çözeceğimizi daha sonra göreceğiz.

Bazaar, dosyaları yok saymak için Git ile aynı modeli kullanır, ancak benzersiz iki özelliğe de sahiptir. Tam açıklamayı dokümantasyonda bulabilirsiniz. Bahsettiğimiz iki özellik şunlardır:

  1. "!!", bir "!" kuralı kullanılarak belirtilse bile belirli dosya kalıplarını yok saymanızı sağlar.

  2. Bir satırın başında "RE:" yazmak, bir Python düzenli ifadesi belirtmenizi sağlar (Git yalnızca shell globlarını destekler).

Sonuç olarak, düşünülmesi gereken iki farklı durum vardır:

  1. Eğer .bzrignore dosyası bu iki belirli önekten herhangi birini içermiyorsa, o zaman sadece bir sembolik bağ oluşturabilirsiniz: ln -s .bzrignore .git/info/exclude

  2. Aksi takdirde, .git/info/exclude dosyasını oluşturmalı ve onu .bzrignore içindeki tam olarak aynı dosyaları yok sayacak şekilde uyarlamalısınız.

Ne olursa olsun, .bzrignore 'daki herhangi bir değişikliğe karşı dikkatli olmalı ve .git/info/exclude dosyasının her zaman .bzrignore 'u yansıttığından emin olmalısınız. Gerçekten de, eğer .bzrignore dosyası değişirse ve "!!" veya "RE:" ile başlayan bir veya daha fazla satır içeriyorsa; Git bu satırları yorumlayamadığından, .git/info/exclude dosyanızı .bzrignore ile aynı dosyaları yok sayacak şekilde uyarlamalısınız. Ayrıca, .git/info/exclude dosyası sembolik bir bağsa, önce sembolik bağı silmeniz, .bzrignore'u .git/info/exclude'a kopyalamanız ve daha sonra ikincisini uyarlamanız gerekecektir. Ancak dikkatli olun, çünkü Git’te bir dosyanın üst dizinini hariç tutarsanız, dosyayı yeniden dahil etmek imkansızdır.

Uzak Repodaki Değişiklikleri Getirmek

Uzak repodaki değişiklikleri getirmek için, Git komutlarını kullanarak değişiklikleri her zamanki gibi çekersiniz. Değişikliklerinizin "master" dalında olduğunu varsayarak, çalışmanızı "Origin/master" dalında birleştirir veya yeniden temellendirirsiniz:

$ git pull --rebase origin

Çalışmalarınızı Uzak Repoya İtmek

Bazaar’ın da birleştirme işlemi kavramı olduğu için, birleştirme işlemi içeren bir işlem yaparsanız sorun yaşamayacaksınız. Bu nedenle bir dalda çalışabilir, değişiklikleri `master`a birleştirebilir ve çalışmanızı gönderebilirsiniz. Sonra, dallarınızı oluşturur, çalışmanızı test eder ve normal şekilde kaydedersiniz. Son olarak, çalışmanızı Bazaar reposuna gönderirsiniz:

$ git push origin master

Uyarılar

Git’in uzak yardımcılar çerçevesinin geçerli bazı sınırlamaları vardır. Özellikle şu komutlar çalışmaz:

  • git Push Origin :branch-to-delete (Bazaar bu şekilde ref silme işlemlerini kabul edemez.)

  • git Push Origin old:new ("old" itilecektir)

  • git Push --dry-run Origin <dal> (itecektir)

  • git push origin :branch-to-delete (Bazaar can’t accept ref deletions in this way.)

  • git push origin old:new (it will push old)

  • git push --dry-run origin branch (it will push)

Özet

Git’in ve Bazaar’ın modelleri benzer olduğundan sınırın ötesinde çalışırken çok fazla direnç görülmez. Sınırlamalara dikkat ettiğiniz ve uzak reponun yerel olarak Git olmadığının her zaman farkında olduğunuz sürece sorun olmaz.

Git ve Perforce

Perforce, kurumsal ortamlarda çok popüler olan bir sürüm kontrol sistemidir. Bu, bu bölümde ele alınan, 1995’ten beri varolan en eski sistemdir. Bu nedenle, o günün kısıtlamaları dahilinde tasarlanmıştır: her zaman tek bir merkezi sunucuya bağlı olduğunuzu ve yerel diskte yalnızca bir sürümünün tutulduğunu varsayar. Elbette, özellikleri ve kısıtlamaları belirli problemlere yönelik çok uygun olmakla beraber, aslında Git’in daha iyi çalışacabileceği birçok projede yine de Perforce kullanılmaktadır.

Perforce ve Git’i karıştırmak isterseniz iki seçeneğiniz bulunmaktadır. İlk olarak, Perforce’un yapımcılarından Git Fusion köprüsünü ele alacağız, bu size Perforce depo ağacının alt kısımlarını okuma-yazma Git repoları olarak açmanızı sağlar. İkincisi, Perforce sunucusunun yeniden yapılandırılmasını gerektirmeyen Git’i bir Perforce istemcisi olarak kullanmanıza izin veren bir istemci tarafı köprüsü olan git-p4’tür.

Git Fusion

Perforce, bir Perforce sunucusunu sunucu tarafındaki Git repolarıyla senkronize eden "Git Fusion" adlı bir ürün sağlar. Bu ürünü http://www.perforce.com/git-fusion adresinden temin edebilirsiniz.

Kurulum

Örneklerimiz için, Git Fusion’ın en kolay kurulum yöntemini kullanacağız. Bu yöntem, Perforce cini (daemon) ve Git Fusion’ı çalıştıran bir sanal makine indirmeyi içerir. Sanal makine görüntüsünü http://www.perforce.com/downloads/Perforce/20-User adresinden edinebilir ve indirme tamamlandıktan sonra dilediğiniz bir sanallaştırma yazılımıyla (biz VirtualBox kullanacağız) içe aktarabilirsiniz.

Makineyi ilk çalıştırdığınızda, üç Linux kullanıcısı (root, perforce ve git) için özel şifre belirlemenizi ve bu kurulumu ağdaki diğer kurulumlardan ayırt etmek için bir örnek adı girmeniz istenir.

Bu işlemler tamamlandığında aşağıdakini göreceksiniz:

Git Fusion sanal makinesi başlangıç ekranı.
Görsel 145. Git Fusion sanal makinesi başlangıç ekranı.

İleride kullanacağınız için burada gösterilen IP adresini not etmelisiniz. Sonraki adımda bir Perforce kullanıcısı oluşturacağız. Alt kısımda bulunan Login seçeneğini seçin ve root olarak giriş yapın. Ardından aşağıdaki komutları kullanarak bir kullanıcı oluşturun:

$ p4 -p localhost:1666 -u super user -f john
$ p4 -p localhost:1666 -u john passwd
$ exit

İlk komut, kullanıcıyı özelleştirmek için bir VI düzenleyici açacak, ancak varsayılanları kabul ederek :wq yazıp enter tuşuna basarak çıkabilirsiniz. İkinci komut, sizden iki kez bir şifre girmenizi isteyecektir. Shell komut istemimizle yapmamız gereken bu kadar, bu yüzden oturumu kapatabilirsiniz.

İlerlemek için yapmanız gereken bir sonraki adım, Git’in SSL sertifikalarını doğrulamamasını söylemektir. Git Fusion görüntüsü bir sertifika ile birlikte gelir; ancak bu, sanal makinenizin IP adresiyle eşleşmeyecek bir alan adı için olduğundan, Git HTTPS bağlantısını reddedecektir. Bu kalıcı bir kurulum olacaksa, farklı bir sertifika yüklemek için Perforce Git Fusion kılavuzuna başvurun; ancak örnek amaçlarımız için, bu yeterlidir:

$ export GIT_SSL_NO_VERIFY=true

Şimdi her şeyin çalışıp çalışmadığını test edebiliriz.

$ git clone https://10.0.1.254/Talkhouse
Cloning into 'Talkhouse'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 630, done.
remote: Compressing objects: 100% (581/581), done.
remote: Total 630 (delta 172), reused 0 (delta 0)
Receiving objects: 100% (630/630), 1.22 MiB | 0 bytes/s, done.
Resolving deltas: 100% (172/172), done.
Checking connectivity... done.

Sanal makine görüntüsü, kopyalayabileceğiniz bir örnek proje ile birlikte gelir. Aşağıda, yukarıda oluşturduğumuz john kullanıcısı ile HTTPS üzerinden kopyalama işlemini gerçekleştiriyoruz; Git bu bağlantı için kimlik bilgisi isteyecek, ancak kimlik bilgisi önbelleği sonraki isteklerde bu adımı atlamamıza izin verecektir.

Fusion Yapılandırması

Git Fusion’ı kurduktan sonra yapılandırmayı ayarlamak isteyeceksiniz. Aslında bunu favori Perforce istemciniz kullanarak kolayca yapabilirsiniz; sadece Perforce sunucusundaki //.git-fusion dizinini çalışma alanınıza eşleyin. Dosya yapısı şuna benzer:

$ tree
.
├── objects
│   ├── repos
│   │   └── [...]
│   └── trees
│       └── [...]
│
├── p4gf_config
├── repos
│   └── Talkhouse
│       └── p4gf_config
└── users
    └── p4gf_usermap

498 directories, 287 files

objects dizini, Perforce nesnelerini Git’e ve tersine eşlemek için Git Fusion tarafından içsel olarak kullanılır. Bu dizindeki herhangi bir şeyle uğraşmanız gerekmez. Bu dizinde bir tane global p4gf_config dosyası bulunur ve her bir repo için de ayrı bir tane (bunlar, Git Fusion’ın nasıl davrandığını belirleyen yapılandırma dosyalarıdır). Şimdi, kök dizindeki dosyaya bir göz atalım:

[repo-creation]
charset = utf8

[git-to-perforce]
change-owner = author
enable-git-branch-creation = yes
enable-swarm-reviews = yes
enable-git-merge-commits = yes
enable-git-submodules = yes
preflight-commit = none
ignore-author-permissions = no
read-permission-check = none
git-merge-avoidance-after-change-num = 12107

[perforce-to-git]
http-url = none
ssh-url = none

[@features]
imports = False
chunked-push = False
matrix2 = False
parallel-push = False

[authentication]
email-case-sensitivity = no

Bu bayrakların anlamlarına burada girmeyeceğiz, ancak bunun yalnızca Git yapılandırması için kullanılan INI dosyaları gibi biçimlendirildiğini unutmayın. Bu dosya, repos/Talkhouse/p4gf_config gibi özel repo yapılandırma dosyaları tarafından geçersiz kılınabilecek global seçenekleri belirtir. Bu dosyayı açarsanız, global varsayılanlardan farklı olan bazı ayarları içeren [@repo] bölümünü göreceksiniz. Ayrıca şu şekilde görünen bölümler de göreceksiniz:

[Talkhouse-master]
git-branch-name = master
view = //depot/Talkhouse/main-dev/... ...

Bu, bir Perforce dalı ile bir Git dalı arasındaki eşlemeyi belirtir. Bölüm adı benzersiz olduğu sürece istediğiniz şekilde adlandırabilirsiniz. git-branch-name, Git altında sıkıntılı olabilecek bir depo yolunu daha dostane bir isme dönüştürmenize olanak tanır. view ayarı, Perforce dosyalarının Git reposuna eşlenme şeklini, standart görünüm eşleme sözdizimini (standard view mapping syntax) kullanarak kontrol eder. Bu örnekte olduğu gibi birden fazla eşleme belirtilebilir:

[multi-project-mapping]
git-branch-name = master
view = //depot/project1/main/... project1/...
       //depot/project2/mainline/... project2/...

Bu şekilde, normal çalışma alanı eşlemeleriniz dizin yapılarında değişiklikler içeriyorsa, bunu bir Git reposuyla çoğaltabilirsiniz.

Bahsedeceğimiz son dosya, Perforce kullanıcılarını Git kullanıcılarına eşleyen ve belki de hiç ihtiyaç duymayacağınız users/p4gf_usermap dosyasıdır. Bir Perforce değişiklik kümesi bir Git katkısına dönüştürülürken, Git Fusion’ın varsayılan davranışı; Perforce kullanıcısını aramak ve Git’teki yazar/adlandırıcı alanı için orada saklanan e-posta adresini ve tam adı kullanmaktır. Diğer yöne dönüştürülürken, varsayılan olarak, Git katkısının yazar alanında saklanan e-posta adresine sahip Perforce kullanıcısını aramak ve değişiklik kümesini, (uygulanan izinlerle) o kullanıcı olarak göndermektir. Çoğu durumda, bu yeterli olacaktır, ancak aşağıdaki eşleme dosyasını düşünün:

john john@example.com "John Doe"
john johnny@appleseed.net "John Doe"
bob employeeX@example.com "Anon X. Mouse"
joe employeeY@example.com "Anon Y. Mouse"

Her satır, bir kullanıcı eşlemesi oluşturan <user> <email> "<tam ad>" formatındadır. İlk iki satır, iki farklı e-posta adresini aynı Perforce kullanıcı hesabına eşler. Bu, birkaç farklı e-posta adresi altında (veya e-posta adreslerini değiştirip) Git katkıları oluşturduysanız, ancak bunların aynı Perforce kullanıcısına eşlenmesini istiyorsanız faydalıdır. Bir Git katkısı oluşturulurken, Perforce kullanıcısını eşleştiren ilk satır Git yazar bilgileri için kullanılır.

Son iki satır, Bob ve Joe’nun gerçek adlarını ve e-posta adreslerini oluşturulan Git katkılarından gizler. Bu, iç bir projeyi açık kaynağa dönüştürmek istiyorsanız, ancak çalışan dizininizi herkese yayınlamak istemiyorsanız iyidir. E-posta adreslerinin ve tam adların benzersiz olması gerektiğini unutmayın, aksi takdirde tüm Git katkıları tek bir kurgusal yazarla ilişkilendirilir.

İş Akışı

Perforce Git Fusion, Perforce ve Git sürüm kontrolü arasında iki yönlü bir köprüdür. Şimdi Git tarafından çalışmak nasıl hissettiriyor, ona bir göz atalım. Yukarıda gösterildiği gibi bir yapılandırma dosyasını kullanarak Jam projesini eşlediğimizi varsayalım. Şu şekilde kopyalayabiliriz:

$ git clone https://10.0.1.254/Jam
Cloning into 'Jam'...
Username for 'https://10.0.1.254': john
Password for 'https://john@10.0.1.254':
remote: Counting objects: 2070, done.
remote: Compressing objects: 100% (1704/1704), done.
Receiving objects: 100% (2070/2070), 1.21 MiB | 0 bytes/s, done.
remote: Total 2070 (delta 1242), reused 0 (delta 0)
Resolving deltas: 100% (1242/1242), done.
Checking connectivity... done.
$ git branch -a
* master
  remotes/origin/HEAD -> origin/master
  remotes/origin/master
  remotes/origin/rel2.1
$ git log --oneline --decorate --graph --all
* 0a38c33 (origin/rel2.1) Create Jam 2.1 release branch.
| * d254865 (HEAD, origin/master, origin/HEAD, master) Upgrade to latest metrowerks on Beos -- the Intel one.
| * bd2f54a Put in fix for jam's NT handle leak.
| * c0f29e7 Fix URL in a jam doc
| * cc644ac Radstone's lynx port.
[...]

Bunu ilk kez yaptığınızda, biraz zaman alabilir. Olup biten şey, Git Fusion’ın Perforce geçmişindeki tüm uygun değişiklikleri Git katkılarına dönüştürmesidir. Bu, sunucuda yerel olarak gerçekleştiği için, nispeten hızlıdır, ancak geçmişiniz çok kalabalıksa, biraz zaman alabilir. Sonraki çekmeler, artımlı dönüşüm yapar, bu yüzden Git’in kendi hızı gibi hissettirecektir.

Görebileceğiniz gibi, repomuz Git ile çalıştığınız diğer herhangi bir Git reposuna benzer. Üç dal var ve Git, origin/master'ı izleyen bir yerel master dalı oluşturdu. Biraz çalışıp birkaç yeni katkı oluşturalım:

# ...
$ git log --oneline --decorate --graph --all
* cfd46ab (HEAD, master) Add documentation for new feature
* a730d77 Whitespace
* d254865 (origin/master, origin/HEAD) Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]

İki yeni katkımız var. Şimdi başka birinin de çalışıp çalışmadığını kontrol edelim:

$ git fetch
remote: Counting objects: 5, done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 3 (delta 2), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://10.0.1.254/Jam
   d254865..6afeb15  master     -> origin/master
$ git log --oneline --decorate --graph --all
* 6afeb15 (origin/master, origin/HEAD) Update copyright
| * cfd46ab (HEAD, master) Add documentation for new feature
| * a730d77 Whitespace
|/
* d254865 Upgrade to latest metrowerks on Beos -- the Intel one.
* bd2f54a Put in fix for jam's NT handle leak.
[...]

Görünüşe göre biri çalışmış! Bu ekrandan bunu bilmezsiniz, ancak 6afeb15 katkısı aslında bir Perforce istemcisi kullanılarak oluşturuldu. Git’in açısından sadece başka bir katkı gibi görünüyor, işte bahsettiğimiz tam olarak bu. Şimdi Perforce sunucusunun bir birleştirme katkısı ile nasıl başa çıktığına bakalım:

$ git merge origin/master
Auto-merging README
Merge made by the 'recursive' strategy.
 README | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
$ git push
Counting objects: 9, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (9/9), done.
Writing objects: 100% (9/9), 917 bytes | 0 bytes/s, done.
Total 9 (delta 6), reused 0 (delta 0)
remote: Perforce: 100% (3/3) Loading commit tree into memory...
remote: Perforce: 100% (5/5) Finding child commits...
remote: Perforce: Running git fast-export...
remote: Perforce: 100% (3/3) Checking commits...
remote: Processing will continue even if connection is closed.
remote: Perforce: 100% (3/3) Copying changelists...
remote: Perforce: Submitting new Git commit objects to Perforce: 4
To https://10.0.1.254/Jam
   6afeb15..89cba2b  master -> master

Git’e göre iş tamam. Şimdi de Perforce açısından, p4v 'nin revizyon grafiği özelliğini kullanarak README dosyasının geçmişine bir göz atalım:

Git itmesinden kaynaklanan Perforce revizyon grafiği.
Görsel 146. Git itmesinden kaynaklanan Perforce revizyon grafiği.

Bu görüntüyü daha önce hiç görmediyseniz, kafa karıştırıcı görünebilir ancak tıpkı Git geçmişi için tasarlanan bir grafiksel görüntüleyici gibi çalışır. README dosyasının geçmişine bakıyoruz, bu yüzden sol üst köşedeki dizin ağacı, dosyanın çeşitli dallarda nasıl göründüğünü göstermetderir. Sağ üstte, dosyanın farklı revizyonlarının nasıl ilişkilendirildiğini gösteren bir görsel grafik vardır, sağ altta ise bu grafiğin genel görünümü bulunur. Geri kalan görünüm, seçilen revizyonun detaylı görünümüne (burada 2) ayrılmıştır.

Dikkat edilmesi gereken bir şey de, grafiğin tam olarak Git geçmişindeki gibi görünmesidir. Perforce, 1 ve 2 katkılarını depolamak için adlandırılmış bir dalı olmadığı için, onu saklamak için .git-fusion dizininde "isimsiz" bir dal oluşturdu. Bu davranış ismi olan Git dalları için de gerçekleşir (bu dalları daha sonra bir Perforce dalına yapılandırma dosyasını kullanarak eşleştirebilirsiniz).

Bunların çoğu arka planda gerçekleşir, ancak sonuç olarak bir ekip içinde bir kişi Git’i kullanırken, diğeri Perforce’u kullanabilir ve ikisi de diğerinin tercihinden haberdar olmaz.

Özet Olarak Git-Fusion

Perforce sunucunuza erişiminiz varsa (veya edinebilirseniz), Git Fusion’ın Git ve Perforce’un birbirleriyle iletişim kurmasının harika bir yolu olduğunu göreceksiniz. Bunun için biraz yapılandırma gereklidir, ancak öğrenme eğrisi çok dik değildir. Bu bölüm, Git’in tam gücünü kullanmanın sakıncalarıyla ilgili uyarıların pek yer almadığı nadir bölümlerden biridir. Bu, Perforce’un üzerine fırlattığınız her şeyden mutlu olacağı anlamına gelmez (mesela, zaten gönderilmiş olan geçmişi yeniden yazmaya çalışırsanız, Git Fusion bunu reddedecektir) ancak Git Fusion normal davranmak için çok çaba sarf eder. Hatta Git altmodüllerini bile kullanabilirsiniz (ancak bunlar Perforce kullanıcıları için garip görünebilir) ve dalları birleştirebilirsiniz (bu, Perforce tarafında bir entegrasyon olarak kaydedilecektir).

Sunucunuzun yöneticisini Git Fusion’ı kurmaya ikna edemezseniz, bu araçları birlikte kullanmanın yine de bir yolu vardır.

Git-p4

Git-p4, Git ile Perforce arasında iki yönlü bir köprüdür. Tamamen Git reposu içinde çalışır, bu nedenle Perforce sunucusuna erişim sağlamanıza gerek yoktur (elbette kullanıcı kimlik bilgilerine ihtiyacınız olacaktır). Git-p4, Git Fusion kadar esnek veya tam bir çözüm değildir, ancak sunucu ortamına aşırı müdahale etmeden istediğiniz çoğu şeyi yapmanıza izin verir.

Not

You’ll need the p4 tool somewhere in your PATH to work with git-p4. As of this writing, it is freely available at http://www.perforce.com/downloads/Perforce/20-User.

Kurulum

Örnek amaçlar için yukarıda gösterildiği gibi Git Fusion OVA’sından Perforce sunucusunu çalıştıracağız, ancak Git Fusion sunucusunu atlayacak ve doğrudan Perforce sürüm kontrolüne gideceğiz.

Git-p4’ün bağımlı olduğu p4 komut satırı istemcisini kullanabilmek için birkaç ortam değişkenini ayarlamanız gerekecektir:

$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
Başlarken

Git’teki herşeyde olduğu gibi, ilk iş kopyalamaktır:

$ git p4 clone //depot/www/live www-shallow
Importing from //depot/www/live into www-shallow
Initialized empty Git repository in /private/tmp/www-shallow/.git/
Doing initial import of //depot/www/live/ from revision #head into refs/remotes/p4/master

Bu, Git terimleriyle bir "yüzeysel" bir kopya oluşturur; sadece en son Perforce revizyonu Git’e aktarılır. Unutmayın, Perforce, her revizyonu her kullanıcıya vermek için tasarlanmamıştır! Bu, Git’i bir Perforce istemcisi olarak kullanmak için yeterlidir, ancak diğer amaçlar için yeterli değildir.

İşlem tamamlandığında, tamamen işlevsel bir Git reposuna sahip olacaksınız:

$ cd myproject
$ git log --oneline --all --graph --decorate
* 70eaf78 (HEAD, p4/master, p4/HEAD, master) Initial import of //depot/www/live/ from the state at revision #head

Perforce sunucusu için uzak bir p4 reposu var gibi görünse de, diğer her şey standart bir kopya gibi görünür. Aslında, bu biraz yanıltıcıdır; zira aslında bir uzak repo yoktur.

$ git remote -v

Bu repoda hiçbir uzak repo yoktur. Git-p4 sunucunun durumunu temsil etmek için bazı referanslar oluşturmuştur ve bunlar git log için uzak referanslara benzeyebilir, ancak Git’in kendisi tarafından yönetilmezler ve bunlara itme işlemi gerçekleştiremezsiniz.

İş Akışı

Hadi, biraz iş yapalım. Varsayalım ki çok önemli bir özellik üzerinde biraz ilerleme kaydettiniz ve geri kalan ekibinize göstermeye hazırsınız.

$ git log --oneline --all --graph --decorate
* 018467c (HEAD, master) Change page title
* c0fb617 Update link
* 70eaf78 (p4/master, p4/HEAD) Initial import of //depot/www/live/ from the state at revision #head

Perforce sunucusuna gönderilmeye hazır iki yeni katkımız var. Bugün başka birinin çalışıp çalışmadığını kontrol edelim:

$ git p4 sync
git p4 sync
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12142 (100%)
$ git log --oneline --all --graph --decorate
* 75cd059 (p4/master, p4/HEAD) Update copyright
| * 018467c (HEAD, master) Change page title
| * c0fb617 Update link
|/
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Görünüşe göre master ile p4/master ayrışmış durumda. Perforce’un dal sistemi kesinlikle Git’inki gibi değil, bu nedenle birleştirme katkılarını göndermek hiçbir anlam ifade etmez. Git-p4 katkılarınızı yeniden temellemenizi önerir ve hatta bunu yapmanız için size bir kısayol sunar:

$ git p4 rebase
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
No changes to import!
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
Applying: Update link
Applying: Change page title
 index.html | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

Çıktıdan anlayabilirsiniz ama git p4 rebase, git rebase p4/master'ı takiben git p4 sync için bir kısayoldur. Özellikle birden fazla dal üzerinde çalışırken biraz daha akılcı bir yöntem ve iyi bir yaklaşımdır.

Şimdi geçmişimiz tekrar çizgisel hale geldi ve değişikliklerimizi Perforce’a tekrar katkıda bulunmaya hazırız. git p4 submit komutu, p4/master ile master arasındaki her Git katkısı için yeni bir Perforce revizyonu oluşturmaya çalışacaktır. Çalıştırdığımızda, bizi favori metin düzenleyicimize götürür ve dosyanın içeriği şuna benzemektedir:

# A Perforce Change Specification.
#
#  Change:      The change number. 'new' on a new changelist.
#  Date:        The date this specification was last modified.
#  Client:      The client on which the changelist was created.  Read-only.
#  User:        The user who created the changelist.
#  Status:      Either 'pending' or 'submitted'. Read-only.
#  Type:        Either 'public' or 'restricted'. Default is 'public'.
#  Description: Comments about the changelist.  Required.
#  Jobs:        What opened jobs are to be closed by this changelist.
#               You may delete jobs from this list.  (New changelists only.)
#  Files:       What opened files from the default changelist are to be added
#               to this changelist.  You may delete files from this list.
#               (New changelists only.)

Change:  new

Client:  john_bens-mbp_8487

User: john

Status:  new

Description:
   Update link

Files:
   //depot/www/live/index.html   # edit


######## git author ben@straub.cc does not match your p4 account.
######## Use option --preserve-user to modify authorship.
######## Variable git-p4.skipUserNameCheck hides this message.
######## everything below this line is just the diff #######
--- //depot/www/live/index.html  2014-08-31 18:26:05.000000000 0000
+++ /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/index.html   2014-08-31 18:26:05.000000000 0000
@@ -60,7 +60,7 @@
 </td>
 <td valign=top>
 Source and documentation for
-<a href="http://www.perforce.com/jam/jam.html">
+<a href="jam.html">
 Jam/MR</a>,
 a software build tool.
 </td>
Bir Perforce Değişiklik Belgesi.

Değişiklik: Değişiklik numarası. Yeni bir değişiklik listesi için 'new.
Tarih:      Bu belgenin son olarak ne zaman değiştirildiği.
İstemci:    Değişiklik listesinin oluşturulduğu istemci. Salt okunur.
Kullanıcı:  Değişiklik listesini oluşturan kullanıcı.
Durum:      'pending' veya 'submitted' olabilir. Salt okunur.
Tür:        'public' veya 'restricted' olabilir. Varsayılan olarak 'public'.
Açıklama:   Değişiklik listesi hakkındaki yorumlar. Gereklidir.
İşler:      Bu değişiklik listesi tarafından kapatılacak açık işler.
            Bu listeden işleri silebilirsiniz. (Yeni değişiklik listeleri için.)
Dosyalar:   What opened files from the default changelist are to be added to this changelist.
            You may delete files from this list. (New changelists only.)

Bu, p4 submit komutunu çalıştırarak görebileceğiniz içeriğin çoğunlukla aynısıdır, ancak git-p4’ün yardımcı olarak dahil ettiği son kısımdan farklıdır. Git-p4, bir katkı veya değişiklik kümesi için bir isim sağlamak zorunda kaldığında, Git ve Perforce ayarlarınızı ayrı ayrı dikkate almaya çalışır, ancak bazı durumlarda bunu geçersiz kılmak isteyebilirsiniz. Örneğin, içe aktardığınız Git katkısı bir Perforce kullanıcı hesabı olmayan bir katılımcı tarafından yazılmışsa; sonuçta oluşan değişiklik kümesinin, sizin tarafınızdan değil de onun tarafından yazıldığı gibi görünmesini isteyebilirsiniz.

Git-p4, bu Perforce değişiklik listesi için içerik olarak Git katkı mesajı ithal ettiği için, yapmamız gereken tek şey her bir katkı için kaydetmek ve çıkmaktır. Sonuçta oluşan shell çıktısı şuna benzer olacaktır:

$ git p4 submit
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Synchronizing p4 checkout...
... - file(s) up-to-date.
Applying dbac45b Update link
//depot/www/live/index.html#4 - opened for edit
Change 12143 created with 1 open file(s).
Submitting change 12143.
Locking 1 files ...
edit //depot/www/live/index.html#5
Change 12143 submitted.
Applying 905ec6a Change page title
//depot/www/live/index.html#5 - opened for edit
Change 12144 created with 1 open file(s).
Submitting change 12144.
Locking 1 files ...
edit //depot/www/live/index.html#6
Change 12144 submitted.
All commits applied!
Performing incremental import into refs/remotes/p4/master git branch
Depot paths: //depot/www/live/
Import destination: refs/remotes/p4/master
Importing revision 12144 (100%)
Rebasing the current branch onto remotes/p4/master
First, rewinding head to replay your work on top of it...
$ git log --oneline --all --graph --decorate
* 775a46f (HEAD, p4/master, p4/HEAD, master) Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Sonuçta, aslında git push yapmışız gibi oldu, bu gerçekte olan şeye en yakın benzetimdir.

Bu süreçte her Git katkısı bir Perforce değişiklik kümesine dönüştürülür. Eğer onları tek bir değişiklik kümesine sıkıştırmak istiyorsanız, bunu git p4 submit komutunu çalıştırmadan önce, etkileşimli bir temelleme ile yapabilirsiniz. Ayrıca, değişiklik kümesi olarak gönderilen tüm katkıların SHA-1 karmalarının değiştiğini unutmayın. Bu, git-p4’ün dönüştürdüğü her katkıya bir satır eklemesinden kaynaklanır:

$ git log -1
commit 775a46f630d8b46535fc9983cf3ebe6b9aa53145
Author: John Doe <john@example.com>
Date:   Sun Aug 31 10:31:44 2014 -0800

    Change page title

    [git-p4: depot-paths = "//depot/www/live/": change = 12144]

Birleştirme katkısını göndermeye çalışırsak ne olacağını bir görelim. İşte kendimizi içine soktuğumuz durum:

$ git log --oneline --all --graph --decorate
* 3be6fd8 (HEAD, master) Correct email address
*   1dcbf21 Merge remote-tracking branch 'p4/master'
|\
| * c4689fc (p4/master, p4/HEAD) Grammar fix
* | cbacd0a Table borders: yes please
* | b4959b6 Trademark
|/
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Git ve Perforce geçmişi 775a46f sonrasında ayrılıyor. Git tarafında iki katkı var, ardından Perforce başı ile birleştirme katkısı, ve onun ardından başka bir katkı daha. Bu katkıları tek bir değişiklik kümesinin üzerine Perforce tarafında göndermeyi deneyeceğiz. Şimdi göndermeye çalışırsak ne olacağını görelim:

$ git p4 submit -n
Perforce checkout for depot path //depot/www/live/ located at /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would synchronize p4 checkout in /Users/ben/john_bens-mbp_8487/john_bens-mbp_8487/depot/www/live/
Would apply
  b4959b6 Trademark
  cbacd0a Table borders: yes please
  3be6fd8 Correct email address

-n bayrağı, --dry-run için kısaltmadır ve gönderme komutunun gerçekten çalıştırılsaydı ne olacağını rapor etmeye çalışır. Burada, üç adet Perforce değişiklik kümesi oluşturacağımızı gösteriyor. Bunlar Perforce sunucusunda henüz bulunmayan birleştirmesiz (non-merge) üç katkıya karşılık gelir. Tam olarak istediğimiz gibi görünüyor. Şimdi nasıl sonuçlandığını görelim:

$ git p4 submit
[…]
$ git log --oneline --all --graph --decorate
* dadbd89 (HEAD, p4/master, p4/HEAD, master) Correct email address
* 1b79a80 Table borders: yes please
* 0097235 Trademark
* c4689fc Grammar fix
* 775a46f Change page title
* 05f1ade Update link
* 75cd059 Update copyright
* 70eaf78 Initial import of //depot/www/live/ from the state at revision #head

Geçmişimiz, katkıları göndermeden önce yeniden temellemişiz gibi çizgisel hale geldi (gerçekte olan budur). Bu, Git tarafında dallar oluşturabileceğiniz, üzerinde çalışabileceğiniz, silebileceğiniz, birleştirebileceğiniz ve geçmişinizin Perforce ile uyumsuz hale gelme korkusu olmadan özgürce çalışabileceğiniz anlamına gelir. Yeniden temelleme yaparsanız, bunu bir Perforce sunucusuna gönderebilirsiniz.

Dallandırma

Perforce projenizde birden fazla dal bulunuyorsa, şansınız tükenmiş değil, git-p4 bunu Gitmişçesine yönetebilir. Diyelim ki Perforce deponuz şu şekilde düzenlenmiş:

//depot
  └── project
      ├── main
      └── dev

Ve diyelim ki dev adında bir dalınız var ve bu dalın bir görünüm özelliği şu şekilde görünüyor:

//depot/project/main/... //depot/project/dev/...

Git-p4 bu durumu otomatik olarak algılayabilir ve doğru işlemi yapabilir:

$ git p4 clone --detect-branches //depot/project@all
Importing from //depot/project@all into project
Initialized empty Git repository in /private/tmp/project/.git/
Importing revision 20 (50%)
    Importing new branch project/dev

    Resuming with change 20
Importing revision 22 (100%)
Updated branches: main dev
$ cd project; git log --oneline --all --graph --decorate
* eae77ae (HEAD, p4/master, p4/HEAD, master) main
| * 10d55fb (p4/project/dev) dev
| * a43cfae Populate //depot/project/main/... //depot/project/dev/....
|/
* 2b83451 Project init

Depo yolundaki ``@all`` belirleyicisine dikkat edin: git-p4’e yalnızca bu alt ağaç için en son değişiklik kümesini değil, bu dizinlere dokunmuş tüm değişiklik kümelerini kopyalamasını söyler. Bu Git’in kopya (clone) kavramına daha yakındır, ancak geçmişi uzun bir projede çalışıyorsanız, biraz zaman alabilir.

--detect-branches bayrağı git-p4’ün Perforce’un dal özelliklerini kullanarak dalları Git referanslarına eşlemesini söyler. Bu eşlemeler Perforce sunucusunda bulunmuyorsa (bu, Perforce’u kullanmanın tamamen geçerli bir yoludur), git-p4’e dal eşlemelerinin ne olduğunu söyleyebilirsiniz ve aynı sonucu alırsınız:

$ git init project
Initialized empty Git repository in /tmp/project/.git/
$ cd project
$ git config git-p4.branchList main:dev
$ git clone --detect-branches //depot/project@all .

git-p4.branchList yapılandırma değişkenini main:dev olarak ayarlamak, git-p4’e ``main`` ve ``dev`` 'in her ikisinin de dallar olduğunu ve ikincisinin birincisinin bir alt dalı olduğunu söyler.

Şimdi git checkout -b dev p4/project/dev yapar ve bazı katkılar işlersek, git p4 submit yaptığımızda git-p4’ün doğru dala hedef alacak kadar akıllı olduğunu göreceğiz. Ne yazık ki, git-p4 sığ kopyaları ve birden fazla dalı karıştıramaz. Büyük bir projede ve birden fazla dalda çalışmak istiyorsanız, göndermek istediğiniz her dal için bir kez git p4 clone yapmanız gerekecektir.

Dallar oluşturmak veya entegre etmek için bir Perforce istemcisini kullanmanız gerekecektir. Git-p4 yalnızca mevcut dalları senkronize edip ve kaydedebilir ve bunu da sadece bir çizgisel değişiklik kümesiyle yapabilir. Eğer Git’te iki dalı birleştirir ve yeni değişiklik kümesini göndermeye çalışırsanız, kaydedilen tek şey bir sürü dosya değişikliği olacaktır. Entegrasyona hangi dalların katıldığına dair meta veriler kaybolacaktır.

Özetle Git ve Perforce

Git-p4, bir Perforce sunucusu ile Git iş akışını kullanmayı mümkün kılar ve bu konuda oldukça iyidir. Ancak kaynakların kontrolünün Perforce’da olduğunu ve Git’i sadece yerelde çalışmak için kullandığınızı unutmamalısınız. Git katkılarını paylaşırken çok dikkatli olun. Başkalarıyla ortak kullandığız bir uzak sunucunuz varsa, Perforce sunucusuna göndermediğiniz hiçbir katkıyı oraya göndermeyin.

Eğer Perforce ve Git’i özgürce kaynak kontrolü istemcileri olarak karıştırmak ister ve sunucu yöneticisini bunu kurmaya ikna edebilirseniz; Git Fusion, Git’i bir Perforce sunucusu için birinci sınıf bir versiyon kontrol istemcisi olarak kullanmanızı sağlar.

Git ve TFS

Git Windows geliştiricileri arasında gittikçe daha popüler hale gelmektedir ve eğer Windows üzerinde kod yazıyorsanız, Microsoft’un Team Foundation Server (TFS) kullanma olasılığınız yüksektir. TFS, hata ve iş öğesi izleme, Scrum ve diğerleri için süreç desteği, kod incelemesi ve sürüm kontrolü gibi işbirliği paketini içerir. Ancak önümüzde biraz kafa karışıklığı vardır: TFS kendi özel VCS’leri olan TFVC (Team Foundation Version Control) ile birlikte Git’i de destekleyen bir sunucudur. Git desteği TFS’in nispeten yeni bir özelliğidir (2013 sürümü ile birlikte gelmiştir), bu yüzden daha öncesindeki tüm araçlar, çoğunlukla TFVC ile çalışsalar da sürüm kontrol kısmını "TFS" olarak adlandırırlar.

Eğer kendinizi TFVC kullanan bir takımda bulursanız ve sürüm kontrol istemci olarak Git’i tercih ediyorsanız, sizin için bir proje bulunmaktadır.

Hangi Araç

İki tane bulunmaktadır: git-tf ve git-tfs.

Git-tfs (https://github.com/git-tfs/git-tfs adresinde bulabilirsiniz) yalnızca Windows’ta çalışın bir .NET projesidir. Git repolarıyla çalışmak için libgit2 için .NET bağlantılarını kullanır. Libgit2 Git’in kütüphane odaklı bir uygulamasıdır ve Git reposunun iç yapısında esneklik ve yüksek performans sağlar. Libgit2, Git’in tam bir uygulaması değildir, bu yüzden farklılıkları kapsamak için bazı işlemlerde aslında komut satırı Git istemcisini çağırır. Yani, Git repolarıyla yapabileceği işlemler üzerinde yapay sınırlamalar yoktur. Sunucu işlemleri için Visual Studio derlemelerini kullandığı için, TFVC özelliklerine olan desteği çok ileri seviyededir. Bu, bu derlemelere erişiminizin olması gerektiği anlamına gelir, yani son sürüm bir Visual Studio (2010 sürümünden itibaren herhangi bir sürüm, 2012 sürümünden itibaren Express sürümleri dahil) veya Visual Studio SDK’sı kurmanız gerekir.

Git-tf (https://gittf.codeplex.com adresinde bulabilirsiniz) bir Java projesidir ve Java çalışma ortamına (runtime environment) sahip her bilgisayarda çalışır. Git repolarıyla JGit (Git’in JVM uygulaması) aracılığıyla etkileşir, bu da Git işlevleri açısından neredeyse hiçbir kısıtlaması olmadığı anlamına gelir. Ancak, git-tfs’e kıyasla TFVC desteği sınırlıdır (örneğin dalları desteklemez).

Her bir aracın avantajları ve dezavantajları vardır ve birini diğerine tercih eden birçok durum bulunur. Bu kitapta her ikisinin de temel kullanımını ele alacağız.

Not

Bu yönergeleri takip etmek için TFVC tabanlı bir repoya erişiminiz olması gerekecek. Bunlar genelde Git veya Subversion repoları kadar yaygın değildir, bu yüzden kendi TFVC tabanlı reponuzu oluşturmanız gerekebilir. Codeplex (https://www.codeplex.com) veya Visual Studio Online (https://visualstudio.microsoft.com) araçlarının her ikisi de bunun için iyi seçeneklerdir.

git-tf Giriş

Herhangi bir Git projesi gibi, ilk yapmanız gereken kopyalamadır. İşte git-tf ile bunun nasıl yapıldığı:

$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main project_git

İlk argüman, bir TFVC koleksiyonunun URL’sidir, ikincisi $ / proje / dal formunda ve üçüncüsü oluşturulacak yerel Git reposunun dizinidir (bu sonuncusu isteğe bağlıdır). Git-tf tek seferde yalnızca bir dalda çalışabilir: farklı bir TFVC dalında geçiş yapmak istiyorsanız, o daldan yeni bir klon oluşturmanız gerekecektir.

Bu tam olarak işlevsel bir Git reposu oluşturur:

$ cd project_git
$ git log --all --oneline --decorate
512e75a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Checkin message

Bu, yalnızca en son değişiklik setinin indirildiği sığ bir klon denir. TFVC her istemcinin tüm geçmişin tam bir kopyasına sahip olması için tasarlanmamıştır, bu nedenle git-tf varsayılan olarak yalnızca en son sürümü almak için ayarlanmıştır ki bu çok daha hızlıdır.

Eğer zamanınız varsa --deep seçeneğini kullanarak tüm proje geçmişini kopyalamakta fayda vardır:

$ git tf clone https://tfs.codeplex.com:443/tfs/TFS13 $/myproject/Main \
  project_git --deep
Username: domain\user
Password:
Connecting to TFS...
Cloning $/myproject into /tmp/project_git: 100%, done.
Cloned 4 changesets. Cloned last changeset 35190 as d44b17a
$ cd project_git
$ git log --all --oneline --decorate
d44b17a (HEAD, tag: TFS_C35190, origin_tfs/tfs, master) Goodbye
126aa7b (tag: TFS_C35189)
8f77431 (tag: TFS_C35178) FIRST
0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
        Team Project Creation Wizard

TFS_C35189 gibi adlara sahip etiketlere dikkat edin: bu hangi Git commit’lerinin TFVC değişiklik setleri ile ilişkilendirildiğini bilmeye yardımcı olan bir özelliktir. Bu basit bir log komutu ile hangi katkılarınızın TFVC’de de bulunan bir poz ile ilişkili olduğunu görebileceğiniz, hoş bir yoldur. Bunlar aslında gerekli değildir (git config git-tf.tag false ile de bunları kapatabilirsiniz). git-tf gerçek katkı-değişiklik seti eşlemelerini .git/git-tf dosyasında tutar.

git-tfs Giriş

Git-tfs klonlaması biraz farklı davranır. İnceleyin:

PS> git tfs clone --with-branches \
    https://username.visualstudio.com/DefaultCollection \
    $/project/Trunk project_git
Initialized empty Git repository in C:/Users/ben/project_git/.git/
C15 = b75da1aba1ffb359d00e85c52acb261e4586b0c9
C16 = c403405f4989d73a2c3c119e79021cb2104ce44a
Tfs branches found:
- $/tfvc-test/featureA
The name of the local branch will be : featureA
C17 = d202b53f67bde32171d5078968c644e562f1c439
C18 = 44cd729d8df868a8be20438fdeeefb961958b674

--with-branches bayrağına dikkat edin. Git-tfs TFVC dallarını Git dallarına eşleyecek yetenektedir ve bu bayrak her TFVC dalı için yerel bir Git dalı kurmasını söyler. Bu TFS’de şimdiye kadar dallandırma veya birleştirme yaptıysanı kesinlikle önerilir, ancak TFS 2010’dan önceki bir sunucu ile çalışmaz (bu sürümden önce "dallar" sadece klasörlerdi, bu yüzden git-tfs onları normal klasörlerden ayırt edemez).

Şimdi oluşan Git reposuna bir göz atalım:

PS> git log --oneline --graph --decorate --all
* 44cd729 (tfs/featureA, featureA) Goodbye
* d202b53 Branched from $/tfvc-test/Trunk
* c403405 (HEAD, tfs/default, master) Hello
* b75da1a New project
PS> git log -1
commit c403405f4989d73a2c3c119e79021cb2104ce44a
Author: Ben Straub <ben@straub.cc>
Date:   Fri Aug 1 03:41:59 2014 +0000

    Hello

    git-tfs-id: [https://username.visualstudio.com/DefaultCollection]$/myproject/Trunk;C16

İki yerel dal vardır: master ve featureA. Bu da kopyalamanın başlangıç noktasını (TFVC’de Trunk) ve bir alt dalı (TFVC’de featureA) temsil eder. Ayrıca tfs "remote" da TFVC dallarını temsil eden bir çift referans da bulunur: default ve featureA. Git-tfs kopyaladığınız dalı tfs/default ile eşler, diğerleri kendi adlarını alır.

Dikkate değer bir başka bir şey de Katkı mesajlarındaki git-tfs-id: satırlarıdır. git-tfs etiketler yerine bu işaretleri kullanarak TFVC değişiklik setlerini Git katkılarıyla ilişkilendirir. Bu Git katkılarınızın TFVC’ye gönderilmeden önce ve sonra farklı SHA-1 karma değerlerine sahip olacağı anlamına gelir.

Git-tf[s] İş Akışı

Not

Hangi aracı kullandığınızdan bağımsız olarak, sorunlarla karşılaşmamak için birkaç Git yapılandırma değerini ayarlamanız önerilir.

$ git config set --local core.ignorecase=true
$ git config set --local core.autocrlf=false

Sıradaki işiniz bir projede çalışmak olacaktır. TFVC ve TFS iş akışınıza karmaşıklık katabilecek birkaç özellik sunar:

  1. TFVC’de temsil edilmeyen özellik dalları karmaşıklığı arttırır. Bu TFVC ve Git’in dalları temsil etme şekillerinin çok farklı olmasından kaynaklanır.

  2. TFVC kullanıcıların dosyaları sunucudan "checkout" yapıp kilitleyerek, başkalarının onları değiştirmesini engellemenize izin verir. Bu, elbette, dosyaları yerel repoda düzenlemeyi engellemeyecektir, ancak değişikliklerinizi TFVC sunucusuna yüklerken engel olabilir.

  3. TFS’nin "gated" checkin kavramı vardır, burada bir TFS derleme-test döngüsünün başarıyla tamamlanması gerekmektedir. Bu, TFVC’de shelve işlevini kullanır, ancak burada bunu incelemeyeceğiz. Bu işlemi git-tf ile manuel olarak taklit edebilirsiniz ve git-tfs gate bilgisine sahip olan checkintool komutunu sağlar.

Kısa ve öz olması adına, burada kapsayacağımız şey, çoğu bu sorunları atlatmanızı veya onlardan kaçınmanızı sağlayacak "mutlu patika" olacaktır.

git-tf İş Akışı

Diyelim ki biraz çalışma yaptınız, master üzerinde birkaç Git katkısı yaptınız ve ilerlemenizi TFVC sunucusuyla paylaşmaya hazırsınız. İşte Git repomuz:

$ git log --oneline --graph --decorate --all
* 4178a82 (HEAD, master) update code
* 9df2ae3 update readme
* d44b17a (tag: TFS_C35190, origin_tfs/tfs) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

4178a82 katkısındaki pozu almak ve bunu TFVC sunucusuna yüklemek istiyoruz. Öncelikle, son bağlandığımızdan beri takım arkadaşlarımızın bir şeyler yapıp yapmadığını kontrol edelim:

$ git tf fetch
Username: domain\user
Password:
Connecting to TFS...
Fetching $/myproject at latest changeset: 100%, done.
Downloaded changeset 35320 as commit 8ef06a8. Updated FETCH_HEAD.
$ git log --oneline --graph --decorate --all
* 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text
| * 4178a82 (HEAD, master) update code
| * 9df2ae3 update readme
|/
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Görünüşe göre başka biri de çalışıyor ve şimdi farklı geçmişlerimiz var. İşte Git’in parladığı yer burasıdır, ancak ilerlemek için iki seçeneğimiz var:

  1. Birleştirme bir Git kullanıcısı olarak doğal hissettirir (sonuçta bu git pull 'un yaptığı şeydir) ve git-tf bunu basit bir git tf pull ile yapabilir. Ancak TFVC bu şekilde düşünmez ve birleştirme işlemlerini gönderirseniz; geçmişiniz her iki tarafta da farklı görünmeye başlayacaktır, bu da kafa karıştırıcı olabilir. Bununla birlikte, tüm değişikliklerinizi bir değişiklik seti olarak göndermeyi planlıyorsanız, bu muhtemelen en kolay seçenektir.

  2. Yeniden temelleme katkı geçmişimizi çizgisel hale getirir, bu da her bir Git katkısını bir TFVC değişiklik setine dönüştürme seçeneğimizin olduğu anlamına gelir. En fazla seçeneği açık bıraktığından, bunu yapmanızı öneririz (git-tf bunu bile git tf pull --rebase ile size kolaylaştırır).

Tercih sizin. Biz bu örnekte yeniden temelleme yapacağız:

$ git rebase FETCH_HEAD
First, rewinding head to replay your work on top of it...
Applying: update readme
Applying: update code
$ git log --oneline --graph --decorate --all
* 5a0e25e (HEAD, master) update code
* 6eb3eb5 update readme
* 8ef06a8 (tag: TFS_C35320, origin_tfs/tfs) just some text
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Şimdi TFVC sunucusuna bir geçmeye hazırız. Git-tf son değişiklikten bu yana tüm değişiklikleri temsil eden tek bir değişiklik seti yapma (varsayılan seçenek olan --shallow) veya her Git katkısı için yeni bir değişiklik seti oluşturma (--deep) seçeneği sunar. Bu örnekte sadece bir değişiklik seti oluşturacağız:

$ git tf checkin -m 'Updating readme and code'
Username: domain\user
Password:
Connecting to TFS...
Checking in to $/myproject: 100%, done.
Checked commit 5a0e25e in as changeset 35348
$ git log --oneline --graph --decorate --all
* 5a0e25e (HEAD, tag: TFS_C35348, origin_tfs/tfs, master) update code
* 6eb3eb5 update readme
* 8ef06a8 (tag: TFS_C35320) just some text
* d44b17a (tag: TFS_C35190) Goodbye
* 126aa7b (tag: TFS_C35189)
* 8f77431 (tag: TFS_C35178) FIRST
* 0745a25 (tag: TFS_C35177) Created team project folder $/tfvctest via the \
          Team Project Creation Wizard

Yeni bir TFS_C35348 etiketi var, bu da TFVC’nin tam olarak 5a0e25e katkısındaki aynı pozu sakladığını gösteriyor. Her Git katkısının TFVC’de tam bir karşılığa sahip olması gerekmediğini bilmek önemlidir: örneğin, 6eb3eb5 katkısı sunucudaki hiçbir yerde mevcut değildir.

Bu ana iş akışıdır. Aklınızda bulundurmanız gereken birkaç başka husus var:

  • Dallanma yoktur. Git-tf bir TFVC dalından yalnızca bir Git reposu oluşturabilir.

  • TFVC veya Git kullanarak işbirliği yapın, ancak her ikisini birden kullanmayın. Aynı TFVC reposunun farklı git-tf kopyaları farklı SHA-1 karma değerlerine sahip olabilir, bu da baş ağrısına neden olabilir.

  • Takımınızın iş akışı, Git’te işbirliği yapmayı ve düzenli aralıklarla TFVC ile senkronize etmeyi içeriyorsa, TFVC’ye sadece Git repolarından biriyle bağlanın.

git-tfs İş Akışı

Aynı senaryoyu git-tfs kullanarak adım adım geçelim. İşte Git reposundaki master dalına işlediğimiz yeni katkılar:

PS> git log --oneline --graph --all --decorate
* c3bd3ae (HEAD, master) update code
* d85e5a2 update readme
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 (tfs/default) Hello
* b75da1a New project

Şimdi, biz çalışırken başka birinin iş yapmış olup olmadığını görelim:

PS> git tfs fetch
C19 = aea74a0313de0a391940c999e51c5c15c381d91d
PS> git log --all --oneline --graph --decorate
* aea74a0 (tfs/default) update documentation
| * c3bd3ae (HEAD, master) update code
| * d85e5a2 update readme
|/
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Evet, iş arkadaşımız aea74a0 katkısıyla yeni bir TFVC değişiklik seti eklemiş ve tfs/default uzak dalı hareket etmiş.

Git-tf ile olduğu gibi, bu ayrık geçmişi nasıl çözeceğimize dair iki temel seçeneğimiz var:

  • çizgisel geçmişi korumak için yeniden temelleme.

  • Gerçekte ne olduğunu korumak için birleştirme.

Bu durumda, her Git katkısının bir TFVC değişiklik seti haline geldiği bir deep (derin) katkılama yapacağız, bu yüzden yeniden temellemek istiyoruz.

PS> git rebase tfs/default
First, rewinding head to replay your work on top of it...
Applying: update readme
Applying: update code
PS> git log --all --oneline --graph --decorate
* 10a75ac (HEAD, master) update code
* 5cec4ab update readme
* aea74a0 (tfs/default) update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Şimdi katkımızı tamamlamak için kodumuzu TFVC sunucusuna işlemeye hazırız. Burada her Git katkısının HEAD kısmandan, ilk bulunan tfs uzak dalına kadar olan yol boyunca bir TFVC değişiklik seti oluşturmak için rcheckin komutunu kullanacağız (checkin komutu Git katkılarını birleştirmek gibi, sadece bir değişiklik seti oluşturur).

PS> git tfs rcheckin
Working with tfs remote: default
Fetching changes from TFS to minimize possibility of late conflict...
Starting checkin of 5cec4ab4 'update readme'
 add README.md
C20 = 71a5ddce274c19f8fdc322b4f165d93d89121017
Done with 5cec4ab4b213c354341f66c80cd650ab98dcf1ed, rebasing tail onto new TFS-commit...
Rebase done successfully.
Starting checkin of b1bf0f99 'update code'
 edit .git\tfs\default\workspace\ConsoleApplication1/ConsoleApplication1/Program.cs
C21 = ff04e7c35dfbe6a8f94e782bf5e0031cee8d103b
Done with b1bf0f9977b2d48bad611ed4a03d3738df05ea5d, rebasing tail onto new TFS-commit...
Rebase done successfully.
No more to rcheckin.
PS> git log --all --oneline --graph --decorate
* ff04e7c (HEAD, tfs/default, master) update code
* 71a5ddc update readme
* aea74a0 update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

Her başarılı checkin işleminin ardından, git-tfs’in kalan işi yeni yaptığı işin üzerine yeniden temellemesi dikkatinizi çekmiş olabilir. Bunun nedeni, katkı mesajlarının altına git-tfs-id alanını eklemesidir, bu da SHA-1 karma değerlerini değiştirir. Bu tam olarak tasarlandığı gibidir ve endişelenecek bir şey yoktur, ancak özellikle de Git katkılarını başkalarıyla paylaşıyorsanız, bunun farkında olmanız önemlidir.

TFS’nin birçok özelliği, iş öğeleri, atanmış gözden geçirenler, kontrollü checkinler vb. gibi sürüm kontrol sistemi ile entegre olan özellikleri bulunmaktadır. Sadece komut satırı aracını kullanarak bu özelliklerle çalışmak sıkıcı olabilir, ancak neyse ki git-tfs çok kolay bir şekilde grafiksel bir checkin aracı başlatabilmenizi sağlar:

PS> git tfs checkintool
PS> git tfs ct

Biraz şöyle şunun gibi görünür:

git-tfs checkin aracı.
Görsel 147. git-tfs checkin aracı.

Bu TFS kullanıcılarının aşina olduğu şekilde, Visual Studio içinden başlatılan iletişim kutusuna benzer.

Git-tfs ayrıca Git reposundan TFVC dallarını kontrol etmenizi sağlar. Bir örnek olarak, bir tane oluşturalım:

PS> git tfs branch $/tfvc-test/featureBee
The name of the local branch will be : featureBee
C26 = 1d54865c397608c004a2cadce7296f5edc22a7e5
PS> git log --oneline --graph --decorate --all
* 1d54865 (tfs/featureBee) Creation branch $/myproject/featureBee
* ff04e7c (HEAD, tfs/default, master) update code
* 71a5ddc update readme
* aea74a0 update documentation
| * 44cd729 (tfs/featureA, featureA) Goodbye
| * d202b53 Branched from $/tfvc-test/Trunk
|/
* c403405 Hello
* b75da1a New project

TFVC’de bir dal oluşturmak, bu dalın artık bulunduğu bir değişiklik seti eklemeyi ve bu değişiklik setinin bir Git katkısı olarak yansıtıldığı anlamına gelir. Ayrıca git-tfs’nin tfs/featureBee uzak dalını oluşturduğunu, ancak HEAD 'in hâlâ main 'i gösterdiğini unutmayın. Yeni oluşturulan dal üzerinde çalışmak istiyorsanız, belki de bu katkıdan bir konu dalı oluşturarak yeni katkılarınızı 1d54865 katkısına dayandırmak isteyebilirsiniz.

Git ve TFS Özeti

Git-tf ve Git-tfs TFVC sunucusuyla etkileşimde bulunmak için harika araçlardır. Size yerelde Git’in gücünü kullanma, sürekli olarak merkezi TFVC sunucusuna yolculuk yapmaktan kaçınma ve geliştirici olarak hayatınızı çok daha kolay hale getirme imkanı sağlarlar, ancak tüm ekibinizi Git’e taşımaya zorlamazlar. Eğer Windows’ta çalışıyorsanız (ki ekibiniz TFS kullanıyorsa muhtemelen durum budur), muhtemelen özellik seti daha tam olduğu için git-tfs’i kullanmak isteyeceksiniz, ancak başka bir platformda çalışıyorsanız, daha sınırlı olan git-tf’i kullanacaksınız. Bu bölümdeki çoğu araç gibi, bu versiyon kontrol sistemlerinden birini standart olarak seçmeli ve diğerini yardımcı bir şekilde kullanmalısınız (ya Git ya da TFVC işbirliğinin merkezi olmalı, ancak ikisi birden değil).

scroll-to-top