Als ontwikkelaar werk ik mee aan meerdere projecten. In veel gevallen is het nodig om een fork van het stroomopwaartse project te maken en een pull-aanvraag toe te voegen. De eerste stappen (een fork maken) enz. zijn niet moeilijk, en in eerste instantie heb je een up-to-date kloon van de originele website waarop je kunt werken en pull-aanvragen kunt openen voor het stroomopwaartse project. De meeste van deze stappen kunnen worden uitgevoerd met behulp van de web-UI (bijv. bij gebruik van Github). Maar tijdens het werken aan een pull request is het vaak nodig om je gevorkte kloon te synchroniseren, bijvoorbeeld om een nieuwe branch te openen. Dan begint de ellende. Wat kan gebeuren:
- Je bent een nieuwe branch gestart, maar de hoofd branch liep niet synchroon
- U moet rebaseen en mogelijk is er een conflict
Mensen beginnen met rebasen, maar halen vaak niet-gerelateerde commits binnen die andere problemen veroorzaken. In dit bericht wil ik enkele methoden delen die ik heb om met dergelijke gevallen om te gaan.
Een nieuwe `branch` openen
Wanneer je een nieuwe pull request wilt openen wil je dat dit correct gebeurt. Ik neem hier aan dat je al een ontwikkelomgeving hebt opgezet met je gekloonde git-repository, klaar om commits te pushen.
Om ervoor te zorgen dat uw fork gesynchroniseerd is, moet u alle upstream-updates ophalen. Dat kunnen we doen met:
git fetch --all
of als het gewoon is upstream
, we kunnen gebruiken
git fetch upstream
welke sneller is.
De volgende stap is het uitchecken van de doelvertakking waartegen je de pull request wilt maken. Dit kan zijn main
, master
of de dev
, maar soms kan dit zelfs anders zijn. In ons voorbeeld gebruiken we main
.
git checkout main
Nu willen we resetten main
naar dezelfde staat als upstream\main
, omdat dit de branch is waar we het pull-verzoek naartoe willen sturen. We moeten ervoor zorgen dat er geen niet-vastgelegde bestanden zijn, aangezien deze zullen worden verwijderd!
git reset --hard upstream/main
Als we de --hard
markeer dan zal git niet-vastgelegde bestanden maken voor alle wijzigingen tussen de oude en nieuwe staat. Dit kan handig zijn als we commits willen terugdraaien, maar niet bij het starten van een nieuwe branch.
Vanaf hier kunnen we de lokale vestiging naar onze vork duwen met:
git push
Nu zijn we op hetzelfde niveau als de doelvestiging en kunnen we een nieuwe vertakking openen die synchroon loopt met upstream
. We kiezen een nieuwe branchenaam die de naam van ons pull-verzoek weerspiegelt, in dit voorbeeld zal ik gebruiken test-pull-verzoek
als filiaalnaam.
git checkout -b test-pull-request
Dit creëert een nieuwe lokale branch, vanaf hier kun je beginnen met coderen en je commits toevoegen. Als je er klaar voor bent, kun je je branch naar je fork publiceren (ik gebruik origin
als naam voor de gekloonde repository). Vanaf dat moment wordt elke nieuwe commit gepusht origin
ook. Wanneer we onze nieuwe lokale branch publiceren, moeten we ook de stroomopwaartse branch instellen, zodat we later een pull-aanvraag kunnen openen.
git push --set-upstream origin test-pull-request
Wanneer alle commits zijn gedaan en we al onze commits hebben gepusht (git push
), dan zijn we klaar om een pull request te openen.
Open een nieuwe pull prequest
Wanneer u Github gebruikt, is het raadzaam om een pull-aanvraag te openen met behulp van de web-UI of met behulp van een plug-in vscode
of andere ontwikkelomgeving. In de meeste gevallen is er een sjabloon die moet worden ingevuld. Zorg ervoor dat de juiste commits worden weergegeven en dat u de juiste doeltak hebt geselecteerd!
Rebasen en oplossen van problemen met `mergen`
Soms moeten we `rebasen`. Dit kan gebeuren als de PR te oud is en we moeten synchroniseren met onze target branch. Persoonlijk zou ik de originele commits bovenop de rebased branch willen forceren in plaats van een merge-commit toe te voegen. Force-push maakt het gemakkelijker om de commits in het pull-verzoek bij te houden en vermijdt extra merge-commits. Om correct te kunnen rebasen, moeten we eerst de nieuwste updates ophalen. We kunnen hiervoor gebruiken:
git fetch upstream
Nu zorgen we ervoor dat we bij het juiste filiaal zijn uitgecheckt.
git checkout test-pull-request
Om te rebaseen met onze stroomopwaartse doeltak starten we een rebase-opdracht.
git rebase upstream/dev
Als je de commits wilt selecteren die moeten worden opgenomen (bijvoorbeeld wanneer je sommige commits wilt terugdraaien), zou je moeten overwegen om de -i
vlag om interactief rebasen te starten.
git rebase -i upstream/dev
Voor elke commit zal git proberen te rebaseen, als dit niet lukt, dan moet je je bestanden corrigeren, opslaan en stagen om git te vertellen welke wijzigingen moeten worden aangebracht. Na staging kun je doorgaan met rebasen:
git rebase --continue
Zorg ervoor dat je alleen wijzigingen aanbrengt in commits die direct gerelateerd zijn aan de samenvoegconflicten en die de gewenste wijzigingen voor die bepaalde commit weergeven. Herhaal dit voor de andere commits (indien van toepassing) totdat de rebase met succes is voltooid.
Als alles een puinhoop wordt, is er een redding door het `merge` commando af te breken.
git rebase --abort
De volgende stap is dat we niet alleen commits nu pullen en pushen, maar alleen rebased commits forceren. Dit kan onlogisch zijn, maar we willen ervoor zorgen dat we de exacte lokale situatie naar onze hand zetten origin
tak.
git push --force
Nu zou onze branch opnieuw moeten worden gebaseerd en in het pull-verzoek zouden we alleen de commits van onze PR moeten zien, of de geselecteerde commits uit het bestand (bij gebruik van de -i
keuze).
Nieuwe schone commits maken van eerder werk
Als je een grotere PR hebt met meerdere bestanden en je bestaande commits wilt vervangen of ongedaan wilt maken zonder je werk te verliezen, kun je dit gebruiken git reset
.
Met git log
we kunnen de commits die we hebben gemaakt bovenop onze branch laten zien. Om deze commits te vervangen moeten we rebaseen naar de commit van waar we opnieuw willen beginnen.
Stel dat we twee commits hebben die we over willen doen. Laat ze zien met git log
.
commit 6090d321e3926ad9c5ffdd026f7c2fb046cdbbf2 (HEAD -> test2) Auteur: jij Datum: wo 24 mei 14:19:24 2023 +0000 commit 2 commit a0ad22921fb8f5797aeb4e414cf3403b80027a3d Auteur: jij Datum: wo 24 mei 14:18:03 2023 +0000 commit 1 commit abf08f66a4c7e01955213c228542884951d45a11 (upstream/dev, origin/test2, origin/dev, origin/HEAD, dev) Auteur: gebruiker Datum: wo 24 mei 01:38:16 2023 -0500 Update upstream
Ervan uitgaande dat we geen niet-vastgelegde bestanden hebben, kunnen we rebaseen om vast te leggen abf08f66a4c7e01955213c228542884951d45a11
(upstream/dev, origin/test2, origin/dev, origin/HEAD, dev).
git reset abf08f66a4c7e01955213c228542884951d45a11
Nu zul je zien dat de wijzigingen van de laatste 2 commits nu unstaged bestanden zijn. Je kunt nu de wijzigingen voor je nieuwe commit stagen, of, als je wilt, dit in meer commits doen totdat alle wijzigingen zijn gestaged en vastgelegd. Nu, om de oude commits te vervangen door de nieuwe, kunnen we ze forceren om ze naar onze te pushen origin
tak.
git push --force
Nu zijn je commits vervangen door de nieuwe.
Tijdelijk niet opgeslagen werk opslaan
Soms moet je tussen branches wisselen, maar heeft u niet-vastgelegde bestanden. Als pre-commit wordt gebruikt, is het misschien niet mogelijk om te committen. In plaats daarvan kunt u uw wijzigingen op de stapel opslaan. U kunt uw wijzigingen later terugkrijgen door ze uit de stapel te halen. Dit werkt ook als u niet-vastgelegde wijzigingen wilt toepassen op een andere branch.
Om uw niet-toegewijde werk op te bergen:
git stash
Om de wijzigingen terug te laten komen:
git stash pop
Er is veel meer dat je kunt doen met git stash, maar ik zal het hier kort houden.
Voor meer git-commando's gebruik je de online documentatie.