Git
Chapters ▾ 2nd Edition

7.12 Εργαλεία του Git - Δεμάτιασμα δεδομένων

Δεμάτιασμα δεδομένων

Αν και καλύψαμε τους συνήθεις τρόπους μεταφοράς των δεδομένων του Git μέσω δικτύου (HTTP, SSH κ.λπ.), υπάρχει πράγματι ένας ακόμη τρόπος να το κάνουμε αυτό που δεν χρησιμοποιείται συνήθως, αλλά μπορεί να είναι πραγματικά πολύ χρήσιμος.

Το Git είναι ικανό να “δεματιάζει” (bundle) τα δεδομένα του σε ένα μοναδικό αρχείο. Αυτό μπορεί να είναι χρήσιμο σε διάφορες περιστάσεις. Ίσως το δίκτυό μας να είναι πεσμένο και θέλουμε να στείλουμε αλλαγές στους συναδέλφους μας. Ίσως εργαζόμαστε κάπου εξ αποστάσεως και δεν έχουμε πρόσβαση στο τοπικό δίκτυο για λόγους ασφαλείας. Ίσως η κάρτα μας ασύρματου δικτύου / δικτύου ethernet μόλις χάλασε. Ίσως δεν έχουμε επί του παρόντος πρόσβαση σε έναν κοινόχρηστο διακομιστή, θέλουμε να στείλουμε διορθώσεις με e-mail σε κάποιον χρήστη και δεν θέλουμε να μεταφέρουμε 40 υποβολές μέσω της format-patch.

Σε αυτές τις περιστάσεις η εντολή git bundle μπορεί να είναι χρήσιμη. Η εντολή bundle πακετάρει όλα όσα θα έπρεπε κανονικά να ωθηθούν πάνω από το δίκτυο με την εντολή git push σε ένα δυαδικό αρχείο το οποίο μπορούμε να στείλουμε με email σε κάποιον ή να τοποθετήσουμε μια flash drive και στη συνέχεια να ξεπακετάρουμε σε κάποιο άλλο αποθετήριο.

Ας δούμε ένα απλό παράδειγμα. Ας υποθέσουμε ότι έχουμε ένα αποθετήριο με δύο υποβολές:

$ git log
commit 9a466c572fe88b195efd356c3f2bbeccdb504102
Author: Scott Chacon <schacon@gmail.com>
Date:   Wed Mar 10 07:34:10 2010 -0800

    second commit

commit b1ec3248f39900d2a406049d762aa68e9641be25
Author: Scott Chacon <schacon@gmail.com>
Date:   Wed Mar 10 07:34:01 2010 -0800

    first commit

Εάν θέλουμε να στείλουμε αυτό το αποθετήριο σε κάποιον και δεν έχουμε πρόσβαση σε κάποιο άλλο αποθετήριο για να το ωθήσουμε ή απλά δεν θέλουμε να εγκαταστήσουμε ένα, μπορούμε να το δεματιάσουμε με την git bundle create.

$ git bundle create repo.bundle HEAD master
Counting objects: 6, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 441 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)

Τώρα έχουμε ένα αρχείο με όνομα repo.bundle που έχει όλα τα δεδομένα που απαιτούνται για να δημιουργηθεί εκ νέου ο κλάδος master του αποθετηρίου. Στην εντολή bundle πρέπει να παραθέσουμε κάθε αναφορά ή συγκεκριμένο εύρος υποβολών θέλουμε να συμπεριλάβουμε. Αν σκοπεύουμε να κλωνοποιηθεί κάπου αλλού, θα πρέπει να προσθέσουμε τον HEAD ως αναφορά, όπως κάναμε εδώ.

Μπορούμε να στείλουμε το αρχείο repo.bundle με e-mail σε κάποιον άλλο, ή να το τοποθετήσουμε σε μια μονάδα USB και να το δώσουμε.

Από την άλλη, ας πούμε ότι κάποιος μας έχει στείλει αυτό το αρχείο repo.bundle και θέλουμε να εργαστούμε στο έργο. Μπορούμε να κλωνοποιήσουμε από το δυαδικό αρχείο σε έναν κατάλογο, όπως θα κάναμε από μια διεύθυνση URL.

$ git clone repo.bundle repo
Initialized empty Git repository in /private/tmp/bundle/repo/.git/
$ cd repo
$ git log --oneline
9a466c5 second commit
b1ec324 first commit

Εάν δεν συμπεριλαμβάνουμε τον HEAD στις αναφορές, πρέπει επίσης να καθορίσουμε το -b master ή οποιονδήποτε κλάδο περιλαμβάνεται επειδή αλλιώς δεν θα ξέρει σε ποιον κλάδο να μεταβεί.

Τώρα ας υποθέσουμε ότι κάνουμε τρεις υποβολές σε αυτό και θέλουμε να στείλουμε τις νέες υποβολές πίσω σε ένα δεμάτι με ένα USB stick ή e-mail.

$ git log --oneline
71b84da last commit - second repo
c99cf5b fourth commit - second repo
7011d3d third commit - second repo
9a466c5 second commit
b1ec324 first commit

Πρώτα πρέπει να καθορίσουμε το εύρος υποβολών που θέλουμε να συμπεριλάβουμε στη δέσμη. Σε αντίθεση με τα πρωτόκολλα δικτύου που καθορίζουν το ελάχιστο σύνολο δεδομένων που θα μεταφερθούν μέσω του δικτύου για εμάς, θα πρέπει να το βρούμε αυτό μόνοι μας. Θα μπορούσαμε να κάνουμε το ίδιο πράγμα και να δεματιάσουμε ολόκληρο το αποθετήριο, και κάτι τέτοιο θα λειτουργήσει, αλλά είναι καλύτερα να δεματιάσουμε τη διαφορά —ακριβώς τις τρεις υποβολές που κάναμε τοπικά.

Για να γίνει αυτό, θα πρέπει να υπολογίσουμε τη διαφορά. Όπως περιγράψαμε στην ενότητα Εύρος υποβολών, μπορούμε να καθορίσουμε μια σειρά υποβολών με διάφορους τρόπους. Για να πάρουμε τις τρεις υποβολές που έχουμε στον κύριο κλάδο μας και που δεν ήταν στον κλάδο που αρχικά κλωνοποιήσαμε, μπορούμε να χρησιμοποιήσουμε κάτι σαν origin/master..master ή master ^origin/master. Ας το δοκιμάσουμε με την εντολή log.

$ git log --oneline master ^origin/master
71b84da last commit - second repo
c99cf5b fourth commit - second repo
7011d3d third commit - second repo

Τώρα, λοιπόν, που έχουμε τον κατάλογο των υποβολών που θέλουμε να συμπεριλάβουμε στο δεμάτι, ας τις δεματιάσουμε. Αυτό το κάνουμε με την εντολή git bundle create, στην οποία δίνουμε το όνομα αρχείου που θέλουμε να έχει το δεμάτι μας και το εύρος των υποβολών που θέλουμε να το κάνουμε.

$ git bundle create commits.bundle master ^9a466c5
Counting objects: 11, done.
Delta compression using up to 2 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (9/9), 775 bytes, done.
Total 9 (delta 0), reused 0 (delta 0)

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

Όταν παίρνει το δεμάτι, μπορεί να το επιθεωρήσει για να δει τι περιέχει πριν το εισάγει στο αποθετήριό της. Η πρώτη εντολή είναι η εντολή bundle verify που θα διασφαλίσει ότι το αρχείο είναι στην πραγματικότητα ένα έγκυρο δεμάτι Git και ότι έχουμε όλους τους απαραίτητους προγόνους για να το ανασυστήσουμε σωστά.

$ git bundle verify ../commits.bundle
The bundle contains 1 ref
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master
The bundle requires these 1 ref
9a466c572fe88b195efd356c3f2bbeccdb504102 second commit
../commits.bundle is okay

Αν αυτός που δημιούργησε το δεμάτι είχε είχε συμπεριλάβει μόνο τις δύο τελευταίες υποβολές που είχε κάνει και όχι και τις τρεις, το αρχικό αποθετήριο δεν θα μπορούσε να το εισάγει, δεδομένου ότι λείπει το απαιτούμενο ιστορικό. Η εντολή verify θα επέστρεφε:

$ git bundle verify ../commits-bad.bundle
error: Repository lacks these prerequisite commits:
error: 7011d3d8fc200abe0ad561c011c3852a4b7bbe95 third commit - second repo

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

$ git bundle list-heads ../commits.bundle
71b84daaf49abed142a373b6e5c59a22dc6560dc refs/heads/master

Η υπο-εντολή verify επίσης θα μας πει τις κεφαλές. Ο σκοπός είναι να μπορούμε να δούμε τι μπορούμε να έλξουμε, ώστε να μπορούμε να χρησιμοποιήσουμε τις εντολές fetch ή pull για να εισάγουμε υποβολές από αυτό το δεμάτι. Εδώ θα ανακτήσουμε τον κύριο κλάδο του δεματιού σε έναν κλάδο που ονομάζεται other-master στο αποθετήριό μας:

$ git fetch ../commits.bundle master:other-master
From ../commits.bundle
 * [new branch]      master     -> other-master

Τώρα βλέπουμε ότι έχουμε τις εισαγόμενες υποβολές στον κλάδο other-master καθώς και τις υποβολές που έχουμε κάνει εν τω μεταξύ στον δικό μας κλάδο master.

$ git log --oneline --decorate --graph --all
* 8255d41 (HEAD, master) third commit - first repo
| * 71b84da (other-master) last commit - second repo
| * c99cf5b fourth commit - second repo
| * 7011d3d third commit - second repo
|/
* 9a466c5 second commit
* b1ec324 first commit

Έτσι, η git bundle μπορεί να είναι πραγματικά χρήσιμη για να μοιραζόμαστε ή να κάνουμε δικτυακές ενέργειες όταν δεν έχουμε το κατάλληλο δίκτυο ή κοινόχρηστο αποθετήριο για να τις κάνουμε.