rebase -i: stop overwriting ORIG_HEAD buffer
After rebasing, ORIG_HEAD is supposed to point to the old HEAD of the rebased branch. The code used find_unique_abbrev() to obtain the object name of the old HEAD and wrote to both .git/rebase-merge/orig-head (used by `rebase --abort` to go back to the previous state) and to ORIG_HEAD. The buffer find_unique_abbrev() gives back is volatile, unfortunately, and was overwritten after the former file is written but before ORIG_FILE is written, leaving an incorrect object name in it. Avoid relying on the volatile buffer of find_unique_abbrev(), and instead supply our own buffer to keep the object name. I think that all of the users of head_hash should actually be using opts->orig_head instead as passing a string rather than a struct object_id around is a hang over from the scripted implementation. This patch just fixes the immediate bug and adds a regression test based on Caspar's reproduction example[1]. The users will be converted to use struct object_id and head_hash removed in the next few commits. [1] https://lore.kernel.org/git/CAFzd1+7PDg2PZgKw7U0kdepdYuoML9wSN4kofmB_-8NHrbbrHg@mail.gmail.com Reported-by: Caspar Duregger <herr.kaste@gmail.com> Signed-off-by: Phillip Wood <phillip.wood@dunelm.org.uk> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
b927c80531
commit
e100bea481
@ -270,15 +270,15 @@ static int edit_todo_file(unsigned flags)
|
||||
}
|
||||
|
||||
static int get_revision_ranges(struct commit *upstream, struct commit *onto,
|
||||
struct object_id *orig_head, const char **head_hash,
|
||||
struct object_id *orig_head, char *head_hash,
|
||||
char **revisions, char **shortrevisions)
|
||||
{
|
||||
struct commit *base_rev = upstream ? upstream : onto;
|
||||
const char *shorthead;
|
||||
|
||||
*head_hash = find_unique_abbrev(orig_head, GIT_MAX_HEXSZ);
|
||||
find_unique_abbrev_r(head_hash, orig_head, GIT_MAX_HEXSZ);
|
||||
*revisions = xstrfmt("%s...%s", oid_to_hex(&base_rev->object.oid),
|
||||
*head_hash);
|
||||
head_hash);
|
||||
|
||||
shorthead = find_unique_abbrev(orig_head, DEFAULT_ABBREV);
|
||||
|
||||
@ -327,7 +327,7 @@ static void split_exec_commands(const char *cmd, struct string_list *commands)
|
||||
static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
|
||||
{
|
||||
int ret;
|
||||
const char *head_hash = NULL;
|
||||
char head_hash[GIT_MAX_HEXSZ];
|
||||
char *revisions = NULL, *shortrevisions = NULL;
|
||||
struct strvec make_script_args = STRVEC_INIT;
|
||||
struct todo_list todo_list = TODO_LIST_INIT;
|
||||
@ -335,7 +335,7 @@ static int do_interactive_rebase(struct rebase_options *opts, unsigned flags)
|
||||
struct string_list commands = STRING_LIST_INIT_DUP;
|
||||
|
||||
if (get_revision_ranges(opts->upstream, opts->onto, &opts->orig_head,
|
||||
&head_hash, &revisions, &shortrevisions))
|
||||
head_hash, &revisions, &shortrevisions))
|
||||
return -1;
|
||||
|
||||
if (init_basic_state(&replay,
|
||||
|
@ -1797,6 +1797,17 @@ test_expect_success 'todo has correct onto hash' '
|
||||
test_i18ngrep "^# Rebase ..* onto $onto" actual
|
||||
'
|
||||
|
||||
test_expect_success 'ORIG_HEAD is updated correctly' '
|
||||
test_when_finished "git checkout master && git branch -D test-orig-head" &&
|
||||
git checkout -b test-orig-head A &&
|
||||
git commit --allow-empty -m A1 &&
|
||||
git commit --allow-empty -m A2 &&
|
||||
git commit --allow-empty -m A3 &&
|
||||
git commit --allow-empty -m A4 &&
|
||||
git rebase master &&
|
||||
test_cmp_rev ORIG_HEAD test-orig-head@{1}
|
||||
'
|
||||
|
||||
# This must be the last test in this file
|
||||
test_expect_success '$EDITOR and friends are unchanged' '
|
||||
test_editor_unchanged
|
||||
|
Loading…
Reference in New Issue
Block a user