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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.