Brancher og HEAD: pekere, ikke kopier
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 switchoggit switch -canvende - 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
- Lag en branch som heter
feature, uten å bytte til den. - Bytt til
feature. - Lag en commit på
feature. - Gå tilbake til
main. - Se på commiten før den
mainpeker på, uten å stå på noen branch. - 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
- Lag en branch
docsmed én commit på.mainskal ikke flytte seg. - Gå med detached HEAD til commiten
docspeker på. Lag en commit der, og bevar den med en branchspike.docsskal 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
mainflytter 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
mainhar lagret - Fra snapshotet i commiten
mainpeker 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 featurebytter til den nye branchen.» Den lager bare navnet. Det ergit switchsom 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 mainskriver ut ID-en,git symbolic-ref HEADskriver 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.mdetter 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:
- Gi den navn før du går:
git switch -c experiment. - Bruk ID-en fra advarselen:
git branch experiment 9bc0be7. - Hvis advarselen har rullet forbi, finner
git reflogden 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.
Per-Arne's Git Good!