[PATCH 3/3] rebase: interactive: fix short SHA-1 collision
From: Junio C Hamano <gitster@pobox.com>
The 'todo' sheet for interactive rebase shows abbreviated SHA-1's and then performs its operations upon those shortened values. This can lead to an abort if the SHA-1 of a reworded or edited commit is no longer unique within the abbreviated SHA-1 space and a subsequent SHA-1 in the todo list has the same abbreviated value.
For example:
edit f00dfad first
pick badbeef second
If, after editing, the new SHA-1 of "first" is now badbeef5ba78983324dff5265c80c4490d5a809a, then the subsequent 'pick badbeef second' will fail since badbeef is no longer a unique SHA-1 abbreviation:
error: short SHA1 badbeef is ambiguous.
fatal: Needed a single revision
Invalid commit name: badbeef
Fix this problem by expanding the SHA-1's in the todo list before performing the operations.
[es: also collapse & expand SHA-1's for --edit-todo]
Signed-off-by: Eric Sunshine <sunshine@sunshineco.com>
---
git-rebase--interactive.sh | 30 ++++++++++++++++++++++++++++++
t/t3404-rebase-interactive.sh | 2 +-
2 files changed, 31 insertions(+), 1 deletion(-)
Show changes to 2 files +31 −1
git-rebase--interactive.sh, t/t3404-rebase-interactive.sh
diff --git a/git-rebase--interactive.sh b/git-rebase--interactive.sh
index 83d6d46..ea11e62 100644
--- a/git-rebase--interactive.sh
+++ b/git-rebase--interactive.sh
@@ -689,6 +689,32 @@ skip_unnecessary_picks () {
die "Could not skip unnecessary pick commands"
}
+transform_todo_ids () {
+ while read -r command rest
+ do
+ case "$command" in
+ '#'* | exec)
+ # Be careful for oddball commands like 'exec'
+ # that do not have a SHA-1 at the beginning of $rest.
+ ;;
+ *)
+ sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
+ rest="$sha1 ${rest#* }"
+ ;;
+ esac
+ printf '%s\n' "$command${rest:+ }$rest"
+ done <"$todo" >"$todo.new" &&
+ mv -f "$todo.new" "$todo"
+}
+
+expand_todo_ids() {
+ transform_todo_ids
+}
+
+collapse_todo_ids() {
+ transform_todo_ids --short=7
+}
+
# Rearrange the todo list that has both "pick sha1 msg" and
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
# comes immediately after the former, and change "pick" to
@@ -841,6 +867,7 @@ skip)
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
@@ -852,6 +879,7 @@ EOF
git_sequence_editor "$todo" ||
die "Could not execute editor"
+ expand_todo_ids
exit
;;
@@ -1008,6 +1036,8 @@ git_sequence_editor "$todo" ||
has_action "$todo" ||
die_abort "Nothing to do"
+expand_todo_ids
+
test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index e5ebec6..db56db3 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -987,7 +987,7 @@ test_expect_success 'short SHA-1 setup' '
test_commit --notick "collide3 115158b5" collide collide3 collide3
'
-test_expect_failure 'short SHA-1 collide' '
+test_expect_success 'short SHA-1 collide' '
test_when_finished "reset_rebase && git checkout master" &&
git checkout collide &&
FAKE_COMMIT_MESSAGE="collide2 815200e" \
--
1.8.4.rc2.460.ga591f4a