Git'te bırakılan bir depo nasıl kurtarılır?


1737

Ben sık kullandığınız git stashve git stash popbenim çalışma ağacında değişiklikleri kaydedip geri yükleyin. Dün çalışma ağacımda sakladığım ve attığım bazı değişiklikler oldu ve sonra çalışma ağacımda daha fazla değişiklik yaptım. Geri dönüp dünün saklanan değişikliklerini gözden geçirmek istiyorum, ancak git stash popilişkili taahhüdün tüm referanslarını kaldırıyor gibi görünüyor.

Ben o git stashzaman .git / refs / stash kullanırsanız, stash oluşturmak için kullanılan taahhüdün referansını içerdiğini biliyorum . Ve .git / logs / refs / stash tüm saklamayı içerir . Ancak bu referanslar geride kaldı git stash pop. Taahhüdün hala bir yerde depomda olduğunu biliyorum, ama ne olduğunu bilmiyorum.

Dünün saklamak taahhüdü referansını kurtarmanın kolay bir yolu var mı?

Günlük yedeklemelerim olduğundan ve değişiklikleri almak için dünün çalışma ağacına geri dönebileceğim için bunun bugün benim için önemli olmadığını unutmayın. Soruyorum çünkü daha kolay bir yol olmalı!


74
Gelecek için not: Her seferinde depolarınızı kaybetmek istemiyorsanız git stash pop, bunu yapabilirsiniz git stash apply. Aynı şeyi yapar, ancak uygulanan stash referansını kaldırmaz.
Kevin

3
Burada her şeyi denedim, zaten patlamış olan bir zulayı bulamadım. IntelliJ'in jetbrains.com/help/idea/local-history.html
Juan Mendes


Bu sorunu yaşadım. Benim repo güncellemek için, Koştum git stash, git pull -r upstream, git push -f origin, git stash pop": hakemlerimizle için günlük / zula boş ölümcül" ve açılan söyledi. Answers Bu cevaplardan bir sürü denedim, hiçbir şey işe yaramadı. .Git / refs / stash'a baktığımda SHA oradaydı. Çevrimdışı eşitleme için bir Windows ağ sürücüsünü işaretlemeyle ilgili bir sorun olabilir? --‍♂️
brianary

Yanıtlar:


2785

Düşürdüğünüz zulası taahhüdünün karmasını öğrendikten sonra, zulası olarak uygulayabilirsiniz:

git stash apply $stash_hash

Veya bunun için ayrı bir dal oluşturabilirsiniz.

git branch recovered $stash_hash

Bundan sonra, tüm normal araçlarla istediğinizi yapabilirsiniz. İşiniz bittiğinde, dalı havaya uçurun.

Karma bulma

Sadece attıysanız ve terminal hala açıksa, hala hash değerini git stash popekranda basmış olacaksınız (teşekkürler, Dolda).

Aksi takdirde, Linux, Unix veya Windows için Git Bash için bunu kullanarak bulabilirsiniz:

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

... veya Windows için Powershell kullanarak:

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

Bu, artık herhangi bir şube veya etiketten referans alınmayan taahhüt grafiğinizin ipuçlarındaki tüm taahhütleri gösterir - şimdiye kadar oluşturduğunuz her saklanma taahhüdü de dahil olmak üzere her kayıp taahhüt, o grafikte bir yerde olacaktır.

İstediğiniz stash taahhüdünü bulmanın en kolay yolu muhtemelen bu listeyi şuraya iletmektir gitk:

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

... veya Windows için Powershell kullanıyorsanız e- postalardan gelen cevaba bakın .

Bu , ulaşılabilir olup olmadığına bakılmaksızın , havuzdaki her bir taahhüdü gösteren bir depo tarayıcı başlatacaktır .

Konsolda ayrı bir GUI uygulaması yerine hoş bir grafik tercih ediyorsanız, gitkbunun gibi bir şeyle değiştirebilirsiniz git log --graph --oneline --decorate.

Stash taahhütlerini tespit etmek için bu formun taahhüt mesajlarını arayın:

Birileri         üzerinde WIP : commithash Bazı eski taahhüt mesajı

Not : Tamamlama mesajı yalnızca, "WIP on" ile başlayarak) bu formda olacaktır git stash.


49
Jaydel kelimeleri ağzımdan çıkardı. Bu yazı işimi kurtardı :) Sadece eklemek istiyorum - kaybettiğiniz her şey üzerinde çalıştığınız tarihi hatırlamak, aradığınız şey için gitk'e göz atmayı kolaylaştırır.
Sridhar Sarnobat

4
@Codey: Çünkü PowerShell. MsysGit'in bir AWK ikili dosyası gönderip göndermediğini bilmiyorum. Googling, PowerShell'de bu komutta %{ $_.Split(' ')[2]; }eşdeğer bir şey yapması gerektiğini söylüyor , ancak bunu test etmek için bir Windows sistemim yok ve yine de parça için eşdeğer olmanız gerekiyor . Her neyse, sadece çalıştırın ve çıktıya bakın. Karmaları "sarkan <commitID>" satırlarından istiyorsunuz. {print $3}awk/dangling commit/git fsck --no-reflog
Aristoteles Pagaltzis

7
Söz konusu iletinin yalnızca "WIP" dizesine sahip olacağını belirtmek gerekir git stash save "<message>".
Samir Aguiar

12
Düşmenin ne zaman gerçekleştiğini biliyorsanız, süreyi artırarak sarkan taahhütlerin listesini almak için bu tek astarı kullanabilirsiniz: git fsck --no-reflog | awk '/dangling commit/ {print $3}' | xargs -L 1 git --no-pager show -s --format="%ci %H" | sortson giriş muhtemelen istediğiniz giriştir stash apply.
ris8_allo_zen0

3
git stash apply {ref}bırakılan bir zulası geri yükledi! gito kadar büyük ki yasadışı olmalı!
Tom Russell

707

Terminali kapatmadıysanız, yalnızca çıkışa bakın git stash popve bırakılan saklamanın nesne kimliğine sahip olursunuz. Normalde şöyle görünür:

$ git stash pop
[...]
Dropped refs/stash@{0} (2ca03e22256be97f9e40f08e6d6773c7d41dbfd1)

( git stash dropAynı çizgiyi de ürettiğini unutmayın .)

Bu zulayı geri almak için, sadece koş git branch tmp 2cae03e, ve bir şube olarak alacaksın. Bunu stash'a dönüştürmek için şunu çalıştırın:

git stash apply tmp
git stash

Bir dal olarak sahip olmak da özgürce manipüle etmenizi sağlar; örneğin, kiraz toplamak veya birleştirmek için.


54
Daha git stash apply commitidsonra git stashyeni bir saklamak için de yapabilirsiniz .
Matthew Flaschen

32
Git zulayı otomatik olarak birleştirir ve çakışırsa, karma değerini göstermeyeceğini unutmayın.
James

31
@James: Sonra tekrar, eğer bu çatışmalar koşmanın bir sonucuysa, zulayı da düşürmez git stash pop, bu normalde bir sorun değildir.
Dolda2000

2
Git stash pop çıkışımda hiçbir SHA yoktu. :(
Deplasman Hesabı

2
@Honey: Amaç bu git stash pop. Zulayı düşürmeden uygulamak istiyorsanız git stash applybunun yerine kullanın. Ayrıca, birkaç dalda değişiklik uygulamak isterseniz, bunun yerine taahhüdü kiraz olarak seçebilirsiniz.
Dolda2000

271

Sadece kabul edilen çözüme bu eklemeden bahsetmek istedim. Bu yöntemi ilk denediğimde hemen belli değildi (belki de olmalıydı), ancak karma değerini karma değerinden uygulamak için sadece "git stash uygulamak" kullanın:

$ git stash apply ad38abbf76e26c803b27a6079348192d32f52219

Git için yeniyken, bu benim için net değildi ve "git show", "git uygula", "patch" gibi farklı kombinasyonları deniyordum.


3
Bunun mevcut çalışma ağacına zulası uyguladığını (duh!) Unutmayın. Ağaç kirliyse, önce geçici bir dal veya saklamak kullanmak, SHA-1'den saklamak, tekrar saklamak ve sonra ikinci saklamak için ikinci saklamak isteyebilirsiniz (stash @ {1} olarak adlandırılır).
musiKk

111

Deponuzda bulunan, ancak artık erişilemeyen depoların listesini almak için:

git fsck --unreachable | grep commit | cut -d" " -f3 | xargs git log --merges --no-walk --grep=WIP

Stash'ınıza bir başlık verdiyseniz -grep=WIP, komutun sonundaki "WIP" i mesajınızın bir bölümü ile değiştirin, örn -grep=Tesselation.

Komut için varsayılan yürütme iletisi formda olduğundan komut "WIP" için selamlıyor WIP on mybranch: [previous-commit-hash] Message of the previous commit.


1
echo 'git fsck - ulaşılmaz | grep taahhüdü | kes -d "" -f3 | xargs git log --merges --no-walk --grep = WIP '> / usr / local / bin / git-stashlog; chmod a + rx / usr / local / bin / git-stashlog # git stashlog
Erik Martino

Veya bunu .gitconfig dosyanıza takma ad olarak ekleyebilirsiniz (komutun önüne a ile başlayabilirsiniz !).
asmeurer

Benim pastırma kaydedildi - gerçekten değil ama beni iş gün yeniden kodlama kurtardı - takdir - Ben sadece son zamanlarda düştü ki ben sadece sadece komutunun çıkışından üst SHA aldı - sonra .... git stash SHA uygulayın ... diğer cevaplarda belirtildiği gibi - birçok thx
danday74

75

Ben sadece kayıp saklamak taahhüt bulmak için bana yardımcı olan bir komut inşa:

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

Bu, .git / objects ağacındaki tüm nesneleri listeler, commit türündeki nesneleri bulur, sonra her birinin bir özetini gösterir. Bu noktadan sonra, uygun bir "iş için Devam Eden Çalışma: 6a9bb2" ("iş" benim şubem, 619bb2 yeni bir taahhüttür) bulmak için taahhütleri incelemek meselesiydi.

Ben "git stash pop" yerine "git stash uygulamak" kullanırsanız, bu sorun olmaz ve "git stash kaydet iletisi " kullanırsanız, taahhüt bulmak daha kolay olabilir.

Güncelleme: Nathan'ın fikriyle, bu kısalır:

for ref in `git fsck --unreachable | grep commit | cut -d' ' -f3`; do git show --summary $ref; done | less

41

git fsck --unreachable | grep commitsha1'i göstermelidir, ancak döndürdüğü liste oldukça büyük olabilir. git show <sha1>istediğiniz taahhüt olup olmadığını gösterecektir.

git cherry-pick -m 1 <sha1> taahhüdü mevcut şube ile birleştirir.


37

Gitk kullanan Windows PowerShell eşdeğeri:

gitk --all $(git fsck --no-reflog | Select-String "(dangling commit )(.*)" | %{ $_.Line.Split(' ')[2] })

Muhtemelen bunu tek bir boruda yapmanın daha etkili bir yolu vardır, ancak bu işi yapar.


1
Cevabınız için çok minnettarım
Виталий Шебаниц

32

Kayıp bir zulayı yeniden görevlendirmek istiyorsanız, önce kayıp zulanızın karmasını bulmanız gerekir.

Aristoteles Pagaltzis'in önerdiği gibi git fscksize yardımcı olmalıdır.

Şahsen log-all, durumu daha iyi görebilmek için her taahhüdü (kurtarılabilir taahhütler) gösteren takma adımı kullanıyorum :

git log --graph --decorate --pretty=oneline --abbrev-commit --all $(git fsck --no-reflogs | grep commit | cut -d' ' -f3)

Yalnızca "WIP on" mesajlarını arıyorsanız daha da hızlı bir arama yapabilirsiniz.

Sha1'inizi öğrendikten sonra, eski saklamayı eklemek için saklamak refleksinizi değiştirmeniz yeterlidir:

git update-ref refs/stash ed6721d

Muhtemelen ilişkili bir mesaj almayı tercih edersiniz. -m

git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721d

Hatta bunu takma ad olarak kullanmak isteyeceksiniz:

restash = !git update-ref -m $(git log -1 --pretty=format:'%s' $1) refs/stash $1

2
Ancak -d\\ olmalı -d\ (hatta daha net -d' ')
joeytwiddle

Bir hata var: "ölümcül: belirsiz argüman" sarkan ": bilinmeyen düzeltme veya çalışma ağacında olmayan yol."
Daniel Ryan

ayrıca alt komutu tırnak işareti ile sarmanız gerekir git update-ref -m "$(git log -1 --pretty=format:'%s' ed6721d)" refs/stash ed6721
Andrei Shostik

18

Aristoteles'in yaklaşımını beğendim, ancak GITK'yi kullanmayı sevmedim ... çünkü komut satırından GIT kullanmaya alışkınım.

Bunun yerine, sarkan taahhütleri aldım ve kod düzenleyicimde incelenmek üzere kodu bir DIFF dosyasına çıktı.

git show $( git fsck --no-reflog | awk '/dangling commit/ {print $3}' ) > ~/stash_recovery.diff

Artık ortaya çıkan diff / txt dosyasını (ana klasörünüzde) txt düzenleyicinize yükleyebilir ve gerçek kodu ve sonuçta ortaya çıkan SHA'yı görebilirsiniz.

Sonra sadece

git stash apply ad38abbf76e26c803b27a6079348192d32f52219

17

Ulaşılamayan tüm taahhütleri terminalde bu komutu yazarak listeleyebilirsiniz -

git fsck --unreachable

Ulaşılamayan karmayı kontrol edin -

git show hash

Son olarak saklanan ürünü bulursanız başvurun -

git stash apply hash

15

İnsanlar neden bu soruyu soruyor? Çünkü bu bloğu henüz bilmiyor ya da anlamıyorlar.

Bu sorunun yanıtlarının çoğu, neredeyse hiç kimsenin hatırlamayacağı seçeneklerle uzun komutlar veriyor. Böylece insanlar bu soruya giriyorlar ve neye ihtiyaçları olduğunu düşünüyorlarsa hemen yapıştırıyorlar.

Bu soru ile herkese sadece reflog (git reflog) kontrol etmesini tavsiye etmem, çok daha fazla değil. Tüm taahhütlerin listesini gördükten sonra, hangi taahhüdü aradığınızı bulmanın ve kiraz seçmenin veya ondan bir şube oluşturmanın yüz yolu vardır. Bu süreçte reflog ve çeşitli temel git komutlarının kullanışlı seçenekleri hakkında bilgi edinmiş olacaksınız.


1
Merhaba Robby. Bu, çalışıyorsanız, yan izlendiğinizde ve yalnızca saklanmış çalışmanızı bulamayacağınızı öğrenmek için birkaç hafta önce kaldığınız yerden geri almanız gerektiğinde önemlidir - muhtemelen diğer şeylerde bir yerde kaybolmuştur yapıyordu. Reflog, yakın geçmişe sahipse harikadır, ancak uzun zaman boşlukları için değil.
emragins

1
Hey perişan, katılıyorum, ama bu tam olarak OP'nin kullanım durumuydu. Burada gönderilen diğer komutların nasıl davranacağından emin değilim, ama benim geuss, saklanan taahhüdüne yapılan ref temizlendiğinde de çalışmayı bırakacaklarıydı.
RobbyD

1
Hmm ... yukarıdaki senaryo beni bu soruya getiren şeydi ve biliyorum ki (bilerek) saklamamı kaybettiğim ve kurtarabildiğim zaman arasında bir aya daha yakın olmasaydım en azından birkaç hafta oldu.
emragins

15

Git v2.6.4 ile OSX'te, sadece git stash drop'ı yanlışlıkla çalıştırıyorum, sonra aşağıdaki adımlardan gidip buldum

Zuvanın adını biliyorsanız, şunu kullanın:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show | grep -B 6 -A 2 <name of the stash>

aksi takdirde, aşağıdakilerden manuel olarak sonuçtan kimlik bulacaksınız:

$ git fsck --unreachable | grep commit | cut -c 20- | xargs git show

Sonra commit-id bulduğunuzda sadece git stash uygula vur {Uygula-id}

Umarım bu birine hızlı bir şekilde yardımcı olur


12

Ben gitk kullanılabilir veya çıkış için X yoksa, tüm değişiklikleri geçmek için iyi bir çözüm kabul edilen çözüm eklemek istiyorum.

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

for h in `cat tmp_commits`; do git show $h | less; done

Sonra birbirleri ardına görüntülenen hashes için tüm diffs olsun. Bir sonraki fark için 'q' tuşuna basın.


12

Basit bir komut penceresinde (benim durumumda Windows 7) Windows üzerinde çalışmak için cevapların hiçbirini alamadım. awk, grepve Select-stringkomut olarak tanınmadı. Farklı bir yaklaşım denedim:

  • ilk çalıştırma: git fsck --unreachable | findstr "commit"
  • çıktıyı not defterine kopyala
  • yerine "ulaşılamaz taahhüt" ifadesini bul start cmd /k git show

şöyle görünecek:

start cmd /k git show 8506d235f935b92df65d58e7d75e9441220537a4 start cmd /k git show 44078733e1b36962571019126243782421fcd8ae start cmd /k git show ec09069ec893db4ec1901f94eefc8dc606b1dbf1 start cmd /k git show d00aab9198e8b81d052d90720165e48b287c302e

  • .bat dosyası olarak kaydedin ve çalıştırın
  • komut dosyası, her komutu gösteren bir grup komut penceresi açacaktır.
  • aradığınızı bulduysanız, çalıştırın: git stash apply (your hash)

en iyi çözüm olmayabilir, ama benim için çalıştı


Git bash'ı Windows'ta bile kullanabilirsiniz. Git bash'da ihtiyacınız olan tüm (unixoid) komut satırı araçlarına sahipsiniz.
Adrian W

10

Aristoteles tarafından kabul edilen cevap, stash benzeri olmayan taahhütler de dahil olmak üzere tüm erişilebilir taahhütleri gösterecektir. Gürültüyü filtrelemek için:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3

Bu sadece tam olarak 3 üst taahhüt içeren (bir stashın sahip olacağı) ve mesajı "WIP on" içeren taahhütleri içerir.

Zulanızı bir mesajla (örneğin git stash save "My newly created stash") kaydettiyseniz, bunun varsayılan "Devam Eden Çalışma ..." mesajını geçersiz kılacağını unutmayın.

Her işlem hakkında daha fazla bilgi görüntüleyebilirsiniz, örneğin işlem mesajını görüntüleme veya iletme git stash show:

git fsck --no-reflog | \
awk '/dangling commit/ {print $3}' | \
xargs git log --no-walk --format="%H" \
  --grep="WIP on" --min-parents=3 --max-parents=3 | \
xargs -n1 -I '{}' bash -c "\
  git log -1 --format=medium --color=always '{}'; echo; \
  git stash show --color=always '{}'; echo; echo" | \
less -R

6

Benim favorim şu tek astarlı:

git log --oneline  $( git fsck --no-reflogs | awk '/dangling commit/ {print $3}' )

Bu temel olarak bu cevapla aynı fikir ama çok daha kısa. Tabii ki, yine de --graphağaç benzeri bir görüntü elde etmek için ekleyebilirsiniz .

Taahhüdü listede bulduğunuzda,

git stash apply THE_COMMIT_HASH_FOUND

Benim için kullanmak --no-reflogs, kayıp saklamak girişini ortaya çıkardı, ancak --unreachable(diğer birçok cevapta olduğu gibi) ortaya çıkmadı.

Windows altındayken git bash üzerinde çalıştırın.

Kredi: Yukarıdaki komutların detayları https://gist.github.com/joseluisq/7f0f1402f05c45bac10814a9e38f81bf adresinden alınmıştır.


5

Aşağıdaki adımları kullanarak kurtardı:

  1. Silinen saklama karma kodunu tanımlayın:

    gitk --all $ (git fsck --no-reflog | awk '/ sarkan taahhüt / {3 $ yazdır}')

  2. Kiraz Zulası Seç:

    git cherry-pick -m 1 $ Instagram Hesabındaki Resim ve Videoları stash_hash_code

  3. Varsa Çakışmaları Çöz:

    git mergetool

Ayrıca gerrit kullanıyorsanız, taahhüt mesajı ile ilgili sorunlar yaşıyor olabilirsiniz. Lütfen bir sonraki alternatifleri izlemeden önce değişikliklerinizi saklayın:

  1. Önceki taahhüdüne sabit sıfırlama kullanın ve ardından bu değişikliği önerin.
  2. Ayrıca değişikliği saklayabilir, yeniden temellendirebilir ve tavsiye edebilirsiniz.

@ miva2 düzenlemeniz bu sorudaki en doğru yanıtın bağlantısını kaldırdı. Bağlantıyı tekrar yoruma ekleme stackoverflow.com/questions/89332/…
Abhijeet

4

Buraya bakmaya geldiğim şey, ne teslim aldığımdan bağımsız olarak, saklamanın nasıl geri alınacağı. Özellikle, bir şey sakladım, daha sonra eski bir versiyonunu kontrol ettim, sonra açtım, ama bu zıvanın önceki zaman noktasında bir operasyon olmamasıydı, bu yüzden zulası kayboldu; Sadece git stashyığının üzerine geri itmek için yapamadım . Bu benim için çalıştı:

$ git checkout somethingOld
$ git stash pop
...
nothing added to commit but untracked files present (use "git add" to track)
Dropped refs/stash@{0} (27f6bd8ba3c4a34f134e12fe69bf69c192f71179)
$ git checkout 27f6bd8ba3c
$ git reset HEAD^    # Make the working tree differ from the parent.
$ git stash # Put the stash back in the stack.
Saved working directory and index state WIP on (no branch): c2be516 Some message.
HEAD is now at c2be516 Some message.
$ git checkout somethingOld # Now we are back where we were.

Geriye baktığımda, git stash applydeğil kullanmalıydım git stash pop. bisectHer bisectadımda uygulamak istediğim küçük bir yama yapıyordum . Şimdi bunu yapıyorum:

$ git reset --hard; git bisect good; git stash apply
$ # Run tests
$ git reset --hard; git bisect bad; git stash apply
etc.

bu bir cevap mı yoksa sorunun devamı mı?
Alex Brown

İkisindende biraz. Bu sayfayı buldum çünkü bir zulayı kaybettim ve geri almaya çalışıyordum. Benim için kullanım durumu, her adımda test etmeden önce bir değişiklik uygulamak istediğim bir ikiliyi yapıyor. Sadece pop, test, stash, bisect yapamamanın zor yolunu öğrendim, çünkü bu stash üzerinde farklı bir taahhüt bırakabilir stash apply.
Ben
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.