]> git.ipfire.org Git - thirdparty/git.git/blame - git-bisect.sh
GIT-VERSION-GEN: support non-standard $GIT_DIR path
[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
CC
129 git checkout "$start_head" -- ||
130 die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <validbranch>'.")"
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" ] &&
9570fc1e 140 die "$(gettext "won't bisect on seeked 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
d3e54c88 240 eval=''
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")"
d3e54c88
CC
245 eval="$eval bisect_write '$state' '$sha'; "
246 done
c9c4e2d5
CC
247 eval "$eval"
248 check_expected_revs "$@" ;;
e3389075 249 *,bad)
9570fc1e 250 die "$(gettext "'git bisect bad' can take only one argument.")" ;;
cc9f24d0
JH
251 *)
252 usage ;;
8cc6a083 253 esac
97e1c51e
CC
254 bisect_auto_next
255}
256
8cc6a083 257bisect_next_check() {
0a5280a9
JH
258 missing_good= missing_bad=
259 git show-ref -q --verify refs/bisect/bad || missing_bad=t
260 test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t
6fecf191 261
0a5280a9
JH
262 case "$missing_good,$missing_bad,$1" in
263 ,,*)
264 : have both good and bad - ok
265 ;;
266 *,)
267 # do not have both but not asked to fail - just report.
268 false
269 ;;
270 t,,good)
271 # have bad but not good. we could bisect although
272 # this is less optimum.
3145b1a2 273 gettextln "Warning: bisecting only with a bad commit." >&2
0a5280a9
JH
274 if test -t 0
275 then
04de0996
ÆAB
276 # TRANSLATORS: Make sure to include [Y] and [n] in your
277 # translation. The program will only accept English input
278 # at this point.
279 gettext "Are you sure [Y/n]? " >&2
e5d3afd7
FM
280 read yesno
281 case "$yesno" in [Nn]*) exit 1 ;; esac
0a5280a9
JH
282 fi
283 : bisect without good...
284 ;;
8cc6a083 285 *)
be508d3a
ÆAB
286
287 if test -s "$GIT_DIR/BISECT_START"
288 then
3145b1a2
JS
289 gettextln "You need to give me at least one good and one bad revisions.
290(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
be508d3a 291 else
3145b1a2 292 gettextln "You need to start by \"git bisect start\".
be508d3a 293You then need to give me at least one good and one bad revisions.
3145b1a2 294(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2
be508d3a 295 fi
0a5280a9 296 exit 1 ;;
8cc6a083
LT
297 esac
298}
299
300bisect_auto_next() {
434d036f 301 bisect_next_check && bisect_next || :
8cc6a083
LT
302}
303
304bisect_next() {
8fe26f44 305 case "$#" in 0) ;; *) usage ;; esac
8cc6a083 306 bisect_autostart
0a5280a9
JH
307 bisect_next_check good
308
0871984d 309 # Perform all bisection computation, display and checkout
4796e823 310 git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
5a1d31c7 311 res=$?
0a5280a9 312
6021be86 313 # Check if we should exit because bisection is finished
5a1d31c7 314 test $res -eq 10 && exit 0
0a5280a9 315
5a1d31c7
CC
316 # Check for an error in the bisection process
317 test $res -ne 0 && exit $res
318
319 return 0
8cc6a083
LT
320}
321
cc9f24d0
JH
322bisect_visualize() {
323 bisect_next_check fail
235997c9
JH
324
325 if test $# = 0
326 then
c4e4644e 327 if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
43b8ff4b 328 type gitk >/dev/null 2>&1
eef12a9a 329 then
c4e4644e
JK
330 set gitk
331 else
332 set git log
333 fi
235997c9
JH
334 else
335 case "$1" in
336 git*|tig) ;;
337 -*) set git log "$@" ;;
338 *) set git "$@" ;;
339 esac
340 fi
341
fc13aa3d 342 eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
cc9f24d0
JH
343}
344
8cc6a083 345bisect_reset() {
823ea121 346 test -s "$GIT_DIR/BISECT_START" || {
3145b1a2 347 gettextln "We are not bisecting."
fce0499f
CC
348 return
349 }
8cc6a083 350 case "$#" in
823ea121 351 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
7d0c2d6f 352 1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null || {
6021be86
JS
353 invalid="$1"
354 die "$(eval_gettext "'\$invalid' is not a valid commit")"
355 }
356 branch="$1" ;;
8fe26f44 357 *)
6021be86 358 usage ;;
8cc6a083 359 esac
43b8ff4b
JH
360
361 if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" --
4796e823 362 then
43b8ff4b 363 die "$(eval_gettext "Could not check out original HEAD '\$branch'.
15eaa049 364Try 'git bisect reset <commit>'.")"
3bb8cf88 365 fi
4796e823 366 bisect_clean_state
e204de28
JH
367}
368
38a47fd6 369bisect_clean_state() {
947a604b 370 # There may be some refs packed during bisection.
634f2464 371 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
947a604b
CC
372 while read ref hash
373 do
823ea121 374 git update-ref -d $ref $hash || exit
947a604b 375 done
c9c4e2d5
CC
376 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
377 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
823ea121
CC
378 rm -f "$GIT_DIR/BISECT_LOG" &&
379 rm -f "$GIT_DIR/BISECT_NAMES" &&
380 rm -f "$GIT_DIR/BISECT_RUN" &&
9d0cd91c 381 # Cleanup head-name if it got left by an old version of git-bisect
823ea121 382 rm -f "$GIT_DIR/head-name" &&
4796e823
JS
383 git update-ref -d --no-deref BISECT_HEAD &&
384 # clean up BISECT_START last
823ea121 385 rm -f "$GIT_DIR/BISECT_START"
38a47fd6
CC
386}
387
e204de28 388bisect_replay () {
55a9fc80
ÆAB
389 file="$1"
390 test "$#" -eq 1 || die "$(gettext "No logfile given")"
391 test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
e204de28 392 bisect_reset
6c98c054 393 while read git bisect command rev
e204de28 394 do
6c98c054 395 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
eef12a9a
JS
396 if test "$git" = "git-bisect"
397 then
6c98c054
MV
398 rev="$command"
399 command="$bisect"
400 fi
e204de28
JH
401 case "$command" in
402 start)
e9a45d75 403 cmd="bisect_start $rev"
737c74ee
CC
404 eval "$cmd" ;;
405 good|bad|skip)
406 bisect_write "$command" "$rev" ;;
e204de28 407 *)
9570fc1e 408 die "$(gettext "?? what are you talking about?")" ;;
e204de28 409 esac
55a9fc80 410 done <"$file"
e204de28 411 bisect_auto_next
8cc6a083
LT
412}
413
a17c4101 414bisect_run () {
6021be86
JS
415 bisect_next_check fail
416
417 while true
418 do
419 command="$@"
3145b1a2 420 eval_gettextln "running \$command"
6021be86
JS
421 "$@"
422 res=$?
423
424 # Check for really bad run error.
eef12a9a
JS
425 if [ $res -lt 0 -o $res -ge 128 ]
426 then
3145b1a2
JS
427 eval_gettextln "bisect run failed:
428exit code \$res from '\$command' is < 0 or >= 128" >&2
6021be86
JS
429 exit $res
430 fi
431
432 # Find current state depending on run success or failure.
433 # A special exit code of 125 means cannot test.
eef12a9a
JS
434 if [ $res -eq 125 ]
435 then
6021be86 436 state='skip'
eef12a9a
JS
437 elif [ $res -gt 0 ]
438 then
6021be86
JS
439 state='bad'
440 else
441 state='good'
442 fi
443
444 # We have to use a subshell because "bisect_state" can exit.
445 ( bisect_state $state > "$GIT_DIR/BISECT_RUN" )
446 res=$?
447
448 cat "$GIT_DIR/BISECT_RUN"
449
450 if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \
eef12a9a
JS
451 > /dev/null
452 then
3145b1a2 453 gettextln "bisect run cannot continue any more" >&2
6021be86
JS
454 exit $res
455 fi
456
eef12a9a
JS
457 if [ $res -ne 0 ]
458 then
3145b1a2
JS
459 eval_gettextln "bisect run failed:
460'bisect_state \$state' exited with error code \$res" >&2
6021be86
JS
461 exit $res
462 fi
a17c4101 463
eef12a9a
JS
464 if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null
465 then
3145b1a2 466 gettextln "bisect run success"
6021be86
JS
467 exit 0;
468 fi
a17c4101 469
6021be86 470 done
a17c4101
CC
471}
472
412ff738 473bisect_log () {
9570fc1e 474 test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")"
412ff738
SG
475 cat "$GIT_DIR/BISECT_LOG"
476}
a17c4101 477
8cc6a083
LT
478case "$#" in
4790)
6021be86 480 usage ;;
8cc6a083 481*)
6021be86
JS
482 cmd="$1"
483 shift
484 case "$cmd" in
485 help)
486 git bisect -h ;;
487 start)
488 bisect_start "$@" ;;
489 bad|good)
490 bisect_state "$cmd" "$@" ;;
491 skip)
492 bisect_skip "$@" ;;
493 next)
494 # Not sure we want "next" at the UI level anymore.
495 bisect_next "$@" ;;
496 visualize|view)
497 bisect_visualize "$@" ;;
498 reset)
499 bisect_reset "$@" ;;
500 replay)
501 bisect_replay "$@" ;;
502 log)
503 bisect_log ;;
504 run)
505 bisect_run "$@" ;;
506 *)
507 usage ;;
508 esac
8cc6a083 509esac