[PATCH 0/3] Fix support for FreeBSD's /bin/sh

DORMANTno replies

4 messages, 1 author, 2016-06-15 · open the first message on its own page

[PATCH 0/3] Fix support for FreeBSD's /bin/sh

From: Kyle J. McKay <hidden>
Date: 2016-06-15 23:00:40

This patch series words around the FreeBSD /bin/sh problems that cause rebase
to fail on FreeBSD as well as test t5560-http-backend-noserver.

The rebase issue was first introduced in Git v1.8.4 which started using the
"return" statement to return from a "dot" command script where the "dot"
command itself was located inside a function.  This behaves badly when using
FreeBSD's /bin/sh.  An attempt was made to fix this in Git v1.8.4.1, but it
only addressed part of the problem.

Patch 1/3 fixes the problem by eliminating such use of "return", patch 2/3
then reverts the earlier workaround since it is no longer needed and did
not fully solve the problem.

The t5560 issue was first introduced in Git v1.7.0 which started using a
backslash escapes in ${...} expansions.  The FreeBSD /bin/sh does not
properly support such escapes, but there is a simple change that works
everywhere (using [?] instead of \?).

There are more details in the individual patches.

This patch series is based on maint since these are bug fixes and that's
what SubmittingPatches says to do...

Kyle J. McKay (3):
  rebase: avoid non-function use of "return" on FreeBSD
  Revert "rebase: fix run_specific_rebase's use of "return" on FreeBSD"
  test: fix t5560 on FreeBSD

 git-rebase--am.sh                | 131 +++++++--------
 git-rebase--interactive.sh       | 341 ++++++++++++++++++++-------------------
 git-rebase--merge.sh             |  87 +++++-----
 git-rebase.sh                    |  11 +-
 t/t5560-http-backend-noserver.sh |   4 +-
 5 files changed, 287 insertions(+), 287 deletions(-)

The above stat may seem like a lot, but when using diff -w --stat you get this:

 git-rebase--am.sh                |  3 +++
 git-rebase--interactive.sh       |  3 +++
 git-rebase--merge.sh             |  3 +++
 git-rebase.sh                    | 11 +----------
 t/t5560-http-backend-noserver.sh |  4 ++--
 5 files changed, 12 insertions(+), 12 deletions(-)

which more accurately reflects what was actually touched.

[PATCH 1/3] rebase: avoid non-function use of "return" on FreeBSD

From: Kyle J. McKay <hidden>
Date: 2016-06-15 23:00:40

Since a1549e10, 15d4bf2e and 01a1e646 (first appearing in v1.8.4) the
git-rebase--*.sh scripts have used a "return" to return from the "dot"
command that runs them.  While this is allowed by POSIX, the FreeBSD
/bin/sh utility behaves poorly under some circumstances when such a
"return" is executed.

In particular, if the "dot" command is contained within a function,
then when a "return" is executed by the script it runs (that is not
itself inside a function), control will return from the function
that contains the "dot" command skipping any statements that might
follow the dot command inside that function.  Commit 99855ddf (first
appearing in v1.8.4.1) addresses this by making the "dot" command
the last line in the function.  Unfortunately the FreeBSD /bin/sh
may also execute some statements in the script run by the "dot"
command that appear after the troublesome "return".  The fix in
99855ddf does not address this problem.

For example, if you have script1.sh with these contents:

#!/bin/sh
# script1.sh
run_script2() {
        . "$(dirname -- "$0")/script2.sh"
        _e=$?
        echo only this line should show
        [ $_e -eq 5 ] || echo expected status 5 got $_e
        return 3
}
run_script2
e=$?
[ $e -eq 3 ] || { echo expected status 3 got $e; exit 1; }

And script2.sh with these contents:

# script2.sh
if [ 5 -gt 3 ]; then
        return 5
fi
case bad in *)
        echo always shows
esac
echo should not get here
! :

When running script1.sh (e.g. '/bin/sh script1.sh' or './script1.sh'
after making it executable), the expected output from a POSIX shell
is simply the single line:

only this line should show

However, when run using FreeBSD's /bin/sh, the following output
appears instead:

should not get here
expected status 3 got 1

Not only did the lines following the "dot" command in the run_script2
function in script1.sh get skipped, but additional lines in script2.sh
following the "return" got executed -- but not all of them (e.g. the
"echo always shows" line did not run).

These issues can be avoided by not using a top-level "return" in
script2.sh.  If script2.sh is changed to this:

# script2.sh fixed
main() {
        if [ 5 -gt 3 ]; then
                return 5
        fi
        case bad in *)
                echo always shows
        esac
        echo should not get here
        ! :
}
main

Then it behaves the same when using FreeBSD's /bin/sh as when using
other more POSIX compliant /bin/sh implementations.

We fix the git-rebase--*.sh scripts in a similar fashion by moving
the top-level code that contains "return" statements into its own
function and then calling that as the last line in the script.

The changes introduced by this commit are best viewed with the
--ignore-all-space (-w) diff option.

Signed-off-by: Kyle J. McKay <redacted>

---
 git-rebase--am.sh          | 117 ++++++++--------
 git-rebase--interactive.sh | 335 +++++++++++++++++++++++----------------------
 git-rebase--merge.sh       |  87 ++++++------
 3 files changed, 274 insertions(+), 265 deletions(-)


For convenience, here are the diffs using -w:

|--- a/git-rebase--am.sh
|+++ b/git-rebase--am.sh
|@@ -4,6 +4,7 @@
 # Copyright (c) 2010 Junio C Hamano.
 #
 
+git_rebase__am() {
 	case "$action" in
 	continue)
 		git am --resolved --resolvemsg="$resolvemsg" &&
|@@ -73,3 +74,5 @@ then
 	fi
 
 	move_to_original_branch
+}
+git_rebase__am

|--- a/git-rebase--interactive.sh
|+++ b/git-rebase--interactive.sh
|@@ -810,6 +810,7 @@ add_exec_commands () {
 	mv "$1.new" "$1"
 }
 
+git_rebase__interactive() {
 	case "$action" in
 	continue)
 		# do we have anything to commit?
|@@ -1042,3 +1043,5 @@ GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
 	output git checkout $onto || die_abort "could not detach HEAD"
 	git update-ref ORIG_HEAD $orig_head
 	do_rest
+}
+git_rebase__interactive

|--- a/git-rebase--merge.sh
|+++ b/git-rebase--merge.sh
|@@ -101,6 +101,7 @@ finish_rb_merge () {
 	say All done.
 }
 
+git_rebase__merge() {
 	case "$action" in
 	continue)
 		read_state
|@@ -151,3 +152,5 @@ do
 	done
 
 	finish_rb_merge
+}
+git_rebase__merge

diff --git a/git-rebase--am.sh b/git-rebase--am.sh
index a4f683a5..2d3f6d55 100644
--- a/git-rebase--am.sh
+++ b/git-rebase--am.sh
@@ -4,72 +4,75 @@
 # Copyright (c) 2010 Junio C Hamano.
 #
 
-case "$action" in
-continue)
-	git am --resolved --resolvemsg="$resolvemsg" &&
-	move_to_original_branch
-	return
-	;;
-skip)
-	git am --skip --resolvemsg="$resolvemsg" &&
-	move_to_original_branch
-	return
-	;;
-esac
-
-test -n "$rebase_root" && root_flag=--root
-
-ret=0
-if test -n "$keep_empty"
-then
-	# we have to do this the hard way.  git format-patch completely squashes
-	# empty commits and even if it didn't the format doesn't really lend
-	# itself well to recording empty patches.  fortunately, cherry-pick
-	# makes this easy
-	git cherry-pick --allow-empty "$revisions"
-	ret=$?
-else
-	rm -f "$GIT_DIR/rebased-patches"
+git_rebase__am() {
+	case "$action" in
+	continue)
+		git am --resolved --resolvemsg="$resolvemsg" &&
+		move_to_original_branch
+		return
+		;;
+	skip)
+		git am --skip --resolvemsg="$resolvemsg" &&
+		move_to_original_branch
+		return
+		;;
+	esac
 
-	git format-patch -k --stdout --full-index --ignore-if-in-upstream \
-		--src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
-		$root_flag "$revisions" >"$GIT_DIR/rebased-patches"
-	ret=$?
+	test -n "$rebase_root" && root_flag=--root
 
-	if test 0 != $ret
+	ret=0
+	if test -n "$keep_empty"
 	then
+		# we have to do this the hard way.  git format-patch completely squashes
+		# empty commits and even if it didn't the format doesn't really lend
+		# itself well to recording empty patches.  fortunately, cherry-pick
+		# makes this easy
+		git cherry-pick --allow-empty "$revisions"
+		ret=$?
+	else
 		rm -f "$GIT_DIR/rebased-patches"
-		case "$head_name" in
-		refs/heads/*)
-			git checkout -q "$head_name"
-			;;
-		*)
-			git checkout -q "$orig_head"
-			;;
-		esac
 
-		cat >&2 <<-EOF
+		git format-patch -k --stdout --full-index --ignore-if-in-upstream \
+			--src-prefix=a/ --dst-prefix=b/ --no-renames --no-cover-letter \
+			$root_flag "$revisions" >"$GIT_DIR/rebased-patches"
+		ret=$?
 
-		git encountered an error while preparing the patches to replay
-		these revisions:
+		if test 0 != $ret
+		then
+			rm -f "$GIT_DIR/rebased-patches"
+			case "$head_name" in
+			refs/heads/*)
+				git checkout -q "$head_name"
+				;;
+			*)
+				git checkout -q "$orig_head"
+				;;
+			esac
 
-		    $revisions
+			cat >&2 <<-EOF
 
-		As a result, git cannot rebase them.
-		EOF
-		return $?
-	fi
+			git encountered an error while preparing the patches to replay
+			these revisions:
+
+			    $revisions
 
-	git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" <"$GIT_DIR/rebased-patches"
-	ret=$?
+			As a result, git cannot rebase them.
+			EOF
+			return $?
+		fi
 
-	rm -f "$GIT_DIR/rebased-patches"
-fi
+		git am $git_am_opt --rebasing --resolvemsg="$resolvemsg" <"$GIT_DIR/rebased-patches"
+		ret=$?
 
-if test 0 != $ret
-then
-	test -d "$state_dir" && write_basic_state
-	return $ret
-fi
+		rm -f "$GIT_DIR/rebased-patches"
+	fi
 
-move_to_original_branch
+	if test 0 != $ret
+	then
+		test -d "$state_dir" && write_basic_state
+		return $ret
+	fi
+
+	move_to_original_branch
+}
+git_rebase__am
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 43631b47..42164f11 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -810,16 +810,17 @@ add_exec_commands () {
 	mv "$1.new" "$1"
 }
 
-case "$action" in
-continue)
-	# do we have anything to commit?
-	if git diff-index --cached --quiet HEAD --
-	then
-		: Nothing to commit -- skip this
-	else
-		if ! test -f "$author_script"
+git_rebase__interactive() {
+	case "$action" in
+	continue)
+		# do we have anything to commit?
+		if git diff-index --cached --quiet HEAD --
 		then
-			die "You have staged changes in your working tree. If these changes are meant to be
+			: Nothing to commit -- skip this
+		else
+			if ! test -f "$author_script"
+			then
+				die "You have staged changes in your working tree. If these changes are meant to be
 squashed into the previous commit, run:
 
   git commit --amend
@@ -832,42 +833,42 @@ In both case, once you're done, continue with:
 
   git rebase --continue
 "
-		fi
-		. "$author_script" ||
-			die "Error trying to find the author identity to amend commit"
-		if test -f "$amend"
-		then
-			current_head=$(git rev-parse --verify HEAD)
-			test "$current_head" = $(cat "$amend") ||
-			die "\
+			fi
+			. "$author_script" ||
+				die "Error trying to find the author identity to amend commit"
+			if test -f "$amend"
+			then
+				current_head=$(git rev-parse --verify HEAD)
+				test "$current_head" = $(cat "$amend") ||
+				die "\
 You have uncommitted changes in your working tree. Please, commit them
 first and then run 'git rebase --continue' again."
-			do_with_author git commit --amend --no-verify -F "$msg" -e ||
-				die "Could not commit staged changes."
-		else
-			do_with_author git commit --no-verify -F "$msg" -e ||
-				die "Could not commit staged changes."
+				do_with_author git commit --amend --no-verify -F "$msg" -e ||
+					die "Could not commit staged changes."
+			else
+				do_with_author git commit --no-verify -F "$msg" -e ||
+					die "Could not commit staged changes."
+			fi
 		fi
-	fi
 
-	record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
+		record_in_rewritten "$(cat "$state_dir"/stopped-sha)"
 
-	require_clean_work_tree "rebase"
-	do_rest
-	return 0
-	;;
-skip)
-	git rerere clear
+		require_clean_work_tree "rebase"
+		do_rest
+		return 0
+		;;
+	skip)
+		git rerere clear
 
-	do_rest
-	return 0
-	;;
-edit-todo)
-	git stripspace --strip-comments <"$todo" >"$todo".new
-	mv -f "$todo".new "$todo"
-	collapse_todo_ids
-	append_todo_help
-	git stripspace --comment-lines >>"$todo" <<\EOF
+		do_rest
+		return 0
+		;;
+	edit-todo)
+		git stripspace --strip-comments <"$todo" >"$todo".new
+		mv -f "$todo".new "$todo"
+		collapse_todo_ids
+		append_todo_help
+		git stripspace --comment-lines >>"$todo" <<\EOF
 
 You are editing the todo file of an ongoing interactive rebase.
 To continue rebase after editing, run:
@@ -875,170 +876,172 @@ To continue rebase after editing, run:
 
 EOF
 
-	git_sequence_editor "$todo" ||
-		die "Could not execute editor"
-	expand_todo_ids
+		git_sequence_editor "$todo" ||
+			die "Could not execute editor"
+		expand_todo_ids
 
-	exit
-	;;
-esac
+		exit
+		;;
+	esac
 
-git var GIT_COMMITTER_IDENT >/dev/null ||
-	die "You need to set your committer info first"
+	git var GIT_COMMITTER_IDENT >/dev/null ||
+		die "You need to set your committer info first"
 
-comment_for_reflog start
+	comment_for_reflog start
 
-if test ! -z "$switch_to"
-then
-	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
-	output git checkout "$switch_to" -- ||
-	die "Could not checkout $switch_to"
+	if test ! -z "$switch_to"
+	then
+		GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $switch_to"
+		output git checkout "$switch_to" -- ||
+		die "Could not checkout $switch_to"
 
-	comment_for_reflog start
-fi
+		comment_for_reflog start
+	fi
 
-orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
-mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
+	orig_head=$(git rev-parse --verify HEAD) || die "No HEAD?"
+	mkdir -p "$state_dir" || die "Could not create temporary $state_dir"
 
-: > "$state_dir"/interactive || die "Could not mark as interactive"
-write_basic_state
-if test t = "$preserve_merges"
-then
-	if test -z "$rebase_root"
+	: > "$state_dir"/interactive || die "Could not mark as interactive"
+	write_basic_state
+	if test t = "$preserve_merges"
 	then
-		mkdir "$rewritten" &&
-		for c in $(git merge-base --all $orig_head $upstream)
-		do
-			echo $onto > "$rewritten"/$c ||
+		if test -z "$rebase_root"
+		then
+			mkdir "$rewritten" &&
+			for c in $(git merge-base --all $orig_head $upstream)
+			do
+				echo $onto > "$rewritten"/$c ||
+					die "Could not init rewritten commits"
+			done
+		else
+			mkdir "$rewritten" &&
+			echo $onto > "$rewritten"/root ||
 				die "Could not init rewritten commits"
-		done
+		fi
+		# No cherry-pick because our first pass is to determine
+		# parents to rewrite and skipping dropped commits would
+		# prematurely end our probe
+		merges_option=
 	else
-		mkdir "$rewritten" &&
-		echo $onto > "$rewritten"/root ||
-			die "Could not init rewritten commits"
+		merges_option="--no-merges --cherry-pick"
 	fi
-	# No cherry-pick because our first pass is to determine
-	# parents to rewrite and skipping dropped commits would
-	# prematurely end our probe
-	merges_option=
-else
-	merges_option="--no-merges --cherry-pick"
-fi
 
-shorthead=$(git rev-parse --short $orig_head)
-shortonto=$(git rev-parse --short $onto)
-if test -z "$rebase_root"
-	# this is now equivalent to ! -z "$upstream"
-then
-	shortupstream=$(git rev-parse --short $upstream)
-	revisions=$upstream...$orig_head
-	shortrevisions=$shortupstream..$shorthead
-else
-	revisions=$onto...$orig_head
-	shortrevisions=$shorthead
-fi
-git rev-list $merges_option --pretty=oneline --abbrev-commit \
-	--abbrev=7 --reverse --left-right --topo-order \
-	$revisions | \
-	sed -n "s/^>//p" |
-while read -r shortsha1 rest
-do
-
-	if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
+	shorthead=$(git rev-parse --short $orig_head)
+	shortonto=$(git rev-parse --short $onto)
+	if test -z "$rebase_root"
+		# this is now equivalent to ! -z "$upstream"
 	then
-		comment_out="$comment_char "
+		shortupstream=$(git rev-parse --short $upstream)
+		revisions=$upstream...$orig_head
+		shortrevisions=$shortupstream..$shorthead
 	else
-		comment_out=
+		revisions=$onto...$orig_head
+		shortrevisions=$shorthead
 	fi
+	git rev-list $merges_option --pretty=oneline --abbrev-commit \
+		--abbrev=7 --reverse --left-right --topo-order \
+		$revisions | \
+		sed -n "s/^>//p" |
+	while read -r shortsha1 rest
+	do
 
-	if test t != "$preserve_merges"
-	then
-		printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
-	else
-		sha1=$(git rev-parse $shortsha1)
-		if test -z "$rebase_root"
+		if test -z "$keep_empty" && is_empty_commit $shortsha1 && ! is_merge_commit $shortsha1
 		then
-			preserve=t
-			for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
-			do
-				if test -f "$rewritten"/$p
-				then
-					preserve=f
-				fi
-			done
+			comment_out="$comment_char "
 		else
-			preserve=f
-		fi
-		if test f = "$preserve"
-		then
-			touch "$rewritten"/$sha1
-			printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+			comment_out=
 		fi
-	fi
-done
 
-# Watch for commits that been dropped by --cherry-pick
-if test t = "$preserve_merges"
-then
-	mkdir "$dropped"
-	# Save all non-cherry-picked changes
-	git rev-list $revisions --left-right --cherry-pick | \
-		sed -n "s/^>//p" > "$state_dir"/not-cherry-picks
-	# Now all commits and note which ones are missing in
-	# not-cherry-picks and hence being dropped
-	git rev-list $revisions |
-	while read rev
-	do
-		if test -f "$rewritten"/$rev -a "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = ""
+		if test t != "$preserve_merges"
 		then
-			# Use -f2 because if rev-list is telling us this commit is
-			# not worthwhile, we don't want to track its multiple heads,
-			# just the history of its first-parent for others that will
-			# be rebasing on top of it
-			git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$dropped"/$rev
-			short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
-			sane_grep -v "^[a-z][a-z]* $short" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
-			rm "$rewritten"/$rev
+			printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+		else
+			sha1=$(git rev-parse $shortsha1)
+			if test -z "$rebase_root"
+			then
+				preserve=t
+				for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -s -f2-)
+				do
+					if test -f "$rewritten"/$p
+					then
+						preserve=f
+					fi
+				done
+			else
+				preserve=f
+			fi
+			if test f = "$preserve"
+			then
+				touch "$rewritten"/$sha1
+				printf '%s\n' "${comment_out}pick $shortsha1 $rest" >>"$todo"
+			fi
 		fi
 	done
-fi
 
-test -s "$todo" || echo noop >> "$todo"
-test -n "$autosquash" && rearrange_squash "$todo"
-test -n "$cmd" && add_exec_commands "$todo"
+	# Watch for commits that been dropped by --cherry-pick
+	if test t = "$preserve_merges"
+	then
+		mkdir "$dropped"
+		# Save all non-cherry-picked changes
+		git rev-list $revisions --left-right --cherry-pick | \
+			sed -n "s/^>//p" > "$state_dir"/not-cherry-picks
+		# Now all commits and note which ones are missing in
+		# not-cherry-picks and hence being dropped
+		git rev-list $revisions |
+		while read rev
+		do
+			if test -f "$rewritten"/$rev -a "$(sane_grep "$rev" "$state_dir"/not-cherry-picks)" = ""
+			then
+				# Use -f2 because if rev-list is telling us this commit is
+				# not worthwhile, we don't want to track its multiple heads,
+				# just the history of its first-parent for others that will
+				# be rebasing on top of it
+				git rev-list --parents -1 $rev | cut -d' ' -s -f2 > "$dropped"/$rev
+				short=$(git rev-list -1 --abbrev-commit --abbrev=7 $rev)
+				sane_grep -v "^[a-z][a-z]* $short" <"$todo" > "${todo}2" ; mv "${todo}2" "$todo"
+				rm "$rewritten"/$rev
+			fi
+		done
+	fi
+
+	test -s "$todo" || echo noop >> "$todo"
+	test -n "$autosquash" && rearrange_squash "$todo"
+	test -n "$cmd" && add_exec_commands "$todo"
 
-cat >>"$todo" <<EOF
+	cat >>"$todo" <<EOF
 
 $comment_char Rebase $shortrevisions onto $shortonto
 EOF
-append_todo_help
-git stripspace --comment-lines >>"$todo" <<\EOF
+	append_todo_help
+	git stripspace --comment-lines >>"$todo" <<\EOF
 
 However, if you remove everything, the rebase will be aborted.
 
 EOF
 
-if test -z "$keep_empty"
-then
-	printf '%s\n' "$comment_char Note that empty commits are commented out" >>"$todo"
-fi
+	if test -z "$keep_empty"
+	then
+		printf '%s\n' "$comment_char Note that empty commits are commented out" >>"$todo"
+	fi
 
 
-has_action "$todo" ||
-	die_abort "Nothing to do"
+	has_action "$todo" ||
+		die_abort "Nothing to do"
 
-cp "$todo" "$todo".backup
-git_sequence_editor "$todo" ||
-	die_abort "Could not execute editor"
+	cp "$todo" "$todo".backup
+	git_sequence_editor "$todo" ||
+		die_abort "Could not execute editor"
 
-has_action "$todo" ||
-	die_abort "Nothing to do"
+	has_action "$todo" ||
+		die_abort "Nothing to do"
 
-expand_todo_ids
+	expand_todo_ids
 
-test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
+	test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
 
-GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
-output git checkout $onto || die_abort "could not detach HEAD"
-git update-ref ORIG_HEAD $orig_head
-do_rest
+	GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
+	output git checkout $onto || die_abort "could not detach HEAD"
+	git update-ref ORIG_HEAD $orig_head
+	do_rest
+}
+git_rebase__interactive
diff --git a/git-rebase--merge.sh b/git-rebase--merge.sh
index e7d96de9..b5f05bf5 100644
--- a/git-rebase--merge.sh
+++ b/git-rebase--merge.sh
@@ -101,53 +101,56 @@ finish_rb_merge () {
 	say All done.
 }
 
-case "$action" in
-continue)
-	read_state
-	continue_merge
-	while test "$msgnum" -le "$end"
-	do
-		call_merge "$msgnum"
+git_rebase__merge() {
+	case "$action" in
+	continue)
+		read_state
 		continue_merge
+		while test "$msgnum" -le "$end"
+		do
+			call_merge "$msgnum"
+			continue_merge
+		done
+		finish_rb_merge
+		return
+		;;
+	skip)
+		read_state
+		git rerere clear
+		msgnum=$(($msgnum + 1))
+		while test "$msgnum" -le "$end"
+		do
+			call_merge "$msgnum"
+			continue_merge
+		done
+		finish_rb_merge
+		return
+		;;
+	esac
+
+	mkdir -p "$state_dir"
+	echo "$onto_name" > "$state_dir/onto_name"
+	write_basic_state
+
+	msgnum=0
+	for cmt in `git rev-list --reverse --no-merges "$revisions"`
+	do
+		msgnum=$(($msgnum + 1))
+		echo "$cmt" > "$state_dir/cmt.$msgnum"
 	done
-	finish_rb_merge
-	return
-	;;
-skip)
-	read_state
-	git rerere clear
-	msgnum=$(($msgnum + 1))
+
+	echo 1 >"$state_dir/msgnum"
+	echo $msgnum >"$state_dir/end"
+
+	end=$msgnum
+	msgnum=1
+
 	while test "$msgnum" -le "$end"
 	do
 		call_merge "$msgnum"
 		continue_merge
 	done
-	finish_rb_merge
-	return
-	;;
-esac
-
-mkdir -p "$state_dir"
-echo "$onto_name" > "$state_dir/onto_name"
-write_basic_state
-
-msgnum=0
-for cmt in `git rev-list --reverse --no-merges "$revisions"`
-do
-	msgnum=$(($msgnum + 1))
-	echo "$cmt" > "$state_dir/cmt.$msgnum"
-done
-
-echo 1 >"$state_dir/msgnum"
-echo $msgnum >"$state_dir/end"
-
-end=$msgnum
-msgnum=1
 
-while test "$msgnum" -le "$end"
-do
-	call_merge "$msgnum"
-	continue_merge
-done
-
-finish_rb_merge
+	finish_rb_merge
+}
+git_rebase__merge
-- 
tg: (0bc85abb..) t/freebsd-sh-return (depends on: maint)

[PATCH 3/3] test: fix t5560 on FreeBSD

From: Kyle J. McKay <hidden>
Date: 2016-06-15 23:00:40

Since fd0a8c2e (first appearing in v1.7.0), the
t/t5560-http-backend-noserver.sh test has used a backslash escape
inside a ${} expansion in order to specify a literal '?' character.

Unfortunately the FreeBSD /bin/sh does not interpret this correctly.

In a POSIX compliant shell, the following:

x='one?two?three'
echo "${x#*\?}"

Would be expected to produce this:

two?three

When using the FreeBSD /bin/sh instead you get this:

one?two?three

In fact the FreeBSD /bin/sh treats the backslash as a literal
character to match so that this:

y='one\two\three'
echo "${y#*\?}"

Produces this unexpected value:

wo\three

In this case the backslash is not only treated literally, it also
fails to defeat the special meaning of the '?' character.

Instead, we can use the [...] construct to defeat the special meaning
of the '?' character and match it exactly in a way that works for the
FreeBSD /bin/sh as well as other POSIX /bin/sh implementations.

Changing the example like so:

x='one?two?three'
echo "${x#*[?]}"

Produces the expected output using the FreeBSD /bin/sh.

Therefore, change the use of \? to [?] in order to be compatible with
the FreeBSD /bin/sh which allows t/t5560-http-backend-noserver.sh to
pass on FreeBSD again.

Signed-off-by: Kyle J. McKay <redacted>

---
 t/t5560-http-backend-noserver.sh | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
diff --git a/t/t5560-http-backend-noserver.sh b/t/t5560-http-backend-noserver.sh
index 9be9ae34..5abd11a5 100755
--- a/t/t5560-http-backend-noserver.sh
+++ b/t/t5560-http-backend-noserver.sh
@@ -9,8 +9,8 @@ test_have_prereq GREP_STRIPS_CR && export GREP_OPTIONS=-U
 
 run_backend() {
 	echo "$2" |
-	QUERY_STRING="${1#*\?}" \
-	PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%\?*}" \
+	QUERY_STRING="${1#*[?]}" \
+	PATH_TRANSLATED="$HTTPD_DOCUMENT_ROOT_PATH/${1%%[?]*}" \
 	git http-backend >act.out 2>act.err
 }
 
-- 
tg: (532c2992..) t/freebsd-t5560 (depends on: t/revert-99855ddf)

[PATCH 2/3] Revert "rebase: fix run_specific_rebase's use of "return" on FreeBSD"

From: Kyle J. McKay <hidden>
Date: 2016-06-15 23:00:40

This reverts commit 99855ddf4bd319cd06a0524e755ab1c1b7d39f3b.

The workaround 99855ddf introduced to deal with problematic
"return" statements in scripts run by "dot" commands located
inside functions only handles one part of the problem.  The
issue has now been addressed by not using "return" statements
in this way in the git-rebase--*.sh scripts.

This workaround is therefore no longer necessary, so clean
up the code by reverting it.

Conflicts:
        git-rebase.sh

Signed-off-by: Kyle J. McKay <redacted>

---
 git-rebase.sh | 11 +----------
 1 file changed, 1 insertion(+), 10 deletions(-)
diff --git a/git-rebase.sh b/git-rebase.sh
index 8a3efa29..07e2bd48 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -169,22 +169,13 @@ You can run "git stash pop" or "git stash drop" at any time.
 	rm -rf "$state_dir"
 }
 
-run_specific_rebase_internal () {
+run_specific_rebase () {
 	if [ "$interactive_rebase" = implied ]; then
 		GIT_EDITOR=:
 		export GIT_EDITOR
 		autosquash=
 	fi
-	# On FreeBSD, the shell's "return" returns from the current
-	# function, not from the current file inclusion.
-	# run_specific_rebase_internal has the file inclusion as a
-	# last statement, so POSIX and FreeBSD's return will do the
-	# same thing.
 	. git-rebase--$type
-}
-
-run_specific_rebase () {
-	run_specific_rebase_internal
 	ret=$?
 	if test $ret -eq 0
 	then
-- 
tg: (1bb252a9..) t/revert-99855ddf (depends on: t/freebsd-sh-return)
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help