bisect: use "bisect--helper" and remove "filter_skipped" function
[git/mingw.git] / git-bisect.sh
blob0f7590dfc2294d93b774f2ba4eed84d3e776625f
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 eval_and_string_together() {
283 _eval="$1"
285 eval "$_eval" | {
286 while read line
288 echo "$line &&"
289 done
290 echo ':'
294 exit_if_skipped_commits () {
295 _tried=$1
296 _bad=$2
297 if test -n "$_tried" ; then
298 echo "There are only 'skip'ped commit left to test."
299 echo "The first bad commit could be any of:"
300 echo "$_tried" | tr '[|]' '[\012]'
301 test -n "$_bad" && echo "$_bad"
302 echo "We cannot bisect more!"
303 exit 2
307 bisect_checkout() {
308 _rev="$1"
309 _msg="$2"
310 echo "Bisecting: $_msg"
311 mark_expected_rev "$_rev"
312 git checkout -q "$_rev" || exit
313 git show-branch "$_rev"
316 is_among() {
317 _rev="$1"
318 _list="$2"
319 case "$_list" in *$_rev*) return 0 ;; esac
320 return 1
323 handle_bad_merge_base() {
324 _badmb="$1"
325 _good="$2"
326 if is_expected_rev "$_badmb"; then
327 cat >&2 <<EOF
328 The merge base $_badmb is bad.
329 This means the bug has been fixed between $_badmb and [$_good].
331 exit 3
332 else
333 cat >&2 <<EOF
334 Some good revs are not ancestor of the bad rev.
335 git bisect cannot work properly in this case.
336 Maybe you mistake good and bad revs?
338 exit 1
342 handle_skipped_merge_base() {
343 _mb="$1"
344 _bad="$2"
345 _good="$3"
346 cat >&2 <<EOF
347 Warning: the merge base between $_bad and [$_good] must be skipped.
348 So we cannot be sure the first bad commit is between $_mb and $_bad.
349 We continue anyway.
354 # "check_merge_bases" checks that merge bases are not "bad".
356 # - If one is "good", that's good, we have nothing to do.
357 # - If one is "bad", it means the user assumed something wrong
358 # and we must exit.
359 # - If one is "skipped", we can't know but we should warn.
360 # - If we don't know, we should check it out and ask the user to test.
362 # In the last case we will return 1, and otherwise 0.
364 check_merge_bases() {
365 _bad="$1"
366 _good="$2"
367 _skip="$3"
368 for _mb in $(git merge-base --all $_bad $_good)
370 if is_among "$_mb" "$_good"; then
371 continue
372 elif test "$_mb" = "$_bad"; then
373 handle_bad_merge_base "$_bad" "$_good"
374 elif is_among "$_mb" "$_skip"; then
375 handle_skipped_merge_base "$_mb" "$_bad" "$_good"
376 else
377 bisect_checkout "$_mb" "a merge base must be tested"
378 return 1
380 done
381 return 0
385 # "check_good_are_ancestors_of_bad" checks that all "good" revs are
386 # ancestor of the "bad" rev.
388 # If that's not the case, we need to check the merge bases.
389 # If a merge base must be tested by the user we return 1 and
390 # otherwise 0.
392 check_good_are_ancestors_of_bad() {
393 test -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
394 return
396 _bad="$1"
397 _good=$(echo $2 | sed -e 's/\^//g')
398 _skip="$3"
400 # Bisecting with no good rev is ok
401 test -z "$_good" && return
403 _side=$(git rev-list $_good ^$_bad)
404 if test -n "$_side"; then
405 # Return if a checkout was done
406 check_merge_bases "$_bad" "$_good" "$_skip" || return
409 : > "$GIT_DIR/BISECT_ANCESTORS_OK"
411 return 0
414 bisect_next() {
415 case "$#" in 0) ;; *) usage ;; esac
416 bisect_autostart
417 bisect_next_check good
419 # Get bad, good and skipped revs
420 bad=$(git rev-parse --verify refs/bisect/bad) &&
421 good=$(git for-each-ref --format='^%(objectname)' \
422 "refs/bisect/good-*" | tr '\012' ' ') &&
423 skip=$(git for-each-ref --format='%(objectname)' \
424 "refs/bisect/skip-*" | tr '\012' ' ') || exit
426 # Maybe some merge bases must be tested first
427 check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
428 # Return now if a checkout has already been done
429 test "$?" -eq "1" && return
431 # Get bisection information
432 eval="git bisect--helper --next-vars" &&
433 eval=$(eval_and_string_together "$eval") &&
434 eval "$eval" || exit
436 if [ -z "$bisect_rev" ]; then
437 # We should exit here only if the "bad"
438 # commit is also a "skip" commit (see above).
439 exit_if_skipped_commits "$bisect_tried"
440 echo "$bad was both good and bad"
441 exit 1
443 if [ "$bisect_rev" = "$bad" ]; then
444 exit_if_skipped_commits "$bisect_tried" "$bad"
445 echo "$bisect_rev is first bad commit"
446 git diff-tree --pretty $bisect_rev
447 exit 0
450 bisect_checkout "$bisect_rev" "$bisect_nr revisions left to test after this (roughly $bisect_steps steps)"
453 bisect_visualize() {
454 bisect_next_check fail
456 if test $# = 0
457 then
458 case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
459 '') set git log ;;
460 set*) set gitk ;;
461 esac
462 else
463 case "$1" in
464 git*|tig) ;;
465 -*) set git log "$@" ;;
466 *) set git "$@" ;;
467 esac
470 not=$(git for-each-ref --format='%(refname)' "refs/bisect/good-*")
471 eval '"$@"' refs/bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
474 bisect_reset() {
475 test -s "$GIT_DIR/BISECT_START" || {
476 echo "We are not bisecting."
477 return
479 case "$#" in
480 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
481 1) git show-ref --verify --quiet -- "refs/heads/$1" ||
482 die "$1 does not seem to be a valid branch"
483 branch="$1" ;;
485 usage ;;
486 esac
487 git checkout "$branch" && bisect_clean_state
490 bisect_clean_state() {
491 # There may be some refs packed during bisection.
492 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
493 while read ref hash
495 git update-ref -d $ref $hash || exit
496 done
497 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
498 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
499 rm -f "$GIT_DIR/BISECT_LOG" &&
500 rm -f "$GIT_DIR/BISECT_NAMES" &&
501 rm -f "$GIT_DIR/BISECT_RUN" &&
502 # Cleanup head-name if it got left by an old version of git-bisect
503 rm -f "$GIT_DIR/head-name" &&
505 rm -f "$GIT_DIR/BISECT_START"
508 bisect_replay () {
509 test -r "$1" || die "cannot read $1 for replaying"
510 bisect_reset
511 while read git bisect command rev
513 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
514 if test "$git" = "git-bisect"; then
515 rev="$command"
516 command="$bisect"
518 case "$command" in
519 start)
520 cmd="bisect_start $rev"
521 eval "$cmd" ;;
522 good|bad|skip)
523 bisect_write "$command" "$rev" ;;
525 die "?? what are you talking about?" ;;
526 esac
527 done <"$1"
528 bisect_auto_next
531 bisect_run () {
532 bisect_next_check fail
534 while true
536 echo "running $@"
537 "$@"
538 res=$?
540 # Check for really bad run error.
541 if [ $res -lt 0 -o $res -ge 128 ]; then
542 echo >&2 "bisect run failed:"
543 echo >&2 "exit code $res from '$@' is < 0 or >= 128"
544 exit $res
547 # Find current state depending on run success or failure.
548 # A special exit code of 125 means cannot test.
549 if [ $res -eq 125 ]; then
550 state='skip'
551 elif [ $res -gt 0 ]; then
552 state='bad'
553 else
554 state='good'
557 # We have to use a subshell because "bisect_state" can exit.
558 ( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
559 res=$?
561 cat "$GIT_DIR/BISECT_RUN"
563 if grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
564 > /dev/null; then
565 echo >&2 "bisect run cannot continue any more"
566 exit $res
569 if [ $res -ne 0 ]; then
570 echo >&2 "bisect run failed:"
571 echo >&2 "'bisect_state $state' exited with error code $res"
572 exit $res
575 if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
576 echo "bisect run success"
577 exit 0;
580 done
584 case "$#" in
586 usage ;;
588 cmd="$1"
589 shift
590 case "$cmd" in
591 help)
592 git bisect -h ;;
593 start)
594 bisect_start "$@" ;;
595 bad|good)
596 bisect_state "$cmd" "$@" ;;
597 skip)
598 bisect_skip "$@" ;;
599 next)
600 # Not sure we want "next" at the UI level anymore.
601 bisect_next "$@" ;;
602 visualize|view)
603 bisect_visualize "$@" ;;
604 reset)
605 bisect_reset "$@" ;;
606 replay)
607 bisect_replay "$@" ;;
608 log)
609 cat "$GIT_DIR/BISECT_LOG" ;;
610 run)
611 bisect_run "$@" ;;
613 usage ;;
614 esac
615 esac