From: Tim Henigan <tim.henigan@gmail.com>
To: git@vger.kernel.org
Cc: Thomas Rast <trast@student.ethz.ch>,
Seba Illingworth <seba.illingworth@gmail.com>
Subject: [PATCH] contrib/diffall: Add script to perform directory diff using external diff tool
Date: Tue, 13 Apr 2010 21:15:21 -0400 [thread overview]
Message-ID: <4BC51729.7090906@gmail.com> (raw)
The existing 'git difftool' command allows the user to view git diffs
using an external diff tool. However, if multiple files contain
differences, a separate instance of the diff tool is launched for
each one.
This script launches a single instance of the external diff tool
and performs a directory diff between the specified revisions.
The before/after files are copied to a tmp directory to do this.
The 'diff.tool' configuration option must be set for this script
to work.
The user interface matches the standard 'git diff' command.
Signed-off-by: Tim Henigan <tim.henigan@gmail.com>
---
This script is based on an example provided by Thomas Rast on the Git list [1].
I tested with:
- msysgit and kdiff3 (the platform where I first needed this script)
- cygwin git and kdiff3
- git and meld
[1] http://thread.gmane.org/gmane.comp.version-control.git/124807
contrib/diffall/git-diffall | 159 +++++++++++++++++++++++++++++++++++++++++++
1 files changed, 159 insertions(+), 0 deletions(-)
create mode 100755 contrib/diffall/git-diffall
diff --git a/contrib/diffall/git-diffall b/contrib/diffall/git-diffall
new file mode 100755
index 0000000..c24fba9
--- /dev/null
+++ b/contrib/diffall/git-diffall
@@ -0,0 +1,159 @@
+#!/bin/sh -e
+# Copyright 2010, Tim Henigan <tim.henigan@gmail.com>
+#
+# Perform a directory diff between commits in the repository using
+# the external diff tool specified in the 'diff.tool' configuration
+# option.
+
+USAGE='<options> <commit>{0,2} -- <path>*
+
+--cached Compare to the index rather than the working tree
+commit SHA1 of a commit
+path Limit the diff to the specified paths
+'
+
+. git-sh-setup
+
+if [ -z $(git config --get diff.tool) ]; then
+ echo "Error: The 'diff.tool' configuration option must be set."
+ usage
+fi
+
+start_dir=$(pwd)
+cd_to_toplevel # needed to access tar utility
+
+# mktemp is not available on all platforms (missing from msysgit)
+# Use a hard-coded tmp dir if it is not available
+if [ -z $(which mktemp) ]; then
+ tmp=/tmp/git-diffall-tmp
+else
+ tmp="$(mktemp -d)"
+fi
+mkdir -p "$tmp" "$tmp"/a "$tmp"/b
+
+left=
+right=
+paths=
+path_sep=
+compare_staged=
+common_anscestor=
+
+while test $# != 0; do
+ case "$1" in
+ -h|--h|--he|--hel|--help)
+ usage
+ ;;
+ --cached)
+ compare_staged=1
+ ;;
+ --)
+ path_sep=1
+ ;;
+ -*)
+ echo Invalid option: "$1"
+ usage
+ ;;
+ *)
+ # could be commit, commit range or path limiter
+ case "$1" in
+ *...*)
+ left=${1%...*}
+ right=${1#*...}
+ common_anscestor=1
+ ;;
+ *..*)
+ left=${1%..*}
+ right=${1#*..}
+ ;;
+ *)
+ if [ -n "$path_sep" ]; then
+ if [ -z "$paths" ]; then
+ paths=$1
+ else
+ paths="$paths $1"
+ fi
+ elif [ -z "$left" ]; then
+ left=$1
+ elif [ -z "$right" ]; then
+ right=$1
+ else
+ if [ -z "$paths" ]; then
+ paths=$1
+ else
+ paths="$paths $1"
+ fi
+ fi
+ ;;
+ esac
+ ;;
+ esac
+ shift
+done
+
+# Determine the set of files which changed
+if [ -n "$left" ] && [ -n "$right" ]; then
+ if [ -n "$compare_staged" ]; then
+ usage
+ elif [ -n "$common_anscestor" ]; then
+ git diff --name-only "$left"..."$right" -- "$paths" > "$tmp"/filelist
+ else
+ git diff --name-only "$left" "$right" -- "$paths" > "$tmp"/filelist
+ fi
+elif [ -n "$left" ]; then
+ if [ -n "$compare_staged" ]; then
+ git diff --name-only --cached "$left" -- "$paths" > "$tmp"/filelist
+ else
+ git diff --name-only "$left" -- "$paths" > "$tmp"/filelist
+ fi
+else
+ if [ -n "$compare_staged" ]; then
+ git diff --name-only --cached -- "$paths" > "$tmp"/filelist
+ else
+ git diff --name-only -- "$paths" > "$tmp"/filelist
+ fi
+fi
+
+# Exit immediately if there are no diffs
+if [ ! -s "$tmp"/filelist ]; then
+ exit 0
+fi
+
+# Populate the tmp/b directory with the files to be compared
+if [ -n "$right" ]; then
+ while read name; do
+ mkdir -p "$tmp"/b/"$(dirname "$name")"
+ git show "$right":"$name" > "$tmp"/b/"$name"
+ done < "$tmp"/filelist
+elif [ -n "$compare_staged" ]; then
+ while read name; do
+ mkdir -p "$tmp"/b/"$(dirname "$name")"
+ git show :"$name" > "$tmp"/b/"$name"
+ done < "$tmp"/filelist
+else
+ tar -c -T "$tmp"/filelist | (cd "$tmp"/b && tar -x)
+fi
+
+# Populate the tmp/a directory with the files to be compared
+while read name; do
+ mkdir -p "$tmp"/a/"$(dirname "$name")"
+ if [ -n "$left" ]; then
+ git show "$left":"$name" > "$tmp"/a/"$name"
+ else
+ if [ -n "$compare_staged" ]; then
+ git show HEAD:"$name" > "$tmp"/a/"$name"
+ else
+ git show :"$name" > "$tmp"/a/"$name"
+ fi
+ fi
+done < "$tmp"/filelist
+
+cd "$tmp"
+$(git config --get diff.tool) a b
+
+# On exit, remove the tmp directory
+cleanup () {
+ cd "$start_dir"
+ rm -rf "$tmp"
+}
+
+trap cleanup EXIT
--
1.7.0.3.291.g5e4f6.dirty
reply other threads:[~2010-04-14 1:15 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=4BC51729.7090906@gmail.com \
--to=tim.henigan@gmail.com \
--cc=git@vger.kernel.org \
--cc=seba.illingworth@gmail.com \
--cc=trast@student.ethz.ch \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).