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