Git
omräkningar görs långt
Sök…
Syntax
-
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
parametrar
Parameter | detaljer |
---|---|
--Fortsätta | Starta ombaseringsprocessen igen efter att ha löst en sammanslagningskonflikt. |
--avbryta | Avbryt rebasoperationen och återställ HEAD till den ursprungliga grenen. Om grenen tillhandahölls när rebasoperationen startades kommer HEAD att återställas till gren. Annars återställs HEAD till var det var när rebasoperationen startades. |
--keep-tom | Håll de åtaganden som inte förändrar något från dess föräldrar i resultatet. |
--hoppa | Starta ombaseringsprocessen igen genom att hoppa över den aktuella korrigeringen. |
-m, - merge | Använd sammanslagningsstrategier för att ombasera. När den rekursiva (standard) sammanslagningsstrategin används gör det möjligt för rebase att vara medveten om namn på uppströmsidan. Observera att en rebase-sammanslagning fungerar genom att spela upp varje åtagande från arbetsgrenen ovanpå uppströmsgrenen. På grund av detta, när en sammanslagningskonflikt inträffar, är den sida som rapporteras som vår den hittills rebaserade serien, börjar med uppströms, och deras är den fungerande grenen. Med andra ord byts sidorna ut. |
--statistik | Visa en diffstat av vad som har ändrats uppströms sedan den sista rebasen. Diffstat styrs också av konfigurationsalternativet rebase.stat. |
-x, - exec- command | Utför interaktiv rebas, stopp mellan varje begå och utföra command |
Anmärkningar
Kom ihåg att omformering effektivt skriver om lagringshistoriken.
Omplaceringskommittéer som finns i fjärrförvaret kan skriva om lagringsnoder som används av andra utvecklare som basnod för deras utveckling. Om du inte riktigt vet vad du gör, är det en bra praxis att rebasera innan du trycker på dina förändringar.
Lokal grenåterföring
Omlastning tillämpar på nytt en serie åtaganden ovanpå ett annat åtagande.
För att rebase
en gren igen, kolla in grenen och sedan rebase
den ovanpå en annan gren.
git checkout topic
git rebase master # rebase current branch onto master branch
Detta skulle orsaka:
A---B---C topic
/
D---E---F---G master
Att bli:
A'--B'--C' topic
/
D---E---F---G master
Dessa operationer kan kombineras till ett enda kommando som kontrollerar grenen och omlagdar omedelbart den:
git rebase master topic # rebase topic branch onto master branch
Viktigt: Efter omfasen har de tillämpade åtagandena en annan hash. Du bör inte omklassificera åtaganden som du redan har drivit till en fjärrvärd. En konsekvens kan vara en oförmåga att git push
din lokala ombaserade filial till en avlägsen värd, vilket lämnar ditt enda alternativ att få git push --force
.
Rebase: vår och deras, lokala och avlägsna
En rebase byter innebörden av "vår" och "deras":
git checkout topic
git rebase master # rebase topic branch on top of master branch
Vad HEAD pekar på är "vårt"
Det första en rebase gör är att återställa HEAD
att master
; innan körsbärsplockning förbinder sig från det gamla topic
till ett nytt (varje åtagande i den tidigare topic
kommer att skrivas om och kommer att identifieras med en annan hash).
Med avseende på terminologier som används av sammanslagningsverktyg (inte förväxlas med lokal ref eller fjärrref )
=> local is master ("ours"),
=> remote is topic ("theirs")
Det betyder att ett sammansättnings- / diff-verktyg kommer att presentera uppströmsgrenen som local
( master
: den gren ovanpå vilken du rebaserar), och arbetsgrenen som remote
( topic
: grenen som omföras)
+-----------------------------------------+
| LOCAL:master | BASE | REMOTE:topic |
+-----------------------------------------+
| MERGED |
+-----------------------------------------+
Inversion illustrerad
Vid en sammanslagning:
c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
\
\
\--y--y--y <- other branch to merge
Vi ändrar inte det aktuella topic
, så det vi har är fortfarande det vi arbetade med (och vi går samman från en annan gren)
c--c--x--x--x---------o(*) MERGE, still on branch topic
\ ^ /
\ ours /
\ /
--y--y--y--/
^
theirs
På en rebase:
Men vid en rebase byter vi sidor eftersom det första en rebase gör är att kassera uppströmsgrenen för att spela upp de aktuella åtagandena ovanpå den!
c--c--x--x--x(*) <- current branch topic ('*'=HEAD)
\
\
\--y--y--y <- upstream branch
En git rebase upstream
kommer först att sätta HEAD
till uppströmsgrenen, därmed växeln till "vår" och "deras" jämfört med den tidigare "nuvarande" arbetsgrenen.
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
Återförsatsen kommer sedan att spela upp "sina" åtaganden på den nya "vår" topic
:
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
Interaktiv rebase
Detta exempel syftar till att beskriva hur man kan använda git rebase
i interaktivt läge. Det förväntas att man har en grundläggande förståelse för vad git rebase
är och vad det gör.
Interaktiv rebas initieras med följande kommando:
git rebase -i
Alternativet -i
avser interaktivt läge . Med hjälp av interaktiv rebase kan användaren ändra engagemang, samt ordna om, dela och / eller squash (kombinera till ett).
Säg att du vill ordna om de tre senaste åtagandena. För att göra detta kan du köra:
git rebase -i HEAD~3
Efter att du har utfört ovanstående instruktion öppnas en fil i din textredigerare där du kan välja hur dina åtaganden ska ombaseras. I det här exemplet ändrar du bara ordningen på dina åtaganden, sparar filen och stänger redigeraren. Detta kommer att initiera en rebas med den ordning du har tillämpat. Om du kontrollerar git log
ser du dina åtaganden i den nya ordningen du angav.
Omlägga meddelande om engagemang
Nu har du beslutat att ett av åtagandemeddelandena är vagt och att du vill att det ska vara mer beskrivande. Låt oss undersöka de tre sista åtagandena med samma kommando.
git rebase -i HEAD~3
Istället för att ordna om ordningen kommer åtagandena att återinföras, den här gången kommer vi att ändra pick
, standard, för att reword
på ett åtagande där du vill ändra meddelandet.
När du stänger redigeraren initieras omfasen och den stannar vid det specifika åtagandemeddelandet som du ville omformulera. Detta låter dig ändra åtagandemeddelandet till vad du än önskar. När du har ändrat meddelandet stänger du bara redigeraren för att fortsätta.
Ändra innehållet i en åtagande
Förutom att du ändrar åtagandemeddelandet kan du också anpassa de ändringar som gjorts av åtagandet. För att göra det, ändra bara pick
att edit
för en åtagande. Git kommer att sluta när det anländer till det åtagandet och tillhandahåller de ursprungliga ändringarna av åtagandet i iscenesättningsområdet. Du kan nu anpassa dessa ändringar genom att avinställa dem eller lägga till nya ändringar.
Så fort sceneringsområdet innehåller alla ändringar du vill ha i det åtagandet, begå ändringarna. Det gamla åtagandemeddelandet visas och kan anpassas för att återspegla det nya åtagandet.
Dela upp ett enda engagemang i flera
Säg att du har gjort ett åtagande men beslutat vid ett senare tillfälle att detta åtagande skulle kunna delas upp i två eller flera åtaganden istället. Använd samma kommando som tidigare, ersätt pick
stället för edit
istället och tryck på enter.
Nu kommer git att stanna vid åtagandet du har markerat för redigering och placera allt dess innehåll i iscenesättningsområdet. Från den punkten kan du köra git reset HEAD^
att placera engagemanget i din arbetskatalog. Sedan kan du lägga till och begå dina filer i en annan sekvens - i slutändan dela upp ett enda engagemang i n åtaganden istället.
Squash flera åtaganden till en
Säg att du har gjort lite arbete och har flera åtaganden som du tror kan vara en enda åtagande istället. För det kan du utföra git rebase -i HEAD~3
och ersätta 3
med ett lämpligt antal åtaganden.
Denna gång byt ut pick
med squash
istället. Under rebaset kommer de åtaganden som du har instruerat att klämmas ut att krossas ovanpå det tidigare åtagandet; förvandla dem till ett enda åtagande istället.
Avbryta en interaktiv rebase
Du har startat en interaktiv rebas. I redaktören där du väljer dina åtaganden, bestämmer du dig för att något går fel (till exempel saknar en åtagande, eller så valde du fel rebasdestination), och du vill avbryta rebasen.
För att göra detta, helt enkelt ta bort alla åtaganden och åtgärder (dvs alla rader som inte börjar med #
-tecknet) och omfasen avbryts!
Hjälptexten i redaktören ger faktiskt detta tips:
# 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
Pushing efter en återföring
Ibland behöver du skriva om historik med en omfasning, men git push
klagar över att göra det eftersom du skrivit om historien.
Detta kan lösas med en git push --force
, men git push --force
git push --force-with-lease
, vilket indikerar att du vill att push ska misslyckas om den lokala fjärrspårningsgrenen skiljer sig från grenen på fjärrkontrollen, t.ex. annars tryckte till fjärrkontrollen efter den senaste hämtningen. Detta undviker oavsiktligt att skriva över någon annans senaste push.
Obs : git push --force
- git push --force
- och till och med - --force-with-lease
för den delen - kan vara ett farligt kommando eftersom det skriver om filialens historia. Om en annan person hade dragit grenen innan den tvingade pushen, kommer hans / hennes git pull
eller git fetch
ha fel eftersom den lokala historien och fjärrhistoriken är divergerade. Detta kan orsaka att personen har oväntade fel. Med noggrann titt på refloggarna kan den andra användarens arbete återvinnas, men det kan leda till mycket slösad tid. Om du måste göra ett tvingat tryck till en gren med andra bidragsgivare, försök att samordna med dem så att de inte behöver hantera fel.
Avfas ner till det första åtagandet
Sedan Git 1.7.12 är det möjligt att rebasera ner till root commit. Rotåtagandet är det första åtagandet som någonsin gjorts i ett arkiv och kan normalt inte redigeras. Använd följande kommando:
git rebase -i --root
Omfasning innan en kodgranskning
Sammanfattning
Detta mål är att omorganisera alla dina spridda åtaganden till mer meningsfulla åtaganden för enklare kodgranskningar. Om det finns för många lager av ändringar över för många filer på en gång är det svårare att göra en kodgranskning. Om du kan omorganisera dina kronologiskt skapade åtaganden till aktuella åtaganden är kodöversynsprocessen enklare (och kanske mindre buggar glider genom kodöversynsprocessen).
Detta alltför förenklade exempel är inte den enda strategin för att använda git för att göra bättre kodrecensioner. Det är så jag gör det, och det är något att inspirera andra att överväga hur man kan göra kodrecensioner och göra historien lättare / bättre.
Detta demonstrerar också pedagogiskt kraften i omprövning i allmänhet.
Det här exemplet antar att du vet om interaktiv omplacering.
Förutsatt:
- du arbetar på en funktionsgren utanför mästaren
- din funktion har tre huvudlager: front-end, back-end, DB
- du har gjort många åtaganden medan du arbetar med en funktionsfilial. Varje åtkomst berör flera lager på en gång
- du vill (till slut) bara tre åtaganden i din gren
- en som innehåller alla ändringar i frontend
- en som innehåller alla ändringar på baksidan
- en som innehåller alla DB-ändringar
Strategi:
- vi kommer att ändra våra kronologiska åtaganden till "aktuella" åtaganden.
- först dela alla åtaganden i flera, mindre åtaganden - var och en innehåller bara ett ämne åt gången (i vårt exempel är ämnena frontend, back end, DB-ändringar)
- Ordna sedan våra aktuella åtaganden tillsammans och "squash" dem till enstaka aktuella åtaganden
Exempel:
$ 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
Detta kommer att visas i textredigeraren:
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
Ändra det till detta:
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
Sedan kommer git att tillämpa en åtagande i taget. Efter varje åtagande kommer det att visa en prompt, och sedan kan du göra följande:
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
Sedan upprepar du dessa steg för varje åtagande. Till slut har du det här:
$ 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 kör vi omklassning en gång till för att ordna och squash:
$ git rebase -i master
Detta kommer att visas i textredigeraren:
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
Ändra det till detta:
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
ANMÄRKNING: se till att du ber om att git rebase ska tillämpa / klämma in de mindre aktuella åtagandena i den ordning de kronologiskt begick . Annars kan du ha falska, onödiga sammanslagningskonflikter att hantera.
När det interaktiva omslaget är allt sagt och gjort, får du detta:
$ git log --oneline master..
74bdd5f adding todos: GUI layer
e8d8f7e adding todos: business logic layer
121c578 adding todos: DB layer
Recap
Du har nu omfördelat dina kronologiska åtaganden till aktuella åtaganden. I verkligheten kanske du inte behöver göra det varje gång, men när du vill eller behöver göra det, nu kan du göra det. Dessutom har du förhoppningsvis lärt dig mer om git rebase.
Ställ in git-pull för att automatiskt utföra en ombas istället för en sammanslagning
Om ditt team följer ett rebasebaserat arbetsflöde kan det vara en fördel att ställa in git så att varje nyskapade gren kommer att utföra en rebasningsoperation, istället för en sammanslagningsoperation, under en git pull
.
Om du vill ställa in varje ny gren så att den automatiskt sänds igen lägger du till följande i din .gitconfig
eller .git/config
:
[branch]
autosetuprebase = always
Kommandorad: git config [--global] branch.autosetuprebase always
Alternativt kan du ställa in git pull
kommandot så att det alltid fungerar som om alternativet --rebase
har passerat:
[pull]
rebase = true
Kommandorad: git config [--global] pull.rebase true
Testa alla åtaganden under omfasning
Innan du gör en dragförfrågan är det användbart att se till att kompilering är framgångsrik och tester passerar för varje åtagande i grenen. Vi kan göra det automatiskt med -x
parametern.
Till exempel:
git rebase -i -x make
kommer att utföra den interaktiva omstarten och stoppa efter varje åtagande att utföra make
. Vid make
misslyckas kommer git sluta att ge dig en möjlighet att åtgärda problemen och ändra begå innan du fortsätter med att plocka nästa.
Konfigurera autostash
Autostash är ett mycket användbart konfigurationsalternativ när du använder rebase för lokala ändringar. Ofta kan du behöva ta in åtaganden från uppströmsgrenen, men är inte redo att begå ännu.
Git tillåter emellertid inte att en rebas startar om arbetskatalogen inte är ren. Autostash till undsättning:
git config --global rebase.autostash # one time configuration
git rebase @{u} # example rebase on upstream branch
Autostasten kommer att tillämpas när rebasen är klar. Det spelar ingen roll om omfasen slutförts framgångsrikt eller om den avbryts. Hursomhelst kommer autostasten att tillämpas. Om rebasen var framgångsrik och basåtagandet därför har ändrats, kan det vara en konflikt mellan autostash och de nya åtagandena. I det här fallet måste du lösa konflikterna innan du begår. Detta är inte annorlunda än om du manuellt skulle ha stashat och sedan applicerat, så det finns ingen nackdel med att göra det automatiskt.