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

Brancher og HEAD: pekere, ikke kopier

Modul 2: Branches og merge · 12 min

Den interaktive leksjonen trenger JavaScript. Teksten under er hele leksjonen.

Etter leksjonen kan du

  • forklare at en branch er en flyttbar peker til én commit, ikke en kopi av filene forstå
  • lage og bytte branch med git branch, git switch og git switch -c anvende
  • forutsi hvilken branch som flytter seg ved en commit, ut fra hvor HEAD står forstå
  • bevare en commit laget med detached HEAD ved å gi den en branch anvende

Forstå: Et navn som flytter seg

Mange tror at en branch er en kopi av hele prosjektmappen. Det stemmer ikke. En branch er bare et navn som peker på én commit. Her peker main på B.

git branch feature lager et nytt navn på den samme commiten. Ingen filer kopieres, og ingen commit lages. HEAD står fortsatt på main.

HEAD forteller hvilken branch du står på. git switch feature flytter HEAD over til feature. Begge navnene peker fortsatt på B, så filene er de samme.

Den nye commiten C får B som forelder. feature går til C, og main blir stående på B.

HEAD kan også peke rett på en commit i stedet for på en branch. Det kalles detached HEAD. Her peker HEAD rett på A. git switch --detach gjør dette, og det er nyttig når du vil se på en gammel versjon.

Du kan fortsatt committe. Den nye commiten D får A som forelder, men ingen branch flytter seg. Bare HEAD følger med. Bytter du bort nå, er det ingen navn som holder fast i D.

Løsningen er å gi arbeidet et navn mens du står der. git switch -c experiment lager en branch på D og bytter til den. Nå er D lett å finne igjen, og HEAD følger en branch igjen.

Se demo: Se pekerne flytte seg

Vi har to commits på main. Først lager vi en ny branch. Se på grafen: et nytt navn dukker opp på samme commit, og HEAD blir stående på main.

$ git branch feature

Nå bytter vi. Bare HEAD flytter seg. Filene er de samme, for begge navnene peker på samme commit.

$ git switch feature

Vi lager en ny fil og legger den i staging-området, akkurat som før.

$ echo "Login form" > login.txt && git add login.txt

Nå committer vi. Se grafen: bare feature flytter seg til den nye commiten, og main blir stående.

$ git commit -m "Add login form"

Vi bytter tilbake til main. Se på filområdene: login.txt forsvinner, fordi snapshotet til main ikke har den. Filen er ikke borte. Den ligger trygt i commiten på feature.

$ git switch main

Nå vil vi se på den aller første versjonen. HEAD~1 betyr commiten før den HEAD står på. Se grafen: HEAD peker nå rett på en commit, uten noen branch.

$ git switch --detach HEAD~1

Vi prøver en idé og committer den her. Se på grafen: den nye commiten får sin egen linje, og bare HEAD fulgte med. Ingen branch holder fast i den.

$ echo "Idea" > idea.txt && git add idea.txt && git commit -m "Try an idea"

Vi redder arbeidet ved å gi det et navn. git switch -c lager branchen og bytter til den i ett steg. Nå er HEAD festet til en branch igjen.

$ git switch -c experiment

Oppgaver

  1. Lag en branch som heter feature, uten å bytte til den.
  2. Bytt til feature.
  3. Lag en commit på feature.
  4. Gå tilbake til main.
  5. Se på commiten før den main peker på, uten å stå på noen branch.
  6. Ta vare på idé-commiten med en branch som heter experiment.

Øv: Overfør: en ny utviklingslinje

Et nytt repository med én commit på main. Ingen demo denne gangen — bruk det du nettopp så.

Oppgaver

  1. Lag en branch docs med én commit på. main skal ikke flytte seg.
  2. Gå med detached HEAD til commiten docs peker på. Lag en commit der, og bevar den med en branch spike. docs skal ikke flytte seg.

Sjekk deg selv: Hent det fram igjen

Du står på main og kjører git branch feature. Hvor står HEAD etterpå?

  • På feature
  • Fortsatt på main
  • Detached, rett på commiten

main, fix og docs peker alle på C, og HEAD står på fix. Du committer. Hvilke navn peker på den nye commiten?

  • Alle tre, fordi de pekte på samme commit
  • fix, og HEAD følger med
  • Ingen. Bare HEAD går videre.

Du committer med detached HEAD og bytter så til main. Hva skjer med den nye commiten?

  • Den slettes med en gang
  • Den finnes fortsatt, men ingen branch peker på den, så den er vanskelig å finne
  • main flytter seg automatisk til den

Repetisjon: Du bytter fra feature til main, og login.txt forsvinner fra mappen. Hvor får Git filene til main fra?

  • Den spiller av alle endringene fra den første commiten fram til main
  • Fra en egen kopi av mappen som main har lagret
  • Fra snapshotet i commiten main peker på

Vanlige misforståelser

  • «En branch er en kopi av prosjektmappen.» Den er et navn som peker på én commit. Filene ligger i commitene.
  • «git branch feature bytter til den nye branchen.» Den lager bare navnet. Det er git switch som flytter HEAD.
  • «Detached HEAD betyr at noe er ødelagt.» HEAD peker bare rett på en commit i stedet for på en branch. Lag en branch hvis du vil beholde det du committer der.

Les mer

Hva en branch egentlig er

En branch er en bitteliten fil som inneholder én commit-ID. HEAD inneholder vanligvis navnet på en branch, ikke en ID:

$ cat .git/HEAD
ref: refs/heads/main
$ cat .git/refs/heads/main
ff0d3edfd4234d9bbfec609f679a5274202d42a0

Når du committer, lagrer Git den nye commiten og flytter deretter branchen som HEAD navngir, dit. Det er hele mekanismen bak «branchen jeg står på, flytter seg». En ny branch koster noen få byte, uansett hvor stort prosjektet er.

Git kan pakke mange refs sammen i .git/packed-refs, så ikke bygg skript på disse filene. Spør Git i stedet: git rev-parse main skriver ut ID-en, git symbolic-ref HEAD skriver ut branchen HEAD er festet til.

Lage, bytte og liste

Kommando Virkning
git branch feature nytt navn på HEADs commit; HEAD blir stående
git branch hotfix v1.0 nytt navn på en annen commit (startpunktet)
git switch feature HEAD følger feature; staging-området og arbeidsmappen oppdateres
git switch -c feature lag og bytt i ett steg
git switch - tilbake til branchen du stod på før
git branch -v list brancher med den nyeste commiten på hver
git branch -m old new gi en branch nytt navn
$ git branch feature
$ git branch -v
  feature ff0d3ed Add contact info
* main    ff0d3ed Add contact info

Stjernen markerer branchen HEAD står på. Begge navnene viser samme ID: ingenting ble kopiert.

git checkout er den eldre kommandoen som både bytter branch og gjenoppretter filer. git switch bare bytter, og er derfor vanskeligere å bruke feil. git checkout -b feature er det samme som git switch -c feature, og du vil møte begge i veiledninger på nettet.

Hva et bytte gjør med filene dine

Et bytte fyller staging-området og arbeidsmappen med snapshotet til commiten du bytter til. En fil som bare finnes på den andre branchen, forsvinner fra mappen, men den ligger trygt i commitene på den branchen.

Endringer som ikke er committet, behandles forsiktig:

  • Hvis den endrede filen er lik på begge brancher, tar Git med endringen og skriver M README.md etter byttet.
  • Hvis byttet ville overskrevet endringen, nekter Git og gjør ingenting:
error: Your local changes to the following files would be overwritten by checkout:
    README.md
Please commit your changes or stash them before you switch branches.
Aborting

Commit endringen, legg den til side med git stash (en senere leksjon), eller angre den, og bytt så på nytt. Ikke grip etter --discard-changes eller -f: de kaster endringene dine.

Detached HEAD

git switch --detach <commit> får HEAD til å inneholde en commit-ID i stedet for et branchnavn. Det er nyttig når du vil se på en gammel versjon, kjøre gamle tester eller lete etter en feil. Den eldre git checkout <commit> gjør det samme og skriver en lang merknad som begynner med «You are in 'detached HEAD' state». git switch nekter å gå til en tag eller ID uten flagget, så du kan ikke havne der ved et uhell:

fatal: a branch is expected, got tag 'v1.0'
hint: If you want to detach HEAD at the commit, try again with the --detach option.

Du kan committe i detached HEAD. Hver nye commit flytter bare HEAD. Når du bytter bort, advarer Git:

Warning: you are leaving 1 commit behind, not connected to
any of your branches:
  9bc0be7 Try an idea

Redde en commit du gikk fra

Commiten er ikke slettet, bare uten navn. Fra enklest til mest omstendelig:

  1. Gi den navn før du går: git switch -c experiment.
  2. Bruk ID-en fra advarselen: git branch experiment 9bc0be7.
  3. Hvis advarselen har rullet forbi, finner git reflog den igjen. Det viser leksjonen om reflog.

Commits som ingen navn når, blir til slutt ryddet bort, så redd dem tidlig. Hvordan du sletter en branch trygt, ser du i leksjonen om fast-forward.

Navn på brancher

Navn kan inneholde skråstrek, og mange team bruker prefikser som feature/login eller fix/42-typo. Mellomrom, .., ~, ^, : og ? er ikke lov, fordi de tegnene betyr noe i revisjonssyntaksen: HEAD~1 er commiten før HEAD.

Offisiell dokumentasjon