Git
Chapters ▾ 2nd Edition

9.2 Git ve Diğer Sistemler - Git’e Geçiş

Git’e Geçiş

Başka bir VCS’te mevcut bir kod tabanınız varsa ancak Git’i kullanmaya başlamaya karar verdiyseniz, projenizi bir şekilde taşımanız gerekir. Bu bölüm, yaygın sistemler için bazı içe aktarıcıları ele alır ve ardından kendi özel içe aktarıcınızı nasıl geliştireceğinizi gösterir. Profesyonel olarak kullanılan SCM sistemlerinin çoğunluğunu oluşturdukları ve yüksek kaliteli araçların bulunması kolay olduğu için, bu sistemlerden veri içe aktarma işlemini öğreneceksiniz.

Subversion

git svn kullanımıyla ilgili önceki bölümü okuduysanız, bir repoyu svn ile kopyalamak (git svn clone) için bu talimatları kolayca kullanabilirsiniz: Sonra Subversion sunucusunu durdurup, yeni bir Git sunucusuna itin ve onu kullanmaya başlayın. Geçmişi istiyorsanız, bunu Subversion sunucusundan verileri çektiğiniz kadar hızlı bir şekilde gerçekleştirebilirsiniz (bu biraz zaman alabilir).

Ancak içe aktarma tamamen mükemmel değildir; çok uzun süreceği için bunu doğru yapsanız iyi olur. İlk sorun yazar bilgisidir. Subversion’da katkıda bulunan her kişinin sistemde katkı bilgilerinde kayıtlı bir kullanıcısı vardır. Önceki bölümdeki örneklerde, blame çıktısı ve git svn log gibi bazı yerlerde schacon gösterilmektedir. Bunu daha iyi Git yazar verileriyle eşleştirmek istiyorsanız, Subversion kullanıcılarından Git yazarlarına bir eşleştirmeye ihtiyacınız vardır. Bu eşlemeyi şu şekilde içeren users.txt adlı bir dosya oluşturun:

schacon = Scott Chacon <schacon@geemail.com>
selse = Someo Nelse <selse@geemail.com>

SVN’nin kullandığı yazar adlarının bir listesini almak için şunu çalıştırabilirsiniz:

$ svn log --xml --quiet | grep author | sort -u | \
  perl -pe 's/.*>(.*?)<.*/$1 = /'

Bu komut dizini günlük (log) çıktısını XML biçiminde oluşturur, ardından yalnızca yazar bilgilerinin bulunduğu satırları tutar, yinelenenleri atar ve XML etiketlerini çıkarır (Bariz şekilde, bu yalnızca grep, sort ve Perl yüklü bir makinede çalışır.) Ardından, her girişin yanına eşdeğer Git kullanıcı verilerini ekleyebilmeniz için bu çıktıyı users.txt dosyanıza yönlendirin.

Yazar verilerini daha doğru bir şekilde eşleştirmesine yardımcı olmak için bu dosyayı git svn 'ye sağlayabilirsiniz. Ayrıca, clone veya init komutuna --no-metadata seçeneğini ileterek, git svn 'ye Subversion’ın normalde içe aktardığı meta verileri eklememesini de söyleyebilirsiniz (ancak senkronizasyon meta verilerini korumak istiyorsanız, bu parametreyi atlamakta özgürsünüz). Bu, import komutunuzun şu şekilde görünmesini sağlar:

$ git svn clone http://my-project.googlecode.com/svn/ \
      --authors-file=users.txt --no-metadata --prefix "" -s my_project
$ cd my_project

Artık my_project dizininizde daha güzel bir Subversion içe aktarımına sahip olmalısınız. Buna benzeyen katkılar yerine

commit 37efa680e8473b615de980fa935944215428a35a
Author: schacon <schacon@4c93b258-373f-11de-be05-5f7a86268029>
Date:   Sun May 3 00:12:22 2009 +0000

    fixed install - go to trunk

    git-svn-id: https://my-project.googlecode.com/svn/trunk@94 4c93b258-373f-11de-
    be05-5f7a86268029

şunun gibi:

commit 03a8785f44c8ea5cdb0e8834b7c8e6c469be2ff2
Author: Scott Chacon <schacon@geemail.com>
Date:   Sun May 3 00:12:22 2009 +0000

    fixed install - go to trunk

Yazar alanı çok daha iyi görünmekle kalmıyor, aynı zamanda git-svn-id de artık orada değil.

Ayrıca biraz içe aktarma sonrası temizlik de yapmalısınız. Bunlardan biri git svn 'nin oluşturduğu tuhaf referansları temizlemektir. Öncelikle etiketleri, tuhaf uzak dallar yerine gerçek etiketler olacak şekilde, ve ardından geri kalan dalları da yerel olacak şekilde taşıyacaksınız.

Etiketleri uygun Git etiketleri olacak şekilde taşımak için şunu çalıştırın:

$ for t in $(git for-each-ref --format='%(refname:short)' refs/remotes/tags); do git tag ${t/tags\//} $t && git branch -D -r $t; done

Bu, refs/remotes/tags/ ile başlayan uzak dal referanslarını alır ve onları gerçek (hafif) etiketler haline getirir.

Ardından, referansların geri kalanını refs/remotes altında yerel şubelere taşıyın:

$ for b in $(git for-each-ref --format='%(refname:short)' refs/remotes); do git branch $b refs/remotes/$b && git branch -D -r $b; done

Subversion’da yalnızca bir dal görürken, sonuna @xxx (burada xxx bir sayıdır) eklenmiş bazı ekstra dallar görebilirsiniz. Bu aslında ``peg-revizyonlar`` adı verilen bir Subversion özelliğidir ve Git’te sözdizimsel karşılığı olmayan bir şeydir. Bu nedenle git svn, svn sürüm numarasını dal adına ekler (tıpkı o dalın sabit revizyonunu ele almak için svn’de yazdığınız gibi) . Artık sabit düzeltmeleri umursamıyorsanız, bunları kaldırmanız yeterlidir:

$ for p in $(git for-each-ref --format='%(refname:short)' | grep @); do git branch -D $p; done

Artık tüm eski dallar gerçek Git dalları ve tüm eski etiketler gerçek Git etiketleridir.

Temizlenecek son bir şey daha var. Ne yazık ki, git svn Subversion’un varsayılan dalına eşlenen trunk adında fazladan bir dal oluşturur, ancak trunk ref’i, master ile aynı yeri işaret eder. master kelimesi Git’e daha uyggun bir ifade biçimi olduğundan, fazladan dalın nasıl kaldırılacağı aşağıda açıklanmıştır:

$ git branch -d trunk

Yapılacak son şey, yeni Git sunucunuzu uzak olarak eklemek ve ona itmektir. Sunucunuzu uzak olarak eklemenin bir örneği:

$ git remote add origin git@my-git-server:myrepository.git

Tüm dallarınızın ve etiketlerinizin üste çıkmasını istediğiniz için artık şunu çalıştırabilirsiniz:

$ git push origin --all
$ git push origin --tags

Artık tüm dal ve etiketleriniz güzel ve temiz bir içe aktarma işlemiyle yeni Git sunucunuzda olmalıdır.

Mercurial

Mercurial ve Git’in sürümleri temsil etme modelleri çok benzer olduğundan ve Git biraz daha esnek olduğundan; bir repoyu Mercurial’den Git’e dönüştürmek oldukça basittir. Bu dönüşüm için hg-fast-export adlı bir araca ihtiyacınız olacak.

$ git clone https://github.com/frej/fast-export.git

Dönüşümün ilk adımı, dönüştürmek istediğiniz Mercurial reposunun tam kopyasını almaktır:

$ hg clone <remote repo URL> /tmp/hg-repo

Bir sonraki adım, bir yazar eşleştirme dosyası oluşturmaktır. Değişiklik setlerindeki yazar alanına koyabileceği şeyler konusunda Mercurial, Git’ten biraz daha esnek olduğu için; temizlemek için bu iyi bir zamandır. Bunu yapmak için bir bash shell’inde tek satırlık bir komut kullanabilirsiniz:

$ cd /tmp/hg-repo
$ hg log | grep user: | sort | uniq | sed 's/user: *//' > ../authors

Bu projenizin geçmişinin ne kadar uzun olduğuna bağlı olarak birkaç saniye sürecektir ve sonrasında /tmp/authors dosyası şöyle görünecektir:

bob
bob@localhost
bob <bob@company.com>
bob jones <bob <AT> company <DOT> com>
Bob Jones <bob@company.com>
Joe Smith <joe@company.com>

Bu örnekte, aynı kişi (Bob), dört farklı ad altında değişiklik setleri oluşturmuştur; bunlardan biri Git katkısı için doğru görünürken, biri tamamen geçersiz olacaktır. Hg-fast-export her bir satırı bir kurala dönüştürerek bunu düzeltmemize izin verir: "<input>"="<output>", bir <giriş> 'i bir <çıkış> 'a eşleyen bir kural. <giriş> ve <çıkış> dizelerinin içinde, python string_escape kodlaması tarafından anlaşılan tüm kaçış dizileri desteklenir. Eğer yazar eşleştirme dosyası eşleşen bir <input> içermiyorsa, bu yazar Git’e değiştirilmeden gönderilecektir. Eğer tüm kullanıcı adları uygun görünüyorsa, bu dosyaya hiç ihtiyacımız olmayacaktır. Bu örnekte, dosyamızın şu şekilde görünmesini istiyoruz:

"bob"="Bob Jones <bob@company.com>"
"bob@localhost"="Bob Jones <bob@company.com>"
"bob <bob@company.com>"="Bob Jones <bob@company.com>"
"bob jones <bob <AT> company <DOT> com>"="Bob Jones <bob@company.com>"

Aynı türdeki eşleştirme dosyası, Mercurial adı Git tarafından izin verilmediğinde dalları ve etiketleri yeniden adlandırmak için de kullanılabilir.

Bir sonraki adım, yeni Git reposunu oluşturmak ve dışa aktarma komut dosyasını çalıştırmaktır:

$ git init /tmp/converted
$ cd /tmp/converted
$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors

-r bayrağı, dönüştürmek istediğimiz Mercurial reposunu bulması için hg-fast-export’a nerede bakacağını ve -A bayrağı da yazar eşleştirme dosyasını nerede bulacağını söyler (dallar ve etiket eşleştirme dosyaları sırasıyla -B ve -T bayrakları ile belirtilir). Betik Mercurial değişiklik setlerini ayrıştırır ve bunları Git’in "fast-import" özelliği için bir betiğe dönüştürür (bu özelliği biraz sonra detaylı bir şekilde inceleyeceğiz). Bu biraz zaman alır (ancak ağ üzerinden yapılmasından çok daha hızlıdır) ancak çıktı oldukça ayrıntılıdır:

$ /tmp/fast-export/hg-fast-export.sh -r /tmp/hg-repo -A /tmp/authors
Loaded 4 authors
master: Exporting full revision 1/22208 with 13/0/0 added/changed/removed files
master: Exporting simple delta revision 2/22208 with 1/1/0 added/changed/removed files
master: Exporting simple delta revision 3/22208 with 0/1/0 added/changed/removed files
[…]
master: Exporting simple delta revision 22206/22208 with 0/4/0 added/changed/removed files
master: Exporting simple delta revision 22207/22208 with 0/2/0 added/changed/removed files
master: Exporting thorough delta revision 22208/22208 with 3/213/0 added/changed/removed files
Exporting tag [0.4c] at [hg r9] [git :10]
Exporting tag [0.4d] at [hg r16] [git :17]
[…]
Exporting tag [3.1-rc] at [hg r21926] [git :21927]
Exporting tag [3.1] at [hg r21973] [git :21974]
Issued 22315 commands
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects:     120000
Total objects:       115032 (    208171 duplicates                  )
      blobs  :        40504 (    205320 duplicates      26117 deltas of      39602 attempts)
      trees  :        52320 (      2851 duplicates      47467 deltas of      47599 attempts)
      commits:        22208 (         0 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:         109 (         2 loads     )
      marks:        1048576 (     22208 unique    )
      atoms:           1952
Memory total:          7860 KiB
       pools:          2235 KiB
     objects:          5625 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit      = 8589934592
pack_report: pack_used_ctr            =      90430
pack_report: pack_mmap_calls          =      46771
pack_report: pack_open_windows        =          1 /          1
pack_report: pack_mapped              =  340852700 /  340852700
---------------------------------------------------------------------

$ git shortlog -sn
   369  Bob Jones
   365  Joe Smith

İşte hepsi bu kadar. Tüm Mercurial etiketleri Git etiketlerine, Mercurial dalları ve yer imleri de Git dallarına dönüştürülmüştür. Şimdi, reponuzu yeni sunucu ana dizinine gönderecek durumdasınız:

$ git remote add origin git@my-git-server:myrepository.git
$ git push origin --all

Bazaar

Bazaar, Git gibi bir Dağıtık Sürüm Kontrol Sistemi (DVCS) aracıdır ve sonuç olarak bir Bazaar reposunu bir Git reposuna dönüştürmek oldukça basittir. Bunun için bzr-fastimport eklentisini içe aktarmanız gerekecek.

bzr-fastimport Eklentisini Edinme

UNIX benzeri işletim sistemlerinde hızlı içe aktarma eklentisini kurmanın yolu ve Windows’tan farklıdır. UNIX’te en kolayı gerekli tüm bağımlılıkları kuracak olan bzr-fastimport paketini kurmaktır.

Örneğin, Debian ve türevlerinde şunları yapabilirsiniz:

$ sudo apt-get install bzr-fastimport

RHEL ile şunları yapabilirsiniz:

$ sudo yum install bzr-fastimport

Fedora ile sürüm 22’den beri paket yöneticisi dnf’tir:

$ sudo dnf install bzr-fastimport

Paket mevcut değilse, onu eklenti olarak yükleyebilirsiniz:

$ mkdir --parents ~/.bazaar/plugins     # creates the necessary folders for the plugins
$ cd ~/.bazaar/plugins
$ bzr branch lp:bzr-fastimport fastimport   # imports the fastimport plugin
$ cd fastimport
$ sudo python setup.py install --record=files.txt   # installs the plugin

Bu eklentinin çalışması için ayrıca fastimport Python modülüne de ihtiyacınız olacaktır. Onun mevcut olup olmadığını kontrol edebilir ve aşağıdaki komutlarla yükleyebilirsiniz:

$ python -c "import fastimport"
Traceback (most recent call last):
  File "<string>", line 1, in <module>
ImportError: No module named fastimport
$ pip install fastimport

Eğer mevcut değilse, onu https://pypi.python.org/pypi/fastimport/ adresinden indirebilirsiniz.

Windows’ta bzr-fastimport standalone (bağımsız) sürümüyle ve varsayılan kurulumla (tüm onay kutularını işaretleyerek) otomatik olarak kuruludır. Bu durumda yapmanız gereken bir şey yoktur.

Bu noktada, bir Bazaar reposunu içe aktarma yöntemi, tek bir dalınızın olup olmadığına veya birçok dala sahip bir repoyla çalışıp çalışmadığınıza göre farklılık gösterir.

Tek Dallı Proje

Şimdi, Bazaar reposunu içeren dizine gidin ve Git reposunu başlatın:

$ cd /path/to/the/bzr/repository
$ git init

Şimdi, Bazaar reposunu dışa aktarabilir ve aşağıdaki komutu kullanarak bir Git reposuna dönüştürebilirsiniz:

$ bzr fast-export --plain . | git fast-import

Proje boyutuna bağlı olarak, Git reposunun oluşturulması birkaç saniye ile birkaç dakika arasında sürebilir.

Bir Anadal ve Bir Çalışma Dalı Olan Proje Durumu

Dallara sahip bir Bazaar reposunu da içe aktarabilirsiniz. Diyelim ki iki dalınız var: biri ana dalı temsil eder (myProject.trunk), diğeri ise çalışma dalıdır (myProject.work).

$ ls
myProject.trunk myProject.work

Git reposunu oluşturun ve dizinine gidin:

$ git init git-repo
$ cd git-repo

Master dalını Git’e çekin:

$ bzr fast-export --export-marks=../marks.bzr ../myProject.trunk | \
git fast-import --export-marks=../marks.git

Çalışma dalını Git’e çekin:

$ bzr fast-export --marks=../marks.bzr --git-branch=work ../myProject.work | \
git fast-import --import-marks=../marks.git --export-marks=../marks.git

Şimdi git branch komutu hem master dalını, hem de work dalını gösterir. Tamam olduğundan emin olmak için; log kayıtlarını kontrol edip, marks.bzr ve marks.git dosyalarını temizleyin.

İzleme Alanını (Stage) Senkronize Etme

Ne kadar çok dalınız olursa olsun ve hangi içe aktarma yöntemini kullanırsanız kullanın, izleme alanınız HEAD ile senkronize değildir; ve birden fazla dalın içe aktarılmasıyla, çalışma diziniz de senkronize değildir.

Bu durumu aşağıdaki komutla kolayca çözebilirsiniz:

$ git reset --hard HEAD

.bzrignore ile Yoksayılmış Dosyaları Yoksaymak

Şimdi yoksayılacak dosyalara bir göz atalım. İlk yapmanız gereken .bzrignore dosyasını .gitignore olarak yeniden adlandırmaktır. .bzrignore dosyası "!!" veya "RE:" ile başlayan bir veya birkaç satır içeriyorsa, bunu değiştirmeniz ve belki de Bazaar’ın yoksaydığı tam olarak aynı dosyaları yoksaymak için birkaç .gitignore dosyası oluşturmanız gerekebilir.

Son olarak, bu değişikliği içeren taşınma (migration) için bir katkı oluşturmanız gerekecektir:

$ git mv .bzrignore .gitignore
$ # modify .gitignore if needed
$ git commit -am 'Migration from Bazaar to Git'

Reponuzu Sunucuya Göndermek

İşte oldu! Artık reponuzu yeni ana sunucusuna aktarabilirsiniz:

$ git remote add origin git@my-git-server:mygitrepository.git
$ git push origin --all
$ git push origin --tags

Git reponuz kullanıma hazırdır.

Perforce

İçe aktarmayı inceleyeceğimiz bir sonraki sistem Perforce’tur. Yukarıda belirttiğimiz gibi Git ve Perforce’un birbirleriyle konuşmasına izin vermenin iki yolu vardır: git-p4 ve Perforce Git Fusion.

Perforce Git Fusion

Git Fusion bu süreci oldukça ağrısız hale getirir. Proje ayarlarınızı, kullanıcı eşlemelerinizi ve dallarınızı bir yapılandırma dosyası kullanarak (Git Fusion bölümünde anlatıldığı gibi) yapılandırın ve repoyu kopyalayın. Git Fusion size yerel bir Git reposuna benzer bir şey bırakır. Bunu daha sonra isterseniz yerel bir Git ana bilgisayarına gönderebilirsiniz. İsterseniz Perforce’u Git sunucunuz olarak bile kullanabilirsiniz.

Git-p4

Git-p4 aynı zamanda bir içe aktarma aracı görevi de görebilir. Örnek olarak Jam projesini "Perforce Public Depot" 'dan içe aktaracağız. İstemcinizi kurmak için P4PORT ortam değişkenini Perforce deposunu işaret edecek şekilde dışa aktarmanız gerekir:

$ export P4PORT=public.perforce.com:1666
Not

Takip etmek için bağlantı kurabileceğiniz bir Perforce deposuna ihtiyacınız olacak. Örneklerimiz için public.perforce.com adresindeki genel depoyu kullanacağız, ancak erişiminiz olan herhangi bir depoyu da kullanabilirsiniz.

Jam projesini Perforce sunucusundan içe aktarmak için depo ve proje yolunu ve projeyi içe aktarmak istediğiniz yolu sağlayarak git p4 clone komutunu çalıştırın:

$ git-p4 clone //guest/perforce_software/jam@all p4import
Importing from //guest/perforce_software/jam@all into p4import
Initialized empty Git repository in /private/tmp/p4import/.git/
Import destination: refs/remotes/p4/master
Importing revision 9957 (100%)

Bu özel projenin yalnızca bir dalı vardır, ancak dal görünümleriyle (veya yalnızca bir dizin kümesi) yapılandırılmış dallarınız varsa; tüm dosyaları ve projenin alt dallarını içe aktarmak için --detect-branches işaretini git p4 clone komutuna ekleyerek kullanabilirsiniz. Bu konuda biraz daha ayrıntılı bilgi için Dallandırma konusuna bakın.

Bu noktada işiniz neredeyse bitti. p4import dizinine gidip git log çalıştırırsanız, içe aktarılan çalışmanızı görebilirsiniz:

$ git log -2
commit e5da1c909e5db3036475419f6379f2c73710c4e6
Author: giles <giles@giles@perforce.com>
Date:   Wed Feb 8 03:13:27 2012 -0800

    Correction to line 355; change </UL> to </OL>.

    [git-p4: depot-paths = "//public/jam/src/": change = 8068]

commit aa21359a0a135dda85c50a7f7cf249e4f7b8fd98
Author: kwirth <kwirth@perforce.com>
Date:   Tue Jul 7 01:35:51 2009 -0800

    Fix spelling error on Jam doc page (cummulative -> cumulative).

    [git-p4: depot-paths = "//public/jam/src/": change = 7304]

git-p4 'ün her katkı mesajında ​​bir tanımlayıcı bıraktığını görebilirsiniz. Daha sonra Perforce değişiklik numarasına başvurmanız gerekebileceği ihtimaline karşı, bu tanımlayıcıyı orada tutmanızda bir sakınca yoktur. Ancak tanımlayıcıyı kaldırmak isterseniz (ki yeni repo üzerinde çalışmaya başlamadan önce bunu yapmanın tam zamanıdır), tanımlayıcı dizeleri topluca kaldırmak için git filter-branch 'ı kullanabilirsiniz:

$ git filter-branch --msg-filter 'sed -e "/^\[git-p4:/d"'
Rewrite e5da1c909e5db3036475419f6379f2c73710c4e6 (125/125)
Ref 'refs/heads/master' was rewritten

git log 'u çalıştırırsanız, katkılara ilişkin tüm SHA-1 sağlama toplamlarının değiştiğini, ancak git-p4 dizelerinin artık katkı mesajlarında olmadığını görebilirsiniz:

$ git log -2
commit b17341801ed838d97f7800a54a6f9b95750839b7
Author: giles <giles@giles@perforce.com>
Date:   Wed Feb 8 03:13:27 2012 -0800

    Correction to line 355; change </UL> to </OL>.

commit 3e68c2e26cd89cb983eb52c024ecdfba1d6b3fff
Author: kwirth <kwirth@perforce.com>
Date:   Tue Jul 7 01:35:51 2009 -0800

    Fix spelling error on Jam doc page (cummulative -> cumulative).

İçe aktarma işleminiz yeni Git sunucunuza gönderilmeye hazırdır.

TFS

Takımınız kaynak kontrolünü TFVC’den Git’e dönüştürüyorsa, bunu en yüksek doğrulukta gerçekleştirmek isteyeceksiniz. Ara işlev bölümünde hem git-tfs’i hem de git-tf’yi ele aldığımızı göz önünde bulundurursak, bu bölümde yalnızca git-tfs’i ele alacağımız anlamına gelir. Çünkü git-tfs dallarını destekler ve bunu git-tf ile yapmak oldukça zordur.

Not

Bu tek yönlü bir dönüşümdür. Oluşan Git reposu, orijinal TFVC projesi ile bağlantı kuramaz.

İlk yapmanız gereken şey, kullanıcı adlarını eşlemektir. TFVC değişiklik setleri için yazar alanına neyin gireceği konusunda oldukça serbesttir, ancak Git okunabilir bir ad ve e-posta adresi ister. Bu bilgiyi tf komut satırı istemcisinden şöyle alabilirsiniz:

PS> tf history $/myproject -recursive > AUTHORS_TMP

Bu projenin tarihindeki tüm değişiklik setlerini alır ve bunları işleyeceğimiz AUTHORS_TMP dosyasına koyar. User sütununun (ikinci sütun) verilerini çıkarmak için dosyayı açın ve sütunun hangi karakterlerde başladığını ve bittiğini bulun, ardından aşağıdaki komut satırındaki cut komutunun 11-20 parametrelerini bulunanlarla değiştirin:

PS> cat AUTHORS_TMP | cut -b 11-20 | tail -n+3 | sort | uniq > AUTHORS

cut komutu her satırdan 11 ile 20 arasındaki karakterleri korur. tail komutu başlık alanları ve ASCII alt çizgileri olan ilk iki satırı atlar. Elde edilen sonuç, yinelenenleri ortadan kaldırmak için sort ve uniq e yönlendirilir ve AUTHORS adında bir dosyaya kaydedilir. Sonraki adım el ile yapılmalıdır, git-tfs’nin bu dosyayı etkin bir şekilde kullanabilmesi için her satır bu formatta olmalıdır:

DOMAIN\username = User Name <email@address.com>

Sol taraftaki bölüm TFVC’den gelen "Kullanıcı" (user) alanıdır, eşittir işaretinin sağ tarafındaki bölüm ise Git işlemleri için kullanılacak olan kullanıcı adıdır.

Bu dosyayı aldıktan sonra, yapmanız gereken sıradaki şey ilgilendiğiniz TFVC projesinin bir kopyasını yapmaktır:

PS> git tfs clone --with-branches --authors=AUTHORS https://username.visualstudio.com/DefaultCollection $/project/Trunk project_git

Aşağıdaki komut, katkı mesajlarının altındaki git-tfs-id bölümlerini temizleyecektir:

PS> git filter-branch -f --msg-filter 'sed "s/^git-tfs-id:.*$//g"' '--' --all

Bu komut Git-bash ortamındaki sed komutunu kullanarak git-tfs-id: ile başlayan her satırı boş bir metinle değiştirir ve Git’in bu satırları görmezden gelmesini sağlar.

Hepsi tamamlandıktan sonra yeni bir uzak repo ekleyebilir, tüm dalları üstakıma itebilir ve ekibinizin Git üzerinden çalışmaya başlamasını sağlayabilirsiniz.

Farklı Bir İçe-Aktarıcı

Eğer sisteminiz yukarıdakilerden biri değilse, çevrimiçi bir içe aktarıcı aramalısınız. Bir çok farklı sistem için CVS, Clear Case, Visual Source Safe ve hatta dizinler için bir arşiv de içeren kaliteli aktarıcılar mevcuttur. Eğer bu araçlardan hiçbiri sizin için uygun değilse, daha az bilinen bir araç kullanıyorsanız veya bir şekilde daha özel bir içe aktarma işlemine ihtiyacınız varsa, git fast-import 'u kullanmalısınız. Bu komut belirli Git verilerini yazmak için stdin’den basit talimatlar okur. Bu şekilde Git nesneleri oluşturmak, ham Git komutlarını çalıştırmaktan veya ham nesneleri yazmaya çalışmaktan çok daha kolaydır (daha fazla bilgi için Dahili Git Ögeleri bölümüne bakın). Bu şekilde, içe aktardığınız sistemden gerekli bilgileri okuyup, stdout’a basit talimatlar yazdıracak bir içe aktarma betiği oluşturabilirsiniz. Ardından, bu programı çalıştırabilir ve çıktısını git fast-import üzerinden akıtarak içe aktarabilirsiniz.

Size hızlı bir şekilde öğretmek için, basit bir içe aktarıcı yazdıracağız. Şimdi, mevcut bir dizinde çalıştığınızı varsayalım. Projenizi zaman zaman dizini zaman damgasıyla işaretlenmiş bir back_YYYY_MM_DD yedek dizinine kopyalayarak yedekliyorsunuz ve bunu Git’e içe aktarmak istiyorsunuz. Dizin yapınız şöyle görünüyor:

$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03
current

Git dizinini içe aktarmak için, Git’in verilerini nasıl depoladığını gözden geçirmeniz gerekir. Hatırlayacağınız üzere, Git temel olarak, içeriğin pozlarına işaret eden katkı nesnelerinin bir listesinden oluşur. Yapmanız gereken tek şey, fast-import ile içerik pozlarının ne olduğunu, onlara işaret eden katkı verilerini ve bunların sıralanma düzenini söylemektir. Stratejiniz pozları tek tek geçerken, her dizinin içeriğini bir önceki katkıyla ilişkilendirekek yeni bir katkı oluşturmaktır.

Bir Örnek: Mecburi Git Politikası bölümünde yaptığımız gibi, genellikle bununla çalıştığımız ve okuması kolay alduğu için kodumuzu Ruby’de yazacağız. Siz aşina olduğunuz herhangi bir dilde de bunu yazabilirsiniz (yalnızca uygun bilgilerin stdout a yazdırılması gerekmektedir). Ve eğer Windows’ta çalışıyorsanız, sadece satır sonuna taşıma dönüşlerini (CRLF) koymamaya, özel bir dikkat göstermeniz gerekecektir. 'git fast-import Windows’un kullandığı satır başı satır beslemelerini (CRLF) değil, yalnızca satır beslemelerini (LF) isteme konusunda çok hassasdır.

Başlamak için, hedef dizine gidip, her birinin bir katkı olarak içe aktarılmasını istediğiniz her alt dizini tanımlayacaksınız. Her alt dizine geçip, onu dışa aktarmak için gerekli komutları yazdırırsınız. Temel ana döngünüz şöyle görünecektir:

last_mark = nil

# loop through the directories
Dir.chdir(ARGV[0]) do
  Dir.glob("*").each do |dir|
    next if File.file?(dir)

    # move into the target directory
    Dir.chdir(dir) do
      last_mark = print_export(dir, last_mark)
    end
  end
end

Her dizin içinde print_export 'u çalıştırırsınız: bu önceki anlık görüntünün bildirimini ve işaretini alırarak sıradakinin bildirim ve işaretini döndürür. Bu şekilde, onları uygun şekilde bağlayabilirsiniz. Mark katkıya verdiğiniz bir "hızlı-içe-aktarma" tanımıdır: katkı oluşturduğunuzda, her birine başka katkılardan bağlantı kurmak için kullanabileceğiniz bir işaret verirsiniz. Dolayısıyla, print_export yönteminizde yapmanız gereken ilk şey, dizin adından bir işaret oluşturmaktır:

mark = convert_dir_to_mark(dir)

İşaretin bir tamsayı olması gerektiği için, bunu bir dizin serisi oluşturarak ve işaret olarak indeks değerini kullanarak yapacaksınız. Yönteminiz şuna benzer:

$marks = []
def convert_dir_to_mark(dir)
  if !$marks.include?(dir)
    $marks << dir
  end
  ($marks.index(dir) + 1).to_s
end

Şimdi katkınız bir tam sayı temsilini aldığına göre, katkı meta verileri için bir tarih gerekmektedir. Tarih dizinin adında ifade edildiğinden, bunu dışarı çıkarmanız gerekecektir. print_export dosyanızdaki bir sonraki satır şu şekildedir:

date = convert_dir_to_date(dir)

burada convert_dir_to_date şu şekilde tanımlanır:

def convert_dir_to_date(dir)
  if dir == 'current'
    return Time.now().to_i
  else
    dir = dir.gsub('back_', '')
    (year, month, day) = dir.split('_')
    return Time.local(year, month, day).to_i
  end
end

Bu her dizinin tarihi için bir tamsayı değeri döndürür. Her katkı için ihtiyacınız olan son meta bilgi parçası, global bir değişkene kodladığınız katkı verileridir:

$author = 'John Doe <john@example.com>'

Artık aktarıcınız için katkı verilerini yazdırmaya başlamaya hazırsınız. İlk bilgiler, bir katkı nesnesini tanımladığınızı ve bunun hangi dalda olduğunu; ardından, oluşturduğunuz işareti, katkılayanın bilgilerini ve katkı mesajını; ve onun ardından da -varsa- önceki katkıyı belirtir. Kodunuz şuna benzer:

# print the import information
puts 'commit refs/heads/master'
puts 'mark :' + mark
puts "committer #{$author} #{date} -0700"
export_data('imported from ' + dir)
puts 'from :' + last_mark if last_mark

Yapması kolay olduğu için saat dilimini (-0700) kodlayın. Başka bir sistemden içe aktarıyorsanız saat dilimini fark olarak belirtmeniz gerekir. Katkı mesajı özel bir formatta ifade edilmelidir:

data (size)\n(contents)

Format: kelime verileri, okunacak verinin boyutu, yeni satır ve son olarak verilerden oluşur. Daha sonra dosya içeriğini belirtmek için aynı biçimi kullanmanız gerektiğinden, export_data adında bir yardımcı yöntem oluşturursunuz:

def export_data(string)
  print "data #{string.size}\n#{string}"
end

Geriye kalan tek şey, her poz için dosya içeriğini belirtmektir. Bunların hepsi tek bir dizinde bulunduğu için bu da kolaydır; deleteall komutunu ve ardından dizindeki her dosyanın içeriğini yazdırabilirsiniz. Git daha sonra her pozu uygun şekilde kaydedecektir:

puts 'deleteall'
Dir.glob("**/*").each do |file|
  next if !File.file?(file)
  inline_data(file)
end

Not: Birçok sistem, revizyonlarını bir katkıdan diğerine yapılan değişiklikler olarak düşündüğünden, hızlı içe aktarma, her bir katkıda hangi dosyaların eklendiğini, kaldırıldığını veya değiştirildiğini; ve yeni içeriklerin neler olduğunu belirtmek için komutlar alabilir. Pozlar arasındaki farkları hesaplayabilir ve yalnızca bu verileri sağlayabilirsiniz, ancak bunu yapmak daha karmaşıktır: Git’e tüm verileri verip, onun çözmesine izin verebilirsiniz. Eğer bu verileriniz için daha uygunsa, verilerinizi bu şekilde nasıl sağlayacağınıza ilişkin ayrıntılar için hızlı içe aktarma kılavuz sayfasına bakın.

Yeni dosya içeriklerini listeleme veya yeni içeriklerle değiştirilmiş bir dosyayı belirtme formatı aşağıdaki gibidir:

M 644 inline path/to/file
data (size)
(file contents)

Burada mod 644’tür (yürütülebilir dosyalarınız varsa, bunun yerine 755’i tespit edip belirtmeniz gerekir) ve satır içinde bu satırın hemen ardından içerikleri listeleyeceğiniz yazmaktadır. inline_data yönteminiz şuna benzer:

def inline_data(file, code = 'M', mode = '644')
  content = File.read(file)
  puts "#{code} #{mode} inline #{file}"
  export_data(content)
end

Katkı mesajı verilerinizi belirttiğiniz yöntemle aynı olduğu için daha önce tanımladığınız export_data yöntemini yeniden kullanırsınız.

Yapmanız gereken son şey, bir sonraki yinelemeye aktarılabilmesi için mevcut işareti döndürmektir:

return mark
Not

Windows üzerinde çalışıyorsanız fazladan bir adım eklediğinizden emin olmanız gerekir. Daha önce de belirtildiği gibi, Windows yeni satır karakterleri için CRLF’yi kullanırken git fast-import yalnızca LF’yi bekler. Bu sorunu aşmak ve git fast-import 'u mutlu etmek için Ruby’ye CRLF yerine LF kullanmasını söylemeniz gerekir:

$stdout.binmode

Bu kadar. İşte senaryonun tamamı:

#!/usr/bin/env ruby

$stdout.binmode
$author = "John Doe <john@example.com>"

$marks = []
def convert_dir_to_mark(dir)
    if !$marks.include?(dir)
        $marks << dir
    end
    ($marks.index(dir)+1).to_s
end

def convert_dir_to_date(dir)
    if dir == 'current'
        return Time.now().to_i
    else
        dir = dir.gsub('back_', '')
        (year, month, day) = dir.split('_')
        return Time.local(year, month, day).to_i
    end
end

def export_data(string)
    print "data #{string.size}\n#{string}"
end

def inline_data(file, code='M', mode='644')
    content = File.read(file)
    puts "#{code} #{mode} inline #{file}"
    export_data(content)
end

def print_export(dir, last_mark)
    date = convert_dir_to_date(dir)
    mark = convert_dir_to_mark(dir)

    puts 'commit refs/heads/master'
    puts "mark :#{mark}"
    puts "committer #{$author} #{date} -0700"
    export_data("imported from #{dir}")
    puts "from :#{last_mark}" if last_mark

    puts 'deleteall'
    Dir.glob("**/*").each do |file|
        next if !File.file?(file)
        inline_data(file)
    end
    mark
end

# Loop through the directories
last_mark = nil
Dir.chdir(ARGV[0]) do
    Dir.glob("*").each do |dir|
        next if File.file?(dir)

        # move into the target directory
        Dir.chdir(dir) do
            last_mark = print_export(dir, last_mark)
        end
    end
end

Bu betiği çalıştırırsanız şuna benzer bir içerik elde edersiniz:

$ ruby import.rb /opt/import_from
commit refs/heads/master
mark :1
committer John Doe <john@example.com> 1388649600 -0700
data 29
imported from back_2014_01_02deleteall
M 644 inline README.md
data 28
# Hello

This is my readme.
commit refs/heads/master
mark :2
committer John Doe <john@example.com> 1388822400 -0700
data 29
imported from back_2014_01_04from :1
deleteall
M 644 inline main.rb
data 34
#!/bin/env ruby

puts "Hey there"
M 644 inline README.md
(...)

Aktarıcıyı çalıştırmak için, içe aktarmak istediğiniz Git dizinindeyken bu çıktıyı git fast-import aracılığıyla aktarın. Yeni bir dizin oluşturabilir ve ardından başlangıç ​​noktası olarak bu dizin içinde git init 'i çalıştırabilir ve ardından betiğinizi çalıştırabilirsiniz:

$ git init
Initialized empty Git repository in /opt/import_to/.git/
$ ruby import.rb /opt/import_from | git fast-import
git-fast-import statistics:
---------------------------------------------------------------------
Alloc'd objects:       5000
Total objects:           13 (         6 duplicates                  )
      blobs  :            5 (         4 duplicates          3 deltas of          5 attempts)
      trees  :            4 (         1 duplicates          0 deltas of          4 attempts)
      commits:            4 (         1 duplicates          0 deltas of          0 attempts)
      tags   :            0 (         0 duplicates          0 deltas of          0 attempts)
Total branches:           1 (         1 loads     )
      marks:           1024 (         5 unique    )
      atoms:              2
Memory total:          2344 KiB
       pools:          2110 KiB
     objects:           234 KiB
---------------------------------------------------------------------
pack_report: getpagesize()            =       4096
pack_report: core.packedGitWindowSize = 1073741824
pack_report: core.packedGitLimit      = 8589934592
pack_report: pack_used_ctr            =         10
pack_report: pack_mmap_calls          =          5
pack_report: pack_open_windows        =          2 /          2
pack_report: pack_mapped              =       1457 /       1457
---------------------------------------------------------------------

Gördüğünüz gibi, başarıyla tamamlandığında, size neleri başardığına dair bir sürü istatistik veriyor. Burada, 1 dalda 4 katkı için toplam 13 nesneyi içe aktardınız. Artık yeni geçmişinizi görmek için git log 'u çalıştırabilirsiniz:

$ git log -2
commit 3caa046d4aac682a55867132ccdfbe0d3fdee498
Author: John Doe <john@example.com>
Date:   Tue Jul 29 19:39:04 2014 -0700

    imported from current

commit 4afc2b945d0d3c8cd00556fbe2e8224569dc9def
Author: John Doe <john@example.com>
Date:   Mon Feb 3 01:00:00 2014 -0700

    imported from back_2014_02_03

İşte güzel ve temiz bir Git reposu. Hiçbir şeyin henüz alınmadığını farketmeniz önemlidir (başlangıçta çalışma dizininizde herhangi bir dosya yoktur). Bunları almak için dalınızı, şu anda master 'ın olduğu yere sıfırlamanız gerekmektedir:

$ ls
$ git reset --hard master
HEAD is now at 3caa046 imported from current
$ ls
README.md main.rb

fast-import aracıyla çok daha fazlasını yapabilirsiniz; farklı modları, ikili verileri, birden fazla dallanmayı ve birleştirmeyi, etiketleri, ilerleme göstergelerini ve daha fazlasını yönetebilirsiniz. Git kaynak kodunun contrib/fast-import dizininde daha karmaşık senaryoların bir dizi örneği mevcuttur.

scroll-to-top