Zoeken…


Syntaxis

  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] [<upstream>] [<branch>]
  • git rebase [-i | --interactive] [options] [--exec <cmd>] [--onto <newbase>] --root [<branch>]
  • git rebase --continue | --skip | --abort | --edit-todo

parameters

Parameter Details
--doorgaan met Start het rebasen-proces opnieuw nadat u een samenvoegconflict hebt opgelost.
--abort Annuleer de rebase-bewerking en reset HEAD naar de oorspronkelijke vertakking. Als vertakking was opgegeven toen de rebase-bewerking werd gestart, wordt HEAD opnieuw ingesteld op vertakking. Anders zal HEAD worden gereset naar waar het was toen de rebase-bewerking werd gestart.
--keep leeg Bewaar de commits die niets veranderen van zijn ouders in het resultaat.
--overspringen Start het rebasen-proces opnieuw door de huidige patch over te slaan.
-m, --merge Gebruik samenvoegstrategieën om opnieuw op te starten. Wanneer de recursieve (standaard) samenvoegstrategie wordt gebruikt, kan rebase op de hoogte zijn van de namen aan de upstream-zijde. Merk op dat een rebase-merge werkt door elke commit van de werkende branch bovenop de upstream branch opnieuw te spelen. Daarom is, wanneer er een samenvoegconflict plaatsvindt, de kant die we hebben gemeld de tot nu toe rebased serie, beginnend met stroomopwaarts, en die van hen is de werkende tak. Met andere woorden, de zijkanten zijn verwisseld.
--stat Toon een diffstat van wat er stroomopwaarts is veranderd sinds de laatste rebase. De diffstat wordt ook bestuurd door de configuratieoptie rebase.stat.
-x, --exec command Voer een interactieve rebase uit en stop tussen elke commit en het uitvoeren van een command

Opmerkingen

Houd er rekening mee dat rebase de geschiedenis van de repository effectief herschrijft.

Rebasen commits die bestaan in de externe repository kunnen repository nodes herschrijven die door andere ontwikkelaars worden gebruikt als basisknooppunt voor hun ontwikkelingen. Tenzij u echt weet wat u doet, is het een goede gewoonte om opnieuw op te starten voordat u uw wijzigingen doorvoert.

Lokale filiaal rebasen

Door rebasen wordt een reeks commits opnieuw bovenop een andere commit toegepast.

Om een branch te rebase , checkt u de branch uit en rebase deze bovenop een andere branch.

git checkout topic
git rebase master  # rebase current branch onto master branch

Dit zou leiden tot:

      A---B---C topic
     /
D---E---F---G master

Veranderen in:

              A'--B'--C' topic
             /
D---E---F---G master

Deze bewerkingen kunnen worden gecombineerd tot een enkele opdracht die de vertakking uitcheckt en deze onmiddellijk opnieuw rebaseert:

git rebase master topic   # rebase topic branch onto master branch

Belangrijk: na de rebase hebben de toegepaste commits een andere hash. U moet geen commits rebasen die u al naar een externe host hebt gepusht. Een gevolg kan een onvermogen zijn git push je lokale rebased branch naar een externe host te git push --force , waardoor je enige optie om git push --force forceren overblijft.

Rebase: die van ons en die van hen, lokaal en op afstand

Een rebase verandert de betekenis van "de onze" en "de hunne":

git checkout topic
git rebase   master    # rebase topic branch on top of master branch

Waar HEAD naar verwijst is "van ons"

Het eerste wat een rebase doet, is het HEAD opnieuw instellen om te master ; voordat cherry-picking van het oude branch- topic naar een nieuw topic committeert (elke commit in de vorige topic branch wordt herschreven en door een andere hash geïdentificeerd).

Met betrekking tot terminologieën die worden gebruikt door samenvoeggereedschappen (niet te verwarren met lokale ref of externe ref )

=> local is master ("ours"),
=> remote is topic ("theirs")

Dat betekent dat een samenvoeg / diff-tool de stroomopwaartse branch zal presenteren als local ( master : de branch waarop je rebaseert), en de werkende branch als remote ( topic : de branch wordt rebased)

+-----------------------------------------+
| LOCAL:master |    BASE   | REMOTE:topic |
+-----------------------------------------+
|             MERGED                      |
+-----------------------------------------+

Inversie geïllustreerd

Samenvoegen:

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- other branch to merge

We veranderen het huidige topic , dus we hebben nog steeds waar we aan werkten (en we voegen samen vanuit een andere branch)

c--c--x--x--x---------o(*)  MERGE, still on branch topic
    \       ^        /
     \     ours     /
      \            /
       --y--y--y--/  
               ^
              theirs

Bij een rebase:

Maar bij een rebase schakelen we van kant omdat het eerste wat een rebase doet, is om de stroomopwaartse tak te controleren om de huidige commits er bovenop te spelen!

c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
    \
     \
      \--y--y--y <- upstream branch

Een git rebase upstream zal eerst HEAD op de stroomopwaartse branch, vandaar de schakelaar van 'ours' en 'theirs' in vergelijking met de vorige "huidige" werkende branch.

c--c--x--x--x <- former "current" branch, new "theirs"
    \
     \
      \--y--y--y(*) <- set HEAD to this commit, to replay x's on it
               ^       this will be the new "ours"
               |
            upstream      

De rebase zal dan 'hun' commits herhalen op de nieuwe 'onze' topic branch:

c--c..x..x..x <- old "theirs" commits, now "ghosts", available through "reflogs"
    \
     \
      \--y--y--y--x'--x'--x'(*) <- topic  once all x's are replayed,
               ^                      point branch topic to this commit
               |
        upstream branch

Interactieve rebase

Dit voorbeeld is bedoeld om te beschrijven hoe iemand git rebase kan gebruiken in interactieve modus. Er wordt verwacht dat men een basiskennis heeft van wat git rebase is en wat het doet.

Interactieve rebase wordt gestart met de volgende opdracht:

git rebase -i

De optie -i verwijst naar de interactieve modus . Met behulp van interactieve rebase kan de gebruiker commit-berichten wijzigen, evenals commits herordenen, splitsen en / of squashen (combineren tot één).

Stel dat je je laatste drie commits wilt herschikken. Om dit te doen, kun je uitvoeren:

git rebase -i HEAD~3

Na het uitvoeren van de bovenstaande instructie, wordt een bestand geopend in uw teksteditor waar u kunt selecteren hoe uw commits zullen worden rebased. Wijzig voor dit voorbeeld de volgorde van uw commits, sla het bestand op en sluit de editor. Hiermee wordt een rebase gestart met de bestelling die u heeft toegepast. Als je git log aanvinkt, zul je je commits zien in de nieuwe volgorde die je hebt opgegeven.

Hercommando berichten herformuleren

Je hebt nu besloten dat een van de commit-berichten vaag is en je wilt dat het meer beschrijvend is. Laten we de laatste drie commits onderzoeken met hetzelfde commando.

git rebase -i HEAD~3

In plaats van het herschikken van de volgorde waarin de commits zal worden herleid, dit keer gaan we veranderen pick , de standaard, te reword op een commit waar je zou willen om het bericht te wijzigen.

Wanneer u de editor sluit, wordt de rebase gestart en stopt deze bij het specifieke commit-bericht dat u opnieuw wilde formuleren. Dit laat je de commit boodschap veranderen in wat je maar wilt. Nadat u het bericht hebt gewijzigd, sluit u eenvoudig de editor om door te gaan.

De inhoud van een commit wijzigen

Naast het wijzigen van het commit bericht kun je ook de wijzigingen aanpassen die door de commit zijn gedaan. Om dit te doen verander je gewoon pick om te edit voor één commit. Git zal stoppen wanneer het bij die commit aankomt en de originele wijzigingen van de commit in het verzamelgebied geven. U kunt deze wijzigingen nu aanpassen door ze onstagelijk te maken of nieuwe wijzigingen toe te voegen.

Zodra het verzamelgebied alle gewenste wijzigingen in die commit bevat, leg je de wijzigingen vast. Het oude commit-bericht wordt getoond en kan worden aangepast om de nieuwe commit weer te geven.

Een enkele commit in meerdere splitsen

Stel dat je een commit hebt gemaakt maar op een later moment hebt besloten dat deze commit in plaats daarvan in twee of meer commits kan worden opgesplitst. Gebruik hetzelfde commando als eerder, vervang in plaats daarvan pick door edit en druk op enter.

Nu zal git stoppen bij de commit die je hebt gemarkeerd om te bewerken en alle inhoud in het verzamelgebied plaatsen. Vanaf dat punt kun je git reset HEAD^ om de commit in je werkmap te plaatsen. Vervolgens kun je je bestanden toevoegen en vastleggen in een andere volgorde - uiteindelijk een enkele vastlegging splitsen in n vastleggingen.

Meerdere commits in één pletten

Stel dat je wat werk hebt gedaan en meerdere commits hebt waarvan je denkt dat het in plaats daarvan een enkele commit zou kunnen zijn. Voor dat u kunt uitvoeren git rebase -i HEAD~3 , ter vervanging van 3 met een geschikte hoeveelheid van commits.

Deze keer vervang pick met squash plaats. Tijdens de rebase wordt de commit die je hebt geplet verpletterd bovenop de vorige commit; ze in plaats daarvan in een enkele commit veranderen.

Interactieve rebase afbreken

U bent begonnen met een interactieve rebase. In de editor waar je je commits kiest, besluit je dat er iets misgaat (bijvoorbeeld een commit ontbreekt, of je hebt de verkeerde rebase-bestemming gekozen), en je wilt de rebase afbreken.

Om dit te doen, verwijdert u eenvoudigweg alle commits en acties (dwz alle regels die niet met het # -teken beginnen) en wordt de rebase afgebroken!

De helptekst in de editor biedt eigenlijk deze hint:

# Rebase 36d15de..612f2f7 onto 36d15de (3 command(s))
#
# Commands:
# p, pick = use commit
# r, reword = use commit, but edit the commit message
# e, edit = use commit, but stop for amending
# s, squash = use commit, but meld into previous commit
# f, fixup = like "squash", but discard this commit's log message
# x, exec = run command (the rest of the line) using shell
#
# These lines can be re-ordered; they are executed from top to bottom.
#
# If you remove a line here THAT COMMIT WILL BE LOST.
#
# However, if you remove everything, the rebase will be aborted.
#          ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
# Note that empty commits are commented out

Pushen na een rebase

Soms moet je de geschiedenis herschrijven met een rebase, maar git push klaagt hierover omdat je de geschiedenis hebt herschreven.

Dit kan worden opgelost met een git push --force , maar overweeg git push --force-with-lease , wat aangeeft dat je wilt dat de push mislukt als de lokale remote-tracking branch verschilt van de branch op de remote, bijv. Iemand anders naar de afstandsbediening geduwd na de laatste ophaalactie. Dit voorkomt onbedoeld overschrijven van de recente push van iemand anders.

Opmerking : git push --force - en zelfs --force-with-lease wat dat betreft - kan een gevaarlijke opdracht zijn omdat het de geschiedenis van de branch herschrijft. Als een andere persoon aan de tak had getrokken vóór de gedwongen push, zal zijn / haar git pull of git fetch fouten bevatten omdat de lokale geschiedenis en de externe geschiedenis uiteenlopen. Dit kan leiden tot onverwachte fouten. Met voldoende kijken naar de reflogs kan het werk van de andere gebruiker worden hersteld, maar het kan tot veel verspilde tijd leiden. Als je een geforceerde push naar een branch met andere bijdragers moet doen, probeer dan met hen te coördineren zodat ze geen fouten hoeven te verwerken.

Rebase naar beneden naar de initiële commit

Sinds Git 1.7.12 is het mogelijk om terug te rebasen naar de root-commit. De root-commit is de eerste commit die ooit in een repository is gemaakt en kan normaal gesproken niet worden bewerkt. Gebruik de volgende opdracht:

git rebase -i --root

Rebasen voor een code review

Samenvatting

Dit doel is om al je verspreide commits te reorganiseren in betekenisvollere commits voor eenvoudiger codebeoordelingen. Als er te veel lagen met wijzigingen tegelijk in te veel bestanden tegelijk zijn, is het moeilijker om een code te herzien. Als je je chronologisch gemaakte commits kunt reorganiseren in actuele commits, dan is het codebeoordelingsproces eenvoudiger (en mogelijk lopen er minder bugs door het codebeoordelingsproces).

Dit te vereenvoudigde voorbeeld is niet de enige strategie om git te gebruiken om betere codebeoordelingen te doen. Het is de manier waarop ik het doe, en het is iets om anderen te inspireren om te overwegen hoe ze code-reviews en git history gemakkelijker / beter kunnen maken.

Dit toont ook pedagogisch de kracht van rebase in het algemeen aan.

In dit voorbeeld wordt ervan uitgegaan dat u weet over interactief rebasen.


Ervan uitgaand:

  • je werkt aan een feature branch off van master
  • uw functie heeft drie hoofdlagen: front-end, back-end, DB
  • je hebt veel commits gemaakt tijdens het werken aan een feature branch. Elke commit raakt meerdere lagen tegelijk
  • u wilt (uiteindelijk) slechts drie commits in uw filiaal
    • één met alle front-end wijzigingen
    • één met alle back-end wijzigingen
    • één met alle DB-wijzigingen

Strategie:

  • we gaan onze chronologische commits veranderen in "actuele" commits.
  • splits eerst alle commits in meerdere, kleinere commits - elk bevat slechts één onderwerp tegelijk (in ons voorbeeld zijn de onderwerpen front-end, back-end, DB-wijzigingen)
  • Sorteer vervolgens onze actuele commits samen en 'squash' ze in enkele actuele commits

Voorbeeld:

$ git log --oneline master..
975430b db adding works: db.sql logic.rb
3702650 trying to allow adding todo items: page.html logic.rb
43b075a first draft: page.html and db.sql
$ git rebase -i master

Dit wordt getoond in de teksteditor:

pick 43b075a first draft: page.html and db.sql
pick 3702650 trying to allow adding todo items: page.html logic.rb
pick 975430b db adding works: db.sql logic.rb

Verander het hierin:

e 43b075a first draft: page.html and db.sql
e 3702650 trying to allow adding todo items: page.html logic.rb
e 975430b db adding works: db.sql logic.rb

Dan zal git één commit per keer toepassen. Na elke commit zal het een prompt tonen, en dan kun je het volgende doen:

Stopped at 43b075a92a952faf999e76c4e4d7fa0f44576579... first draft: page.html and db.sql
You can amend the commit now, with

        git commit --amend

Once you are satisfied with your changes, run

        git rebase --continue

$ git status
rebase in progress; onto 4975ae9
You are currently editing a commit while rebasing branch 'feature' on '4975ae9'.
  (use "git commit --amend" to amend the current commit)
  (use "git rebase --continue" once you are satisfied with your changes)

nothing to commit, working directory clean
$ git reset HEAD^ #This 'uncommits' all the changes in this commit.
$ git status -s
 M db.sql
 M page.html
$ git add db.sql  #now we will create the smaller topical commits
$ git commit -m "first draft: db.sql"
$ git add page.html
$ git commit -m "first draft: page.html"
$ git rebase --continue

Dan herhaal je die stappen voor elke commit. Uiteindelijk heb je dit:

$ git log --oneline
0309336 db adding works: logic.rb
06f81c9 db adding works: db.sql
3264de2 adding todo items: page.html
675a02b adding todo items: logic.rb
272c674 first draft: page.html
08c275d first draft: db.sql

Nu voeren we nog een keer rebase uit om opnieuw te ordenen en te pletten:

$ git rebase -i master

Dit wordt getoond in de teksteditor:

pick 08c275d first draft: db.sql
pick 272c674 first draft: page.html
pick 675a02b adding todo items: logic.rb
pick 3264de2 adding todo items: page.html
pick 06f81c9 db adding works: db.sql
pick 0309336 db adding works: logic.rb

Verander het hierin:

pick 08c275d first draft: db.sql
s 06f81c9 db adding works: db.sql
pick 675a02b adding todo items: logic.rb
s 0309336 db adding works: logic.rb
pick 272c674 first draft: page.html
s  3264de2 adding todo items: page.html

KENNISGEVING: zorg ervoor dat je git rebase vertelt om de kleinere actuele commits toe te passen / pletten in de volgorde waarin ze chronologisch werden gecommitteerd . Anders kunt u valse, onnodige samenvoegconflicten hebben om mee om te gaan.

Wanneer die interactieve rebase alles gezegd en gedaan is, krijg je dit:

$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer

Samenvatting

Je hebt nu je chronologische commits omgebouwd naar actuele commits. In het echte leven hoeft u dit misschien niet elke keer te doen, maar als u dit wilt of moet doen, dan kan dat nu. Plus, hopelijk heb je meer geleerd over git rebase.

Stel git-pull in voor automatisch een rebase uitvoeren in plaats van een samenvoeging

Als je team een rebase-gebaseerde workflow volgt, kan het een voordeel zijn om git zo in te stellen dat elke nieuw gemaakte branch een rebase-operatie uitvoert, in plaats van een merge-operatie, tijdens een git pull .

Om elke nieuwe branch automatisch opnieuw in te stellen, voeg je het volgende toe aan je .gitconfig of .git/config :

[branch]
autosetuprebase = always

Opdrachtregel: git config [--global] branch.autosetuprebase always

Als alternatief kun je het git pull commando instellen om altijd te gedragen alsof de optie --rebase is doorgegeven:

[pull]
rebase = true

Opdrachtregel: git config [--global] pull.rebase true

Alle commits testen tijdens rebase

Voordat u een pull-aanvraag doet, is het handig om te controleren of compileren is geslaagd en tests zijn geslaagd voor elke commit in de branch. We kunnen dat automatisch doen met behulp van de parameter -x .

Bijvoorbeeld:

git rebase -i -x make

zal de interactieve rebase uitvoeren en stoppen na elke commit om make te voeren. In het geval dat make mislukt, zal git stoppen om je de gelegenheid te geven om de problemen op te lossen en de commit te wijzigen voordat je doorgaat met het kiezen van de volgende.

Autostash configureren

Autostash is een zeer nuttige configuratie-optie wanneer rebase wordt gebruikt voor lokale wijzigingen. Vaak moet je commits van de upstream-branch binnenhalen, maar ben je nog niet klaar om te committeren.

Git staat echter niet toe dat een rebase wordt gestart als de werkmap niet schoon is. Autostash komt te hulp:

git config --global rebase.autostash    # one time configuration
git rebase @{u}                         # example rebase on upstream branch

De autostash wordt toegepast wanneer de rebase is voltooid. Het maakt niet uit of de rebase is voltooid of wordt afgebroken. Hoe dan ook, de autostash wordt toegepast. Als de rebase succesvol was, en de basis-commit daarom is veranderd, dan kan er een conflict zijn tussen de autostash en de nieuwe commits. In dit geval moet u de conflicten oplossen voordat u begint. Dit is niet anders dan als u handmatig zou hebben opgeslagen en vervolgens toegepast, dus er is geen nadeel aan het automatisch doen.



Modified text is an extract of the original Stack Overflow Documentation
Licentie onder CC BY-SA 3.0
Niet aangesloten bij Stack Overflow