【问题标题】:`git stash` during a merge conflict合并冲突期间的`git stash`
【发布时间】:2012-02-19 00:41:53
【问题描述】:

我们做了坏事。

我们在合并冲突期间运行了git stash save,现在我们无法恢复我们的工作。

我们尝试过的事情:

git pull -Xours origin master
git stash apply --index

还有:

 git pull origin master
 git stash save --keep-index "merge conflicts"
 git stash apply stash@{1}

请帮忙!

【问题讨论】:

  • 你真的做了什么有意义的事吗? (你真的需要恢复隐藏的更改吗?)你可以重置尝试的合并,然后重新开始吗?
  • 是和否,分别。这些更改包括超过一天的合并冲突解决。
  • @bukzor:如果您需要超过一天的时间来解决合并冲突,那么可能是时候重新考虑有关分支处理和工作分配(或合并频率)的政策了。毕竟,由于一次提交中完成的更改量很大,如此冗长的合并解决方案是很难找到错误的一个很好的来源
  • 你遇到了什么错误?为什么不是简单的“git stash apply”?
  • @inger:由于stash save 清除索引并且stash apply 不修改它,因此您最终会得到常规的非暂存更改,而不是合并。我想在合并期间应用这些更改,但不知道如何。

标签: git merge git-merge git-stash merge-conflict-resolution


【解决方案1】:

我摆脱这种情况的解决方案(合并冲突期间的 git stash pop)是:

  • 创建并签出一个新的(本地)分支mytemporarybranch

    git branch mytemporarybranch && git checkout mytemporarybranch

  • 提交到这个 mytemporarybranch

    git commit -m "我凌乱的合并和挤压"

  • 结帐我的原始分支

    git checkout myoriginalbranch

  • 正确合并(这次没有 squash pop/apply!)

  • squashmytemporarybranch 合并到 myoriginal 分支上

    git merge --squash mytemporarybranch

【讨论】:

    【解决方案2】:

    鉴于您的最后一条评论:您可以使用

    git stash megre --no-commit <branch>
    

    将索引置于“合并”状态而不提交更改

    然后用你想要的修改它:

    如果您已经在 stash 中完成了合并:

    git reset #to remove the "conflicts" flags
    git checkout <initial commit> -- ./ #to revert everything to the previous working state,
    git stash apply   #apply your changes
    

    一旦一切都处于理想状态,git commit


    关于bukzor的评论:git checkout &lt;tree-ish&gt;git checkout &lt;tree-ish&gt; -- &lt;files&gt;其实有很大区别。

    来自reference 上的git checkout

    • git checkout &lt;branch&gt; :此表单通过更新索引、工作树和 HEAD 来切换分支以反映指定的分支或提交。

    • git checkout [-p|--patch] &lt;tree-ish&gt; -- &lt;pathspec&gt; :当 或 --patch 给出时, git checkout 不会切换分支。它从索引文件或命名的 (通常是提交)更新工作树中的命名路径。

    git checkout &lt;initial commit&gt; 确实会丢弃合并信息。

    另一方面,git checkout &lt;initial commit&gt; -- ./(注意额外的-- ./)将保留合并信息,并将每个跟踪的文件恢复到&lt;initial commit&gt;中的状态。

    【讨论】:

    • git checkout 将删除合并状态,不是吗?我最终会得到一个正常的提交,它会复制 master 中的所有更改。
    【解决方案3】:

    我今天做了同样的事情,并采取了不同的方法(经过反复试验)以回到存储之前的状态,这样我就可以继续解决冲突并完成合并。

    首先,在目标分支中取消部分合并后,我捕获了具有剩余冲突的文件列表(文本文件或编辑器选项卡)。这只是取消存储后未暂存文件的列表,因为已解决冲突的文件将在暂存之前暂存。

    $ git status
    # Changes not staged for commit:
    #   (use "git add <file>..." to update what will be committed)
    #   (use "git checkout -- <file>..." to discard changes in working directory)
    #
    #   modified:   myproject/src/main/java/com/acme/package3/Class3.java
    #   modified:   myproject/src/main/java/com/acme/package3/Class4.java
    #
    

    接下来,我创建了一个补丁并将分支重置为合并前的状态:

    $ git diff HEAD > ~/merge-with-resolved-conflicts.patch
    $ git reset --hard HEAD
    

    然后我创建了一个临时分支(从合并目标分支派生),并应用了补丁:

    $ git checkout -b my-temp-branch
    $ git apply ~/merge-with-resolved-conflicts.patch
    $ git commit -a -m "Merge with resolved conflicts"
    

    因此,my-temp-branch 的 HEAD 现在包含已合并的所有内容,包括已解决冲突的文件和剩余冲突的文件。

    然后我切换回原来的分支,再次合并,查看了git状态

    $ git checkout my-branch
    $ git merge other-branch
    $ git status
    

    状态显示有冲突的文件的完整列表:

    # Unmerged paths:
    #   (use "git add <file>..." to mark resolution)
    #
    #   both modified:      myproject/src/main/java/com/acme/package1/Class1.java
    #   both modified:      myproject/src/main/java/com/acme/package2/Class2.java
    #   both modified:      myproject/src/main/java/com/acme/package3/Class3.java
    #   both modified:      myproject/src/main/java/com/acme/package3/Class4.java
    #
    

    现在我需要比较这两个文件列表。第二个列表中但不是第一个列表中的所有文件都已被解析(在此示例中,Class1.java 和 Class2.java)。因此,对于每个文件,我从临时分支中提取了冲突解决的版本(如cherry-pick,但针对单个文件而不是整个提交):

    $ git checkout my-temp-branch myproject/src/main/java/com/acme/package1/Class1.java
    $ git checkout my-temp-branch myproject/src/main/java/com/acme/package2/Class2.java
    

    完成此操作后,我回到了存储之前的状态,因此我可以继续解决剩余的冲突并提交合并。

    【讨论】:

      【解决方案4】:

      问题似乎是git stash 没有保存对您尝试合并的分支的引用。在合并期间,它存储在名为MERGE_HEAD 的引用中。

      要修复它并恢复到以前的状态,您需要找到您尝试合并的修订版(假设它是 d7a9884a380f81b2fbf002442ee9c9eaf34ff68d),并在应用存储后将 MERGE_HEAD 设置为它。

      然后您可以应用 stash(使用 --index 重新暂存之前暂存的所有内容),并设置您的 MERGE_HEAD:

      git stash apply --index
      git update-ref MERGE_HEAD d7a9884a380f81b2fbf002442ee9c9eaf34ff68d
      

      【讨论】:

      • 虽然以上对我来说似乎是正确的,但我并不完全相信仅设置 MERGE_HEAD 和 unstashing 就足以恢复合并状态。如果可能的话,我会避免在冲突期间使用 git stash。
      • 遇到了同样的问题,并尝试了您的解决方案。它抱怨.git/MERGE_MSG 不存在,我使用自定义合并消息创建了该文件,然后我提交了。我担心我会被标记为合并中所有更改的作者,但它似乎已经成功了。其他作者得到了适当的认可。谢谢:)
      • 我的 pre-commit 钩子中有一个 stash 和一个 pop,它正在删除 .git/MERGE_HEAD 导致在尝试提交合并时找不到文件错误。它会在我第二次尝试时提交,但实际上不会被“合并”。
      【解决方案5】:

      当您处于冲突状态(索引和工作目录)时,您将无法执行git stash - 它会在未合并条目时出错。

      确保你真的做了一个藏匿。查看git stautsgit stash show 的输出

      【讨论】:

      • git stash 之前,我已经解决了冲突并继续使用git add。在我有git add 我的决议之后,我做了进一步的编辑,然后做了一个git stash save msg。所以确实成功了。
      • @bukzor 实际上,我只是在 Windows 7 上使用 msysgit 1.8.3 对此进行了测试。如果文件存在冲突(即没有尝试解决合并冲突),那么 git stash save确实中止,没有隐藏冲突的文件。所以这其实是对的,不是假的
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-04-08
      • 2017-07-24
      • 1970-01-01
      • 2013-10-22
      • 1970-01-01
      • 1970-01-01
      • 2015-10-15
      相关资源
      最近更新 更多