3

I have a few dozen files I need to compare and merge with vimdiff. Is there any way to queue pairs of files for comparison so that I may open them all at once, rather than returning to the shell again and again to open each pair of files?

Could this be done by opening each pair in its own tab? My shell is Bash.

Michael Berkowski
  • 267,341
  • 46
  • 444
  • 390

5 Answers5

2

If you want to compare all the files in a directory with each other in all combinations, here's how to do that and still avoid comparing a pair twice (or a file with itself):

for f1 in *; do 
  for f2 in *; do 
    [[ $f1 < $f2 ]] || vimdiff "$f1" "$f2"
  done
done
unhammer
  • 4,306
  • 2
  • 39
  • 52
2

This is doable without any shell shenanigans by setting all the diffy options globally (along with some autocommands, because vim gets angry if you try to diff more than 8 files at once)

vim -c 'windo set diff scrollbind cursorbind scrollopt+=hor nowrap foldmethod=diff foldcolumn=2 | au BufWinEnter * setlocal diff | au BufWinLeave * setlocal nodiff' -O2 your filenames here

This will open all your files in buffers, and vertically split vim into two windows (use -o2 if you want horizontal), and always be in diff mode, even if you switch between buffers or open new files.

If you're merging all your files together into one super-file, then using :bn will be fine for getting around.

If you're merging pairs of files, then you'll want some variation of :windo bn N, where N depends on how you listed your files:

  • For A1 A2 B1 B2 C1 C2, :windo bn 2 will do the right thing
  • For A1 B1 C1 A2 B2 C2, you'll need to initially go to the A2 buffer, and then :windo bn 1 will do the right thing

I pulled the settings from the help file:

In each of the edited files these options are set:

'diff'    on
'scrollbind'  on
'cursorbind'  on
'scrollopt' includes "hor"
'wrap'    off
'foldmethod'  "diff"
'foldcolumn'  value from 'diffopt', default is 2

These options are set local to the window. When editing another file they are reset to the global value.

And only discovered the need for the autocommand nonsense empirically.

Sodium
  • 21
  • 1
  • 3
1

You can't do it using a single vim command as far as I am aware. You could start vimdiff from within a for loop.

Alternatively try "meld" http://meld.sourceforge.net/

Stephen Paulger
  • 5,204
  • 3
  • 28
  • 46
1

Like StephenPaulger suggested a for loop would work well for a small number of files. The way that I would do it is to create a small script (say do.sh) with the following contents:

#!/bin/bash

files1=( file1.txt file1_.txt )
files2=( file2.txt file2_.txt )
for i in {0..1} ; do
  vimdiff ${files1[i]} ${files2[i]}
done

this would allow you to not have to type anything in the shell while doing the diff for the different files, once you exit the diff for one pair of files the other shows up right away.

Another useful tip to use here is to put the following in your .vimrc

if &diff
   map <f4> :qa<cr>
   map <f5> :wqa!<cr>
   map <f6> :qa!<cr>
 endif

then if there are no changes you just press f4 to exit, if there are changes you press f5.

skeept
  • 12,077
  • 7
  • 41
  • 52
1

Here is another answer that opens each pair in it's own tab. Save again the following in a file (do2.sh):

#!/bin/bash

files1=( file1.txt file2.txt file3.txt )
files2=( file1_.txt file2_.txt file3_.txt )

cmd="vim -c 'set diffopt=filler,vertical' -c 'edit ${files1[0]}' -c 'diffsplit ${files2[0]}' "
echo $cmd
for i in {1..2}; do
  cmd="${cmd} -c 'tabe ${files1[i]}' -c 'diffsplit ${files2[i]}' "
done

eval $cmd

when you execute it will open the pairs in their own tab.

skeept
  • 12,077
  • 7
  • 41
  • 52
  • By the time your answer came in I'd made it through most pairs manually. This would have been exactly what I hoped for though, thanks. – Michael Berkowski Mar 25 '11 at 17:21
  • This is a great idea, but vim has a limit of ten -c arguments, so it doesn't work for the "few dozen files" specified in the question (as I discovered trying to use it). Better is to use the for loop to write the tabe and diffsplit commands to a file, then source it with -S on starting vim. – Etaoin Mar 12 '15 at 16:09
  • Also better to use an array than a string to build up complex commands: avoids wordsplitting issues. – D. Ben Knoble Dec 27 '18 at 14:51