Subject: [RFC] stash: let the stash stack live in a configurable ref
Vladimir Sitnikov <[email protected]>
| Newsgroups | org.kernel.vger.git |
|---|---|
| Message-ID | <CAB=Je-GRbyonmkW4qXCuMRQhWcAZE8zc_Xp32hwC1i61bNnjaw@mail.gmail.com> |
Hi,
refs/stash is shared by the main checkout and every linked worktree, so
two worktrees push onto and pop from the same stack. With git 2.52.0:
git init wt-a && cd wt-a
git commit --allow-empty -m base
git worktree add ../wt-b -b b
echo A >file-a && git add file-a
git stash push -m "worktree A: half-finished refactor"
cd ../wt-b
echo B >file-b && git add file-b
git stash push -m "worktree B: unrelated fix"
git stash pop # worktree B's own entry, as expected
git stash pop # worktree A's entry, applied here
After the second pop, wt-b holds both file-a and file-b, and wt-a has an
empty stash and a clean tree. Nothing warned about it, and the entry is
gone from the stack, so wt-a has no way to find out where its changes
went.
This is documented behavior: git-worktree(1) lists refs/bisect,
refs/worktree and refs/rewritten as the per-worktree exceptions, and
refs/stash is not among them. For a human who drives one worktree at a
time it is mostly harmless, and sharing is occasionally useful - stash
in one worktree, apply in another, as a way to move work across
checkouts.
What changed is who runs these commands. Running one coding agent per
worktree, against one repository, has become a common setup, and the
agents stash and pop on their own schedule. The failure above then
turns into silent data movement between unrelated sessions. The same
report has already been filed against at least two such tools:
https://github.com/github/copilot-cli/issues/1725
https://github.com/stablyai/orca/issues/13695
I would like to propose a configuration knob rather than a new concept,
because most of the machinery is already in the tree:
- refs/worktree/* is per-worktree, so a private stack has somewhere
to live;
- `git stash export --to-ref` and `git stash import` already read and
write a stash stack under an arbitrary ref;
- extensions.worktreeConfig and `git config --worktree` already give
a worktree its own configuration.
The missing piece is telling stash itself which ref to use. Say
stash.ref, defaulting to refs/stash, honored by push, save, list,
show, pop, apply, drop, branch and clear. A worktree that wants
isolation then asks for it once:
git config extensions.worktreeConfig true
git config --worktree stash.ref refs/worktree/stash
Nothing changes for anyone who does not set it, and the tools that
manage worktrees for agents can set it when they create a worktree.
Alternatives I considered and rejected:
- Making the stash per-worktree unconditionally. It breaks the
stash-here-apply-there workflow, and it moves existing entries out
from under scripts. If that is the destination, it belongs in
Documentation/BreakingChanges.adoc for Git 3.0, with a warning
released first - but it does not have to block a knob today.
- Named stashes. A name that survives a push by another process is
what a ref already is, so this would grow a second naming scheme
over the one branches and tags already use, plus commands to list
and delete those names.
- Leaving it to tooling. It works - `git stash create` writes a
stash commit without touching any ref, so a wrapper can store it
under refs/worktree/<name> and apply it later - but every tool
reimplements it, and the failure mode for anyone who does not is
silent.
Points I am not sure about, and where I would like guidance before
writing a patch:
- Whether stash.ref is the right name, and whether it should be
restricted to refs/ (rejecting a value that is not a ref name).
- Whether `git stash list` should be able to show the other stacks -
a worktree's entries becoming invisible to the main checkout is the
cost of the knob, and `git stash list --all` over
worktrees/*/refs/worktree/stash might be a reasonable answer.
- Reachability. fsck and reflog expiry learned to iterate
per-worktree refs, and I would like a second opinion on whether
stash entries under refs/worktree/* are safe from gc in the same
way refs/stash entries are.
If the direction sounds reasonable, I am happy to write the patch.
Thanks,
Vladimir Sitnikov