diff options
Diffstat (limited to 'git-bisect.sh')
| -rwxr-xr-x | git-bisect.sh | 414 | 
1 files changed, 238 insertions, 176 deletions
diff --git a/git-bisect.sh b/git-bisect.sh index 6e2acb8ef2..99efbe8845 100755 --- a/git-bisect.sh +++ b/git-bisect.sh @@ -2,43 +2,56 @@  USAGE='[help|start|bad|good|skip|next|reset|visualize|replay|log|run]'  LONG_USAGE='git bisect help -        print this long help message. -git bisect start [<bad> [<good>...]] [--] [<pathspec>...] -        reset bisect state and start bisection. +	print this long help message. +git bisect start [--no-checkout] [<bad> [<good>...]] [--] [<pathspec>...] +	reset bisect state and start bisection.  git bisect bad [<rev>] -        mark <rev> a known-bad revision. +	mark <rev> a known-bad revision.  git bisect good [<rev>...] -        mark <rev>... known-good revisions. +	mark <rev>... known-good revisions.  git bisect skip [(<rev>|<range>)...] -        mark <rev>... untestable revisions. +	mark <rev>... untestable revisions.  git bisect next -        find next bisection to test and check it out. +	find next bisection to test and check it out.  git bisect reset [<commit>] -        finish bisection search and go back to commit. +	finish bisection search and go back to commit.  git bisect visualize -        show bisect status in gitk. +	show bisect status in gitk.  git bisect replay <logfile> -        replay bisection log. +	replay bisection log.  git bisect log -        show bisect log. +	show bisect log.  git bisect run <cmd>... -        use <cmd>... to automatically bisect. +	use <cmd>... to automatically bisect.  Please use "git help bisect" to get the full man page.'  OPTIONS_SPEC=  . git-sh-setup -require_work_tree +. git-sh-i18n  _x40='[0-9a-f][0-9a-f][0-9a-f][0-9a-f][0-9a-f]'  _x40="$_x40$_x40$_x40$_x40$_x40$_x40$_x40$_x40" +bisect_head() +{ +	if test -f "$GIT_DIR/BISECT_HEAD" +	then +		echo BISECT_HEAD +	else +		echo HEAD +	fi +} +  bisect_autostart() {  	test -s "$GIT_DIR/BISECT_START" || { -		echo >&2 'You need to start by "git bisect start"' +		gettextln "You need to start by \"git bisect start\"" >&2  		if test -t 0  		then -			echo >&2 -n 'Do you want me to do it for you [Y/n]? ' +			# TRANSLATORS: Make sure to include [Y] and [n] in your +			# translation. The program will only accept English input +			# at this point. +			gettext "Do you want me to do it for you [Y/n]? " >&2  			read yesno  			case "$yesno" in  			[Nn]*) @@ -53,11 +66,55 @@ bisect_autostart() {  bisect_start() {  	# +	# Check for one bad and then some good revisions. +	# +	has_double_dash=0 +	for arg; do +		case "$arg" in --) has_double_dash=1; break ;; esac +	done +	orig_args=$(git rev-parse --sq-quote "$@") +	bad_seen=0 +	eval='' +	if test "z$(git rev-parse --is-bare-repository)" != zfalse +	then +		mode=--no-checkout +	else +		mode='' +	fi +	while [ $# -gt 0 ]; do +		arg="$1" +		case "$arg" in +		--) +			shift +			break +		;; +		--no-checkout) +			mode=--no-checkout +			shift ;; +		--*) +			die "$(eval_gettext "unrecognised option: '\$arg'")" ;; +		*) +			rev=$(git rev-parse -q --verify "$arg^{commit}") || { +				test $has_double_dash -eq 1 && +				die "$(eval_gettext "'\$arg' does not appear to be a valid revision")" +				break +			} +			case $bad_seen in +			0) state='bad' ; bad_seen=1 ;; +			*) state='good' ;; +			esac +			eval="$eval bisect_write '$state' '$rev' 'nolog' &&" +			shift +			;; +		esac +	done + +	#  	# Verify HEAD.  	#  	head=$(GIT_DIR="$GIT_DIR" git symbolic-ref -q HEAD) ||  	head=$(GIT_DIR="$GIT_DIR" git rev-parse --verify HEAD) || -	die "Bad HEAD - I need a HEAD" +	die "$(gettext "Bad HEAD - I need a HEAD")"  	#  	# Check if we are bisecting. @@ -67,7 +124,11 @@ bisect_start() {  	then  		# Reset to the rev from where we started.  		start_head=$(cat "$GIT_DIR/BISECT_START") -		git checkout "$start_head" -- || exit +		if test "z$mode" != "z--no-checkout" +		then +			git checkout "$start_head" -- || +			die "$(eval_gettext "Checking out '\$start_head' failed. Try 'git bisect reset <validbranch>'.")" +		fi  	else  		# Get rev from where we start.  		case "$head" in @@ -76,11 +137,11 @@ bisect_start() {  			# cogito usage, and cogito users should understand  			# it relates to cg-seek.  			[ -s "$GIT_DIR/head-name" ] && -				die "won't bisect on seeked tree" +				die "$(gettext "won't bisect on seeked tree")"  			start_head="${head#refs/heads/}"  			;;  		*) -			die "Bad HEAD - strange symbolic ref" +			die "$(gettext "Bad HEAD - strange symbolic ref")"  			;;  		esac  	fi @@ -91,39 +152,6 @@ bisect_start() {  	bisect_clean_state || exit  	# -	# Check for one bad and then some good revisions. -	# -	has_double_dash=0 -	for arg; do -	    case "$arg" in --) has_double_dash=1; break ;; esac -	done -	orig_args=$(git rev-parse --sq-quote "$@") -	bad_seen=0 -	eval='' -	while [ $# -gt 0 ]; do -	    arg="$1" -	    case "$arg" in -	    --) -		shift -		break -		;; -	    *) -		rev=$(git rev-parse -q --verify "$arg^{commit}") || { -		    test $has_double_dash -eq 1 && -		        die "'$arg' does not appear to be a valid revision" -		    break -		} -		case $bad_seen in -		0) state='bad' ; bad_seen=1 ;; -		*) state='good' ;; -		esac -		eval="$eval bisect_write '$state' '$rev' 'nolog'; " -		shift -		;; -	    esac -	done - -	#  	# Change state.  	# In case of mistaken revs or checkout error, or signals received,  	# "bisect_auto_next" below may exit or misbehave. @@ -136,9 +164,12 @@ bisect_start() {  	#  	# Write new start state.  	# -	echo "$start_head" >"$GIT_DIR/BISECT_START" && +	echo "$start_head" >"$GIT_DIR/BISECT_START" && { +		test "z$mode" != "z--no-checkout" || +		git update-ref --no-deref BISECT_HEAD "$start_head" +	} &&  	git rev-parse --sq-quote "$@" >"$GIT_DIR/BISECT_NAMES" && -	eval "$eval" && +	eval "$eval true" &&  	echo "git bisect start$orig_args" >>"$GIT_DIR/BISECT_LOG" || exit  	#  	# Check if we can proceed to the next bisect state. @@ -155,7 +186,7 @@ bisect_write() {  	case "$state" in  		bad)		tag="$state" ;;  		good|skip)	tag="$state"-"$rev" ;; -		*)		die "Bad bisect_write argument: $state" ;; +		*)		die "$(eval_gettext "Bad bisect_write argument: \$state")" ;;  	esac  	git update-ref "refs/bisect/$tag" "$rev" || exit  	echo "# $state: $(git show-branch $rev)" >>"$GIT_DIR/BISECT_LOG" @@ -169,7 +200,8 @@ is_expected_rev() {  check_expected_revs() {  	for _rev in "$@"; do -		if ! is_expected_rev "$_rev"; then +		if ! is_expected_rev "$_rev" +		then  			rm -f "$GIT_DIR/BISECT_ANCESTORS_OK"  			rm -f "$GIT_DIR/BISECT_EXPECTED_REV"  			return @@ -178,18 +210,18 @@ check_expected_revs() {  }  bisect_skip() { -        all='' +	all=''  	for arg in "$@"  	do -	    case "$arg" in -            *..*) -                revs=$(git rev-list "$arg") || die "Bad rev input: $arg" ;; -            *) -                revs=$(git rev-parse --sq-quote "$arg") ;; -	    esac -            all="$all $revs" -        done -        eval bisect_state 'skip' $all +		case "$arg" in +		*..*) +			revs=$(git rev-list "$arg") || die "$(eval_gettext "Bad rev input: \$arg")" ;; +		*) +			revs=$(git rev-parse --sq-quote "$arg") ;; +		esac +		all="$all $revs" +	done +	eval bisect_state 'skip' $all  }  bisect_state() { @@ -197,10 +229,10 @@ bisect_state() {  	state=$1  	case "$#,$state" in  	0,*) -		die "Please call 'bisect_state' with at least one argument." ;; +		die "$(gettext "Please call 'bisect_state' with at least one argument.")" ;;  	1,bad|1,good|1,skip) -		rev=$(git rev-parse --verify HEAD) || -			die "Bad rev input: HEAD" +		rev=$(git rev-parse --verify $(bisect_head)) || +			die "$(gettext "Bad rev input: $(bisect_head)")"  		bisect_write "$state" "$rev"  		check_expected_revs "$rev" ;;  	2,bad|*,good|*,skip) @@ -209,13 +241,13 @@ bisect_state() {  		for rev in "$@"  		do  			sha=$(git rev-parse --verify "$rev^{commit}") || -				die "Bad rev input: $rev" +				die "$(eval_gettext "Bad rev input: \$rev")"  			eval="$eval bisect_write '$state' '$sha'; "  		done  		eval "$eval"  		check_expected_revs "$@" ;;  	*,bad) -		die "'git bisect bad' can take only one argument." ;; +		die "$(gettext "'git bisect bad' can take only one argument.")" ;;  	*)  		usage ;;  	esac @@ -238,25 +270,29 @@ bisect_next_check() {  	t,,good)  		# have bad but not good.  we could bisect although  		# this is less optimum. -		echo >&2 'Warning: bisecting only with a bad commit.' +		gettextln "Warning: bisecting only with a bad commit." >&2  		if test -t 0  		then -			printf >&2 'Are you sure [Y/n]? ' +			# TRANSLATORS: Make sure to include [Y] and [n] in your +			# translation. The program will only accept English input +			# at this point. +			gettext "Are you sure [Y/n]? " >&2  			read yesno  			case "$yesno" in [Nn]*) exit 1 ;; esac  		fi  		: bisect without good...  		;;  	*) -		THEN='' -		test -s "$GIT_DIR/BISECT_START" || { -			echo >&2 'You need to start by "git bisect start".' -			THEN='then ' -		} -		echo >&2 'You '$THEN'need to give me at least one good' \ -			'and one bad revisions.' -		echo >&2 '(You can use "git bisect bad" and' \ -			'"git bisect good" for that.)' + +		if test -s "$GIT_DIR/BISECT_START" +		then +			gettextln "You need to give me at least one good and one bad revisions. +(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2 +		else +			gettextln "You need to start by \"git bisect start\". +You then need to give me at least one good and one bad revisions. +(You can use \"git bisect bad\" and \"git bisect good\" for that.)" >&2 +		fi  		exit 1 ;;  	esac  } @@ -271,10 +307,10 @@ bisect_next() {  	bisect_next_check good  	# Perform all bisection computation, display and checkout -	git bisect--helper --next-all +	git bisect--helper --next-all $(test -f "$GIT_DIR/BISECT_HEAD" && echo --no-checkout)  	res=$? -        # Check if we should exit because bisection is finished +	# Check if we should exit because bisection is finished  	test $res -eq 10 && exit 0  	# Check for an error in the bisection process @@ -288,10 +324,13 @@ bisect_visualize() {  	if test $# = 0  	then -		case "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" in -		'')	set git log ;; -		set*)	set gitk ;; -		esac +		if test -n "${DISPLAY+set}${SESSIONNAME+set}${MSYSTEM+set}${SECURITYSESSIONID+set}" && +			type gitk >/dev/null 2>&1 +		then +			set gitk +		else +			set git log +		fi  	else  		case "$1" in  		git*|tig) ;; @@ -305,18 +344,26 @@ bisect_visualize() {  bisect_reset() {  	test -s "$GIT_DIR/BISECT_START" || { -		echo "We are not bisecting." +		gettextln "We are not bisecting."  		return  	}  	case "$#" in  	0) branch=$(cat "$GIT_DIR/BISECT_START") ;; -	1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null || -	       die "'$1' is not a valid commit" -	   branch="$1" ;; +	1) git rev-parse --quiet --verify "$1^{commit}" > /dev/null || { +			invalid="$1" +			die "$(eval_gettext "'\$invalid' is not a valid commit")" +		} +		branch="$1" ;;  	*) -	    usage ;; +		usage ;;  	esac -	git checkout "$branch" -- && bisect_clean_state + +	if ! test -f "$GIT_DIR/BISECT_HEAD" && ! git checkout "$branch" -- +	then +		die "$(eval_gettext "Could not check out original HEAD '\$branch'. +Try 'git bisect reset <commit>'.")" +	fi +	bisect_clean_state  }  bisect_clean_state() { @@ -333,17 +380,21 @@ bisect_clean_state() {  	rm -f "$GIT_DIR/BISECT_RUN" &&  	# Cleanup head-name if it got left by an old version of git-bisect  	rm -f "$GIT_DIR/head-name" && - +	git update-ref -d --no-deref BISECT_HEAD && +	# clean up BISECT_START last  	rm -f "$GIT_DIR/BISECT_START"  }  bisect_replay () { -	test -r "$1" || die "cannot read $1 for replaying" +	file="$1" +	test "$#" -eq 1 || die "$(gettext "No logfile given")" +	test -r "$file" || die "$(eval_gettext "cannot read \$file for replaying")"  	bisect_reset  	while read git bisect command rev  	do  		test "$git $bisect" = "git bisect" -o "$git" = "git-bisect" || continue -		if test "$git" = "git-bisect"; then +		if test "$git" = "git-bisect" +		then  			rev="$command"  			command="$bisect"  		fi @@ -354,94 +405,105 @@ bisect_replay () {  		good|bad|skip)  			bisect_write "$command" "$rev" ;;  		*) -			die "?? what are you talking about?" ;; +			die "$(gettext "?? what are you talking about?")" ;;  		esac -	done <"$1" +	done <"$file"  	bisect_auto_next  }  bisect_run () { -    bisect_next_check fail - -    while true -    do -      echo "running $@" -      "$@" -      res=$? - -      # Check for really bad run error. -      if [ $res -lt 0 -o $res -ge 128 ]; then -	  echo >&2 "bisect run failed:" -	  echo >&2 "exit code $res from '$@' is < 0 or >= 128" -	  exit $res -      fi - -      # Find current state depending on run success or failure. -      # A special exit code of 125 means cannot test. -      if [ $res -eq 125 ]; then -	  state='skip' -      elif [ $res -gt 0 ]; then -	  state='bad' -      else -	  state='good' -      fi - -      # We have to use a subshell because "bisect_state" can exit. -      ( bisect_state $state > "$GIT_DIR/BISECT_RUN" ) -      res=$? - -      cat "$GIT_DIR/BISECT_RUN" - -      if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \ -		> /dev/null; then -	  echo >&2 "bisect run cannot continue any more" -	  exit $res -      fi - -      if [ $res -ne 0 ]; then -	  echo >&2 "bisect run failed:" -	  echo >&2 "'bisect_state $state' exited with error code $res" -	  exit $res -      fi - -      if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null; then -	  echo "bisect run success" -	  exit 0; -      fi - -    done +	bisect_next_check fail + +	while true +	do +		command="$@" +		eval_gettextln "running \$command" +		"$@" +		res=$? + +		# Check for really bad run error. +		if [ $res -lt 0 -o $res -ge 128 ] +		then +			eval_gettextln "bisect run failed: +exit code \$res from '\$command' is < 0 or >= 128" >&2 +			exit $res +		fi + +		# Find current state depending on run success or failure. +		# A special exit code of 125 means cannot test. +		if [ $res -eq 125 ] +		then +			state='skip' +		elif [ $res -gt 0 ] +		then +			state='bad' +		else +			state='good' +		fi + +		# We have to use a subshell because "bisect_state" can exit. +		( bisect_state $state > "$GIT_DIR/BISECT_RUN" ) +		res=$? + +		cat "$GIT_DIR/BISECT_RUN" + +		if sane_grep "first bad commit could be any of" "$GIT_DIR/BISECT_RUN" \ +			> /dev/null +		then +			gettextln "bisect run cannot continue any more" >&2 +			exit $res +		fi + +		if [ $res -ne 0 ] +		then +			eval_gettextln "bisect run failed: +'bisect_state \$state' exited with error code \$res" >&2 +			exit $res +		fi + +		if sane_grep "is the first bad commit" "$GIT_DIR/BISECT_RUN" > /dev/null +		then +			gettextln "bisect run success" +			exit 0; +		fi + +	done  } +bisect_log () { +	test -s "$GIT_DIR/BISECT_LOG" || die "$(gettext "We are not bisecting.")" +	cat "$GIT_DIR/BISECT_LOG" +}  case "$#" in  0) -    usage ;; +	usage ;;  *) -    cmd="$1" -    shift -    case "$cmd" in -    help) -        git bisect -h ;; -    start) -        bisect_start "$@" ;; -    bad|good) -        bisect_state "$cmd" "$@" ;; -    skip) -        bisect_skip "$@" ;; -    next) -        # Not sure we want "next" at the UI level anymore. -        bisect_next "$@" ;; -    visualize|view) -	bisect_visualize "$@" ;; -    reset) -        bisect_reset "$@" ;; -    replay) -	bisect_replay "$@" ;; -    log) -	cat "$GIT_DIR/BISECT_LOG" ;; -    run) -        bisect_run "$@" ;; -    *) -        usage ;; -    esac +	cmd="$1" +	shift +	case "$cmd" in +	help) +		git bisect -h ;; +	start) +		bisect_start "$@" ;; +	bad|good) +		bisect_state "$cmd" "$@" ;; +	skip) +		bisect_skip "$@" ;; +	next) +		# Not sure we want "next" at the UI level anymore. +		bisect_next "$@" ;; +	visualize|view) +		bisect_visualize "$@" ;; +	reset) +		bisect_reset "$@" ;; +	replay) +		bisect_replay "$@" ;; +	log) +		bisect_log ;; +	run) +		bisect_run "$@" ;; +	*) +		usage ;; +	esac  esac  | 
