mirror of
https://github.com/git/git.git
synced 2024-11-01 14:57:52 +01:00
bfe392e367
Prior to this commit, the cleanup trap that removes the tmp dir created by the script would fail on Windows. The error was silently ignored by the script. On Windows, a directory cannot be removed while it is the working directory of the process (thanks to Johannes Sixt on the Git list for this info [1]). This commit eliminates the 'cd' into the tmp directory that caused the error. [1]: http://article.gmane.org/gmane.comp.version-control.git/193086 Signed-off-by: Tim Henigan <tim.henigan@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
257 lines
5.6 KiB
Bash
Executable file
257 lines
5.6 KiB
Bash
Executable file
#!/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)
|
|
|
|
# All the file paths returned by the diff command are relative to the root
|
|
# of the working copy. So if the script is called from a subdirectory, it
|
|
# must switch to the root of working copy before trying to use those paths.
|
|
cdup=$(git rev-parse --show-cdup) &&
|
|
cd "$cdup" || {
|
|
echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
|
|
exit 1
|
|
}
|
|
|
|
# set up temp dir
|
|
tmp=$(perl -e 'use File::Temp qw(tempdir);
|
|
$t=tempdir("/tmp/git-diffall.XXXXX") or exit(1);
|
|
print $t') || exit 1
|
|
trap 'rm -rf "$tmp"' 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
|
|
while read name
|
|
do
|
|
if test -n "$right"
|
|
then
|
|
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
|
|
elif test -n "$compare_staged"
|
|
then
|
|
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
|
|
else
|
|
if test -e "$name"
|
|
then
|
|
mkdir -p "$tmp/$right_dir/$(dirname "$name")"
|
|
cp "$name" "$tmp/$right_dir/$name"
|
|
fi
|
|
fi
|
|
done < "$tmp/filelist"
|
|
|
|
# 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"
|
|
|
|
LOCAL="$tmp/$left_dir"
|
|
REMOTE="$tmp/$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
|