]> git.ipfire.org Git - thirdparty/git.git/blob - git-bisect.sh
Merge branch 'en/merge-recursive-2'
[thirdparty/git.git] / git-bisect.sh
1 #!/bin/sh
2
3 USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'
4 LONG_USAGE='git bisect help
5 print this long help message.
6 git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...]
7 reset bisect state and start bisection.
8 git bisect bad [<rev>]
9 mark <rev> a known-bad revision.
10 git bisect good [<rev>...]
11 mark <rev>... known-good revisions.
12 git bisect skip [(<rev>|<range>)...]
13 mark <rev>... untestable revisions.
14 git bisect next
15 find next bisection to test and check it out.
16 git bisect reset [<commit>]
17 finish bisection search and go back to commit.
18 git bisect visualize
19 show bisect status in gitk.
20 git bisect replay <logfile>
21 replay bisection log.
22 git bisect log
23 show bisect log.
24 git bisect run <cmd>...
25 use <cmd>... to automatically bisect.
26
27 Please use "git help bisect" to get the full man page.'
28
29 OPTIONS_SPEC=
30 . git-sh-setup
31 . git-sh-i18n
32
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
36 bisect_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
46 bisect_autostart() {
47 test -s "$GIT_DIR/BISECT_START" || {
48 (
49 gettext "You need to start by \"git bisect start\"" &&
50 echo
51 ) >&2
52 if test -t 0
53 then
54 # TRANSLATORS: Make sure to include [Y] and [n] in your
55 # translation. The program will only accept English input
56 # at this point.
57 gettext "Do you want me to do it for you [Y/n]? " >&2
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
70 bisect_start() {
71 #
72 # Check for one bad and then some good revisions.
73 #
74 has_double_dash=0
75 for arg; do
76 case "$arg" in --) has_double_dash=1; break ;; esac
77 done
78 orig_args=$(git rev-parse --sq-quote "$@")
79 bad_seen=0
80 eval=''
81 if test "z$(git rev-parse --is-bare-repository)" != zfalse
82 then
83 mode=--no-checkout
84 else
85 mode=''
86 fi
87 while [ $# -gt 0 ]; do
88 arg="$1"
89 case "$arg" in
90 --)
91 shift
92 break
93 ;;
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}") || {
101 test $has_double_dash -eq 1 &&
102 die "$(eval_gettext "'\$arg' does not appear to be a valid revision")"
103 break
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 ;;
112 esac
113 done
114
115 #
116 # Verify HEAD.
117 #
118 head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||
119 head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) ||
120 die "$(gettext "Bad HEAD - I need a HEAD")"
121
122 #
123 # Check if we are bisecting.
124 #
125 start_head=''
126 if test -s "$GIT_DIR/BISECT_START"
127 then
128 # Reset to the rev from where we started.
129 start_head=$(cat "$GIT_DIR/BISECT_START")
130 if test "z$mode" != "z--no-checkout"
131 then
132 git checkout "$start_head" --
133 fi
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" ] &&
142 die "$(gettext "won't bisect on seeked tree")"
143 start_head="${head#refs/heads/}"
144 ;;
145 *)
146 die "$(gettext "Bad HEAD - strange symbolic ref")"
147 ;;
148 esac
149 fi
150
151 #
152 # Get rid of any old bisect state.
153 #
154 bisect_clean_state || exit
155
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 #
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 } &&
173 git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" &&
174 eval "$eval true" &&
175 echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit
176 #
177 # Check if we can proceed to the next bisect state.
178 #
179 bisect_auto_next
180
181 trap '-' 0
182 }
183
184 bisect_write() {
185 state="$1"
186 rev="$2"
187 nolog="$3"
188 case "$state" in
189 bad) tag="$state" ;;
190 good|skip) tag="$state"-"$rev" ;;
191 *) die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;
192 esac
193 git update-ref "refs/bisect/$tag" "$rev" || exit
194 echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG"
195 test -n "$nolog" || echo "git bisect $state $rev" >>"$GIT_DIR/BISECT_LOG"
196 }
197
198 is_expected_rev() {
199 test -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
200 test "$1" = $(cat "$GIT_DIR/BISECT_EXPECTED_REV")
201 }
202
203 check_expected_revs() {
204 for _rev in "$@"; do
205 if ! is_expected_rev "$_rev"
206 then
207 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"
208 rm -f "$GIT_DIR/BISECT_EXPECTED_REV"
209 return
210 fi
211 done
212 }
213
214 bisect_skip() {
215 all=''
216 for arg in "$@"
217 do
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
227 }
228
229 bisect_state() {
230 bisect_autostart
231 state=$1
232 case "$#,$state" in
233 0,*)
234 die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;
235 1,bad|1,good|1,skip)
236 rev=$(git rev-parse --verify $(bisect_head)) ||
237 die "$(gettext "Bad rev input: $(bisect_head)")"
238 bisect_write "$state" "$rev"
239 check_expected_revs "$rev" ;;
240 2,bad|*,good|*,skip)
241 shift
242 eval=''
243 for rev in "$@"
244 do
245 sha=$(git rev-parse --verify "$rev^{commit}") ||
246 die "$(eval_gettext "Bad rev input: \$rev")"
247 eval="$eval bisect_write '$state' '$sha'; "
248 done
249 eval "$eval"
250 check_expected_revs "$@" ;;
251 *,bad)
252 die "$(gettext "'git bisect bad' can take only one argument.")" ;;
253 *)
254 usage ;;
255 esac
256 bisect_auto_next
257 }
258
259 bisect_next_check() {
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
263
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.
275 (
276 gettext "Warning: bisecting only with a bad commit." &&
277 echo
278 ) >&2
279 if test -t 0
280 then
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
285 read yesno
286 case "$yesno" in [Nn]*) exit 1 ;; esac
287 fi
288 : bisect without good...
289 ;;
290 *)
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\".
302 You 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
307 exit 1 ;;
308 esac
309 }
310
311 bisect_auto_next() {
312 bisect_next_check && bisect_next || :
313 }
314
315 bisect_next() {
316 case "$#" in 0) ;; *) usage ;; esac
317 bisect_autostart
318 bisect_next_check good
319
320 # Perform all bisection computation, display and checkout
321 git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)
322 res=$?
323
324 # Check if we should exit because bisection is finished
325 test $res -eq 10 && exit 0
326
327 # Check for an error in the bisection process
328 test $res -ne 0 && exit $res
329
330 return 0
331 }
332
333 bisect_visualize() {
334 bisect_next_check fail
335
336 if test $# = 0
337 then
338 if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" &&
339 type gitk >/dev/null 2>&1
340 then
341 set gitk
342 else
343 set git log
344 fi
345 else
346 case "$1" in
347 git*|tig) ;;
348 -*) set git log "$@" ;;
349 *) set git "$@" ;;
350 esac
351 fi
352
353 eval '"$@"' --bisect -- $(cat "$GIT_DIR/BISECT_NAMES")
354 }
355
356 bisect_reset() {
357 test -s "$GIT_DIR/BISECT_START" || {
358 gettext "We are not bisecting."; echo
359 return
360 }
361 case "$#" in
362 0) branch=$(cat "$GIT_DIR/BISECT_START") ;;
363 1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null || {
364 invalid="$1"
365 die "$(eval_gettext "'\$invalid' is not a valid commit")"
366 }
367 branch="$1" ;;
368 *)
369 usage ;;
370 esac
371
372 if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" --
373 then
374 die "$(eval_gettext "Could not check out original HEAD '\$branch'.
375 Try 'git bisect reset <commit>'.")"
376 fi
377 bisect_clean_state
378 }
379
380 bisect_clean_state() {
381 # There may be some refs packed during bisection.
382 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* |
383 while read ref hash
384 do
385 git update-ref -d $ref $hash || exit
386 done
387 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" &&
388 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" &&
389 rm -f "$GIT_DIR/BISECT_LOG" &&
390 rm -f "$GIT_DIR/BISECT_NAMES" &&
391 rm -f "$GIT_DIR/BISECT_RUN" &&
392 # Cleanup head-name if it got left by an old version of git-bisect
393 rm -f "$GIT_DIR/head-name" &&
394 git update-ref -d --no-deref BISECT_HEAD &&
395 # clean up BISECT_START last
396 rm -f "$GIT_DIR/BISECT_START"
397 }
398
399 bisect_replay () {
400 file="$1"
401 test "$#" -eq 1 || die "$(gettext "No logfile given")"
402 test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"
403 bisect_reset
404 while read git bisect command rev
405 do
406 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue
407 if test "$git" = "git-bisect"
408 then
409 rev="$command"
410 command="$bisect"
411 fi
412 case "$command" in
413 start)
414 cmd="bisect_start $rev"
415 eval "$cmd" ;;
416 good|bad|skip)
417 bisect_write "$command" "$rev" ;;
418 *)
419 die "$(gettext "?? what are you talking about?")" ;;
420 esac
421 done <"$file"
422 bisect_auto_next
423 }
424
425 bisect_run () {
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.
436 if [ $res -lt 0 -o $res -ge 128 ]
437 then
438 (
439 eval_gettext "bisect run failed:
440 exit code \$res from '\$command' is < 0 or >= 128" &&
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.
448 if [ $res -eq 125 ]
449 then
450 state='skip'
451 elif [ $res -gt 0 ]
452 then
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" \
465 > /dev/null
466 then
467 (
468 gettext "bisect run cannot continue any more" &&
469 echo
470 ) >&2
471 exit $res
472 fi
473
474 if [ $res -ne 0 ]
475 then
476 (
477 eval_gettext "bisect run failed:
478 'bisect_state \$state' exited with error code \$res" &&
479 echo
480 ) >&2
481 exit $res
482 fi
483
484 if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null
485 then
486 gettext "bisect run success"; echo
487 exit 0;
488 fi
489
490 done
491 }
492
493 bisect_log () {
494 test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")"
495 cat "$GIT_DIR/BISECT_LOG"
496 }
497
498 case "$#" in
499 0)
500 usage ;;
501 *)
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
529 esac