11

I really like git diff's output format, and I use it a lot as git diff --no-index to compare arbitrary non-git-related files. But as far as I can tell when using --no-index you can provide only a single pair of files. I'd really like to be able to pass it multiple pairs, like:

git diff --no-index a.new a.old b.new b.old

And get the kind of output you'd get by running git diff in a repo:

diff --git a/a b/a
index e965047..ce01362 100644
--- a/a
+++ b/a
@@ -1 +1 @@
-Hello
+hello
diff --git a/b b/b
index 2b60207..dd7e1c6 100644
--- a/b
+++ b/b
@@ -1 +1 @@
-Goodbye
+goodbye

Is there any way to do this with git diff, or a similar tool?

alecbz
  • 368

2 Answers2

4

Since git diff --no-index accepts also two directories and compare these, you could always write a wrapper script around that, copying your files into two temporary directories.

Other than that, I don't know of a diff tool that accepts multiple pairs of files to compare. Even diff only accepts a single pair of files, or a directory and a list of files.

4

This is basically two context-dependent versions of Jaap's answer for git diff --no-index, with an extra color suggestion.

Special coloring for moved lines

Before running git diff --no-index, you may want to set diff.colorMoved in the Git config. Alternatively, you can include a --color-moved option instead of setting it globally.

diff.colorMoved settings use a different line color when lines removed from one place show up elsewhere in the diff. This works, whether they moved within the file or they moved to another file, like in a refactor.

I have been quite pleased with the dimmed-zebra color option.

Two circumstances for diffing

Complete or almost complete sets

You have some files in a directory, current-version, that you want to compare to some other files. If the set of files you want to compare them to in new-version is nearly identical in content, just use Jaap's suggestion:

git diff --no-index current-version/ new-version/

Specific files to compare

If there are only a handful of files in one version and lots of files in the other, like so…

┌ current-project
| ├ (various folders)
| └ src
|   ├ (various files)
|   ├ foo.c
|   └ bar.c
└ proposed-replacements
  ├ new-foo.c
  └ new-bar.c

…you can try to let Git's rename detection1 do the work.

You don't care to see that the majority of the files are "missing" in proposed-replacements. You don't want to painstakingly give proposed-replacements' files the same name/path as they appear in current-project, so you leave them where they were and add a filter that includes only renamed and modified files.

git diff --no-index --diff-filter=RM current-project/ proposed-replacements/
diff --git a/current-project/src/foo.c b/proposed-replacements/new-foo.c
similarity index 65%
rename from current-project/src/foo.c
rename to proposed-replacements/new-foo.c
index dd51990..64445b1 100644
--- a/current-project/src/foo.c
+++ b/proposed-replacements/new-foo.c
@@ -1,4 +1,4 @@
 octopus
 cow
-dog
 tiger
+flamingo

diff --git a/current-project/src/bar.c b/proposed-replacements/new-bar.c similarity index 87% rename from current-project/src/bar.c rename to proposed-replacements/new-bar.c ...

The default rename detection is when the file is 50+% the same as the old version. You can tweak that with --find-renames=40% or similar. See the documentation for more.

1 I don't know what version of Git adds the degree of rename tracking that is necessary to do this. I'm using v2.18, but some of the options date back to at least 2005. Also, the testing I did was on a pretty trivial set of files.