git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[BUG] stash.index=true leaves a redundant stash entry after an autostash fast-forward

From
Eli Barzilay <eli@barzilay.org>
Date
Sep 7, 2026, 04:44 UTC
Message-ID
<CALO-guvbk2TcrVwzdNQ3yRpzHr0HHZ3h1wite0Xp0sUyAT4otA@mail.gmail.com>

Disclaimer, the following is written by an agent, but the bug is a real problem that I have.

With stash.index=true, an autostash that is applied successfully is nevertheless stored as a stash entry, and deleting MERGE_AUTOSTASH fails. A staged change at the time of the merge is required to trigger it.

Reproduction (independent of the reporter's configuration):
    #!/bin/sh
    set -e
    export GIT_AUTHOR_NAME=A GIT_AUTHOR_EMAIL=a@b \
           GIT_COMMITTER_NAME=A GIT_COMMITTER_EMAIL=a@b
    rm -rf /tmp/gitbug && mkdir /tmp/gitbug && cd /tmp/gitbug
    git init -q -b main up
    cd up && echo a >u && echo z >z && git add . &&
        git commit -qm base && cd ..
    git clone -q up dn
    cd up && echo more >>u && git commit -qam up2 && cd ../dn
    echo staged >>z && git add z          # a STAGED change is required
    git fetch -q origin
    git -c stash.index=true merge --ff-only --autostash origin/main
    echo "--- git stash list:"; git stash list
Actual output:
    Updating 34a5e40..84ccd9d
    Created autostash: 71d4617
    Fast-forward
     u | 1 +
     1 file changed, 1 insertion(+)
    Applied autostash.
    error: cannot lock ref 'MERGE_AUTOSTASH': unable to resolve
reference 'MERGE_AUTOSTASH'
    --- git stash list:
    stash@{0}: autostash
Expected: the same without the error and with an empty stash list, as
happens with stash.index=false (the only change to the script).

The autostash is applied correctly, so nothing is lost: the leftover entry duplicates what is already in the working tree and index. The command also exits 0, so the error is easy to miss, and the entries accumulate one per merge.

Reported via `git merge` above for brevity, but the common way to meet this is `git pull` with rebase.autoStash and pull.rebase set: when the pull can fast-forward, builtin/pull.c:1164 hands off to `git merge --ff-only --autostash` rather than to rebase. Every such pull with something staged leaves an entry behind.

Analysis --------

Merge keeps its autostash in the MERGE_AUTOSTASH ref (builtin/merge.c:1675) and applies it from finish() (builtin/merge.c:540). apply_save_autostash_ref() resolves the ref, applies it, and then deletes it (sequencer.c:4821-4848).

The apply is a child process, `git stash apply <oid>` (sequencer.c:4737-4751). stash.index turns that into an --index apply, which takes the index-restoring branch of do_apply_stash() and calls reset_head() (builtin/stash.c:684-691), i.e. a `git reset --quiet --refresh` child (builtin/stash.c:455-467).

That reset has no pathspec, so it calls remove_branch_state() (builtin/reset.c:543) -> remove_merge_branch_state() (branch.c:829-838), whose last statement is

    save_autostash_ref(r, "MERGE_AUTOSTASH");

which stores the autostash into refs/stash and deletes the ref -- in the middle of the very apply that was about to consume it. Control returns to apply_save_autostash_ref(), the apply reports success ("Applied autostash."), and its refs_delete_ref() then fails on a ref that is already gone, producing the error line.

The child's own explanation, "Autostash exists; creating a new stash entry." (sequencer.c:4775-4779), never reaches the user because the parent mutes the apply child's output (sequencer.c:4736-4738).

A staged change is required because with a clean index the stash's base and index trees are equal, has_index is cleared (builtin/stash.c:665-668), and reset_head() is never reached.

The rebase backend is unaffected: it keeps its autostash in the file .git/rebase-merge/autostash, which remove_merge_branch_state() does not touch. Only the merge (ref-based) autostash is exposed.

Possible directions, in case they are useful: remove_merge_branch_state() is about ending a merge, and `git stash apply --index` is not ending one -- having stash's reset_head() avoid the branch-state cleanup, or teaching an in-flight autostash apply to shield MERGE_AUTOSTASH, would both close it. Making apply_save_autostash_ref() tolerate a missing ref would silence the error but leave the duplicate entry.

Versions --------

Seen with git 2.55.0 on Linux (WSL2). The code paths above are unchanged on master as of 2026-09-07.

-- 
                 ((x=>x(x))(x=>x(x)))                  Eli Barzilay:
                 http://barzilay.org/                  Maze is Life!
Next: D. Ben Knoble
Message 1 of 12 in “[BUG] stash.index=true leaves a redundant stash entry after an autostash fast-forward”
  1. Eli BarzilaySep 7, 2026
  2. D. Ben KnobleSep 15, 2026
  3. Phillip WoodSep 16, 2026
  4. Ben KnobleSep 16, 2026
  5. Eli BarzilaySep 16, 2026
  6. D. Ben KnobleSep 17, 2026
  7. Phillip WoodSep 17, 2026
  8. D. Ben KnobleSep 17, 2026
  9. Phillip WoodSep 17, 2026
  10. Phillip WoodSep 19, 2026
  11. D. Ben KnobleSep 19, 2026
  12. D. Ben KnobleSep 19, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.