Ako obnoviť stratenú zásobu v systéme Git?

Na ukladanie a obnovovanie zmien v pracovnom strome často používam git stash a git stash pop. Včera som mal v pracovnom strome niekoľko zmien, ktoré som uložil a popp, a potom som urobil ďalšie zmeny v pracovnom strome. Chcel by som sa vrátiť a skontrolovať včerajšie uložené zmeny, ale zdá sa, že git stash pop odstráni všetky odkazy na súvisiace revízie.

Viem, že ak použijem git stash, potom .git/refs/stash obsahuje odkaz na revíziu použitú na vytvorenie stash. A .git/logs/refs/stash obsahuje celý stash. Ale tieto odkazy zmiznú po git stash pop. Viem, že revízia je stále niekde v mojom úložisku, ale neviem, čo to bolo.

Existuje nejaký jednoduchý spôsob, ako obnoviť včerajší odkaz na revíziu stash'u?

Upozorňujem, že dnes to pre mňa nie je'kritické, pretože mám denné zálohy a môžem sa vrátiť do včerajšieho pracovného stromu, aby som získal svoje zmeny. Pýtam sa, pretože musí existovať jednoduchší spôsob!

Riešenie

Keď poznáte hash revízie skrýše, ktorá vám vypadla, môžete ju použiť ako skrýšu:

git stash apply $stash_hash

Alebo pre ňu môžete vytvoriť samostatnú vetvu pomocou

git branch recovered $stash_hash

Potom môžete robiť, čo chcete, pomocou všetkých bežných nástrojov. Keď skončíte, vetvu jednoducho odstráňte.

Nájdenie hash

Ak ste ho práve vypustili a terminál je stále otvorený, budete mať na obrazovke stále hodnotu hash vypísanú pomocou git stash pop (vďaka, Dolda).

V opačnom prípade ju môžete nájsť pomocou tejto funkcie pre Linux, Unix alebo Git Bash pre Windows:

git fsck --no-reflog | awk '/dangling commit/ {print $3}'

...alebo pomocou Powershell pre Windows:

git fsck --no-reflog | select-string 'dangling commit' | foreach { $bits = $_ -split ' '; echo $bits[2];}

Zobrazia sa vám všetky revízie na koncoch grafu revízií, na ktoré sa už neodkazuje zo žiadnej vetvy alebo značky - každá stratená revízia, vrátane každej revízie zásobníka, ktorú ste kedy vytvorili, bude niekde v tomto grafe.

Najjednoduchší spôsob, ako nájsť požadovanú revíziu stash, je pravdepodobne odovzdať tento zoznam príkazu gitk:

gitk --all $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' )

...alebo si pozrite odpoveď od emragins, ak používate Powershell pre Windows.

Tým sa spustí prehliadač úložiska, ktorý vám zobrazí každú jednu revíziu v úložisku vôbec bez ohľadu na to, či je dosiahnuteľná alebo nie.

Môžete tam nahradiť gitk niečím ako git log --graph --oneline --decorate, ak dávate prednosť peknému grafu na konzole pred samostatnou aplikáciou GUI.

Ak chcete odhaliť revízie skrýše, hľadajte správy o revízii v tomto tvare:

        WIP on somebranch: commithash Some old commit message

Poznámka: Správa o revízii bude v tomto tvare (začínajúcom "WIP on") len vtedy, ak ste správu neposkytli pri git stash.

Komentáre (23)

Práve som skonštruoval príkaz, ktorý mi pomohol nájsť stratenú skrinku commit:

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

Tento príkaz vypíše všetky objekty v strome .git/objects, nájde tie, ktoré sú typu commit, a potom zobrazí prehľad každého z nich. Od tohto bodu bolo už len otázkou prechádzania revízií, aby som našiel vhodný "WIP on work: ("work" je moja vetva, 619bb2 je nedávna revízia).

Poznamenávam, že keby som použil "git stash apply" namiesto "git stash pop", nemal by som tento problém, a keby som použil "git stash save message", potom by sa revízia možno našla ľahšie.

Aktualizácia: S Nathanovým'nápadom sa to skráti:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less
Komentáre (0)

git fsck --unreachable | grep commit by mal zobraziť sha1, hoci zoznam, ktorý vráti, môže byť dosť veľký. git show ukáže, či ide o požadovanú revíziu.

git cherry-pick -m 1 zlúči revíziu do aktuálnej vetvy.

Komentáre (1)