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