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 THEN='' 265test -s"$GIT_DIR/BISECT_START"|| { 266echo>&2'You need to start by "git bisect start".' 267 THEN='then ' 268} 269echo>&2'You '$THEN'need to give me at least one good' \ 270'and one bad revisions.' 271echo>&2'(You can use "git bisect bad" and' \ 272'"git bisect good" for that.)' 273exit1;; 274esac 275} 276 277bisect_auto_next() { 278 bisect_next_check && bisect_next || : 279} 280 281bisect_next() { 282case"$#"in0) ;; *) usage ;;esac 283 bisect_autostart 284 bisect_next_check good 285 286# Perform all bisection computation, display and checkout 287 git bisect--helper --next-all 288 res=$? 289 290# Check if we should exit because bisection is finished 291test$res-eq10&&exit0 292 293# Check for an error in the bisection process 294test$res-ne0&&exit$res 295 296return0 297} 298 299bisect_visualize() { 300 bisect_next_check fail 301 302iftest$#=0 303then 304iftest -n"${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}"&& 305type gitk >/dev/null 2>&1;then 306set gitk 307else 308set git log 309fi 310else 311case"$1"in 312 git*|tig) ;; 313-*)set git log "$@";; 314*)set git "$@";; 315esac 316fi 317 318eval'"$@"'--bisect --$(cat "$GIT_DIR/BISECT_NAMES") 319} 320 321bisect_reset() { 322test -s"$GIT_DIR/BISECT_START"|| { 323gettext"We are not bisecting.";echo 324return 325} 326case"$#"in 3270) branch=$(cat "$GIT_DIR/BISECT_START");; 3281) git rev-parse --quiet --verify"$1^{commit}"> /dev/null || { 329 invalid="$1" 330 die "$(eval_gettext "'\$invalid' is not a valid commit")" 331} 332 branch="$1";; 333*) 334 usage ;; 335esac 336if git checkout "$branch"--;then 337 bisect_clean_state 338else 339 die "$(eval_gettext "Could not check out original HEAD '\$branch'. 340Try 'git bisect reset <commit>'.")" 341fi 342} 343 344bisect_clean_state() { 345# There may be some refs packed during bisection. 346 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* | 347whileread ref hash 348do 349 git update-ref -d$ref $hash||exit 350done 351rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&& 352rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&& 353rm-f"$GIT_DIR/BISECT_LOG"&& 354rm-f"$GIT_DIR/BISECT_NAMES"&& 355rm-f"$GIT_DIR/BISECT_RUN"&& 356# Cleanup head-name if it got left by an old version of git-bisect 357rm-f"$GIT_DIR/head-name"&& 358 359rm-f"$GIT_DIR/BISECT_START" 360} 361 362bisect_replay () { 363file="$1" 364test"$#"-eq1|| die "$(gettext "No logfile given")" 365test -r"$file"|| die "$(eval_gettext "cannot read \$file for replaying")" 366 bisect_reset 367whileread git bisect commandrev 368do 369test"$git$bisect"="git bisect"-o"$git"="git-bisect"||continue 370iftest"$git"="git-bisect";then 371rev="$command" 372command="$bisect" 373fi 374case"$command"in 375 start) 376 cmd="bisect_start$rev" 377eval"$cmd";; 378 good|bad|skip) 379 bisect_write "$command""$rev";; 380*) 381 die "$(gettext "?? what are you talking about?")";; 382esac 383done<"$file" 384 bisect_auto_next 385} 386 387bisect_run () { 388 bisect_next_check fail 389 390while true 391do 392command="$@" 393 eval_gettext "running \$command";echo 394"$@" 395 res=$? 396 397# Check for really bad run error. 398if[$res-lt0-o$res-ge128];then 399( 400 eval_gettext "bisect run failed: 401exit code \$resfrom '\$command' is < 0 or >= 128"&& 402echo 403) >&2 404exit$res 405fi 406 407# Find current state depending on run success or failure. 408# A special exit code of 125 means cannot test. 409if[$res-eq125];then 410 state='skip' 411elif[$res-gt0];then 412 state='bad' 413else 414 state='good' 415fi 416 417# We have to use a subshell because "bisect_state" can exit. 418( bisect_state $state>"$GIT_DIR/BISECT_RUN") 419 res=$? 420 421cat"$GIT_DIR/BISECT_RUN" 422 423if sane_grep "first bad commit could be any of""$GIT_DIR/BISECT_RUN" \ 424> /dev/null;then 425( 426gettext"bisect run cannot continue any more"&& 427echo 428) >&2 429exit$res 430fi 431 432if[$res-ne0];then 433( 434 eval_gettext "bisect run failed: 435'bisect_state \$state' exited with error code \$res"&& 436echo 437) >&2 438exit$res 439fi 440 441if sane_grep "is the first bad commit""$GIT_DIR/BISECT_RUN"> /dev/null;then 442gettext"bisect run success";echo 443exit0; 444fi 445 446done 447} 448 449bisect_log () { 450test -s"$GIT_DIR/BISECT_LOG"|| die "$(gettext "We are not bisecting.")" 451cat"$GIT_DIR/BISECT_LOG" 452} 453 454case"$#"in 4550) 456 usage ;; 457*) 458 cmd="$1" 459shift 460case"$cmd"in 461help) 462 git bisect -h;; 463 start) 464 bisect_start "$@";; 465 bad|good) 466 bisect_state "$cmd""$@";; 467 skip) 468 bisect_skip "$@";; 469 next) 470# Not sure we want "next" at the UI level anymore. 471 bisect_next "$@";; 472 visualize|view) 473 bisect_visualize "$@";; 474reset) 475 bisect_reset "$@";; 476 replay) 477 bisect_replay "$@";; 478 log) 479 bisect_log ;; 480 run) 481 bisect_run "$@";; 482*) 483 usage ;; 484esac 485esac