1#!/bin/sh 2 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 [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...] 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. 12git bisect skip [(<rev>|<range>)...] 13 mark <rev>... untestable revisions. 14git bisect next 15 find next bisection to test and check it out. 16git bisect reset [<commit>] 17 finish bisection search and go back to commit. 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>... 25 use <cmd>... to automatically bisect. 26 27Please use "git help bisect" to get the full man page.' 28 29OPTIONS_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 36bisect_head() 37{ 38iftest -f"$GIT_DIR/BISECT_HEAD" 39then 40echo BISECT_HEAD 41else 42echo HEAD 43fi 44} 45 46bisect_autostart() { 47test -s"$GIT_DIR/BISECT_START"|| { 48( 49gettext"You need to start by\"git bisect start\""&& 50echo 51) >&2 52iftest -t0 53then 54# TRANSLATORS: Make sure to include [Y] and [n] in your 55# translation. The program will only accept English input 56# at this point. 57gettext"Do you want me to do it for you [Y/n]? ">&2 58read yesno 59case"$yesno"in 60[Nn]*) 61exit;; 62esac 63 bisect_start 64else 65exit1 66fi 67} 68} 69 70bisect_start() { 71# 72# Check for one bad and then some good revisions. 73# 74 has_double_dash=0 75for arg;do 76case"$arg"in--) has_double_dash=1;break;;esac 77done 78 orig_args=$(git rev-parse --sq-quote "$@") 79 bad_seen=0 80eval='' 81iftest"z$(git rev-parse --is-bare-repository)"!= zfalse 82then 83 mode=--no-checkout 84else 85 mode='' 86fi 87while[$#-gt0];do 88 arg="$1" 89case"$arg"in 90--) 91shift 92break 93;; 94--no-checkout) 95 mode=--no-checkout 96shift;; 97--*) 98 die "$(eval_gettext "unrecognised option: '\$arg'")";; 99*) 100rev=$(git rev-parse -q --verify "$arg^{commit}")|| { 101test$has_double_dash-eq1&& 102 die "$(eval_gettext "'\$arg' does not appear to be a valid revision")" 103break 104} 105case$bad_seenin 1060) state='bad'; bad_seen=1;; 107*) state='good';; 108esac 109eval="$evalbisect_write '$state' '$rev' 'nolog' &&" 110shift 111;; 112esac 113done 114 115# 116# Verify HEAD. 117# 118head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD)|| 119head=$(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='' 126iftest -s"$GIT_DIR/BISECT_START" 127then 128# Reset to the rev from where we started. 129 start_head=$(cat "$GIT_DIR/BISECT_START") 130iftest"z$mode"!="z--no-checkout" 131then 132 git checkout "$start_head"-- 133fi 134else 135# Get rev from where we start. 136case"$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;; 148esac 149fi 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# 163trap'bisect_clean_state'0 164trap'exit 255'1 2 3 15 165 166# 167# Write new start state. 168# 169echo"$start_head">"$GIT_DIR/BISECT_START"&& { 170test"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"&& 174eval"$evaltrue"&& 175echo"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 181trap'-'0 182} 183 184bisect_write() { 185 state="$1" 186rev="$2" 187 nolog="$3" 188case"$state"in 189 bad) tag="$state";; 190 good|skip) tag="$state"-"$rev";; 191*) die "$(eval_gettext "Bad bisect_write argument: \$state")";; 192esac 193 git update-ref"refs/bisect/$tag""$rev"||exit 194echo"#$state:$(git show-branch $rev)">>"$GIT_DIR/BISECT_LOG" 195test -n"$nolog"||echo"git bisect$state$rev">>"$GIT_DIR/BISECT_LOG" 196} 197 198is_expected_rev() { 199test -f"$GIT_DIR/BISECT_EXPECTED_REV"&& 200test"$1"=$(cat "$GIT_DIR/BISECT_EXPECTED_REV") 201} 202 203check_expected_revs() { 204for _rev in"$@";do 205if! is_expected_rev "$_rev" 206then 207rm-f"$GIT_DIR/BISECT_ANCESTORS_OK" 208rm-f"$GIT_DIR/BISECT_EXPECTED_REV" 209return 210fi 211done 212} 213 214bisect_skip() { 215 all='' 216for arg in"$@" 217do 218case"$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");; 223esac 224 all="$all$revs" 225done 226eval bisect_state 'skip'$all 227} 228 229bisect_state() { 230 bisect_autostart 231 state=$1 232case"$#,$state"in 2330,*) 234 die "$(gettext "Please call 'bisect_state' with at least one argument.")";; 2351,bad|1,good|1,skip) 236rev=$(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 259bisect_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\". 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 307 exit 1 ;; 308 esac 309} 310 311bisect_auto_next() { 312 bisect_next_check && bisect_next || : 313} 314 315bisect_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 333bisect_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 356bisect_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'. 375Try 'git bisect reset <commit>'.")" 376 fi 377 bisect_clean_state 378} 379 380bisect_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 399bisect_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 425bisect_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: 440exit 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 493bisect_log () { 494 test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")" 495 cat "$GIT_DIR/BISECT_LOG" 496} 497 498case "$#" in 4990) 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 529esac