【问题标题】:Aborting a stash pop in Git在 Git 中中止 stash pop
【发布时间】:2012-01-20 21:23:46
【问题描述】:

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

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

【问题讨论】:

  • 至于您未提交的更改:这些更改是否已经在索引中?
  • 你能发布你正在使用的git版本吗?
  • 接受的答案看起来很复杂。我认为永远不要在不干净的工作目录上尝试git stash pop 之类的事情是非常好的一般做法。在这种情况下,您可以简单地 git reset --hard 并且您的存储仍然完好无损。 (这或多或少是@BradKoch 的链接主题所暗示的)
  • @StevenLu,我同意,但如果您为了将更改移动到不同的分支而隐藏更改,则问题可能出现在干净的工作目录中。存储与旧分支上不存在的新分支上存在的提交冲突。

标签: git git-stash


【解决方案1】:

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

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

简单。

【讨论】:

  • 所以你想要的 stash 会一直保留在 stash 列表中,直到你成功弹出?
  • 这不是原始问题的答案,因为它会擦除未提交的本地更改。
  • @RyanClark 请参阅下面的DavidG's answer。基本上,是的,它保留在存储列表中。
  • 我认为发现自己处于这种情况的绝大多数用户会发现此解决方案是理想的。我无法想象在尝试 stash pop 进入工作目录之前我在工作目录中未提交更改的情况。这听起来像是灾难的秘诀。
  • 不错。阅读完这篇文章后,我查看了 git stash pop 文档,上面写着“应用状态可能会因冲突而失败;在这种情况下,它不会从存储列表中删除。”。所以,这就是为什么在重置/结帐后能够重新弹出存储。
【解决方案2】:

简单的一个班轮

我一直在用

git reset --merge

我不记得它曾经失败过。


注意:git reset --merge 将丢弃任何分阶段的更改

【讨论】:

  • 给这个人一枚勋章
  • 最好的我不知道为什么人们不给这个单行答案
  • 如果您这样做,之前隐藏的内容会发生什么情况?它是放回藏匿处还是丢失了?
  • 它被放回藏匿处。
  • @AdamParkin 当git stash pop因为合并冲突不成功时,stash的内容会自动存入stash而不是删除
【解决方案3】:

好的,我想我已经解决了“git stash unapply”。它比git apply --reverse 更复杂,因为您需要反向合并操作,以防git stash apply 完成任何合并。

反向合并要求将所有当前更改推送到索引中:

  • git add -u

然后反转git stash apply完成的merge-recursive

  • 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)

【讨论】:

  • 执行此操作后,之前隐藏的编辑会永远丢失,还是会重新回到隐藏中?
  • git stash apply 永远不会丢弃存储,当合并失败时,git stash pop 也会保留存储
  • 如果在原始存储弹出期间发生合并冲突,将会发生坏事
  • 继续滚动以获得更好的答案
【解决方案4】:

编辑:来自 pop 部分的git help stash 文档:

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

如果使用了 --index 选项,则不仅会尝试恢复工作树的更改,还会尝试恢复索引的更改。但是,当您发生冲突时,这可能会失败(这些冲突存储在索引中,因此您无法再按原来的方式应用更改)。

尝试将所有 repo 硬拷贝到一个新目录中(这样你就有了它的副本)并运行:

git stash show 并将输出保存在某处,如果您关心的话。

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

这应该让你的 repo 保持以前的状态(希望我仍然无法重现你的问题)

===

我正在尝试重现您的问题,但使用 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 试图合并我的更改,它只是失败了。您有任何我们可以遵循的重现步骤来帮助您吗?

【讨论】:

  • 尝试将更改存储到其他文件。
  • 尝试存储到不同的文件不起作用(请参阅新的复制步骤)。我只是无法重现这个问题......
  • 如果工作目录中有未提交的更改,此解决方案将不起作用。
  • @here 这不是一个真正的解决方案,这只是为了表明我无法重现 OP 的问题,并且他没有提供任何步骤来到达他所在的位置。
  • 实际情况是:1)更改文件A。2)存储更改3)在文件A中进行冲突更改并提交(例如更改同一行)4)更改文件B 5)执行'git stash pop '。现在您有冲突和本地更改。通常它们将位于不同的文件中,但您永远不会知道哪些来自 stash 的非冲突修改文件以及哪些是本地未暂存的更改。
【解决方案5】:

如果您不必担心您所做的任何其他更改并且只想返回上一次提交,那么您可以这样做:

git reset .
git checkout .
git clean -f

【讨论】:

    【解决方案6】:

    好的,我想我已经设法找到了一个工作流程,可以让你回到你需要的地方(就像你没有完成弹出一样)。

    提前备份!!我不知道这是否对你有用,所以复制你的整个仓库以防万一它不起作用。

    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^
    

    我已经通过一个简单的示例运行它,它可以让您回到您想要的位置 - 直接在弹出存储之前,您的本地更改和存储仍然可以弹出。

    【讨论】:

    • 如果这不太奏效,希望它能帮您顺利完成任务! :-)
    • git stash show -p | git apply -R 如果git stash apply 进行了任何真正的合并,那将不起作用。看我的回答...
    【解决方案7】:

    我以不同的方式解决了这个问题。这就是发生的事情。

    首先,我跳错了分支并发生了冲突。存储保持不变,但索引处于冲突解决状态,阻塞了许多命令。

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

    几个git co &lt;filename&gt; 将索引恢复到初始状态。最后,我用git co &lt;branch-name&gt; 切换分支并运行一个新的git stash pop,解决没有冲突。

    【讨论】:

      【解决方案8】:

      一些想法:

      • 使用git mergetool 将合并文件拆分为原始部分和新部分。希望其中之一是其中包含您的非存储更改的文件。

      • 反向应用存储的差异,以撤消这些更改。您可能必须手动拆分具有合并冲突的文件(希望上述技巧适用)。

      我没有测试过这两种方法,所以我不确定它们是否会起作用。

      【讨论】:

        【解决方案9】:

        我可以在“脏”目录上重现干净的git stash pop,但未提交更改,但尚未弹出会产生合并冲突。

        如果在合并冲突时您尝试应用的存储没有消失,您可以尝试检查git show stash@{0}(可选--ours--theirs)并与git statis 进行比较和git diff HEAD。您应该能够看到哪些更改来自应用存储。

        【讨论】:

          【解决方案10】:

          如果 DavidG 由于合并冲突而没有弹出存储是正确的,那么您只需要清理您的工作目录。快速git commit您关心的一切。 (如果你还没有完成,你可以在以后resetsquash 提交。)然后将所有你关心的安全,git reset 其他所有git stash pop 转储到你的工作目录中。

          【讨论】:

            【解决方案11】:

            如果在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
            

            【讨论】:

            • 我认为这是迄今为止最正确的答案。考虑得很周到。
            【解决方案12】:

            使用git reflog 列出在您的 git 历史记录中所做的所有更改。复制操作 ID 并输入 git reset ACTION_ID

            【讨论】:

            • Git 在你弹出之前不会创建一个 reflog 条目(你需要有一个提交)
            【解决方案13】:

            尝试使用 if 跟踪文件。

            git rm <path to file>
            git reset  <path to file>
            git checkout <path to file>
            

            【讨论】:

              【解决方案14】:

              我在这里发帖希望其他人发现我的回答有帮助。当我尝试在与我存储的分支不同的分支上进行存储弹出时,我遇到了类似的问题。在我的情况下,我没有未提交或索引中的文件,但仍然进入合并冲突情况(与@pid 相同的情况)。正如其他人之前指出的那样,失败的 git stash pop 确实保留了我的存储,然后快速 git reset HEAD 加上回到我原来的分支并从那里进行存储确实解决了我的问题。

              【讨论】:

                猜你喜欢
                • 2017-11-25
                • 2013-02-23
                • 2012-12-25
                • 1970-01-01
                • 2015-02-10
                • 1970-01-01
                • 1970-01-01
                • 2016-04-09
                相关资源
                最近更新 更多