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