From: "Son Luong Ngoc via GitGitGadget" <gitgitgadget@gmail•com>
To: git@vger•kernel.org
Cc: Son Luong Ngoc <sluongng@gmail•com>, Son Luong Ngoc <sluongng@gmail•com>
Subject: [PATCH 2/2] rebase: skip branch symref aliases
Date: Thu, 28 May 2026 05:42:01 +0000 [thread overview]
Message-ID: <0ab0a717441e9fc7c494da194065a948a35a7f01.1779946921.git.gitgitgadget@gmail.com> (raw)
In-Reply-To: <pull.2126.git.1779946921.gitgitgadget@gmail.com>
From: Son Luong Ngoc <sluongng@gmail•com>
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 symref 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>
---
sequencer.c | 63 +++++++++++++++++++++++++++++------
t/t3404-rebase-interactive.sh | 2 +-
2 files changed, 53 insertions(+), 12 deletions(-)
diff --git a/sequencer.c b/sequencer.c
index 1ee4b2875b..4a83d1337c 100644
--- a/sequencer.c
+++ b/sequencer.c
@@ -6445,15 +6445,22 @@ static int add_decorations_to_list(const struct commit *commit,
struct todo_add_branch_context *ctx)
{
const struct name_decoration *decoration = get_name_decoration(&commit->object);
- const char *head_ref = refs_resolve_ref_unsafe(get_main_ref_store(the_repository),
- "HEAD",
+ struct ref_store *refs = get_main_ref_store(the_repository);
+ const char *head_ref = refs_resolve_ref_unsafe(refs, "HEAD",
RESOLVE_REF_READING,
- NULL,
- NULL);
+ NULL, NULL);
+ char *resolved_head_ref = refs_resolve_refdup(refs, "HEAD",
+ RESOLVE_REF_READING,
+ NULL, NULL);
+ struct strbuf update_ref = STRBUF_INIT;
while (decoration) {
struct todo_item *item;
const char *path;
+ const char *ref = decoration->name;
+ const char *resolved_ref;
+ int is_symref = 0;
+ int flags = 0;
size_t base_offset = ctx->buf->len;
/*
@@ -6461,12 +6468,44 @@ static int add_decorations_to_list(const struct commit *commit,
* updated by the default rebase behavior.
* Exclude it from the list of refs to update,
* as well as any non-branch decorations.
+ *
+ * Resolve branch symrefs after checking for the current HEAD so
+ * that aliases do not schedule duplicate updates for their
+ * referents.
+ *
* Non-branch decorations may be present if the pretty format
* includes "%d", which would have loaded all refs
* into the global decoration table.
*/
- if ((head_ref && !strcmp(head_ref, decoration->name)) ||
- (decoration->type != DECORATION_REF_LOCAL)) {
+ if (decoration->type != DECORATION_REF_LOCAL) {
+ decoration = decoration->next;
+ continue;
+ }
+
+ if (head_ref && !strcmp(head_ref, ref)) {
+ decoration = decoration->next;
+ continue;
+ }
+
+ strbuf_reset(&update_ref);
+ resolved_ref = refs_resolve_ref_unsafe(refs, ref,
+ RESOLVE_REF_READING |
+ RESOLVE_REF_NO_RECURSE,
+ NULL, &flags);
+ if ((flags & REF_ISSYMREF) && resolved_ref) {
+ if (!starts_with(resolved_ref, "refs/heads/")) {
+ decoration = decoration->next;
+ continue;
+ }
+
+ strbuf_addstr(&update_ref, resolved_ref);
+ ref = update_ref.buf;
+ is_symref = 1;
+ }
+
+ if ((is_symref && resolved_head_ref &&
+ !strcmp(resolved_head_ref, ref)) ||
+ string_list_has_string(&ctx->refs_to_oids, ref)) {
decoration = decoration->next;
continue;
}
@@ -6478,19 +6517,19 @@ static int add_decorations_to_list(const struct commit *commit,
memset(item, 0, sizeof(*item));
/* If the branch is checked out, then leave a comment instead. */
- if ((path = branch_checked_out(decoration->name))) {
+ if ((path = branch_checked_out(ref))) {
item->command = TODO_COMMENT;
strbuf_commented_addf(ctx->buf, comment_line_str,
"Ref %s checked out at '%s'\n",
- decoration->name, path);
+ ref, path);
} else {
struct string_list_item *sti;
item->command = TODO_UPDATE_REF;
- strbuf_addf(ctx->buf, "%s\n", decoration->name);
+ strbuf_addf(ctx->buf, "%s\n", ref);
sti = string_list_insert(&ctx->refs_to_oids,
- decoration->name);
- sti->util = init_update_ref_record(decoration->name);
+ ref);
+ sti->util = init_update_ref_record(ref);
}
item->offset_in_buf = base_offset;
@@ -6501,6 +6540,8 @@ static int add_decorations_to_list(const struct commit *commit,
decoration = decoration->next;
}
+ strbuf_release(&update_ref);
+ free(resolved_head_ref);
return 0;
}
diff --git a/t/t3404-rebase-interactive.sh b/t/t3404-rebase-interactive.sh
index 42ba8cc313..29447c0fc3 100755
--- a/t/t3404-rebase-interactive.sh
+++ b/t/t3404-rebase-interactive.sh
@@ -1978,7 +1978,7 @@ test_expect_success '--update-refs ignores non-branch decorations' '
test_cmp expect actual
'
-test_expect_failure '--update-refs skips branch symrefs to current branch' '
+test_expect_success '--update-refs skips branch symrefs to current branch' '
test_when_finished "
test_might_fail git rebase --abort &&
git checkout primary &&
--
gitgitgadget
next prev parent reply other threads:[~2026-05-28 5:42 UTC|newest]
Thread overview: 9+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-05-28 5:41 [PATCH 0/2] rebase: handle --update-refs branch symrefs Son Luong Ngoc via GitGitGadget
2026-05-28 5:42 ` [PATCH 1/2] t3404: add failing branch symref test Son Luong Ngoc via GitGitGadget
2026-06-01 13:52 ` Phillip Wood
2026-05-28 5:42 ` Son Luong Ngoc via GitGitGadget [this message]
2026-05-28 7:08 ` [PATCH 2/2] rebase: skip branch symref aliases Kristoffer Haugsbakk
2026-06-01 14:10 ` Phillip Wood
2026-05-28 20:42 ` [PATCH 0/2] rebase: handle --update-refs branch symrefs Junio C Hamano
2026-06-03 10:27 ` [PATCH v2] rebase: skip branch symref aliases Son Luong Ngoc via GitGitGadget
2026-06-04 15:37 ` Phillip Wood
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=0ab0a717441e9fc7c494da194065a948a35a7f01.1779946921.git.gitgitgadget@gmail.com \
--to=gitgitgadget@gmail$(echo .)com \
--cc=git@vger$(echo .)kernel.org \
--cc=sluongng@gmail$(echo .)com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox