bisect: fix exiting when checkout failed in bisect_start()
[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