29

How do I make git automatically run git mergetool for any merge conflict? This should apply for all merges, using merge, rebase, pull, etc.

Matthew Flaschen
  • 278,309
  • 50
  • 514
  • 539
  • 1
    Maybe you can use a [githook](http://www.kernel.org/pub/software/scm/git/docs/githooks.html), e.g. `post-checkout` (I don't know if it is actually invoked during a merge. `post-merge` requires a successful merge) – Tobias Kienzler Aug 03 '12 at 08:35
  • 1
    @TobiasKienzler You might be on to something. If you can figure out a working solution I'll give you the bounty for this question. – Quinn Strahl Jul 14 '13 at 23:03
  • @QuinnStrahl I don't think there currently exists a hook which is executed before each of the various commands leading to a merge, so [rospov's wrapper](http://stackoverflow.com/a/17620046/321973) is probably the easiest solution. That or modifying the git source to implement a `pre-merge` hook functionality, in which case you could of course simply have git run mergetool on conflicts depending on a config setting anyway... – Tobias Kienzler Jul 15 '13 at 07:54
  • 1
    Hm, okay. Thanks for the help. I think I'll submit a patch. – Quinn Strahl Jul 15 '13 at 13:17
  • @QuinnStrahl In case you have submitted a Patch by now, I would appreciate a link here :) – IARI Dec 12 '16 at 19:57

3 Answers3

8

You cannot (yet) make git do this.


This may or may not be an acceptable workaround.

Create a function in your ~/.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 isn't invoked when it merges:

$ 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 is called when there are conflicts:

$ 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 is not called on other errors:

$ git merge adasds
fatal: adasds - not something we can merge
onionjake
  • 3,905
  • 27
  • 46
  • 1
    This isn't making git automatically open mergetool, this is making the shell do it. – Quinn Strahl Jul 17 '13 at 16:36
  • 1
    Why the downvote? This is essentially a cleaner way to implement rosipov's answer. – onionjake Jul 17 '13 at 21:13
  • How is it cleaner? You're missing some kinds of conflicts (such as `git stash pop`). Since he doesn't filter by command, that's not an issue. As you note yourself, the current code will launch `git mergetool` on any error with 1 status. – Matthew Flaschen Jul 17 '13 at 22:35
  • I cannot say for sure if there are any other errors with a return value of 1 for the commands in question as git return values are generally undocumented. I have yet to find one that wasn't a merge conflict though. – onionjake Jul 24 '13 at 04:06
  • 2
    @QuinnStrahl git cannot do it (yet), so is it a wrong answer to accomplish it through the shell? – onionjake Jul 24 '13 at 04:11
  • @onionjake Yes. The question was how to make *git* do it, not how to make the shell do it. – Quinn Strahl Jul 24 '13 at 16:18
  • +1, @Quinn: as @onionjake noted, git *cannot* do it. Don't be pedantic; the OP wants a way to run `git mergetool` automatically, and I highly doubt he cares whether it's git or the shell doing it. – Brian Vandenberg Jul 24 '13 at 16:57
  • @BrianVandenberg Given that OP personally (and rightfully) criticised this answer and has yet to accept it (or any of the other answers that fail to address the question as literally asked), I'm inclined to disagree with you. Furthermore, this answer was posted after I placed a bounty that specifically requested a git-native method. – Quinn Strahl Jul 24 '13 at 17:04
  • @QuinnStrahl, I've seen people be openly hostile of answers they get to questions they ask, even when the answers are good ones. That doesn't validate (or invalidate) the criticism. Furthermore, there's a list of thousands of questions marked as unanswered because the OP either doesn't bother or doesn't care. – Brian Vandenberg Sep 16 '13 at 15:28
  • @BrianVandenberg It was not my objective to convince you that hostility evidences the validity of criticism. Perhaps the OP forgot to accept this answer after pointing out why it was not good one, but I don't think it likely. – Quinn Strahl Sep 16 '13 at 20:20
  • -1: I'm with Quinn. It does not do it using git, which was part of the question - I do find the answer using an alias more appropriate. – IARI Dec 12 '16 at 19:54
  • The answer is "You cannot (yet) make git do this", the rest was a helpful suggestion on how you might get the same effect. I will edit the answer to make that clearer. – onionjake Dec 13 '16 at 23:07
4

You could always use alias

alias 'git-merge'='git merge && git mergetool'
alias 'git-rebase'='git rebase && git mergetool'
alias 'git-pull'='git pull && git mergetool'

And/or write a helper script along these lines

#/bin/bash
git $*
[ "$(git ls-files –abbrev –unmerged | wc -l)" -gt 0 ] && git mergetool

and then

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

There is no direct way of invoking mergetool, because it is only one of several ways to merge (see "HOW TO RESOLVE CONFLICTS" in man 1 git-merge).

j13r
  • 2,576
  • 2
  • 21
  • 28
  • 3
    As I mentioned, I only want to call `mergetool` if there is a conflict. The "only one of several ways to merge" argument isn't convincing. Yes, there are multiple ways, but it's quite reasonable to want to choose one as the default. – Matthew Flaschen Apr 05 '12 at 17:51
  • 1
    git mergetool won't do anything if there is no conflict. – j13r Apr 05 '12 at 18:17
2

As far as I know, there is no porcelain way to do it.

You can have a wrapper around git like this (file git_mergetool.sh, on your path, +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

Then add alias:

echo alias git=\"git_mergetool.sh\" >> ~/.bashrc

Every time you invoke git, the wrapper will check if the word "CONFLICT" pops up. If it does - wrapper launches mergetool.

This can be improved by adding more precise phrase to $SEARCH (like "Automatic merge failed; fix conflicts and then commit the result.") as well as by checking if first argument ($1) is in the list of commands resulting in merge conflict (pull, merge, etc...). Otherwise you will end up parsing a lot of unnecessary data if git command output is too long.

Ruslan Osipov
  • 5,655
  • 4
  • 29
  • 44
  • Is it possible without effectively aliasing git? – Quinn Strahl Jul 13 '13 at 11:56
  • @QuinnStrahl You can name script `git` (without file extension) and put in on your path before the actual git executable. But it is pretty much just another way of aliasing. So no, I don't know of a way to accomplish that without aliasing git. – Ruslan Osipov Jul 13 '13 at 16:54
  • 2
    Should be somewhat workable, but the CONFLICT regex needs improvement. I think it will currently pick it up anywhere, even in e.g. diff output. At least you can filter by line position (e.g. an anchor), and maybe expand the text. – Matthew Flaschen Jul 17 '13 at 22:37