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 <sunshine@sunshineco.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Junio C Hamano 2013-08-23 20:10:42 -04:00
parent 66ae9a57b8
commit 75c6976655
2 changed files with 31 additions and 1 deletions

View file

@ -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
"$comment_char"* | 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"

View file

@ -1049,7 +1049,7 @@ test_expect_success 'short SHA-1 setup' '
)
'
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 &&
(