public inbox for git@vger.kernel.org 
 help / color / mirror / Atom feed
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

  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