Den dag jeg ødelagde hele historikken med et forkert rebase

Den dag jeg ødelagde hele historikken med et forkert rebase

Git rebase er ikke farlig magi. Det er bare et meget skarpt værktøj, der kan skære utrolig rent, hvis du ved hvad du laver – og rigtig grimt, hvis du ikke gør.

Hvad git merge faktisk gør ved din historik

Jeg starter med merge, fordi det er det mindst dramatiske. Merge ændrer ikke på gamle commits, den lægger bare nyt ovenpå.

Forestil dig at du har en main og en feature-branch feature-a:

main:    A --- B --- C
                    
feature:             D --- E

Når du kører:

git checkout main
git merge feature-a

ender du typisk med noget i stil med:

main:    A --- B --- C ------- M
                           /
feature:             D --- E

M er et merge-commit. Historikken er bevaret:

  • Commits A, B, C, D og E er stadig præcis som før
  • Ingen commit-hashes er ændret
  • Alle kan stadig finde rundt i historikken, hvis de sad på en ældre branch

Fordele ved merge:

  • Sikkert i teams, fordi du ikke omskriver historik
  • Nemt at se hvor og hvornår branches er blevet flettet
  • God standard, hvis I ikke har aftalt noget særligt

Ulempen: historikken kan blive ret “zigzag” med mange merge-commits. Det er ikke forkert, bare lidt tungt at læse.

Hvad git rebase gør ved din historik

Rebase gør noget helt andet: det flytter dine commits, som om de var lavet oven på en anden base-commit. Historikken bliver omskrevet.

Samme udgangspunkt:

main:    A --- B --- C
                    
feature:             D --- E

Du står på feature-a og kører:

git rebase main

Efter en vellykket rebase vil din graf ligne:

main:    A --- B --- C
                        
feature:                 D' --- E'

Her er pointen: D’ og E’ er nye commits. De har nye hashes. Indholdet kan være det samme, men Git betragter dem som nye.

Fordele ved rebase:

  • Historikken bliver lineær og pæn
  • Nemt at læse “hvad skete i hvilken rækkefølge”
  • Godt til at rydde op i egne rodede commits, før du deler dem

Ulempe: du omskriver historik. Hvis andre bygger ovenpå de commits du rebaser, kan du ødelægge deres verden ret effektivt.

3 typiske situationer – rebase eller merge?

1. Opdatér din feature-branch fra main

Scenario: Du har arbejdet på feature-a i nogle dage. Imens er der landet nye commits på main. Du vil lige have det nyeste ind, før du fortsætter.

Her har du to muligheder:

Løsning med merge (sikker, lidt mere støj)

git checkout feature-a
git merge main

Fordele:

  • Risikofri historikmæssigt
  • Godt, hvis du er ny i Git eller hvis teamet ikke bruger rebase

Ulempe: du kan ende med mange små merge-commits, som primært siger “merge main into feature-a”.

Løsning med rebase (pænere historik, kræver disciplin)

git checkout feature-a
git fetch origin
git rebase origin/main

Det betyder: tag alle dine feature-commits og læg dem oven på den nyeste main.

Jeg bruger selv rebase her, når:

  • Jeg er den eneste på branch’en
  • Jeg ikke har delt branch’en med andre endnu (ingen har pull’et den)

Har du allerede pushet og ved at andre bruger branch’en, så vælg merge i stedet. Det skaber mindre rod for de andre.

2. Ryd op i dine commits før en pull request

Scenario: Du har 17 commits der hedder ting som “fix again”, “oops” og “debug”. Koden er fin, men historikken er pinlig. Du vil sende en pull request til review.

Her er interaktiv rebase guld.

Rebase interactive til at squash’e commits

Stå på din feature-branch:

git rebase -i origin/main

Git åbner en editor med noget i stil med:

pick a1b2c3 Tilføj formular
pick d4e5f6 Fix validering
pick 123abc Debug log
pick 456def Fjern debug log

Nu kan du:

  • Skifte pick til squash for commits der skal slås sammen med den forrige
  • Skifte pick til reword for at ændre commit-beskeden

Eksempel, hvis du vil samle de sidste tre til ét commit:

pick a1b2c3 Tilføj formular
squash d4e5f6 Fix validering
squash 123abc Debug log
squash 456def Fjern debug log

Efter rebase ender du med én ren historik, fx:

a7c9d1 Tilføj formular med validering

Det gør review meget rarere, både for dig og for alle andre. Færre støj-commits.

Vigtigt: gør den her oprydning før du begynder at dele branch’en bredt. Den omskriver historik, så samme regel som før: ikke gør det på noget, andre allerede bygger ovenpå.

3. Når I er flere på samme branch (det du ikke skal gøre)

Scenario: Du og en kollega arbejder begge på feature-a. I har begge pull’et den ned, og I pusher løbende.

Her er min regel:

  • Brug merge til at få main ind
  • Brug ikke rebase til at omskrive fælles commits

Hvis du rebaser en branch, som andre også arbejder på, sker der typisk det her:

  • Du rebaser lokalt og pusher med --force
  • Din kollega har stadig de gamle commits lokalt
  • Når de prøver at pushe, får de konflikter, mærkelige divergenser og generel forvirring

Så som team-regel: rebase kun på branches, du “ejer” alene, medmindre I er meget, meget enige om hvad I laver.

Konkrete kommandoer du kan copy/paste

Opdatér feature-branch med merge

# Sørg for at have nyeste main
git checkout main
git pull origin main

# Tilbage til din branch
git checkout feature-a

# Merge main ind i feature
git merge main

Opdatér feature-branch med rebase

# Hent nyeste main, uden at skifte branch
git fetch origin

# Stå på din feature-branch
git checkout feature-a

# Læg dine commits oven på origin/main
git rebase origin/main

Ryd op i commits med interaktiv rebase

# Stå på din feature-branch
git checkout feature-a

# Rebase interaktivt mod origin/main
git rebase -i origin/main

# Følg instruktionerne i editoren

Hvis du vil læse lidt mere om hvad de forskellige rebase-flags gør, er den officielle git rebase dokumentation faktisk ret god, når man først har prøvet det i praksis et par gange.

Konflikter: sådan kommer du igennem uden panik

Konflikter er ikke en fejl i sig selv. De er bare Git der siger: “jeg kan ikke gætte, hvad du vil”.

Typisk konflikt-flow ved rebase

Du kører:

git rebase origin/main

og får noget ala:

CONFLICT (content): Merge conflict in src/Login.js

Nu er rebase pauset. Din opgave:

  1. Åbn filen med konflikt (fx i VS Code)
  2. Find konflikt-markeringerne:
<<<<<<< HEAD
kode fra main
=======
kode fra din commit
>>>>>>> feature-commit
  1. Ret koden, så den er som du vil have den (uden markeringer)
  2. Gem filen
  3. Marker konflikten som løst:
git add src/Login.js
  1. Fortsæt rebase:
git rebase --continue

Hvis næste commit også giver konflikt, gentager du processen. Til sidst er rebase færdig.

Hvis du fortryder midt i en rebase

Hvis du sidder fast, og det hele føles forkert, så afbryd:

git rebase --abort

Så vender Git tilbage til den tilstand, du var i, før du startede rebase. Brug det. Det er ikke snyd.

Hvis du vil træne konflikter uden at ødelægge noget vigtigt, så lav et lille test-repo lokalt og øv dig. Det lyder kedeligt, men det gør dig meget roligere, når det sker “rigtigt”. Du kan fx kombinere det med at lære andre Git-kommandoer, som vi også er inde på i vores indlæg om Git og versionsstyring, hvis du vil bygge dit fundament lidt op.

5 simple regler for git rebase vs merge

Hvis jeg skulle skrive en lille team-plakat, ville den se sådan ud:

  1. Brug merge til fælles branches og til at flette feature ind i main.
  2. Brug rebase til dine egne branches, før du laver pull request.
  3. Rebase aldrig en branch, som andre allerede bygger ovenpå (medmindre I er helt enige om processen).
  4. Hvis du er i tvivl, så vælg merge. Det er næsten altid sikrere.
  5. Lær git rebase -i i et lille test-repo. Når du først er tryg ved det, bliver din historik markant pænere.

Hvis du har lyst til at kæde det her sammen med resten af dit workflow, kan du med fordel kombinere det med branch-strategier og pull requests. Mange af de samme principper går igen i andre emner, vi skriver om, fx når vi arbejder med samarbejde og versionsstyring i større projekter.

Hvis du kun gør én ting anderledes efter at have læst det her, så beslut en klar regel for dig selv: “jeg rebaser kun på branches, jeg ejer alene” og hold fast i den.

Stop med yderligere pushes og koordiner med teamet. Brug git reflog og git fsck på den maskine, der havde de gamle commits, eller få kolleger til at dele deres lokale refs; du kan oprette en recovery-branch fra et gammelt hash (git branch recover ) og så enten pushe den eller lave en merge/revert, så ingen taber arbejde. Undgå at overskrive remote igen uden at være sikker - kommunikation før en ny force-push er afgørende.
Ja - --force-with-lease er mere defensiv, fordi den fejler hvis remote har ændret sig siden du sidst hentede, så den mindsker risikoen for at overskrive andres arbejde. Kombiner det med branch protection i fjernlaget (for eksempel at slå force-push fra på main) og gode teamregler om hvem der må rebase og force-pushe.
Når der er konflikt, ret filerne, kør git add og så git rebase --continue; hvis du vil opgive rebasen og gå tilbage til udgangspunktet, kør git rebase --abort. Hvis du har ændringer du vil gemme midlertidigt, brug git stash før du starter rebasen.
Brug git rebase -i (fx git rebase -i origin/main) når du vil slå commits sammen, omarrangere eller ændre beskeder på dine lokale commits. I editoren skifter du 'pick' til 's' eller 'squash' for at fusionere commits, gemmer og følger op med en samlet commit-besked.

Sara Vestergaard er selvlært kode-nørd, der stille og roligt er gået fra at rode med en enkelt HTML-side til at bygge små værktøjer, scripts og hjemmesider til sig selv og vennerne. Hun startede med at lave en simpel band-hjemmeside som teenager og opdagede, hvor tilfredsstillende det er, når noget, du har skrevet, pludselig lever på skærmen.

For Sara handler kodning ikke om store ord eller imponerende titler, men om meget konkrete problemer: den kedelige opgave, der tager for lang tid, den ven der mangler en lille porteføljeside, eller den liste, der burde sortere sig selv. Hun elsker at pille ting fra hinanden – også kode – for at se, hvad der egentlig foregår, og hun har brugt utallige aftener på at google fejlbeskeder, teste små eksempler og langsomt bygge sin forståelse op.

På Coding Class deler hun den tilgang videre. Hun skriver til dig, der gerne vil lære at kode ved at gøre det i praksis: små projekter, korte kodebidder og forklaringer, der hænger sammen med det, du faktisk sidder med på skærmen. Hun skærer ind til benet, viser typiske fejl og deres løsninger og giver altid et forslag til, hvordan du kan bygge en tand videre, når grundideen først virker.

Når hun ikke skriver til Coding Class eller nørkler med nye små projekter, hænger Sara på klatrevæggen, vander sine altanplanter eller spiller gamle Nintendo-spil. Men hun ender næsten altid tilbage ved tasterne – for der er altid endnu en lille ting, der kunne være smartere, hurtigere eller bare lidt sjovere at bruge.

Send kommentar

You May Have Missed