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 eval='' 241 for rev in "$@" 242 do 243 sha=$(git rev-parse --verify "$rev^{commit}")|| 244 die "$(eval_gettext "Bad rev input: \$rev")" 245 eval="$eval bisect_write '$state''$sha';" 246 done 247 eval "$eval" 248 check_expected_revs "$@" ;; 249 *,bad) 250 die "$(gettext "'git bisect bad' can take only one argument.")" ;; 251 *) 252 usage ;; 253 esac 254 bisect_auto_next 255} 256 257bisect_next_check() { 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 261 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. 273 gettextln "Warning: bisecting only with a bad commit." >&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 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 291 else 292 gettextln "You need to start by \"git bisect start\". 293You then need to give me at least one good and one bad revisions. 294(You can use \"git bisect bad\" and \"git bisect good\"for that.)" >&2 295 fi 296 exit 1 ;; 297 esac 298} 299 300bisect_auto_next() { 301 bisect_next_check && bisect_next || : 302} 303 304bisect_next() { 305 case "$#" in 0) ;; *) usage ;; esac 306 bisect_autostart 307 bisect_next_check good 308 309 # Perform all bisection computation, display and checkout 310 git bisect--helper --next-all$(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout) 311 res=$? 312 313 # Check if we should exit because bisection is finished 314 if test$res-eq 10 315 then 316 bad_rev=$(git show-ref --hash --verify refs/bisect/bad) 317 bad_commit=$(git show-branch $bad_rev) 318 echo "# first bad commit: $bad_commit" >>"$GIT_DIR/BISECT_LOG" 319exit0 320eliftest$res-eq2 321then 322echo"# only skipped commits left to test">>"$GIT_DIR/BISECT_LOG" 323 good_revs=$(git for-each-ref --format="%(objectname)" "refs/bisect/good-*") 324 for skipped in$(git rev-list refs/bisect/bad --not $good_revs) 325 do 326 skipped_commit=$(git show-branch $skipped) 327 echo "# possible first bad commit: $skipped_commit" >>"$GIT_DIR/BISECT_LOG" 328done 329exit$res 330fi 331 332# Check for an error in the bisection process 333test$res-ne0&&exit$res 334 335return0 336} 337 338bisect_visualize() { 339 bisect_next_check fail 340 341iftest$#=0 342then 343iftest -n"${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}"&& 344type gitk >/dev/null 2>&1 345then 346set gitk 347else 348set git log 349fi 350else 351case"$1"in 352 git*|tig) ;; 353-*)set git log "$@";; 354*)set git "$@";; 355esac 356fi 357 358eval'"$@"'--bisect --$(cat "$GIT_DIR/BISECT_NAMES") 359} 360 361bisect_reset() { 362test -s"$GIT_DIR/BISECT_START"|| { 363 gettextln "We are not bisecting." 364return 365} 366case"$#"in 3670) branch=$(cat "$GIT_DIR/BISECT_START");; 3681) git rev-parse --quiet --verify"$1^{commit}">/dev/null || { 369 invalid="$1" 370 die "$(eval_gettext "'\$invalid' is not a valid commit")" 371} 372 branch="$1";; 373*) 374 usage ;; 375esac 376 377if!test -f"$GIT_DIR/BISECT_HEAD"&& ! git checkout "$branch"-- 378then 379 die "$(eval_gettext "Could not check out original HEAD '\$branch'. 380Try 'git bisect reset <commit>'.")" 381fi 382 bisect_clean_state 383} 384 385bisect_clean_state() { 386# There may be some refs packed during bisection. 387 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* | 388whileread ref hash 389do 390 git update-ref -d$ref $hash||exit 391done 392rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&& 393rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&& 394rm-f"$GIT_DIR/BISECT_LOG"&& 395rm-f"$GIT_DIR/BISECT_NAMES"&& 396rm-f"$GIT_DIR/BISECT_RUN"&& 397# Cleanup head-name if it got left by an old version of git-bisect 398rm-f"$GIT_DIR/head-name"&& 399 git update-ref -d --no-deref BISECT_HEAD && 400# clean up BISECT_START last 401rm-f"$GIT_DIR/BISECT_START" 402} 403 404bisect_replay () { 405file="$1" 406test"$#"-eq1|| die "$(gettext "No logfile given")" 407test -r"$file"|| die "$(eval_gettext "cannot read \$file for replaying")" 408 bisect_reset 409whileread git bisect commandrev 410do 411test"$git$bisect"="git bisect"-o"$git"="git-bisect"||continue 412iftest"$git"="git-bisect" 413then 414rev="$command" 415command="$bisect" 416fi 417case"$command"in 418 start) 419 cmd="bisect_start$rev" 420eval"$cmd";; 421 good|bad|skip) 422 bisect_write "$command""$rev";; 423*) 424 die "$(gettext "?? what are you talking about?")";; 425esac 426done<"$file" 427 bisect_auto_next 428} 429 430bisect_run () { 431 bisect_next_check fail 432 433while true 434do 435command="$@" 436 eval_gettextln "running \$command" 437"$@" 438 res=$? 439 440# Check for really bad run error. 441if[$res-lt0-o$res-ge128] 442then 443 eval_gettextln "bisect run failed: 444exit code \$resfrom '\$command' is < 0 or >= 128">&2 445exit$res 446fi 447 448# Find current state depending on run success or failure. 449# A special exit code of 125 means cannot test. 450if[$res-eq125] 451then 452 state='skip' 453elif[$res-gt0] 454then 455 state='bad' 456else 457 state='good' 458fi 459 460# We have to use a subshell because "bisect_state" can exit. 461( bisect_state $state>"$GIT_DIR/BISECT_RUN") 462 res=$? 463 464cat"$GIT_DIR/BISECT_RUN" 465 466if sane_grep "first bad commit could be any of""$GIT_DIR/BISECT_RUN" \ 467>/dev/null 468then 469 gettextln "bisect run cannot continue any more">&2 470exit$res 471fi 472 473if[$res-ne0] 474then 475 eval_gettextln "bisect run failed: 476'bisect_state \$state' exited with error code \$res">&2 477exit$res 478fi 479 480if sane_grep "is the first bad commit""$GIT_DIR/BISECT_RUN">/dev/null 481then 482 gettextln "bisect run success" 483exit0; 484fi 485 486done 487} 488 489bisect_log () { 490test -s"$GIT_DIR/BISECT_LOG"|| die "$(gettext "We are not bisecting.")" 491cat"$GIT_DIR/BISECT_LOG" 492} 493 494case"$#"in 4950) 496 usage ;; 497*) 498 cmd="$1" 499shift 500case"$cmd"in 501help) 502 git bisect -h;; 503 start) 504 bisect_start "$@";; 505 bad|good) 506 bisect_state "$cmd""$@";; 507 skip) 508 bisect_skip "$@";; 509 next) 510# Not sure we want "next" at the UI level anymore. 511 bisect_next "$@";; 512 visualize|view) 513 bisect_visualize "$@";; 514reset) 515 bisect_reset "$@";; 516 replay) 517 bisect_replay "$@";; 518 log) 519 bisect_log ;; 520 run) 521 bisect_run "$@";; 522*) 523 usage ;; 524esac 525esac