终止Git中的隐藏流行


257

我弹出一个存储区,发生合并冲突。与列出为重复项的问题不同,我已经在要保留的目录中进行了一些未提交的更改。我不仅要使合并冲突消失,还要使目录恢复到弹出之前的状态。

我尝试了git merge --abort,但是git声称没有进行合并。有没有一种简单的方法可以在不破坏我原来在目录中进行的更改的情况下中止弹出窗口?


至于您未提交的更改:这些更改是否已在索引中?
约根森

可以发布您正在使用的git版本。
Tinman 2012年


2
接受的答案看起来很复杂。我认为,绝对不要尝试git stash pop对不干净的工作目录进行尝试,这是一个很好的常规做法。在这种情况下,您可以简单地git reset --hard保存自己的藏匿处。(这或多或少是@BradKoch的链接主题所建议的)
Steven Lu

1
@StevenLu,我同意,但是如果您存储更改以便将它们移动到另一个分支,则可能在干净的工作目录中发生此问题。存储与新分支上的提交冲突,旧分支上不存在。
杰克·史蒂文斯-哈斯

Answers:


55

好的,我想我已经解决了“ git stash unapply”的问题。它比git apply --reverse因为需要进行反向合并操作(以防万一)进行了任何合并而复杂git stash apply

反向合并要求将所有当前更改都推入索引:

  • git add -u

然后倒置的merge-recursive是做的git stash apply

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

现在,您将只剩下非隐藏更改。它们将在索引中。git reset如果愿意,可以用来取消更改。

考虑到您原来的git stash apply失败,我认为反向操作也可能失败,因为它要撤消的某些事情没有完成。

这是一个示例,展示了工作副本(通过git status)如何再次干净地结束:

 $ 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
完成此操作后,先前保存的编辑会永远丢失,还是重新保存?
Brian H.

7
git stash apply永远不会丢弃存储,并且当合并失败时,它git stash pop也会保留存储
Xerus

如果在原始存储流行期间发生合并冲突,将会发生不好的事情
3ocene

285

我的用例:只是尝试跳到错误的分支上而发生冲突。我需要做的只是撤消弹出窗口,但将其保留在存储列表中,这样我就可以将其弹出到正确的分支上。我这样做:

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

简单。


22
因此,您想要的存储藏在存储清单中,直到您成功弹出为止?
瑞安·克拉克

52
这不是原始问题的答案,因为它会擦除未提交的本地更改。
德米特里

13
@RyanClark请参阅下面的DavidG的答案。基本上,是的,它保留在存储列表中。
fkorsa

1
我认为绝大多数处于这种情况的用户会发现此解决方案是理想的。我无法想象在尝试stash pop进入工作目录之前未提交更改的情况。这听起来像是灾难的秘诀。
Shadoninja

2
真好 阅读完这篇文章后,我看了看git stash pop docs,它说:“应用状态可能因冲突而失败;在这种情况下,不会从存储列表中删除它。” 因此,这就是为什么在重置/签出后可以重新弹出存储库的原因。
布雷迪·霍尔特

48

编辑:从git help stash弹出部分的文档中:

应用状态可能会因冲突而失败;在这种情况下,它不会从存储列表中删除。您需要手动解决冲突,然后手动调用git stash drop。

如果使用--index选项,则不仅尝试恢复工作树的更改,而且尝试恢复索引的更改。但是,当您有冲突时(存储在索引中,因此您不再可以像以前那样应用更改),这可能会失败。

尝试将所有存储库硬拷贝到新目录(这样就可以得到副本)并运行:

git stash show 并在需要时将其保存在某个地方。

然后:git stash drop删除冲突的存储,然后:git reset HEAD

那应该使您的存储库保持以前的状态(希望我仍然无法再现您的问题)

===

我正在尝试再现您的问题,但是当我使用时,我得到的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

在一个干净的目录中:

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试图合并我的更改,但是失败了。您是否有任何复制步骤可为您效劳?


尝试将更改存储到其他文件。
asmeurer

尝试隐藏到其他文件不起作用(请参阅新的repro步骤)。我只是
无法解决

1
如果工作目录中有未提交的更改,则此解决方案不起作用。
这里

@here这不是一个真正的解决方案,这只是表明我无法重现OP所遇到的问题,并且他没有提供任何步骤来达到他所处的位置。
DavidG

1
实际情况是:1)更改文件A。2)存储更改3)在文件A中进行冲突更改并提交(例如更改同一行)4)更改文件B 5)执行“ git stash pop”。现在您有冲突和本地更改。通常,它们将位于不同的文件中,但是您将永远不会知道从存储中哪些非冲突的已修改文件以及哪些是本地未暂存的更改。
德米特里

16

我一直都用

git reset --merge

我不记得它曾经失败过。


@GauravPaliwal,我下次再看git reset。您知道它在功能上是否相同git reset --merge吗?
Kenn Sebesta

5

如果您不必担心所做的任何其他更改,而只想回到上一次提交,则可以执行以下操作:

git reset .
git checkout .
git clean -f

4

好的,我想我已经找到了一个工作流程,可以将您带回到需要的位置(就像您没有做流行音乐一样)。

进行备份之前!!我不知道这是否适合您,因此请复制您的整个存储库以防万一。

1)通过选择补丁中的所有更改来解决合并问题并解决所有冲突(在tortoisemerge中,这显示为one.REMOETE(它们的))。

git mergetool

2)提交这些更改(它们已经通过mergetool命令添加了)。给它提交“合并”的消息或您记得的东西。

git commit -m "merge"

3)现在,您仍将拥有最初开始的本地未暂存的更改,并从补丁中提交了新的提交(我们可以稍后删除它)。现在提交您未进行的更改

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

4)颠倒补丁。可以使用以下命令完成此操作:

git stash show -p | git apply -R

5)进行以下更改:

git commit -a -m "reversed patch"

6)摆脱补丁/取消补丁提交

git rebase -i HEAD^^^

从中,删除其中带有“合并”和“反向补丁”的两行。

7)找回您未做的更改,并撤消“本地更改”提交

git reset HEAD^

我已经通过一个简单的示例进行了遍历,它使您回到想要的位置-在弹出隐藏存储之前,就可以进行本地更改并且仍然可以弹出存储存储。


如果那还行不通,希望它能带给您大部分帮助!:-)
agentgonzo

git stash show -p | git apply -R如果进行了git stash apply真正的合并,那是行不通的。看看我的答案...
本杰克逊

3

我以某种不同的方式解决了这个问题。这是发生了什么。

首先,我在错误的分支上弹出并遇到冲突。存储区保持完整,但索引处于冲突解决状态,从而阻止了许多命令。

一个简单的git reset HEAD中止冲突解决方案,并保留未提交(和UNWANTED)的更改。

有几个git co <filename>将索引恢复到初始状态。最后,我使用切换了分支git co <branch-name>并运行了new git stash pop,该解析没有冲突。


2

一些想法:

  • 使用git mergetool到合并文件分割成原始的和新的部件。希望其中之一是其中包含非隐藏更改的文件。

  • 反向应用存储的差异,以撤消那些更改。您可能必须手动将合并冲突的文件分割开(希望上述技巧可以解决)。

我没有测试任何一个,所以我不确定它们是否会起作用。


1

我可以git stash pop在“脏”目录上重做干净的目录,并进行未提交的更改,但是还没有弹出会产生合并冲突。

如果发生合并冲突,您尝试应用的存储区没有消失,则可以尝试检查git show stash@{0}(可选地使用--ours--theirs)并与git statis和进行比较git diff HEAD。您应该能够看到应用存储所带来的变化。


1

如果DavidG是正确的,因为合并冲突没有弹出存储,那么您只需要清理工作目录即可。迅速处理git commit您关心的一切。(您可以resetsquash稍后再提交。)然后,您在乎安全的git reset所有事项以及git stash pop倾倒到您的工作目录。


1

如果在之前没有分段更改git stash pop,如问题中所示,那么以下两个命令应该起作用。

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

第一个从存储中撤消任何合并,无论成功与否。第二个删除存储的所有未跟踪文件。

发件人man git stashThe working directory must match the index. @DavidG指出,stash pop如果任何当前未暂存的已修改文件发生冲突,将失败。因此,除了回到之前,我们不必担心消除合并冲突HEAD。然后,所有剩余的已修改文件都与存储无关,并在stash pop

如果发生了阶段性的更改,我不清楚我们是否可以依靠相同的命令,您可能想尝试@Ben Jackson的技术。建议表示赞赏。

这是针对所有各种情况的测试设置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

我认为这是迄今为止最正确的答案。深思熟虑。
特工


-1

我在这里发布,希望其他人对我的回答有所帮助。当我尝试在与我藏身的分支不同的分支上进行藏匿弹出时,我遇到了类似的问题。就我而言,我没有未提交或在索引中的文件,但仍然陷入合并冲突的情况(与@pid相同)。正如其他人先前指出的那样,失败的git stash pop确实确实保留了我的stash,然后快速git reset HEAD再返回到我的原始分支并从那里进行隐藏确实解决了我的问题。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.