Skip to content

Commit 9938d7e

Browse files
committed
rebase: skip branch symref aliases
rebase --update-refs records local branch decorations before replaying commits. If a decoration is a symbolic branch such as refs/heads/main pointing at refs/heads/master, updating it later dereferences back to master and can fail because the normal rebase path already moved that branch. Resolve local branch decorations to their referents before queuing update-ref commands, and skip duplicates. This keeps branch aliases from scheduling a second update for the same underlying branch while still using the existing old-OID check for the single queued update. Signed-off-by: Son Luong Ngoc <sluongng@gmail.com>
1 parent a550923 commit 9938d7e

2 files changed

Lines changed: 36 additions & 13 deletions

File tree

sequencer.c

Lines changed: 35 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6445,28 +6445,49 @@ static int add_decorations_to_list(const struct commit *commit,
64456445
struct todo_add_branch_context *ctx)
64466446
{
64476447
const struct name_decoration *decoration = get_name_decoration(&commit->object);
6448-
const char *head_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
6449-
"HEAD",
6450-
RESOLVE_REF_READING,
6451-
NULL,
6452-
NULL);
6448+
struct ref_store *refs = get_main_ref_store(the_repository);
6449+
char *head_ref = refs_resolve_refdup(refs, "HEAD", RESOLVE_REF_READING,
6450+
NULL, NULL);
6451+
struct strbuf update_ref = STRBUF_INIT;
64536452

64546453
while (decoration) {
64556454
struct todo_item *item;
64566455
const char *path;
6456+
const char *ref = decoration->name;
6457+
const char *resolved_ref;
64576458
size_t base_offset = ctx->buf->len;
64586459

64596460
/*
64606461
* If the branch is the current HEAD, then it will be
64616462
* updated by the default rebase behavior.
64626463
* Exclude it from the list of refs to update,
64636464
* as well as any non-branch decorations.
6465+
*
6466+
* Resolve branch symrefs before these checks so that aliases
6467+
* do not schedule duplicate updates for their referents.
6468+
*
64646469
* Non-branch decorations may be present if the pretty format
64656470
* includes "%d", which would have loaded all refs
64666471
* into the global decoration table.
64676472
*/
6468-
if ((head_ref && !strcmp(head_ref, decoration->name)) ||
6469-
(decoration->type != DECORATION_REF_LOCAL)) {
6473+
if (decoration->type != DECORATION_REF_LOCAL) {
6474+
decoration = decoration->next;
6475+
continue;
6476+
}
6477+
6478+
strbuf_reset(&update_ref);
6479+
resolved_ref = refs_resolve_ref_unsafe(refs, ref,
6480+
RESOLVE_REF_READING,
6481+
NULL, NULL);
6482+
if (resolved_ref)
6483+
strbuf_addstr(&update_ref, resolved_ref);
6484+
else
6485+
strbuf_addstr(&update_ref, ref);
6486+
ref = update_ref.buf;
6487+
6488+
if (!starts_with(ref, "refs/heads/") ||
6489+
(head_ref && !strcmp(head_ref, ref)) ||
6490+
string_list_has_string(&ctx->refs_to_oids, ref)) {
64706491
decoration = decoration->next;
64716492
continue;
64726493
}
@@ -6478,19 +6499,19 @@ static int add_decorations_to_list(const struct commit *commit,
64786499
memset(item, 0, sizeof(*item));
64796500

64806501
/* If the branch is checked out, then leave a comment instead. */
6481-
if ((path = branch_checked_out(decoration->name))) {
6502+
if ((path = branch_checked_out(ref))) {
64826503
item->command = TODO_COMMENT;
64836504
strbuf_commented_addf(ctx->buf, comment_line_str,
64846505
"Ref %s checked out at '%s'\n",
6485-
decoration->name, path);
6506+
ref, path);
64866507
} else {
64876508
struct string_list_item *sti;
64886509
item->command = TODO_UPDATE_REF;
6489-
strbuf_addf(ctx->buf, "%s\n", decoration->name);
6510+
strbuf_addf(ctx->buf, "%s\n", ref);
64906511

64916512
sti = string_list_insert(&ctx->refs_to_oids,
6492-
decoration->name);
6493-
sti->util = init_update_ref_record(decoration->name);
6513+
ref);
6514+
sti->util = init_update_ref_record(ref);
64946515
}
64956516

64966517
item->offset_in_buf = base_offset;
@@ -6501,6 +6522,8 @@ static int add_decorations_to_list(const struct commit *commit,
65016522
decoration = decoration->next;
65026523
}
65036524

6525+
strbuf_release(&update_ref);
6526+
free(head_ref);
65046527
return 0;
65056528
}
65066529

t/t3404-rebase-interactive.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1978,7 +1978,7 @@ test_expect_success '--update-refs ignores non-branch decorations' '
19781978
test_cmp expect actual
19791979
'
19801980

1981-
test_expect_failure '--update-refs skips branch symrefs to current branch' '
1981+
test_expect_success '--update-refs skips branch symrefs to current branch' '
19821982
test_when_finished "
19831983
test_might_fail git rebase --abort &&
19841984
git checkout primary &&

0 commit comments

Comments
 (0)