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