]> git.ipfire.org Git - thirdparty/git.git/blame - git-bisect.sh
Documentation/bisect: revise overall content
[thirdparty/git.git] / git-bisect.sh
CommitLineData
8cc6a083 1#!/bin/sh
d025524d 2
243a60fb
CC
3USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
4LONG_USAGE='git bisect help
6021be86 5 print this long help message.
4796e823 6git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
6021be86 7 reset bisect state and start bisection.
38a47fd6 8git bisect bad [<rev>]
6021be86 9 mark <rev> a known-bad revision.
38a47fd6 10git bisect good [<rev>...]
6021be86 11 mark <rev>... known-good revisions.
5413812f 12git bisect skip [(<rev>|<range>)...]
6021be86 13 mark <rev>... untestable revisions.
38a47fd6 14git bisect next
6021be86 15 find next bisection to test and check it out.
6b87ce23 16git bisect reset [<commit>]
6021be86 17 finish bisection search and go back to commit.
38a47fd6 18git bisect visualize
6021be86 19 show bisect status in gitk.
38a47fd6 20git bisect replay <logfile>
6021be86 21 replay bisection log.
38a47fd6 22git bisect log
6021be86 23 show bisect log.
38a47fd6 24git bisect run <cmd>...
6021be86 25 use <cmd>... to automatically bisect.
243a60fb
CC
26
27Please use "git help bisect" to get the full man page.'
d025524d 28
8f321a39 29OPTIONS_SPEC=
ae2b0f15 30. git-sh-setup
dcf9c2e5 31. git-sh-i18n
8cc6a083 32
ce32660e
JS
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
4796e823
JS
36bisect_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
8cc6a083 46bisect_autostart() {
823ea121 47 test -s "$GIT_DIR/BISECT_START" || {
3145b1a2 48 gettextln "You need to start by \"git bisect start\"" >&2
8cc6a083
LT
49 if test -t 0
50 then
04de0996
ÆAB
51 # TRANSLATORS: Make sure to include [Y] and [n] in your
52 # translation. The program will only accept English input
53 # at this point.
6021be86 54 gettext "Do you want me to do it for you [Y/n]? " >&2
8cc6a083
LT
55 read yesno
56 case "$yesno" in
57 [Nn]*)
58 exit ;;
59 esac
60 bisect_start
61 else
62 exit 1
63 fi
64 }
65}
66
67bisect_start() {
4764f464
JS
68 #
69 # Check for one bad and then some good revisions.
70 #
71 has_double_dash=0
72 for arg; do
6021be86 73 case "$arg" in --) has_double_dash=1; break ;; esac
4764f464
JS
74 done
75 orig_args=$(git rev-parse --sq-quote "$@")
76 bad_seen=0
77 eval=''
24c51280
JS
78 if test "z$(git rev-parse --is-bare-repository)" != zfalse
79 then
80 mode=--no-checkout
81 else
82 mode=''
83 fi
4764f464 84 while [ $# -gt 0 ]; do
6021be86
JS
85 arg="$1"
86 case "$arg" in
87 --)
88 shift
89 break
4764f464 90 ;;
6021be86
JS
91 --no-checkout)
92 mode=--no-checkout
93 shift ;;
94 --*)
95 die "$(eval_gettext "unrecognised option: '\$arg'")" ;;
96 *)
97 rev=$(git rev-parse -q --verify "$arg^{commit}") || {
43b8ff4b
JH
98 test $has_double_dash -eq 1 &&
99 die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
100 break
6021be86
JS
101 }
102 case $bad_seen in
103 0) state='bad' ; bad_seen=1 ;;
104 *) state='good' ;;
105 esac
106 eval="$eval bisect_write '$state' '$rev' 'nolog' &&"
107 shift
108 ;;
4764f464 109 esac
4764f464
JS
110 done
111
8cc6a083 112 #
634f2464 113 # Verify HEAD.
8cc6a083 114 #
48949a18 115 head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
ce32660e 116 head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
9570fc1e 117 die "$(gettext "Bad HEAD - I need a HEAD")"
634f2464 118
ee831f7d 119 #
634f2464 120 # Check if we are bisecting.
ee831f7d 121 #
d3e54c88 122 start_head=''
634f2464
CC
123 if test -s "$GIT_DIR/BISECT_START"
124 then
125 # Reset to the rev from where we started.
9d0cd91c 126 start_head=$(cat "$GIT_DIR/BISECT_START")
4796e823
JS
127 if test "z$mode" != "z--no-checkout"
128 then
1acf1171 129 git checkout "$start_head" -- ||
9c9b4f2f 130 die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <valid-branch>'.")"
4796e823 131 fi
634f2464
CC
132 else
133 # Get rev from where we start.
134 case "$head" in
135 refs/heads/*|$_x40)
136 # This error message should only be triggered by
137 # cogito usage, and cogito users should understand
138 # it relates to cg-seek.
139 [ -s "$GIT_DIR/head-name" ] &&
382d20e3 140 die "$(gettext "won't bisect on cg-seek'ed tree")"
634f2464
CC
141 start_head="${head#refs/heads/}"
142 ;;
143 *)
9570fc1e 144 die "$(gettext "Bad HEAD - strange symbolic ref")"
634f2464
CC
145 ;;
146 esac
147 fi
8cc6a083
LT
148
149 #
634f2464 150 # Get rid of any old bisect state.
8cc6a083 151 #
823ea121 152 bisect_clean_state || exit
38a47fd6 153
ba963de8
CC
154 #
155 # Change state.
156 # In case of mistaken revs or checkout error, or signals received,
157 # "bisect_auto_next" below may exit or misbehave.
158 # We have to trap this to be able to clean up using
159 # "bisect_clean_state".
160 #
161 trap 'bisect_clean_state' 0
162 trap 'exit 255' 1 2 3 15
163
164 #
165 # Write new start state.
166 #
4796e823
JS
167 echo "$start_head" >"$GIT_DIR/BISECT_START" && {
168 test "z$mode" != "z--no-checkout" ||
169 git update-ref --no-deref BISECT_HEAD "$start_head"
170 } &&
de52f5a8 171 git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
6ba7acff 172 eval "$eval true" &&
6c98c054 173 echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
ba963de8
CC
174 #
175 # Check if we can proceed to the next bisect state.
176 #
38a47fd6 177 bisect_auto_next
ba963de8
CC
178
179 trap '-' 0
8cc6a083
LT
180}
181
55624f9a
CC
182bisect_write() {
183 state="$1"
184 rev="$2"
737c74ee 185 nolog="$3"
55624f9a
CC
186 case "$state" in
187 bad) tag="$state" ;;
188 good|skip) tag="$state"-"$rev" ;;
15eaa049 189 *) die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
55624f9a 190 esac
ba963de8 191 git update-ref "refs/bisect/$tag" "$rev" || exit
f454cdc4 192 echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
6c98c054 193 test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
55624f9a
CC
194}
195
c9c4e2d5
CC
196is_expected_rev() {
197 test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
198 test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
199}
200
c9c4e2d5
CC
201check_expected_revs() {
202 for _rev in "$@"; do
eef12a9a
JS
203 if ! is_expected_rev "$_rev"
204 then
c9c4e2d5
CC
205 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
206 rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
207 return
208 fi
209 done
210}
211
ee2314f5 212bisect_skip() {
6021be86 213 all=''
ee2314f5
CC
214 for arg in "$@"
215 do
6021be86
JS
216 case "$arg" in
217 *..*)
218 revs=$(git rev-list "$arg") || die "$(eval_gettext "Bad rev input: \$arg")" ;;
219 *)
220 revs=$(git rev-parse --sq-quote "$arg") ;;
221 esac
222 all="$all $revs"
223 done
224 eval bisect_state 'skip' $all
ee2314f5
CC
225}
226
155fc795 227bisect_state() {
8cc6a083 228 bisect_autostart
155fc795
CC
229 state=$1
230 case "$#,$state" in
231 0,*)
9570fc1e 232 die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
155fc795 233 1,bad|1,good|1,skip)
4796e823
JS
234 rev=$(git rev-parse --verify $(bisect_head)) ||
235 die "$(gettext "Bad rev input: $(bisect_head)")"
c9c4e2d5
CC
236 bisect_write "$state" "$rev"
237 check_expected_revs "$rev" ;;
e3389075 238 2,bad|*,good|*,skip)
155fc795 239 shift
6bc02d56 240 hash_list=''
e3389075 241 for rev in "$@"
155fc795 242 do
a179a303 243 sha=$(git rev-parse --verify "$rev^{commit}") ||
15eaa049 244 die "$(eval_gettext "Bad rev input: \$rev")"
6bc02d56 245 hash_list="$hash_list $sha"
d3e54c88 246 done
6bc02d56
CC
247 for rev in $hash_list
248 do
249 bisect_write "$state" "$rev"
250 done
251 check_expected_revs $hash_list ;;
e3389075 252 *,bad)
9570fc1e 253 die "$(gettext "'git bisect bad' can take only one argument.")" ;;
cc9f24d0
JH
254 *)
255 usage ;;
8cc6a083 256 esac
97e1c51e
CC
257 bisect_auto_next
258}
259
8cc6a083 260bisect_next_check() {
0a5280a9
JH
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
6fecf191 264
0a5280a9
JH
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.
3145b1a2 276 gettextln "Warning: bisecting only with a bad commit." >&2
0a5280a9
JH
277 if test -t 0
278 then
04de0996
ÆAB
279 # TRANSLATORS: Make sure to include [Y] and [n] in your
280 # translation. The program will only accept English input
281 # at this point.
282 gettext "Are you sure [Y/n]? " >&2
e5d3afd7
FM
283 read yesno
284 case "$yesno" in [Nn]*) exit 1 ;; esac
0a5280a9
JH
285 fi
286 : bisect without good...
287 ;;
8cc6a083 288 *)
be508d3a
ÆAB
289
290 if test -s "$GIT_DIR/BISECT_START"
291 then
ad5fe377 292 gettextln "You need to give me at least one good and one bad revision.
3145b1a2 293(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
be508d3a 294 else
3145b1a2 295 gettextln "You need to start by \"git bisect start\".
ad5fe377 296You then need to give me at least one good and one bad revision.
3145b1a2 297(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
be508d3a 298 fi
0a5280a9 299 exit 1 ;;
8cc6a083
LT
300 esac
301}
302
303bisect_auto_next() {
434d036f 304 bisect_next_check && bisect_next || :
8cc6a083
LT
305}
306
307bisect_next() {
8fe26f44 308 case "$#" in 0) ;; *) usage ;; esac
8cc6a083 309 bisect_autostart
0a5280a9
JH
310 bisect_next_check good
311
0871984d 312 # Perform all bisection computation, display and checkout
4796e823 313 git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
5a1d31c7 314 res=$?
0a5280a9 315
6021be86 316 # Check if we should exit because bisection is finished
a7f8b8ac
TH
317 if test $res -eq 10
318 then
319 bad_rev=$(git show-ref --hash --verify refs/bisect/bad)
320 bad_commit=$(git show-branch $bad_rev)
321 echo "# first bad commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG"
322 exit 0
f989cac9
TH
323 elif test $res -eq 2
324 then
325 echo "# only skipped commits left to test" >>"$GIT_DIR/BISECT_LOG"
7358a672
TH
326 good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/good-*")
327 for skipped in $(git rev-list refs/bisect/bad --not $good_revs)
f989cac9
TH
328 do
329 skipped_commit=$(git show-branch $skipped)
330 echo "# possible first bad commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG"
331 done
332 exit $res
a7f8b8ac 333 fi
0a5280a9 334
5a1d31c7
CC
335 # Check for an error in the bisection process
336 test $res -ne 0 && exit $res
337
338 return 0
8cc6a083
LT
339}
340
cc9f24d0
JH
341bisect_visualize() {
342 bisect_next_check fail
235997c9
JH
343
344 if test $# = 0
345 then
c4e4644e 346 if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
43b8ff4b 347 type gitk >/dev/null 2>&1
eef12a9a 348 then
c4e4644e
JK
349 set gitk
350 else
351 set git log
352 fi
235997c9
JH
353 else
354 case "$1" in
355 git*|tig) ;;
356 -*) set git log "$@" ;;
357 *) set git "$@" ;;
358 esac
359 fi
360
fc13aa3d 361 eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
cc9f24d0
JH
362}
363
8cc6a083 364bisect_reset() {
823ea121 365 test -s "$GIT_DIR/BISECT_START" || {
3145b1a2 366 gettextln "We are not bisecting."
fce0499f
CC
367 return
368 }
8cc6a083 369 case "$#" in
823ea121 370 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
305a233c 371 1) git rev-parse --quiet --verify "$1^{commit}" >/dev/null || {
6021be86
JS
372 invalid="$1"
373 die "$(eval_gettext "'\$invalid' is not a valid commit")"
374 }
375 branch="$1" ;;
8fe26f44 376 *)
6021be86 377 usage ;;
8cc6a083 378 esac
43b8ff4b
JH
379
380 if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" --
4796e823 381 then
43b8ff4b 382 die "$(eval_gettext "Could not check out original HEAD '\$branch'.
15eaa049 383Try 'git bisect reset <commit>'.")"
3bb8cf88 384 fi
4796e823 385 bisect_clean_state
e204de28
JH
386}
387
38a47fd6 388bisect_clean_state() {
947a604b 389 # There may be some refs packed during bisection.
634f2464 390 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
947a604b
CC
391 while read ref hash
392 do
823ea121 393 git update-ref -d $ref $hash || exit
947a604b 394 done
c9c4e2d5
CC
395 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
396 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
823ea121
CC
397 rm -f "$GIT_DIR/BISECT_LOG" &&
398 rm -f "$GIT_DIR/BISECT_NAMES" &&
399 rm -f "$GIT_DIR/BISECT_RUN" &&
9d0cd91c 400 # Cleanup head-name if it got left by an old version of git-bisect
823ea121 401 rm -f "$GIT_DIR/head-name" &&
4796e823
JS
402 git update-ref -d --no-deref BISECT_HEAD &&
403 # clean up BISECT_START last
823ea121 404 rm -f "$GIT_DIR/BISECT_START"
38a47fd6
CC
405}
406
e204de28 407bisect_replay () {
55a9fc80
ÆAB
408 file="$1"
409 test "$#" -eq 1 || die "$(gettext "No logfile given")"
410 test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
e204de28 411 bisect_reset
6c98c054 412 while read git bisect command rev
e204de28 413 do
c82af12a 414 test "$git $bisect" = "git bisect" || test "$git" = "git-bisect" || continue
eef12a9a
JS
415 if test "$git" = "git-bisect"
416 then
6c98c054
MV
417 rev="$command"
418 command="$bisect"
419 fi
e204de28
JH
420 case "$command" in
421 start)
e9a45d75 422 cmd="bisect_start $rev"
737c74ee
CC
423 eval "$cmd" ;;
424 good|bad|skip)
425 bisect_write "$command" "$rev" ;;
e204de28 426 *)
9570fc1e 427 die "$(gettext "?? what are you talking about?")" ;;
e204de28 428 esac
55a9fc80 429 done <"$file"
e204de28 430 bisect_auto_next
8cc6a083
LT
431}
432
a17c4101 433bisect_run () {
6021be86
JS
434 bisect_next_check fail
435
436 while true
437 do
438 command="$@"
3145b1a2 439 eval_gettextln "running \$command"
6021be86
JS
440 "$@"
441 res=$?
442
443 # Check for really bad run error.
eef12a9a
JS
444 if [ $res -lt 0 -o $res -ge 128 ]
445 then
3145b1a2
JS
446 eval_gettextln "bisect run failed:
447exit code \$res from '\$command' is < 0 or >= 128" >&2
6021be86
JS
448 exit $res
449 fi
450
451 # Find current state depending on run success or failure.
452 # A special exit code of 125 means cannot test.
eef12a9a
JS
453 if [ $res -eq 125 ]
454 then
6021be86 455 state='skip'
eef12a9a
JS
456 elif [ $res -gt 0 ]
457 then
6021be86
JS
458 state='bad'
459 else
460 state='good'
461 fi
462
463 # We have to use a subshell because "bisect_state" can exit.
305a233c 464 ( bisect_state $state >"$GIT_DIR/BISECT_RUN" )
6021be86
JS
465 res=$?
466
467 cat "$GIT_DIR/BISECT_RUN"
468
469 if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
305a233c 470 >/dev/null
eef12a9a 471 then
3145b1a2 472 gettextln "bisect run cannot continue any more" >&2
6021be86
JS
473 exit $res
474 fi
475
eef12a9a
JS
476 if [ $res -ne 0 ]
477 then
3145b1a2
JS
478 eval_gettextln "bisect run failed:
479'bisect_state \$state' exited with error code \$res" >&2
6021be86
JS
480 exit $res
481 fi
a17c4101 482
305a233c 483 if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" >/dev/null
eef12a9a 484 then
3145b1a2 485 gettextln "bisect run success"
6021be86
JS
486 exit 0;
487 fi
a17c4101 488
6021be86 489 done
a17c4101
CC
490}
491
412ff738 492bisect_log () {
9570fc1e 493 test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")"
412ff738
SG
494 cat "$GIT_DIR/BISECT_LOG"
495}
a17c4101 496
8cc6a083
LT
497case "$#" in
4980)
6021be86 499 usage ;;
8cc6a083 500*)
6021be86
JS
501 cmd="$1"
502 shift
503 case "$cmd" in
504 help)
505 git bisect -h ;;
506 start)
507 bisect_start "$@" ;;
508 bad|good)
509 bisect_state "$cmd" "$@" ;;
510 skip)
511 bisect_skip "$@" ;;
512 next)
513 # Not sure we want "next" at the UI level anymore.
514 bisect_next "$@" ;;
515 visualize|view)
516 bisect_visualize "$@" ;;
517 reset)
518 bisect_reset "$@" ;;
519 replay)
520 bisect_replay "$@" ;;
521 log)
522 bisect_log ;;
523 run)
524 bisect_run "$@" ;;
525 *)
526 usage ;;
527 esac
8cc6a083 528esac