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

[RFC PATCH v3 6/9] Add and use git_rebase__interactive__preserve_merges

From
Wink Saville <wink@saville.com>
Date
Mar 22, 2018, 16:57 UTC
Message-ID
<4b0a72043d351ced18b299c8bb9b0f3f27f101fb.1521690197.git.wink@saville.com>
In-Reply-To
<cover.1521690197.git.wink@saville.com>

At the moment it's an exact copy of git_rebase__interactive except the name has changed.

Signed-off-by: Wink Saville <wink@saville.com>
---
 git-rebase--interactive.sh | 108 +++++++++++++++++++++++++++++++++++++++++++++
 git-rebase.sh              |   7 ++-
 2 files changed, 114 insertions(+), 1 deletion(-)
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 2c10a7f1a..ab5513d80 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -1058,3 +1058,111 @@ git_rebase__interactive () {
 
 	complete_action
 }
+
+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 t = "$preserve_merges"
+	then
+		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=
+	else
+		merges_option="--no-merges --cherry-pick"
+	fi
+
+	init_revisions_and_shortrevisions
+
+	if test t != "$preserve_merges"
+	then
+		git rebase--helper --make-script ${keep_empty:+--keep-empty} \
+			$revisions ${restrict_revision+^$restrict_revision} >"$todo" ||
+		die "$(gettext "Could not generate todo list")"
+	else
+		format=$(git config --get rebase.instructionFormat)
+		# the 'rev-list .. | sed' requires %m to parse; the instruction requires %H to parse
+		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
+	fi
+
+	# 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 &&
+			   ! 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
+	fi
+
+	complete_action
+}
diff --git a/git-rebase.sh b/git-rebase.sh
index c4ec7c21b..b32282f4c 100755
--- a/git-rebase.sh
+++ b/git-rebase.sh
@@ -199,7 +199,12 @@ run_specific_rebase () {
 	if test "$type" = interactive
 	then
 		. git-rebase--interactive
-		git_rebase__interactive
+		if test "$preserve_merges" = t
+		then
+			git_rebase__interactive__preserve_merges
+		else
+			git_rebase__interactive
+		fi
 		ret=$?
 	else
 		. git-rebase--$type
-- 
2.16.2
Previous: Wink SavilleNext: Wink Saville
Message 17 of 20 in “rebase-interactive:”
  1. 0/9 rebase-interactive:Wink Saville, Mar 22, 2018
  2. 1/9 Simplify pick_on_preserving_mergesWink Saville, Mar 22, 2018
  3. 2/9 Call git_rebase__interactive from run_specific_rebaseWink Saville, Mar 22, 2018
  4. Junio C HamanoMar 22, 2018
  5. Wink SavilleMar 22, 2018
  6. 2/9 rebase-interactive: Do not automatically run codeWink Saville, Mar 22, 2018
  7. Junio C HamanoMar 22, 2018
  8. Wink SavilleMar 22, 2018
  9. Junio C HamanoMar 23, 2018
  10. 3/9 Indent function git_rebase__interactiveWink Saville, Mar 22, 2018
  11. Johannes SchindelinMar 23, 2018
  12. 4/9 Extract functions out of git_rebase__interactiveWink Saville, Mar 22, 2018
  13. 5/9 Use new functions in git_rebase__interactiveWink Saville, Mar 22, 2018
  14. Johannes SchindelinMar 23, 2018
  15. Junio C HamanoMar 23, 2018
  16. Wink SavilleMar 23, 2018
  17. 6/9 Add and use git_rebase__interactive__preserve_mergesWink Saville, Mar 22, 2018
  18. 8/9 Remove unused code paths from git_rebase__interactive__preserve_mergesWink Saville, Mar 22, 2018
  19. 9/9 Remove merges_option and a blank lineWink Saville, Mar 22, 2018
  20. 7/9 Remove unused code paths from git_rebase__interactiveWink Saville, Mar 22, 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.