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