Meny for Per-Arne's Git Good!
Fag og prosjekt Per-Arne's Git Good!

Fast-forward: når merge bare flytter en peker

Modul 2: Branches og merge · 10 min

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 main med git merge mens du står på main anvende
  • velge mellom fast-forward og --no-ff, og forklare forskjellen i grafen vurdere
  • slette en ferdig merget branch med git branch -d anvende

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

  1. Vis grafen med alle brancher.
  2. Gå til branchen som skal ta imot arbeidet.
  3. Ta arbeidet fra feature inn i main uten å lage en ny commit.
  4. 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

  1. Teamet vil at historikken til main skal vise hvor hver ferdige feature ble merget inn. Ta docs inn i main etter den regelen.
  2. 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 feature har, 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 docs nå er på main
  • Regelen er brutt: det ble en fast-forward. git merge --no-ff docs hadde gitt merge-commiten
  • Merge feilet, så docs må 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 main ikke 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 -d sletter 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-current eller git status forteller 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..feature lister 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