Skip to content

Latest commit

 

History

History
398 lines (333 loc) · 21.7 KB

client-hg.asc

File metadata and controls

398 lines (333 loc) · 21.7 KB

Git και Mercurial

Το σύμπαν των DVCS είναι μεγαλύτερο από το Git. Στην πραγματικότητα, υπάρχουν πολλά άλλα συστήματα σε αυτό το σύμπαν, το καθένα με τη δική του οπτική για το πώς γίνεται σωστά ο κατανεμημένος έλεγχος εκδόσεων. Πέρα από το Git, το πιο δημοφιλές είναι το Mercurial, και μάλιστα και δύο συστήματα είναι πολύ παρόμοια από πολλές απόψεις.

Τα καλά νέα, εφόσον προτιμάμε τη συμπεριφορά από την πλευρά του πελάτη του Git αλλά εργαζόμαστε με ένα έργο του οποίου ο πηγαίος κώδικας ελέγχεται με το Mercurial, είναι ότι υπάρχει ένας τρόπος να χρησιμοποιήσουμε το Git ως πελάτη για ένα αποθετήριο που φιλοξενείται από Mercurial. Δεδομένου ότι ο τρόπος με τον οποίο το Git μιλάει με αποθετήρια διακομιστών μέσω απομακρυσμένων, δεν πρέπει να αποτελεί έκπληξη ότι αυτή η γέφυρα έχει υλοποιηθεί ως απομακρυσμένος βοηθός. Το όνομα του έργου είναι git-remote-hg και μπορεί να βρεθεί στη https://github.com/felipec/git-remote-hg.

git-remote-hg

Πρώτα, πρέπει να εγκαταστήσουμε το git-remote-hg. Αυτό ουσιαστικά γίνεται αν απλά αντιγράψουμε το αρχείο κάπου στη διαδρομή μας, όπως παρακάτω:

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

… με την προϋπόθεση ότι ο ~/bin είναι στο $PATH μας. η git-remote-hg έχει άλλη μία εξάρτηση: τη βιβλιοθήκη Python του Mercurial. Αν έχουμε εγκατεστημένη την Python, αυτό γίνεται πανεύκολα:

$ pip install mercurial

(Εάν δεν έχουμε εγκαταστήσει την Python, επισκεφτόμαστε τη διεύθυνση https://www.python.org/ για να την κατεβάσουμε και να την εγκαταστήσουμε.)

Το τελευταίο πράγμα που θα χρειαστούμε είναι ο πελάτης του Mercurial. Μεταβαίνουμε στη διεύθυνση http://mercurial.selenic.com/ και τον εγκαταθιστούμε αν δεν το έχουμε ήδη κάνει.

Τώρα είμαστε έτοιμοι να παίξουμε μπάλα. Το μόνο που χρειαζόμαστε είναι ένα αποθετήριο Mercurial στο οποίο να έχουμε δικαίωμα ώθησης. Ευτυχώς, κάθε αποθετήριο Mercurial μπορεί να ενεργήσει με αυτόν τον τρόπο, οπότε θα χρησιμοποιήσουμε μόνο το αποθετήριο hello world που χρησιμοποιούν όλοι για να μάθουν το Mercurial:

$ hg clone http://selenic.com/repo/hello /tmp/hello
Ξεκινώντας

Τώρα που έχουμε έναν κατάλληλο αποθετήριο ``από την πλευρά του διακομιστή'', μπορούμε να εξετάσουμε μια τυπική ροή εργασίας. Όπως θα δούμε, αυτά τα δύο συστήματα είναι αρκετά παρόμοια, συνεπώς δεν υπάρχουν πολλές προστριβές.

Όπως πάντα στο Git, αρχικά κλωνοποιούμε:

$ 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

Παρατηρούμε ότι η εργασία με ένα αποθετήριο Mercurial χρησιμοποιεί την τυπική εντολή git clone. Αυτό συμβαίνει επειδή το git-remote-hg λειτουργεί σε αρκετά χαμηλό επίπεδο, χρησιμοποιώντας έναν παρόμοιο μηχανισμό με αυτόν που είναι υλοποιημένο το πρωτόκολλο HTTP/S του Git (με απομακρυσμένους βοηθούς). Δεδομένου ότι τα Git και Mercurial έχουν σχεδιαστεί και τα δύο ώστε κάθε πελάτης να έχει ένα πλήρες αντίγραφο του ιστορικού του αποθετηρίου, αυτή η εντολή δημιουργεί έναν πλήρη κλώνο, συμπεριλαμβανομένου ολόκληρου του ιστορικού του έργου και μάλιστα το κάνει αρκετά γρήγορα.

Η εντολή log δείχνει δύο υποβολές, με την πιο πρόσφατη να δείχνεται από πληθώρα αναφορών. Αποδεικνύεται ότι κάποιες από αυτές δεν είναι πραγματικά εκεί. Ας ρίξουμε μια ματιά στο τι υπάρχει πραγματικά στον κατάλογο .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-h`g προσπαθεί να κάνει το ιδίωμα πιο Git-οειδές, αλλά εσωτερικά διαχειρίζεται την εννοιολογική απεικόνιση μεταξύ δύο ελαφρώς διαφορετικών συστημάτων. Ο κατάλογος `refs/hg είναι εκεί όπου αποθηκεύονται οι πραγματικές απομακρυσμένες αναφορές. Για παράδειγμα, το αρχείο refs/hg/origin/branches/default είναι ένα αρχείο ref του Git που περιέχει τον SHA-1 που αρχίζει με το ac7955c. Έτσι, ο κατάλογος refs/hg είναι σαν ένα ψεύτικο refs/remotes/origin, αλλά έχει την πρόσθετη διάκριση μεταξύ σελιδοδεικτών και κλάδων.

Το αρχείο notes/hg είναι το σημείο εκκίνησης για τον τρόπο με τον οποίο το git-remote-hg απεικονίζει τους αριθμούς SHA-1 των υποβολών Git σε ID συνόλων αλλαγών του Mercurial. Ας το εξερευνήσουμε αυτό λίγο:

$ 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

Επομένως, το refs/notes/hg δείχνει σε ένα δέντρο, το οποίο στη βάση δεδομένων αντικειμένων του Git είναι μια λίστα άλλων αντικειμένων με ονόματα. Το git ls-tree εξάγει τα δικαιώματα πρόσβασης, τον τύπο, το hash αντικειμένου και το όνομα αρχείου για τα στοιχεία μέσα σε ένα δέντρο. Μόλις σκάψουμε σε ένα από τα στοιχεία του δέντρου, διαπιστώνουμε ότι μέσα του υπάρχει ένα blob που ονομάζεται ac9117f (ο αριθμός SHA-1 της υποβολής στην οποία δείχνει ο 'master`), με τα περιεχόμενα 0a04b98 (που είναι το αναγνωριστικό του συνόλου αλλαγών του Mercurial στην κορυφή του κλάδου default.

Τα καλά νέα είναι ότι δεν χρειάζεται να ανησυχούμε για όλα αυτά. Η τυπική ροή εργασίας δεν θα είναι πολύ διαφορετική από αυτήν με ένα απομακρυσμένο αποθετήριο Git.

Υπάρχει ένα ακόμα πράγμα που πρέπει να εξετάσουμε πριν συνεχίσουμε: τα αγνοεί. Το Mercurial και το Git χρησιμοποιούν έναν πολύ παρόμοιο μηχανισμό για αυτό, αλλά είναι πιθανό ότι δεν θέλουμε πραγματικά να υποβάλουμε ένα αρχείο .gitignore σε ένα αποθετήριο Mercurial. Ευτυχώς, το Git έχει έναν τρόπο να αγνοήσει αρχεία που είναι τοπικά σε ένα αποθετήριο στον δίσκο μας και η μορφή του Mercurial είναι συμβατή με το Git, οπότε απλά πρέπει να το αντιγράψουμε:

$ cp .hgignore .git/info/exclude

Το αρχείο .git/info/exclude λειτουργεί ακριβώς όπως το .gitignore, αλλά δεν περιλαμβάνεται στις υποβολές.

Ροή εργασίας

Ας υποθέσουμε ότι έχουμε κάνει κάποια εργασία και κάποιες υποβολές στον κλάδο master και είμαστε έτοιμοι να τις ωθήσουμε στο απομακρυσμένο αποθετήριο. Εδώ φαίνεται το αποθετήριό μας:

$ 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

Ο κλάδος master προηγείται κατά δύο υποβολές του origin/master, αλλά αυτές οι δύο υποβολές υπάρχουν μόνο στο τοπικό μας μηχάνημα. Ας δούμε αν κάποιος άλλος έχει κάνει σημαντικό έργο την ίδια στιγμή:

$ 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

Εφόσον χρησιμοποιήσαμε τη σημαία --all, βλέπουμε τις αναφορές `notes'' που χρησιμοποιούνται εσωτερικά από το `git-remote-hg, αλλά μπορούμε να τις αγνοήσουμε. Τα υπόλοιπα είναι όπως τα αναμέναμε· ο origin/master έχει προχωρήσει κατά μία υποβολή και το ιστορικό μας έχει αποκλίνει τώρα. Σε αντίθεση με τα άλλα συστήματα με τα οποία εργαζόμαστε σε αυτό το κεφάλαιο, το Mercurial είναι ικανό να χειριστεί τις συγχωνεύσεις, οπότε δεν πρόκειται να κάνουμε τίποτα φανταχτερό.

$ 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

Τέλεια. Εκτελούμε τις δοκιμές και όλα πετυχαίνουν, οπότε είμαστε έτοιμοι να μοιραστούμε το έργο μας με την υπόλοιπη ομάδα:

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

Αυτό ήταν! Εάν ρίξουμε μια ματιά στο αποθετήριο Mercurial, θα δούμε ότι έκανε αυτό που αναμέναμε:

$ 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

Το σύνολο των αλλαγών 2 έγινε από το Mercurial και τα σύνολα αλλαγών 3 και 4 έγιναν από το git-remote-hg, με ώθηση των υποβολών που έγιναν με το Git.

Κλάδοι και σελιδοδείκτες

Το Git έχει μόνο ένα είδος κλάδου: μια αναφορά που μετακινείται όταν γίνονται υποβολές. Στο Mercurial, αυτό το είδος μίας αναφοράς ονομάζεται ``σελιδοδείκτης'' και συμπεριφέρεται με τον ίδιο τρόπο όπως ένας κλάδος Git.

Η αντίληψη του Mercurial περί `κλάδου'' είναι πιο βαριά. Ο κλάδος στο οποίο πραγματοποιείται ένα σύνολο αλλαγών καταγράφεται με το σύνολο αλλαγών (changeset), που σημαίνει ότι θα βρίσκεται πάντα στο ιστορικό του αποθετηρίου. Ακολουθεί ένα παράδειγμα υποβολής που έγινε στον κλάδο `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

Παρατηρούμε τη γραμμή που αρχίζει με branch. Το Git δεν μπορεί να αναπαράγει αυτό το πράγμα (και ούτε χρειάζεται, αφού και οι δύο τύποι κλάδων μπορούν να αναπαρασταθούν ως ref του Git), αλλά το git-remote-hg πρέπει να κατανοήσει τη διαφορά, επειδή το Mercurial πρέπει να ξέρει.

Η δημιουργία των σελιδοδεικτών στο Mercurial είναι τόσο εύκολη όσο και η δημιουργία κλάδων στο Git. Από την πλευρά του Git:

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

Αυτό ήταν όλο. Από την πλευρά του Mercurial, μοιάζει με αυτό:

$ 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

Παρατηρούμε τη νέα ετικέτα [featureA] στην αναθεώρηση 5. Αυτά λειτουργούν ακριβώς όπως οι κλάδοι Git στην πλευρά του Git, με μια εξαίρεση: δεν μπορούμε να διαγράψουμε έναν σελιδοδείκτη από την πλευρά του Git (αυτός είναι ένας περιορισμός των απομακρυσμένων βοηθών).

Επίσης μπορούμε να εργαστούμε σε έναν κλάδο `βαρέων βαρών'' του Mercurial: απλά βάζουμε έναν κλάδο στον ονοματοχώρο `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

Ακολουθεί το πώς μοιάζει από την πλευρά του 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'
[...]

Το όνομα κλάδου permanent καταγράφηκε με το σύνολο αλλαγών 7.

Από την πλευρά του Git, η συνεργασία με οποιοδήποτε από αυτά τα στυλ κλάδου είναι ίδια: απλώς ελέγχουμε, διεκπεραιώνουμε, ανακτούμε, συγχωνεύουμε, έλκουμε και ωθούμε όπως θα κάναμε κανονικά. Ένα πράγμα που πρέπει να ξέρουμε είναι ότι το Mercurial δεν υποστηρίζει την επανεγγραφή ιστορικού και μόνο προσθέτει σε αυτό. Ακολουθεί η εμφάνιση του αποθετηρίου μας Mercurial μετά από μια διαδραστική αλλαγή βάσης και μια εξαναγκασμένη ώθηση:

$ 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

Οι αλλαγές 8, 9 και 10 έχουν δημιουργηθεί και ανήκουν στον κλάδο permanent, αλλά τα παλιά σύνολα αλλαγών είναι ακόμα εκεί. Αυτό μπορεί να επιφέρει πολλή σύγχυση στους συνεργάτες μας που χρησιμοποιούν Mercurial, οπότε προσπαθούμε να το αποφύγουμε.

Ανακεφαλαίωση Mercurial

Τα Git και Mercurial είναι αρκετά παρόμοια ώστε η συνεργασία μεταξύ τους είναι αρκετά ανώδυνη. Εάν αποφύγουμε να αλλάξουμε το ιστορικό που έχει αφήσει το μηχάνημά μας (όπως συνήθως συνιστάται), ίσως να μην γνωρίζουμε καν ότι το άλλο άκρο είναι Mercurial.