Git
Chapters ▾ 2nd Edition

9.1 Git və Digər Sistemlər - Git Müştəri kimi

Dünya mükəmməl deyil. Ümumiyyətlə, təmasda olduğunuz hər bir layihəni dərhal Git’ə keçirə bilməzsiniz. Bəzən başqa bir VNS istifadə edərək bir layihədə qalırsınız və bunun Git istəyirsiniz. Bu fəslin birinci hissəsini üzərində çalışdığınız layihə fərqli bir sistemdə yerləşdikdə Git’in müştəri kimi istifadəsi yollarını öyrənməyə sərf edəcəyik.

Bir nöqtədə mövcud layihənizi Git’ə çevirmək istəyə bilərsiniz. Bu fəslin ikinci hissəsi, layihənizi bir neçə xüsusi sistemdən Git’ə necə köçürəcəyinizi və əvvəlcədən qurulmuş idxal vasitəsi olmadığı təqdirdə işləyəcək bir üsulu əhatə edir.

Git Müştəri kimi

Git, developer’lər üçün o qədər gözəl bir təcrübə təmin edir ki, komandasının qalan hissəsi tamamilə fərqli bir VNS istifadə etsə də bir çox insan iş yerində necə istifadə ediləcəyini anladı. “Bridges” adlanan bu adapterlərdən bir neçəsi mövcuddur. Burada vəhşi təbəqədə qarşılaşma ehtimalı olanları əhatə edəcəyik.

Git və Subversion

Açıq mənbəli development layihələrinin böyük bir hissəsi və çox sayda korporativ layihə mənbə kodlarını idarə etmək üçün Subversiondan istifadə edir.

On ildən çoxdur ki, mövcuddur və əksər vaxt açıq mənbəli layihələr üçün de facto VNS seçimi idi. Bundan başqa, bir çox cəhətdən ondan əvvəl mənbə nəzarəti dünyasının böyük oğlu olan CVS-ə çox oxşayır.

Git-in ən böyük xüsusiyyətlərindən biri də, git svn adlanan Subversion-a iki yönlü körpüdür. Bu vasitə, Git’i bir Subversion serverinə etibarlı bir müştəri olaraq istifadə etməyə imkan verir, beləliklə Git’in bütün lokal xüsusiyyətlərindən istifadə edə bilərsiniz və sonra Subversion’u lokal istifadə etdiyiniz kimi bir Subversion serverinə push edə bilərsiniz. Bu, həmkarlarınız qaranlıq və qədim yollarla işləməyə davam edərkən local branching və birləşmə, səhnə sahəsindən istifadə, rebasing və cherry-picking və s edə bilərsiniz. Git-i korporativ mühitdə gizlətmək və developer-lərinizin daha effektiv olmasına kömək etmək üçün yaxşı bir yoldur, Git-i tam dəstəkləmək üçün infrastrukturun dəyişdirilməsini təmin edin. Subversion körpüsü DVCS dünyasına açılan bir dərmandır.

git svn

Bütün Subversion körpü əmrləri üçün Git-dəki əsas əmr git svn-dir. Bunun üçün kifayət qədər bir neçə əmr lazımdır, buna görə bir neçə sadə iş axınından keçərkən ən çox yayılmışları göstərəcəyik. Qeyd etmək vacibdir ki, git svn istifadə edərkən Git-dən çox fərqli işləyən bir sistem olan Subversion ilə qarşılıqlı əlaqə qurursunuz. Local branching və birləşmə işlərini edə bilsəniz də, işinizi bərpa edərək və eyni zamanda bir Git remote deposu ilə qarşılıqlı əlaqə qurmaq kimi şeylərdən çəkinərək tarixinizi mümkün qədər xətti tutmaq yaxşıdır. Tarixinizi yenidən yazmayın və təkrar push etməyə çalışmayın və eyni zamanda Git developerləri ilə əməkdaşlıq etmək üçün paralel bir Git deposuna push etməyin.

Subversion yalnız bir xətti tarixçəyə sahib ola bilər və onu qarışdırmaq çox asandır. Bir komanda ilə işləyirsinizsə, bəziləri SVN, bəziləri Git istifadə edirsinizsə, hər kəsin əməkdaşlıq etmək üçün SVN serverindən istifadə etdiyinə əmin olun - bunu etmək həyatınızı asanlaşdıracaq.

Ayarlamaq

Bu funksiyanı nümayiş etdirmək üçün yazmaq üçün daxil olduğunuz tipik bir SVN deposuna ehtiyacınız var. Bu nümunələri kopyalamaq istəyirsinizsə, bir SVN test deposunun yazılı surətini çıxarmalısınız. Bunu asanlıqla etmək üçün Subversion ilə gələn svnsync adlı bir vasitə istifadə edə bilərsiniz.

İzləmək üçün əvvəlcə yeni bir lokal Subversion deposu yaratmalısınız:

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

Sonra bütün istifadəçilərə revpropları dəyişdirməyə imkan verin - asan yol, həmişə 0-dan çıxan bir pre-revprop-change skriptini əlavə etməkdir:

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

Artıq bu proyekti depolardan və svnsync init çağıraraq lokal maşınınızla sinxronizasiya edə bilərsiniz.

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

Bu, sinxronizasiyanı işə salmaq üçün xüsusiyyətləri qurur. Daha sonra kodu işə salmaqla klonlaya bilərsiniz:

$ 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 əməliyyat yalnız bir neçə dəqiqə çəkə bilsə də, orijinal deponu lokal əvəzinə başqa bir uzaq depoya köçürməyə çalışarsanız, 100-dən az commit olmasına baxmayaraq proses təxminən bir saat çəkəcəkdir. Subversion bir dəfəyə bir revizyonu klonlamalı və sonra başqa bir depoya qaytarmalıdır - gülünc dərəcədə səmərəsizdir, amma bunu etmək üçün yeganə asan yoldur.

Başlayırıq

İndi yazma girişiniz olan bir Subversion deposuna sahib olduğunuz üçün tipik bir iş axınından keçə bilərsiniz. Bütün Subversion deposunu yerli Git deposuna idxal edən git svn clone əmri ilə başlayacaqsınız. Unutmayın ki, həqiqi bir yerləşdirilmiş Subversion deposundan idxal edirsinizsə, buradakı file:///tmp/test-svn-ni Subversion deposunuzun URL’si ilə əvəz etməlisiniz:

Artıq yazma girişiniz olan bir Subversion deposuna sahib olduğunuz üçün tipik bir iş axınından keçə bilərsiniz. Bütün Subversion deposunu yerli Git deposuna idxal edən git svn clone əmri ilə başlayacaqsınız. Unutmayın ki, həqiqi bir yerləşdirilmiş Subversion deposundan idxal edirsinizsə, buradakı file:///tmp/test-svn-ni Subversion deponuzun URL’si ilə əvəz etməlisiniz:

$ 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, təqdim etdiyiniz URL-də iki əmr - git svn init və ardından git svn fetch kimi ekvivalentdir. Bu bir müddət çəkə bilər.

Məsələn, test layihəsində yalnız 75 iş görülürsə və kod bazası o qədər böyük deyilsə, Git buna baxmayaraq hər versiyanı bir-bir yoxlamalı və fərdi olaraq həyata keçirməlidir. Yüzlərlə və ya minlərlə commit-i olan bir layihə üçün bunun sözün əsl mənasında bitməsi saatlarla, hətta günlərlə davam edə bilər.

-T trunk -b branches -t tags hissəsi Git-ə bu Subversion deposunun əsas branching və etiketləmə şərtlərini izlədiyini bildirir. Trunk-nıza, branch-larınıza və ya etiketlərinizə fərqli ad verirsinizsə, bu seçimləri dəyişə bilərsiniz. Bu çox yayılmış olduğundan, bütün hissəni standart düzən mənasını verən və bütün bu variantları nəzərdə tutan -s ilə əvəz edə bilərsiniz. Aşağıdakı əmr bərabərdir:

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

Bu nöqtədə branch-larınızı və etiketlərinizi idxal edən etibarlı bir Git deposuna sahib olmalısınız:

$ 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 vasitənin Subversion etiketlərini uzaqdan idarəedici olaraq necə idarə etdiyinə diqqət yetirin. Git plumbing əmri ilə show-ref ilə daha yaxından tanış olaq:

$ 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 serverindən klonladıqda bunu etmir; etiketli bir deponun təzə bir klondan sonra necə göründüyü:

$ 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 etiketi uzaq branch-lara müalicə etmək əvəzinə birbaşa refs/tags-ə gətirir.

Committing Back to Subversion

Artıq işləyən bir qovluğa sahib olduğunuz üçün Git-dən bir SVN müştərisi kimi effektiv istifadə edərək, proyektdə bir az iş görə bilər və commit-lərinizi yuxarı axın istiqamətində push edə bilərsiniz. Fayllardan birini redaktə edib onu yerinə yetirirsinizsə, Subversion serverində olmayan Git-də yerli olaraq mövcud olan bir commit-iniz var:

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

Bundan sonra dəyişikliklərinizi yuxarıya doğru push etməlisiniz . Bunun Subversion ilə işləmə tərzinizi necə dəyişdirdiyinə diqqət yetirin - bir neçə commit-i oflayn edə və sonra hamısını birdən Subversion serverinə köçürə bilərsiniz. Subversion serverinə keçmək üçün git svn dcommit əmrini yerinə yetirirsiniz:

$ 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 server kodunun üstündə etdiyiniz bütün commit-ləri götürür, hər biri üçün bir Subversion commit-i götürür və sonra yerli Git unikal identifikatoru əlavə etmək üçün yenidən yazır.

Bu vacibdir, çünki commit-ləriniz üçün bütün SHA-1 hesablama cəmlərinin dəyişməsi deməkdir. Qismən bu səbəbdən bir Subversion server ilə eyni vaxtda layihələrinizin Git əsaslı uzaq versiyaları ilə işləmək yaxşı bir fikir deyil. Son commit-ə baxsanız, əlavə edilmiş yeni git-svn-id-i görə bilərsiniz:

$ 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

Diqqət yetirin ki, commit etdiyiniz zaman əvvəlcə 4af61fd ilə başlayan SHA-1 hesablama cəmi 95e0222 ilə başlayır. Həm Git serverinə, həm də bir Subversion serverinə push etmək istəyirsinizsə, əvvəlcə Subversion serverinə (dcommit) push etməyə, çünki bu hərəkət commit məlumatınızı dəyişdirir.

Yeni Dəyişikliklərdə Pulling Etmək

Digər developerlərlə işləyirsinizsə, o zaman biriniz birini push edəcəksiniz, sonra digəri konflikt bir dəyişikliyə push etməyə çalışacaq. İşlərinizdə birləşənə qədər bu dəyişiklik rədd ediləcək. git svn-də belə 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 vəziyyəti həll etmək üçün serverdə hələ olmadığınız hər hansı bir dəyişiklikləri aşağı salan və serverdə olanların üstündə etdiyiniz hər hansı bir işi yenidən bərpa edən git svn rebase-i işlədə bilirsiniz:

$ 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.

İndi bütün işləriniz Subversion serverindəki işlərin üstündədir, beləliklə uğurla dcommit edə bilərsiniz:

$ 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

Diqqət yetirmədən əvvəl local işinizi birləşdirməyinizi tələb edən Gitdən fərqli olaraq, git svn bunu yalnız dəyişikliklər konflikt təşkil edərsə (Subversionun necə işlədiyi kimi) edir. Başqası bir dəyişikliyi bir fayla push edirsə, sonra başqa bir fayla dəyişiklik göndərirsinizsə, dcommi-iniz yaxşı işləyəcək:

$ 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...

Bunu unutmamaq vacibdir, çünki nəticə siz push etdiyiniz zaman hər iki kompüterinizdə olmayan bir layihə vəziyyətidir. Dəyişikliklər bir-birinə uyğun deyilsə, konflikt təşkil etmirsə, diaqnozu çətin olan problemlərlə qarşılaşa bilərsiniz. Bu, bir Git serverindən istifadə etməkdən fərqlidir - Git-də, vəziyyəti dərc etmədən əvvəl müştəri sisteminizdə tam olaraq yoxlaya bilərsiniz, halbuki SVN-də, işdən əvvəl və commit götürdükdən sonra vəziyyətlərin eyni olduğuna əmin ola bilməzsiniz.

Özünüzü commit etməyə hazır olmasanız da, Subversion serverindən dəyişikliklər etmək üçün bu əmri də işləməlisiniz. Yeni məlumatları əldə etmək üçün git svn fetch-i işə sala bilərsiniz, lakin git svn rebase gətirir və sonra local commit-lərinizi yeniləyir.

$ 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.

Hər dəfə git svn rebase işlətmək kodunuzun daima yeniləndiyinə əmin olur. Buna baxmayaraq işləyərkən iş qovluğunuzun təmiz olduğundan əmin olmalısınız.

Local dəyişiklikləriniz varsa, işinizi gizlətməlisiniz və ya git svn rebase-i işə salmadan əvvəl müvəqqəti olaraq etməlisiniz - əks təqdirdə, rebase-in birləşmə konflikti ilə nəticələnəcəyini görsə əmr dayanacaq.

Git Branching Issues

Bir Git iş axını ilə rahat olduqda, ehtimal ki, mövzu branch-ları yaradacaq, üzərində işləyəcək və sonra onları birləşdirəcəksiniz. git svn vasitəsi ilə Subversion serverinə müraciət edirsinizsə, branch-larınızı birləşdirmək əvəzinə hər dəfə işinizi tək branch-da bərpa etmək istəyə bilərsiniz.

Rebasing seçiminə üstünlük vermə səbəbi, Subversionun xətti bir tarixçəyə sahib olması və Git kimi birləşmələrlə məşğul olmamasıdır, buna görə də git svn snapshotları Subversion commit-lərinə çevirərkən yalnız ilk valideynə commit edir.

Tutaq ki, tarixiniz aşağıdakı kimidir: bir experiment branch-ı yaratdınız, iki commit etdiniz və sonra onları yenidən master-ə çevirdiniz. dcommit etdiyiniz zaman, nəticəni belə 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

Birləşdirilmiş tarixə malik bir branch-da dcommit çalışması yaxşı işləyir, ancaq Git layihə tarixçənizə baxdığınız zaman experiment branch-da etdiyiniz commit-lərin heç birini yenidən yazmadı - bunun əvəzinə bütün bu dəyişikliklər tək birləşmə commit-inin SVN versiyası.

Başqa birisi işləyən klonlaşdırdıqda, gördükləri bütün işin içərisinə yığılan birləşmə əmridir, sanki git merge --squash işlətmisiniz; haradan gəldiyi və nə vaxt edildiyi barədə commit məlumatlarını görmürlər.

Subversion Branching

Subversionda branching, Git-də branching ilə eyni deyil; istifadə etməkdən çox çəkinə bilsəniz, ən yaxşısı budur. Bununla birlikdə, git svn istifadə edərək Subversion-dakı branch-ları yarada və commit edə bilərsiniz.

Yeni SVN Branch-ının Yaradılması

Subversion-da yeni bir branch yaratmaq üçün git svn branch [new-branch] işlədin:

$ 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, Subversiondakı svn copy trunk branches/opera əmrinin ekvivalentini edir və Subversion serverində işləyir. Qeyd etmək vacibdir ki, sizi bu branch-a daxil etmir; Əgər bu anda commit götürsəniz, bu əməliyyat serverdəki opera-a yox, trunk-a gedəcək.

Aktiv Branche-ların Dəyişdirilməsi

Git, tarixinizdəki Subversion branch-larınızın hər hansı birinin ucunu axtararaq dcommits-nizin hansı branch-a getdiyini müəyyənləşdirir - yalnız birinə sahib olmalısınız və mövcud branch-ınızda bir "git-svn-id" olan sonuncusu olmalıdır tarix.

Git, tarixinizdəki Subversion branch-larınızın hər hansı birinin ucunu axtararaq dcommitslərinizin hansı qola getdiyini müəyyənləşdirir - yalnız birinə sahib olmalısınız və mövcud filialınızda bir git-svn-id olan sonuncusu olmalıdır.

Eyni anda birdən çox branch üzərində işləmək istəyirsinizsə, bu branch üçün idxal olunan Subversion commit-indən başlayaraq müəyyən Subversion branch-larına dcommit etmək üçün local branch-lar qura bilərsiniz. Ayrı-ayrılıqda işləyə biləcəyiniz bir opera branch-ı istəsəniz, çalışdıra bilərsiniz:

$ git branch opera remotes/origin/opera

İndi opera branch-ınızı trunk-a (master branch-nızın) birləşdirmək istəyirsinizsə, bunu normal bir git birləşmə ilə edə bilərsiniz. Ancaq təsviri bir commit mesajı verməlisiniz (-m vasitəsilə), əks halda birləşmə faydalı bir şey əvəzinə “Merge branch opera” deyəcəkdir.

Unutmayın ki, bu əməliyyatı yerinə yetirmək üçün git merge istifadə etsəniz də birləşmə ehtimalı Subversionda olduğundan daha asan olacaq (çünki Git sizin üçün uyğun birləşmə bazasını avtomatik olaraq aşkar edəcək), Git birləşmə commiti normal deyil. Bu məlumatları birdən çox valideynə baxan bir commit-i yerinə yetirə bilməyən bir Subversion serverinə qaytarmalısınız; belə ki, onu push etdikdən sonra, başqa bir branch-ın bütün işlərində tək bir commit altında əzilən tək bir commit-ə bənzəyir. Bir branch-ı digərinə birləşdirdikdən sonra asanlıqla geri qaytara bilməzsiniz və normal olaraq Gitdə olduğu kimi bu branch üzərində işləməyə davam edə bilməzsiniz. İşlətdiyiniz dcommit əmri hansı branch-ın birləşdirildiyini bildirən hər hansı bir məlumatı silir, bu səbəbdən sonrakı birləşmə bazası hesablamaları səhv olacaq -dcommit git merge nəticənizi git merge --squash kimi işlədir. Təəssüf ki, bu vəziyyətdən qaçınmaq üçün yaxşı bir yol yoxdur - Subversion bu məlumatı saxlaya bilməz, buna görə də onu server olaraq istifadə edərkən məhdudiyyətləri ilə əlil olacaqsınız. Problemlərin qarşısını almaq üçün trunk-a birləşdirdikdən sonra local branch-ı (bu halda, opera) silməlisiniz.

Subversion Əmrləri

git svn alətlər dəsti Subversion-dakılara bənzər bəzi funksionallıq təmin edərək Git-ə keçidi asanlaşdırmağa kömək edəcək bir sıra əmrlər təqdim edir. Budur sizə Subversionun istifadə etdiyini verən bir neçə əmr.

SVN Style Tarixi

Subversiona alışmışsınızsa və tarixinizi SVN çıxış tərzində görmək istəyirsinizsə, SVN formatında commit tarixçənizə baxmaq üçün git svn log-nu işə sala bilərsiniz:

$ 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 haqqında iki vacib şeyi bilməlisiniz. Birincisi, Subversion serverindən məlumat istəyən həqiqi svn log əmrindən fərqli olaraq oflayn işləyir. İkincisi, yalnız Subversion serverinə sadiq qaldığınızı göstərir. İcazə vermədiyiniz Local Git commit-ləri görünmür; bu müddətdə insanların Subversion serverinə verdiyi commit-lər də yoxdur. Subversion serverindəki commit-lərin son bilinən vəziyyətinə daha çox bənzəyir.

SVN Annotasiyası

git svn log əmri, svn log əmrini oflayn olaraq simulyasiya etdiyi kimi git svn blame [FILE] işlədərək svn annotate bərabərliyini ala bilərsiniz. Nəticə belə 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

Yenə də yerli olaraq Gitdə etdiyiniz və ya bu müddətdə Subversion-a itələdiyiniz commit-ləri göstərmir.

SVN Server Məlumatı

Siz də git svn info-nu işə salıb svn info-un sizə verdiyi məlumatları əldə edə bilərsiniz:

$ 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, blamelog kimi bir şeydir ki, oflayn işləyir və yalnız Subversion server ilə sonuncu dəfə ünsiyyət qurduğunuz günə qədərdir.

Subversion Ignore-larını Nə İgnore Etdi

Hər hansı bir yerdə qurulmuş svn:ignore xüsusiyyətlərinə sahib olan bir Subversion deposunu klonlaşdırırsınızsa, ehtimal ki, commit etməməli olduğunuz faylları təsadüfən etməməyiniz üçün müvafiq .gitignore fayllarını təyin etmək istərdiniz. git svn-in bu məsələdə kömək edəcək iki əmri var. Birincisi, avtomatik olaraq sizin üçün müvafiq .gitignore fayllarını yaradan git svn create-ignore, növbəti işinizdə bunları daxil edə bilər. İkinci əmr, .gitignore faylına qoymağınız lazım olan sətirləri düzəltmək üçün yazdıran git svn show-ignore-dir, nəticədə proyektinizə çıxarılan faylı yönləndirə bilərsiniz:

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

Bu şəkildə layihəni .gitignore sənədləri ilə zibil etmirsiniz. Subversion komandasındakı tək Git istifadəçisisinizsə və komanda yoldaşlarınız layihədəki .gitignore sənədlərini istəmirsinizsə, bu yaxşı bir seçimdir.

Git-Svn-nin Qısa Məzmunu

git svn alətləri bir Subversion serverinə qapıldığınızda və ya başqa bir şəkildə Subversion serverinin işlədilməsini zəruri edən inkişaf mühitində olduğunuzda faydalıdır. Bununla birlikdə şikəst Git olduğunu düşünməlisiniz, yoxsa tərcümədə sizi və həmkarlarınızı qarışdıra biləcək məsələlərə toxunacaqsınız. Problemlərdən uzaq olmaq üçün aşağıdakı qaydalara əməl etməyə çalışın:

  • git merge tərəfindən birləşdirmə commit-lərini ehtiva etməyən xətti bir Git tarixçəsi saxlayın. Əsas xətt branch-ınız xaricində etdiyiniz hər hansı bir işi yenidən üzərinə qaytarın; birləşdirməyin.

  • Ayrı bir Git server qurmayın və əməkdaşlıq etməyin. Yeni developerlər üçün klonları sürətləndirmək üçün birinə sahib ola bilərsiniz, ancaq ona git-svn-id girişi olmayan bir şey push etməyin. Hətta hər bir gediş mesajını bir git-svn-id üçün yoxlayan və onsuz commit-ləri olan itkiləri rədd edən bir pre-receive hook-nu əlavə etmək istəyə bilərsiniz.

Bu təlimatlara əməl etsəniz, Subversion server ilə işləmək daha dözümlü ola bilər. Ancaq həqiqi bir Git serverinə keçmək mümkündürsə, bunu etmək komandanızı daha çox qazana bilər.

Git və Mercurial

DVCS kainatı yalnız Git-dən daha böyükdür. Əslində, bu məkanda çox sayda sistem var, hər biri paylanmış versiya nəzarətinin düzgün şəkildə necə ediləcəyinə dair öz bucağına malikdir. Git xaricində ən populyar Mercurialdır və ikisi bir çox cəhətdən çox oxşardır.

Yaxşı bir xəbər, Git’in müştəri tərəfindəki davranışını üstün tutsanız, lakin mənbə kodu Mercurial ilə idarə olunan bir layihə ilə işləyirsinizsə, Git’i bir Mercurial-a yerləşdirilən bir depo üçün müştəri olaraq istifadə etməyin bir yolu olmasıdır. Gitin server depoları ilə danışıq üsulu uzaqdan idarəedici olduğundan bu körpünün uzaq bir köməkçi kimi həyata keçirilməsinə təəccüblənməməliyik. Layihənin adı git-remote-hg-dir və https://github.com/felipec/git-remote-hg saytında tapa bilərsiniz.

git-remote-hg

Əvvəlcə git-remote-hg yükləməlisiniz. Bu, əsasən faylı path-nıza bir yerə atmağa səbəb olur:

$ 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-in $PATH-da olduğunuzu düşünürük. Git-remote-hg-nin başqa bir asılılığı var: Python üçün mercurial kitabxanası. Python quraşdırılıbsa, bu qədər sadədir:

$ pip install mercurial

Python’unuz yoxdursa, https://www.python.org/ səhifəsini ziyarət edin və əvvəl əldə edin.

Sizə lazım olan son şey Mercurial müştərisidir. https://www.mercurial-scm.org/ saytına gedin və hələ də yoxdursa quraşdırın.

İndi isə rock etməyə hazırsınız. Sadəcə, push etməyə bir Mercurial deposuna ehtiyacınız var. Xoşbəxtlikdən, hər bir Mercurial deposu bu şəkildə hərəkət edə bilər, buna görə Mercurial-ı öyrənmək üçün hər kəsin istifadə etdiyi "hello world" deposundan istifadə edəcəyik:

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

Başlangıc

Artıq uyğun bir “server-tərəf” depomuz olduğuna görə tipik bir iş axınından keçə bilərik. Gördüyünüz kimi, bu iki sistem kifayət qədər sürtünmə olmadan oxşayır.

Həmişə olduğu kimi Git ilə əvvəlcə klonlaşdırırıq:

$ 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

Bir Mercurial deposu ilə işləmək üçün standart git clone əmrini istifadə etdiyini görəcəksiniz. Git-in HTTP/S protokolunun necə tətbiq olunduğuna bənzər bir mexanizm istifadə edərək (remote köməkçilər) git-remote-hg-nin kifayət qədər aşağı səviyyədə işləməsidir. Git və Mercurial, hər bir müştərinin anbar tarixinin tam bir nüsxəsinə sahib olması üçün hazırlandığından, bu əmr bütün layihə tarixi daxil olmaqla tam bir klon yaradır və bunu kifayət qədər tez edir.

Log əmri iki commit göstərir, ən sonuncusu isə bir çox refer tərəfindən göstərilmişdir. Bunlardan bəzilərinin əslində orada olmadığı ortaya çıxdı. Gəlin .git qovluğundakılara nəzər salaq:

$ 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 şeyləri daha idiomatik olaraq Git-esque etməyə çalışır, ancaq başlıq altında iki fərqli sistem arasındakı konseptual xəritələşməni idarə edir. refs/hg qovluğu faktiki uzaq reflərin saxlanıldığı yerdir. Məsələn, refs/hg/origin/branches/default, master-in işarə etdiyi “ac7955c” ilə başlayan SHA-1-i ehtiva edən bir Git ref sənədidir.

Beləliklə, refs/hg qovluğu bir növ saxta refs/remotes/origin kimidir, lakin bookmark-lar və branch-lar arasında əlavə bir fərq var.

notes/hg faylı, git-remote-hg xəritələrinin Gitin Mercurial dəyişən ID-lərinə necə hash olduğunun üçün başlanğıc nöqtəsidir. Gəlin bir az araşdıraq:

$ 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

Beləliklə, refs/notes/hg, Git obyekt bazasında adları olan digər obyektlərin siyahısı olan bir ağaca işarə edir. git ls-tree bir ağacın içindəki əşyalar üçün rejimi, növü, obyekt hash-ı və fayl adını çıxarır.

Ağac item-larından birinə endikdən sonra içərisində “0a04b98” konteksi ilə (bu, default branch-nın ucundakı Mercurial dəyişikliyinin identifikatorudur) “ac9117f” ( master tərəfindən göstərilən commit-in SHA-1 hashı) adlı bir blob olduğunu görürük.

Yaxşı xəbər odur ki, bunların hamısı üçün narahat olmaq lazım deyil. Tipik iş axını, Git remote ilə işləməkdən çox fərqli olmayacaq.

Davam etməzdən əvvəl iştirak etməli olduğumuz bir şey daha var: ignores. Mercurial və Git bunun üçün çox bənzər bir mexanizm istifadə edirlər, lakin çox güman ki, bir .gitignore sənədini Mercurial deposuna daxil etmək istəməyəcəksiniz. Xoşbəxtlikdən, Git’in diskdəki bir depo üçün lokal olan faylları ignore etməyin bir yolu var və Mercurial formatı Git ilə uyğundur, buna görə onu köçürməlisiniz:

$ cp .hgignore .git/info/exclude

The .git/info/exclude file acts just like a .gitignore, but isn’t included in commits.

Workflow

Fərz edək ki, master branch-ında bir az iş gördük və bir neçə commit götürdük və onu uzaq depoya push etməyə hazırsınız. Depomuz hazırda belə görünür:

$ 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

master branch-ımız origin/master-dan iki commit-dir, lakin bu iki vəzifə yalnız local maşınımızda mövcuddur. Başqa birinin eyni zamanda mühüm bir iş görüb görmədiyini baxaq:

$ 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 flag-ından istifadə etdiyimiz üçün git-remote-hg tərəfindən daxili istifadə edilən “qeydlər” istinadlarını görürük, lakin onları ignore edə bilərik. Qalan nə gözlədiyimizdir; origin/master bir commit-lə irəli getdi və tariximiz indi fərqlidir. Bu fəsildə işlədiyimiz digər sistemlərdən fərqli olaraq, Mercurial birləşmələri idarə edə bilir, buna görə də zərif bir şey etməyəcəyik.

$ 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

Əla. Testləri aparırıq və hər şey uğurlu keçir, buna görə işimizi komandanın qalan üzvləri ilə bölüşməyə hazırıq:

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

Bu qədər! Merkuri deposuna nəzər yetirsəniz, bunun gözlədiyimizi etdiyini görərsiniz:

$ 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 nömrəli dəyişikliklər Mercurial tərəfindən, 34 nömrəli dəyişikliklər git-remote-hg tərəfindən Git ilə edilən commit-ləri push etməklə edilmişdir.

Branch-lar və Bookmark-lar

Gitin yalnız bir növ branch-ı var: commit-lər qoyulduqda hərəkət edən bir istinad. Mercurial-da bu növ bir istinad “bookmark” adlanır və Git branch-ı ilə eyni şəkildə davranır.

Mercurial-ın “branch” konsepsiyası daha ağırdır. Dəyişikliklərin edildiyi branch dəyişikliklərlə yazılır, yəni həmişə depo tarixində olacaqdır.

Budur develop branch-ında edilən bir commit-in nümunəsi:

$ 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” ilə başlayan sətrə diqqət yetirin. Git bunu həqiqətən təkrarlaya bilməz (və buna ehtiyac yoxdur; hər iki branch növü də Git ref kimi təmsil edilə bilər), lakin git-remote-hg fərqi anlamalıdır, çünki Mercurial qayğı göstərir.

Mercurial bookmark-lar yaratmaq, Git branch-ları yaratmaq qədər asandır. Git tərəfində:

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

Bunun üçün hər şey var. Mercurial tərəfdən bu belə 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

Reviziya 5-də yeni [featureA] etiketinə diqqət yetirin. Bunlar bir istisna olmaqla, Git tərəfindəki Git branch-ları kimi hərəkət edirlər: bir bookmark-ı Git tərəfdən silə bilməzsiniz (bu, uzaq köməkçilərin məhdudiyyətidir).

“heavyweight” bir Mercurial branch-da da işləyə bilərsiniz: sadəcə branches namespace-nə bir branch qoyun:

$ 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 tərəfdə görünən budur:

$ 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” branch adı 7 işarəsi ilə dəyişiklik dəsti ilə qeyd edildi.

Git tərəfdən, bu branch üslublarından hər hansı biri ilə işləmək eynidir: normalda istədiyiniz kimi checkout, commit, fetch, merge, pull, və push etmək. Bilməli olduğunuz bir şey, Mercurial-ın tarixin yenidən yazılmasını dəstəkləməməsi, yalnız tarixə əlavə etməsidir. Mercurial depomuzun interaktiv rebase və force-push tətbiqindən sonra belə görünəcək:

$ 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, 910 dəyişikliklər yaradıldı və permanent branch-na aiddir, lakin köhnə dəyişikliklər hələ də mövcuddur. Bu, Mercurial istifadə edən komanda yoldaşlarınız üçün çox qarışıq ola bilər, buna görə də bundan çəkinməyə çalışın.

Mercurial-ın Qısa Məzmunu

Git və Mercurial kifayət qədər oxşardır və sərhəd boyunca işləmək kifayət qədər ağrısızdır. Maşınınızda qalan tarixi dəyişdirməkdən çəkinsəniz (ümumiyyətlə tövsiyə olunduğu kimi), digər ucunun Mercurial olduğunu da bilməyəcəksiniz.

Git və Bazaar

DVCS arasında daha bir məşhur Bazaar-dır. Bazaar pulsuz və açıq mənbəlidir və GNU Project-nin bir hissəsidir. Bu Git-dən çox fərqli davranır. Bəzən Git ilə eyni şeyi etmək üçün fərqli bir keyword istifadə etməlisiz və ümumi olan bəzi keyword-lər eyni məna daşımır. Xüsusilə branch idarəetməsi çox fərqlidir və xüsusən kimsə Git’in kainatından gələndə qarışıqlığa səbəb ola bilər. Buna baxmayaraq bir Git deposundan Bazaar deposu üzərində işləmək mümkündür.

Git’i Bazaar müştərisi kimi istifadə etməyə imkan verən bir çox layihə var. Burada https://github.com/felipec/git-remote-bzr saytında tapa biləcəyiniz Felipe Contreras layihəsini istifadə edəcəyik. Qurmaq üçün yalnız git-remote-bzr faylını $PATH-nızdakı bir qovluğa yükləməlisiniz:

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

Bazaarın quraşdırılmasına da ehtiyacınız var. Bu qədər!

Bir Bazaar deposundan bir Git deposu yaradın

İstifadəsi sadədir. Bir Bazaar deposunu əvvəldən əlavə edən bzr:: ilə klonlaşdırmaq kifayətdir. Git və Bazaar hər ikisi də cihazınıza tam klonlar verdiyindən local Bazaar klonuna bir Git klonu əlavə etmək mümkündür, lakin tövsiyə edilmir. Git klonunuzu birbaşa Bazaar klonunuzun bağlandığı yerə - mərkəzi depoya əlavə etmək daha asandır.

Fərz edək ki, bzr+ssh://developer@mybazaarserver:myproject ünvanında olan uzaq bir depo ilə işləmisiniz. Sonra aşağıdakı şəkildə klonlamalısınız:

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

Bu nöqtədə Git deposunuz yaradılır, lakin optimal disk istifadəsi üçün sıxılmır. Bu səbəbdən Git deposunuzu təmizləmək və yığmaq lazımdır, xüsusən də böyükdürsə:

$ git gc --aggressive

Bazaar Branch’ları

Bazaar yalnız branch-ları klonlamağa imkan verir, ancaq bir depo bir neçə branch-dan ibarət ola bilər və git-remote-bzr hər ikisini də klonlaya bilər. Məsələn, branch-ı klonlamaq üçün:

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

Və bütün deponu klonlamaq üçün:

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

İkinci komanda, emacs deposundakı bütün branch-ları klonlaşdırır; buna baxmayaraq, bəzi branch-lara işarə etmək mümkündür:

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

Bəzi uzaq depolar branch-larını siyahıya almağa imkan vermir, bu halda onları manual olaraq təyin etməlisiniz və klonlama əmrində konfiqurasiyanı təyin edə bilsəniz də, bunu daha asan tapa bilərsiniz:

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

.bzrignore ilə ignore edilənləri ignore edin

Bazaar ilə idarə olunan bir layihə üzərində çalışdığınız üçün .gitignore faylı yaratmamalısınız, çünki təsadüfən onu versiya nəzarəti altına olacaqsınız və Bazaar ilə işləyən digər insanlar narahat olacaqlar. Çözüm, .git/info/exclude faylını simvolik bir link və ya adi bir fayl olaraq yaratmaqdır. Bu sualın necə həll ediləcəyini daha sonra görəcəyik.

Bazaar, faylları ignore etmək üçün Git ilə eyni modeli istifadə edir, eyni zamanda Git-ə ekvivalenti olmayan iki xüsusiyyəti var. Tam təsviri the documentation-də tapa bilərsiniz. İki xüsusiyyət bunlardır:

  1. "!!" "!" qaydada göstərilsə də, müəyyən fayl nümunələrini ignore etməyə imkan verir.

  2. Bir sətrin əvvəlindəki "RE:" bir Python regular expression təyin etməyə imkan verir (Git yalnız shell glob-lara icazə verir).

Nəticə olaraq, nəzərə alınacaq iki fərqli vəziyyət var:

  1. Əgər .bzrignore faylında bu iki xüsusi prefixes-dən heç biri yoxdursa, onda depoda sadəcə simvolik bir əlaqə qura bilərsiniz: ln -s .bzrignore .git/info/exclude.

  2. Əks təqdirdə, .git/info/exclude faylını yaratmalı və .bzrignore-dakı tam eyni faylları ignore etməlisiniz.

Nə olursa olsun, .git/info/exclude faylının hər zaman .bzrignore yansıtdığından əmin olmaq üçün .bzrignore dəyişikliyinə qarşı xəbərdar olmalısınız. Həqiqətən, .bzrignore faylı dəyişdirilərsə və "!!" ilə başlayan bir və ya daha çox sətir var idi və ya "RE:", Git bu sətirləri şərh edə bilmirsə, .git/info/exclude faylınızı .bzrignore ilə ignore olunanlarla eyni faylları ignore etmək üçün uyğunlaşdırmalısınız. Üstəlik, .git/info/exclude faylı simvolik bir əlaqə olsaydı, əvvəlcə simvolik linki silməli, .bzrignore .git/info/exclude şəklində kopyalayıb sonra ikincisini uyğunlaşdırmalısınız. Bununla birlikdə, onun yaradılmasında diqqətli olun, çünki Git ilə bu faylın bir ana qovluğu xaric edildikdə bir faylı yenidən daxil etmək mümkün deyil.

Uzaq deponun dəyişikliklərini fetch edin

Remote-un dəyişikliklərini əldə etmək üçün Git əmrlərindən istifadə edərək dəyişiklikləri adətən fetch edirsiniz. Dəyişikliklərinizin master branch-ında olduğunu düşünərək, origin/master branch-ında işlərinizi birləşdirir və ya yenidən artırırsınız:

$ git pull --rebase origin

Uzaqdakı depoda işinizi push edin

Bazaar da birləşmə commit-i konsepsiyasına sahib olduğundan birləşdirmə commit-ini irəli sürsəniz, heç bir problem olmayacaqdır. Beləliklə, bir branch-da işləyə, dəyişiklikləri master halına gətirə və işinizi push edə bilərsiniz. Sonra, branch-larınızı yaradırsınız, işinizi həmişəki kimi sınaqdan keçirirsiniz. Nəhayət işinizi Bazaar deposuna push edirsiniz:

$ git push origin master

Xəbərdarlıqlar

Git’in uzaqdan köməkçilər çərçivəsinin tətbiq olunan bəzi məhdudiyyətləri var. Xüsusilə, bu əmrlər işləmir:

  • git push origin :branch-to-delete (Bazaar bu şəkildə ref silmələrini qəbul edə bilməz)

  • git push origin old:new (old-u push edəcək)

  • git push --dry-run origin branch (push edəcək)

Qısa Məzmun

Git və Bazaar modelləri bir-birinə bənzədiyi üçün sərhəd xaricində işləyərkən çox müqavimət göstərmir. Məhdudiyyətlərə diqqət yetirdiyiniz və uzaqdakı deponun local olaraq Git olmadığını bildiyiniz müddətdə yaxşı olacaqsınız.

Git və Perforce

Perforce korporativ mühitlərdə çox populyar bir versiya nəzarət sistemidir. 1995-ci ildən bəri mövcuddur, bu da bu bölmədə yer alan ən qədim sistemdir. Beləliklə, gününün məhdudiyyətləri ilə dizayn edilmişdir; hər zaman tək bir mərkəzi serverə bağlı olduğunuzu və yalnız bir versiyanın yerli diskdə saxlandığını düşünür. Əmin olmaq üçün xüsusiyyətləri və məhdudiyyətləri bir neçə spesifik problemə çox uyğundur, lakin Perforce istifadə edərək Git-in daha yaxşı işləyəcəyi bir çox layihə var.

Perforce və Git istifadəsini qarışdırmaq istəsəniz iki seçim var. Əhatə edəcəyimiz ilk şey, Perforce depolarınızın alt ağaclarını Git read-write depoları kimi göstərməyə imkan verən Perforce istehsalçılarının “Git Fusion” körpüsüdür. İkincisi, Git’i Perforce serverinin hər hansı bir yenidən konfiqurasiyasına ehtiyac olmadan Perforce müştərisi kimi istifadə etməyə imkan verən müştəri tərəfi olan git-p4-dür.

Git Fusion

Perforce, bir Perforce serverini server tərəfindəki Git depoları ilə sinxronizasiya edən Git Fusion adlı bir məhsul təqdim edir (http://www.perforce.com/git-fusion).

Quraşdırılması

Nümunələrimiz üçün Perforce demonunu və Git Fusion-u işləyən bir virtual maşın yükləyən Git Fusion üçün ən asan quraşdırma metodundan istifadə edəcəyik. Virtual maşın şəklini http://www.perforce.com/downloads/Perforce/20-User saytından əldə edə bilərsiniz və yüklədikdən sonra onu ən sevdiyiniz virtualizasiya proqramına daxil edin (VirtualBox istifadə edəcəyik).

Maşın ilk işə salındıqdan sonra üç Linux istifadəçisi üçün şifrənizi (root, perforcegit) fərdiləşdirməyinizi və bu quraşdırmanı digərlərindən fərqləndirmək üçün istifadə edilə bilən bir nümunə adını eyni şəbəkədə verməyinizi xahiş edir. Hamısı tamamlandıqda bunları görəcəksiniz:

The Git Fusion virtual machine boot screen
Figure 146. The Git Fusion virtual machine boot screen

Burada göstərilən IP ünvanını qeyd etməlisiniz, daha sonra istifadə edəcəyik. Sonra bir Perforce istifadəçisi yaradacağıq. Aşağıdakı “Login” seçimini seçin və enter düyməsini basın (və ya maşın üçün SSH) və root olaraq daxil olun. Sonra bir istifadəçi yaratmaq üçün bu əmrləri istifadə edin:

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

Birincisi, istifadəçini fərdiləşdirmək üçün VI redaktoru açacaq, ancaq :wq yazaraq enter düyməsini basaraq standartları qəbul edə bilərsiniz. İkincisi, iki dəfə bir parol daxil etməyinizi istər. Bir shell prompt ilə etməli olduğumuz şey budur, buna görə sessiyadan çıxın.

İzləmək üçün etməyiniz lazım olan növbəti şey, Git-ə SSL sertifikatlarının təsdiqlənməməsini söyləməkdir. Git Fusion görüntüsü sertifikatla gəlir, ancaq virtual maşınınızın IP ünvanına uyğun gəlməyən bir domen üçündür, buna görə Git HTTPS bağlantısını rədd edəcəkdir. Qalıcı bir quraşdırma olacaqsa, fərqli bir sertifikat quraşdırmaq üçün Perforce Git Fusion təlimatına müraciət edin; nümunə məqsədlərimiz üçün bu kifayət edəcəkdir:

$ export GIT_SSL_NO_VERIFY=true

İndi hər şeyin işlədiyini test edə bilərik.

$ 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.

Virtual maşın şəkli klonlaya biləcəyiniz bir nümunə layihə ilə təchiz olunmuşdur. Budur yuxarıda yaratdığımız john istifadəçisi ilə HTTPS üzərindən klonlaşdırırıq; Git bu əlaqə üçün etimadnaməsini tələb edir, lakin etimadnamə cache-i, sonrakı istəklər üçün bu addımı atlamağımıza imkan verəcəkdir.

Fusion Konfiqurasiyası

Git Fusion quraşdırıldıqdan sonra konfiqurasiyanı düzəltmək lazımdır. Ən sevdiyiniz Perforce müştərisini istifadə edərək bunu etmək olduqca asan; yalnız Perforce serverindəki //.git-fusion qovluğunu iş sahənizə uyğunlaşdırın. Fayl quruluşu belə görünür:

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

498 directories, 287 files

objects qovluğuna Perforce obyektlərini Git-ə uyğunlaşdırmaq üçün Git Fusion tərəfindən daxili olaraq istifadə olunur və əksinə, orada heç bir şey ilə məşğul olmaq lazım deyil. The objects directory is used internally by Git Fusion to map Perforce objects to Git and vice versa, you won’t have to mess with anything in there. Bu qovluqda qlobal bir p4gf_config faylı və hər bir depo üçün biri var - bunlar Git Fusion-un necə davrandığını təyin edən konfiqurasiya sənədləridir. Root-dakı fayla nəzər salaq:

[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

Buradakı bu flag-ların mənalarına toxunmayacağıq, ancaq bunun Git-in konfiqurasiya üçün istifadə etdiyi kimi yalnız INI formatlı bir mətn faylı olduğunu unutmayın. Bu fayl daha sonra repos/Talkhouse/p4gf_config kimi depoya məxsus konfiqurasiya sənədləri ilə ləğv edilə bilən qlobal seçimləri müəyyənləşdirir. Bu faylı açsanız, qlobal standartlardan fərqli bəzi parametrləri olan bir [@repo] bölməsini görəcəksiniz. Buna bənzər bölmələri də görəcəksiniz:

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

Bu, Perforce branch-ı ilə Git branch-ı arasındakı bir mapping-dir. Bölmə istədiyiniz hər hansı bir ad verilə bilər, ad özünəməxsus olduğu təqdirdə. git-branch-name, Git altında çətin olacaq bir depo yolunu daha səmimi bir ada çevirməyə imkan verir. View ayarı, standart görünüş uyğunlaşdırma sintaksisindən istifadə edərək Perforce fayllarının Git deposuna necə uyğunlaşdırıldığını idarə edir. Bu nümunədə olduğu kimi birdən çox uyğunlaşma müəyyən edilə bilər:

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

Bu yolla normal iş sahəsi xəritənizə qovluqların strukturundakı dəyişikliklər daxildirsə, bunu Git deposu ilə təkrarlaya bilərsiniz.

Müzakirə edəcəyimiz son sənəd Perforce istifadəçilərini Git istifadəçiləri ilə əlaqələndirən və hətta ehtiyacınız olmaya biləcək `users/p4gf_usermap`dır. Bir Perforce dəyişikliyindən Git commit-inə çevrildikdə Git Fusion-un standart davranışı Perforce istifadəçisini axtarmaq və Git-dəauthor/committer sahəsi üçün orada saxlanılan e-poçt adresini və tam adından istifadə etməkdir. Başqa bir şəkildə konvertasiya edərkən default Perforce istifadəçisini Git commit-inin müəllif sahəsində saxlanan e-poçt ünvanı ilə axtarmaq və dəyişiklikləri həmin istifadəçi kimi təqdim etməkdir (icazələrin tətbiqi ilə). Əksər hallarda, bu davranış çox yaxşı olacaq, lakin aşağıdakı uyğunlaşdırma sənədini nəzərdən keçirin:

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"

Hər sətir <user> <email> "<full name>" formatındadır və vahid istifadəçi xəritəsini yaradır. İlk iki sətirdə iki fərqli e-poçt ünvanı eyni Perforce istifadəçi hesabına uyğunlaşdırılır. Bu, Git’i bir neçə fərqli e-poçt ünvanı altında yaratdığınız (və ya e-poçt adreslərini dəyişdirdiyiniz), lakin eyni Perforce istifadəçisinə uyğunlaşdırılmasını istəməyiniz üçün faydalıdır. Bir Perforce dəyişikliyindən bir Git commit-i yaradarkən, Git müəllif məlumatları üçün Perforce istifadəçisinə uyğun gələn ilk sətir istifadə olunur.

Son iki sətir, Bob və Joe-nun əsl adlarını və Git-dən yaradılan e-poçt adreslərini gizlədir. Daxili bir layihə mənbəyi açmaq istəsəniz də yaxşıdır, ancaq işçilərinizin qovluğunu bütün dünyaya yayımlamaq istəmirsiniz. Bütün Git commit-lərinin tək bir uydurma müəllifə aid edilməsini istəmədiyiniz təqdirdə e-poçt adresləri və tam adların unikal olması lazım olduğunu unutmayın.

Workflow

Perforce Git Fusion, Perforce və Git versiyası nəzarəti arasında iki tərəfli bir körpüdür. Git tərəfdən işləməyin nə hiss etdiyinə bir nəzər salaq. Yuxarıda göstərildiyi kimi bir konfiqurasiya faylı istifadə edərək “Jam” layihəsində uyğunlaşdırdığımızı güman edəcəyik, bu şəkildə klonlaya bilərik:

$ 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 dəfə etdiyiniz zaman biraz çəkə bilər. Olan şey, Git Fusion Perforce tarixindəki bütün dəyişiklikləri Git commit-lərinə çevirir. Bu, serverdə yerli olaraq baş verir, buna görə nisbətən sürətlidir, ancaq bir çox tarixiniz varsa, hələ bir az vaxt ala bilər. Sonrakı gətirmələr artan dönüşüm edir, beləliklə Gitin yerli sürətinə daha çox bənzəyir.

Gördüyünüz kimi, depomuz işləyə biləcəyiniz digər Git deposuna bənzəyir. Üç branch var və Git köməyi ilə origin/master-ni izləyən yerli bir master branch-ı yaratdı. Gəlin bir az iş görək və bir neçə yeni commit yaradaq:

# ...
$ 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 vəzifəmiz var. İndi başqasının işlədiyini yoxlayaq:

$ 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.
[...]

Deyəsən kimsə olub! Bu baxışdan bunu bilmirsən, amma 6afeb15 commit-i əslində bir Perforce müştərisindən istifadə edərək yaradılmışdır. Sadəcə Git baxımından başqa bir commit-ə bənzəyir, bu da tam nöqtədir. Gəlin Perforce serverinin birləşdirmə commit-i ilə necə məşğul olduğunu görək:

$ 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 düşünür ki, bu işləyir. Gəlin p4v-nin düzəliş qrafiki xüsusiyyətindən istifadə edərək Perforce baxımından README faylının tarixinə nəzər salaq:

Perforce revision graph resulting from Git push
Figure 147. Perforce revision graph resulting from Git push

Bu görünüşü əvvəllər heç görməmisinizsə, qarışıq görünə bilər, ancaq Git tarixçəsi üçün qrafik görüntüləyici ilə eyni anlayışları göstərir. README faylının tarixçəsinə baxırıq, buna görə sol üstdəki qovluq ağacı yalnız müxtəlif branch-larda səthdə olduğu halda bu faylı göstərir. Sağ üstdə, faylın müxtəlif düzəlişlərinin bir-birilə əlaqəli olduğuna dair əyani bir qrafik var və bu qrafın böyük şəkil görünüşü sağ alt hissədədir. Görünüşün qalan hissəsi seçilmiş düzəliş üçün detallar görünüşünə verilir (bu vəziyyətdə 2).

Diqqət çəkən bir şey qrafikin Git tarixindəki şəkilə bənzəməsidir. Perforce-nin 12 commit-lərini saxlamaq üçün adlanan bir branch-ı yox idi, ona görə də .git-fusion qovluğunda “anonymous” bir branch yaratdı. Bu, adı verilən bir Perforce branch-ına uyğun gəlməyən Git branch-ları üçün də baş verəcəkdir (və daha sonra onları konfiqurasiya sənədini istifadə edərək Perforce branch-ına uyğunlaşdıra bilərsiniz).

Bunların əksəriyyəti pərdə arxasında baş verir, amma nəticə budur ki, komandadakı bir nəfər Git, digəri Perforce istifadə edə bilər və heç biri digərinin seçimini bilmiyəcək.

Git-Fusion Nəticəsi

Perforce serverinizə girişiniz varsa (və ya əldə edə bilsəniz), Git Fusion, Git və Perforce’u bir-biri ilə danışdırmaq üçün əla bir yoldur. Bir az konfiqurasiya var, amma öyrənmə əyrisi çox dik deyil. Bu, Git-in tam gücündən istifadə ilə bağlı xəbərdarlıqların görünməyəcəyi bu hissədəki bəzi hissələrdən biridir. Bu, Perforceun atdığınız hər şeydən məmnun qalacağı demək deyil - onsuz da push edilmiş bir keçmişi yenidən yazmağa çalışsanız, Git Fusion bunu rədd edəcək - ancaq Git Fusion təbii hiss etmək üçün çox çalışır. Hətta Git alt modullarını da istifadə edə bilərsiniz (baxmayaraq ki, onlar Perforce istifadəçiləri üçün qəribə görünəcəklər) və branch-ları birləşdirə bilərsiniz (bu Perforce tərəfində inteqrasiya kimi qeyd olunacaq).

Serverinizin administratorunu Git Fusion qurmağa inandıra bilmirsinizsə, bu alətləri birlikdə istifadə etməyin bir yolu var.

Git-p4

Git-p4, Git və Perforce arasında iki tərəfli bir körpüdür. Tamamilə Git deponuzun içərisində işləyir, beləliklə Perforce serverinə hər hansı bir girişə ehtiyacınız olmayacaq (əlbəttə ki, istifadəçi məlumatları xaricində). Git-p4, Git Fusion qədər çevik deyil və ya bir həll yolu tamamlamamaqla yanaşı, istədiyiniz işlərin əksəriyyətini server mühitinə müdaxilə olmadan etməyinizə imkan verir.

Note

Git-p4 ilə işləmək üçün PATH-nızın bir yerində p4 alətinə ehtiyacınız olacaq. Bu yazıdan etibarənhttp://www.perforce.com/downloads/Perforce/20-User[] saytında sərbəst şəkildə əldə edilə bilər.

Ayarlamaq

Məsələn, Perforce serverini yuxarıda göstərildiyi kimi Git Fusion OVA-dan çalışdıracağıq, lakin Git Fusion serverini bypass edərək birbaşa Perforce versiya nəzarətinə keçəcəyik.

p4 əmr sətri müştərisini (git-p4-dən asılı olan) istifadə etmək üçün bir neçə mühit dəyişənini təyin etməlisiniz:

$ export P4PORT=10.0.1.254:1666
$ export P4USER=john
Başlayırıq

Git-də olduğu kimi, ilk əmr klonlaşdırmaqdı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 baxımından “shallow” bir klon yaradır; yalnız ən son Perforce revizyonu Git’e idxal olunur; unutmayın, Perforce hər bir istifadəçiyə hər düzəliş vermək üçün dizayn edilməyib. Bu, Git’i Perforce müştərisi kimi istifadə etmək üçün kifayətdir, lakin digər məqsədlər üçün bu kifayət deyil.

Tamamlandıqdan sonra tam işləyən bir Git depomuz var:

$ 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 server üçün necə bir “p4” remote-nun olduğunu, ancaq hər şeyin standart bir klon kimi göründüyünə diqqət yetirin. Əslində, bu bir az yanıltıcıdır; həqiqətən orada bir remote yoxdur.

$ git remote -v

Bu depoda heç bir remote yoxdur. Git-p4, serverin vəziyyətini təmsil etmək üçün bəzi referanslar yaratdı və bunlar git log üçün remote-dan gələn referanslara bənzəyir, lakin onlar Git tərəfindən idarə olunmur və onlara push etmək olmur.

Workflow

Yaxşı, biraz iş görək. Güman edək ki, çox vacib bir xüsusiyyət üzərində bir az irəliləyiş əldə etdiniz və bunu komandanızın qalan hissəsinə göstərməyə 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 serverinə təqdim etməyə hazır olduğumuz iki yeni commit götürdük. Bu gün başqa birinin işlədiyini yoxlayaq:

$ 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ündüyü kimi onlar idi və masterp4/master ayrıldı. Perforce-in branching sistemi Git kimi heç bir şey deyil, bu səbəbdən birləşmə commit-lərini təqdim etməyin heç bir mənası yoxdur. Git-p4, commit-lərinizi yenidən düzəltməyinizi tövsiyə edir və hətta bunu etmək üçün qısa yolla gəlir:

$ 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(-)

Çıxışdan çox şey bilə bilərsiniz, ancaq git p4 rebase git p4 sync üçün bir qısayoldur, ardından git rebase p4/master izləyin. Xüsusilə birdən çox branch-la işləyəndə bundan biraz ağıllıdır, amma yaxşı bir yanaşma var.

İndi tariximiz yenidən xəttidir və dəyişikliklərimizi Perforce-a qaytarmaq üçün hazırıq. git p4 submit əmri, p4/mastermaster arasındakı hər Git commit-i üçün yeni bir Perforce revizyonu yaratmağa çalışacaq. Çalıştırmamız bizi sevdiyimiz redaktora salır və faylın məzmunu belə bir şeyə bənzəyir:

# 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>

Bu, əsasən git-p4-in daxil etdiyi şeylər istisna olmaqla, p4 submit düyməsini işə salmaqla gördüyünüz eyni məzmundur. Git-p4, bir commit və ya dəyişiklik üçün bir ad verməli olduqda, Git və Perforce parametrlərinizi fərdi olaraq hörmət etməyə çalışır, lakin bəzi hallarda onu ləğv etmək istəyirsiniz. Məsələn, idxal etdiyiniz Git commit-ini Perforce istifadəçi hesabına sahib olmayan bir iştirakçı yazmışsa, nəticədə dəyişikliklərin yazdıqları kimi görünməsini istəyə bilərsiniz (siz də yox).

Git-p4, bu Perforce dəyişikliyinin məzmunu olaraq Git commit-indən mesajı faydalı bir şəkildə idxal etdi, buna görə etməli olduğumuz şey iki dəfə saxlamaq və çıxmaqdır (hər bir commit üçün bir dəfə). Nəticədə shell çıxışı belə görünəcəkdir:

$ 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

Nəticə sanki sadəcə baş verənlərə ən yaxın bənzətmə olan bir git push işlətmişik.

Qeyd edək ki, bu müddət ərzində hər Git commit-i Perforce dəyişikliyinə çevrilir; onları tək bir dəyişiklik qrupuna yığmaq istəyirsinizsə, bunu git p4 submit-i işə salmadan əvvəl interaktiv bir bərpa ilə edə bilərsiniz. Dəyişiklik olaraq təqdim olunan bütün commit-lərin SHA-1 hash-larının dəyişdiyini də unutmayın; çünki git-p4 çevirdiyi hər bir commit-in sonuna bir sətir əlavə edir:

$ 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]

Birləşdirmə commit-ini təqdim etməyə çalışsanız nə olur? Gəlin bir cəhd edək. Budur düşdüyümüz vəziyyət:

$ 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 və Perforce tarixi 775a46f-dən sonra ayrılır. Git tərəfinin iki commit var, daha sonra Perforce başlığı ilə birləşdirmə, sonra başqa bir commit vardır. Bunları Perforce tərəfindəki tək bir dəyişiklik üzərində təqdim etməyə çalışacağıq. İndi təqdim etməyə çalışsaq nə olacağını görək:

$ 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 flag-ı --dry-run-nın qısaldılmasıdır və submit əmri real olaraq işləsəydi nə olacağını bildirməyə çalışır. Bu vəziyyətdə, Perforce serverində hələ mövcud olmayan birləşdirilməmiş üç commit-ə uyğun üç Perforce dəyişiklikləri yaratdığımıza bənzəyir. Bu, tam olaraq istədiyimiz kimi səslənir, gəlin nəticəyə baxaq:

$ 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

Göndərmədən əvvəl yenidən müəyyənləşdirdiyimiz kimi keçmişimiz xətti oldu (tam olaraq nə baş verdi). Bu, keçmişinizin Perforce ilə bir araya sığmayacağından qorxmadan Git tərəfində branch-ları yaratmaq, işləmək, atmaq və birləşdirməkdə sərbəst ola biləcəyiniz deməkdir.. Yenidən düzəldə bilsəniz, bir Perforce serverinə kömək edə bilərsiniz.

Branching

Perforce layihənizin birdən çox branch-ı varsa, hələ də şansınız var; git-p4 bunu Git kimi hiss etdirəcək şəkildə idarə edə bilər. Deyək ki, Perforce deposunuz belə qurulub:

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

Git-p4 bilər və deyək ki, belə bir görünüş spesifikasiyasına sahib bir dev branch-ı var: Bu vəziyyəti tamamilə aşkar edin və düzgün bir şey edin:

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

Git-p4 bu vəziyyəti avtomatik olaraq aşkar edə bilər və düzgün işi edə bilər:

$ 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 yolundakı “@all” spesifikatoruna diqqət yetirin; bu git-p4-ə yalnız bu alt ağac üçün son dəyişiklikləri deyil, bu yollara toxunan bütün dəyişiklikləri klonlamasını söyləyir. Bu, Git-in bir klon konsepsiyasına daha yaxındır, ancaq uzun bir tarixə sahib bir layihə üzərində işləyirsinizsə, biraz vaxt ala bilər.

--detect-branches flag-ı git-p4-ə Perforce-in branch xüsusiyyətlərini istifadə edərək branch-ları Git reflərinə uyğunlaşdırmağı məsləhət görür. Bu uyğunlaşmalar Perforce serverində yoxdursa (Perforce’u istifadə etmək üçün tamamilə etibarlı bir yoldur), git-p4-ə branch uyğunlaşmalarının nə olduğunu söyləyə bilərsiniz və eyni nəticəni əldə edə bilərsiniz:

$ 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 konfiqurasiya dəyişənini main:dev olaraq təyin etmək git-p4-ə “main” and “dev”-in hər iki branch olduğunu, ikincisinin isə birincinin övladı olduğunu bildirir.

İndi git checkout -b dev p4/project/dev və bəzi işlər görsək, git-p4 git p4 submit etdiyimiz zaman doğru branch-ı hədəf alacaq qədər ağıllıdır. Təəssüf ki, git-p4 shallow klonları və çoxsaylı branch-ları qarışdıra bilməzr; nəhəng bir layihəniz varsa və birdən çox branch üzərində işləmək istəyirsinizsə, təqdim etmək istədiyiniz hər branch üçün bir dəfə git p4 clone işlətməlisiniz.

Branch-lar yaratmaq və ya birləşdirmək üçün bir Perforce müştərisindən istifadə etməlisiniz. Git-p4 yalnız mövcud branch-lara sinxronizasiya edə və təqdim edə bilər və eyni anda yalnız bir xətti dəyişiklik edə bilər. Git-də iki branch-ı birləşdirirsinizsə və yeni dəyişiklikləri göndərməyə çalışsanız, qeyd olunacaq bir çox fayl dəyişikliyidir; branch-ların inteqrasiyada iştirak etdiyi metadata itiriləcəkdir.

Git və Perforce Nəticəsi

Git-p4 Perforce server ilə bir Git iş axını istifadə etməyi mümkün edir və bu işdə olduqca yaxşıdır. Bununla birlikdə, Perforce-un mənbədən məsul olduğunu və yalnız Git’i yerli işləmək üçün istifadə etdiyinizi unutmamalısınız. Yalnız Git commit-lərini bölüşmək üçün həqiqətən diqqətli olun; digər insanların istifadə etdiyi bir remote-nuz varsa, əvvəllər Perforce serverinə təqdim olunmamış commit-lər verməyin.

Perforce və Git-in mənbə nəzarəti üçün müştəri kimi istifadəsini sərbəst şəkildə qarışdırmaq istəyirsinizsə və server administratorunu onu quraşdırmağa inandıra bilsəniz, Git Fusion, Git-i Perforce server üçün birinci dərəcəli versiya-nəzarət müştərisinə çevirir.

Git və TFS

Git, Windows developer-ləri ilə populyarlaşır və Windows-da kod yazırsınızsa, Microsoft Team Foundation Server (TFS) istifadə etmək üçün böyük bir şans var. TFS, qüsur və iş elementlərinin izlənməsi, Scrum və digərləri üçün proses dəstəyi, kodun nəzərdən keçirilməsi və versiya nəzarətini əhatə edən bir əməkdaşlıq paketidir. Qarşıda bir az qarışıqlıq var: TFS həm Git’i, həm də TFVC (Team Foundation Version Control) adını verdikləri öz xüsusi VNCS-lərini istifadə edərək nəzarət mənbəyi kodunu dəstəkləyən serverdir. Git dəstəyi TFS üçün bir qədər yeni bir xüsusiyyətdir (2013 versiyası ilə göndərmə), buna görə əvvəldən gələn bütün vasitələr, əsasən TFVC ilə çalışsalar da versiya nəzarət hissəsini “TFS” adlandırırlar.

Özünüzü TFVC istifadə edən bir komandada görürsəniz, ancaq versiya nəzarət müştərisi olaraq Git’i istifadə etsəniz, sənin üçün bir layihə var.

Hansı Tool

Əslində iki var: git-tf və git-tfs.

Git-tfs (https://github.com/git-tfs/git-tfs saytında tapın) bir .NET layihəsidir və (bu yazı kimi) yalnız Windows-da işləyir. Git depoları ilə işləmək üçün yüksək performanslı və Git deposunun bağırsaqları ilə çox rahatlıq təmin edən Git-in kitabxana yönümlü tətbiqi olan libgit2 üçün .NET bağlamalarından istifadə edir. Libgit2, Git-in tam bir tətbiqi deyil, beləliklə fərqi ödəmək üçün git-tfs həqiqətən bəzi əməliyyatlar üçün əmr sətiri Git müştəri çağıracaq, buna görə də Git depoları ilə əlaqəli süni məhdudiyyətlər yoxdur. TFVC xüsusiyyətlərini dəstəkləməsi çox yetkindir, çünki serverlərlə əməliyyatlar üçün Visual Studio assemblilərindən stifadə edir. Bu o assemblilərə girişə ehtiyacınız olacaq deməkdir, yəni Visual Studio-nun son versiyasını (versiya 2012-dən bəri Express daxil olmaqla 2010-cu ildən bəri hər hansı bir nəşr) və ya Visual Studio SDK-nı quraşdırmanız lazımdır.

Caution

Git-tf, End-of-Life (EOL), heç bir yeniləmə almayacaq. Artıq Microsoft tərəfindən dəstəklənmir.

Git-tf (hansı ki evi https://archive.codeplex.com/?p=gittf ünvanındadı) bir Java layihəsidir və bu şəkildə Java işləmə müddəti olan istənilən kompüterdə işləyir. JGit (Git’in bir JVM tətbiqi) vasitəsi ilə Git depoları ilə əlaqə qurur, yəni Git funksiyaları baxımından heç bir məhdudiyyətə sahib deyildir. Bununla birlikdə, TFVC üçün dəstəyi git-tfs ilə müqayisədə məhduddur - məsələn branch-ları dəstəkləmir.

Beləliklə, hər bir vasitənin müsbət və mənfi cəhətləri var və bir-birinə üstünlük verən çoxlu vəziyyət var. Hər ikisinin əsas istifadəsini bu kitabda nəzərdən keçirəcəyik.

Note

Bu təlimatları izləmək üçün TFVC əsaslı bir depoya daxil olmağınız lazımdır. Bunlar vəhşi təbiətdə Git və ya Subversion depoları qədər çox deyil, buna görə özünüzdən birini yaratmanız lazım ola bilər. Codeplex (https://archive.codeplex.com/)) və ya Visual Studio Online (https://visualstudio.microsoft.com) hər ikisi bunun üçün yaxşı seçimdir.

Başlanğıc: git-tf

Etdiyiniz ilk şey hər hansı bir Git layihəsində olduğu kimi klondur. git-tf ilə görünən budur:

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

Birinci arqument bir TFVC kolleksiyasının URL’si, ikincisi $/project/branch şəklində, üçüncüsü isə yaradılacaq yerli Git deposuna gedən yoldur (sonuncusu istəyə bağlıdır). Git-tf hər dəfə yalnız bir branch ilə işləyə bilər; fərqli bir TFVC branch-ında chekinlər etmək istəyirsinizsə, bu branch-dan yeni bir klon etməlisiniz.

Bu, tamamilə işləyən bir Git deposu yaradır:

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

Buna yalnız son dəyişikliklər endirildiyi anlamına bir shallow klonu deyilir. TFVC, hər bir müştərinin tarixin tam bir nüsxəsini əldə etməsi üçün nəzərdə tutulmamışdır, beləliklə git-tf varsayılan olaraq yalnız son versiyasını alır, bu da daha sürətlidir.

Bir az vaxtınız varsa, ehtimal ki, bütün layihə tarixçəsini --deep seçimindən istifadə edərək klonlamağa dəyə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 kimi adlarla etiketlərə diqqət yetirin; bu, hansı Gitin TFVC dəyişiklikləri ilə əlaqəli olduğunu bilməyinizə kömək edən bir xüsusiyyətdir. Bu onu təmsil etmək üçün gözəl bir yoldur, çünki sadə bir günlük əmri ilə hansınızın TFVC-də mövcud olan bir snapshot ilə əlaqəli olduğunu görə bilərsiniz. Bunlar lazım deyil (və əslində onları git config git-tf.tag false ilə söndürə bilərsiniz) - git-tf, .git/git-tf faylında həqiqi commit-changeset uyğunlaşmalarını saxlayır.

Başlanğıc: git-tfs

Git-tfs klonlama bir az fərqli davranır. Baxaq:

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 flag-na diqqət yetirin. Git-tfs, TFVC branch-larını Git branch-larına uyğunlaşdırma qabiliyyətinə malikdir və bu bayraq hər TFVC branch-ı üçün yerli bir Git branch-ının qurulmasını bildirir. TFS-də branched zamanı və ya birləşdiyiniz təqdirdə bu çox tövsiyə olunur, lakin TFS 2010-dan əvvəlki bir serverlə işləməyəcək - git-tfs onları adi qovluqlardan ayıra bilməz, çünki bu buraxılışdan əvvəl “branch-lar” sadəcə qovluq idi.

Nəticədə çıxan Git deposuna nəzər salaq:

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

Klonun başlanğıc nöqtəsini (TFVC-də Trunk) və bir child branch-ını (TFVC-də featureA) təmsil edən iki local branch, masterfeatureA var. Ayrıca, tfs “remote”-da bir neçə referensa sahib olduğunu görə bilərsiniz: TFVC branch-larını təmsil edən defaultfeatureA. Git-tfs klonladığınız branch-ı tfs/default-a xəritələşdirir və digərləri öz adlarını alır.

Diqqəti cəlb edən başqa bir şey, mesajlardakı git-tfs-id: sətirləridir. Etiket əvəzinə git-tfs, TFVC dəyişikliklərini Git commit-ləri ilə əlaqələndirmək üçün bu markerlərdən istifadə edir. Bu, Git commit-lərinizin TFVC-yə göndərilmədən əvvəl və sonra fərqli bir SHA-1 qarışığına sahib olacağı mənasını verir.

Git-tf[s] Workflow

Note

Hansı alətdən istifadə etməyinizdən asılı olmayaraq, problemlərlə qarşılaşmamaq üçün bir neçə Git konfiqurasiya dəyərini təyin etməlisiniz.

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

İstəyəcəyiniz açıq bir şey layihə üzərində işləməkdir. TFVC və TFS, iş axınınıza mürəkkəblik əlavə edə biləcək bir neçə xüsusiyyətə malikdir:

  1. TFVC-də təmsil olunmayan xüsusiyyət branch-ları bir az mürəkkəblik əlavə edir. Bu, TFVC və Gitin branch-ları təmsil etdiyi çox fərqli yollarla əlaqəlidir.

  2. Qeyd edək ki, TFVC, istifadəçilərə serverdəki faylları “checkout” və kilidləməyə imkan verir ki, heç kim onu ​​düzəldə bilməz. Şübhəsiz ki, bu, onları yerli deponuzda düzəltməyinizə mane olmayacaq, ancaq dəyişikliklərinizi TFVC serverinə göndərmə vaxtı gələndə mane ola bilərsiniz.

  3. TFS, girişə icazə verilməzdən əvvəl bir TFS build-test dövrünün uğurla başa çatması lazım olan “gated” qeydlər konsepsiyasına malikdir. Bu, TFVC-də burada “shelve” funksiyasından istifadə edir, hansı ki burada ətraflı danışmırıq. Bunu git-tf ilə manual olaraq saxta edə bilərsiniz və git-tfs gate-aware olan checkintool əmrini təmin edir.

Qısaca, burada əhatə edəcəyimiz bu məsələlərin əksəriyyətini kənara qoyan və ya çəkindirən xoşbəxt yoldur.

Workflow: git-tf

Deyək ki, bir az iş görmüsünüz, bir neçə Git master üzərində commit götürdünüz və TFVC serverində irəliləyişinizi bölüşməyə hazırsınız. Budur Git depomuz:

$ 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 commit-indəki ani görüntüyü götürmək və TFVC serverinə ötürmək istəyirik. Əvvəlcə hər şey: gəlin görək komanda yoldaşlarımızdan biri son əlaqə qurandan bəri bir şey edib etməyib:

$ 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

Deyəsən başqası da işləyir və indi fərqli tarixə sahibik. Gitin parladığı yer budur, amma necə davam edəcəyimizə dair iki seçimimiz var:

  1. Birləşdirmə commit-i etmək, Git istifadəçisi olaraq təbiidir (nəticə olaraq git pull-da elə bunu edir) və git-tf bunu sizin üçün sadə bir git tf pull ilə edə bilər. Ancaq unutmayın ki, TFVC bu şəkildə düşünmür və birləşməni push etsəniz tarixiniz hər iki tərəfdə fərqli görünməyə başlayacaq, bu da qarışıq ola bilər. Bununla birlikdə, bütün dəyişikliklərinizi bir dəyişiklik kimi təqdim etməyi planlaşdırırsınızsa, bu, yəqin ki, ən asan seçimdir.

  2. Rebasing, tariximizi xətti edir, yəni hər bir Git commit-imizi bir TFVC dəyişikliyinə çevirmə seçimimiz var. Ən çox seçim açıq qaldığı üçün bunu bu şəkildə etməyinizi məsləhət görürük; git-tf hətta git tf pull --rebase ilə sizin üçün asanlaşdırır.

Seçim sizindir. Bu nümunə üçün biz geri qayıdacağıq:

$ 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

İndi TFVC serverinə giriş yazmağa hazırıq. Git-tf, sonuncudan başlayaraq bütün dəyişiklikləri əks etdirən tək bir dəyişiklik etmə seçimini (default olaraq --shallow) və hər bir Git commit-i üçün yeni bir dəyişiklik yaratma seçimini verir (--deep). Bu nümunə üçün yalnız bir dəyişiklik düzəldəcəyik:

$ 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

TFVC-nin 5a0e25e commit-i ilə eyni snapshot-nu saxladığını göstərən yeni bir TFS_C35348 etiketi var. Qeyd etmək vacibdir ki, hər bir Gitin TFVC-də dəqiq bir həmkarına sahib olması lazım deyil; məsələn, 6eb3eb5 commit-i serverin heç bir yerində yoxdur.

Əsas iş axını budur. Unutmamaq istədiyiniz bir neçə başqa məqam var:

  • Branching yoxdur. Git-tf hər dəfə yalnız bir TFVC branch-ından Git depoları yarada bilər.

  • TFVC və ya Git istifadə edərək əməkdaşlıq edin, lakin hər ikisini istifadə etməyin. Eyni TFVC deposunun fərqli git-tf klonlarında, baş ağrısına səbəb olmayan fərqli yekunlaşdırıcı SHA-1 hash-ları ola bilər.

  • Komandanızın iş axını Git-də iş birliyini və TFVC ilə vaxtaşırı sinxronizasiyanı əhatə edirsə, yalnız Git depolarından biri ilə TFVC-yə qoşulun.

Workflow: git-tfs

Git-tfs istifadə edərək eyni ssenaridən keçək. Git depomuzdakı master branch-na etdiyimiz yeni commit-lər:

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

İndi gəlin görək başqaları işimizi görüb ya yox:

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

Bəli, iş yoldaşımızın yeni aea74a0 əmri kimi görünən yeni bir TFVC dəyişiklik dəsti əlavə etdiyi və tfs/default uzaq branch-ın hərəkət etdiyi ortaya çıxdı.

Git-tf-də olduğu kimi, bu fərqli tarixi necə həll etmək üçün iki əsas seçimimiz var:

  1. Xətti bir tarixi qorumaq üçün yenidən bərpa edin.

  2. Həqiqətən baş verənləri qorumaq üçün birləşdirin.

Bu vəziyyətdə, hər bir Git-in bir TFVC dəyişikliyinə çevrildiyi bir “dərin” yoxlama edəcəyik, buna görə geri qayıdaq.

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

İndi TFVC serverinə kodumuzu yoxlayaraq töhfəmizi tamamlamağa hazırıq. HEAD-dən tapılan ilk tfs uzaq branch-ına gedən yolda hər bir Git əməli üçün bir TFVC dəyişikliyi yaratmaq üçün burada rcheckin əmrindən istifadə edəcəyik (checkin əmri yalnız bir dəyişik yaradır; Git kimi commit-lər götürür).

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

TFVC serverinə hər uğurlu qeydiyyatdan keçdikdən sonra git-tfs-in qalan işləri əvvəlki işlərinə necə qaytardığına diqqət yetirin. Bunun səbəbi SHA-1 hash-ları dəyişdirən commit mesajlarının altına git-tfs-id sahəsini əlavə etməsidir.

Bu tam olaraq dizayn edilmiş şəkildədir və narahat olacağınız bir şey yoxdur, ancaq bunun baş verdiyini, xüsusən də Git commit-lərini başqaları ilə bölüşdüyünüzü bilməlisiniz.

TFS, versiya nəzarət sistemi ilə inteqrasiya olunan bir çox xüsusiyyətə malikdir, məsələn iş item-ları, təyin olunmuş reviewer-lərin, gated checkins və s. Bu xüsusiyyətlərlə yalnız bir əmr sətiri alətindən istifadə etmək çətin ola bilər, amma xoşbəxtlikdən git-tfs qrafik qeyd alətini çox asanlıqla işə salmağa imkan verir:

PS> git tfs checkintool
PS> git tfs ct

Belə görünəcəkdir:

The git-tfs checkin tool
Figure 148. The git-tfs checkin tool

Bu, Visual Studio içərisindən başlayan eyni dialoq olduğundan TFS istifadəçilərinə tanış görünür.

Git-tfs ayrıca Git deposundan TFVC branch-larını idarə etməyə imkan verir. Nümunə olaraq birini yaradaq:

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-də bir branch yaratmaq, bu branch-ın mövcud olduğu bir dəyişiklik dəsti əlavə etmək deməkdir və bu, Git commit-i kimi proqnozlaşdırılır. Git-tfs tfs/featureBee uzaq branch-ını yaratdığını da unutmayın, lakin HEAD hələ də master-ə işarə edir. Newly-minted branch-da işləmək istəyirsinizsə, yeni commit-lərinizi, bəlkə də həmin commit-dən mövzu commit-i yaratmaqla 1d54865 commit-i üzərində qurmaq istəyirsiniz.

Git və TFS Qısa Məzmunu

Git-tf və Git-tfs TFVC serverlə əlaqə yaratmaq üçün əla vasitədir. Git gücünü yerli olaraq istifadə etməyə, mərkəzi TFVC serverinə davamlı gediş-gəlişdən çəkinməyə və bütün komandanızı Git-ə köçməyə məcbur etmədən bir developer olaraq həyatınızı asanlaşdırmağa imkan verirlər. Windows-da işləyirsinizsə (çox güman ki, komandanız TFS istifadə edir), xüsusiyyət dəsti daha tamamlandığından git-tfs istifadə etmək istərdiniz, ancaq başqa bir platformada işləsəniz, daha məhdud olan git-tf istifadə edəcəksiniz. Bu fəsildəki alətlərin əksəriyyətində olduğu kimi, bu versiya idarəetmə sistemlərindən birini kanonik olaraq seçməlisiniz və digərini tabe bir şəkildə istifadə etməlisiniz - ya Git ya da TFVC əməkdaşlıq mərkəzi olmalıdır, lakin hər ikisi deyil.