Fast-forward: når merge bare flytter en peker
Den interaktive leksjonen trenger JavaScript. Teksten under er hele leksjonen.
Etter leksjonen kan du
- forutsi ut fra grafen når en merge blir en fast-forward forstå
- merge en ferdig branch inn i
mainmedgit mergemens du står påmainanvende - velge mellom fast-forward og
--no-ff, og forklare forskjellen i grafen vurdere - slette en ferdig merget branch med
git branch -danvende
Forstå: Pekeren glir fram
Du har jobbet på feature og laget to commits. main har ikke fått noe nytt i mellomtiden. Den peker fortsatt på A, der feature startet.
Følg pilene bakover fra C: først B, så A. Commiten til main er altså en stamfar til feature. Alt som er på main, finnes allerede i feature.
Git trenger ikke lage noe nytt. git merge feature skyver bare main fram til C. Det kalles en fast-forward. Ingen ny commit, og historikken er fortsatt en rett linje.
Nå peker begge navnene på samme commit. git branch -d feature sletter navnet, men ikke commitene. De er med i historikken til main. Er arbeidet ikke merget inn, nekter -d og sier ifra.
Noen team vil heller se i historikken at en feature ble merget inn. Vi går tilbake til utgangspunktet: main på A og feature på C.
git merge --no-ff feature lager nå en merge-commit M med to foreldre, A og C, selv om en fast-forward var mulig. main flytter til M. Det er et valg teamet tar, ikke et krav.
Se demo: En fast-forward i ekte Git
Vi står på feature, som har to nye commits. main står igjen på den første. Grafen er en rett linje: main ligger rett bak feature.
$ git log --oneline --graph --all
En merge tar arbeid inn i branchen du står på. Vi vil at main skal få arbeidet, så vi bytter dit først.
$ git switch main
Nå merger vi inn feature. Terminalen sier Fast-forward, og i grafen glir main fram til samme commit som feature.
$ git merge feature
feature har gjort jobben sin. Vi sletter navnet. Se grafen: lappen forsvinner, men commitene blir værende, fordi main når dem.
$ git branch -d feature
Oppgaver
- Vis grafen med alle brancher.
- Gå til branchen som skal ta imot arbeidet.
- Ta arbeidet fra
featureinn imainuten å lage en ny commit. - Slett branchen som nå er ferdig merget inn.
Øv: Overfør: velg form på historikken
Du står på docs. To brancher har hver sin commit etter main: docs er ferdig, spike er et uferdig forsøk.
Oppgaver
- Teamet vil at historikken til
mainskal vise hvor hver ferdige feature ble merget inn. Tadocsinn imainetter den regelen. - Rydd opp: slett de branchene som er ferdig merget inn i
main, og la resten stå.
Sjekk deg selv: Hent det fram igjen
Historikken er en rett linje A, B, C, D. main peker på B og feature på D. Du står på main og kjører git merge feature. Hvor mange nye commits lager Git?
- Ingen
- Én merge-commit
- Like mange som
featurehar, som kopier
Du vil at main skal få arbeidet fra feature. Hvor må du stå når du kjører git merge?
- På
feature - På
main - Det spiller ingen rolle
Hva forsvinner når du kjører git branch -d feature etter en fast-forward?
- Commitene som ble laget på
feature - Bare navnet
feature - Filene som ble lagt til på
feature
Teamet vil se hver feature som én merge-commit på main. Etter git merge docs er historikken en rett linje. Hva er riktig vurdering?
- Regelen er fulgt, fordi arbeidet fra
docsnå er påmain - Regelen er brutt: det ble en fast-forward.
git merge --no-ff docshadde gitt merge-commiten - Merge feilet, så
docsmå merges på nytt
Repetisjon: Før du merger, viser git status --short en M i den andre kolonnen for README.md. Hva betyr det?
- README.md er endret og ligger klar i staging-området
- README.md er endret i arbeidsmappen, men endringen er ikke i staging-området
- README.md er allerede merget
Vanlige misforståelser
- «En merge lager alltid en ny commit.» Når
mainikke har flyttet seg, skyves bare pekeren fram. - «Det spiller ingen rolle hvilken branch jeg står på når jeg merger.» Merge endrer bare branchen HEAD står på.
- «
git branch -dsletter arbeidet.» Den sletter bare navnet. Commitene blir værende i historikken.
Les mer
Når blir en merge en fast-forward?
git merge feature endrer bare branchen du står på. Git stiller først ett spørsmål: er commiten til branchen du står på, en stamfar (ancestor) til feature? Hvis ja, finnes alt på main allerede i feature, det er ingenting å kombinere, og Git flytter bare branchen fram. Du kan stille det samme spørsmålet selv:
$ git merge-base --is-ancestor main feature && echo "fast-forward possible"
fast-forward possible
En fast-forward skriver ut gammel og ny posisjon og et sammendrag av hva som kom inn i arbeidsmappen:
$ git merge feature
Updating df6c7db..2379bbb
Fast-forward
login.txt | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 login.txt
Ingen commit ble laget, og ingen commit ble kopiert. main navngir nå samme commit som feature.
Er det omvendt, slik at feature allerede finnes i main, svarer Git Already up to date. og gjør ingenting.
Tre måter å styre formen på
| Valg | Oppførsel |
|---|---|
--ff (standard) |
fast-forward når det går, ellers en merge-commit |
--ff-only |
fast-forward eller ingenting: nekter når linjene har skilt lag |
--no-ff |
en merge-commit også når fast-forward var mulig |
--ff-only: oppdater, aldri kombiner
Bruk det når du bare forventer å ta igjen, for eksempel når du oppdaterer din main fra teamets main. Har begge linjene nye commits, stopper Git uten å endre noe og avslutter med status 128:
$ git merge --ff-only feature
hint: Diverging branches can't be fast-forwarded, you need to either:
...
fatal: Not possible to fast-forward, aborting.
Det er ikke en feil: det trengs et ekte integrasjonsvalg, en treveis merge (neste leksjon) eller en rebase. Vil du ha dette som standard, kjør git config merge.ff only.
--no-ff: hold featuren synlig
$ git merge --no-ff feature
Merge made by the 'ort' strategy.
login.txt | 2 ++
1 file changed, 2 insertions(+)
create mode 100644 login.txt
$ git log --oneline --graph
* 4f3483e Merge branch 'feature'
|\
| * 2379bbb Style login form
| * 27a6985 Add login form
|/
* df6c7db Initial snapshot
Fordeler: commitene til én feature holdes samlet, git log --first-parent viser hver feature som er merget inn, som én merge-commit, og hele featuren kan senere angres med én git revert -m 1 av merge-commiten. Ulemper: flere commits og en travlere graf. Det er et valg teamet tar, ikke et spørsmål om rett og galt.
Squash-merge, kort fortalt
git merge --squash feature legger alle endringene fra feature i staging-området, og du lager én vanlig commit med git commit. Den har bare én forelder, så Git vet ikke at feature er merget inn, og git branch -d feature nekter senere. Sjekk med git diff main feature at ingenting mangler, og slett da med -D.
Før du merger
- Stå på branchen som skal ta imot.
git branch --show-currentellergit statusforteller deg det. En merge på feil branch flytter feil navn. - Start rent. Hvis endringer som ikke er committet, ville blitt overskrevet, nekter Git og endrer ingenting:
error: Your local changes to the following files would be overwritten by merge:
README.md
Please commit your changes or stash them before you merge.
Aborting
- Vit hva som kommer.
git log --oneline main..featurelister commitene merge vil ta inn.
Har du merget inn i feil branch, har Git lagret forrige posisjon i ORIG_HEAD. Leksjonen om reset viser hvordan du trygt flytter tilbake dit.
Rydde bort ferdige brancher
$ git branch --merged
feature
* main
$ git branch -d feature
Deleted branch feature (was 2379bbb).
git branch --merged lister brancher der alle commitene allerede finnes i branchen du står på, så -d kan slette dem trygt. git branch --no-merged lister dem som fortsatt har eget arbeid, og på dem nekter -d:
error: the branch 'spike' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D spike'
git log main..spike viser arbeidet bare spike har. Bruk -D bare når du vet at det ikke trengs. Å slette et navn sletter aldri commits som en annen branch fortsatt når.
Offisiell dokumentasjon
- git merge, særlig avsnittet om fast-forward
- Pro Git: Basic Branching and Merging
- git merge-base, git branch
Per-Arne's Git Good!