This is an in-progress translation.
To help translate the book, please fork the book at GitHub and push your contributions.

Subboom mergen

Nu je de moeilijkheden van het submodulesysteem hebt gezien, laten we eens kijken naar een alternatieve manier om hetzelfde probleem aan te pakken. Zodra Git merge’t, kijkt het naar wat het samen moet mergen en kiest dan een toepasselijke mergestrategie om te gebruiken. Als je twee branches aan het mergen bent, zal Git een recursive strategie gebruiken. Als je meer dan twee branches aan het mergen bent, zal Git de octopus strategie kiezen. Deze strategieën worden automatisch voor je gekozen, omdat de recursieve strategie complexe drie-weg merge situaties kan behandelen – bijvoorbeeld, meer dan één gezamenlijke voorouder – maar het kan slechts twee branches behandelen. De octopus merge kan meerdere branches behandelen, maar is voorzichtiger om moeilijke conflicten te vermijden, dus is het gekozen als de standaard strategie als je meer dan twee branches probeert te mergen.

Maar er zijn meerdere strategieën die je ook kunt kiezen. Eén ervan is de subtree merge, en je kunt het gebruiken om met het subproject probleem om te gaan. Hier zul je zien hoe je dezelfde rack inbedding kunt doen als in de laatste sectie, maar in plaats daarvan subboommerges te gebruiken.

Het idee van de subboommerge is dat je twee projecten hebt, en één van de projecten wijst naar de submap van de andere en vice versa. Als je een subboommerge specificeerd, dan is Git slim genoeg om uit te vogelen dat de ene een subboom van de andere is en toepasselijk te mergen – het is erg verbazingwekkend.

Eerst voeg je de Rack applicatie toe aan je project. Dan voeg je het Rack project toe als een remote reference in je eigen project en checked het dan uit in zijn eigen branch:

$ git remote add rack_remote git@github.com:schacon/rack.git
$ git fetch rack_remote
warning: no common commits
remote: Counting objects: 3184, done.
remote: Compressing objects: 100% (1465/1465), done.
remote: Total 3184 (delta 1952), reused 2770 (delta 1675)
Receiving objects: 100% (3184/3184), 677.42 KiB | 4 KiB/s, done.
Resolving deltas: 100% (1952/1952), done.
From git@github.com:schacon/rack
 * [new branch]      build      -> rack_remote/build
 * [new branch]      master     -> rack_remote/master
 * [new branch]      rack-0.4   -> rack_remote/rack-0.4
 * [new branch]      rack-0.9   -> rack_remote/rack-0.9
$ git checkout -b rack_branch rack_remote/master
Branch rack_branch set up to track remote branch refs/remotes/rack_remote/master.
Switched to a new branch "rack_branch"

Nu heb je de wortel van het Rack project in je rack_branch branch en je eigen project in de master branch. Als je één uitchecked en dan de andere, kun je zien dat ze verschillende project wortels hebben:

$ ls
AUTHORS	       KNOWN-ISSUES   Rakefile      contrib	       lib
COPYING	       README         bin           example	       test
$ git checkout master
Switched to branch "master"
$ ls
README

Je wilt het Rack project in je master project pullen als een submap. Je kunt dat in Git doen met git read-tree. Je zult meer over read-tree en zijn vrienden leren in Hoofdstuk 9, maar weet voor nu dat het de wortel boom van een branch in je huidige staging area en werkmap leest. Je hebt zojuist teruggewisseld naar je master branch, en je pulled de rack branch in de rack submap van je master branch in je hoofdproject:

$ git read-tree --prefix=rack/ -u rack_branch

Als je commit, ziet het eruit alsof je alle Rack bestanden in die submap hebt – alsof je ze uit een tarball gekopieerd hebt. Wat interessant is is dat je vrij makkelijk veranderingen van één branch in de andere kunt mergen. Dus als het Rack project vernieuwd kun je alle stroomopwaartse wijzigingen binnenhalen door naar die branch te wisselen en te pullen:

$ git checkout rack_branch
$ git pull

Dan kun je die veranderingen in je master branch mergen. Je kunt git merge -s subtree gebruiken en het zal prima werken; maar Git zal ook de geschiedenissen samenvoegen, wat je waarschijnlijk niet wilt. Om de veranderingen binnen te halen en het commit bericht te vullen, gebruik dan de --squash en --no-commit opties samen met de -s subtree strategie optie:

$ git checkout master
$ git merge --squash -s subtree --no-commit rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requested

Alle wijzigingen van je Rack project worden ingemerged en zijn klaar om lokaal gecommit te worden. Je kunt ook het tegenovergestelde doen – veranderingen doen in de rack submap van je master branch en dan die later in je rack_branch branch mergen om ze naar de eigenaren te sturen of ze stroomopwaarts te pushen.

Om een diff te krijgen tussen wat je in je rack submap hebt en de code in je rack_branch branch – om te zien of je ze moet mergen – kun je niet het gebruikelijke diff commando toepassen. In plaats daarvan moet je git diff-tree uitvoeren met de branch waarmee je wilt vergelijken:

$ git diff-tree -p rack_branch

Of, om te vergelijken met wat in je rack submap zit met wat in de master branch op de server zat de laatste keer dat je gefetched hebt, kun je dit uitvoeren:

$ git diff-tree -p rack_remote/master