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