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