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"
49 tmp
=$
(perl
-e 'use File::Temp qw(tempdir);
50 $t=tempdir("/tmp/git-diffall.XXXXX") or exit(1);
52 trap 'rm -rf "$tmp" 2>/dev/null' EXIT
68 -h|
--h|
--he|
--hel|
--help)
77 -x|
--e|
--ex|
--ext|
--extc|
--extcm|
--extcmd)
80 echo You must specify the tool
for use with
--extcmd
91 echo Invalid option
: "$1"
95 # could be commit, commit range or path limiter
107 if test -n "$dashdash_seen"
113 elif test -z "$right"
126 # Determine the set of files which changed
127 if test -n "$left" && test -n "$right"
129 left_dir
="cmt-$(git rev-parse --short $left)"
130 right_dir
="cmt-$(git rev-parse --short $right)"
132 if test -n "$compare_staged"
135 elif test -n "$merge_base"
137 git
diff --name-only "$left"...
"$right" -- $paths >"$tmp/filelist"
139 git
diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
143 left_dir
="cmt-$(git rev-parse --short $left)"
145 if test -n "$compare_staged"
148 git
diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
150 right_dir
="working_tree"
151 git
diff --name-only "$left" -- $paths >"$tmp/filelist"
156 if test -n "$compare_staged"
159 git
diff --name-only --cached -- $paths >"$tmp/filelist"
161 right_dir
="working_tree"
162 git
diff --name-only -- $paths >"$tmp/filelist"
166 # Exit immediately if there are no diffs
167 if test ! -s "$tmp/filelist"
172 if test -n "$copy_back" && test "$right_dir" != "working_tree"
174 echo "--copy-back is only valid when diff includes the working tree."
178 # Create the named tmp directories that will hold the files to be compared
179 mkdir
-p "$tmp/$left_dir" "$tmp/$right_dir"
181 # Populate the tmp/right_dir directory with the files to be compared
186 ls_list
=$
(git ls-tree
$right "$name")
187 if test -n "$ls_list"
189 mkdir
-p "$tmp/$right_dir/$(dirname "$name")"
190 git show
"$right":"$name" >"$tmp/$right_dir/$name" || true
192 done < "$tmp/filelist"
193 elif test -n "$compare_staged"
197 ls_list
=$
(git ls-files
-- "$name")
198 if test -n "$ls_list"
200 mkdir
-p "$tmp/$right_dir/$(dirname "$name")"
201 git show
:"$name" >"$tmp/$right_dir/$name"
203 done < "$tmp/filelist"
205 # Mac users have gnutar rather than tar
206 (tar --ignore-failed-read -c -T "$tmp/filelist" |
(cd "$tmp/$right_dir" && tar -x)) ||
{
207 gnutar
--ignore-failed-read -c -T "$tmp/filelist" |
(cd "$tmp/$right_dir" && gnutar
-x)
211 # Populate the tmp/left_dir directory with the files to be compared
216 ls_list
=$
(git ls-tree
$left "$name")
217 if test -n "$ls_list"
219 mkdir
-p "$tmp/$left_dir/$(dirname "$name")"
220 git show
"$left":"$name" >"$tmp/$left_dir/$name" || true
223 if test -n "$compare_staged"
225 ls_list
=$
(git ls-tree HEAD
"$name")
226 if test -n "$ls_list"
228 mkdir
-p "$tmp/$left_dir/$(dirname "$name")"
229 git show HEAD
:"$name" >"$tmp/$left_dir/$name"
232 mkdir
-p "$tmp/$left_dir/$(dirname "$name")"
233 git show
:"$name" >"$tmp/$left_dir/$name"
236 done < "$tmp/filelist"
242 if test -n "$diff_tool"
245 eval $diff_tool '"$LOCAL"' '"$REMOTE"'
247 run_merge_tool
"$merge_tool" false
250 # Copy files back to the working dir, if requested
251 if test -n "$copy_back" && test "$right_dir" = "working_tree"
254 git_top_dir
=$
(git rev-parse
--show-toplevel)
255 find "$tmp/$right_dir" -type f |
258 cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"