Apply or pop a stash without confusing the result

Comparison Last tested 26 October 2026

Applying a stash restores its saved changes while keeping the stash entry; a successful pop restores the changes and removes the entry. If pop conflicts, the entry remains, so a failed restoration does not mean the saved copy disappeared. Choose based on whether you want to retain that saved entry after a successful application.

Decide what should remain afterward

The important comparison has two parts: what appeared in the working files, and whether the saved entry still appears in the stash list. A working file can look correct after either command. Looking only at that file misses the behavior that distinguishes them. In the first two cases below, the restored text is identical, while the number of remaining entries differs.

Start with apply when you want a separate inspection step before deciding that the stash is no longer needed. That choice makes the remaining entry visible rather than treating its removal as part of restoration. Pop combines those actions when application succeeds. Neither choice establishes that the restored changes are correct for the current branch; that judgment still needs a diff and the project’s checks.

Before restoring real work, inspect the current working and staged changes, identify the intended stash entry, and read its contents. Do not identify an entry only by its number if another stash has been added or removed since you last looked. The numbered positions can change as the list changes. A descriptive message helps distinguish similar entries, but the actual saved changes are what matter.

Run four separate cases

The original example creates four repositories beneath one new directory. Each starts with the same two committed files. The first pair differs only in whether it uses apply or pop. The third deliberately creates a conflict, and the fourth separates a staged version from a later working edit. Run the script in an empty directory with Git 2.56.0 available; it refuses an existing example directory.

Download the exact MIT-licensed example. The printed code and downloadable file are identical.

#!/bin/sh
# SPDX-License-Identifier: MIT
set -eu
export TZ=UTC LC_ALL=C
export GIT_CONFIG_NOSYSTEM=1 GIT_CONFIG_GLOBAL=/dev/null
export GIT_AUTHOR_NAME='Example Author'
export GIT_AUTHOR_EMAIL='author@example.invalid'
export GIT_COMMITTER_NAME='Example Author'
export GIT_COMMITTER_EMAIL='author@example.invalid'
export GIT_AUTHOR_DATE='2026-10-25T12:00:00Z'
export GIT_COMMITTER_DATE='2026-10-25T12:00:00Z'
test "$(git --version)" = 'git version 2.56.0'
mkdir stash-example
cd stash-example
new_case() {
  mkdir "$1"
  cd "$1"
  git -c init.templateDir= init -q -b main
  printf 'base\n' > note.txt
  printf 'original\n' > other.txt
  git add note.txt other.txt
  git commit -qm 'Base'
}
new_case apply
printf 'saved change\n' > note.txt
git stash push -qm 'Saved change'
git stash apply -q
test "$(cat note.txt)" = 'saved change'
test "$(git stash list | wc -l | tr -d ' ')" = 1
printf 'apply: change restored; one stash remains\n'
cd ..
new_case pop
printf 'saved change\n' > note.txt
git stash push -qm 'Saved change'
git stash pop -q
test "$(cat note.txt)" = 'saved change'
test -z "$(git stash list)"
printf 'pop: change restored; no stash remains\n'
cd ..
new_case conflict
printf 'saved change\n' > note.txt
git stash push -qm 'Saved change'
printf 'committed change\n' > note.txt
git commit -qam 'Different change'
printf 'unrelated edit\n' > other.txt
if git stash pop -q > pop-output.txt 2>&1; then
  printf 'Expected a conflict\n' >&2
  exit 1
else
  result=$?
fi
test "$result" = 1
test "$(git stash list | wc -l | tr -d ' ')" = 1
test -n "$(git ls-files -u -- note.txt)"
printf 'conflict: exit 1; stash remains\n'
printf 'combined decision\n' > note.txt
git add --resolved -- note.txt
test -z "$(git ls-files -u -- note.txt)"
test -n "$(git diff --cached -- note.txt)"
test -z "$(git diff --cached -- other.txt)"
test "$(cat other.txt)" = 'unrelated edit'
printf 'resolved: selected conflict staged; unrelated edit unstaged\n'
test "$(git show :note.txt)" = 'combined decision'
git diff --cached -- note.txt
git diff -- other.txt
git stash list
# The sole retained entry was checked in this isolated example.
git stash drop -q 'stash@{0}'
test -z "$(git stash list)"
printf 'checked resolution: retained stash deliberately dropped\n'
cd ..
new_case indexed
printf 'staged\n' > note.txt
git add note.txt
printf 'staged\nworking\n' > note.txt
git stash push -qm 'Two states'
git stash apply --index -q
test "$(git show :note.txt)" = 'staged'
test "$(cat note.txt)" = "$(printf 'staged\nworking')"
printf 'index: staged and later working edits restored separately\n'

Case one: keep the saved entry

In the apply repository, the first line of note.txt changes from the committed base to the saved change. The stash operation temporarily puts the committed version back. Applying the saved entry then restores the edited text. The script checks both that text and a stash count of one before printing its result.

Those checks answer different questions. The content assertion establishes that this example’s saved edit returned. The count assertion establishes that the saved entry was retained. Neither checks a remote repository, a build result or whether the edit belongs in the current task. Treat a successful application as a state change to review, not as a completed development decision.

The official Git 2.56.0 documentation distinguishes apply by its retained entry1. The practical reason to care is that review can happen before cleanup. If a later check reveals that the restored edit is unsuitable, the saved entry is still listed. This example does not delete it as part of proving that behavior.

Case two: remove the entry after success

The pop repository begins independently, so it cannot accidentally reuse the first case’s restored files or stash list. It saves the same edit, pops it, checks the file, and verifies that the stash list is empty. That is the successful path: restored work remains in the working directory and the corresponding saved entry no longer appears in the list.

This is why running apply followed immediately by pop is not a fair comparison on the same unchanged working tree. The first application has already changed that tree. A second application can encounter content that was not present at the start of the first operation. Independent starting states make the difference visible without asking readers to mentally undo an earlier command.

Case three: a conflicting pop retains the entry

The conflict repository saves one replacement line, then commits a different replacement to the same line. It also adds an unrelated edit to other.txt. Popping the saved change returns a conflict. The example checks the nonzero result, the remaining stash entry and the unresolved index entry; it does not equate an error message with lost work.

Inspect the files and status before deciding how to resolve a real conflict. A retained stash entry is useful evidence of what was saved, but it does not choose between competing edits. In this fictional case the resolution text is supplied explicitly. No general resolution rule is inferred from that chosen text.

Git 2.56.0’s git add --resolved is marker-based2. Here it stages the explicit path after its markers are replaced, while the unrelated edit stays unstaged. Binary and deletion conflicts can have no markers without being correctly resolved; decide those yourself and check git diff --cached before committing.

After checking the resolution, working diff and retained stash entry, remove only that entry with git stash drop1. The isolated example checks its sole entry and drops 'stash@{0}'; in real work, identify the intended entry again before dropping it. A conflicting pop keeps the entry until this deliberate cleanup.

Case four: preserve the staged boundary

The final repository first stages one line, then adds another line only to the working file. After saving that two-part state, it applies the stash with the option that attempts to reinstate the index. The assertions compare the staged content and the working content separately. They establish that both versions returned in this clean example.

This matters when a partially prepared commit should remain partially prepared. “The changes came back” is too vague if the next commit must include only the earlier portion. The staged and working diff guide shows how to inspect those two comparisons without treating the latest file on disk as the staged version.

Finish with an inspection decision

After restoration, decide whether the content, staged boundary and current task all agree. If they do not, stop before adding unrelated changes or removing the remaining stash. Keep the question narrow: which state needs to change next? The command explorer separates restoration, staging and history changes so their warnings remain attached to the operation being considered.

Not covered on this page

Sources

  1. git-stash — Git 2.56.0. ↩ ↩2

  2. git-add — Git 2.56.0. ↩

How we test: methodology. Found a mistake? Corrections.