git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: "Jörg Sommer" <joerg@alea.gnuu.de>
To: git@vger.kernel.org
Cc: gitster@pobox.com, Johannes.Schindelin@gmx.de,
	"Jörg Sommer" <joerg@alea.gnuu.de>
Subject: [PATCH/RFC 10/10] Do rebase with preserve merges with advanced TODO list
Date: Thu, 10 Apr 2008 01:58:41 +0200	[thread overview]
Message-ID: <1207785521-27742-11-git-send-email-joerg@alea.gnuu.de> (raw)
In-Reply-To: <1207785521-27742-10-git-send-email-joerg@alea.gnuu.de>

---
 git-rebase--interactive.sh    |  248 ++++++++++++++++++++++++-----------------
 t/t3404-rebase-interactive.sh |   34 ++++++
 2 files changed, 181 insertions(+), 101 deletions(-)

diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 060b40f..27bd87e 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -22,12 +22,10 @@ TODO="$DOTEST"/git-rebase-todo
 DONE="$DOTEST"/done
 MSG="$DOTEST"/message
 SQUASH_MSG="$DOTEST"/message-squash
-REWRITTEN="$DOTEST"/rewritten
 MARKS="$DOTEST"/marks
 PRESERVE_MERGES=
 STRATEGY=
 VERBOSE=
-test -d "$REWRITTEN" && PRESERVE_MERGES=t
 test -f "$DOTEST"/strategy && STRATEGY="$(cat "$DOTEST"/strategy)"
 test -f "$DOTEST"/verbose && VERBOSE=t
 
@@ -137,8 +135,6 @@ pick_one () {
 	no_ff=
 	case "$1" in -n) sha1=$2; no_ff=t ;; *) sha1=$1 ;; esac
 	output git rev-parse --verify $sha1 || die "Invalid commit name: $sha1"
-	test -d "$REWRITTEN" &&
-		pick_one_preserving_merges "$@" && return
 	parent_sha1=$(git rev-parse --verify $sha1^) ||
 		die "Could not get the parent of $sha1"
 	current_sha1=$(git rev-parse --verify HEAD)
@@ -152,66 +148,6 @@ pick_one () {
 	fi
 }
 
-pick_one_preserving_merges () {
-	case "$1" in -n) sha1=$2 ;; *) sha1=$1 ;; esac
-	sha1=$(git rev-parse $sha1)
-
-	if test -f "$DOTEST"/current-commit
-	then
-		current_commit=$(cat "$DOTEST"/current-commit) &&
-		git rev-parse HEAD > "$REWRITTEN"/$current_commit &&
-		rm "$DOTEST"/current-commit ||
-		die "Cannot write current commit's replacement sha1"
-	fi
-
-	# rewrite parents; if none were rewritten, we can fast-forward.
-	fast_forward=t
-	preserve=t
-	new_parents=
-	for p in $(git rev-list --parents -1 $sha1 | cut -d' ' -f2-)
-	do
-		if test -f "$REWRITTEN"/$p
-		then
-			preserve=f
-			new_p=$(cat "$REWRITTEN"/$p)
-			test $p != $new_p && fast_forward=f
-			case "$new_parents" in
-			*$new_p*)
-				;; # do nothing; that parent is already there
-			*)
-				new_parents="$new_parents $new_p"
-				;;
-			esac
-		fi
-	done
-	case $fast_forward in
-	t)
-		output warn "Fast forward to $sha1"
-		test $preserve = f || echo $sha1 > "$REWRITTEN"/$sha1
-		;;
-	f)
-		test "a$1" = a-n && die "Refusing to squash a merge: $sha1"
-
-		first_parent=$(expr "$new_parents" : ' \([^ ]*\)')
-		# detach HEAD to current parent
-		output git checkout $first_parent 2> /dev/null ||
-			die "Cannot move HEAD to $first_parent"
-
-		echo $sha1 > "$DOTEST"/current-commit
-		case "$new_parents" in
-		' '*' '*)
-			# No point in merging the first parent, that's HEAD
-			redo_merge $sha1 ${new_parents# $first_parent}
-			;;
-		*)
-			output git cherry-pick "$@" ||
-				die_with_patch $sha1 "Could not pick $sha1"
-			;;
-		esac
-		;;
-	esac
-}
-
 nth_string () {
 	case "$1" in
 	*1[0-9]|*[04-9]) echo "$1"th;;
@@ -410,20 +346,7 @@ do_next () {
 	HEADNAME=$(cat "$DOTEST"/head-name) &&
 	OLDHEAD=$(cat "$DOTEST"/head) &&
 	SHORTONTO=$(git rev-parse --short $(cat "$DOTEST"/onto)) &&
-	if test -d "$REWRITTEN"
-	then
-		test -f "$DOTEST"/current-commit &&
-			current_commit=$(cat "$DOTEST"/current-commit) &&
-			git rev-parse HEAD > "$REWRITTEN"/$current_commit
-		if test -f "$REWRITTEN"/$OLDHEAD
-		then
-			NEWHEAD=$(cat "$REWRITTEN"/$OLDHEAD)
-		else
-			NEWHEAD=$OLDHEAD
-		fi
-	else
-		NEWHEAD=$(git rev-parse HEAD)
-	fi &&
+	NEWHEAD=$(git rev-parse HEAD) &&
 	case $HEADNAME in
 	refs/*)
 		message="$GIT_REFLOG_ACTION: $HEADNAME onto $SHORTONTO)" &&
@@ -448,6 +371,138 @@ do_rest () {
 	done
 }
 
+sha1_to_mark() {
+	# args: "sha1" " sha1#mark sha1#mark"
+	local tmp
+	case "$2" in
+	*" $1#"*)
+		tmp="${2#* $1#}"
+		echo "${tmp%% *}"
+		;;
+	*)
+		return 1
+		;;
+	esac
+}
+
+insert_sha1_with_mark_in_list() {
+	# args: "sha1" "mark" " sha1#mark sha1#mark"
+	case "$3" in
+	*" $1#"*)
+		echo "$3"
+		return 1
+		;;
+	*)
+		echo "$3 $1#$2"
+		;;
+	esac
+}
+
+create_extended_todo_list() {
+	(
+	while IFS=_ read commit parents subject
+	do
+		if test "${last_parent:-$commit}" != "$commit"
+		then
+			if test t = "${delayed_mark:-f}"
+			then
+				case "${marked_commits:-} " in
+				*" $last_parent ")
+					;;
+				*)
+					marked_commits="${marked_commits:-} $last_parent"
+					;;
+				esac
+				delayed_mark=f
+			fi
+			test "$last_parent" = $SHORTUPSTREAM && \
+				last_parent=$SHORTONTO
+			echo "reset $last_parent"
+		fi
+		last_parent="${parents%% *}"
+
+		case "${marked_commits:-} " in
+		*" $commit "*)
+			echo mark
+			;;
+		esac
+
+		case "$parents" in
+		*' '*)
+			delayed_mark=t
+			new_parents=
+			for p in ${parents#* }
+			do
+				case "${marked_commits:-} " in
+				*" $p ")
+					;;
+				*)
+					marked_commits="${marked_commits:-} $p"
+					;;
+				esac
+				if test "$p" = $SHORTUPSTREAM
+				then
+					new_parents="$new_parents $SHORTONTO"
+				else
+					new_parents="$new_parents $p"
+				fi
+			done
+			unset p
+			echo merge $commit $new_parents
+			unset new_parents
+			;;
+		*)
+			echo "pick $commit $subject"
+			;;
+		esac
+	done
+	test -n "${last_parent:-}" -a "${last_parent:-}" != $SHORTUPSTREAM && \
+		echo reset $last_parent
+	) | \
+	tac | \
+	while read cmd args
+	do
+		: ${commit_mark_list:=} ${last_commit:=000}
+		case "$cmd" in
+		pick)
+			last_commit="${args%% *}"
+			;;
+		mark)
+			: ${next_mark:=0}
+			if commit_mark_list=$(insert_sha1_with_mark_in_list \
+				$last_commit $next_mark "$commit_mark_list")
+			then
+				args="#$next_mark"
+				next_mark=$(($next_mark + 1))
+			else
+				die "Internal error: two marks for the same commit"
+			fi
+			;;
+		reset)
+			if tmp=$(sha1_to_mark $args "$commit_mark_list")
+			then
+				args="#$tmp"
+			fi
+			;;
+		merge)
+			new_args=
+			for i in ${args#* }
+			do
+				if tmp=$(sha1_to_mark $i "$commit_mark_list")
+				then
+					new_args="$new_args #$tmp"
+				else
+					new_args="$new_args $i"
+				fi
+			done
+			last_commit="${args%% *}"
+			args="$last_commit ${new_args# }"
+			;;
+		esac
+		echo "$cmd $args"
+	done
+}
+
 while test $# != 0
 do
 	case "$1" in
@@ -580,33 +635,24 @@ do
 		echo $ONTO > "$DOTEST"/onto
 		test -z "$STRATEGY" || echo "$STRATEGY" > "$DOTEST"/strategy
 		test t = "$VERBOSE" && : > "$DOTEST"/verbose
-		if test t = "$PRESERVE_MERGES"
-		then
-			# $REWRITTEN contains files for each commit that is
-			# reachable by at least one merge base of $HEAD and
-			# $UPSTREAM. They are not necessarily rewritten, but
-			# their children might be.
-			# This ensures that commits on merged, but otherwise
-			# unrelated side branches are left alone. (Think "X"
-			# in the man page's example.)
-			mkdir "$REWRITTEN" &&
-			for c in $(git merge-base --all $HEAD $UPSTREAM)
-			do
-				echo $ONTO > "$REWRITTEN"/$c ||
-					die "Could not init rewritten commits"
-			done
-			MERGES_OPTION=
-		else
-			MERGES_OPTION=--no-merges
-		fi
 
 		SHORTUPSTREAM=$(git rev-parse --short=7 $UPSTREAM)
 		SHORTHEAD=$(git rev-parse --short=7 $HEAD)
 		SHORTONTO=$(git rev-parse --short=7 $ONTO)
-		git rev-list $MERGES_OPTION --pretty=oneline --abbrev-commit \
-			--abbrev=7 --reverse --left-right --cherry-pick \
-			$UPSTREAM...$HEAD | \
-			sed -n "s/^>/pick /p" > "$TODO"
+		common_rev_parse_opts="--abbrev-commit
+			--abbrev=7 --left-right --cherry-pick
+			$UPSTREAM...$HEAD"
+		if test t = "$PRESERVE_MERGES"
+		then
+			git rev-list --pretty='format:%h_%p_%s' \
+				--topo-order $common_rev_parse_opts | \
+				grep -v ^commit | \
+				create_extended_todo_list
+		else
+			git rev-list --no-merges --reverse --pretty=oneline \
+				$common_rev_parse_opts | sed -n "s/^>/pick /p"
+		fi > "$TODO"
+
 		cat >> "$TODO" << EOF
 
 # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index be26a78..af7d818 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -245,7 +245,41 @@ test_expect_success 'preserve merges with -p' '
 	test $(git show HEAD~2:file1) = B
 '
 
+test_expect_success 'rebase with preserve merge forth and back is a noop' '
+	git checkout -b big-branch-1 master &&
+	: > bb1a &&
+	git add bb1a &&
+	git commit -m "big branch commit 1" &&
+	: > bb1b &&
+	git add bb1b &&
+	git commit -m "big branch commit 2" &&
+	: > bb1c &&
+	git add bb1c &&
+	git commit -m "big branch commit 3" &&
+	git checkout -b big-branch-2 master &&
+	: > bb2a &&
+	git add bb2a &&
+	git commit -m "big branch commit 4" &&
+	: > bb2b &&
+	git add bb2b &&
+	git commit -m "big branch commit 5" &&
+	git merge big-branch-1~1 &&
+	git merge to-be-preserved &&
+	tbp_merge=$(git rev-parse HEAD) &&
+	: > bb2c &&
+	git add bb2c &&
+	git commit -m "big branch commit 6" &&
+	git merge big-branch-1 &&
+	head=$(git rev-parse HEAD) &&
+	FAKE_LINES="16 6 19 20 4 1 2 5 22" \
+		git rebase -i -p --onto dead-end master &&
+	FAKE_LINES="3 7 mark#10 8 9 5 1 2 merge$tbp_merge~1/#10 merge$tbp_merge/to-be-preserved 6 11" \
+	git rebase -i -p --onto master dead-end &&
+	test "$head" = "$(git rev-parse HEAD)"
+'
+
 test_expect_success '--continue tries to commit' '
+	git checkout to-be-rebased &&
 	test_tick &&
 	! git rebase -i --onto new-branch1 HEAD^ &&
 	echo resolved > file1 &&
-- 
1.5.4.5

  reply	other threads:[~2008-04-10  0:04 UTC|newest]

Thread overview: 104+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-03-23 21:42 [PATCH 1/4] Move redo merge code in a function Jörg Sommer
2008-03-23 21:42 ` [PATCH 2/4] Rework redo_merge Jörg Sommer
2008-03-23 21:42   ` [PATCH 3/4] Add a function for get the parents of a commit Jörg Sommer
2008-03-23 21:42     ` [PATCH 4/4] git-rebase -i: New option to support rebase with merges Jörg Sommer
2008-03-23 22:41       ` Johannes Schindelin
2008-03-24 11:14         ` Jörg Sommer
2008-03-24 13:08           ` Johannes Schindelin
2008-03-24 23:40             ` Jörg Sommer
2008-03-24 18:35           ` Junio C Hamano
2008-03-24 23:30             ` Junio C Hamano
2008-03-25 10:13             ` Jörg Sommer
2008-03-26  8:02               ` Junio C Hamano
2008-04-09 23:58             ` Teach rebase interactive more commands to do better preserve merges Jörg Sommer
2008-04-09 23:58               ` [PATCH/RFC 01/10] Teach rebase interactive the mark command Jörg Sommer
2008-04-09 23:58                 ` [PATCH/RFC 02/10] Teach rebase interactive the reset command Jörg Sommer
2008-04-09 23:58                   ` [PATCH/RFC 03/10] Teach rebase interactive the merge command Jörg Sommer
2008-04-09 23:58                     ` [PATCH/RFC 04/10] Move redo merge code in a function Jörg Sommer
2008-04-09 23:58                       ` [PATCH/RFC 05/10] Rework redo_merge Jörg Sommer
2008-04-09 23:58                         ` [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list Jörg Sommer
2008-04-09 23:58                           ` [PATCH/RFC 07/10] fake-editor: output TODO list if unchanged Jörg Sommer
2008-04-09 23:58                             ` [PATCH/RFC 08/10] Don't append default merge message to -m message Jörg Sommer
2008-04-09 23:58                               ` [PATCH/RFC 09/10] Select all lines with fake-editor Jörg Sommer
2008-04-09 23:58                                 ` Jörg Sommer [this message]
2008-04-12  0:00                           ` [PATCH/RFC 06/10] Unify the lenght of $SHORT* and the commits in the TODO list Junio C Hamano
2008-04-12  9:13                             ` Jörg Sommer
2008-04-13  6:20                               ` Junio C Hamano
2008-04-13 16:39                                 ` Jörg Sommer
2008-04-14  1:06                                 ` Tarmigan
2008-04-11 23:56                   ` [PATCH/RFC 02/10] Teach rebase interactive the reset command Junio C Hamano
2008-04-12  9:37                     ` Jörg Sommer
2008-04-10  9:33                 ` [PATCH/RFC 01/10] Teach rebase interactive the mark command Mike Ralphson
2008-04-12 10:17                   ` Jörg Sommer
2008-04-11 23:48                 ` Junio C Hamano
2008-04-12 10:11                   ` Jörg Sommer
2008-04-13  3:56                     ` Shawn O. Pearce
2008-04-13 16:50                       ` Jörg Sommer
2008-04-14  6:24                         ` Shawn O. Pearce
2008-04-14  6:54                           ` Junio C Hamano
2008-04-14 10:06                           ` Jörg Sommer
2008-04-14  0:20             ` [PATCH v2 01/13] fake-editor: output TODO list if unchanged Jörg Sommer
2008-04-14  0:20               ` [PATCH v2 02/13] Don't append default merge message to -m message Jörg Sommer
2008-04-14  0:20                 ` [PATCH v2 03/13] Move cleanup code into it's own function Jörg Sommer
2008-04-14  0:21                   ` [PATCH v2 04/13] Teach rebase interactive the mark command Jörg Sommer
2008-04-14  0:21                     ` [PATCH v2 05/13] Teach rebase interactive the reset command Jörg Sommer
2008-04-14  0:21                       ` [PATCH v2 06/13] Move redo merge code in a function Jörg Sommer
2008-04-14  0:21                         ` [PATCH v2 07/13] Teach rebase interactive the merge command Jörg Sommer
2008-04-14  0:21                           ` [PATCH v2 08/13] Unify the lenght of $SHORT* and the commits in the TODO list Jörg Sommer
2008-04-14  0:21                             ` [PATCH v2 09/13] Select all lines with fake-editor Jörg Sommer
2008-04-14  0:21                               ` [PATCH v2 10/13] Do rebase with preserve merges with advanced TODO list Jörg Sommer
2008-04-14  0:21                                 ` [PATCH v2 11/13] Add option --first-parent Jörg Sommer
2008-04-14  0:21                                   ` [PATCH v2 12/13] Teach rebase interactive the tag command Jörg Sommer
2008-04-14  0:21                                     ` [PATCH v2 13/13] Add option --preserve-tags Jörg Sommer
2008-04-22  5:32                     ` [PATCH v2 04/13] Teach rebase interactive the mark command Junio C Hamano
2008-04-22  8:13                       ` Junio C Hamano
2008-04-22  8:52                       ` Johannes Schindelin
2008-04-22  9:55                       ` Jörg Sommer
2008-04-22 10:31                         ` Johannes Schindelin
2008-04-22 16:56                           ` Junio C Hamano
2008-04-22 17:12                             ` Johannes Schindelin
2008-04-29  0:25                               ` Junio C Hamano
2008-04-29  0:39                                 ` Johannes Schindelin
2008-04-29  5:17                                   ` Junio C Hamano
2008-04-29  7:12                                     ` Johannes Sixt
2008-04-29 10:52                                       ` Johannes Schindelin
2008-04-29 21:16                                         ` Junio C Hamano
2008-04-29 21:25                                           ` Johannes Schindelin
2008-04-29 22:23                                             ` Junio C Hamano
2008-04-29 22:55                                               ` Johannes Schindelin
2008-04-29 23:06                                                 ` Junio C Hamano
2008-04-29 23:31                                                   ` Johannes Schindelin
2008-04-30  1:23                                                     ` Junio C Hamano
2008-04-30  6:25                                                       ` Johannes Sixt
2008-04-30  7:10                                                         ` Junio C Hamano
2008-04-30  8:47                                                       ` Johannes Schindelin
2008-04-30  9:19                                                         ` Junio C Hamano
2008-04-30 10:29                                                           ` Johannes Sixt
2008-04-30 11:56                                                           ` Johannes Schindelin
2008-05-01 19:04                                                             ` Junio C Hamano
2008-05-03 12:45                                                               ` Johannes Schindelin
2008-05-03 17:09                                                                 ` Junio C Hamano
2008-05-04  9:38                                                                   ` Johannes Schindelin
2008-05-04 12:52                                                                     ` Jörg Sommer
2008-04-30 13:06                                                         ` Dmitry Potapov
2008-05-01 12:59                                                           ` Johannes Schindelin
2008-04-22 18:04                         ` Junio C Hamano
2008-04-25  9:11                           ` Jörg Sommer
2008-04-25  9:44                             ` [PATCH v2.2] " Jörg Sommer
2008-04-27  6:13                               ` Junio C Hamano
2008-04-27  8:28                                 ` Jörg Sommer
2008-04-14 10:39                   ` [PATCH v2.1] " Jörg Sommer
2008-04-14 23:29                     ` Shawn O. Pearce
2008-04-20 23:44                       ` mark parsing in fast-import Jörg Sommer
2008-04-21  0:26                         ` Shawn O. Pearce
2008-04-21  8:41                           ` Jörg Sommer
2008-04-21 23:59                             ` Shawn O. Pearce
2008-04-22  9:39                               ` Jörg Sommer
2008-04-22 23:15                                 ` Shawn O. Pearce
2008-04-25  9:04                                   ` [PATCH v2] Make mark parsing much more restrictive Jörg Sommer
2008-04-20 16:52                 ` [PATCH v2 02/13] Don't append default merge message to -m message Junio C Hamano
2008-04-21  0:17                   ` Jörg Sommer
2008-04-22  5:27                     ` Junio C Hamano
2008-03-23 22:33     ` [PATCH 3/4] Add a function for get the parents of a commit Johannes Schindelin
2008-03-23 22:29   ` [PATCH 2/4] Rework redo_merge Johannes Schindelin
2008-03-23 22:26 ` [PATCH 1/4] Move redo merge code in a function Johannes Schindelin

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1207785521-27742-11-git-send-email-joerg@alea.gnuu.de \
    --to=joerg@alea.gnuu.de \
    --cc=Johannes.Schindelin@gmx.de \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).