Idén med delträdsammanfogning är att du har två projekt, och att det ena projektet motsvarar en underkatalog i det andra. När du anger en delträdsammanfogning är Git ofta smart nog att räkna ut att det ena är ett delträd av det andra och sammanfoga därefter.
Vi går igenom ett exempel där vi lägger in ett separat projekt i ett befintligt projekt och sedan sammanfogar koden från det andra in i en underkatalog till det första.
Först lägger vi till Rack‑applikationen i vårt projekt. Vi lägger till Rack‑projektet som en fjärrreferens i vårt eget projekt och växlar sedan till det i en egen gren:
$ git remote add rack_remote https://github.com/rack/rack
$ git fetch rack_remote --no-tags
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 https://github.com/rack/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 har vi roten till Rack‑projektet i vår gren rack_branch och vårt eget projekt i grenen master.
Om du växlar till den ena och sedan den andra kan du se att de har olika projektrötter:
$ ls
AUTHORS KNOWN-ISSUES Rakefile contrib lib
COPYING README bin example test
$ git checkout master
Switched to branch "master"
$ ls
READMEDet här är ett lite udda koncept. Alla grenar i ditt kodförråd måste inte vara grenar av samma projekt. Det är inte vanligt, eftersom det sällan är hjälpsamt, men det är ganska enkelt att låta grenar innehålla helt olika historiker.
I det här fallet vill vi dra in Rack‑projektet i vårt master‑projekt som en underkatalog.
Det kan vi göra i Git med git read-tree.
Du kommer att lära dig mer om read-tree och dess vänner i ch10-git-internals.asc, men för tillfället räcker det att veta att den läser rotträdet från en gren in i din nuvarande köyta och din arbetskatalog.
Vi bytte just tillbaka till grenen master, och vi drar in grenen rack_branch i underkatalogen rack i vår master‑gren i huvudprojektet:
$ git read-tree --prefix=rack/ -u rack_branchNär vi checkar in ser det ut som att vi har alla Rack‑filer under den underkatalogen — ungefär som om vi kopierat in dem från en tar‑fil. Det intressanta är att vi ganska enkelt kan sammanfoga ändringar från den ena grenen till den andra. Så om Rack‑projektet uppdateras kan vi dra in uppströmsändringar genom att byta till den grenen och dra:
$ git checkout rack_branch
$ git pullSedan kan vi sammanfoga dessa ändringar tillbaka till vår master‑gren.
För att dra in ändringarna och förifylla incheckningsmeddelandet använder du flaggan --squash, samt den rekursiva sammanslagningsstrategins -Xsubtree‑alternativ.
Den rekursiva strategin är standard här, men vi tar med den för tydlighet.
$ git checkout master
$ git merge --squash -s recursive -Xsubtree=rack rack_branch
Squash commit -- not updating HEAD
Automatic merge went well; stopped before committing as requestedAlla ändringar från Rack‑projektet sammanfogas och är redo att checkas in lokalt.
Du kan också göra tvärtom — göra ändringar i underkatalogen rack i din master‑gren och sedan sammanfoga dem in i din rack_branch‑gren senare för att skicka dem till förvaltarna eller skicka dem uppströms.
Detta ger oss ett arbetsflöde som liknar undermoduler utan att använda undermoduler (som vi går igenom i ch07-git-tools.asc). Vi kan behålla grenar med andra relaterade projekt i vårt kodförråd och delträdssammanfoga dem i vårt projekt då och då. Det är trevligt på vissa sätt, till exempel att all kod checkas in på ett enda ställe. Det har dock andra nackdelar, som att det är lite mer komplext och lättare att göra misstag när man återintegrerar ändringar eller råkar skicka en gren till ett orelaterat kodförråd.
En annan lite märklig sak är att om du vill få en diff mellan det du har i din underkatalog rack och koden i din rack_branch‑gren — för att se om du behöver sammanfoga dem — kan du inte använda vanliga git diff.
I stället måste du köra git diff-tree med den gren du vill jämföra mot:
$ git diff-tree -p rack_branchEller, om du vill jämföra det som finns i din underkatalog rack med vad master‑grenen på servern var när du senast hämtade, kan du köra:
$ git diff-tree -p rack_remote/master