Git er et særdeles kraftig verktøy med et notorisk dårlig brukergrensesnitt, og hvis du gjør en feil kan det være vanskelig å vite hvordan man kommer deg ut av situasjonen. Har du for eksempel noen gang opplevd at du har blitt sittende med en enorm commit som har alt for mange endringer i seg? Eller har du slettet endringene du har gjort ved med en uheldig git reset
? Heldigvis finnes det muligheter for å komme seg ut av slike situasjoner, men kommandoene man kan bruke er ofte underkommunisert.
Dagens luke tar for derfor for seg noen mindre brukte og diskuterte git-kommandoer som lar deg finne feil, rydde opp, og generelt gjøre det lettere å jobbe med Git.
Bisect
Vi starter med den minst obskure kommandoen: git bisect
(dette er den eneste som er representert i hjelpeteksten som dukker opp hvis man skriver git
i kommandolinjen). Poenget med bisect er å raskt finne ut hvilken commit en endring har oppstått i, og er spesielt nyttig for å finne når og hvor bugs har blitt introdusert i kodebasen. Måten git bisect
funker på er som et slags interaktivt binærsøk gjennom commit-historikken:
For å sette i gang en bisect skriver du git bisect start
. Deretter må du si hvilken del av historikken du ønsker å søke i, ved å si en commit du vet feilen skjer i, og en du vet feilen ikke skjer i. Vet du f.eks. at feilen har oppstått i endringer du har gjort som ikke har havnet i main
enda, bruker du git bisect bad
og git bisect good main
.
Du blir så plassert på commiten midt mellom den nåværende commiuen og main
. Sjekk om feilen finnes her, og skriv git bisect good
hvis feilen er borte, eller git bisect bad
hvis feilen fortsatt er der. Igjen blir du plassert på commiten midt mellom siste commit du merket som good
og siste commit du merket som bad
, og du fortsetter å søke gjennom commitene til du sitter igjen med commiten hvor feilen oppsto. Du kan alltid skrive git bisect visualize
for å se hvilke commits som er igjen mellom sist markerte good
og bad
commit.
Bisect fungerer spesielt bra der man har et utviklingsmiljø med noen form for hot reloading, f.eks. i frontendprosjekter med en automatisk oppdaterende uteiklingsserver kjørende. Si du ønsker å finne ut hvilken endring som ble gjort som fører til at et skjema ikke lenger er responsivt på mobil: Navigér til skjemaet og velg responsiv modus med en enhet som knekker designet, og så er det bare å se i nettleservinduet og skrive git bisect good
eller git bisect bad
til du finner commiten hvor feilen oppsto.
Interaktiv rebase
Rebasing gjennom git rebase
lar deg plassere alle commitene i en branch på toppen av commitene i en annen branch, og er et enkelt og greit alternativ til å merge. Slenger man på ett lite parameter får man noe helt annet: git rebase -i
lar deg herje med commitene dine, ved å omstrukturere, slette, endre og samle commits. Måten interaktiv rebase fungerer på er at du redigerer en fil som lister ut alle commitene, som når den lagres og lukkes gjennomfører endringene du har spesifisert. Skriver du f.eks. git rebase -i HEAD~5
skal editoren din åpne seg med en liste over de siste 5 commitene. Det vil se ca. slik ut:
pick 38a30ac5 fix: This commit fixed a bug part 2
pick 2c95d8f1 fix: This commit fixed a bug part 1
pick 3b23eb1d feat: This commit added a feature
pick e29fc828 refactor: Move some code around
pick 123e9d1b refactor: Format some code
Etter committene kommer en kommentar som beskriver hvilke operasjoner du kan gjøre.
For å endre på rekkefølgen flytter du linjene opp og ned, og for å gjøre operasjonene endrer du pick
til f.eks. fixup
eller drop
. Når du lagrer kjøres alle endringene dine.
Her er noen caser hvor interaktiv rebasing er nyttig:
Du har en endring du vil ha med i en tidligere commit, men har gjort en annen commit i mellomtiden: Commit de nyeste endringene dine, og
git rebase -i HEAD~3
for å interaktivt rebase de tre siste commitene. Endre rekkefølgen på de to øverste linjene, og skrivfixup
som kommando på den siste commiten du lagde (som nå er nummer 2 i rekken).Du ønsker å splitte en commit du gjorde for 3 commiter siden i to commits:
git rebase -i HEAD~3
, endre den øverste (eldste) commiten tiledit
, og lukk editoren. Du kan nå redigere commiten din. For å dele den opp, kan du f.eks.git reset HEAD~1
, og stage/commite endringene slik du ønsker. For at endringene skal gjelde, skriver dugit rebase —continue
.Du har startet en branch en annen branch enn fra
main
-branchen, og ønsker å fjerne de overflødige commitene:git reset -i main
, og sett kommando på de overflødige commitene tild
(forkortelse fordrop
, alle forkortelsene står i kommentaren når man gjennomfører en rebase).
Reflog
Noen ganger er man uheldig og gjør noe som er vanskelig å reversere i git. Da er git reflog
en reddende engel. Refloggen er en historikk over alle endringene som er gjort i et git-repository, og alle endringene kan sjekkes ut som om de var en commit. For å vise refloggen, bruker du kommandoen git reflog
, som gir deg en liste over alle endringene som er gjort. Hver linje viser en endring på følgende form:
86ea836b HEAD@{2}: checkout: moving from main to 86ea836bb03fc29f6aa20dde697084d1aeaf331b
Første ledd er en hash som identifiserer endringen, etterfulgt av navnet på endringen. Den nyeste endringen heter HEAD@{0}
, den forrige heter HEAD@{1}
, og så videre. Man kan sjekke ut disse, f.eks. vil git checkout HEAD@{8}
plassere deg 8 endringer tilbake i tid. Etter navnet på endringen kommer en beskrivelse av endringen som ble gjort.
Her er et par eksempelsituasjoner hvor refloggen kan komme til hjelp:
* Du har resatt en branch og vil ha tak i enkelte endringer som ble gjort før du resatte: git checkout HEAD@{1}
for å gå tilbake tilbake til forrige endring, og kopiér det du trenger fra filene der. git checkout -
tar deg tilbake til nåtiden, og du kan lime inn endringene du trenger der.
* Du har gjennomført en rebase med mergekonflikter valgte feil i konfliktene: Sjekk med git reflog
når du begynte rebasen og git reset —hard HEAD@{N}
, hvor N er tallet som hører til endringen når rebasen begynte. Så kan du rebase på nytt og gjøre de riktige valgene.
* Du har amendet alle kodeendringene dine inn i forrige commit istedenfor å lage en ny commit: git reset —mixed HEAD@{1}
for å angre endringen som ble gjort og gjøre det mulig å stage kodeendringene på nytt.