Git'te saklanan bir pop'u iptal etme


258

Bir zulası attım ve birleşme çatışması vardı. Yinelenen olarak listelenen sorunun aksine, zaten dizinde saklamak istediğim bazı değişmemiş değişiklikler vardı. Sadece birleştirme çatışmasını ortadan kaldırmak istemiyorum, aynı zamanda dizinimi pop'dan önceki haline geri döndürmek istiyorum.

Denedim git merge --abort, ama git hiçbir birleşmenin sürmediğini iddia etti. Başlangıçta dizinde yaptığım değişiklikleri yok etmeden bir pop'u iptal etmenin kolay bir yolu var mı?


Taahhütsüz değişikliklerinizle ilgili olarak: bu değişiklikler zaten dizinde miydi?
jørgensen

Kullandığınız git sürümünü gönderebilir misiniz?
Tinman


2
Kabul edilen cevap karmaşık görünüyor. Bence git stash popkirli çalışma direncini asla deneme gibi bir şey yapmamak oldukça iyi bir genel uygulamadır . Bu durumda basitçe git reset --hardve saklamak hala bozulmamış olabilir. (Bu aşağı yukarı @ BradKoch'un bağlantılı konusunun önerdiği şeydir)
Steven Lu

1
@StevenLu, katılıyorum, ancak değişiklikleri farklı bir şubeye taşımak için değişiklikleri saklıyorsanız, sorun temiz bir çalışma dizininde ortaya çıkabilir. Stash, eskisinde var olmayan yeni dalda var olan taahhütlerle çelişir.
Jake Stevens-Haas

Yanıtlar:


56

Tamam, bence "git stash unapply". git apply --reverseTarafından yapılan birleştirme durumunda ters birleştirme eylemine ihtiyacınız olduğundan daha karmaşıktır git stash apply.

Ters birleştirme, tüm geçerli değişikliklerin dizine aktarılmasını gerektirir:

  • git add -u

Sonra merge-recursivebu tarafından ters çevirin git stash apply:

  • git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1

Şimdi sadece saklı olmayan değişikliklerle kalacaksınız. Dizinde olacaklar. İsterseniz git resetdeğişikliklerinizi bozmak için kullanabilirsiniz .

Orijinalinizin git stash applybaşarısız olduğu göz önüne alındığında, geri almak istediği bazı şeylerin yapılmadığı için tersinin de başarısız olabileceğini varsayıyorum.

Çalışma kopyasının (üzerinden git status) nasıl tekrar temizlendiğini gösteren bir örnek :

 $ git status
# On branch trunk
nothing to commit (working directory clean)
 $ git stash apply
Auto-merging foo.c
# On branch trunk
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#   (use "git checkout -- <file>..." to discard changes in working directory)
#
#       modified:   foo.c
#
no changes added to commit (use "git add" and/or "git commit -a")
 $ git add -u
 $ git merge-recursive stash@{0}: -- $(git write-tree) stash@{0}^1
Auto-merging foo.c
 $ git status
# On branch trunk
nothing to commit (working directory clean)

2
bunu yaptıktan sonra, daha önce saklanan düzenlemeler sonsuza dek kaybolacak mı yoksa tekrar saklanacak mı?
Brian H.

7
git stash applyasla bir zulası git stash pop
düşürmez

Orijinal saklamak pop sırasında bir birleşme çatışması varsa kötü şeyler olacak
3ocene

286

Benim kullanım durumum: sadece yanlış dalda haşhaş denedim ve çatışmalar var. Tek ihtiyacım pop geri almak ama stash listesinde tutmak böylece doğru dalda dışarı pop olabilir. Bunu ben yaptım:

git reset HEAD --hard
git checkout my_correct_branch
git stash pop

Kolay.


22
İstediğiniz stash, başarılı bir pop çıkana kadar stash listesinde kalır mı?
Ryan Clark

52
Bu, taahhüt edilmemiş olan yerel değişiklikleri sileceği için orijinal sorunun cevabı değildir.
Dmitry

13
@RyanClark Aşağıdaki DavidG'nin cevabına bakınız. Temel olarak, evet, saklamak listesinde kalır.
fkorsa

1
Bu durumda kendilerini bulan kullanıcıların büyük çoğunluğunun bu çözümü ideal bulacağını düşünüyorum. Çalışmaya çalışmadan önce çalışma dizinimde taahhüt edilmemiş değişikliklerin olduğu bir durumu hayal edemiyorum stash pop. Bu bir felaket tarifi gibi geliyor.
Shadoninja

2
Güzel. Bunu okuduktan sonra git stash pop belgelerine baktım. Bu nedenle, bir sıfırlama / ödeme yapıldıktan sonra saklamanın yeniden patlatılmasının nedeni budur.
Brady Holt

48

Düzenleme: git help stashPop bölümündeki belgelerden:

Devleti uygulamak çatışmalarda başarısız olabilir; bu durumda, saklamak listesinden kaldırılmaz. Çakışmaları elle çözmeniz ve daha sonra git stash drop'u manuel olarak çağırmanız gerekir.

--İndex seçeneği kullanılırsa, yalnızca çalışan ağacın değişikliklerini değil, dizinin değişikliklerini de eski durumuna döndürmeye çalışır. Ancak, çakışmalarınız olduğunda (dizinde depolandığından, artık değişiklikleri orijinal olarak uygulayamayacağınız yerlerde) bu başarısız olabilir.

Tüm deponuzu yeni bir dizine kopyalamayı deneyin (böylece bir kopyasına sahip olursunuz) ve çalıştırın:

git stash show ve ilgilenirseniz bu çıktıyı bir yere kaydedin.

sonra: git stash dropçakışan zulayı bırakmak için:git reset HEAD

Bu, repo'nuzu daha önce olduğu durumda bırakmalıdır (umarım, sorununuzu hala çoğaltamadım)

===

Ben sorununuzu repro çalışıyorum ama usin ne zaman elde git stash pop:

error: Your local changes to the following files would be overwritten by merge:
...
Please, commit your changes or stash them before you can merge.
Aborting

Temiz bir şekilde:

git init
echo hello world > a
git add a & git commit -m "a"
echo hallo welt >> a
echo hello world > b
git add b & git commit -m "b"
echo hallo welt >> b
git stash
echo hola mundo >> a
git stash pop

Git değişiklikleriimi birleştirmeye çalışırken görmüyorum, sadece başarısız oluyor. Size yardımcı olmak için uygulayabileceğimiz herhangi bir repro adımınız var mı?


Değişiklikleri farklı bir dosyada saklamayı deneyin.
asmeurer

Farklı bir dosyaya saklamaya çalışmak işe yaramadı (yeni repro adımlarına bakın). Sadece sorunu
çözemiyorum

1
Çalışma dizininde onaylanmamış değişiklikler varsa bu çözüm çalışmaz.
burada

@burada Bu gerçek bir çözüm değil, bu sadece OP'nin sahip olduğu sorunu yeniden üretemediğimi ve bulunduğu yere ulaşmak için herhangi bir adım atmadığını göstermek için.
DavidG

1
Gerçek senaryo: 1) A dosyasını değiştir. 2) Stash değişiklikleri 3) A dosyasında çakışma değişikliği yapma ve kaydetme (örneğin aynı satırı değiştirme) 4) B dosyasını değiştirme 5) 'git stash pop' yapın. Artık çatışma ve yerel değişiklikleriniz var. Genellikle farklı dosyalarda olurlar, ancak stash'dan hangi çelişkili olmayan değiştirilmiş dosyaları ve hangilerinin yerel işaretsiz değişiklikler olduğunu asla bilemezsiniz.
Dmitry

17

Her zaman kullandım

git reset --merge

Başarısız olduğunu hatırlayamıyorum.


@GauravPaliwal, bir dahaki sefere buna bir göz atacağım git reset. İşlevsel olarak aynı olup olmadığını biliyor musunuz git reset --merge?
Kenn Sebesta

5

Yaptığınız diğer değişiklikler hakkında endişelenmeniz gerekmiyorsa ve yalnızca son işleme geri dönmek istiyorsanız, şunları yapabilirsiniz:

git reset .
git checkout .
git clean -f

4

Tamam, sanırım seni olması gereken yere geri götürecek bir iş akışı bulmayı başardım (sanki pop yapmamış gibi).

ÖNCE YEDEKLEME YAPIN !! Bunun sizin için işe yarayıp yaramayacağını bilmiyorum, bu yüzden işe yaramazsa tüm deponuzu kopyalayın.

1) Birleştirme sorunlarını düzeltin ve yamadan gelen tüm değişiklikleri seçerek tüm çakışmayı düzeltin (kaplumbağa sisteminde bu bir olarak görünür. REMOETE (onların)).

git mergetool

2) Bu değişiklikleri yapın (bunlar zaten mergetool komutu ile eklenecektir). Ona "birleştirme" veya hatırladığınız bir şey verin.

git commit -m "merge"

3) Şimdi, yamadan yeni bir taahhütle, başlangıçta başlattığınız yerel işaretsiz değişiklikleriniz devam edecek (bundan sonra kurtulabiliriz). Şimdi değişmemiş değişikliklerinizi yapın

git add .
git add -u .
git commit -m "local changes"

4) Yamayı ters çevirin. Bu, aşağıdaki komutla yapılabilir:

git stash show -p | git apply -R

5) Bu değişiklikleri yapın:

git commit -a -m "reversed patch"

6) Yamadan / unpatch taahhütlerinden kurtulun

git rebase -i HEAD^^^

bundan, içinde 'birleştirme' ve 'ters yama' bulunan iki satırı kaldırın.

7) Sabit olmayan değişikliklerinizi geri alın ve 'yerel değişiklikler' taahhüdünü geri alın

git reset HEAD^

Ben basit bir örnek ile üzerinden koştum ve olmak istediğiniz yere geri götürür - doğrudan stash attı önce, yerel değişiklikleri ve stash hala pop mevcut.


Eğer bu pek işe yaramazsa, umarım sizi oraya götürür! :-)
agentgonzo

git stash show -p | git apply -Rgit stash applyherhangi bir gerçek birleştirme yaptıysanız işe yaramaz . Cevabımı görün ...
Ben Jackson

3

Bunu biraz farklı bir şekilde çözdüm. İşte olanlar.

İlk olarak, yanlış şubeye atladım ve çatışmalar yaşadım. Zımba sağlam kaldı ancak dizin birçok komutu engelleyen çakışma çözümlemesiydi.

Basit bir git reset HEADçözüm, çatışma çözümlemesini iptal etti ve taahhüt edilmemiş (ve İSTENMEYEN ) değişiklikleri bıraktı .

Çeşitli git co <filename>başlangıç durumuna endeksi geri döndürüldü. Sonunda, şubeye geçtim git co <branch-name>ve git stash popçatışma olmadan çözülen yeni bir tane çalıştırdım .


2

Bazı fikirler:

  • git mergetoolBirleştirme dosyalarını orijinal ve yeni parçalara bölmek için kullanın . Umarım bunlardan biri, içinde saklanmayan değişikliklerin olduğu dosyadır.

  • Sadece bu değişiklikleri geri almak için saklamanın farkını tersine uygulayın. Muhtemelen dosyaları birleştirme çakışmalarıyla manuel olarak ayırmanız gerekecektir (umarım yukarıdaki hile işe yarayacaktır).

Bunlardan hiçbirini test etmedim, bu yüzden çalışacaklarından emin değilim.


1

git stash pop"Kirli" dizinde, taahhüt edilmemiş değişikliklerle temiz çoğaltabilirim , ancak henüz bir birleşme çatışması oluşturan pop değil.

Eğer birleştirme çatışma üzerine sen kaybolmadı uygulamak çalıştı uyuşturucu madde, incelemek için deneyebileceğiniz git show stash@{0}(isteğe ile --oursveya --theirs) ile karşılaştırmak git statisve git diff HEAD. Zımba uygulamasından hangi değişikliklerin geldiğini görebilmelisiniz.


1

DavidG, birleştirme çakışması nedeniyle zulayı atmadığı konusunda doğruysa, sadece çalışma dizininizi temizlemeniz gerekir. Önem verdiğiniz git commither şey hızla . (Daha sonra bitiremezseniz resetveya squashtaahhütte bulunabilirsiniz .) O zaman güvenliğe önem git resetverdiğiniz her şeyle, git stash popçalışma dizininize dökülen diğer her şeyle .


1

Soruda git stash popolduğu gibi, aşamasından önce hiçbir aşama değişikliği yoksa , aşağıdaki iki komutun çalışması gerekir.

git diff --name-only --cached | xargs git checkout --ours HEAD
git ls-tree stash@{0}^3 --name-only | xargs rm

Birincisi, başarılı veya değil, stash'dan herhangi bir birleşmeyi tersine çevirir. İkincisi, stash tarafından tanıtılan izlenmemiş dosyaları siler.

Kimden man git stash: The working directory must match the index. @ @ DavidG'nin işaret ettiği gibi stash pop, şu anda kullanılmamış olan değiştirilmiş dosyalar çakışırsa başarısız olur. Bu nedenle, geri dönmenin ötesinde gevşetici birleştirme çatışmaları hakkında endişelenmemize gerek yoktur HEAD. Geriye kalan değiştirilmiş dosyalar daha sonra sakla ile ilişkisizdir vestash pop

Aşamalı değişiklikler olsaydı, aynı komutlara güvenip güvenemeyeceğimizden emin değilim ve @Ben Jackson'ın tekniğini denemek isteyebilirsiniz. Takdir edilen öneriler ..

İşte tüm çeşitli durumlar için bir test kurulumu https://gist.github.com/here/4f3af6dafdb4ca15e804

# Result:
# Merge succeeded in m (theirs)
# Conflict in b
# Unstaged in a
# Untracked in c and d

# Goal:
# Reverse changes to successful merge m
# Keep our version in merge conflict b
# Keep our unstaged a
# Keep our untracked d
# Delete stashed untracked c

Bence bu şimdiye kadarki en doğru cevap. Çok iyi düşünülmüş.
Ajan Cuma

0

git reflogGit geçmişinizde yapılan tüm değişiklikleri listelemek için kullanın . Bir eylem kimliğini kopyalayın ve yazıngit reset ACTION_ID


2
Git açılmadan önce bir reflog girişi oluşturmuyor (bir taahhütte bulunmanız gerekiyor)
Casebash

-1

Başkalarının cevabımı yararlı bulmasını umarak buraya gönderiyorum. Farklı bir dalda saklanandan daha farklı bir dalda saklamak için çalıştığımda da benzer bir sorun yaşadım. Benim durumumda, taahhüt edilmemiş veya dizinde ancak hala birleştirme çakışmaları durumuna (@pid ile aynı durumda) var hiçbir dosya vardı. Diğerleri daha önce işaret ettiği gibi, başarısız git stash pop gerçekten benim saklamak, daha sonra Hızlı git sıfırlama kafa HEAD artı orijinal şubesine geri dönüyor ve oradan saklamak yapmak benim sorunum çözdü.

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.