2 # Copyright 2010 - 2012, Tim Henigan <tim.henigan@gmail.com>
4 # Perform a directory diff between commits in the repository using
5 # the external diff or merge tool specified in the user's config.
7 USAGE
='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*]
9 --cached Compare to the index rather than the working tree.
11 --copy-back Copy files back to the working tree when the diff
12 tool exits (in case they were modified by the
13 user). This option is only valid if the diff
14 compared with the working tree.
17 --extcmd=<command> Specify a custom command for viewing diffs.
18 git-diffall ignores the configured defaults and
19 runs $command $LOCAL $REMOTE when this option is
20 specified. Additionally, $BASE is set in the
25 .
"$(git --exec-path)/git-sh-setup"
28 .
"$(git --exec-path)/git-mergetool--lib"
30 merge_tool
="$(get_merge_tool)"
31 if test -z "$merge_tool"
33 echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
39 # All the file paths returned by the diff command are relative to the root
40 # of the working copy. So if the script is called from a subdirectory, it
41 # must switch to the root of working copy before trying to use those paths.
42 cdup
=$
(git rev-parse
--show-cdup) &&
44 echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
48 # mktemp is not available on all platforms (missing from msysgit)
49 # Use a hard-coded tmp dir if it is not available
50 tmp
="$(mktemp -d -t tmp.XXXXXX 2>/dev/null)" ||
{
51 tmp
=/tmp
/git-diffall-tmp.$$
52 mkdir
"$tmp" ||
exit 1
55 trap 'rm -rf "$tmp" 2>/dev/null' EXIT
71 -h|
--h|
--he|
--hel|
--help)
80 -x|
--e|
--ex|
--ext|
--extc|
--extcm|
--extcmd)
83 echo You must specify the tool
for use with
--extcmd
94 echo Invalid option
: "$1"
98 # could be commit, commit range or path limiter
110 if test -n "$dashdash_seen"
116 elif test -z "$right"
129 # Determine the set of files which changed
130 if test -n "$left" && test -n "$right"
132 left_dir
="cmt-$(git rev-parse --short $left)"
133 right_dir
="cmt-$(git rev-parse --short $right)"
135 if test -n "$compare_staged"
138 elif test -n "$merge_base"
140 git
diff --name-only "$left"...
"$right" -- $paths >"$tmp/filelist"
142 git
diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
146 left_dir
="cmt-$(git rev-parse --short $left)"
148 if test -n "$compare_staged"
151 git
diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
153 right_dir
="working_tree"
154 git
diff --name-only "$left" -- $paths >"$tmp/filelist"
159 if test -n "$compare_staged"
162 git
diff --name-only --cached -- $paths >"$tmp/filelist"
164 right_dir
="working_tree"
165 git
diff --name-only -- $paths >"$tmp/filelist"
169 # Exit immediately if there are no diffs
170 if test ! -s "$tmp/filelist"
175 if test -n "$copy_back" && test "$right_dir" != "working_tree"
177 echo "--copy-back is only valid when diff includes the working tree."
181 # Create the named tmp directories that will hold the files to be compared
182 mkdir
-p "$tmp/$left_dir" "$tmp/$right_dir"
184 # Populate the tmp/right_dir directory with the files to be compared
189 ls_list
=$
(git ls-tree
$right "$name")
190 if test -n "$ls_list"
192 mkdir
-p "$tmp/$right_dir/$(dirname "$name")"
193 git show
"$right":"$name" >"$tmp/$right_dir/$name" || true
195 done < "$tmp/filelist"
196 elif test -n "$compare_staged"
200 ls_list
=$
(git ls-files
-- "$name")
201 if test -n "$ls_list"
203 mkdir
-p "$tmp/$right_dir/$(dirname "$name")"
204 git show
:"$name" >"$tmp/$right_dir/$name"
206 done < "$tmp/filelist"
208 # Mac users have gnutar rather than tar
209 (tar --ignore-failed-read -c -T "$tmp/filelist" |
(cd "$tmp/$right_dir" && tar -x)) ||
{
210 gnutar
--ignore-failed-read -c -T "$tmp/filelist" |
(cd "$tmp/$right_dir" && gnutar
-x)
214 # Populate the tmp/left_dir directory with the files to be compared
219 ls_list
=$
(git ls-tree
$left "$name")
220 if test -n "$ls_list"
222 mkdir
-p "$tmp/$left_dir/$(dirname "$name")"
223 git show
"$left":"$name" >"$tmp/$left_dir/$name" || true
226 if test -n "$compare_staged"
228 ls_list
=$
(git ls-tree HEAD
"$name")
229 if test -n "$ls_list"
231 mkdir
-p "$tmp/$left_dir/$(dirname "$name")"
232 git show HEAD
:"$name" >"$tmp/$left_dir/$name"
235 mkdir
-p "$tmp/$left_dir/$(dirname "$name")"
236 git show
:"$name" >"$tmp/$left_dir/$name"
239 done < "$tmp/filelist"
245 if test -n "$diff_tool"
248 eval $diff_tool '"$LOCAL"' '"$REMOTE"'
250 run_merge_tool
"$merge_tool" false
253 # Copy files back to the working dir, if requested
254 if test -n "$copy_back" && test "$right_dir" = "working_tree"
257 git_top_dir
=$
(git rev-parse
--show-toplevel)
258 find "$tmp/$right_dir" -type f |
261 cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"