Skip to content

Commit 75c6976

Browse files
committed
rebase -i: fix short SHA-1 collision
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" also has prefix badbeef, 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; respect core.commentchar in transform_todo_ids(); compose commit message] Signed-off-by: Eric Sunshine <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 66ae9a5 commit 75c6976

File tree

2 files changed

+31
-1
lines changed

2 files changed

+31
-1
lines changed

git-rebase--interactive.sh

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -689,6 +689,32 @@ skip_unnecessary_picks () {
689689
die "Could not skip unnecessary pick commands"
690690
}
691691

692+
transform_todo_ids () {
693+
while read -r command rest
694+
do
695+
case "$command" in
696+
"$comment_char"* | exec)
697+
# Be careful for oddball commands like 'exec'
698+
# that do not have a SHA-1 at the beginning of $rest.
699+
;;
700+
*)
701+
sha1=$(git rev-parse --verify --quiet "$@" ${rest%% *}) &&
702+
rest="$sha1 ${rest#* }"
703+
;;
704+
esac
705+
printf '%s\n' "$command${rest:+ }$rest"
706+
done <"$todo" >"$todo.new" &&
707+
mv -f "$todo.new" "$todo"
708+
}
709+
710+
expand_todo_ids() {
711+
transform_todo_ids
712+
}
713+
714+
collapse_todo_ids() {
715+
transform_todo_ids --short=7
716+
}
717+
692718
# Rearrange the todo list that has both "pick sha1 msg" and
693719
# "pick sha1 fixup!/squash! msg" appears in it so that the latter
694720
# comes immediately after the former, and change "pick" to
@@ -841,6 +867,7 @@ skip)
841867
edit-todo)
842868
git stripspace --strip-comments <"$todo" >"$todo".new
843869
mv -f "$todo".new "$todo"
870+
collapse_todo_ids
844871
append_todo_help
845872
git stripspace --comment-lines >>"$todo" <<\EOF
846873
@@ -852,6 +879,7 @@ EOF
852879

853880
git_sequence_editor "$todo" ||
854881
die "Could not execute editor"
882+
expand_todo_ids
855883

856884
exit
857885
;;
@@ -1008,6 +1036,8 @@ git_sequence_editor "$todo" ||
10081036
has_action "$todo" ||
10091037
die_abort "Nothing to do"
10101038

1039+
expand_todo_ids
1040+
10111041
test -d "$rewritten" || test -n "$force_rebase" || skip_unnecessary_picks
10121042

10131043
GIT_REFLOG_ACTION="$GIT_REFLOG_ACTION: checkout $onto_name"

t/t3404-rebase-interactive.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1049,7 +1049,7 @@ test_expect_success 'short SHA-1 setup' '
10491049
)
10501050
'
10511051

1052-
test_expect_failure 'short SHA-1 collide' '
1052+
test_expect_success 'short SHA-1 collide' '
10531053
test_when_finished "reset_rebase && git checkout master" &&
10541054
git checkout collide &&
10551055
(

0 commit comments

Comments
 (0)