Git stash pop neden izlenmeyen dosyaları zula girişinden geri yükleyemediğini söylüyor?


94

Bir dizi aşamalı ve aşamalı olmayan değişikliğim vardı ve hızla başka bir dala geçip sonra geri dönmek istedim.

Bu yüzden değişikliklerimi kullanarak şunları yaptım:

$ git stash push -a

(Geriye dönüp baktığımda muhtemelen --include-untrackedyerine kullanabilirdim --all)

Sonra zulayı açmaya gittiğimde şu satırlarda bir sürü hata alıyorum:

$ git stash pop
foo.txt already exists, no checkout
bar.txt already exists, no checkout
...
Could not restore untracked files from stash entry

Zuladan geri yüklenen herhangi bir değişiklik yok gibi görünüyor.

Ben de denedim $ git stash branch tempama bu aynı hataları gösteriyor.

Bunu kullanmam için bir yol buldum:

$ git stash show -p | git apply

Afet şimdilik önlendi ancak bu bazı soruları gündeme getiriyor.

Bu hata neden ilk etapta oldu ve bir dahaki sefere bundan nasıl kaçınabilirim?


29
Şunu kullanmak zorunda kaldım:git stash show -p | git apply --3
xmedeko

2
Benim için çalışan tek şey YORUM YUKARIDIR !!
Mehraj Malik

4
Teşekkürler @xmedeko, herkes git stash show -p arasındaki farkı söyleyebilir mi? git uygula ve git zula göster -p | git başvuru --3?
Deepak Mohandas

3
Eğer panik, sadece ile saklanmış dosyaları listelemek git stash showkurtarma dosyaları tek tek ve daha: $ git show stash@{0}:your/stashed/file.txt > your_rescued_file.txt. Bu, dosyayı zuladan alacak ve farklı bir adla kaydedecektir. Artık uygun kurtarma yöntemlerini deneyebilirsiniz (aşağıdaki yanıtlara bakın). İşler ters giderse, kurtarılan dosyalarınız her zaman son kaynak olarak sizdedir.
Danijel

Vay canına, teşekkürler @xmedeko! Bir kez daha yorumunuz işe yarayan tek şeydi ve çok basitti. +1!
pcdev

Yanıtlar:


99

Biraz ek açıklama olarak, git stashiki veya üç commit yaptığına dikkat edin. Varsayılan ikidir; --allveya --include-untrackedseçeneklerinin herhangi bir yazımını kullanırsanız üç elde edersiniz .

Bu iki ya da üç, kaydedilmesini yönden önemi özeldir: onlar üzerinde hiçbir dalda değildirler. Git onları özel adla bulur stash. 1 en önemli şey olsa da, Git sen-ve sağlayan şeydir kılan bu iki veya üç kaydedilmesini ile sen-do. Bunu anlamak için bu taahhütlerde ne olduğuna bakmamız gerekiyor.

Zulanın içinde ne var

Her kayıt, bir veya daha fazla ebeveyn kaydını listeleyebilir . Bunlar, daha sonraki taahhütlerin daha öncekilere işaret ettiği bir grafik oluşturur. Zula normalde idizin / hazırlık alanı içeriği ve wçalışma ağacı içeriği için çağırmaktan hoşlandığım iki commit tutar . Ayrıca her işlemenin bir anlık görüntü içerdiğini unutmayın. Normal bir işlemde bu anlık görüntü yapılır gelen endeks / hazırlık alanlı içerikleri. Yani ikesinleştirme aslında tamamen normal bir işlemdir! Herhangi bir dalda yok:

...--o--o--o   <-- branch (HEAD)
           |
           i

Normal bir zula yapıyorsanız, git stashkod, wizlenen tüm çalışma ağacı dosyalarınızı (geçici bir yardımcı dizine) kopyalayarak yapar . Git, bu wcommit'in ilk ebeveynini commit'i gösterecek şekilde HEADve ikinci ebeveyni commit'i işaret edecek şekilde ayarlar.i . Son olarak, stashşu wkaydetmeye işaret eder :

...--o--o--o   <-- branch (HEAD)
           |\
           i-w   <-- stash

--include-untrackedVeya eklerseniz --all, Git, uyapmak ive w. İçin anlık görüntü içeriği uizlenmeyen ancak yok sayılmayan dosyalar ( --include-untracked) veya yok sayılsalar bile izlenmeyen dosyalardır ( --all). Bu ekstra utaahhüt sahip hiçbir ebeveyn ve sonra ne zaman git stashyapar w, bu ayarlar w'ın üçüncü Buna ebeveyni ualmak, böylece taahhüt:

...--o--o--o   <-- branch (HEAD)
           |\
           i-w   <-- stash
            /
           u

Git ayrıca, bu noktada, işlemede ortaya çıkan tüm çalışma ağacı dosyalarını kaldırıru ( git cleanbunu yapmak için kullanarak ).

Bir zulayı geri yükleme

Bir zulayı geri yüklemeye gittiğinizde , onu kullanma --indexya da kullanmama seçeneğiniz vardır . Bu söyler git stash apply(veya dahili olarak kullanmak komutların herhangi applygibi pop) o gerektiğini kullanmaki geçerli dizini değiştirmeye çalışmayın taahhüt. Bu değişiklik şu şekilde yapılır:

git diff <hash-of-i> <hash-of-i's-parent> | git apply --index

(aşağı yukarı; burada temel fikrin yoluna giren bir sürü nitty ayrıntı var).

Atlarsanız --index, kesinliği git stash applytamamen yok sayar i.

Zulada yalnızca iki kaydetme varsa git stash apply, artık wkesinleştirme uygulayabilirsiniz . Bunu, git merge2'yi çağırarak (sonucu normal bir birleştirme olarak işlemesine veya işlemesine izin vermeden), zulanın yapıldığı orijinal taahhüdü ( iebeveyn ve wilk ebeveyn) birleştirme tabanı wolarak kullanarak yapar. --theirscommit ve birleştirme hedefi olarak mevcut (HEAD) taahhüdünüz. Birleştirme başarılı olursa, her şey iyidir - en azından Git öyle düşünüyor - ve git stash applykendisi de başarılı olur. Eğer kullanılırsa git stash popzulası uygulamak, kod artık düşer zulası. 3 Birleştirme başarısız olursa, Git başvurunun başarısız olduğunu bildirir. Kullandıysanızgit stash popkod, zulayı korur ve için olduğu gibi aynı hata durumunu verir git stash apply.

Ancak bu üçüncü taahhüdünüz varsa - uuyguladığınız zulada bir taahhüt varsa - o zaman işler değişir! Kayıt yokmuş gibi davranma seçeneği uyoktur. 4 Git tüm dosyaları ayıklanması ısrar gelen o uişlemek mevcut çalışma-ağaca. Bu, dosyaların ya hiç var olmaması ya da ukaydetmede olduğu gibi aynı içeriğe sahip olması gerektiği anlamına gelir .

Bunun olmasını sağlamak için git cleankendinizi kullanabilirsiniz - ancak izlenmemiş dosyaların (göz ardı edilmiş olsun ya da olmasın) Git deposunda başka bir varlığı olmadığını unutmayın, bu nedenle bu dosyaların tamamen yok edilebileceğinden emin olun! Veya, geçici bir dizin yapmak ve başka yapmak hatta saklanması amacıyla veya orada dosya taşıyabilirsiniz git stash save -uveya git stash save -abu çalışacaktır, çünkü git cleansenin için. Ancak bu sizi udaha sonra uğraşmak için başka bir stil zulasına bırakıyor .


1 Bu aslında refs/stash. Bu, adında bir şube yaparsanız önemlidir stash: şubenin tam adı refs/heads/stash, yani bunlar çelişkili değildir. Ama bunu yapma: Git aldırmaz ama kafanı karıştıracaksın. :-)

2git stash kod aslında kullanır git merge-recursivedoğrudan buraya. Bu, birçok nedenden dolayı gereklidir ve ayrıca Git'in çatışmaları çözdüğünüzde ve tamamladığınızda bunu bir birleştirme olarak değerlendirmediğinden emin olma yan etkisine de sahiptir.

3 Bu yüzden git stash pop, lehine kaçınmayı öneriyorum git stash apply. Neyin uygulandığını gözden geçirme ve gerçekten doğru uygulanıp uygulanmadığına karar verme şansınız olur . Değilse, hala zulanız var, bu da git stash branchher şeyi mükemmel bir şekilde kurtarmak için kullanabileceğiniz anlamına gelir . Pekala, bu sinir bozucu utaahhüdün eksikliğini varsayarsak .

4 Gerçekten olmalı: git stash apply --skip-untrackedveya başka bir şey. Ayrıca, tüm bu ucommit dosyalarını yeni bir dizine bırakma anlamına gelen bir varyant da olmalıdır , örneğin git stash apply --untracked-into <dir>, belki.


8
Şaşırtıcı derecede ayrıntılı cevap. Bunu yazmaya zaman ayırdığınız için teşekkür ederiz. Çok şey öğrendim!
steinybot

Bu açıklama bir kahraman rozetini hak ediyor. Böyle büyük ayrıntılar koyduğunuz için teşekkürler!
Lucas Fowler

1
@seelts Maalesef Git sürekli olarak evrim geçiriyor, bu nedenle kitapların güncelliği çabucak bitiyor. Ama Git sen yararlıdır ne olursa olsun içine monte ne olursa olsun-bir manipüle işlemek-ful dosyaların veya grafiğini işlemek işlemek veya araçları-komutlar kümesi olarak anlaşılmalıdır sana değil Çok fazla kitap olduğunu yaklaştığı gözlenmektedir ya da.
torek

3
Sorunun çözümünü anlayamıyorum. Sadece ekliyor --index: git stash apply --index?
Danijel

1
Teşekkürler @torek. Önce yaptım git stash save --all, sonra hemen yaptım git stash apply, ancak bazı dosyalar eksikti çünkü onları yeniden adlandırdım ve sonra yeniden yarattım (saklamadan önce). Yardımcı olan şey şuydu: git checkout stash@{0} -- .Zahmet etmeyeceğim git checkout stash^3 -- .çünkü artık her şey yolunda görünüyor. Ne olduğunu gerçekten anlamaya vaktim olmaması ne yazık. Teşekkürler.
Danijel

100

Sorununuzu yeniden yaratmayı başardım. Görünüşe göre izlenmeyen dosyaları saklıyorsanız ve sonra bu dosyaları oluşturuyorsanız (örneğinizde foo.txtve bar.txt), uyguladığınızda üzerine yazılacak izlenmeyen dosyalarda yerel değişiklikleriniz olur git stash pop.

Bu sorunu aşmak için aşağıdaki komutu kullanabilirsiniz. Bu, kaydedilmemiş yerel değişiklikleri geçersiz kılacaktır, bu nedenle dikkatli olun.

git checkout stash -- .

İşte önceki komutta bulduğum bazı ek bilgiler .


Çalışma ağacım kesinlikle temizdi, ancak göz ardı edilen dosyalarda değişiklikler olabilirdi.
steinybot

1
Görünüşe göre --all/ kullanılıyor gibi -a göz ardı edilen dosyaları içerecek , bu nedenle alakalı olabilir.
Daniel Smith

1
Aynı mantığın göz ardı edilen dosyalar için de geçerli olduğunu varsayacağım ve bunu yanıt olarak işaretleyeceğim ( git merge --squash --strategy-option=theirs stashbu durumda yaklaşımın daha iyi olduğunu düşünmeme rağmen ).
steinybot

Kabul ediyorum, bu ikinci yaklaşımı seviyorum! Çalışmanızda bol şans!
Daniel Smith

Bu yardımcı oldu, ancak izlenmeyen dosyaları geri yüklemedi - aynı sorunu yaşıyorsanız ( already exists, no checkout), aşağıdaki cevabımı kontrol edin.
Erik Koopmans

25

Daniel Smith'in cevabını genişletmek gerekirse : Bu kod , zulayı oluştururken (veya ) kullanmış olsanız bile, yalnızca izlenen dosyaları geri yükler . Gereken tam kod:--include-untracked-u

git checkout stash -- .
git checkout stash^3 -- .
git stash drop

# Optional to unstage the changes (auto-staged by default).
git reset

Bu, izlenen içerikleri (giriş stash) ve izlenmeyen içerikleri (giriş stash^3) tamamen geri yükler , ardından zulayı siler. Birkaç not:

  • Dikkatli olun - bu, zula içeriğinizle her şeyin üzerine yazacaktır!
  • Dosyaları geri yüklemek, git checkouthepsinin otomatik olarak hazırlanmasına neden oluyor, bu yüzden git resether şeyi aşamalı hale getirmek için ekledim.
  • Bazı kaynaklar kullanır stash@{0}ve stash@{0}^3benim testlerimde aynı şekilde veya onsuz çalışır@{0}

Kaynaklar:


1
Zulayı neden siliyorsunuz, neden güvenlik nedenleriyle onu bir süre orada bırakmıyorsunuz?
Danijel

@Danijel Elbette zulayı koruyabilirsiniz - sanırım kullanım durumunuza bağlı. Amacım için, geri yüklendikten sonra zulayla işim bitti.
Erik Koopmans

3

diğer cevapların yanı sıra küçük bir numara yaptım

  • Tüm yeni dosyaları sildi (zaten var olan dosyalar, örn. Sorudaki foo.txt ve bar.txt)
  • git stash apply (herhangi bir komutu kullanabilir, örneğin, uygula, pop vb.)

Çalışmıyor .. Silinen Dosyalar saklandığında tekrar görünür .. ve hata da öyle!
Aditya Rewari
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.