Ако ваш систем није ниједан од горе наведених, требало би да на мрежи потражите алат за увоз – доступни су квалитетни алати за увоз из многих других система, укључујући CVS, Clear Case, Visual Source Safe, чак и директоријум архива.
Ако ниједан од њих не ради у вашем случају, имате прилично непознат алат, или вам је потребан још више прилагођени процес увоза, требало би да искористите git fast-import.
Ова команда чита једноставне инструкције са stdin за уписивање одређених Гит података.
На овај начин је много једноставније креирати Гит објекте него да извршавате сирове Гит команде, или да покушате уписивање сирових објеката (за више информација, погледајте ch10-git-internals.asc).
На овај начин можете написати скрипту за увоз која чита неопходне информације из система који увозите и пише јасне инструкције на 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 кажете шта су снимци садржаја, који комит подаци указују на њих, и у ком редоследу се јављају.
Ваша стратегија ће бити да пролазите кроз снимке један по један и да креирате комитове са садржајем сваког директоријум, повезујући сваки комит са претходним.
Као што смо урадили у ch08-customizing-git.asc, написаћемо то у Рубију, јер у општем случају радимо на том језику и углавном може лако да се чита.
Овај пример прилично лако можете да напишете на било ком језику који вам је близак – он само мора да испише одговарајуће информације на 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|
Note
|
Ако користите Виндоуз биће вам потребан још један корак.
Као што смо поменули раније, Виндоуз користи CRLF карактере као прелом реда, док команда $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 директоријуму изворног кода програма Гит.