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 seeked 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 320fi 321 322# Check for an error in the bisection process 323test$res-ne0&&exit$res 324 325return0 326} 327 328bisect_visualize() { 329 bisect_next_check fail 330 331iftest$#=0 332then 333iftest -n"${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}"&& 334type gitk >/dev/null 2>&1 335then 336set gitk 337else 338set git log 339fi 340else 341case"$1"in 342 git*|tig) ;; 343-*)set git log "$@";; 344*)set git "$@";; 345esac 346fi 347 348eval'"$@"'--bisect --$(cat "$GIT_DIR/BISECT_NAMES") 349} 350 351bisect_reset() { 352test -s"$GIT_DIR/BISECT_START"|| { 353 gettextln "We are not bisecting." 354return 355} 356case"$#"in 3570) branch=$(cat "$GIT_DIR/BISECT_START");; 3581) git rev-parse --quiet --verify"$1^{commit}"> /dev/null || { 359 invalid="$1" 360 die "$(eval_gettext "'\$invalid' is not a valid commit")" 361} 362 branch="$1";; 363*) 364 usage ;; 365esac 366 367if!test -f"$GIT_DIR/BISECT_HEAD"&& ! git checkout "$branch"-- 368then 369 die "$(eval_gettext "Could not check out original HEAD '\$branch'. 370Try 'git bisect reset <commit>'.")" 371fi 372 bisect_clean_state 373} 374 375bisect_clean_state() { 376# There may be some refs packed during bisection. 377 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* | 378whileread ref hash 379do 380 git update-ref -d$ref $hash||exit 381done 382rm-f"$GIT_DIR/BISECT_EXPECTED_REV"&& 383rm-f"$GIT_DIR/BISECT_ANCESTORS_OK"&& 384rm-f"$GIT_DIR/BISECT_LOG"&& 385rm-f"$GIT_DIR/BISECT_NAMES"&& 386rm-f"$GIT_DIR/BISECT_RUN"&& 387# Cleanup head-name if it got left by an old version of git-bisect 388rm-f"$GIT_DIR/head-name"&& 389 git update-ref -d --no-deref BISECT_HEAD && 390# clean up BISECT_START last 391rm-f"$GIT_DIR/BISECT_START" 392} 393 394bisect_replay () { 395file="$1" 396test"$#"-eq1|| die "$(gettext "No logfile given")" 397test -r"$file"|| die "$(eval_gettext "cannot read \$file for replaying")" 398 bisect_reset 399whileread git bisect commandrev 400do 401test"$git$bisect"="git bisect"-o"$git"="git-bisect"||continue 402iftest"$git"="git-bisect" 403then 404rev="$command" 405command="$bisect" 406fi 407case"$command"in 408 start) 409 cmd="bisect_start$rev" 410eval"$cmd";; 411 good|bad|skip) 412 bisect_write "$command""$rev";; 413*) 414 die "$(gettext "?? what are you talking about?")";; 415esac 416done<"$file" 417 bisect_auto_next 418} 419 420bisect_run () { 421 bisect_next_check fail 422 423while true 424do 425command="$@" 426 eval_gettextln "running \$command" 427"$@" 428 res=$? 429 430# Check for really bad run error. 431if[$res-lt0-o$res-ge128] 432then 433 eval_gettextln "bisect run failed: 434exit code \$resfrom '\$command' is < 0 or >= 128">&2 435exit$res 436fi 437 438# Find current state depending on run success or failure. 439# A special exit code of 125 means cannot test. 440if[$res-eq125] 441then 442 state='skip' 443elif[$res-gt0] 444then 445 state='bad' 446else 447 state='good' 448fi 449 450# We have to use a subshell because "bisect_state" can exit. 451( bisect_state $state>"$GIT_DIR/BISECT_RUN") 452 res=$? 453 454cat"$GIT_DIR/BISECT_RUN" 455 456if sane_grep "first bad commit could be any of""$GIT_DIR/BISECT_RUN" \ 457> /dev/null 458then 459 gettextln "bisect run cannot continue any more">&2 460exit$res 461fi 462 463if[$res-ne0] 464then 465 eval_gettextln "bisect run failed: 466'bisect_state \$state' exited with error code \$res">&2 467exit$res 468fi 469 470if sane_grep "is the first bad commit""$GIT_DIR/BISECT_RUN"> /dev/null 471then 472 gettextln "bisect run success" 473exit0; 474fi 475 476done 477} 478 479bisect_log () { 480test -s"$GIT_DIR/BISECT_LOG"|| die "$(gettext "We are not bisecting.")" 481cat"$GIT_DIR/BISECT_LOG" 482} 483 484case"$#"in 4850) 486 usage ;; 487*) 488 cmd="$1" 489shift 490case"$cmd"in 491help) 492 git bisect -h;; 493 start) 494 bisect_start "$@";; 495 bad|good) 496 bisect_state "$cmd""$@";; 497 skip) 498 bisect_skip "$@";; 499 next) 500# Not sure we want "next" at the UI level anymore. 501 bisect_next "$@";; 502 visualize|view) 503 bisect_visualize "$@";; 504reset) 505 bisect_reset "$@";; 506 replay) 507 bisect_replay "$@";; 508 log) 509 bisect_log ;; 510 run) 511 bisect_run "$@";; 512*) 513 usage ;; 514esac 515esac