Merge branch 'cc/maint-1.6.0-bisect-fix'
[git/mingw/j6t.git] / git-bisect.sh
bloba857db447ceaf293f6e4ddad3c9038e18b96c0ca
1 #!/bin/sh
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 [<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 [<branch>]
17 finish bisection search and go back to branch.
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.
27 Please use "git help bisect" to get the full man page.'
29 OPTIONS_SPEC=
30 . git-sh-setup
31 require_work_tree
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"
36 sq() {
37 @@PERL@@ -e '
38 for (@ARGV) {
39 s/'\''/'\'\\\\\'\''/g;
40 print " '\''$_'\''";
42 print "\n";
43 ' "$@"
46 bisect_autostart() {
47 test -s "$GIT_DIR/BISECT_START" || {
48 echo >&2 'You need to start by "git bisect start"'
49 if test -t 0
50 then
51 echo >&2 -n 'Do you want me to do it for you [Y/n]? '
52 read yesno
53 case "$yesno" in
54 [Nn]*)
55 exit ;;
56 esac
57 bisect_start
58 else
59 exit 1
64 bisect_start() {
66 # Verify HEAD.
68 head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
69 head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
70 die "Bad HEAD - I need a HEAD"
73 # Check if we are bisecting.
75 start_head=''
76 if test -s "$GIT_DIR/BISECT_START"
77 then
78 # Reset to the rev from where we started.
79 start_head=$(cat "$GIT_DIR/BISECT_START")
80 git checkout "$start_head" || exit
81 else
82 # Get rev from where we start.
83 case "$head" in
84 refs/heads/*|$_x40)
85 # This error message should only be triggered by
86 # cogito usage, and cogito users should understand
87 # it relates to cg-seek.
88 [ -s "$GIT_DIR/head-name" ] &&
89 die "won't bisect on seeked tree"
90 start_head="${head#refs/heads/}"
93 die "Bad HEAD - strange symbolic ref"
95 esac
99 # Get rid of any old bisect state.
101 bisect_clean_state || exit
104 # Check for one bad and then some good revisions.
106 has_double_dash=0
107 for arg; do
108 case "$arg" in --) has_double_dash=1; break ;; esac
109 done
110 orig_args=$(sq "$@")
111 bad_seen=0
112 eval=''
113 while [ $# -gt 0 ]; do
114 arg="$1"
115 case "$arg" in
117 shift
118 break
121 rev=$(git rev-parse -q --verify "$arg^{commit}") || {
122 test $has_double_dash -eq 1 &&
123 die "'$arg' does not appear to be a valid revision"
124 break
126 case $bad_seen in
127 0) state='bad' ; bad_seen=1 ;;
128 *) state='good' ;;
129 esac
130 eval="$eval bisect_write '$state' '$rev' 'nolog'; "
131 shift
133 esac
134 done
137 # Change state.
138 # In case of mistaken revs or checkout error, or signals received,
139 # "bisect_auto_next" below may exit or misbehave.
140 # We have to trap this to be able to clean up using
141 # "bisect_clean_state".
143 trap 'bisect_clean_state' 0
144 trap 'exit 255' 1 2 3 15
147 # Write new start state.
149 echo "$start_head" >"$GIT_DIR/BISECT_START" &&
150 sq "$@" >"$GIT_DIR/BISECT_NAMES" &&
151 eval "$eval" &&
152 echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
154 # Check if we can proceed to the next bisect state.
156 bisect_auto_next
158 trap '-' 0
161 bisect_write() {
162 state="$1"
163 rev="$2"
164 nolog="$3"
165 case "$state" in
166 bad) tag="$state" ;;
167 good|skip) tag="$state"-"$rev" ;;
168 *) die "Bad bisect_write argument: $state" ;;
169 esac
170 git update-ref "refs/bisect/$tag" "$rev" || exit
171 echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
172 test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
175 is_expected_rev() {
176 test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
177 test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
180 mark_expected_rev() {
181 echo "$1" > "$GIT_DIR/BISECT_EXPECTED_REV"
184 check_expected_revs() {
185 for _rev in "$@"; do
186 if ! is_expected_rev "$_rev"; then
187 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
188 rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
189 return
191 done
194 bisect_skip() {
195 all=''
196 for arg in "$@"
198 case "$arg" in
199 *..*)
200 revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;;
202 revs=$(sq "$arg") ;;
203 esac
204 all="$all $revs"
205 done
206 eval bisect_state 'skip' $all
209 bisect_state() {
210 bisect_autostart
211 state=$1
212 case "$#,$state" in
213 0,*)
214 die "Please call 'bisect_state' with at least one argument." ;;
215 1,bad|1,good|1,skip)
216 rev=$(git rev-parse --verify HEAD) ||
217 die "Bad rev input: HEAD"
218 bisect_write "$state" "$rev"
219 check_expected_revs "$rev" ;;
220 2,bad|*,good|*,skip)
221 shift
222 eval=''
223 for rev in "$@"
225 sha=$(git rev-parse --verify "$rev^{commit}") ||
226 die "Bad rev input: $rev"
227 eval="$eval bisect_write '$state' '$sha'; "
228 done
229 eval "$eval"
230 check_expected_revs "$@" ;;
231 *,bad)
232 die "'git bisect bad' can take only one argument." ;;
234 usage ;;
235 esac
236 bisect_auto_next
239 bisect_next_check() {
240 missing_good= missing_bad=
241 git show-ref -q --verify refs/bisect/bad || missing_bad=t
242 test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
244 case "$missing_good,$missing_bad,$1" in
245 ,,*)
246 : have both good and bad - ok
249 # do not have both but not asked to fail - just report.
250 false
252 t,,good)
253 # have bad but not good. we could bisect although
254 # this is less optimum.
255 echo >&2 'Warning: bisecting only with a bad commit.'
256 if test -t 0
257 then
258 printf >&2 'Are you sure [Y/n]? '
259 read yesno
260 case "$yesno" in [Nn]*) exit 1 ;; esac
262 : bisect without good...
265 THEN=''
266 test -s "$GIT_DIR/BISECT_START" || {
267 echo >&2 'You need to start by "git bisect start".'
268 THEN='then '
270 echo >&2 'You '$THEN'need to give me at least one good' \
271 'and one bad revisions.'
272 echo >&2 '(You can use "git bisect bad" and' \
273 '"git bisect good" for that.)'
274 exit 1 ;;
275 esac
278 bisect_auto_next() {
279 bisect_next_check && bisect_next || :
282 filter_skipped() {
283 _eval="$1"
284 _skip="$2"
286 if [ -z "$_skip" ]; then
287 eval "$_eval"
288 return
291 # Let's parse the output of:
292 # "git rev-list --bisect-vars --bisect-all ..."
293 eval "$_eval" | {
294 VARS= FOUND= TRIED=
295 while read hash line
297 case "$VARS,$FOUND,$TRIED,$hash" in
298 1,*,*,*)
299 # "bisect_foo=bar" read from rev-list output.
300 echo "$hash &&"
302 ,*,*,---*)
303 # Separator
305 ,,,bisect_rev*)
306 # We had nothing to search.
307 echo "bisect_rev= &&"
308 VARS=1
310 ,,*,bisect_rev*)
311 # We did not find a good bisect rev.
312 # This should happen only if the "bad"
313 # commit is also a "skip" commit.
314 echo "bisect_rev='$TRIED' &&"
315 VARS=1
317 ,,*,*)
318 # We are searching.
319 TRIED="${TRIED:+$TRIED|}$hash"
320 case "$_skip" in
321 *$hash*) ;;
323 echo "bisect_rev=$hash &&"
324 echo "bisect_tried='$TRIED' &&"
325 FOUND=1
327 esac
329 ,1,*,bisect_rev*)
330 # We have already found a rev to be tested.
331 VARS=1
333 ,1,*,*)
336 # Unexpected input
337 echo "die 'filter_skipped error'"
338 die "filter_skipped error " \
339 "VARS: '$VARS' " \
340 "FOUND: '$FOUND' " \
341 "TRIED: '$TRIED' " \
342 "hash: '$hash' " \
343 "line: '$line'"
345 esac
346 done
347 echo ':'
351 exit_if_skipped_commits () {
352 _tried=$1
353 if expr "$_tried" : ".*[|].*" > /dev/null ; then
354 echo "There are only 'skip'ped commit left to test."
355 echo "The first bad commit could be any of:"
356 echo "$_tried" | tr '[|]' '[\012]'
357 echo "We cannot bisect more!"
358 exit 2
362 bisect_checkout() {
363 _rev="$1"
364 _msg="$2"
365 echo "Bisecting: $_msg"
366 mark_expected_rev "$_rev"
367 git checkout -q "$_rev" || exit
368 git show-branch "$_rev"
371 is_among() {
372 _rev="$1"
373 _list="$2"
374 case "$_list" in *$_rev*) return 0 ;; esac
375 return 1
378 handle_bad_merge_base() {
379 _badmb="$1"
380 _good="$2"
381 if is_expected_rev "$_badmb"; then
382 cat >&2 <<EOF
383 The merge base $_badmb is bad.
384 This means the bug has been fixed between $_badmb and [$_good].
386 exit 3
387 else
388 cat >&2 <<EOF
389 Some good revs are not ancestor of the bad rev.
390 git bisect cannot work properly in this case.
391 Maybe you mistake good and bad revs?
393 exit 1
397 handle_skipped_merge_base() {
398 _mb="$1"
399 _bad="$2"
400 _good="$3"
401 cat >&2 <<EOF
402 Warning: the merge base between $_bad and [$_good] must be skipped.
403 So we cannot be sure the first bad commit is between $_mb and $_bad.
404 We continue anyway.
409 # "check_merge_bases" checks that merge bases are not "bad".
411 # - If one is "good", that's good, we have nothing to do.
412 # - If one is "bad", it means the user assumed something wrong
413 # and we must exit.
414 # - If one is "skipped", we can't know but we should warn.
415 # - If we don't know, we should check it out and ask the user to test.
417 # In the last case we will return 1, and otherwise 0.
419 check_merge_bases() {
420 _bad="$1"
421 _good="$2"
422 _skip="$3"
423 for _mb in $(git merge-base --all $_bad $_good)
425 if is_among "$_mb" "$_good"; then
426 continue
427 elif test "$_mb" = "$_bad"; then
428 handle_bad_merge_base "$_bad" "$_good"
429 elif is_among "$_mb" "$_skip"; then
430 handle_skipped_merge_base "$_mb" "$_bad" "$_good"
431 else
432 bisect_checkout "$_mb" "a merge base must be tested"
433 return 1
435 done
436 return 0
440 # "check_good_are_ancestors_of_bad" checks that all "good" revs are
441 # ancestor of the "bad" rev.
443 # If that's not the case, we need to check the merge bases.
444 # If a merge base must be tested by the user we return 1 and
445 # otherwise 0.
447 check_good_are_ancestors_of_bad() {
448 test -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
449 return
451 _bad="$1"
452 _good=$(echo $2 | sed -e 's/\^//g')
453 _skip="$3"
455 # Bisecting with no good rev is ok
456 test -z "$_good" && return
458 _side=$(git rev-list $_good ^$_bad)
459 if test -n "$_side"; then
460 # Return if a checkout was done
461 check_merge_bases "$_bad" "$_good" "$_skip" || return
464 : > "$GIT_DIR/BISECT_ANCESTORS_OK"
466 return 0
469 bisect_next() {
470 case "$#" in 0) ;; *) usage ;; esac
471 bisect_autostart
472 bisect_next_check good
474 # Get bad, good and skipped revs
475 bad=$(git rev-parse --verify refs/bisect/bad) &&
476 good=$(git for-each-ref --format='^%(objectname)' \
477 "refs/bisect/good-*" | tr '\012' ' ') &&
478 skip=$(git for-each-ref --format='%(objectname)' \
479 "refs/bisect/skip-*" | tr '\012' ' ') || exit
481 # Maybe some merge bases must be tested first
482 check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
483 # Return now if a checkout has already been done
484 test "$?" -eq "1" && return
486 # Get bisection information
487 BISECT_OPT=''
488 test -n "$skip" && BISECT_OPT='--bisect-all'
489 eval="git rev-list --bisect-vars $BISECT_OPT $good $bad --" &&
490 eval="$eval $(cat "$GIT_DIR/BISECT_NAMES")" &&
491 eval=$(filter_skipped "$eval" "$skip") &&
492 eval "$eval" || exit
494 if [ -z "$bisect_rev" ]; then
495 echo "$bad was both good and bad"
496 exit 1
498 if [ "$bisect_rev" = "$bad" ]; then
499 exit_if_skipped_commits "$bisect_tried"
500 echo "$bisect_rev is first bad commit"
501 git diff-tree --pretty $bisect_rev
502 exit 0
505 # We should exit here only if the "bad"
506 # commit is also a "skip" commit (see above).
507 exit_if_skipped_commits "$bisect_rev"
509 bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this"
512 bisect_visualize() {
513 bisect_next_check fail
515 if test $# = 0
516 then
517 case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
518 '') set git log ;;
519 set*) set gitk ;;
520 esac
521 else
522 case "$1" in
523 git*|tig) ;;
524 -*) set git log "$@" ;;
525 *) set git "$@" ;;
526 esac
529 not=$(git for-each-ref --format='%(refname)' "refs/bisect/good-*")
530 eval '"$@"' refs/bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
533 bisect_reset() {
534 test -s "$GIT_DIR/BISECT_START" || {
535 echo "We are not bisecting."
536 return
538 case "$#" in
539 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
540 1) git show-ref --verify --quiet -- "refs/heads/$1" ||
541 die "$1 does not seem to be a valid branch"
542 branch="$1" ;;
544 usage ;;
545 esac
546 git checkout "$branch" && bisect_clean_state
549 bisect_clean_state() {
550 # There may be some refs packed during bisection.
551 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
552 while read ref hash
554 git update-ref -d $ref $hash || exit
555 done
556 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
557 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
558 rm -f "$GIT_DIR/BISECT_LOG" &&
559 rm -f "$GIT_DIR/BISECT_NAMES" &&
560 rm -f "$GIT_DIR/BISECT_RUN" &&
561 # Cleanup head-name if it got left by an old version of git-bisect
562 rm -f "$GIT_DIR/head-name" &&
564 rm -f "$GIT_DIR/BISECT_START"
567 bisect_replay () {
568 test -r "$1" || die "cannot read $1 for replaying"
569 bisect_reset
570 while read git bisect command rev
572 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
573 if test "$git" = "git-bisect"; then
574 rev="$command"
575 command="$bisect"
577 case "$command" in
578 start)
579 cmd="bisect_start $rev"
580 eval "$cmd" ;;
581 good|bad|skip)
582 bisect_write "$command" "$rev" ;;
584 die "?? what are you talking about?" ;;
585 esac
586 done <"$1"
587 bisect_auto_next
590 bisect_run () {
591 bisect_next_check fail
593 while true
595 echo "running $@"
596 "$@"
597 res=$?
599 # Check for really bad run error.
600 if [ $res -lt 0 -o $res -ge 128 ]; then
601 echo >&2 "bisect run failed:"
602 echo >&2 "exit code $res from '$@' is < 0 or >= 128"
603 exit $res
606 # Find current state depending on run success or failure.
607 # A special exit code of 125 means cannot test.
608 if [ $res -eq 125 ]; then
609 state='skip'
610 elif [ $res -gt 0 ]; then
611 state='bad'
612 else
613 state='good'
616 # We have to use a subshell because "bisect_state" can exit.
617 ( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
618 res=$?
620 cat "$GIT_DIR/BISECT_RUN"
622 if grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
623 > /dev/null; then
624 echo >&2 "bisect run cannot continue any more"
625 exit $res
628 if [ $res -ne 0 ]; then
629 echo >&2 "bisect run failed:"
630 echo >&2 "'bisect_state $state' exited with error code $res"
631 exit $res
634 if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
635 echo "bisect run success"
636 exit 0;
639 done
643 case "$#" in
645 usage ;;
647 cmd="$1"
648 shift
649 case "$cmd" in
650 help)
651 git bisect -h ;;
652 start)
653 bisect_start "$@" ;;
654 bad|good)
655 bisect_state "$cmd" "$@" ;;
656 skip)
657 bisect_skip "$@" ;;
658 next)
659 # Not sure we want "next" at the UI level anymore.
660 bisect_next "$@" ;;
661 visualize|view)
662 bisect_visualize "$@" ;;
663 reset)
664 bisect_reset "$@" ;;
665 replay)
666 bisect_replay "$@" ;;
667 log)
668 cat "$GIT_DIR/BISECT_LOG" ;;
669 run)
670 bisect_run "$@" ;;
672 usage ;;
673 esac
674 esac