Thursday, August 20, 2009

Git diff and difftool, open all files immediately, not in serial

The default behaviour for git diff and git difftool is to open each file in a new window one at a time, only opening the next file after the previous has closed - its a one-by-one, one direction process.

I wanted them to open all at once, so that in a external diff tool such as BeyondCompare all files would open immediately in tabs within a single window.

Hunting around I found a couple of related workarounds (here and here), which involved copying the appropriate before/after files to temp directories and doing a folder diff. But I wanted something simpler, more lightweight, and the breakthrough came when I played with background tasks in bash.

The result of some testing was git diff --name-only to get a file list and git difftool & to diff in a background task; initially using a for-loop, followed by some input/improvements (David and kaizer.se), until the following was finally settled on:

Git diffall

1. Write the following code to a file called git-diffall and place in your path (I put it in …/my-git-install-dir/cmd/ )

#!/bin/sh
git diff --name-only "$@" | while read filename; do
git difftool "$@" --no-prompt "$filename" &
done

2. And run it in git (with usual diff input parameters), for example:

git diffall
git diffall HEAD
git diffall --cached
git diffall rev1..rev2

The initial journey started here at StackOverflow, but I thought this was good content for a first blog post - hope you find it useful.

10 comments:

  1. Ah, great tip! Finally, difftool is useful again and is used the way it should be to begin with. :)

    ReplyDelete
  2. Heyo getting an error response:
    fatal: ambiguous argument 'path/file': unknown revision or path not in the working tree.
    Use '--' to separate paths from revisions

    any ideas? hit me up at @victusfate on twitter or messel at victusmedia dot com

    ReplyDelete
  3. A word of warning: I just tried this in a directory with *lots* of changes. My comp went completely unresponsive and is killing processes. I can't even start a bash shell to kill the offensive processes. I have meld set as the diff tool.

    It looks like the system just runs out of memory because it tries to start so many processes.

    ReplyDelete
  4. If you are thinking of using this, you should really look at http://github.com/dbingham/git-diffall which I forked from http://github.com/thenigan/git-diffall

    It is a script that you can throw in your path. Then you use it like:
    $ git diffall
    $ git diffall HEAD
    $ git diffall --cached
    $ git diffall rev1..rev2
    etc

    No excessive process spawning for diffs with many, many changes.

    The only requirement is that you get yourself a diff tool that does directory diffs. I like SmartSynchronize, but suit yourself.

    ReplyDelete
  5. The error that mentions "Use '--' to separate paths from revisions" is caused by the output of 'git diff --name-only' being a set of paths written from the top of the repo tree. So you need to run `git diffall` from there.

    ReplyDelete
  6. Add

    while [ ! -d .git ] && [ ! `pwd` = "/" ]; do cd ..; done

    to the top of this script so it works from any subdirectory of your working copy.

    ReplyDelete
  7. Thank you! This is exactly what I needed. :)
    Regards,
    Mark.

    ReplyDelete
  8. Any idea how to open the compares in different tabs in a meld window rather than opening two instances of meld?

    ReplyDelete