git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[RFC PATCH 2/3] rebase-interactive: create git-rebase--interactive--preserve-merges

From
Wink Saville <wink@saville.com>
Date
Mar 20, 2018, 20:45 UTC
Message-ID
<20180320204507.12623-3-wink@saville.com>
In-Reply-To
<20180320204507.12623-1-wink@saville.com>

Extract the code that is executed when $preserve_merges is t from git-rebase--interactive to git-rebase--interactive--preserve-merges.sh. The extracted code uses functions from git-rebase--interactve--lib.

Signed-off-by: Wink Saville <wink@saville.com>
---
 .gitignore                                  |   1 +
 Makefile                                    |   1 +
 git-rebase--interactive--preserve-merges.sh | 134 ++++++++++++++++++++++++++++
 git-rebase.sh                               |   7 +-
 4 files changed, 142 insertions(+), 1 deletion(-)
 create mode 100644 git-rebase--interactive--preserve-merges.sh
diff --git a/.gitignore b/.gitignore
index 4ea246780..c57a6b563 100644
--- a/.gitignore
+++ b/.gitignore
@@ -116,6 +116,7 @@
 /git-rebase--am
 /git-rebase--helper
 /git-rebase--interactive
+/git-rebase--interactive--preserve-merges
 /git-rebase--interactive--lib
 /git-rebase--merge
 /git-receive-pack
diff --git a/Makefile b/Makefile
index f13540da6..543e0a659 100644
--- a/Makefile
+++ b/Makefile
@@ -567,6 +567,7 @@ SCRIPT_LIB += git-mergetool--lib
 SCRIPT_LIB += git-parse-remote
 SCRIPT_LIB += git-rebase--am
 SCRIPT_LIB += git-rebase--interactive
+SCRIPT_LIB += git-rebase--interactive--preserve-merges
 SCRIPT_LIB += git-rebase--interactive--lib
 SCRIPT_LIB += git-rebase--merge
 SCRIPT_LIB += git-sh-setup
diff --git a/git-rebase--interactive--preserve-merges.sh b/git-rebase--interactive--preserve-merges.sh
new file mode 100644
index 000000000..e00b5c990
--- /dev/null
+++ b/git-rebase--interactive--preserve-merges.sh
@@ -0,0 +1,134 @@
+#!/bin/sh
+# This shell script fragment is sourced by git-rebase to implement
+# its interactive mode with --preserve-merges flag.
+# "git rebase --interactive" makes it easy to fix up commits in the
+# middle of a series and rearrange commits and adding --preserve-merges
+# requests it to preserve merges while rebase.
+#
+# Copyright (c) 2006 Johannes E. Schindelin
+#
+# The original idea comes from Eric W. Biederman, in
+# https://public-inbox.org/git/m1odwkyuf5.fsf_-_@ebiederm.dsl.xmission.com/
+
+. git-rebase--interactive--lib
+
+# The whole contents of this file is run by dot-sourcing it from
+# inside a shell function.  It used to be that "return"s we see
+# below were not inside any function, and expected to return
+# to the function that dot-sourced us.
+#
+# However, older (9.x) versions of FreeBSD /bin/sh misbehave on such a
+# construct and continue to run the statements that follow such a "return".
+# As a work-around, we introduce an extra layer of a function
+# here, and immediately call it after defining it.
+git_rebase__interactive__preserve_merges () {
+	initiate_action "$action"
+	ret=$?
+	if test $ret == 0; then
+		return 0
+	fi
+
+	setup_reflog_action
+	init_basic_state
+
+	if test -z "$rebase_root"
+	then
+		mkdir "$rewritten" &&
+		for c in $(git merge-base --all $orig_head $upstream)
+		do
+			echo $onto > "$rewritten"/$c ||
+			    die "$(gettext "Could not init rewritten commits")"
+		done
+	else
+		mkdir "$rewritten" &&
+		echo $onto > "$rewritten"/root ||
+			die "$(gettext "Could not init rewritten commits")"
+	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=
+
+	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
+
+	# The 'rev-list .. | sed'
+	#   requires %m to parse; where as the the instruction
+	#   requires %H to parse
+	format=$(git config --get rebase.instructionFormat)
+	git rev-list $merges_option --format="%m%H ${format:-%s}" \
+		--reverse --left-right --topo-order \
+		$revisions ${restrict_revision+^$restrict_revision} | \
+		sed -n "s/^>//p" |
+	while read -r sha1 rest
+	do
+		if test -z "$keep_empty" \
+			&& is_empty_commit $sha1 \
+			&& ! is_merge_commit $sha1
+		then
+			comment_out="$comment_char "
+		else
+			comment_out=
+		fi
+
+		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 $sha1 $rest" >>"$todo"
+		fi
+	done
+
+	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 &&
+		   ! sane_grep "$rev" "$state_dir"/not-cherry-picks >/dev/null
+		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
+			sha1=$(git rev-list -1 $rev)
+			sane_grep -v "^[a-z][a-z]* $sha1" <"$todo" > "${todo}2"
+			mv "${todo}2" "$todo"
+			rm "$rewritten"/$rev
+		fi
+	done
+
+	complete_action
+}
+# ... and then we call the whole thing.
+git_rebase__interactive__preserve_merges
diff --git a/git-rebase.sh b/git-rebase.sh
index a1f6e5de6..3c2fc35f7 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -196,7 +196,12 @@ run_specific_rebase () {
 		export GIT_EDITOR
 		autosquash=
 	fi
-	. git-rebase--$type
+	if test "$type" = interactive
+	then
+		. git-rebase--${type}${preserve_merges:+--preserve-merges}
+	else
+		. git-rebase--${type}
+	fi
 	ret=$?
 	if test $ret -eq 0
 	then
-- 
2.16.2
Previous: Wink SavilleNext: Wink Saville
Message 3 of 14 in “rebase-interactive”
  1. 0/3 rebase-interactiveWink Saville, Mar 20, 2018
  2. 1/3 rebase-interactive: create git-rebase--interactive--lib.shWink Saville, Mar 20, 2018
  3. 2/3 rebase-interactive: create git-rebase--interactive--preserve-mergesWink Saville, Mar 20, 2018
  4. 3/3 rebase-interactive: refactor git-rebase--interactive to use libraryWink Saville, Mar 20, 2018
  5. Eric SunshineMar 20, 2018
  6. Wink SavilleMar 20, 2018
  7. Eric SunshineMar 20, 2018
  8. Wink SavilleMar 21, 2018
  9. Eric SunshineMar 21, 2018
  10. 0/1 rebase-interactive: Add git_rebase__interactive__preserve_mergesWink Saville, Mar 21, 2018
  11. 1/1 rebase-interactive: Add git_rebase__interactive__preserve_mergesWink Saville, Mar 21, 2018
  12. Junio C HamanoMar 21, 2018
  13. Wink SavilleMar 21, 2018
  14. Junio C HamanoMar 21, 2018

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.