GuideGit

Git reflog: hitta en förlorad commit efter AI-agentens reset eller rebase

Hitta en commit som försvann efter en AI-agents reset eller rebase med git reflog, kontrollera den med git show och återställ den på en ny gren.

Publicerad · Senast granskad

Svarta metallskenor på en mörk yta där en böjd skena med grön ljuskant viker av från huvudspåret, med små etsade mönster längs den bortre kanten.
Reflog är spåret bakåt: den visar var grenen pekade innan den flyttades.
Kort sagt

När en AI-agent har kört reset --hard, rebase eller bytt gren kan en commit se borta ut fast den ofta finns kvar lokalt. git reflog visar var HEAD och grenarna har pekat. Hitta rätt post, kontrollera den med git show och lägg den på en ny gren i stället för att göra ytterligare en reset. Ändringar som inte committades går inte att hämta den vägen.

1. Vad reflog kan rädda

Du bad en AI-agent städa upp grenen. Efteråt saknas din senaste commit i git log. Enligt dokumentationen för git reflog registrerar referensloggarna när topparna för grenar och andra referenser uppdaterades i det lokala repot. Commiten ligger alltså ofta kvar som objekt, och reflogposten pekar fortfarande på den. Manualen för git gc anger att skräpsamlingen behåller objekt som refereras från reflogs, även commits på grenar som senare skrivits om eller spolats tillbaka.

Guiden gäller lokala commits. Ska en felaktig ändring som redan är delad tas bort följer du i stället guiden om Git revert. Vet du inte vilken commit som införde felet hjälper Git bisect för AI-fel. Ska du rekonstruera en hel incident med loggar från flera system är artikeln om AI-agentfel i produktion bredare. Här gör du bara en sak: hittar en försvunnen commit och lägger den på en ny gren.

Kör proven i PowerShell, block för block i samma fönster. Det första blocket skapar ett nytt repo med slumpat namn i din temporärmapp. Ingen server och inget befintligt projekt ingår. Stanna om ett kommando misslyckas och läs felet innan du går vidare.

2. Skapa övningsrepot med tre commits

$provKatalog = Join-Path ([IO.Path]::GetTempPath()) ('reflog-prov-' + [guid]::NewGuid().ToString('N'))
New-Item -ItemType Directory -Path $provKatalog | Out-Null
Set-Location -LiteralPath $provKatalog
Get-Location
git --version
git init --quiet -b main
if ($LASTEXITCODE -ne 0) { throw 'Init misslyckades' }
git config user.name 'Reflog Test'
git config user.email 'reflog@example.invalid'
git config core.autocrlf false
git config core.hooksPath "$provKatalog/.git/empty-hooks"
$utf8 = New-Object System.Text.UTF8Encoding($false)
foreach ($steg in 'ett', 'tva', 'tre') {
  [IO.File]::WriteAllText("$provKatalog/steg.txt", "steg $steg`n", $utf8)
  git add -- steg.txt
  git commit --quiet -m "Steg $steg"
  if ($LASTEXITCODE -ne 0) { throw 'Commit misslyckades' }
}
git log --oneline

Kontrollera att Get-Location visar den nya katalogen. Facit är tre rader i loggen med Steg tre överst. Dina förkortade hashvärden blir andra än i guiden, eftersom de beror på bland annat tidpunkt. Jämför därför meddelandena, inte siffrorna.

3. Låt en reset --hard ta bort den senaste

git reset --hard HEAD~1
git log --oneline
Get-Content -LiteralPath ./steg.txt

Det här är steget en agent kan ta när den vill börja om från förra versionen. Enligt manualen för git reset skriver --hard över filerna med versionen från målcommiten och uppdaterar indexet så att inget är staged. I provet pekar main nu på Steg tva. Loggen visar två commits och filen innehåller steg tva. Steg tre syns inte längre i den vanliga historiken.

4. Läs reflog: HEAD@{n}, handling och meddelande

git reflog -5

Så här såg utdata ut i redaktionens körning:

069a666 HEAD@{0}: reset: moving to HEAD~1
0844646 HEAD@{1}: commit: Steg tre
069a666 HEAD@{2}: commit: Steg tva
8335d5c HEAD@{3}: commit (initial): Steg ett

Läs uppifrån. HEAD@{0} är nuläget och HEAD@{1} är där HEAD stod en förflyttning tidigare; dokumentationen beskriver HEAD@{2} som där HEAD var för två förflyttningar sedan. Texten efter kolon anger handlingen: commit, reset, checkout eller rebase. Leta upp den handling som tog bort arbetet och välj posten närmast under den, här commit: Steg tre.

I ett verkligt repo kan listan vara lång. Numren förskjuts vid varje ny handling, så när du väl har hittat rätt post är det hashen du ska anteckna, inte numret.

5. Kontrollera kandidaten innan du rör något

$kandidat = git rev-parse 'HEAD@{1}'
git log -1 --format='%H %s' $kandidat
git show --stat --format='%h %s' $kandidat
git show "${kandidat}:steg.txt"

Facit: meddelandet Steg tre, en ändrad fil (steg.txt, en rad in och en ut) och innehållet steg tre. Kontrollera både meddelande och innehåll. En agent som har committat flera gånger kan lämna poster med nästan samma meddelande, och då är det filinnehållet som avgör. Sätt enkla citattecken runt HEAD@{1} i PowerShell, så skickas texten oförändrad till Git.

6. Återställ på en ny gren, inte med en ny reset

git branch raddning/steg-tre $kandidat
if ($LASTEXITCODE -ne 0) { throw 'Grenen kunde inte skapas' }
git log --oneline raddning/steg-tre
git branch --show-current
git status --short

Facit: räddningsgrenen visar Steg tre, Steg tva och Steg ett, du står kvar på main och status är tom. Enligt manualen för git branch pekar den nya grenen på startpunkten men byter inte arbetskatalog. Vill du byta direkt gör git switch -c samma sak i ett kommando.

Finns grennamnet redan vägrar Git. I redaktionens körning gav ett andra försök felet fatal: a branch named 'raddning/steg-tre' already exists och exitkod 128. Välj då ett nytt namn i stället för att tvinga med -f, som enligt manualen flyttar den befintliga grenen. En ny reset --hard tillbaka till kandidaten hade fungerat i provet, men den flyttar main och skriver över arbetskatalogen igen. Med en ny gren ändrar du ingenting som redan finns. Jämför sedan i lugn och ro och för över det du behöver, till exempel med Git cherry-pick.

7. Samma metod efter grenbyte och rebase

Nästa block skapar en AI-gren, byter tillbaka till main, gör en commit där och låter sedan AI-grenen rebasas ovanpå main. Rebasen skapar en ny commit med samma meddelande och nytt hashvärde.

git switch --quiet -c ai/omskrivning
[IO.File]::WriteAllText("$provKatalog/ai.txt", "AI-forsok`n", $utf8)
git add -- ai.txt
git commit --quiet -m 'AI-forsok'
git switch --quiet main
[IO.File]::WriteAllText("$provKatalog/main.txt", "steg fyra`n", $utf8)
git add -- main.txt
git commit --quiet -m 'Steg fyra'
git switch --quiet ai/omskrivning
git rebase main
if ($LASTEXITCODE -ne 0) { throw 'Rebase stoppade' }
git reflog -6
git reflog show -3 ai/omskrivning

Redaktionens utdata från de två sista kommandona:

28cc11e HEAD@{0}: rebase (finish): returning to refs/heads/ai/omskrivning
28cc11e HEAD@{1}: rebase (pick): AI-forsok
abac49f HEAD@{2}: rebase (start): checkout main
2fcd475 HEAD@{3}: checkout: moving from main to ai/omskrivning
abac49f HEAD@{4}: commit: Steg fyra
069a666 HEAD@{5}: checkout: moving from ai/omskrivning to main
28cc11e ai/omskrivning@{0}: rebase (finish): refs/heads/ai/omskrivning onto abac49fd2da809d5e6437c851163b0cfbafa52b5
2fcd475 ai/omskrivning@{1}: commit: AI-forsok
069a666 ai/omskrivning@{2}: branch: Created from HEAD

Grenbytena syns som checkout: moving from … to …, så du ser vilken gren agenten lämnade. Originalet före rebasen, 2fcd475, finns i HEAD:s logg som posten checkout: moving from main to ai/omskrivning, men det är lättare att läsa grenens egen reflog. Där är det ai/omskrivning@{1}.

$foreRebase = git rev-parse 'ai/omskrivning@{1}'
git show --stat --format='%h %s' $foreRebase
git switch -c raddning/fore-rebase $foreRebase
if ($LASTEXITCODE -ne 0) { throw 'Grenen kunde inte skapas' }
git log --oneline -3

Facit: AI-forsok ovanpå Steg tva och Steg ett, alltså versionen före rebasen, utan Steg fyra under sig.

8. Gränser: lokalt, 90/30 dagar och ocommittat arbete

Bara lokalt. Dokumentationen beskriver reflog som en logg över uppdateringar i det lokala repot. I redaktionens körning fick en klon av provrepot bara en reflogpost, clone: from …, fast originalet hade ett tiotal. Reflog följer inte med vid push, och som provet visar inte heller vid kloning. Leta därför i den katalog och på den dator där agenten faktiskt arbetade.

Tidsgräns. Manualerna för git reflog och git gc anger att poster rensas efter gc.reflogExpire, med förvalet 90 dagar, och att poster som inte nås från grenens nuvarande topp rensas efter gc.reflogExpireUnreachable, med förvalet 30 dagar. Det är förval och inget löfte: inställningarna kan vara ändrade, och git gc-manualen anger att vanliga kommandon som skapar objekt kan starta skräpsamling automatiskt. En commit som försvann vid en reset eller rebase nås just inte från grenens topp, så räkna med det kortare fönstret och skapa räddningsgrenen samma dag.

Raderad gren. Enligt manualen för git branch tas grenens reflog bort tillsammans med grenen. Då återstår HEAD:s logg om grenen var utcheckad. Därefter finns git fsck --unreachable, som listar objekt som finns men inte nås från någon referens. Med --no-reflogs räknas även commits som bara nås via en reflogpost som onåbara.

Ocommittat arbete. Reflog loggar flyttar av referenser, inte filinnehåll. I redaktionens körning ändrades ai.txt utan commit; efter reset --hard visade reflog bara reset: moving to HEAD och filen var återställd. Utkastet fanns inte i någon post. Det förebyggande steget är en commit eller en stash innan AI-försöket.

När du är klar: kontrollera sökvägen i $provKatalog och ta bort just den katalogen i Utforskaren.

Källor och genomfört prov

Primärkällor kontrollerade 26 oktober 2026. Kommandoflödet kördes i ett separat syntetiskt repo med Git 2.53.0.windows.2 och Windows PowerShell 5.1: tre commits, reset --hard, reflog, show, ny gren, grenbyte med rebase, klon och en ocommittad ändring. Utdata i guiden är från den körningen; hashvärdena blir andra hos dig. Ingen AI-agent, server eller befintligt projekt ingick.