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