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@xxxxxxxxx> --- 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@xxxxxxxxx> +# +# 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 -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html