我该如何在错误合并后获取我的git合并冲突?

23

我正在尝试合并两个具有许多更改(其中一些具有合并冲突)的分支。 我使用了git mergetool来合并文件,但后来发现我错误地合并了其中一些文件。 我基本上想回到那些文件的冲突状态,以便重新运行mergetool并纠正我的错误。 因为大部分内容都是正确的,所以我不想放弃整个合并。

我已经尝试了重置到我的head然后执行git checkout -m other_branch -- my_file,但没有成功。 我最终将其重置到HEAD,将文件从另一个分支中取出,并在文件上只执行git add --patch,并将我想要的部分暂存。 但肯定有更好的方法...

4个回答

12

首先,在重置到HEAD之前,通过检查索引中是否存在冲突状态来确定。

$ git ls-files --stage --abbrev my_file
你应该会得到类似下面的东西:
100644 257cc56  1        my_file
100644 b7d6715 2        my_file
100644 5716ca5  3        my_file

如果你不理解这个,你需要使用git update-index,就像Charles Bailey所说的那样,或者使用临时文件。如果你已经有了,那么

$ git checkout -m my_file

应该有效(我已经验证过了)。


1
刚刚尝试了 git checkout -m 命令,即使我只有一个已暂存的文件版本(即在执行 git add 或成功使用 git mergetool 后),它也能正常工作。也许这是较新的 Git 版本特性(我正在使用 2.1.3 版本)。 - siegi

6
您可以使用git update-index命令并使用--cacheinfo或者--index-info选项来删除索引中给定文件的0条目,同时将123 条目分别填充为基础版本、本地版本和远程版本,但这可能会比较繁琐。
最好的方法可能是将各个版本提取到临时文件中,手动运行您的合并工具,将答案写入正确的文件并添加成功合并的结果。
例如:
git show $(git merge-base HEAD MERGE_HEAD):file >base-file
git show HEAD:file >local-file
git show MERGE_HEAD:file >remote-file

手动运行 mergetool,写入 file
git add file

0

您可以使用:

git checkout [--ours|--theirs|--merge] <paths>

检查正在合并进入或从中合并的分支上发现的路径,或重新创建冲突的合并。

git-checkout手册对此问题有更多的说明。

正如Charles Bailey指出的那样,当已将合并的文件添加到索引中时,这无法工作。我做了一些尝试,这里是一个应该能够完成工作的脚本:

#!/bin/bash
#
# Distributed under the GNU General Public License, version 2.0.
#
# git-goat:
#
#   Restore a merge conflict, after it has already been resolved.

# Lifted from contrib/completion/git-completion.bash
__gitdir ()
{
    if [ -z "${1-}" ]; then
        if [ -n "${__git_dir-}" ]; then
            echo "$__git_dir"
        elif [ -d .git ]; then
            echo .git
        else
            git rev-parse --git-dir 2>/dev/null
        fi
    elif [ -d "$1/.git" ]; then
        echo "$1/.git"
    else
        echo "$1"
    fi
}

into=$(git describe --all HEAD)
from=$(cat $(__gitdir)/MERGE_HEAD)
base=$(git merge-base $into $from)

case "$1" in --ours|--theirs|--merge) whose=$1; shift; esac

[ -z "$1" ] && echo "fatal: at least one file has to be specified" && exit

for file in "$@"
do
    (
        echo -e "0 0000000000000000000000000000000000000000\t$file"
        git ls-tree $base $file | sed -e "s/\t/ 1\t/"
        git ls-tree $into $file | sed -e "s/\t/ 2\t/"
        git ls-tree $from $file | sed -e "s/\t/ 3\t/"
    ) | git update-index --index-info
    git checkout ${whose:-"--merge"} $file
done

请注意我没有进行过多测试。如果您发现任何问题或有其他改进在这里是一个可分叉的"gist"。

1
值得注意的是,这仅在您未退出合并工具并成功保存时才有效,因为这会导致合并工具“添加”已解决的文件并从索引中删除冲突条目。 - CB Bailey
Charles Bailey,你确定你说的是正确的吗?对我来说,这个脚本看起来非常像是将索引恢复到添加之前的状态!它不是最初指的是:{1,2,3}:,而是通过HEAD、MERGE_HEAD和merge-base...来寻址提交。 - Tilman Vogel
@TilmanVogel:请检查我评论的答案版本,而不是针对我的评论所做的更新。 - CB Bailey
@CharlesBailey:哦,抱歉,我没有注意到历史记录。他甚至在答案中提到了你的评论... - Tilman Vogel

0
如果您意外地同意了冲突解决提示框,却没有保存Mergetool中的更改,我认为您可以将已暂存的更改隐藏起来,然后重新执行合并操作。
git stash
git merge <other branch>

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接