[PATCH v2.2] Teach rebase interactive the mark command

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



This new command can be used to set symbolic marks for an commit while
doing a rebase. This symbolic name can later be used for merges or
resets.

The decision to use references for the marks and not files like done with
the rewritten commits for preserve merges was made to ensure no commit
objects get lost if prune is started while (a long term) rebase is
running. This also unifies the checking of the validity of marks and
references by using rev-parse for it.

The format of the marks is as close as possible to the format of the
marks used by fast-export and fast-import, i.e. :001 == :1 and “:12a” is
an invalid mark. It differs from the format of fast-import in that point
that the colon is not required after the mark command, i.e. “mark 12” is
the same as “mark :12”. This should ease the writing of commads.

Signed-off-by: Jörg Sommer <joerg@xxxxxxxxxxxx>
---
 git-rebase--interactive.sh    |   31 +++++++++++++++++++++++++++++++
 t/t3404-rebase-interactive.sh |   17 +++++++++++++++++
 2 files changed, 48 insertions(+), 0 deletions(-)

That's the diff to the last version:
>diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
>index eaf5563..1751b08 100755
>--- a/git-rebase--interactive.sh
>+++ b/git-rebase--interactive.sh
>@@ -105,13 +105,11 @@ die_with_patch () {
> }
> 
> cleanup_before_quit () {
>-	rm -rf "$DOTEST" &&
>-	for ref in "$GIT_DIR/$mark_prefix"*
>+	for ref in $(git for-each-ref --format='%(refname)' "${mark_prefix%/}")
> 	do
>-		test "$ref" = "$GIT_DIR/$mark_prefix*" && continue
>-		git update-ref -d "${ref#$GIT_DIR/}" "${ref#$GIT_DIR/}" || \
>-			return 1
>+		git update-ref -d "$ref" "$ref" || return 1
> 	done
>+	rm -rf "$DOTEST"
> }
> 
> die_abort () {
>@@ -194,14 +192,12 @@ peek_next_command () {
> }
> 
> mark_to_ref () {
>-	case "$1" in
>-	:[0-9]*)
>-		echo "$mark_prefix$(printf %d ${1#:} 2>/dev/null)"
>-		;;
>-	*)
>+	if expr match "$1" "^:[0-9][0-9]*$" >/dev/null
>+	then
>+		echo "$mark_prefix$(printf %d ${1#:})"
>+	else
> 		echo "$1"
>-		;;
>-	esac
>+	fi
> }
> 
> do_next () {
>@@ -285,6 +281,8 @@ do_next () {
> 		mark_action_done
> 
> 		mark=$(mark_to_ref :${sha1#:})
>+		test :${sha1#:} = "$mark" && die "Invalid mark '$sha1'"
>+
> 		git rev-parse --verify "$mark" > /dev/null 2>&1 && \
> 			warn "mark $sha1 already exist; overwriting it"
> 


diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 531ee94..c0abc01 100755
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -35,6 +35,8 @@ mark the corrected paths with 'git add <paths>', and
 run 'git rebase --continue'"
 export GIT_CHERRY_PICK_HELP
 
+mark_prefix=refs/rebase-marks/
+
 warn () {
 	echo "$*" >&2
 }
@@ -105,6 +107,10 @@ die_with_patch () {
 }
 
 cleanup_before_quit () {
+	for ref in $(git for-each-ref --format='%(refname)' "${mark_prefix%/}")
+	do
+		git update-ref -d "$ref" "$ref" || return 1
+	done
 	rm -rf "$DOTEST"
 }
 
@@ -244,6 +250,15 @@ peek_next_command () {
 	sed -n "1s/ .*$//p" < "$TODO"
 }
 
+mark_to_ref () {
+	if expr match "$1" "^:[0-9][0-9]*$" >/dev/null
+	then
+		echo "$mark_prefix$(printf %d ${1#:})"
+	else
+		echo "$1"
+	fi
+}
+
 do_next () {
 	rm -f "$DOTEST"/message "$DOTEST"/author-script \
 		"$DOTEST"/amend || exit
@@ -321,6 +336,17 @@ do_next () {
 			die_with_patch $sha1 ""
 		fi
 		;;
+	mark)
+		mark_action_done
+
+		mark=$(mark_to_ref :${sha1#:})
+		test :${sha1#:} = "$mark" && die "Invalid mark '$sha1'"
+
+		git rev-parse --verify "$mark" > /dev/null 2>&1 && \
+			warn "mark $sha1 already exist; overwriting it"
+
+		git update-ref "$mark" HEAD || die "update-ref failed"
+		;;
 	*)
 		warn "Unknown command: $command $sha1 $rest"
 		die_with_patch $sha1 "Please fix this in the file $TODO."
@@ -533,10 +559,15 @@ do
 
 # Rebase $SHORTUPSTREAM..$SHORTHEAD onto $SHORTONTO
 #
+# In the todo insn whenever you need to refer to a commit, in addition
+# to the usual commit object name, you can use ':mark' syntax to refer
+# to a commit previously marked with the 'mark' insn.
+#
 # Commands:
 #  pick = use commit
 #  edit = use commit, but stop for amending
 #  squash = use commit, but meld into previous commit
+#  mark :mark = mark the current HEAD for later reference
 #
 # If you remove a line here THAT COMMIT WILL BE LOST.
 # However, if you remove everything, the rebase will be aborted.
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 8d29878..fa3560e 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -82,6 +82,9 @@ for line in $FAKE_LINES; do
 	case $line in
 	squash|edit)
 		action="$line";;
+	mark*)
+		echo "mark ${line#mark}"
+		echo "mark ${line#mark}" >> "$1";;
 	*)
 		echo sed -n "${line}s/^pick/$action/p"
 		sed -n "${line}p" < "$1".tmp
@@ -189,6 +192,20 @@ test_expect_success '-p handles "no changes" gracefully' '
 	test $HEAD = $(git rev-parse HEAD)
 '
 
+test_expect_success 'setting marks works' '
+	git checkout master &&
+	FAKE_LINES="mark:0 2 1 mark:42 3 edit 4" git rebase -i HEAD~4 &&
+	marks_dir=.git/refs/rebase-marks &&
+	test -d $marks_dir &&
+	test $(ls $marks_dir | wc -l) -eq 2 &&
+	test "$(git rev-parse HEAD~4)" = \
+		"$(git rev-parse refs/rebase-marks/0)" &&
+	test "$(git rev-parse HEAD~2)" = \
+		"$(git rev-parse refs/rebase-marks/42)" &&
+	git rebase --abort &&
+	ls $marks_dir | wc -l | grep -Fx 0
+'
+
 test_expect_success 'preserve merges with -p' '
 	git checkout -b to-be-preserved master^ &&
 	: > unrelated-file &&
-- 
1.5.5.1

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [Linux Kernel Development]     [Gcc Help]     [IETF Annouce]     [DCCP]     [Netdev]     [Networking]     [Security]     [V4L]     [Bugtraq]     [Yosemite]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Linux SCSI]     [Fedora Users]

  Powered by Linux