Če vaš sistem ni eden od zgoraj omenjenih, poiščite uvoznika na spletu — kakovostni uvozniki so na voljo za mnoge druge sisteme, vključno s CVS, Clear Case, Visual Source Safe in celo imenikom arhivov.
Če nobeno od teh orodij ne deluje za vas, ali imate bolj zapleteno orodje, ali pa potrebujete drugačen postopek uvoza, uporabite git fast-import.
Ta ukaz preprosto prebere navodila iz standardnega vhoda za pisanje določenih podatkov Git.
Na ta način je veliko lažje ustvariti objekte Git kot z uporabo surovih ukazov Git ali poskusom pisanja surovih objektov (za več informacij glejte poglavje ch10-git-internals.asc).
Na ta način lahko napišete uvozni skript, ki iz sistema, iz katerega uvažate, bere potrebne informacije in izpiše preprosta navodila na standardni izhod.
Nato lahko to program poženete in njegov izhod preusmerite skozi git fast-import.
Za hitro demonstracijo boste napisali preprost program za uvažanje.
Predpostavimo, da delate v mapi current, svoj projekt pa varnostno kopirate tako, da občasno kopirate mapo v varnostno kopijo back_YYYY_MM_DD z oznako datuma, in to želite uvoziti v Git.
Vaša mapa je videti takole:
$ ls /opt/import_from
back_2014_01_02
back_2014_01_04
back_2014_01_14
back_2014_02_03
currentČe želite uvoziti Gitov direktorij, morate pregledati, kako Git shranjuje svoje podatke.
Kot se morda spomnite, je Git v osnovi povezan seznam objektov potrditev, ki kažejo na posnetek vsebine.
Vse, kar morate storiti, je povedati fast-import, kaj so posnetki vsebine, na kaj kažejo podatki potrditve in v kakšnem vrstnem redu gredo.
Vaša strategija bo, da boste posamezne posnetke poiskali po vrstnem redu in za vsako mapo ustvarili potrditev z vsebino te mape, pri tem pa vsako potrditev povezali s prejšnjo.
Kot smo storili v ch08-customizing-git.asc, bomo to napisali v Rubyju, ker gre za jezik, s katerim se običajno ukvarjamo, in ker je običajno enostaven za branje.
Ta primer lahko precej enostavno napišete v katerem koli drugem jeziku, ki ga poznate — le ustrezne podatke morate izpisati v stdout.
Če delate v sistemu Windows, bodite pozorni, da ne vnesete vsebnosti pomika na konec vrstice — git fast-import zelo natančno zahteva samo vrstice (LF), ne pa vsebnosti pomika s karetom (CRLF), ki jih uporablja Windows.
Najprej se boste premaknili v ciljni imenik in identificirali vsak podimenik, ki predstavlja posnetek, ki ga želite uvoziti kot potrditev. Za vsak podimenik se boste premaknili vanj in natisnili ukaze, ki so potrebni za izvoz. Osnovna zanka je videti tako:
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
endV vaši metodi print_export v vsaki mapi zaženete funkcijo, ki vzame manifest in označbo (angl. mark) prejšnje različice posnetka in vrne manifest in označbo za trenutno različico; tako jih lahko pravilno povežete.
»Označba« je izraz v fast-import, ki se nanaša na identifikator, ki ga daste potrditvi; vsakič, ko ustvarite potrditev, ji dodelite označbo, ki jo lahko uporabite za povezavo z drugimi potrditvami.
Torej, prva stvar, ki jo morate storiti v vaši metodi print_export, je generirati označbo iz imena mape:
mark = convert_dir_to_mark(dir)To boste naredili z ustvarjanjem polja direktorijev in uporabili vrednost indeksa kot označbo, saj mora biti označba celo število. Vaša metoda je videti takole:
$marks = []
def convert_dir_to_mark(dir)
if !$marks.include?(dir)
$marks << dir
end
($marks.index(dir) + 1).to_s
endZdaj, ko imate celoštevilsko predstavitev svoje potrditve, potrebujete datum za metapodatke potrditve.
Ker je datum izražen v imenu mape, ga boste razčlenili.
Naslednja vrstica v vaši datoteki print_export je:
date = convert_dir_to_date(dir)kjer je convert_dir_to_date definiran kot:
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
endTo vrne celoštevilsko vrednost za podatke v vsakem direktoriju. Zadnji del metapodatkov, ki ga potrebujete za vsako potrditev, so podatki potrjevalca, ki ga vgradite v kodo preko globalne spremenljivke:
$author = 'John Doe <john@example.com>'Zdaj ste pripravljeni za začetek izpisa podatkov o potrditvi za svoj program uvažanja. Začetni podatki navajajo, da opredeljujete objekt potrditve in na kateri veji je, nato sledi oznaka, ki ste jo generirali, podatki o potrditelju in sporočilu potrditve, nato pa še prejšnja potrditev, če obstaja. Koda je videti tako:
# 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Časovni pas zacementirate v kodo (-0700), ker je to enostavno. Če uvažate iz drugega sistema, morate časovni pas določiti kot odmik. Sporočilo potrditve mora biti izraženo v posebnem formatu:
data (size)\n(contents)Format sestoji iz podatka besede, velikosti podatkov, ki jih je treba prebrati, nove vrstice in nazadnje samih podatkov.
Ker morate kasneje uporabiti isti format za določanje vsebine datoteke, ustvarite pomožno metodo export_data:
def export_data(string)
print "data #{string.size}\n#{string}"
endVse, kar je še ostalo, je določiti vsebino datoteke za vsak posnetek.
To je enostavno, saj imate vsak posnetek v mapi — lahko natisnete ukaz deleteall, nato pa vsebino vsake datoteke v mapi.
Git bo nato ustrezno zabeležil vsak posnetek:
puts 'deleteall'
Dir.glob("**/*").each do |file|
next if !File.file?(file)
inline_data(file)
endOpomba: Ker se mnogi sistemi nanašajo na svoje revizije kot spremembe med eno potrditvijo in drugo, lahko hitri uvoz vzame tudi ukaze z vsako potrditvijo, ki določajo, katere datoteke so bile dodane, odstranjene ali spremenjene ter kakšne so nove vsebine.
Lahko bi izračunali razlike med posnetki in zagotovili samo te podatke, vendar je to bolj zapleteno — raje dajte Gitu vse podatke in ga pustite, da sam ugotovi.
Če je to bolj primerno za vaše podatke, preverite stran priročnika fast-import za podrobnosti o tem, kako zagotoviti svoje podatke na ta način.
Format za naštevanje novih vsebin datotek ali določanje spremenjene datoteke z novimi vsebinami je naslednji:
M 644 inline path/to/file
data (size)
(file contents)Tukaj je način 644 (če imate izvršljive datoteke, morate zaznati in določiti namesto tega 755), in znotraj vrstice pove, da boste takoj po tej vrstici našteli vsebine.
Vaša metoda inline_data je videti tako:
def inline_data(file, code = 'M', mode = '644')
content = File.read(file)
puts "#{code} #{mode} inline #{file}"
export_data(content)
endPonovno uporabljate metodo export_data, ki ste jo prej definirali, ker je enaka načinu, kako ste določili podatke za sporočilo o potrditvi.
Zadnja stvar, ki jo morate storiti, je vrniti trenutno označbo, da jo lahko prenesete v naslednjo ponovitev:
return mark|
Note
|
Če delujete v sistemu Windows, morate poskrbeti za dodaten korak.
Kot je bilo že omenjeno, sistem Windows uporablja znake CRLF za nove vrstice, medtem ko $stdout.binmode |
To je vse. Tu je skript v svoji celoti:
#!/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Če poženete ta skript, boste dobili vsebino, ki je videti nekako takole:
$ 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
(...)Za zagon uvoznika morate izhodno datoteko preusmeriti v git fast-import, medtem ko ste v mapi Git, kamor želite uvoziti podatke.
Lahko ustvarite novo mapo in nato v njej začnete z git init, nato pa zaženete svoj skript:
$ 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
---------------------------------------------------------------------Kot vidite, vam po uspešnem zaključku poda cel kup statističnih podatkov o doseženem napredku.
V tem primeru ste skupaj uvozili 13 objektov za 4 potrditve v 1 vejo.
Sedaj lahko za ogled nove zgodovine zaženete 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_03In to je to — lep in čist repozitorij Git.
Pomembno je opozoriti, da nič ni izvlečeno — na začetku nimate nobene datoteke v svoji delovni mapi.
Da bi jih dobili, morate ponastaviti svojo vejo na trenutno stanje veje master:
$ ls
$ git reset --hard master
HEAD is now at 3caa046 imported from current
$ ls
README.md main.rbZ orodjem fast-import lahko storite veliko več — obvladovanje različnih načinov, binarnih podatkov, več vej in združevanje, oznak, kazalnikov napredka in še več.
V mapi contrib/fast-import izvorne kode Git je na voljo več primerov bolj zapletenih scenarijev.