bisect: further style nitpicks
[git/git.git] / git-bisect.sh
CommitLineData
8cc6a083 1#!/bin/sh
d025524d 2
243a60fb
CC
3USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
4LONG_USAGE='git bisect help
6021be86 5 print this long help message.
4796e823 6git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
6021be86 7 reset bisect state and start bisection.
38a47fd6 8git bisect bad [<rev>]
6021be86 9 mark <rev> a known-bad revision.
38a47fd6 10git bisect good [<rev>...]
6021be86 11 mark <rev>... known-good revisions.
5413812f 12git bisect skip [(<rev>|<range>)...]
6021be86 13 mark <rev>... untestable revisions.
38a47fd6 14git bisect next
6021be86 15 find next bisection to test and check it out.
6b87ce23 16git bisect reset [<commit>]
6021be86 17 finish bisection search and go back to commit.
38a47fd6 18git bisect visualize
6021be86 19 show bisect status in gitk.
38a47fd6 20git bisect replay <logfile>
6021be86 21 replay bisection log.
38a47fd6 22git bisect log
6021be86 23 show bisect log.
38a47fd6 24git bisect run <cmd>...
6021be86 25 use <cmd>... to automatically bisect.
243a60fb
CC
26
27Please use "git help bisect" to get the full man page.'
d025524d 28
8f321a39 29OPTIONS_SPEC=
ae2b0f15 30. git-sh-setup
dcf9c2e5 31. git-sh-i18n
4c550686 32require_work_tree
8cc6a083 33
ce32660e
JS
34_x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'
35_x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40"
36
4796e823
JS
37bisect_head()
38{
39 if test -f "$GIT_DIR/BISECT_HEAD"
40 then
41 echo BISECT_HEAD
42 else
43 echo HEAD
44 fi
45}
46
8cc6a083 47bisect_autostart() {
823ea121 48 test -s "$GIT_DIR/BISECT_START" || {
ddd7a7c2
ÆAB
49 (
50 gettext "You need to start by \"git bisect start\"" &&
51 echo
52 ) >&2
8cc6a083
LT
53 if test -t 0
54 then
04de0996
ÆAB
55 # TRANSLATORS: Make sure to include [Y] and [n] in your
56 # translation. The program will only accept English input
57 # at this point.
6021be86 58 gettext "Do you want me to do it for you [Y/n]? " >&2
8cc6a083
LT
59 read yesno
60 case "$yesno" in
61 [Nn]*)
62 exit ;;
63 esac
64 bisect_start
65 else
66 exit 1
67 fi
68 }
69}
70
71bisect_start() {
4764f464
JS
72 #
73 # Check for one bad and then some good revisions.
74 #
75 has_double_dash=0
76 for arg; do
6021be86 77 case "$arg" in --) has_double_dash=1; break ;; esac
4764f464
JS
78 done
79 orig_args=$(git rev-parse --sq-quote "$@")
80 bad_seen=0
81 eval=''
4796e823 82 mode=''
4764f464 83 while [ $# -gt 0 ]; do
6021be86
JS
84 arg="$1"
85 case "$arg" in
86 --)
87 shift
88 break
4764f464 89 ;;
6021be86
JS
90 --no-checkout)
91 mode=--no-checkout
92 shift ;;
93 --*)
94 die "$(eval_gettext "unrecognised option: '\$arg'")" ;;
95 *)
96 rev=$(git rev-parse -q --verify "$arg^{commit}") || {
43b8ff4b
JH
97 test $has_double_dash -eq 1 &&
98 die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
99 break
6021be86
JS
100 }
101 case $bad_seen in
102 0) state='bad' ; bad_seen=1 ;;
103 *) state='good' ;;
104 esac
105 eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
106 shift
107 ;;
4764f464 108 esac
4764f464
JS
109 done
110
8cc6a083 111 #
634f2464 112 # Verify HEAD.
8cc6a083 113 #
48949a18 114 head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
ce32660e 115 head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
9570fc1e 116 die "$(gettext "Bad HEAD - I need a HEAD")"
634f2464 117
ee831f7d 118 #
634f2464 119 # Check if we are bisecting.
ee831f7d 120 #
d3e54c88 121 start_head=''
634f2464
CC
122 if test -s "$GIT_DIR/BISECT_START"
123 then
124 # Reset to the rev from where we started.
9d0cd91c 125 start_head=$(cat "$GIT_DIR/BISECT_START")
4796e823
JS
126 if test "z$mode" != "z--no-checkout"
127 then
43b8ff4b 128 git checkout "$start_head" --
4796e823 129 fi
634f2464
CC
130 else
131 # Get rev from where we start.
132 case "$head" in
133 refs/heads/*|$_x40)
134 # This error message should only be triggered by
135 # cogito usage, and cogito users should understand
136 # it relates to cg-seek.
137 [ -s "$GIT_DIR/head-name" ] &&
9570fc1e 138 die "$(gettext "won't bisect on seeked tree")"
634f2464
CC
139 start_head="${head#refs/heads/}"
140 ;;
141 *)
9570fc1e 142 die "$(gettext "Bad HEAD - strange symbolic ref")"
634f2464
CC
143 ;;
144 esac
145 fi
8cc6a083
LT
146
147 #
634f2464 148 # Get rid of any old bisect state.
8cc6a083 149 #
823ea121 150 bisect_clean_state || exit
38a47fd6 151
ba963de8
CC
152 #
153 # Change state.
154 # In case of mistaken revs or checkout error, or signals received,
155 # "bisect_auto_next" below may exit or misbehave.
156 # We have to trap this to be able to clean up using
157 # "bisect_clean_state".
158 #
159 trap 'bisect_clean_state' 0
160 trap 'exit 255' 1 2 3 15
161
162 #
163 # Write new start state.
164 #
4796e823
JS
165 echo "$start_head" >"$GIT_DIR/BISECT_START" && {
166 test "z$mode" != "z--no-checkout" ||
167 git update-ref --no-deref BISECT_HEAD "$start_head"
168 } &&
de52f5a8 169 git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
6ba7acff 170 eval "$eval true" &&
6c98c054 171 echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
ba963de8
CC
172 #
173 # Check if we can proceed to the next bisect state.
174 #
38a47fd6 175 bisect_auto_next
ba963de8
CC
176
177 trap '-' 0
8cc6a083
LT
178}
179
55624f9a
CC
180bisect_write() {
181 state="$1"
182 rev="$2"
737c74ee 183 nolog="$3"
55624f9a
CC
184 case "$state" in
185 bad) tag="$state" ;;
186 good|skip) tag="$state"-"$rev" ;;
15eaa049 187 *) die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
55624f9a 188 esac
ba963de8 189 git update-ref "refs/bisect/$tag" "$rev" || exit
f454cdc4 190 echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
6c98c054 191 test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
55624f9a
CC
192}
193
c9c4e2d5
CC
194is_expected_rev() {
195 test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
196 test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
197}
198
c9c4e2d5
CC
199check_expected_revs() {
200 for _rev in "$@"; do
eef12a9a
JS
201 if ! is_expected_rev "$_rev"
202 then
c9c4e2d5
CC
203 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
204 rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
205 return
206 fi
207 done
208}
209
ee2314f5 210bisect_skip() {
6021be86 211 all=''
ee2314f5
CC
212 for arg in "$@"
213 do
6021be86
JS
214 case "$arg" in
215 *..*)
216 revs=$(git rev-list "$arg") || die "$(eval_gettext "Bad rev input: \$arg")" ;;
217 *)
218 revs=$(git rev-parse --sq-quote "$arg") ;;
219 esac
220 all="$all $revs"
221 done
222 eval bisect_state 'skip' $all
ee2314f5
CC
223}
224
155fc795 225bisect_state() {
8cc6a083 226 bisect_autostart
155fc795
CC
227 state=$1
228 case "$#,$state" in
229 0,*)
9570fc1e 230 die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
155fc795 231 1,bad|1,good|1,skip)
4796e823
JS
232 rev=$(git rev-parse --verify $(bisect_head)) ||
233 die "$(gettext "Bad rev input: $(bisect_head)")"
c9c4e2d5
CC
234 bisect_write "$state" "$rev"
235 check_expected_revs "$rev" ;;
e3389075 236 2,bad|*,good|*,skip)
155fc795 237 shift
d3e54c88 238 eval=''
e3389075 239 for rev in "$@"
155fc795 240 do
a179a303 241 sha=$(git rev-parse --verify "$rev^{commit}") ||
15eaa049 242 die "$(eval_gettext "Bad rev input: \$rev")"
d3e54c88
CC
243 eval="$eval bisect_write '$state' '$sha'; "
244 done
c9c4e2d5
CC
245 eval "$eval"
246 check_expected_revs "$@" ;;
e3389075 247 *,bad)
9570fc1e 248 die "$(gettext "'git bisect bad' can take only one argument.")" ;;
cc9f24d0
JH
249 *)
250 usage ;;
8cc6a083 251 esac
97e1c51e
CC
252 bisect_auto_next
253}
254
8cc6a083 255bisect_next_check() {
0a5280a9
JH
256 missing_good= missing_bad=
257 git show-ref -q --verify refs/bisect/bad || missing_bad=t
258 test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
6fecf191 259
0a5280a9
JH
260 case "$missing_good,$missing_bad,$1" in
261 ,,*)
262 : have both good and bad - ok
263 ;;
264 *,)
265 # do not have both but not asked to fail - just report.
266 false
267 ;;
268 t,,good)
269 # have bad but not good. we could bisect although
270 # this is less optimum.
ddd7a7c2
ÆAB
271 (
272 gettext "Warning: bisecting only with a bad commit." &&
273 echo
274 ) >&2
0a5280a9
JH
275 if test -t 0
276 then
04de0996
ÆAB
277 # TRANSLATORS: Make sure to include [Y] and [n] in your
278 # translation. The program will only accept English input
279 # at this point.
280 gettext "Are you sure [Y/n]? " >&2
e5d3afd7
FM
281 read yesno
282 case "$yesno" in [Nn]*) exit 1 ;; esac
0a5280a9
JH
283 fi
284 : bisect without good...
285 ;;
8cc6a083 286 *)
be508d3a
ÆAB
287
288 if test -s "$GIT_DIR/BISECT_START"
289 then
290 (
291 gettext "You need to give me at least one good and one bad revisions.
292(You can use \"git bisect bad\" and \"git bisect good\" for that.)" &&
293 echo
294 ) >&2
295 else
296 (
297 gettext "You need to start by \"git bisect start\".
298You then need to give me at least one good and one bad revisions.
299(You can use \"git bisect bad\" and \"git bisect good\" for that.)" &&
300 echo
301 ) >&2
302 fi
0a5280a9 303 exit 1 ;;
8cc6a083
LT
304 esac
305}
306
307bisect_auto_next() {
434d036f 308 bisect_next_check && bisect_next || :
8cc6a083
LT
309}
310
311bisect_next() {
8fe26f44 312 case "$#" in 0) ;; *) usage ;; esac
8cc6a083 313 bisect_autostart
0a5280a9
JH
314 bisect_next_check good
315
0871984d 316 # Perform all bisection computation, display and checkout
4796e823 317 git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
5a1d31c7 318 res=$?
0a5280a9 319
6021be86 320 # Check if we should exit because bisection is finished
5a1d31c7 321 test $res -eq 10 && exit 0
0a5280a9 322
5a1d31c7
CC
323 # Check for an error in the bisection process
324 test $res -ne 0 && exit $res
325
326 return 0
8cc6a083
LT
327}
328
cc9f24d0
JH
329bisect_visualize() {
330 bisect_next_check fail
235997c9
JH
331
332 if test $# = 0
333 then
c4e4644e 334 if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
43b8ff4b 335 type gitk >/dev/null 2>&1
eef12a9a 336 then
c4e4644e
JK
337 set gitk
338 else
339 set git log
340 fi
235997c9
JH
341 else
342 case "$1" in
343 git*|tig) ;;
344 -*) set git log "$@" ;;
345 *) set git "$@" ;;
346 esac
347 fi
348
fc13aa3d 349 eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
cc9f24d0
JH
350}
351
8cc6a083 352bisect_reset() {
823ea121 353 test -s "$GIT_DIR/BISECT_START" || {
d0238a88 354 gettext "We are not bisecting."; echo
fce0499f
CC
355 return
356 }
8cc6a083 357 case "$#" in
823ea121 358 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
7d0c2d6f 359 1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null || {
6021be86
JS
360 invalid="$1"
361 die "$(eval_gettext "'\$invalid' is not a valid commit")"
362 }
363 branch="$1" ;;
8fe26f44 364 *)
6021be86 365 usage ;;
8cc6a083 366 esac
43b8ff4b
JH
367
368 if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" --
4796e823 369 then
43b8ff4b 370 die "$(eval_gettext "Could not check out original HEAD '\$branch'.
15eaa049 371Try 'git bisect reset <commit>'.")"
3bb8cf88 372 fi
4796e823 373 bisect_clean_state
e204de28
JH
374}
375
38a47fd6 376bisect_clean_state() {
947a604b 377 # There may be some refs packed during bisection.
634f2464 378 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
947a604b
CC
379 while read ref hash
380 do
823ea121 381 git update-ref -d $ref $hash || exit
947a604b 382 done
c9c4e2d5
CC
383 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
384 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
823ea121
CC
385 rm -f "$GIT_DIR/BISECT_LOG" &&
386 rm -f "$GIT_DIR/BISECT_NAMES" &&
387 rm -f "$GIT_DIR/BISECT_RUN" &&
9d0cd91c 388 # Cleanup head-name if it got left by an old version of git-bisect
823ea121 389 rm -f "$GIT_DIR/head-name" &&
4796e823
JS
390 git update-ref -d --no-deref BISECT_HEAD &&
391 # clean up BISECT_START last
823ea121 392 rm -f "$GIT_DIR/BISECT_START"
38a47fd6
CC
393}
394
e204de28 395bisect_replay () {
55a9fc80
ÆAB
396 file="$1"
397 test "$#" -eq 1 || die "$(gettext "No logfile given")"
398 test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
e204de28 399 bisect_reset
6c98c054 400 while read git bisect command rev
e204de28 401 do
6c98c054 402 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
eef12a9a
JS
403 if test "$git" = "git-bisect"
404 then
6c98c054
MV
405 rev="$command"
406 command="$bisect"
407 fi
e204de28
JH
408 case "$command" in
409 start)
e9a45d75 410 cmd="bisect_start $rev"
737c74ee
CC
411 eval "$cmd" ;;
412 good|bad|skip)
413 bisect_write "$command" "$rev" ;;
e204de28 414 *)
9570fc1e 415 die "$(gettext "?? what are you talking about?")" ;;
e204de28 416 esac
55a9fc80 417 done <"$file"
e204de28 418 bisect_auto_next
8cc6a083
LT
419}
420
a17c4101 421bisect_run () {
6021be86
JS
422 bisect_next_check fail
423
424 while true
425 do
426 command="$@"
427 eval_gettext "running \$command"; echo
428 "$@"
429 res=$?
430
431 # Check for really bad run error.
eef12a9a
JS
432 if [ $res -lt 0 -o $res -ge 128 ]
433 then
6021be86
JS
434 (
435 eval_gettext "bisect run failed:
09209255 436exit code \$res from '\$command' is < 0 or >= 128" &&
6021be86
JS
437 echo
438 ) >&2
439 exit $res
440 fi
441
442 # Find current state depending on run success or failure.
443 # A special exit code of 125 means cannot test.
eef12a9a
JS
444 if [ $res -eq 125 ]
445 then
6021be86 446 state='skip'
eef12a9a
JS
447 elif [ $res -gt 0 ]
448 then
6021be86
JS
449 state='bad'
450 else
451 state='good'
452 fi
453
454 # We have to use a subshell because "bisect_state" can exit.
455 ( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
456 res=$?
457
458 cat "$GIT_DIR/BISECT_RUN"
459
460 if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
eef12a9a
JS
461 > /dev/null
462 then
6021be86
JS
463 (
464 gettext "bisect run cannot continue any more" &&
465 echo
466 ) >&2
467 exit $res
468 fi
469
eef12a9a
JS
470 if [ $res -ne 0 ]
471 then
6021be86
JS
472 (
473 eval_gettext "bisect run failed:
c6649c92 474'bisect_state \$state' exited with error code \$res" &&
6021be86
JS
475 echo
476 ) >&2
477 exit $res
478 fi
a17c4101 479
eef12a9a
JS
480 if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null
481 then
6021be86
JS
482 gettext "bisect run success"; echo
483 exit 0;
484 fi
a17c4101 485
6021be86 486 done
a17c4101
CC
487}
488
412ff738 489bisect_log () {
9570fc1e 490 test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")"
412ff738
SG
491 cat "$GIT_DIR/BISECT_LOG"
492}
a17c4101 493
8cc6a083
LT
494case "$#" in
4950)
6021be86 496 usage ;;
8cc6a083 497*)
6021be86
JS
498 cmd="$1"
499 shift
500 case "$cmd" in
501 help)
502 git bisect -h ;;
503 start)
504 bisect_start "$@" ;;
505 bad|good)
506 bisect_state "$cmd" "$@" ;;
507 skip)
508 bisect_skip "$@" ;;
509 next)
510 # Not sure we want "next" at the UI level anymore.
511 bisect_next "$@" ;;
512 visualize|view)
513 bisect_visualize "$@" ;;
514 reset)
515 bisect_reset "$@" ;;
516 replay)
517 bisect_replay "$@" ;;
518 log)
519 bisect_log ;;
520 run)
521 bisect_run "$@" ;;
522 *)
523 usage ;;
524 esac
8cc6a083 525esac