gitvimdiffmergetool

What are the various "vimdiff" difftools/mergetools?


When I run git difftool --tool-help or git mergetool --tool-help, I see:

What are these different "versions"? I assume they all start Vim with different options, but what are the options? Are they documented anywhere?


Solution

  • They don't seem to be documented anywhere, unfortunately.

    The relevant source code is here. Note how vimdiff, nvimdiff, and gvimdiff are all implemented with the same script.

    Difftool

    When invoked as a difftool, they all do the same thing:

    vim -R -f -d \
      -c 'wincmd l' \
      -c 'cd $GIT_PREFIX' \
      "$LOCAL" "$REMOTE"
    

    This starts Vim in read-only mode -R and diff mode -d. For information on diff mode, see the manpage vimdiff(1) and the Vim help page diff.txt.

    Mergetool

    When invoked as a mergetool, the behavior of these options varies.

    In the diagrams below, Local corresponds to "ours", Remote corresponds to "theirs", Base corresponds to "merge base", and Merge is the file that will actually be saved to the work tree (and staged to the index if the resolution is successful).

    vimdiff

    If there is a "merge base" present, the window layout is:

    # | Local | Base | Remote |
    # | --------------------- |
    # |        Merge          |
    
    vim -f -d \
      -c '4wincmd w | wincmd J' \
      "$LOCAL" "$BASE" "$REMOTE" "$MERGED"
    

    If there is not a merge base present, the layout is:

    # |       |       |        |
    # | Local | Merge | Remote |
    # |       |       |        |
    
    vim -f -d \
      -c 'wincmd l' \
      "$LOCAL" "$MERGED" "$REMOTE"
    

    vimdiff1

    The layout is:

    # |       |        |
    # | Local | Remote |
    # |       |        |
    
    vim -f -d "$LOCAL" "$REMOTE"
    ret="$?"
    if test "$ret" -eq 0
    then
      cp -- "$LOCAL" "$MERGED"
    fi
    

    Local will then be saved to the work tree upon success, taking the place of Merged.

    vimdiff2

    The layout is identical to vimdiff without a merge base.

    vimdiff3

    Each of Local, Remote, Base (if present) will be opened but hidden. Merged will be opened and visible. You can switch among these buffers with the :buffer command.

    # With Base
    vim -f -d \
      -c 'hid | hid | hid' \
      "$LOCAL" "$REMOTE" "$BASE" "$MERGED"
    
    # Without Base
    vim -f -d \
      -c 'hid | hid' \
      "$LOCAL" "$REMOTE" "$MERGED"
    

    Create your own mergetool!

    Let's create a vimdiff4, which uses the same layout as vimdiff-with-Base, but omitting the Base part.

    Add the following to your Git config (e.g. $XDG_CONFIG_HOME/git/config):

    [mergetool "nvimdiff4"]
      # Like "nvimdiff", but always ignore $BASE.
      cmd = nvim -f -d -c '$wincmd w' -c 'wincmd J' $LOCAL $REMOTE $MERGED 
    

    When you invoke git mergetool --tool-help, you will see a new line in the output:

        user-defined:
            nvimdiff4.cmd nvim -d -c '$wincmd w' -c 'wincmd J' $LOCAL $REMOTE $MERGED
    

    Now you can run git mergetool --tool=nvimdiff4, which will invoke the command we specified above.