Git stashing allows developers to temporarily shelf and restore uncommitted changes – a invaluable technique for collaborating with others, reviewing code, testing, and handling interruptions. This comprehensive guide will elaborate on unshelving, including:
- Core concepts like the stash list
- Specific step-by-step examples
- How stashing compares to alternatives
- Advanced application like merges
- Best practices for avoiding pitfalls
- When unshelving can cause conflicts
- How to resolve conflicts when unstashing
- Key takeaways for learning the process
Whether you are new to Git or an experienced practitioner, this guide aims to provide deeper technical insight into stashing and unshelving workflows.
What is the Stash List in Git?
The stash list maintains a stack-based record of all changesets captured during git stash save operations. New stashes get pushed onto the top at stash@{0}:
$ git stash list
stash@{0}: WIP on feature/report-generator
stash@{1}: On master: Updated readme
Internally, stashes reside under .git/refs/stash. Each stash ref saves 3 trees recording the pre-stash state, changes to the index/staging area, and changes to the working tree:
.git/
└─ refs/
└─ stash
├─ stash@{0}
│ ├─ pre-state-tree
│ ├─ index-tree
│ └─ working-tree
└─ stash@{1}
├─ pre-state-tree
├─ index-tree
└─ working-tree
Note only the pre-stash tree gets committed to the regular repository history during stash creation. The other two trees remain isolated from the commit DAG as implementation details purely for restoring state.
Fig 1. Overview of stash creation and application lifecycle
Now that you understand the stash data structure, let‘s see how to leverage stashing/unshelving in practice.
Why Stash Changes Instead of Using Feature Branches?
Developers commonly utilize feature branches for encapsulating work-in-progress code as well. Feature branches act as partitions that isolate development. What advantages does stashing offer over long-lived branches?
Isolating experiments: Stashing allows quick capture of transient changes for ethnography or prototyping – no need to pollute history with throwaway branches.
Reduced overhead: Creating and merging branches introduces overhead from resolving naming conflicts or keeping branches up-to-date. Stash operations are atomic metadata manipulations rather than full commits.
Lower storage: Stashes consume negligible disk space unlike potentially massive feature branch commits bloating .git.
In summary, stashing shines for short-term isolation. Lean on branches for long-running, substantial workstreams.
When Should You Stash Changes?
Let‘s explore several common scenarios where stashing uncommitted changes shines:
Task switching: Shelve in-flight work before jumping onto higher priorities using:
git stash push -m "WIP: Payment form styling"
Collaborating: Stash experimental or unfinished work to share a clean branch:
git stash push -u -m "prototype: automl module"
git checkout feature/reports
The -u flag stashes and removes untracked files in a single step.
Testing: Stow UI changes to diagnose a system regression:
git stash push
mvn test // build application and run test suite
git stash pop
Pausing: Temporarily stash incremental progress when forced to context switch:
// Friday afternoon
git stash push
// Monday morning
git stash pop
These scenarios demonstrate stashing‘s versatility. Next let‘s break down implementation step-by-step.
Step-By-Step Guide to Stash Changes
Stashing in Git checks out the current branch to a pristine state, stages modifications, removes untracked files, and records metadata – atomically in a single command.
Here is how to easily stash changes:
1. Inspect progress
Always start by reviewing changes about to be stashed:
➜ git status
On branch feature/dashboard
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
modified: src/charts.js
modified: src/config.yaml
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
modified: src/index.html
Untracked files:
(use "git add <file>..." to include in what will be committed)
src/assets/img/
This repo has a mix of staged changes, unstaged changes, and untracked files.
2. Execute git stash push
➜ git stash push -m "Stash dashboard layout experiment"
Saved working directory and index state WIP on feature/dashboard: Dashboard layout experiment
Git stashes all 3 categories of changes and cleans up the working tree.
3. Verify working tree is clean
Double check git status to confirm the stash worked properly:
➜ git status
On branch feature/dashboard
nothing to commit, working tree clean
Success! The push subcommand bundles all progress on feature/dashboard into a shelved changeset.
When Do You Unshelve Changes?
Now those changes reside tucked away safely in the stash list rather than the active file system. When should you restore them?
Resuming work: Unstash after handling interruptions to pick up right where you left off:
➜ git stash pop
Reviewing progress: Apply stashes to share unfinished features or review incremental work.
Discarding experiments: Popping and immediately dropping stashes constitutes a simple undo mechanism.
Debugging builds: Extract modifications necessary to reproduce an issue after stashing non-essential adjustments.
Maintaining context: Jumping around long-running branches can lose surrounding awareness. Stashes preserve tribal knowledge.
Next let‘s demonstrate actually unshelving changes…
Unshelving the Latest Stash
Restoring the most recently created stash is straightforward:
git stash pop # apply latest stash
# OR
git stash apply stash@{0} # use explicit reference
By default this tries merging changes back into the working tree. Use git stash apply for a less destructive restore.
Fig 2. Unshelving the most recent stash from index 0.
Note this does not remove anything from the stash list itself. Changes are extracted out normally.
Unshelving Specific Older Stashes
The stash list tracks push order with older stashes sinking towards the bottom. Reference any stash by inserting its ID:
➜ git stash list
stash@{2}: WIP on new-payment-service: 81250b0 Configure Stripe webhook
stash@{1}: On production: 750b2f0 Hotfix - increase cache TTL to 10 minutes
stash@{0}: On master: 5001020 Updated contributing guidelines
git stash apply stash@{2} # apply oldest stash
Traveling further back in history unstashes older lines of development!
Partially Unshelving Changes
The pop and apply commands work on whole stashes. But git also supports interactively choosing individual file hunks to re-apply:
git stash pop -p # choose hunks interactively
diff --git a/src/index.html b/src/index.html
+<<<- stash
+ <li>New nav item</li>
```
Apply this hunk to index and worktree [y,n,q,a,d,e,?]?
Answer y to accept or n to reject hunks. This offers granular control for big changesets.
Challenges with Unshelving: Merge Conflicts
What happens if the code base advances while a stash sits suspended in time? The potential arises for merge conflicts.
For example, say feature/dashboard gets developed:
// On feature/dashboard
git stash push # Shelve dashboard experiment
git checkout main
git pull origin main # Pull latest main with dashboard changes
git checkout feature/dashboard
git stash pop
This could produce conflicts like:
Auto-merging src/index.html
CONFLICT (content): Merge conflict in src/index.html
Automatic merge failed; fix conflicts and then commit the result
Git was unable to cleanly merge parallel modifications to the same regions. How should you resolve?
1. Investigate conflicts
Examine the conflict markers pointing out mismatches:
<<<<<<< Updated upstream
<div id="header">
=======
<div id="page-header">
>>>>>>> Stashed changes
2. Resolve each conflict
Manually edit files to remove markers and reconcile changes:
<div id="page-header">
</div>
3. Add resolved files & commit
Stage resolved files then create a merge commit:
git add .
git commit -m "Merged stashed dashboard changes"
Pay careful attention to conflicts. They indicate accidental divergence that needs aligned!
Removing Stashes Safely
As you continually apply and delete stashes, the list gradually fills with obsolete entries. To delete:
git stash clear # remove all but latest
git stash drop stash@{5} # delete single stash
Dropped stashes get PERMANENTLY erased and cannot be recovered!
Proceed carefully and avoid force pushes after deleting commits another dev may have relied on. The reflog serves as a safety net providing roughly 90 days to rescue dropped stashes with git log -g --stat refs/stash.
Alternatively, you can extract diffs to inspect changes first:
git stash show -p stash@{2} > /tmp/experiment.diff
git apply /tmp/experiment.diff
6 Best Practices for Stashing/Unshelving
Let‘s conclude by highlighting key learnings for stashing and unstashing smoothly:
1. Comment stashes with -m messages explaining origins.
2. Limit stash lifetime by regularly unstashing stale entries.
3. Handle conflicts diligently when unstashing parallel work.
4. Delete obsolete stashes to avoid clutter from accumulation.
5. Extract diffs rather than directly applying risky changes.
6. Leverage the reflog to rescue accidentally dropped stashes.
Respecting these best practices will ensure you become a stash master!
Conclusion
Temporary stashing serves a complementary role to long-lived feature branching. Stashes enable developers to easily shelve, share, and restore changes by manipulating Git‘s metadata.
This guide covered the inner workings of the stash list, step-by-step usage examples, challenges like conflicts, and tips for unshelving smoothly. Leveraging stashes unlocks new workflows!
Now put this knowledge into practice with git stash. What other creative applications can you discover?


