What are the various "vimdiff" difftools/mergetools?
Asked Answered
O

2

11

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

  • vimdiff
  • vimdiff1
  • vimdiff2
  • vimdiff3

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

Overrefinement answered 2/7, 2021 at 3:8 Comment(0)
O
9

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.

Overrefinement answered 2/7, 2021 at 3:8 Comment(0)
A
1

The Documentation/mergetools/vimdiff.txt recently (2022) documented:

In addition, for backwards compatibility with previous Git versions, you can also append 1, 2 or 3 to either vimdiff or any of the variants (ex: vimdiff3, nvimdiff1, etc...) to use a predefined layout.

In other words, using --tool=[g,n,]vimdiffx is the same as using --tool=[g,n,]vimdiff and setting configuration variable mergetool.[g,n,]vimdiff.layout to...

  • x=1: "@LOCAL, REMOTE"
  • x=2: "LOCAL, MERGED, REMOTE"
  • x=3: "MERGED"

Example: using --tool=gvimdiff2 will open gvim with three columns (LOCAL,MERGED and REMOTE).


This should work better with Git 2.37.3 (Q3 2022), which does fix a "vimdiff3" regression.

See commit 34133d9, commit b6014ee, commit ffcc33f, commit 60184ab, commit 66dd83a, commit 79db50d, commit d619183 (10 Aug 2022) by Felipe Contreras (felipec).
(Merged by Junio C Hamano -- gitster -- in commit 4d8074b, 18 Aug 2022)

mergetools: vimdiff: fix single window layouts

Cc: Fernando Ramos
Signed-off-by: Felipe Contreras
Reviewed-by: Fernando Ramos

Layouts with a single window other than "MERGED" do not work (e.g. "LOCAL" or "MERGED+LOCAL").

This is because as the documentation of bufdo says:

The last buffer (or where an error occurred) becomes the current
buffer.

And we do always do bufdo the end.

Additionally, we do it only once, when it should be per tab.

Fix this by doing it once per tab right after it's created and before any buffer is switched.

Aztec answered 7/9, 2022 at 12:43 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.