]> git.ipfire.org Git - thirdparty/git.git/commitdiff
rebase: ignore non-branch update-refs
authorAbhinav Gupta <mail@abhinavg.net>
Sun, 10 May 2026 22:41:11 +0000 (15:41 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 11 May 2026 00:00:44 +0000 (09:00 +0900)
The following Git configuration breaks git rebase --update-refs:

    [rebase]
        instructionFormat = %s%d

The '%d' format requests all available decorations for a commit,
filling the global decoration table with all of them,
which --update-refs then uses to populate 'update-ref' instructions
in the rebase todo list.

Specifically, this results in the following instruction:

    update-ref HEAD

The todo parser then rejects the instruction:

    error: update-ref requires a fully qualified refname e.g. refs/heads/HEAD
    error: invalid line 3: update-ref HEAD

To fix, ignore decorations that are not local branches
when scanning through the table.

This matches the documented contract:
it moves branch refs under refs/heads/
and leaves display-only decorations (HEAD, tags, etc.) alone.

Verification:
A regression test that fails without this fix is included.

Signed-off-by: Abhinav Gupta <mail@abhinavg.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
sequencer.c
t/t3404-rebase-interactive.sh

index 1f492f8460e23765f0dd04a25d89f0966b24b115..df5906a64e2f0cf1e6ded4b2027779f0b0ec9617 100644 (file)
@@ -6361,8 +6361,14 @@ static int add_decorations_to_list(const struct commit *commit,
                /*
                 * If the branch is the current HEAD, then it will be
                 * updated by the default rebase behavior.
+                * Exclude it from the list of refs to update,
+                * as well as any non-branch decorations.
+                * 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)) {
+               if ((head_ref && !strcmp(head_ref, decoration->name)) ||
+                   (decoration->type != DECORATION_REF_LOCAL)) {
                        decoration = decoration->next;
                        continue;
                }
index e778dd8ae4a6dc5dd91c5f138fd3dd5020364e61..217184fb868330d99353c6618aac2d807033efa4 100755 (executable)
@@ -1954,6 +1954,24 @@ test_expect_success '--update-refs adds commands with --rebase-merges' '
        )
 '
 
+test_expect_success '--update-refs ignores non-branch decorations' '
+       test_when_finished "git branch -D update-refs" &&
+       test_when_finished "git checkout primary" &&
+       git checkout -B update-refs no-conflict-branch &&
+       (
+               set_cat_todo_editor &&
+
+               # rebase.instructionFormat=%d loads normal log decorations before
+               # --update-refs adds its branch placeholders so we must ignore
+               # all non-local decorations.
+               test_must_fail git -c rebase.instructionFormat="%s%d" \
+                       rebase -i --update-refs HEAD^ >todo
+       ) &&
+       grep ^update-ref todo >actual &&
+       test_write_lines "update-ref refs/heads/no-conflict-branch" >expect &&
+       test_cmp expect actual
+'
+
 test_expect_success '--update-refs updates refs correctly' '
        git checkout -B update-refs no-conflict-branch &&
        git branch -f base HEAD~4 &&