Test commit
[cogito/jonas.git] / cg-diff
blobd320ed8e703ba404023b2082b207e9ad5248e955
1 #!/usr/bin/env bash
3 # Show changes in the diff format
4 # Copyright (c) Petr Baudis, 2005
6 # Outputs a diff for converting the first tree to the second one.
7 # By default compares the current working tree to the state at the
8 # last commit. The output will automatically be displayed in a pager
9 # unless it is piped to a program.
11 # OPTIONS
12 # -------
13 # -c:: Colorize
14 # Colorize the output. You can customize the colors using the
15 # $CG_COLORS environment variable (see below).
17 # --diffcore ARGS:: Diffcore arguments to pass the Git diff command
18 # Pass the given diffcore arguments the called Git diff command.
19 # See e.g. git-diff-tree(1) documentation for the list of possible
20 # arguments; '-R', '-B', and '-C' might be of particular interest
21 # ('-M' is already passed by default).
23 # --no-renames:: Do not detect renames
24 # By default, `cg-diff` will automatically detect file renames.
25 # Diff produced by the rename-aware `cg-diff` will be unappliable
26 # using patch(1) (you need to use `cg-patch`) and the renames
27 # detection can add slight extra performance penalty. This switch
28 # will turn the rename detection off.
30 # -p:: Diff against commit parent
31 # Show diff to the parent of the current commit (or the commit
32 # specified by the -r parameter).
34 # -s:: Summarize and show diff stat
35 # Summarize the diff by showing a histogram for removed and added
36 # lines (similar to the output of diffstat(1)) and information
37 # about added and renamed files and mode changes.
39 # -r FROM_ID[..TO_ID]:: Limit to revision range
40 # Specify the revisions to diff using either '-r rev1..rev2' or
41 # '-r rev1 -r rev2'. If no revision is specified, the current
42 # working tree is implied. Note that no revision is different from
43 # empty revision which means '-r rev..' compares between 'rev' and
44 # 'HEAD', while '-r rev' compares between 'rev' and working tree.
46 # -m:: Base the diff at the merge base
47 # Base the diff at the merge base of the -r arguments (defaulting
48 # to HEAD and 'origin' or the current branch's default remote
49 # branch, see `cg-fetch` for details).
51 # ENVIRONMENT VARIABLES
52 # ---------------------
53 # PAGER::
54 # The pager to display log information in, defaults to `less`.
56 # PAGER_FLAGS::
57 # Flags to pass to the pager.
59 # CG_COLORS::
60 # Colon-separated list of 'name=color' pairs, where name is
61 # one of diffhdr, diffhdradd, diffhdrmod, diffhdrrem, diffadd,
62 # diffmod, diffrem, diffhunk, diffctx, default, and value is
63 # an ECMA-48 SGR sequence (see e.g. console_codes(4)).
65 # CG_COLORS_AUTO::
66 # Even if -c was passed or specified in ~/.cgrc, if this option
67 # is set, use colors only when the output is a terminal and it
68 # supports colors.
70 # CG_LESS::
71 # This is what the $LESS environment variable value will be set
72 # to before invoking $PAGER. It defaults to $LESS concatenated
73 # with the `R` flag to allow displaying of colorized output.
75 # CONFIGURATION VARIABLES
76 # -----------------------
77 # The following GIT configuration file variables are recognized:
79 # diff.usecolor::
80 # If enabled, colorify the output like with -c if the output
81 # is a terminal.
83 # NOTES
84 # -----
85 # The ':' is equivalent to '..' in revisions range specification (to make
86 # things more comfortable to SVN users). See cogito(7) for more details
87 # about revision specification.
89 # Testsuite: TODO
91 USAGE="cg-diff [-c] [-m] [-s] [-p] [-r FROM_ID[..TO_ID]] [FILE]..."
92 _git_wc_unneeded=1
94 . "${COGITO_LIB}"cg-Xlib || exit 1
97 setup_colors()
99 colorify_setup "$colorify_diffcolors"
100 # It could've been turned on by diff.usecolor
101 opt_color=1
104 colorize()
106 if [ "$opt_color" ]; then
107 sed -e '
108 s/^diff --git.*/'$coldiffhdr'&'$coldefault'/
109 s/^+++.*/'$coldiffhdradd'&'$coldefault'/
110 s/^---.*/'$coldiffhdrrem'&'$coldefault'/
111 s/^[+].*/'$coldiffadd'&'$coldefault'/
112 s/^[-].*/'$coldiffrem'&'$coldefault'/
113 s/^new\( file\)\{0,1\} mode .*/'$coldiffadd'&'$coldefault'/
114 s/^\(deleted file\|old\) mode .*/'$coldiffrem'&'$coldefault'/
115 s/^rename to .*/'$coldiffadd'&'$coldefault'/
116 s/^rename from .*/'$coldiffrem'&'$coldefault'/
117 s/^\(@@ -.* +.* @@\)\(.*\)/'$coldiffhunk'\1'$coldiffctx'\2'$coldefault'/
119 else
125 id1=" " # means HEAD
126 id2=" " # means working copy
127 diffcore=
128 parent=
129 opt_color=
130 mergebase=
131 style=-p
132 renames=-M
134 while optparse; do
135 if optparse -c; then
136 opt_color=1
137 elif optparse --diffcore=; then
138 diffcore="$OPTARG"
139 elif optparse -p; then
140 [ "$mergebase" ] && optconflict -m
141 parent=1
142 elif optparse -R || optparse --no-renames; then
143 renames=
144 elif optparse -s; then
145 style="--stat"
146 elif optparse -r=; then
147 if echo "$OPTARG" | fgrep -q '..'; then
148 id2="${OPTARG#*..}"
149 id1="${OPTARG%..*}"
150 elif echo "$OPTARG" | grep -q ':'; then
151 id2="${OPTARG#*:}"
152 id1="${OPTARG%:*}"
153 elif [ "$id1" = " " ]; then
154 id1="$OPTARG"
155 elif [ "$id2" = " " ]; then
156 id2="$OPTARG"
157 else
158 die "too many revisions"
160 elif optparse -m; then
161 [ "$parent" ] && optconflict -p
162 mergebase=1
163 else
164 optfail
166 done
169 colorify_detect "$opt_color" diff && setup_colors
171 [ "$id1" = " " ] && id1=HEAD
173 if [ "$parent" ]; then
174 [ "$id2" = " " ] || die "too many revisions"
175 id2="$id1"
177 ids="$(cg-object-id -p "$id2")" || exit 1
178 [ "$(echo "$ids" | wc -l)" -gt 1 ] && \
179 warn "choosing the first parent of a merge commit. This may not be what you want."
180 id1="$(echo "$ids" | head -n 1)" || exit 1
182 elif [ "$mergebase" ]; then
183 [ "$id2" = " " ] && { id2="$(choose_origin refs/heads "what to diff against?")" || exit 1; }
185 id1="$(cg-object-id -c "$id1")" || exit 1
186 id2="$(cg-object-id -c "$id2")" || exit 1
188 conservative_merge_base "$id1" "$id2" || exit 1
189 [ "$_cg_base_conservative" ] &&
190 warn -b "multiple merge bases, picking the most conservative one"
191 id1="$_cg_baselist"
193 else
194 id1="$(cg-object-id -t "$id1")" || exit 1
198 if [ "$id2" = " " ]; then
199 [ "$_git_no_wc" ] && die "only cg-diff between two revisions allowed outside a working copy"
201 # Make sure we only diff modified files
202 git-update-index --refresh >/dev/null
204 diffprog=git-diff-index
205 diffargs=(-m "$id1")
207 else
208 id2="$(cg-object-id -t "$id2")" || exit 1
209 [ "$id1" = "$id2" ] && exit 0
211 diffprog=git-diff-tree
212 diffargs=("$id1" "$id2")
216 diffargs[${#diffargs[@]}]="--"
217 if [ ! "$ARGS" ]; then
218 diffargs[${#diffargs[@]}]="${_git_relpath:-.}"
219 else
220 for file in "${ARGS[@]}"; do
221 diffargs[${#diffargs[@]}]="$_git_relpath$file"
222 done
225 # FIXME: Update ret based on what did we match. And take "$@"
226 # to account after all.
227 #ret=
228 $diffprog -r $renames $diffcore $style "${diffargs[@]}" | colorize | pager
229 #[ "$ret" ] && die "no files matched"
230 #exit $ret
231 exit 0