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