Skip to content

Commit 1252bbe

Browse files
thenigangitster
authored andcommitted
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 <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent bd444ca commit 1252bbe

File tree

2 files changed

+292
-0
lines changed

2 files changed

+292
-0
lines changed

contrib/diffall/README

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
The git-diffall script provides a directory based diff mechanism
2+
for git.
3+
4+
To determine what diff viewer is used, the script requires either
5+
the 'diff.tool' or 'merge.tool' configuration option to be set.
6+
7+
This script is compatible with most common forms used to specify a
8+
range of revisions to diff:
9+
10+
1. git diffall: shows diff between working tree and staged changes
11+
2. git diffall --cached [<commit>]: shows diff between staged
12+
changes and HEAD (or other named commit)
13+
3. git diffall <commit>: shows diff between working tree and named
14+
commit
15+
4. git diffall <commit> <commit>: show diff between two named commits
16+
5. git diffall <commit>..<commit>: same as above
17+
6. git diffall <commit>...<commit>: show the changes on the branch
18+
containing and up to the second, starting at a common ancestor
19+
of both <commit>
20+
21+
Note: all forms take an optional path limiter [-- <path>*]
22+
23+
The '--extcmd=<command>' option allows the user to specify a custom
24+
command for viewing diffs. When given, configured defaults are
25+
ignored and the script runs $command $LOCAL $REMOTE. Additionally,
26+
$BASE is set in the environment.
27+
28+
This script is based on an example provided by Thomas Rast on the
29+
Git list [1]:
30+
31+
[1] http://thread.gmane.org/gmane.comp.version-control.git/124807

contrib/diffall/git-diffall

Lines changed: 261 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,261 @@
1+
#!/bin/sh
2+
# Copyright 2010 - 2012, Tim Henigan <[email protected]>
3+
#
4+
# Perform a directory diff between commits in the repository using
5+
# the external diff or merge tool specified in the user's config.
6+
7+
USAGE='[--cached] [--copy-back] [-x|--extcmd=<command>] <commit>{0,2} [-- <path>*]
8+
9+
--cached Compare to the index rather than the working tree.
10+
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.
15+
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.
22+
'
23+
24+
SUBDIRECTORY_OK=1
25+
. "$(git --exec-path)/git-sh-setup"
26+
27+
TOOL_MODE=diff
28+
. "$(git --exec-path)/git-mergetool--lib"
29+
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
35+
fi
36+
37+
start_dir=$(pwd)
38+
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
44+
}
45+
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
51+
}
52+
53+
trap 'rm -rf "$tmp" 2>/dev/null' EXIT
54+
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=
65+
66+
while test $# != 0
67+
do
68+
case "$1" in
69+
-h|--h|--he|--hel|--help)
70+
usage
71+
;;
72+
--cached)
73+
compare_staged=1
74+
;;
75+
--copy-back)
76+
copy_back=1
77+
;;
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
86+
fi
87+
;;
88+
--)
89+
dashdash_seen=1
90+
;;
91+
-*)
92+
echo Invalid option: "$1"
93+
usage
94+
;;
95+
*)
96+
# could be commit, commit range or path limiter
97+
case "$1" in
98+
*...*)
99+
left=${1%...*}
100+
right=${1#*...}
101+
merge_base=1
102+
;;
103+
*..*)
104+
left=${1%..*}
105+
right=${1#*..}
106+
;;
107+
*)
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 "
119+
fi
120+
;;
121+
esac
122+
;;
123+
esac
124+
shift
125+
done
126+
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)"
132+
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"
141+
fi
142+
elif test -n "$left"
143+
then
144+
left_dir="cmt-$(git rev-parse --short $left)"
145+
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"
153+
fi
154+
else
155+
left_dir="HEAD"
156+
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"
164+
fi
165+
fi
166+
167+
# Exit immediately if there are no diffs
168+
if test ! -s "$tmp/filelist"
169+
then
170+
exit 0
171+
fi
172+
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
177+
fi
178+
179+
# Create the named tmp directories that will hold the files to be compared
180+
mkdir -p "$tmp/$left_dir" "$tmp/$right_dir"
181+
182+
# Populate the tmp/right_dir directory with the files to be compared
183+
if test -n "$right"
184+
then
185+
while read name
186+
do
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
192+
fi
193+
done < "$tmp/filelist"
194+
elif test -n "$compare_staged"
195+
then
196+
while read name
197+
do
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"
203+
fi
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)
209+
}
210+
fi
211+
212+
# Populate the tmp/left_dir directory with the files to be compared
213+
while read name
214+
do
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
222+
fi
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"
231+
fi
232+
else
233+
mkdir -p "$tmp/$left_dir/$(dirname "$name")"
234+
git show :"$name" >"$tmp/$left_dir/$name"
235+
fi
236+
fi
237+
done < "$tmp/filelist"
238+
239+
cd "$tmp"
240+
LOCAL="$left_dir"
241+
REMOTE="$right_dir"
242+
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
249+
fi
250+
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
258+
do
259+
cp "$file" "$git_top_dir/${file#$tmp/$right_dir/}"
260+
done
261+
fi

0 commit comments

Comments
 (0)