Git
Chapters ▾ 2nd Edition

9.2 Гит и остали системи - Мигрирање на Гит

Мигрирање на Гит

Ако имате постојећу базу кода у неком другом VCS али сте одлучили да почнете користити програм Гит, морате да мигрирате пројекат на један или други начин. Овај одељак представља неке увознике за уобичајене системе, па онда приказује како можете да израдите свој сопствени. Научићете како да увезете податке из неколико других већих SCM који се професионално користе, зато што њих користи већина корисника који желе да начине промену и због тога што је једноставно доћи до високо квалитетних алата за њих.

Subversion

Ако сте читали претходни одељак о коришћењу git svn, та упутства можете лако да следите и направите git svn clone репозиторијума; па затим престанете да користите Subversion сервер, гурнете на нови Гит сервер и почнете то да користите. Ако вам је потребна историја, добићете је онолико брзо колико је потребно да повучете податке са Subversion сервера (што може да потраје).

Међутим, увоз није савршен; а пошто ће потрајати прилично дуго, такође можете да га урадите и како треба. Први проблем су информације о аутору. У програму Subversion, свака особа која комитује има корисничко име на систему које се бележи у комит информацијама. Примери у претходном одељку приказују на неким местима schacon, као што је излаз команди blame и git svn log. Ако ово желите да мапирате у боље Гит податке о аутору, потребно вам је мапирање из Subversion корисника на Гит ауторе. Креирајте фајл под именом users.txt који ово мапирање има у следећем формату:

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

Да бисте добили листу имена аутора које користи SVN, извршите следеће:

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

Ово генерише лог излаз у XML формату, затим задржава само линије са информацијама о аутору, одбацује дупликате и уклања XML ознаке. Очигледно је да функционише само на машини са инсталираним grep, sort, и perl. Затим, преусмерава узлаз у ваш users.txt фајл тако да уз сваку ставку можете додати податке еквивалентног Гит корисника.

Белешка

Ако ово пробате на Виндоуз машини, на овом месту ћете наићи на проблем. Мајкрософт је понудио неколико добрих савета и примера на адреси https://docs.microsoft.com/en-us/azure/devops/repos/git/perform-migration-from-svn-to-git.

Овај фајл можете доставити команди git svn и помогнете јој да прецизније мапира податке о аутору. git svn такође можете наложити да не укључи метаподатке које Subversion обично увози, ако команди clone или init проследите --no-metadata. Метаподаци садрже git-svn-id у свакој комит поруци коју ће програм Гит генерисати током увоза. То ће да претрпа ваш Гит лог, па може постати донекле нејасан.

Белешка

Ако комитове направљене у Гит репозиторијуму желите да пресликате назад у оригинални SVN репозиторијум, мораћете да очувате метаподатке. Ако у свом логу комитова не желите синхронизацију, слободно изоставите параметар --no-metadata.

Тако да ваша import команда изгледа овако:

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

Сада би у my_project директоријуму требало да имате лепше увезене Subversion податке. Уместо да комитови изгледају на следећи начин:

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

они изгледају овако:

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

    fixed install - go to trunk

Не само да поље Author изгледа много боље, већ се ту више не налази ни git-svn-id.

Такође би требало мало и да почистите након увоза. Било би добро да почистите чудне референце које је поставила git svn. Најпре ћете преместити ознаке тако заиста постану ознаке, е не чудне удаљене гране, па ћете затим преместити остатак грана тако да постану локалне.

Да би ознаке постале прописне Гит ознаке, извршите:

$ 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

Ово узима референце које су биле удаљене гране, а почињу на remotes/origin/tags/ и претвара их у праве (просте) ознаке.

Затим, преместите остатак референци под refs/remotes тако да постану локалне гране:

$ 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

Може се догодити да видите неке додатне гране које имају @xxx суфикс (где је xxx број), док у Subversion видите само једну грану. Ово је заправо Subversion могућност под називом „peg-revisions” и програм Гит за то једноставно нема одговарајући синтаксни елемент. Стога, git svn просто додаје број svn верзије имену гране на исти начин као што бисте ви и ви урадили у svn како би се обратили peg-ревизији те гране. Ако више не водите рачуна о peg-ревизијама, једноставно их уклоните:

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

Сада су све старе гране праве Гит гране и све старе ознаке праве Гит ознаке.

Постоји још једна ствар која треба да се почисти. Нажалост, git svn креира додатну грану под називом trunk и која се мапира на подразумевану грану у Subversion, али trunk референца показује на исто место као и master. Пошто master више одговара Гит стилу, ево како да уклоните додатну грану:

$ git branch -d trunk

Последња ствар који треба да урадите је да свој нови Гит сервер додате као удаљени репозиторијум и да гурнете на њега. Ево примера како да додате свој сервер као удаљени репозиторијум:

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

Пошто желите да све ваше гране и ознаке оду узводно, требало би да извршите следеће:

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

Сада би све ваше гране и ознаке требало да се налазе на Гит серверу након финог, чистог увоза.

Меркуријал

Пошто Меркуријал и Гит имају прилично сличне моделе за представљање верзија, а како је програм Гит мало флексибилнији, конвертовање репозиторијума из Меркуријал у Гит је прилично лако, употребом алата под називом hg-fast-export, који прво треба да преузмете:

$ git clone http://repo.or.cz/r/fast-export.git /tmp/fast-export

Први корак конверзије је да преузмете потпуни клон Меркуријал репозиторијума који желите да конвертујете:

$ hg clone <URL адреса удаљеног репозиторијума> /tmp/hg-repo

Наредни корак је креирање фајла за мапирање аутора. Меркуријал није толико стриктан као Гит у вези тога шта ће ставити у поље аутора скупа измена, тако да је ово добар тренутак да мало поспремите кућу. Генерисање овог фајла је једнолинијска команда у bash љуски:

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

Ово ће потрајати неколико секунди, зависно од величине историје пројекта, па ће након тога фајл /tmp/authors изгледати отприлике овако:

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

У овом примеру, иста особа (Bob) је креирала скупове измена користећи четири различита имена, од којих једно изгледа коректно, а једно би било потпуне неисправно за Гит комит. Hg-fast-export вам омогућава да ово исправите тако што сваку линију претворите у правило: "<улаз>"="<излаз>", које мапира <улаз> у <излаз>. Унутар стрингова <улаз> и <излаз>, подржавају се сви означени низови које препознаје Пајтон string_escape кодирање. Ако фајл мапирања аутора не садржи одговарајући <улаз>, онда се тај аутор шаље програму Гит неизмењен. Ако сва корисничка имена изгледају како треба, нема потребе да се овај фајл исправља. У овом примеру, желимо да наш фајл изгледа на следећи начин:

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

Наредни корак је да креирамо наш нови Гит репозиторијум и да извршимо скрипту за извоз:

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

Заставица -r говори hg-fast-export где да пронађе Меркуријал репозиторијум који желимо да конвертујемо, а заставица -A говори где да пронађе фајл са мапирањима аутора. Скрипта парсира Меркуријал скупове измена и конвертује их у скрипту за „fast-import” могућност програма Гит (коју ћемо детаљно приказати мало касније). Ово ће потрајати (мада је много брже него што би било преко мреже), а излаз је прилично детаљан:

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

И то је скоро све у вези конверзије. Све Меркуријал ознаке су конвертоване у Гит ознаке, а Меркуријал гране и маркери су конвертовани у Гит гране. Сада сте спремни да гурнете репозиторијум узводно на његово ново место на серверу:

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

Базаар

Базаар је DVCS алат који веома личи на Гит, па је стога прилично једноставно конвертовати Базаар репозиторијум у Гит. Да бисте то постигли, потребан вам је bzr-fastimport додатак.

Преузимање bzr-fastimport додатка

Процедура за инсталацију fastimport додатка се разликује на Виндоуз и системима сличним Јуниксу. У другом случају је најједноставније да инсталирате bzr-fastimport пакет који ће инсталирати и све неопходне зависности.

На пример, на Дебијан и системима изведеним из њега, урадили бисте следеће:

$ sudo apt-get install bzr-fastimport

На RHEL, урадили бисте следеће:

$ sudo yum install bzr-fastimport

На Федори, почевши од издања 22, нови менаџер пакета је dnf:

$ sudo dnf install bzr-fastimport

Ако пакет није доступан, можете да га инсталирате као додатак:

$ 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

Да би овај додатак радио, такође вам је потребан и fastimport Пајтон модул. Следећим командама можете проверити да ли је присутан или не и инсталирати га ако треба:

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

Ако није доступан, преузмите га са адресе https://pypi.python.org/pypi/fastimport/.

У првом случају (на Виндоуз систему), bzr-fastimport се аутоматски инсталира са самосталном верзијом и подразумеваном инсталацијом (оставите штиклирана сва поља). Тако да у овом случају није потребно да било шта урадите.

Сада се начин увоза Базаар репозиторијума разликује у зависности од тога да ли имате једну грану или радите са репозиторијумом који има неколико грана.

Пројекти са једном граном

Извршите cd у директоријум који садржи ваш Базаар репозиторијум и иницијализујте Гит репозиторијум:

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

Сада једноставно извезете свој Базаар репозиторијум и конвертујете га у Гит репозиторијум следећом командом:

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

Зависно од величине пројекта, ваш Гит репозиторијум се изграђује у року од неколико секунди до неколико минута.

Случај пројекта са главном граном и радним гранама

Такође можете да увезете и Базаар репозиторијум који садржи гране. Претпоставимо да имате две гране: једна представља главну грану (myProject.trunk), а друга је радна грана (myProject.work).

$ ls
myProject.trunk myProject.work

Креирајте Гит репозиторијум и извршите cd у њега:

$ git init git-repo
$ cd git-repo

Повуците master грану у Гит:

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

Повуците радну грану у Гит:

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

Сада вам команда git branch приказује master грану као и work грану. Проверите логове да потврдите јесу ли комплетни и решите се marks.bzr и marks.git фајлова.

Синхронизација стејџа

Колико год грана да сте имали и који год метод за увоз употребили, ваш стејџ се не синхронизује са HEAD, а увозом неколико грана се чак ни ваш радни директоријум не синхронизује. Ситуација се једноставно решава следећом командом:

$ git reset --hard HEAD

Игнорисање фајлова који су игнорисани са .bzrignore

Хајде сада да погледамо како се игноришу фајлови. Прва ствар коју треба да урадите је да преименујете .bzrignore у .gitignore. Ако .bzrignore фајл садржи једну или неколико линија које почињу са „!!” или „RE:”, мораћете да измените и можда креирате и неколико .gitignore фајлова како би се игнорисали потпуно исти фајлови које је игнорисао и програм Базаар.

Коначно, мораћете да креирате комит који садржи ову измену за миграцију:

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

Слање вашег репозиторијума на сервер

Ево нас! Сада репозиторијум можете да гурнете на његов нови сервер:

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

Ваш Гит репозиторијум је спреман за употребу.

Перфорс

Наредни систем за који ћете видети процедуру увоза је Перфорс. Као што смо разматрали изнад, постоји два начина да Гит и Перфорс комуницирају међусобно: git-p4 и Perforce Git Fusion.

Perforce Git Fusion

”Git Fusion” чини овај процес прилично безболним. Једноставно конфигуришете поставке вашег пројекта, мапирања корисника и гране користећи конфигурациони фајл (као што је разматрано у Git Fusion), и клонирате репозиторијум. Git Fusion вам оставља оно што изгледа као природни Гит репозиторијум, који затим можете да гурнете на природни Гит хост ако желите. Могли бисте чак да користите и Перфорс као свој Гит гост ако то желите.

Git-p4

Git-p4 такође може да се понаша као алат за увоз. Као пример, извршићемо увоз Jam пројекта из Перфорс јавног депоа. Да бисте подесили свој клијент, прво морате да извезете променљиву окружења P4PORT тако да показује на Перфорс депо:

$ export P4PORT=public.perforce.com:1666
Белешка

Да бисте могли пратити пример, потребан вам је Перфорс депо на који можете да се повежете. У нашим примерима ћемо користити јавни депо на адреси public.perforce.com, али можете да користите било који депо на које имате приступ.

Извршите команду git p4 clone да увезете Jam пројекат са Перфорс сервера, наводећи депо и путању пројекта, као и путању у коју желите да увезете пројекат:

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

Овај пројекат има само једну грану, али ако имате гране конфигурисане да погледима на гране (или само скуп директоријума), можете да употребите заставицу --detect-branches уз команду git p4 clone да такође увезете и све гране пројекта. За мало више детаља у вези овога, погледајте Гранање.

У овом тренутку сте скоро готови. Ако одете у p4import директоријум и извршите git log, видећете ваш увезени рад:

$ 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 оставила идентификатор у свакој комит поруци. Нема проблема да се тај идентификатор тамо задржи, у случају да вам је касније потребна референца на Перфорс број измене. Међутим, ако желите да уклоните идентификатор, сада је право време за то – пре него што почнете рад на репозиторијуму. За групно уклањање идентификатора можете употребити команду git filter-branch:

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

Ако извршите git log видећете да се се измениле све SHA-1 контролне суме комитова, али да се git-p4 стрингови више не налазе у комит порукама:

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

Ваш увоз је спреман да се гурне на нови Гит сервер.

Прилагодљиви увозник

Ако ваш систем није ниједан од горе наведених, требало би да на мрежи потражите алат за увоз – доступни су квалитетни алати за увоз из многих других система, укључујући CVS, Clear Case, Visual Source Safe, чак и директоријум архива. Ако ниједан од њих не ради у вашем случају, имате прилично непознат алат, или вам је потребан још више прилагођени процес увоза, требало би да искористите git fast-import. Ова команда чита једноставне инструкције са stdin за уписивање одређених Гит података. На овај начин је много једноставније креирати Гит објекте него да извршавате сирове Гит команде, или да покушате уписивање сирових објеката (за више информација, погледајте Гит изнутра). На овај начин можете написати скрипту за увоз која чита неопходне информације из система који увозите и пише јасне инструкције на stdout. Затим можете да покренете овај програм и спроведете његов излаз кроз git fast-import.

Да бисмо брзо показали, написаћете једноставан алат за увоз. Претпоставимо да радите у current, повремено правите резервну копију свог пројекта копирњањем директоријума у временски обележен back_YYYY_MM_DD директоријум који чува резерве и желите да то увезете у програм Гит. Структура ваших директоријума изгледа овако:

$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03
current

Да бисте увезли Гит директоријум, морате знати како програм Гит чува своје податке. Вероватно се сећате, Гит је у основи увезана листа комит објеката који показују на снимак садржаја. Све што треба да урадите је да команди fast-import кажете шта су снимци садржаја, који комит подаци указују на њих, и у ком редоследу се јављају. Ваша стратегија ће бити да пролазите кроз снимке један по један и да креирате комитове са садржајем сваког директоријум, повезујући сваки комит са претходним.

Као што смо урадили у Пример полисе коју спроводи програм Гит, написаћемо то у Рубију, јер у општем случају радимо на том језику и углавном може лако да се чита. Овај пример прилично лако можете да напишете на било ком језику који вам је близак – он само мора да испише одговарајуће информације на stdout. А ако извршавате на Виндоуз систему, то значи да посебно морате пазити да не уведете carriage returns карактере на крај редове – git fast-import стриктно жели само line feed (LF) карактере, а не carriage return line feed (CRLF) комбинацију коју користи Виндоуз.

За почетак, прећи ћете у циљни директоријум и идентификоваћете свако поддиректоријум, од којих је сваки снимак који желите да увезете као комит. Ући ћете у свако поддиректоријум и исписаћете команде које су неопходне да се извезе. Ваша основна главна петља изгледа овако:

last_mark = nil

# прођи кроз све директоријуме
Dir.chdir(ARGV[0]) do
  Dir.glob("*").each do |dir|
    next if File.file?(dir)

    # уђи у циљни директоријум
    Dir.chdir(dir) do
      last_mark = print_export(dir, last_mark)
    end
  end
end

Унутар сваког директоријума сте извршили функцију print_export, која узима манифест и маркер претходног снимка и враћа манифест и маркер тренутног; на тај начин можете исправно да их увежете. „Маркер” је термин команде fast-import за идентификатор који постављате сваком комиту; док креирате комитове, сваком додељујете маркер који употребљавате да до њега дођете од осталих комитова. Дакле, прва ствар коју треба да урадите у својој print_export методи је да из имена директоријума генеришете маркер:

mark = convert_dir_to_mark(dir)

Ово ћете урадити тако што ћете направити низ директоријума и употребити вредност индекса као маркер, јер маркер мора бити целобројна вредност. Ваша метода изгледа овако:

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

Сада када имате целобројну представу вашег комита, потребан вам је датум за метаподатке комита. Пошто је датум део имена директоријум, парсираћете га из њега. Следећа линија у вашем print_export фајлу је:

date = convert_dir_to_date(dir)

где је convert_dir_to_date дефинисана као:

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

Ово враћа целобројну вредност за датум сваког директоријума. Последњи део метаподатака који вам је потребан за сваки комит су подаци о комитеру, које једноставно фиксирате у глобалној променљивој:

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

Сада сте спремни да почнете испис комит података вашем алату за увоз. Почетна информација наводи дефинишете комит објекат и грану на којој се налази, иза чега следи маркер који сте генерисали, информације о комитеру и комит порука, па затим претходни комит, ако постоји. Кôд изгледа овако:

# 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

Временску зону фиксирате (-0700) јер је тако једноставно да се изведе. Ако увозите из неког другог система, временску зону морате да наведете као померај (у односу на зону у којој је ваш систем). Комит порука мора да се наведе у посебном формату:

data (size)\n(contents)

Формат се састоји из речи data, величине података који треба да се прочитају, прелома реда и коначно самих података. Пошто је касније потребно да исти формат употребите за навођење фајла са садржајем, креираћете помоћну методу, export_data:

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

Преостало је само да за сваки снимак наведете садржај. То је једноставно јер се сваки налази у посебном директоријуму – можете да га испишете deleteall командом након које следи садржај сваког фајла у директоријуму. Програм Гит онда на одговарајући начин бележи сваки снимак:

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

Напомена: пошто многи системи на своје ревизије гледају као на промене од једног на други комит, fast-import такође може да прими и команде уз сваки комит које наводе који фајлови су додати, уклоњени или измењени, као шта је нови садржај. Израчунали бисте разлике између снимака и доставили само те податке, али то је много компликованије – исто тако можете програму Гит да доставите све податке, па да њему препустите да одреди шта и како. Ако је тако погодније за ваше податке, проверите fast-import ман страницу у вези детаља о томе како да податке доставите на овај начин.

Формат за испис садржаја новог фајла или за навођење измењеног фајла са новим садржајем је као што следи:

M 644 inline путања/до/фајла
data (величина)
(садржај фајла)

Овде 644 представља режим (ако имате извршни фајл, морате то да откријете и да уместо овога наведете 755), а inline наводи да садржај следи непосредно након ове линије. Ваша inline_data метода изгледа на следећи начин:

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

Поново искоришћавате export_data методу коју сте дефинисали раније, јер је начин исти као онај на који сте навели податке комит поруке.

Последње што треба да урадите је да вратите текући маркер, тако да се може проследити у наредну итерацију:

return mark
Белешка

Ако користите Виндоуз биће вам потребан још један корак. Као што смо поменули раније, Виндоуз користи CRLF карактере као прелом реда, док команда git fast-import очекује само LF карактер. Да бисте решили овај проблем и усрећили команду git fast-import, потребно је да Рубију наложите да уместо CRLF користи LF:

$stdout.binmode

То је то. Ево како изгледа комплетна скрипта:

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

Ако извршите ову скрипту, добићете садржај који отприлике изгледа овако:

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

Да бисте покренули алат за увоз, проследите овај излаз команди git fast-import док се налазите у Гит директоријуму у који желите да увезете податке. Можете да креирате нови директоријум, па да у њему као први корак извршите git init, а затим покренете своју скрипту:

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

Као што можете видети, када се процес успешно заврши, враћа вам гомилу статистичких података о ономе што је урађено. У овом случају, увезли сте укупно 13 објеката за 4 комита у 1 грану. Сада можете да извршите git log и погледате своју нову историју:

$ 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

Ево финог чистог Гит репозиторијума. Важно је приметити да се ништа не одјављује – у почетку немате ниједан фајл у свом радном директоријуму. Да бисте их добили, своју грану најпре морате да ресетујете на место на којем се сада налази master:

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

Алатом fast-import можете да урадите још много тога – обрађујете различите режиме, бинарне податке, вишеструке гране и спајања, ознаке, индикаторе напретка процеса и још тога.Већи број примера компликованијих сценарија можете да погледате у contrib/fast-import директоријуму изворног кода програма Гит.