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"-- 130fi 131else 132# Get rev from where we start. 133case"$head"in 134 refs/heads/*|$_x40) 135# This error message should only be triggered by 136# cogito usage, and cogito users should understand 137# it relates to cg-seek. 138[-s"$GIT_DIR/head-name"] && 139 die "$(gettext "won't bisect on seeked tree")" 140 start_head="${head#refs/heads/}" 141;; 142*) 143 die "$(gettext "Bad HEAD - strange symbolic ref")" 144;; 145esac 146fi 147 148# 149# Get rid of any old bisect state. 150# 151 bisect_clean_state ||exit 152 153# 154# Change state. 155# In case of mistaken revs or checkout error, or signals received, 156# "bisect_auto_next" below may exit or misbehave. 157# We have to trap this to be able to clean up using 158# "bisect_clean_state". 159# 160trap'bisect_clean_state'0 161trap'exit 255'1 2 3 15 162 163# 164# Write new start state. 165# 166echo"$start_head">"$GIT_DIR/BISECT_START"&& { 167test"z$mode"!="z--no-checkout"|| 168 git update-ref --no-deref BISECT_HEAD "$start_head" 169} && 170 git rev-parse --sq-quote"$@">"$GIT_DIR/BISECT_NAMES"&& 171eval"$evaltrue"&& 172echo"git bisect start$orig_args">>"$GIT_DIR/BISECT_LOG"||exit 173# 174# Check if we can proceed to the next bisect state. 175# 176 bisect_auto_next 177 178trap'-'0 179} 180 181bisect_write() { 182 state="$1" 183rev="$2" 184 nolog="$3" 185case"$state"in 186 bad) tag="$state";; 187 good|skip) tag="$state"-"$rev";; 188*) die "$(eval_gettext "Bad bisect_write argument: \$state")";; 189esac 190 git update-ref"refs/bisect/$tag""$rev"||exit 191echo"#$state:$(git show-branch $rev)">>"$GIT_DIR/BISECT_LOG" 192test -n"$nolog"||echo"git bisect$state$rev">>"$GIT_DIR/BISECT_LOG" 193} 194 195is_expected_rev() { 196test -f"$GIT_DIR/BISECT_EXPECTED_REV"&& 197test"$1"=$(cat "$GIT_DIR/BISECT_EXPECTED_REV") 198} 199 200check_expected_revs() { 201for _rev in"$@";do 202if! is_expected_rev "$_rev" 203then 204rm-f"$GIT_DIR/BISECT_ANCESTORS_OK" 205rm-f"$GIT_DIR/BISECT_EXPECTED_REV" 206return 207fi 208done 209} 210 211bisect_skip() { 212 all='' 213for arg in"$@" 214do 215case"$arg"in 216*..*) 217 revs=$(git rev-list "$arg")|| die "$(eval_gettext "Bad rev input: \$arg")";; 218*) 219 revs=$(git rev-parse --sq-quote "$arg");; 220esac 221 all="$all$revs" 222done 223eval bisect_state 'skip'$all 224} 225 226bisect_state() { 227 bisect_autostart 228 state=$1 229case"$#,$state"in 2300,*) 231 die "$(gettext "Please call 'bisect_state' with at least one argument.")";; 2321,bad|1,good|1,skip) 233rev=$(git rev-parse --verify $(bisect_head)) || 234 die "$(gettext "Bad rev input: $(bisect_head)")" 235 bisect_write "$state" "$rev" 236 check_expected_revs "$rev" ;; 237 2,bad|*,good|*,skip) 238 shift 239 eval='' 240 for rev in "$@" 241 do 242 sha=$(git rev-parse --verify "$rev^{commit}")|| 243 die "$(eval_gettext "Bad rev input: \$rev")" 244 eval="$eval bisect_write '$state''$sha';" 245 done 246 eval "$eval" 247 check_expected_revs "$@" ;; 248 *,bad) 249 die "$(gettext "'git bisect bad' can take only one argument.")" ;; 250 *) 251 usage ;; 252 esac 253 bisect_auto_next 254} 255 256bisect_next_check() { 257 missing_good= missing_bad= 258 git show-ref -q --verify refs/bisect/bad || missing_bad=t 259 test -n "$(git for-each-ref "refs/bisect/good-*")" || missing_good=t 260 261 case "$missing_good,$missing_bad,$1" in 262 ,,*) 263 : have both good and bad - ok 264 ;; 265 *,) 266 # do not have both but not asked to fail - just report. 267 false 268 ;; 269 t,,good) 270 # have bad but not good. we could bisect although 271 # this is less optimum. 272 gettextln "Warning: bisecting only with a bad commit." >&2 273 if test -t 0 274 then 275 # TRANSLATORS: Make sure to include [Y] and [n] in your 276 # translation. The program will only accept English input 277 # at this point. 278 gettext "Are you sure [Y/n]? " >&2 279 read yesno 280 case "$yesno" in [Nn]*) exit 1 ;; esac 281 fi 282 : bisect without good... 283 ;; 284 *) 285 286 if test -s "$GIT_DIR/BISECT_START" 287 then 288 gettextln "You need to give me at least one good and one bad revisions. 289(You can use \"git bisect bad\" and \"git bisect good\"for that.)" >&2 290 else 291 gettextln "You need to start by \"git bisect start\". 292You then need to give me at least one good and one bad revisions. 293(You can use \"git bisect bad\" and \"git bisect good\"for that.)" >&2 294 fi 295 exit 1 ;; 296 esac 297} 298 299bisect_auto_next() { 300 bisect_next_check && bisect_next || : 301} 302 303bisect_next() { 304 case "$#" in 0) ;; *) usage ;; esac 305 bisect_autostart 306 bisect_next_check good 307 308 # Perform all bisection computation, display and checkout 309 git bisect--helper --next-all$(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout) 310 res=$? 311 312 # Check if we should exit because bisection is finished 313 test$res-eq 10 && exit 0 314 315 # Check for an error in the bisection process 316 test$res-ne 0 && exit$res 317 318 return 0 319} 320 321bisect_visualize() { 322 bisect_next_check fail 323 324 if test$#= 0 325 then 326 if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" && 327 type gitk >/dev/null 2>&1 328 then 329 set gitk 330 else 331 set git log 332 fi 333 else 334 case "$1" in 335 git*|tig) ;; 336 -*) set git log "$@" ;; 337 *) set git "$@" ;; 338 esac 339 fi 340 341 eval '"$@"' --bisect --$(cat "$GIT_DIR/BISECT_NAMES") 342} 343 344bisect_reset() { 345 test -s "$GIT_DIR/BISECT_START" || { 346 gettextln "We are not bisecting." 347 return 348 } 349 case "$#" in 350 0) branch=$(cat "$GIT_DIR/BISECT_START");; 351 1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null || { 352 invalid="$1" 353 die "$(eval_gettext "'\$invalid' is not a valid commit")" 354 } 355 branch="$1" ;; 356 *) 357 usage ;; 358 esac 359 360 if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" -- 361 then 362 die "$(eval_gettext "Could not check out original HEAD '\$branch'. 363Try 'git bisect reset <commit>'.")" 364 fi 365 bisect_clean_state 366} 367 368bisect_clean_state() { 369 # There may be some refs packed during bisection. 370 git for-each-ref --format='%(refname) %(objectname)' refs/bisect/\* | 371 while read ref hash 372 do 373 git update-ref -d$ref$hash|| exit 374 done 375 rm -f "$GIT_DIR/BISECT_EXPECTED_REV" && 376 rm -f "$GIT_DIR/BISECT_ANCESTORS_OK" && 377 rm -f "$GIT_DIR/BISECT_LOG" && 378 rm -f "$GIT_DIR/BISECT_NAMES" && 379 rm -f "$GIT_DIR/BISECT_RUN" && 380 # Cleanup head-name if it got left by an old version of git-bisect 381 rm -f "$GIT_DIR/head-name" && 382 git update-ref -d --no-deref BISECT_HEAD && 383 # clean up BISECT_START last 384 rm -f "$GIT_DIR/BISECT_START" 385} 386 387bisect_replay () { 388 file="$1" 389 test "$#" -eq 1 || die "$(gettext "No logfile given")" 390 test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")" 391 bisect_reset 392 while read git bisect command rev 393 do 394 test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue 395 if test "$git" = "git-bisect" 396 then 397 rev="$command" 398 command="$bisect" 399 fi 400 case "$command" in 401 start) 402 cmd="bisect_start $rev" 403 eval "$cmd" ;; 404 good|bad|skip) 405 bisect_write "$command" "$rev" ;; 406 *) 407 die "$(gettext "?? what are you talking about?")" ;; 408 esac 409 done <"$file" 410 bisect_auto_next 411} 412 413bisect_run () { 414 bisect_next_check fail 415 416 while true 417 do 418 command="$@" 419 eval_gettextln "running \$command" 420 "$@" 421 res=$? 422 423 # Check for really bad run error. 424 if [$res-lt 0 -o$res-ge 128 ] 425 then 426 eval_gettextln "bisect run failed: 427exit code \$res from '\$command' is <0 or >=128" >&2 428 exit$res 429 fi 430 431 # Find current state depending on run success or failure. 432 # A special exit code of 125 means cannot test. 433 if [$res-eq 125 ] 434 then 435 state='skip' 436 elif [$res-gt 0 ] 437 then 438 state='bad' 439 else 440 state='good' 441 fi 442 443 # We have to use a subshell because "bisect_state" can exit. 444 ( bisect_state$state> "$GIT_DIR/BISECT_RUN" ) 445 res=$? 446 447 cat "$GIT_DIR/BISECT_RUN" 448 449 if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \ 450 > /dev/null 451 then 452 gettextln "bisect run cannot continue any more" >&2 453 exit$res 454 fi 455 456 if [$res-ne 0 ] 457 then 458 eval_gettextln "bisect run failed: 459'bisect_state \$state' exited with error code \$res" >&2 460 exit$res 461 fi 462 463 if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null 464 then 465 gettextln "bisect run success" 466 exit 0; 467 fi 468 469 done 470} 471 472bisect_log () { 473 test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")" 474 cat "$GIT_DIR/BISECT_LOG" 475} 476 477case "$#" in 4780) 479 usage ;; 480*) 481 cmd="$1" 482 shift 483 case "$cmd" in 484 help) 485 git bisect -h ;; 486 start) 487 bisect_start "$@" ;; 488 bad|good) 489 bisect_state "$cmd" "$@" ;; 490 skip) 491 bisect_skip "$@" ;; 492 next) 493 # Not sure we want "next" at the UI level anymore. 494 bisect_next "$@" ;; 495 visualize|view) 496 bisect_visualize "$@" ;; 497 reset) 498 bisect_reset "$@" ;; 499 replay) 500 bisect_replay "$@" ;; 501 log) 502 bisect_log ;; 503 run) 504 bisect_run "$@" ;; 505 *) 506 usage ;; 507 esac 508esac