Skip to content

Latest commit

 

History

History
396 lines (333 loc) · 14.4 KB

File metadata and controls

396 lines (333 loc) · 14.4 KB

Git in Mercurial

Vesolje DVCS (porazdeljenega nadzora nad različicami) je večje od samega Gita. Dejansko obstaja veliko drugih sistemov na tem področju, vsak s svojim pristopom, kako pravilno izvajati porazdeljeni nadzor različic. Poleg Gita je najbolj priljubljen Mercurial, oba pa sta si v mnogih pogledih zelo podobna.

Dobra novica, če vam je vedenje odjemalca Gita ljubše, vendar delate na projektu, kjer je koda shranjena v sistemu Mercurial, je, da obstaja način uporabe Gita kot odjemalca za Mercurialov repozitorij. Ker Git na strežniku uporablja daljave, ni presenetljivo, da je ta mostovna povezava implementirana kot pomožni program za daljave. Projekt se imenuje git-remote-hg in najdete ga na spletnem naslovu https://github.com/felipec/git-remote-hg.

git-remote-hg

Najprej morate namestiti git-remote-hg. To v bistvu vključuje odlaganje njegove datoteke nekam v vašo pot, takole:

$ curl -o ~/bin/git-remote-hg \
  https://raw.githubusercontent.com/felipec/git-remote-hg/master/git-remote-hg
$ chmod +x ~/bin/git-remote-hg

… če je ~/bin v vaši $PATH. Git-remote-hg ima še eno odvisnost: knjižnico mercurial za Python. Če imate Python nameščen, je to zelo preprosto:

$ pip install mercurial

Če nimate nameščenega Pythona, obiščite https://www.python.org/ in ga najprej namestite.

Zadnja stvar, ki jo boste potrebovali, je odjemalec Mercurial. Če ga še niste namestili, obiščite https://www.mercurial-scm.org/ in ga namestite.

Zdaj ste pripravljeni za uporabo. Potrebujete samo repozitorij Mercurial, kamor lahko potiskate. Na srečo lahko vsak repozitorij Mercurial deluje na ta način, zato bomo uporabili repozitorij »hello world«, ki ga vsi uporabljajo za učenje Mercuriala:

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

Zdaj, ko imamo ustrezen repozitorij »strežniške strani«, lahko opravimo običajen potek dela. Kot boste videli, sta ta dva sistema dovolj podobna, da ni veliko trenja.

Kot vedno pri Gitu, najprej kloniramo:

$ 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

Opazili boste, da delo z Mercurialovim repozitorijem uporablja standardni ukaz git clone. To je zato, ker git-remote-hg deluje na precej nizki ravni in uporablja podoben mehanizem, kot je implementacija Gitovega protokola HTTP/S (oddaljeni pomočniki). Ker sta Git in Mercurial zasnovana tako, da ima vsak odjemalec polno kopijo zgodovine repozitorija, ta ukaz naredi celotno kopijo, vključno z vso zgodovino projekta, in to relativno hitro.

Ukaz log prikaže dve spremembi, najnovejša od teh je označena z velikim številom referenc. Izkazalo se je, da nekatere od teh referenc dejansko ne obstajajo. Poglejmo, kaj je dejansko v direktoriju .git:

$ 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 skuša stvari narediti bolj v slogu, ki je bolj podoben Gitu, toda v ozadju upravlja osnovno preslikavo med dvema nekoliko drugačnima sistemoma. Mapiranje med oddaljenimi referencami dejansko poteka v mapi refs/hg. Na primer, datoteka z referenco Git refs/hg/origin/branches/default vsebuje SHA-1, ki se začne z »ac7955c«, to pa je tista potrditev, na katero kaže master. Tako je mapa refs/hg nekako lažna različica refs/remotes/origin, vendar ima dodatno razlikovanje med zaznamki in vejami.

Datoteka notes/hg je izhodišče za preslikavo med Gitovimi zgoščenimi vrednostmi potrditev in ID-ji sprememb Mercuriala, ki jih uporablja git-remote-hg. Poglejmo si to nekoliko podrobneje:

$ 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

Torej refs/notes/hg kaže na drevo, ki je v Gitovi objektni bazi podatkov seznam drugih objektov z imeni. git ls-tree izpiše način, vrsto, zgoščeno vrednost objekta in ime datoteke za elemente znotraj drevesa. Ko se potopimo v enega od elementov drevesa, odkrijemo, da je znotraj njega objekt z imenom ac9117f (zgoščena vrednost SHA-1 potrditve, na katero kaže master), z vsebino 0a04b98 (to je ID nabora sprememb Mercurial na vrhu veje default).

Dobra novica je, da se nam s tem večinoma ni treba ukvarjati. Tipičen potek dela ne bo preveč drugačen od dela z oddaljenim repozitorijem Git.

Preden nadaljujemo, moramo rešiti še eno stvar: ignoriranje datotek. Mercurial in Git uporabljata za to zelo podoben mehanizem, vendar verjetno ne želite dejansko shraniti datoteke .gitignore v repozitorij Mercurial. Na srečo ima Git način za ignoriranje datotek, ki je lokalno za posamezen diskovni repozitorij, in format Mercuriala je združljiv z Gitom, zato ga le prekopirajte:

$ cp .hgignore .git/info/exclude

Datoteka .git/info/exclude se obnaša enako kot .gitignore, vendar v potrditvah ni vključena.

Potek dela

Naj predpostavimo, da smo opravili nekaj dela in naredili nekaj potrditev na veji master ter ste pripravljeni, da jih pošljete na oddaljeni repozitorij. Tako je videti naš repozitorij trenutno:

$ 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

Naša veja master je dva predhodnika pred origin/master, toda ti dve potrditvi obstajata le na našem lokalnem računalniku. Poglejmo, ali je kdo drug v istem času opravljal kakšno pomembno delo:

$ 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

Ker smo uporabili zastavico --all, vidimo tudi reference »notes«, ki jih uporablja git-remote-hg, vendar jih lahko ignoriramo. Preostalo je tako, kot smo pričakovali; origin/master se je premaknil za eno potrditev in naša zgodovina se je zdaj razcepila. V primerjavi z drugimi sistemi, s katerimi delamo v tem poglavju, lahko Mercurial upravlja združevanja, zato ne bomo počeli ničesar zapletenega.

$ 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

Odlično. Zaženemo teste in vse poteka brez napak, zato smo pripravljeni deliti svoje delo z ostalimi člani ekipe:

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

To je vse! Če si ogledamo repozitorij Mercurial, vidimo, da je ta ukaz storil, kar smo pričakovali:

$ 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

Spremenitve z oznako 2 so bile narejene z Mercurialom, spremembe z oznakami 3 in 4 pa so bile narejene z git-remote-hg, s pomočjo potiskanja potrditev, narejenih z Gitom.

Veje in zaznamki

Git ima samo eno vrsto veje: referenco, ki se premika, ko so narejene potrditve. V Mercurialu se ta vrsta reference imenuje »zaznamek« (angl. bookmark) in se obnaša podobno kot Gitova veja.

Mercurialova zasnova »veje« je bolj obremenjujoča. Veja, na kateri je bil narejen nabor sprememb, je zabeležena z naborom sprememb, kar pomeni, da bo vedno v zgodovini repozitorija. Tu je primer za potrditev, ki je bila izvedena na veji develop:

$ hg log -l 1
changeset:   6:8f65e5e02793
branch:      develop
tag:         tip
user:        Ben Straub <[email protected]>
date:        Thu Aug 14 20:06:38 2014 -0700
summary:     More documentation

Poglejte vrstico, ki se začne z »branch«. Git tega ne more dejansko ponoviti (in tudi ne potrebuje; oba tipa vej lahko predstavimo kot Git ref), vendar mora git-remote-hg razumeti razliko, saj Mercurial skrbi za to.

Ustvarjanje zaznamkov Mercurial je enostavno, kot ustvarjanje vej Git. Na strani Git:

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

To je vse, kar spada sem. Na strani Mercurial je videti takole:

$ 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

Opazite novo oznako [featureA] v reviziji 5. Te se obnašajo enako kot veje Git na strani Git, do ene izjeme: iz Gitove strani ne morete izbrisati zaznamka (to je omejitev oddaljenih pomočnikov).

Prav tako lahko delate na »težkih« vejah Mercurial: preprosto postavite vejo v imenski prostor branches:

$ 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

Takole bo videti stran Mercurial:

$ 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 <[email protected]>
|  date:        Thu Aug 14 20:21:09 2014 -0700
|  summary:     A permanent change
|
| @  changeset:   6:8f65e5e02793
|/   branch:      develop
|    user:        Ben Straub <[email protected]>
|    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 <[email protected]>
| |  date:        Thu Aug 14 20:02:21 2014 -0700
| |  summary:     Merge remote-tracking branch 'origin/master'
[...]

Ime veje »permanent« je bilo zabeleženo z označenim naborom sprememb 7.

S stališča Gita je delo z enim od teh načinov vej enako: preprosto izvlečete, potrdite, pridobite, združite, povlečete in potisnite, kot bi sicer storili. Ena stvar, ki jo morate vedeti, je, da Mercurial ne podpira ponovnega pisanja zgodovine, ampak samo dodajanje k njej. Tako je videti naš repozitorij Mercurial po interaktivnem ponovnem baziranju in prisilnem potiskanju:

$ 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

Nabori sprememb 8, 9 in 10 so bili ustvarjeni in spadajo v vejo permanent, vendar so stari nabori sprememb še vedno tam. To lahko zelo zmede vaše sodelavce, ki uporabljajo Mercurial, zato se temu poskusite izogniti.

Povzetek Mercurial

Git in Mercurial sta dovolj podobna, da je delo prek meje precej neboleče. Če se izogibate spreminjanju zgodovine, ki je že zapustila vaš računalnik (kar je običajno priporočljivo), morda sploh ne boste vedeli, da je drugi konec Mercurial.