Git
Chapters ▾ 2nd Edition

7.12 Git Tools - Bundelen

Bundelen

Alhoewel we de reguliere manieren om Git data over een netwerk te transporteren al behandeld hebben (HTTP, SSH, etc), is er eigenlijk nog een weinig gebruikte manier om dit te doen, maar die wel erg nuttig kan zijn.

Git is in staat om zijn gegevens te “bundelen” (bundling) in een enkel bestand. Dit kan handig zijn in verscheidene situaties. Misschien is je netwerk uit de lucht en je wilt wijzigingen naar je medewerkers sturen. Misschien werk je ergens buiten de deur en heb je om beveiligingsredenen geen toegang tot het lokale netwerk. Misschiens is je wireless/ethernet kaart gewoon kapot. Misschien heb je op dat moment geen toegang tot een gedeelde server, wil je iemand updates mailen en je wilt niet 40 commits via een format-patch sturen.

Dit is waar het git bundle commando behulpzaam kan zijn. Het bundle commando pakt alles wat normaalgesproken over het netwerk zou worden gepushed met een git push commando in een binair bestand die je naar iemand kunt mailen of op een flash drive kunt bewaren, en dan uitpakken in de andere repository.

Laten we een eenvoudig voorbeeld bekijken. Laten we zeggen dat je een repository met twee commits hebt:

$ 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

Als je deze repository naar iemand wilt sturen en je hebt geen toegang tot een repository om naar te pushen, of deze gewoon niet wil inrichten, kan je het bundelen met 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)

Nu heb je een bestand die repo.bundle heet die alle gegevens heeft die nodig zijn om de master branch van de repository weer op te bouwen. Met het bundle commando moet je elke referentie of een reeks van commits opgeven die je erin wilt betrekken. Als de bedoeling is dat deze elders wordt gekloond, moet je HEAD als referentie meenemen zoals we hier gedaan hebben.

Je kunt dit repo.bundle bestand naar iemand mailen, of op een USB schijf zetten en het even langsbrengen.

Aan de andere kant, stel dat je dit repo.bundle bestand gestuurd krijgt en je wilt aan het project werken. Je kunt dan van dit binaire bestand naar een directory clonen, vergelijkbaar met hoe je dit zou doen vanaf een 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

Als je de HEAD niet in de referenties meeneemt, moet je ook -b master opgeven of welke branch er dan ook inzit, omdat het anders niet duidelijk is welke branch er moet wodren uitgechecked.

Laten we nu zeggen dat je drie commits hierop doet en de nieuwe commits terug wilt sturen via een bundel op een USB stick of email.

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

Eerst moeten we de reeks van commits vaststellen die we in de bundel willen stoppen. In tegenstelling tot de netwerk protocollen die de minimum set van gegevens die verstuurd moeten worden voor ons kunnen bepalen, moeten we het hier handmatig uitvinden. Je kunt natuurlijk hier hetzelfde doen en de gehele repository bundelen, en dat zou werken, maar het is beter om alleen het verschil te bundelen - alleen de drie commits die we zojuist lokaal gemaakt hebben.

Om dat te doen, moet je het verschil berekenen. Zoals we hebben beschreven in Commit reeksen, kan je op verschillende manieren een reeks van commits aangeven. Om de drie commits te krijgen die we in onze master branch hebben die niet in de originele gecloonde branch zaten, kunnen we zoiets als origin/master..master of master ^origin/master gebruiken. Je kunt dat verifiëren met het log commando.

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

Dus nu dat we de lijst met commits hebben die we in de bundel willen pakken, laten we ze dan ook gaan bundelen. We doen dat met het git bundle create commando, waaraan we een bestandsnaam meegeven waar we onze bundel in willen pakken en de reeks met commits die we erin willen gaan doen.

$ 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)

Nu hebben we een commits.bundle bestand in onze directory. Als we deze naar onze partner sturen, kan zij deze importeren in de orginele repository, zelfs als daar in de tussentijd weer meer werk aan gedaan is.

Als ze de bundel krijgt, kan ze deze inspecteren om te zien wat erin zit voordat ze deze in haar repository importeert. Het eerste commando is het bundle verify commando, dat controleert dat het bestand een geldige Git bundel is en dat je alle benodigde voorouders hebt om het op de juiste wijze te importeren.

$ 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

Als degene die de bundel heeft aangemaakt van alleen de laatste twee commits die ze hadden gedaan, in plaats van alle drie, zou de originele repository niet in staat zijn geweest om deze te importeren, omdat de benodigde historie ontbreekt. Het verify commando zou dan iets als dit hebben laten zien:

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

Echter, onze eerste bundel is geldig, dus we kunnen de commits ervan gaan fetchen. Als je zou willen zien welke branches er uit de bundel kunnen worden geïmporteerd, is er ook een commando die alleen de heads laat zien:

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

Het verify sub-commando laat je ook de heads zien. Het belangrijkste is om te zien wat er naar binnen gepulled kan worden, zodat je het fetch of pull commando kunt gebruiken om de commits van deze bundel kunt importeren. Hier gaan we de master branch van de bundel naar een branch met de naam other-master in onze repository fetchen:

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

Nu kunnen we zien dat we de commits op de other-master branch hebben geïmporteerd zowel als elke andere commit die we in de tussentijd in onze eigen master branch hebben gedaan.

$ 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

Dus git bundle kan erg handig zijn voor het delen of netwerk-achtige operaties te doen als je niet de beschikking hebt over een geschikt netwerk of gedeelde repository om te gebruiken.