contrib: add git-diffall script
The 'git difftool' allows the user to view diffs using an external tool. It runs a separate instance of the tool for each file in the diff. This makes it tedious to review changes spanning multiple files. The 'git-diffall' script instead prepares temporary directories with the files to be compared and launches a single instance of the external diff tool to view them (i.e. a directory diff). The 'diff.tool' or 'merge.tool' configuration variable is used to specify which external tool is used. Signed-off-by: Tim Henigan <tim.henigan@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
bd444cadb5
commit
1252bbe1c6
31
contrib/diffall/README
Normal file
31
contrib/diffall/README
Normal file
@ -0,0 +1,31 @@
|
|||||||
|
The git-diffall script provides a directory based diff mechanism
|
||||||
|
for git.
|
||||||
|
|
||||||
|
To determine what diff viewer is used, the script requires either
|
||||||
|
the 'diff.tool' or 'merge.tool' configuration option to be set.
|
||||||
|
|
||||||
|
This script is compatible with most common forms used to specify a
|
||||||
|
range of revisions to diff:
|
||||||
|
|
||||||
|
1. git diffall: shows diff between working tree and staged changes
|
||||||
|
2. git diffall --cached [<commit>]: shows diff between staged
|
||||||
|
changes and HEAD (or other named commit)
|
||||||
|
3. git diffall <commit>: shows diff between working tree and named
|
||||||
|
commit
|
||||||
|
4. git diffall <commit> <commit>: show diff between two named commits
|
||||||
|
5. git diffall <commit>..<commit>: same as above
|
||||||
|
6. git diffall <commit>...<commit>: show the changes on the branch
|
||||||
|
containing and up to the second, starting at a common ancestor
|
||||||
|
of both <commit>
|
||||||
|
|
||||||
|
Note: all forms take an optional path limiter [-- <path>*]
|
||||||
|
|
||||||
|
The '--extcmd=<command>' option allows the user to specify a custom
|
||||||
|
command for viewing diffs. When given, configured defaults are
|
||||||
|
ignored and the script runs $command $LOCAL $REMOTE. Additionally,
|
||||||
|
$BASE is set in the environment.
|
||||||
|
|
||||||
|
This script is based on an example provided by Thomas Rast on the
|
||||||
|
Git list [1]:
|
||||||
|
|
||||||
|
[1] http://thread.gmane.org/gmane.comp.version-control.git/124807
|
261
contrib/diffall/git-diffall
Executable file
261
contrib/diffall/git-diffall
Executable file
@ -0,0 +1,261 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
# Copyright 2010 - 2012, Tim Henigan <tim.henigan@gmail.com>
|
||||||
|
#
|
||||||
|
# Perform a directory diff between commits in the repository using
|
||||||
|
# the external diff or merge tool specified in the user's config.
|
||||||
|
|
||||||
|
USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*]
|
||||||
|
|
||||||
|
--cached Compare to the index rather than the working tree.
|
||||||
|
|
||||||
|
--copy-back Copy files back to the working tree when the diff
|
||||||
|
tool exits (in case they were modified by the
|
||||||
|
user). This option is only valid if the diff
|
||||||
|
compared with the working tree.
|
||||||
|
|
||||||
|
-x=<command>
|
||||||
|
--extcmd=<command> Specify a custom command for viewing diffs.
|
||||||
|
git-diffall ignores the configured defaults and
|
||||||
|
runs $command $LOCAL $REMOTE when this option is
|
||||||
|
specified. Additionally, $BASE is set in the
|
||||||
|
environment.
|
||||||
|
'
|
||||||
|
|
||||||
|
SUBDIRECTORY_OK=1
|
||||||
|
. "$(git --exec-path)/git-sh-setup"
|
||||||
|
|
||||||
|
TOOL_MODE=diff
|
||||||
|
. "$(git --exec-path)/git-mergetool--lib"
|
||||||
|
|
||||||
|
merge_tool="$(get_merge_tool)"
|
||||||
|
if test -z "$merge_tool"
|
||||||
|
then
|
||||||
|
echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
|
||||||
|
usage
|
||||||
|
fi
|
||||||
|
|
||||||
|
start_dir=$(pwd)
|
||||||
|
|
||||||
|
# needed to access tar utility
|
||||||
|
cdup=$(git rev-parse --show-cdup) &&
|
||||||
|
cd "$cdup" || {
|
||||||
|
echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# mktemp is not available on all platforms (missing from msysgit)
|
||||||
|
# Use a hard-coded tmp dir if it is not available
|
||||||
|
tmp="$(mktemp -d -t tmp.XXXXXX 2>/dev/null)" || {
|
||||||
|
tmp=/tmp/git-diffall-tmp.$$
|
||||||
|
mkdir "$tmp" || exit 1
|
||||||
|
}
|
||||||
|
|
||||||
|
trap 'rm -rf "$tmp" 2>/dev/null' EXIT
|
||||||
|
|
||||||
|
left=
|
||||||
|
right=
|
||||||
|
paths=
|
||||||
|
dashdash_seen=
|
||||||
|
compare_staged=
|
||||||
|
merge_base=
|
||||||
|
left_dir=
|
||||||
|
right_dir=
|
||||||
|
diff_tool=
|
||||||
|
copy_back=
|
||||||
|
|
||||||
|
while test $# != 0
|
||||||
|
do
|
||||||
|
case "$1" in
|
||||||
|
-h|--h|--he|--hel|--help)
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
--cached)
|
||||||
|
compare_staged=1
|
||||||
|
;;
|
||||||
|
--copy-back)
|
||||||
|
copy_back=1
|
||||||
|
;;
|
||||||
|
-x|--e|--ex|--ext|--extc|--extcm|--extcmd)
|
||||||
|
if test $# = 1
|
||||||
|
then
|
||||||
|
echo You must specify the tool for use with --extcmd
|
||||||
|
usage
|
||||||
|
else
|
||||||
|
diff_tool=$2
|
||||||
|
shift
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
--)
|
||||||
|
dashdash_seen=1
|
||||||
|
;;
|
||||||
|
-*)
|
||||||
|
echo Invalid option: "$1"
|
||||||
|
usage
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
# could be commit, commit range or path limiter
|
||||||
|
case "$1" in
|
||||||
|
*...*)
|
||||||
|
left=${1%...*}
|
||||||
|
right=${1#*...}
|
||||||
|
merge_base=1
|
||||||
|
;;
|
||||||
|
*..*)
|
||||||
|
left=${1%..*}
|
||||||
|
right=${1#*..}
|
||||||
|
;;
|
||||||
|
*)
|
||||||
|
if test -n "$dashdash_seen"
|
||||||
|
then
|
||||||
|
paths="$paths$1 "
|
||||||
|
elif test -z "$left"
|
||||||
|
then
|
||||||
|
left=$1
|
||||||
|
elif test -z "$right"
|
||||||
|
then
|
||||||
|
right=$1
|
||||||
|
else
|
||||||
|
paths="$paths$1 "
|
||||||
|
fi
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
;;
|
||||||
|
esac
|
||||||
|
shift
|
||||||
|
done
|
||||||
|
|
||||||
|
# Determine the set of files which changed
|
||||||
|
if test -n "$left" && test -n "$right"
|
||||||
|
then
|
||||||
|
left_dir="cmt-$(git rev-parse --short $left)"
|
||||||
|
right_dir="cmt-$(git rev-parse --short $right)"
|
||||||
|
|
||||||
|
if test -n "$compare_staged"
|
||||||
|
then
|
||||||
|
usage
|
||||||
|
elif test -n "$merge_base"
|
||||||
|
then
|
||||||
|
git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist"
|
||||||
|
else
|
||||||
|
git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
|
||||||
|
fi
|
||||||
|
elif test -n "$left"
|
||||||
|
then
|
||||||
|
left_dir="cmt-$(git rev-parse --short $left)"
|
||||||
|
|
||||||
|
if test -n "$compare_staged"
|
||||||
|
then
|
||||||
|
right_dir="staged"
|
||||||
|
git diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
|
||||||
|
else
|
||||||
|
right_dir="working_tree"
|
||||||
|
git diff --name-only "$left" -- $paths >"$tmp/filelist"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
left_dir="HEAD"
|
||||||
|
|
||||||
|
if test -n "$compare_staged"
|
||||||
|
then
|
||||||
|
right_dir="staged"
|
||||||
|
git diff --name-only --cached -- $paths >"$tmp/filelist"
|
||||||
|
else
|
||||||
|
right_dir="working_tree"
|
||||||
|
git diff --name-only -- $paths >"$tmp/filelist"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Exit immediately if there are no diffs
|
||||||
|
if test ! -s "$tmp/filelist"
|
||||||
|
then
|
||||||
|
exit 0
|
||||||
|
fi
|
||||||
|
|
||||||
|
if test -n "$copy_back" && test "$right_dir" != "working_tree"
|
||||||
|
then
|
||||||
|
echo "--copy-back is only valid when diff includes the working tree."
|
||||||
|
exit 1
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Create the named tmp directories that will hold the files to be compared
|
||||||
|
mkdir -p "$tmp/$left_dir" "$tmp/$right_dir"
|
||||||
|
|
||||||
|
# Populate the tmp/right_dir directory with the files to be compared
|
||||||
|
if test -n "$right"
|
||||||
|
then
|
||||||
|
while read name
|
||||||
|
do
|
||||||
|
ls_list=$(git ls-tree $right "$name")
|
||||||
|
if test -n "$ls_list"
|
||||||
|
then
|
||||||
|
mkdir -p "$tmp/$right_dir/$(dirname "$name")"
|
||||||
|
git show "$right":"$name" >"$tmp/$right_dir/$name" || true
|
||||||
|
fi
|
||||||
|
done < "$tmp/filelist"
|
||||||
|
elif test -n "$compare_staged"
|
||||||
|
then
|
||||||
|
while read name
|
||||||
|
do
|
||||||
|
ls_list=$(git ls-files -- "$name")
|
||||||
|
if test -n "$ls_list"
|
||||||
|
then
|
||||||
|
mkdir -p "$tmp/$right_dir/$(dirname "$name")"
|
||||||
|
git show :"$name" >"$tmp/$right_dir/$name"
|
||||||
|
fi
|
||||||
|
done < "$tmp/filelist"
|
||||||
|
else
|
||||||
|
# Mac users have gnutar rather than tar
|
||||||
|
(tar --ignore-failed-read -c -T "$tmp/filelist" | (cd "$tmp/$right_dir" && tar -x)) || {
|
||||||
|
gnutar --ignore-failed-read -c -T "$tmp/filelist" | (cd "$tmp/$right_dir" && gnutar -x)
|
||||||
|
}
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Populate the tmp/left_dir directory with the files to be compared
|
||||||
|
while read name
|
||||||
|
do
|
||||||
|
if test -n "$left"
|
||||||
|
then
|
||||||
|
ls_list=$(git ls-tree $left "$name")
|
||||||
|
if test -n "$ls_list"
|
||||||
|
then
|
||||||
|
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
|
||||||
|
git show "$left":"$name" >"$tmp/$left_dir/$name" || true
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
if test -n "$compare_staged"
|
||||||
|
then
|
||||||
|
ls_list=$(git ls-tree HEAD "$name")
|
||||||
|
if test -n "$ls_list"
|
||||||
|
then
|
||||||
|
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
|
||||||
|
git show HEAD:"$name" >"$tmp/$left_dir/$name"
|
||||||
|
fi
|
||||||
|
else
|
||||||
|
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
|
||||||
|
git show :"$name" >"$tmp/$left_dir/$name"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done < "$tmp/filelist"
|
||||||
|
|
||||||
|
cd "$tmp"
|
||||||
|
LOCAL="$left_dir"
|
||||||
|
REMOTE="$right_dir"
|
||||||
|
|
||||||
|
if test -n "$diff_tool"
|
||||||
|
then
|
||||||
|
export BASE
|
||||||
|
eval $diff_tool '"$LOCAL"' '"$REMOTE"'
|
||||||
|
else
|
||||||
|
run_merge_tool "$merge_tool" false
|
||||||
|
fi
|
||||||
|
|
||||||
|
# Copy files back to the working dir, if requested
|
||||||
|
if test -n "$copy_back" && test "$right_dir" = "working_tree"
|
||||||
|
then
|
||||||
|
cd "$start_dir"
|
||||||
|
git_top_dir=$(git rev-parse --show-toplevel)
|
||||||
|
find "$tmp/$right_dir" -type f |
|
||||||
|
while read file
|
||||||
|
do
|
||||||
|
cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
|
||||||
|
done
|
||||||
|
fi
|
Loading…
Reference in New Issue
Block a user