Ik gebruik vaak git stash
en git stash pop
om wijzigingen in mijn werkstructuur op te slaan en terug te zetten. Gisteren had ik enkele wijzigingen in mijn werkboom die ik had gestasht en gepopped, en toen maakte ik meer wijzigingen in mijn werkboom. Ik'wil graag teruggaan en de verborgen wijzigingen van gisteren bekijken, maar git stash pop
lijkt alle verwijzingen naar de geassocieerde commit te verwijderen.
Ik weet dat als ik git stash
gebruik, dan bevat .git/refs/stash de referentie van de commit die gebruikt is om de stash te maken. En .git/logs/refs/stash bevat de hele stash. Maar die referenties zijn verdwenen na git stash pop
. Ik weet dat de commit nog ergens in mijn repository zit, maar ik weet niet meer wat het was.
Is er een makkelijke manier om de stash commit referentie van gisteren's terug te krijgen?
Merk op dat dit vandaag niet kritisch voor mij is, omdat ik dagelijkse back-ups heb en terug kan gaan naar de werkboom van gisteren om mijn wijzigingen te krijgen. Ik'm vraag het omdat er een makkelijkere manier moet zijn!
Als je eenmaal de hash weet van de stash commit die je hebt laten vallen, kun je hem toepassen als stash:
git stash apply $stash_hash
Of, je kunt er een aparte branch voor maken met
git branch recovered $stash_hash
Daarna kun je doen wat je wilt met alle normale gereedschappen. Als je klaar bent, blaas je de tak gewoon weg.
Als je nog maar net gepopt hebt en de terminal is nog open, dan zul je nog steeds de hash waarde die door git stash pop
op het scherm wordt afgedrukt (bedankt, Dolda).
Anders kun je het vinden met dit voor Linux, Unix of Git Bash voor Windows:
git fsck --no-reflog | awk '/dangling commit/ {print $3}'
...of met Powershell voor Windows:
git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}
Dit zal je alle commits laten zien aan de uiteinden van je commit grafiek die niet langer gerefereerd worden vanuit een branch of tag - elke verloren commit, inclusief elke stash commit die je ooit gemaakt hebt, zal ergens in die grafiek staan.
De makkelijkste manier om de stash commit te vinden die je wilt, is waarschijnlijk om die lijst aan gitk
door te geven:
gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )
...of zie het antwoord van emragins als je Powershell voor Windows gebruikt.
Dit zal een archief-verkenner starten die je elke commit in het archief ooit laat zien, ongeacht of het bereikbaar is of niet.
Je kunt gitk
daar vervangen door iets als git log --graph --oneline --decorate
als je een mooie grafiek op de console prefereert boven een aparte GUI app.
Om stash commits te vinden, zoek naar commit boodschappen van deze vorm:
WIP op somebranch: commithash Een of andere oude commit boodschap
Note: De commit boodschap zal alleen in deze vorm zijn (beginnend met "WIP on") als je geen boodschap hebt meegegeven toen je git stash
deed.
Ik heb net een commando gemaakt dat me hielp mijn verloren stash te vinden:
for ref in `find .git/objects | sed -e 's#.git/objects/##' | grep / | tr -d /`; do if [ `git cat-file -t $ref` = "commit" ]; then git show --summary $ref; fi; done | less
Dit toont alle objecten in de .git/objects boom, zoekt de objecten die van het type commit zijn, en toont dan een samenvatting van elk object. Vanaf dit punt was het gewoon een kwestie van door de commits kijken om een passende "WIP on work: 6a9bb2" ("work" is mijn branch, 619bb2 is een recente commit).
Ik merk op dat als ik "git stash apply" zou gebruiken in plaats van "git stash pop", ik dit probleem niet zou hebben, en als ik "git stash save message" zou gebruiken, dan zou de commit misschien makkelijker te vinden zijn geweest.
Update: Met Nathan's idee, wordt dit korter:
for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
git fsck --unreachable | grep commit
zou de sha1 moeten laten zien, hoewel de lijst die het teruggeeft vrij groot kan zijn. git show <sha1>
zal laten zien of het de commit is die je wilt.
git cherry-pick -m 1 <sha1>
zal de commit op de huidige branch samenvoegen.