Fix old-style function declaration
[git/dscho.git] / contrib / diffall / git-diffall
blob9bbd27f4a5db3352dc97d50e011615650ac0e533
1 #!/bin/sh
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.
16 -x=<command>
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
21 environment.
24 SUBDIRECTORY_OK=1
25 . "$(git --exec-path)/git-sh-setup"
27 TOOL_MODE=diff
28 . "$(git --exec-path)/git-mergetool--lib"
30 merge_tool="$(get_merge_tool)"
31 if test -z "$merge_tool"
32 then
33 echo "Error: Either the 'diff.tool' or 'merge.tool' option must be set."
34 usage
37 start_dir=$(pwd)
39 # needed to access tar utility
40 cdup=$(git rev-parse --show-cdup) &&
41 cd "$cdup" || {
42 echo >&2 "Cannot chdir to $cdup, the toplevel of the working tree"
43 exit 1
46 # mktemp is not available on all platforms (missing from msysgit)
47 # Use a hard-coded tmp dir if it is not available
48 tmp="$(mktemp -d -t tmp.XXXXXX 2>/dev/null)" || {
49 tmp=/tmp/git-diffall-tmp.$$
50 mkdir "$tmp" || exit 1
53 trap 'rm -rf "$tmp" 2>/dev/null' EXIT
55 left=
56 right=
57 paths=
58 dashdash_seen=
59 compare_staged=
60 merge_base=
61 left_dir=
62 right_dir=
63 diff_tool=
64 copy_back=
66 while test $# != 0
68 case "$1" in
69 -h|--h|--he|--hel|--help)
70 usage
72 --cached)
73 compare_staged=1
75 --copy-back)
76 copy_back=1
78 -x|--e|--ex|--ext|--extc|--extcm|--extcmd)
79 if test $# = 1
80 then
81 echo You must specify the tool for use with --extcmd
82 usage
83 else
84 diff_tool=$2
85 shift
88 --)
89 dashdash_seen=1
91 -*)
92 echo Invalid option: "$1"
93 usage
96 # could be commit, commit range or path limiter
97 case "$1" in
98 *...*)
99 left=${1%...*}
100 right=${1#*...}
101 merge_base=1
103 *..*)
104 left=${1%..*}
105 right=${1#*..}
108 if test -n "$dashdash_seen"
109 then
110 paths="$paths$1 "
111 elif test -z "$left"
112 then
113 left=$1
114 elif test -z "$right"
115 then
116 right=$1
117 else
118 paths="$paths$1 "
121 esac
123 esac
124 shift
125 done
127 # Determine the set of files which changed
128 if test -n "$left" && test -n "$right"
129 then
130 left_dir="cmt-$(git rev-parse --short $left)"
131 right_dir="cmt-$(git rev-parse --short $right)"
133 if test -n "$compare_staged"
134 then
135 usage
136 elif test -n "$merge_base"
137 then
138 git diff --name-only "$left"..."$right" -- $paths >"$tmp/filelist"
139 else
140 git diff --name-only "$left" "$right" -- $paths >"$tmp/filelist"
142 elif test -n "$left"
143 then
144 left_dir="cmt-$(git rev-parse --short $left)"
146 if test -n "$compare_staged"
147 then
148 right_dir="staged"
149 git diff --name-only --cached "$left" -- $paths >"$tmp/filelist"
150 else
151 right_dir="working_tree"
152 git diff --name-only "$left" -- $paths >"$tmp/filelist"
154 else
155 left_dir="HEAD"
157 if test -n "$compare_staged"
158 then
159 right_dir="staged"
160 git diff --name-only --cached -- $paths >"$tmp/filelist"
161 else
162 right_dir="working_tree"
163 git diff --name-only -- $paths >"$tmp/filelist"
167 # Exit immediately if there are no diffs
168 if test ! -s "$tmp/filelist"
169 then
170 exit 0
173 if test -n "$copy_back" && test "$right_dir" != "working_tree"
174 then
175 echo "--copy-back is only valid when diff includes the working tree."
176 exit 1
179 # Create the named tmp directories that will hold the files to be compared
180 mkdir -p "$tmp/$left_dir" "$tmp/$right_dir"
182 # Populate the tmp/right_dir directory with the files to be compared
183 if test -n "$right"
184 then
185 while read name
187 ls_list=$(git ls-tree $right "$name")
188 if test -n "$ls_list"
189 then
190 mkdir -p "$tmp/$right_dir/$(dirname "$name")"
191 git show "$right":"$name" >"$tmp/$right_dir/$name" || true
193 done < "$tmp/filelist"
194 elif test -n "$compare_staged"
195 then
196 while read name
198 ls_list=$(git ls-files -- "$name")
199 if test -n "$ls_list"
200 then
201 mkdir -p "$tmp/$right_dir/$(dirname "$name")"
202 git show :"$name" >"$tmp/$right_dir/$name"
204 done < "$tmp/filelist"
205 else
206 # Mac users have gnutar rather than tar
207 (tar --ignore-failed-read -c -T "$tmp/filelist" | (cd "$tmp/$right_dir" && tar -x)) || {
208 gnutar --ignore-failed-read -c -T "$tmp/filelist" | (cd "$tmp/$right_dir" && gnutar -x)
212 # Populate the tmp/left_dir directory with the files to be compared
213 while read name
215 if test -n "$left"
216 then
217 ls_list=$(git ls-tree $left "$name")
218 if test -n "$ls_list"
219 then
220 mkdir -p "$tmp/$left_dir/$(dirname "$name")"
221 git show "$left":"$name" >"$tmp/$left_dir/$name" || true
223 else
224 if test -n "$compare_staged"
225 then
226 ls_list=$(git ls-tree HEAD "$name")
227 if test -n "$ls_list"
228 then
229 mkdir -p "$tmp/$left_dir/$(dirname "$name")"
230 git show HEAD:"$name" >"$tmp/$left_dir/$name"
232 else
233 mkdir -p "$tmp/$left_dir/$(dirname "$name")"
234 git show :"$name" >"$tmp/$left_dir/$name"
237 done < "$tmp/filelist"
239 cd "$tmp"
240 LOCAL="$left_dir"
241 REMOTE="$right_dir"
243 if test -n "$diff_tool"
244 then
245 export BASE
246 eval $diff_tool '"$LOCAL"' '"$REMOTE"'
247 else
248 run_merge_tool "$merge_tool" false
251 # Copy files back to the working dir, if requested
252 if test -n "$copy_back" && test "$right_dir" = "working_tree"
253 then
254 cd "$start_dir"
255 git_top_dir=$(git rev-parse --show-toplevel)
256 find "$tmp/$right_dir" -type f |
257 while read file
259 cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
260 done