Skip to content
Back to skills

Git Stash Pop Pulls Unrelated Stash

ASecurity

Diagnose and avoid `git stash pop` pulling in a stale stash from a different branch when the preceding `git stash` was a no-op. Use when: (1) `git stash` reports "No local changes to save" but you `git stash pop` anyway as a reflex; (2) `git stash pop` surfaces files you don't recognize, often with "both modified" merge conflicts in files unrelated to your current work; (3) `git status` after a stash pop shows changes in files from other features / other branches; (4) `git stash list` reveals...

  • 3 stars
  • 0 votes
  • 0 copies
  • 9 views
  • Added September 6, 2026
ai-agentsgobashgit

Works with

  • claude code

Security analysis

A100/100

Scanned September 6, 2026

npx -y skills add wan-huiyan/agent-traffic-control --skill git-stash-pop-pulls-unrelated-stash --agent claude-code

Installs into .claude/skills of the current project.

Are you the author of Git Stash Pop Pulls Unrelated Stash?

Add the live security badge to your README. It updates with every re-scan.

Security grade badge for Git Stash Pop Pulls Unrelated Stash
[![Security: A — Skills Directory](https://www.skillsdirectory.com/api/skills/wan-huiyan-git-stash-pop-pulls-unrelated-stash/badge)](https://www.skillsdirectory.com/skills/wan-huiyan-git-stash-pop-pulls-unrelated-stash)

More formats (shields.io, HTML) on the badges page. Keep it an A: scan every change in CI with Pro.

Download with Pro
SKILL.md
---
name: git-stash-pop-pulls-unrelated-stash
description: |
  Diagnose and avoid `git stash pop` pulling in a stale stash from a different
  branch when the preceding `git stash` was a no-op. Use when: (1) `git stash`
  reports "No local changes to save" but you `git stash pop` anyway as a
  reflex; (2) `git stash pop` surfaces files you don't recognize, often with
  "both modified" merge conflicts in files unrelated to your current work;
  (3) `git status` after a stash pop shows changes in files from other features
  / other branches; (4) `git stash list` reveals stash entries from sibling
  worktrees or older branches. The stash stack is GLOBAL across branches and
  worktrees — it's LIFO and branch-agnostic. Pairing `git stash` / `git stash
  pop` defensively (e.g., before `git checkout -- file`) only works when the
  initial stash actually saved something; otherwise the pop reaches deeper
  into history. Save under user-wide skills.
author: Claude Code
version: 1.0.0
date: 2026-05-15
disable-model-invocation: true
---

# `git stash pop` pulls an unrelated stash when preceding `git stash` was a no-op

## Problem

You defensively wrap a risky operation with `git stash` / ... / `git stash pop`
to preserve in-progress work. The working tree is clean, so `git stash` prints
**"No local changes to save"** and exits 0. Later, `git stash pop` pulls in
modifications from a *different* branch's stash entry — sometimes months old,
sometimes from another worktree, often producing merge conflicts in files you
never touched in this session.

## Context / Trigger Conditions

You'll see one or more of:

- `git stash` immediately echoed **"No local changes to save"**
- `git stash pop` runs without error and announces something like
  `On branch <X>: WIP on <other-branch>: <sha> <commit-msg-from-elsewhere>`
- `git status` afterward shows:
  - Modified or unmerged files you didn't touch
  - `both modified: <path>` for paths from unrelated features
  - Filenames matching files on entirely different branches
- `git stash list` shows entries like `stash@{0}: WIP on feature/sca-polish: ...`
  that reference branches you're not on

## Root Cause

The stash stack is a **global, branch-agnostic, LIFO data structure**, shared
across every worktree of the repo. `git stash pop` always pops `stash@{0}` —
it doesn't care which branch the stash was created on. When `git stash` is a
no-op (clean tree), nothing is pushed onto the stack, so a subsequent
`git stash pop` reaches whatever was on top *before* this session — potentially
unrelated work from another branch, sometimes from months ago.

## Solution

### Prevent

1. **Don't pair `git stash` / `git stash pop` reflexively.** Check the output
   of `git stash` first:
   ```bash
   git stash push -m "session-N defensive snapshot" 2>&1 | tee /tmp/stash-msg
   grep -q "Saved working directory" /tmp/stash-msg && DID_STASH=1 || DID_STASH=0
   # ... do risky thing ...
   [ "$DID_STASH" = "1" ] && git stash pop
   ```
2. **Always use `-m` with `git stash push`** so your stash entries are
   identifiable in `git stash list`.
3. **Audit before popping** when you're unsure:
   ```bash
   git stash list | head -5    # show top of stack
   git stash show -p stash@{0} # full diff
   ```
4. **Use a worktree-scoped stash alternative.** Instead of `git stash`, commit
   to a throwaway branch:
   ```bash
   git checkout -b /tmp/snapshot-$$
   git add -A && git commit -m "snapshot"
   git checkout -
   # later: git cherry-pick /tmp/snapshot-$$ ; git branch -D /tmp/snapshot-$$
   ```

### Recover

If you've already popped an unrelated stash:

1. Identify what changed:
   ```bash
   git status -s
   ```
2. **Unstage everything** (the stash pop may have staged things):
   ```bash
   git reset HEAD
   ```
3. **Discard the popped changes** in files you did NOT intend to touch:
   ```bash
   git checkout -- <file1> <file2> ...
   ```
   For unmerged paths, the same `git checkout -- <file>` works after `git reset`.
4. **Verify clean tree:**
   ```bash
   git status -s         # should be empty
   git stash list        # confirm the stale stash is still there if you need it
   ```
5. **Decide on the stale stash:** if it's from another branch, leave it on the
   stack (someone else may want it). If you're confident it's dead, drop it:
   ```bash
   git stash drop stash@{0}
   ```

## Verification

After preventive measures:
- `git stash` should either successfully save (print
  `Saved working directory and index state ...`) or print "No local changes to
  save" — your conditional pop respects which case occurred.

After recovery:
- `git status -s` returns empty
- Subsequent test runs / builds reflect only your intended changes
- `git log --oneline -5` shows no unexpected new commits

## Example

This session ran into the bug while verifying a base-branch behavior:

```bash
$ git stash                              # working tree was already clean
No local changes to save

$ git checkout origin/release-uk -- tests/test_app_flow.py
$ pytest tests/test_app_flow.py -q

$ git checkout HEAD -- tests/test_app_flow.py
$ git stash pop                          # ← reached into unrelated history
On branch feat/report-bundler
Changes to be committed:
        modified:   deliverables/future_roadmap.html
Unmerged paths:
        both modified:   docs/plans/future_sessions_plan.md
        both modified:   tests/test_ci_core.py
        both modified:   webapp/ci_core.py
        both modified:   webapp/cloud_run_task.py

$ git stash list
stash@{0}: WIP on feature/sca-polish: 498faed feat: P2 Specification Curve ...  # ← old, unrelated branch
```

Recovery:
```bash
$ git reset HEAD
$ git checkout -- deliverables/future_roadmap.html docs/plans/future_sessions_plan.md \
                  tests/test_ci_core.py webapp/ci_core.py webapp/cloud_run_task.py \
                  webapp/cloud_runner.py webapp/research_utils.py webapp/templates/sca_results.html
$ git status -s
# (clean)
```

## Notes

- This applies to **all worktrees of a repo** — the stash stack is shared.
  Don't assume "my worktree" or "my branch" scopes the stash.
- `git stash pop` is **partially destructive on conflicts** — if you can't
  cleanly resolve, prefer `git stash drop stash@{0}` to discard the pop and
  recover from your last commit.
- A safer mental model: **`git stash` and `git stash pop` are not a matched
  pair**. They operate on a stack that exists outside the session.
- If you're inside a long-lived repo with stale stashes, periodically run
  `git stash list` and clean up entries you're done with.
- Related skills: `git-recover-lost-branch` (if a stash drop loses important
  work), `git-worktree` (alternative to stash for inter-worktree state).

## References

- [Git Tools — Stashing and Cleaning (Pro Git)](https://git-scm.com/book/en/v2/Git-Tools-Stashing-and-Cleaning)
- [`git-stash(1)` man page](https://git-scm.com/docs/git-stash) — "The latest stash you created is stored in `refs/stash`; older stashes are found in the reflog of this reference."

Attribution

Is this your skill, or is something wrong with this listing? Request removal or report an issue. Author removals are honored within 72 hours.

Comments

Loading comments…

Newsletter

Get the weekly list of safe new skills, and the ones we pulled.