Git merge en git rebase
Wellicht wel een van de functies die je het meest zal gaan gebruiken, en ook daar waar Git bekend door is geworden. Als je Git gebruikt zoals het bedoeld is zul je regelmatig branches willen mergen of rebasen.
Mergen of rebasen via 'git pull'
Je gebruikt mergen wellicht al een tijde, Git doet dit namelijk automatisch voor je als in je branch aan het comitten bent geweest en ondertussen zijn er remote ook commits gepushed door andere ontwikkelaars. In zo'n geval kan er geen 'faster-forward' gedaan worden. Een faster forward kan alleen als je eigen branch niet veranderd is sinds de laatste pull of fetch. Standaard zal git dus een merge commit maken die de laatste commits remote en je lokale commits in een commit zal gaan samenvoegen.
Merge
Naast dat 'git pull' een merge doet kun je ook zelf mergen. Het resolven van conflicts werkt in beide gevallen hetzellfde. 'Git merge' gebruik je om 2 branches te mergen. Een voorbeeld:
Het is wel belangrijk dat 'anderebranch' wel lokaal beschikbaar is. Git zal dan alle commits die op 'anderebranch' zijn gedaan sinds dat de branch is gemaakt samenvoegen met de branch die je uitgechecked hebt in 1 nieuwe commit. Wanneer er geen conflicten zijn zal Git deze merge direct committen.
Als er wel conflicten zijn zal Git dit melden dat de auto merge voor bepaalde files niet is gelukt. Je kunt dan met je favoriete editor deze conflicten oplossen en als je dat gedaan hebt stage je deze files met 'git add conflictfile'. Wanneer je alle conflicten hebt opgelost dan voer je het commando 'git commit' uit. Je hebt dan in een editor de mogelijkheid om toelichting te geven over het conflict en zal het je snel duidelijk worden dat het nu gaat om een merge commit.
Na het comitten is je merge compleet en kun je deze pushen naar de remote. Wanneer je een conflict hebt na een git pull los je deze op precies dezelfde manier op.
Stel dat je halverwege het mergen bent, en je het niet meer ziet zitten kun je git reset gebruiken als volgt:
Je gaat dan terug naar de laatste recente versie en je merge is dan terug gedraaid. De wijzigingen die je hebt gemaakt om het conflict op te lossen zijn dan ook ongedaan gemaakt. Je kunt eventueel --soft gebruiken als je dat niet wilt.
Git rebase
Een andere prachtige feature van git is 'git rebase'. De naam klinkt voor sommige misschien vaag maar na de volgende uitleg vindt je het hopelijk simpel.
Stel je wilt alle wijzigingen van 'anderebranch' in de master zetten. Dan kun je voor een merge kiezen, maar soms is rebasen eenvoudiger. Dit is vooral wanneer je de commits die op 'anderebranch' zijn gedaan overzichtelijk terug wilt kunnen zien na de rebase. Het is dan ook eenvoudiger om een individuele commit uit 'anderebranch' in de master later terug te draaien met "git revert". Ook blijft je tijdlijn mooier doordat je niet weer een aftakking maakt van je master branch en deze weer samenvoegt. Als je het programma "gitk" geïnstalleerd hebt zal het je snel duidelijk worden wat ik daarmee bedoel.
Meestal doe ik een rebase als ik weet dat 'anderebranch' maar 5 commits heeft bijvoorbeeld. Om een hele merge te maken vindt ik dan overbodig. Wanneer je een rebase doet zal Git proberen alle commits die in 'anderebranch' zijn gedaan in de juiste tijdsvolgorde 'opnieuw af te spelen'. Het verschil met een merge is dat die bovenop je HEAD wordt gezet. Een andere branch rebasen gaat als volgt:
Als je dan in de master uitgechecked bent zal Git proberen alle commits in 'anderebranch' in de juiste tijdsvolgorde in te voegen in de master. Nog een voordeel t.o.v. van een merge is dat je in je Git log geen meldingen ziet die lijken op: "Merge branch 'anderebranch' of ssh://host/var... master" die weinig zeggen. Je kunt deze melding bij een merge wel overschrijven/wijzigen door:
Te doen. Als de merge in een keer lukt zal Git "Cool new feature" als message meegeven en geen vage "Merge branch.. etc".
Wanneer je een conflict hebt tijdens het rebase los je deze conflict per conflict op. Je ziet in je console dat Git het mislukt is om het conflict automatisch op te lossen, en zal de rebase tijdelijk stoppen. Je opent het bestand in je favoriete editor en lost het probleem op. Vervolgens doe je dan:
En dan zal Git weer doorgaan met rebasen. Je kunt ook --skip gebruiken als je vindt dat het conflict niet erg is (bijvoorbeeld bij een add of delete conflict). Wanneer je het niet meer vertrouwt doe je het volgende:
En alles wordt dan weer terug gedraait en HEAD is dan weer zoals voor de rebase.
Rebase via pull
Wanneer je "git pull" doet zal Git automatisch een merge doen als er geen faster-forward gedaan kan worden. Feitelijk worden jouw commits die niet remote staan, en remote commits die niet bij jou lokaal staan samengevoegd in een merge commit. Ik vindt dit vaak niet wenselijk omdat anderen dan niet goed kunnen zien wat je nou precies aangepast hebt. Bij een rebase zal git proberen jouw commits proberen in te voegen in de juiste tijdsvolgorde tussen de andere remote commits. Zo is overzichtelijk wie wat gedaan heeft.
Je doet dit als volgt:
2
3
4
5
En het vervolg process zal precies hetzelfde zijn als hierboven. Wanneer een faster-forward mogelijk is zal Git de rebase negeren (want je loopt tenslotte niet voor op de remote branch). Het oplossen van conflicten gaat precies hetzelfde!
Met merge en rebase kan nog veel meer. Bijvoorbeeld interactief rebasen. En bij "git merge" en "git rebase" kun je nog een tal van opties meegeven. Ik kan je zeker aanraden om eens de help goed door te lezen van beiden en met het e.e.a. eens te experimenteren.
Inhoudsopgave
- Git clone of git init
- Git reset
- Git revert
- Git branch
- Git diff
- Git checkout
- Git cherry-pick
- Git merge en git rebase
- Git pull
- Git tag