bisect--helper: remove "--next-vars" option as it is now useless
[git/dscho.git] / git-bisect.sh
blobe1f300bed1b926ca2e800d0c8bcefcc7d39a0071
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 bisect_checkout() {
283 _rev="$1"
284 _msg="$2"
285 echo "Bisecting: $_msg"
286 mark_expected_rev "$_rev"
287 git checkout -q "$_rev" -- || exit
288 git show-branch "$_rev"
291 is_among() {
292 _rev="$1"
293 _list="$2"
294 case "$_list" in *$_rev*) return 0 ;; esac
295 return 1
298 handle_bad_merge_base() {
299 _badmb="$1"
300 _good="$2"
301 if is_expected_rev "$_badmb"; then
302 cat >&2 <<EOF
303 The merge base $_badmb is bad.
304 This means the bug has been fixed between $_badmb and [$_good].
306 exit 3
307 else
308 cat >&2 <<EOF
309 Some good revs are not ancestor of the bad rev.
310 git bisect cannot work properly in this case.
311 Maybe you mistake good and bad revs?
313 exit 1
317 handle_skipped_merge_base() {
318 _mb="$1"
319 _bad="$2"
320 _good="$3"
321 cat >&2 <<EOF
322 Warning: the merge base between $_bad and [$_good] must be skipped.
323 So we cannot be sure the first bad commit is between $_mb and $_bad.
324 We continue anyway.
329 # "check_merge_bases" checks that merge bases are not "bad".
331 # - If one is "good", that's good, we have nothing to do.
332 # - If one is "bad", it means the user assumed something wrong
333 # and we must exit.
334 # - If one is "skipped", we can't know but we should warn.
335 # - If we don't know, we should check it out and ask the user to test.
337 # In the last case we will return 1, and otherwise 0.
339 check_merge_bases() {
340 _bad="$1"
341 _good="$2"
342 _skip="$3"
343 for _mb in $(git merge-base --all $_bad $_good)
345 if is_among "$_mb" "$_good"; then
346 continue
347 elif test "$_mb" = "$_bad"; then
348 handle_bad_merge_base "$_bad" "$_good"
349 elif is_among "$_mb" "$_skip"; then
350 handle_skipped_merge_base "$_mb" "$_bad" "$_good"
351 else
352 bisect_checkout "$_mb" "a merge base must be tested"
353 return 1
355 done
356 return 0
360 # "check_good_are_ancestors_of_bad" checks that all "good" revs are
361 # ancestor of the "bad" rev.
363 # If that's not the case, we need to check the merge bases.
364 # If a merge base must be tested by the user we return 1 and
365 # otherwise 0.
367 check_good_are_ancestors_of_bad() {
368 test -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
369 return
371 _bad="$1"
372 _good=$(echo $2 | sed -e 's/\^//g')
373 _skip="$3"
375 # Bisecting with no good rev is ok
376 test -z "$_good" && return
378 _side=$(git rev-list $_good ^$_bad)
379 if test -n "$_side"; then
380 # Return if a checkout was done
381 check_merge_bases "$_bad" "$_good" "$_skip" || return
384 : > "$GIT_DIR/BISECT_ANCESTORS_OK"
386 return 0
389 bisect_next() {
390 case "$#" in 0) ;; *) usage ;; esac
391 bisect_autostart
392 bisect_next_check good
394 # Get bad, good and skipped revs
395 bad=$(git rev-parse --verify refs/bisect/bad) &&
396 good=$(git for-each-ref --format='^%(objectname)' \
397 "refs/bisect/good-*" | tr '\012' ' ') &&
398 skip=$(git for-each-ref --format='%(objectname)' \
399 "refs/bisect/skip-*" | tr '\012' ' ') || exit
401 # Maybe some merge bases must be tested first
402 check_good_are_ancestors_of_bad "$bad" "$good" "$skip"
403 # Return now if a checkout has already been done
404 test "$?" -eq "1" && return
406 # Perform bisection computation, display and checkout
407 git bisect--helper --next-exit
408 res=$?
410 # Check if we should exit because bisection is finished
411 test $res -eq 10 && exit 0
413 # Check for an error in the bisection process
414 test $res -ne 0 && exit $res
416 return 0
419 bisect_visualize() {
420 bisect_next_check fail
422 if test $# = 0
423 then
424 case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in
425 '') set git log ;;
426 set*) set gitk ;;
427 esac
428 else
429 case "$1" in
430 git*|tig) ;;
431 -*) set git log "$@" ;;
432 *) set git "$@" ;;
433 esac
436 not=$(git for-each-ref --format='%(refname)' "refs/bisect/good-*")
437 eval '"$@"' refs/bisect/bad --not $not -- $(cat "$GIT_DIR/BISECT_NAMES")
440 bisect_reset() {
441 test -s "$GIT_DIR/BISECT_START" || {
442 echo "We are not bisecting."
443 return
445 case "$#" in
446 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
447 1) git show-ref --verify --quiet -- "refs/heads/$1" ||
448 die "$1 does not seem to be a valid branch"
449 branch="$1" ;;
451 usage ;;
452 esac
453 git checkout "$branch" -- && bisect_clean_state
456 bisect_clean_state() {
457 # There may be some refs packed during bisection.
458 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
459 while read ref hash
461 git update-ref -d $ref $hash || exit
462 done
463 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
464 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
465 rm -f "$GIT_DIR/BISECT_LOG" &&
466 rm -f "$GIT_DIR/BISECT_NAMES" &&
467 rm -f "$GIT_DIR/BISECT_RUN" &&
468 # Cleanup head-name if it got left by an old version of git-bisect
469 rm -f "$GIT_DIR/head-name" &&
471 rm -f "$GIT_DIR/BISECT_START"
474 bisect_replay () {
475 test -r "$1" || die "cannot read $1 for replaying"
476 bisect_reset
477 while read git bisect command rev
479 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
480 if test "$git" = "git-bisect"; then
481 rev="$command"
482 command="$bisect"
484 case "$command" in
485 start)
486 cmd="bisect_start $rev"
487 eval "$cmd" ;;
488 good|bad|skip)
489 bisect_write "$command" "$rev" ;;
491 die "?? what are you talking about?" ;;
492 esac
493 done <"$1"
494 bisect_auto_next
497 bisect_run () {
498 bisect_next_check fail
500 while true
502 echo "running $@"
503 "$@"
504 res=$?
506 # Check for really bad run error.
507 if [ $res -lt 0 -o $res -ge 128 ]; then
508 echo >&2 "bisect run failed:"
509 echo >&2 "exit code $res from '$@' is < 0 or >= 128"
510 exit $res
513 # Find current state depending on run success or failure.
514 # A special exit code of 125 means cannot test.
515 if [ $res -eq 125 ]; then
516 state='skip'
517 elif [ $res -gt 0 ]; then
518 state='bad'
519 else
520 state='good'
523 # We have to use a subshell because "bisect_state" can exit.
524 ( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
525 res=$?
527 cat "$GIT_DIR/BISECT_RUN"
529 if grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
530 > /dev/null; then
531 echo >&2 "bisect run cannot continue any more"
532 exit $res
535 if [ $res -ne 0 ]; then
536 echo >&2 "bisect run failed:"
537 echo >&2 "'bisect_state $state' exited with error code $res"
538 exit $res
541 if grep "is first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then
542 echo "bisect run success"
543 exit 0;
546 done
550 case "$#" in
552 usage ;;
554 cmd="$1"
555 shift
556 case "$cmd" in
557 help)
558 git bisect -h ;;
559 start)
560 bisect_start "$@" ;;
561 bad|good)
562 bisect_state "$cmd" "$@" ;;
563 skip)
564 bisect_skip "$@" ;;
565 next)
566 # Not sure we want "next" at the UI level anymore.
567 bisect_next "$@" ;;
568 visualize|view)
569 bisect_visualize "$@" ;;
570 reset)
571 bisect_reset "$@" ;;
572 replay)
573 bisect_replay "$@" ;;
574 log)
575 cat "$GIT_DIR/BISECT_LOG" ;;
576 run)
577 bisect_run "$@" ;;
579 usage ;;
580 esac
581 esac