如何使git在合并冲突时自动打开合并工具?

30

我如何使 Git 在任何合并冲突时自动运行 git mergetool?这应适用于所有合并,包括使用 mergerebasepull 等。


1
也许你可以使用 githook,例如 post-checkout(我不知道它在合并期间是否被实际调用。post-merge 需要成功合并)。 - Tobias Kienzler
1
@TobiasKienzler 你可能有眉目了。如果你能找出一个可行的解决方案,我会给你这个问题的赏金。 - Quinn Strahl
@QuinnStrahl 我认为目前不存在在合并之前执行各种命令的钩子,因此 rospov 的包装器 可能是最简单的解决方案。或者修改 git 源代码以实现 pre-merge 钩子功能,在这种情况下,您当然可以根据配置设置让 git 在冲突时运行 mergetool... - Tobias Kienzler
1
嗯,好的。谢谢你的帮助。我想我会提交一个补丁。 - Quinn Strahl
@QuinnStrahl 如果您已经提交了一个 Patch,我会很感激在此处提供一个链接 :) - IARI
3个回答

8

你目前还不能让git做到这一点。


这可能是一个可接受的解决方法。

在你的~/.bashrc中创建一个函数:

git() 
{ 
  if [[ $1 == "merge" ]] || [[ $1 == "rebase" ]] || [[ $1 == "pull" ]]; then 
    command git "$@" 
    rc=$?
    if [[ $rc == 1 ]]; then
      echo "There are conflicts, better run git-mergetool!!!"
      # There might be some other condition that returns a '1',
      # if so you can add another check like this:
      # if grep Conflicts $(git --git-dir)/MERGE_MSG;
      command git mergetool
    fi
  else 
    command git "$@"
  fi
}

在合并时Mergetool没有被调用:

$ git merge non_conflicting_branch
Merge made by the 'recursive' strategy.
 bar | 0
 1 file changed, 0 insertions(+), 0 deletions(-)
 create mode 100644 bar

当存在冲突时,Mergetool会被调用:

$ git merge conflicting_branch
Auto-merging foo
CONFLICT (content): Merge conflict in foo
Automatic merge failed; fix conflicts and then commit the result.
There are Conflicts, better run git-mergetool!!!

Mergetool在其他错误时不会被调用:

$ git merge adasds
fatal: adasds - not something we can merge

1
这不是让git自动打开mergetool,而是让shell来执行它。 - Quinn Strahl
1
为什么要踩?这本质上是一种更清晰的实现rosipov答案的方式。 - onionjake
2
@QuinnStrahl git目前无法做到这一点,因此通过shell完成它是错误的答案吗? - onionjake
@QuinnStrahl,我见过有些人对他们所问的问题得到的答案公开表现出敌意,即使这些答案是好的。这并不证明(或否定)批评的有效性。此外,还有数千个问题被标记为未回答,因为提问者要么不费心思,要么不在乎。 - Brian Vandenberg
@BrianVandenberg,我的目标不是说服你敌对情绪证明了批评的有效性。也许OP在指出这不是一个好答案后忘记接受它,但我认为这不太可能。 - Quinn Strahl
显示剩余7条评论

4
您可以始终使用别名。
alias 'git-merge'='git merge && git mergetool'
alias 'git-rebase'='git rebase && git mergetool'
alias 'git-pull'='git pull && git mergetool'

而且/或者,可以撰写一个类似这样的辅助脚本以帮助完成此任务。
#/bin/bash
git $*
[ "$(git ls-files –abbrev –unmerged | wc -l)" -gt 0 ] && git mergetool

然后

alias git='~/.git/git-script'

没有直接调用合并工具的方式,因为它只是解决冲突的多种方式之一(请参见git-merge手册中的“如何解决冲突”)。


3
如我所提到的,我只想在有冲突时才调用mergetool。"多种合并方式中的其中一种"这个论点并不令人信服。是的,有多种方法,但选择一个作为默认值是相当合理的。 - Matthew Flaschen
1
如果没有冲突,git mergetool 将不会执行任何操作。 - j13r

2
据我所知,没有一种完美的方法可以做到这一点。
您可以使用类似于以下方式的git包装器(文件git_mergetool.sh,在您的路径上,+x):
#!/bin/bash

SEARCH="CONFLICT"
OUTPUT=$(git "$@" 2>&1 | tee /dev/tty)
if `echo ${OUTPUT} | grep -i "${SEARCH}" 1>/dev/null 2>&1`
then
  git mergetool
fi

然后添加别名:
echo alias git=\"git_mergetool.sh\" >> ~/.bashrc

每次调用git时,包装器都会检查是否出现“CONFLICT”一词。如果是,则启动mergetool。
可以通过将更精确的短语添加到$SEARCH(例如“自动合并失败;解决冲突,然后提交结果。”)以及检查第一个参数($1)是否在导致合并冲突的命令列表中(pull,merge等)来改进此功能。否则,如果git命令输出太长,您将最终解析大量不必要的数据。

能否在不有效地为 Git 设置别名的情况下实现这一点? - Quinn Strahl
@QuinnStrahl 你可以将脚本命名为 git(不带文件扩展名),并将其放在实际的 git 可执行文件之前的路径上。但这基本上只是另一种别名的方式。所以,不,我不知道有什么方法可以在不使用别名的情况下完成 git 的操作。 - Ruslan Osipov
2
应该可以工作,但是“CONFLICT”正则表达式需要改进。我认为它目前会在任何地方都匹配,甚至在diff输出中也是如此。至少你可以通过行位置(例如锚点)进行过滤,并且可能扩展文本。 - Matthew Flaschen

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