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