Git merge
Samenvoegen is de manier waarop je in Git een geforkte geschiedenis weer bij elkaar brengt. Met de opdracht git merge
neem je de onafhankelijke ontwikkelingsregels die door git branch
zijn gemaakt en integreer je ze in één branch.
Houd er rekening mee dat alle onderstaande opdrachten s worden samengevoegd in de huidige branch. De huidige branch wordt zo bijgewerkt dat de samenvoeging wordt weergegeven, maar de doelbranch zal volledig buiten schot blijven. Dit betekent, nogmaals, dat git merge
vaak wordt gebruikt in combinatie met git checkout
voor het selecteren van de huidige branch en git branch -d
voor het verwijderen van de verouderde doelbranch.
Hoe het werkt
Git merge
combineert meerdere reeksen commits in één uniforme geschiedenis. In de meest voorkomende gevallen wordt git merge
gebruikt om twee branches te combineren. In de volgende voorbeelden in dit document wordt ingegaan op dit patroon voor het samenvoegen van branches.In deze scenario's neemt git merge
twee commit-pointers, meestal de branch-tips, om vervolgens een gemeenschappelijke basiscommit voor beide te vinden. Zodra Git een gemeenschappelijke basiscommit heeft gevonden, wordt er een nieuwe 'merge commit' gemaakt, die de wijzigingen van beide merget-commitreeksen in de wachtrij combineert.
Stel dat we een nieuwe branchfunctie hebben die is gebaseerd op de main
-branche. We willen deze functiebranch nu samenvoegen met main
.
gerelateerd materiaal
Uitgebreid Git log
Oplossing bekijken
Git leren met Bitbucket Cloud
Als je deze opdracht aanroept, wordt de opgegeven branchfunctie samengevoegd in de huidige branch; we gaan ervan uit dat dit main
is. Git bepaalt automatisch het samenvoegingsalgoritme (hieronder besproken).
Merge-commits zijn uniek ten opzichte van andere commits doordat ze twee bovenliggende commits hebben. Bij het maken van een merge-commit zal Git proberen om automatisch de afzonderlijke geschiedenissen voor je samen te voegen. Als Git gegevens tegenkomt die in beide geschiedenissen zijn gewijzigd, kunnen deze niet automatisch worden gecombineerd. Dit scenario is een conflict met versiebeheer. Hier is tussenkomst van de gebruiker nodig om door te kunnen gaan.
Voorbereiden voor het samenvoegen
Voordat je een samenvoeging uitvoert, moeten er een aantal voorbereidingsstappen worden genomen om ervoor te zorgen dat de samenvoeging soepel verloopt.
Bevestig de ontvangende branch
Voer git status
uit om ervoor te zorgen dat HEAD
verwijst naar de juiste branch die de merge ontvangt. Voer indien nodig git checkout
uit om over te schakelen naar de ontvangende branch. In ons geval zullen we git checkout main
uitvoeren.
Haal de nieuwste externe commits op
Zorg ervoor dat de ontvangende branch en de samenvoegende branch allebei up-to-date zijn met de laatste externe wijzigingen. Voer git fetch
uit om de nieuwste externe commits op te halen. Zodra het op ophalen is voltooid, moet je controleren of de main
-branch over de laatste updates beschikt. Dit doe je door git pull
uit te voeren.
Samenvoegen
Zodra de eerder besproken stappen voor het 'voorbereiden om samen te voegen' zijn uitgevoerd, kan een merge worden gestart door git merge
uit te voeren, waarbij
Fast Forward-merge
Je kunt een fast forward-merge uitvoeren wanneer er een lineair pad is van de huidige branch-tip naar de doelbranch. In plaats van de branches 'daadwerkelijk' samen te voegen, hoeft Git alleen maar de huidige branch-tip naar de doelbranch-tip te verplaatsen (d.w.z. 'fast forward') om de geschiedenissen te integreren. Hierdoor worden de geschiedenissen gecombineerd, aangezien alle commits die vanaf de doelbranch bereikbaar zijn, nu beschikbaar zijn via de huidige. Een snelle samenvoeging van een bepaalde functie in main
zou er ongeveer als volgt uitzien:
Een snelle samenvoeging is echter niet mogelijk als de branches uiteenlopen. Als er geen lineair pad naar de doelbranch is, heeft Git geen andere keuze dan ze te combineren via een '3-weg merge'. Deze '3-weg merge' gebruikt een speciale commit om de twee geschiedenissen aan elkaar te koppelen. De naam is te danken aan het feit dat Git drie commits gebruikt om de merge-commit te genereren: de twee branch-tips en hun gemeenschappelijke voorouder.
Je kunt een van deze samenvoegstrategieën gebruiken, maar veel ontwikkelaars gebruiken graag fast forward-merges (vergemakkelijkt door rebasing) voor kleine functies of bugfixes. De '3-weg merges' reserveren ze voor de integratie van langerlopende functies. In het laatste geval dient de resulterende merge-commit als een symbolische verbinding van de twee branches.
Ons eerste voorbeeld toont een 'fast forward-merge'. De onderstaande code maakt een nieuwe branch, voegt er twee commits aan toe en integreert deze vervolgens in de hoofdregel met een 'fast forward-merge'.
# Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Merge in the new-feature branch
git checkout main
git merge new-feature
git branch -d new-feature
Dit is een veelgebruikte workflow voor kortstondige onderwerpbranches die meer worden gebruikt als een geïsoleerde ontwikkeling dan als organisatorisch hulpmiddel voor langerlopende functies.
Merk ook op dat Git niet mag klagen over de git branch -d
, aangezien new-feature nu toegankelijk is vanuit de main-branch.
In het geval dat je tijdens een 'fast forward-merge' een merge-commit nodig hebt voor registratie, kun je git merge
uitvoeren met de optie --no-ff
.
git merge --no-ff <branch>
Deze opdracht voegt de opgegeven branch samen in de huidige branch, maar genereert altijd een merge-commit (zelfs als het een 'fast forward-merge' was). Dit is handig voor het documenteren van alle merges die in je repository voorkomen.
'3-weg merge'
Het volgende voorbeeld lijkt er erg op, maar vereist een '3-weg merge' omdat de main
vordert terwijl aan de functie wordt gewerkt. Dit is een veelvoorkomend scenario voor grote functies of wanneer meerdere ontwikkelaars tegelijkertijd aan een project werken.
Start a new feature
git checkout -b new-feature main
# Edit some files
git add <file>
git commit -m "Start a feature"
# Edit some files
git add <file>
git commit -m "Finish a feature"
# Develop the main branch
git checkout main
# Edit some files
git add <file>
git commit -m "Make some super-stable changes to main"
# Merge in the new-feature branch
git merge new-feature
git branch -d new-feature
Merk op dat het voor Git onmogelijk is om een snel voorwaartse samenvoeging uit te voeren, omdat er geen manier is om main
naar new-feature
te verplaatsen zonder backtracking.
Voor de meeste workflows zou new-feature
een veel grotere functie zijn met een lange ontwikkelingstijd –en daarom zouden er in de tussentijd nieuwe commits in main
verschijnen. Als je feature branch eigenlijk net zo klein is als die in het bovenstaande voorbeeld, zou je waarschijnlijk beter een rebase kunnen uitvoeren in main
en een 'fast forward-merge' kunnen uitvoeren. Dit voorkomt dat overbodige merge-commits de projectgeschiedenis vervuilen.
Conflicten oplossen
Als de twee branches die je probeert samen te voegen hetzelfde deel van hetzelfde bestand hebben gewijzigd, kan Git niet achterhalen welke versie moet worden gebruikt. In een dergelijke situatie stopt Git direct voor de merge-commit, zodat je de conflicten handmatig kunt oplossen.
Het mooie aan het samenvoegingsproces in Git is dat de vertrouwde workflow edit/stage/commit wordt gebruikt om conflicten tijdens het samenvoegen op te lossen. Wanneer je een conflict tijdens het samenvoegen tegenkomt, toont de opdracht git status
in welke bestanden ze moeten worden opgelost. Als beide branches bijvoorbeeld hetzelfde gedeelte van hello.py
hebben gewijzigd, zie je dan iets zoals in het volgende voorbeeld:
On branch main
Unmerged paths:
(use "git add/rm ..." as appropriate to mark resolution)
both modified: hello.py
Weergave van conflicten
Wanneer Git tijdens een samenvoeging een conflict tegenkomt , wordt de inhoud van de getroffen bestanden bewerkt met visuele indicatoren die beide zijden van de conflicterende inhoud markeren. Deze visuele markeringen zijn: <<<<<<<, =======, en >>>>>>>. Het is nuttig om tijdens een samenvoeging in een project naar deze indicatoren te zoeken om te achterhalen waar conflicten moeten worden opgelost.
here is some content not affected by the conflict
<<<<<<< main
this is conflicted text from main
=======
this is conflicted text from feature branch
>>>>>>> feature branch;
Over het algemeen is de inhoud vóór de markering =======
de ontvangende branch en het deel erna de samenvoegende branch.
Zodra je conflicterende secties hebt geïdentificeerd, kun je daarin duiken en de samenvoeging naar wens herstellen. Als je klaar bent om de samenvoeging te voltooien, hoef je alleen maar git add
uit te voeren op de conflicterende bestanden om Git te laten weten dat ze zijn opgelost. Vervolgens voer je een normale git commit
uit om de merge-commit te genereren. Het is precies hetzelfde proces als het committen van een gewoon snapshot –en dus gemakkelijk voor normale ontwikkelaars om hun eigen samenvoegingen te beheren.
NB: Samenvoegingsconflicten ontstaan alleen in het geval van een '3-weg merge'. Er kunnen geen conflicterende wijzigingen ontstaan in een 'fast forward-merge'.
Samenvatting
Dit document biedt een overzicht van de opdracht git merge
. Samenvoegen is een essentieel proces in het gebruik van Git. We bespraken de interne mechanica achter een merge en de verschillen tussen een 'fast forward-merge' en een '3-weg merge' (een 'echte' merge). Dit zijn de belangrijkste leerpunten:
1. Samenvoegingen in Git combineren reeksen commits in één uniforme geschiedenis met commits;
2. Er zijn twee manieren waarop Git zal samenvoegen: 'Fast Forward' en '3-weg';
3. Git kan commits automatisch samenvoegen, tenzij beide commit-reeksen wijzigingen bevatten die conflicten veroorzaken.
Dit document integreerde en verwees naar andere Git-opdrachten, zoals: git branch, git pull en git fetch. Bezoek de bijbehorende zelfstandige pagina's voor meer informatie.
Deel dit artikel
Volgend onderwerp
Aanbevolen artikelen
Bookmark deze resources voor meer informatie over soorten DevOps-teams of voor voortdurende updates over DevOps bij Atlassian.