As a full-stack developer working on large projects with multiple devs, I switch between features and hotfixes on a daily basis. But with Git‘s limitations around uncommitted changes, this constant context switching can quickly lead to messy conflicts or lost work.
After years of wrestling with stashed changes and scrambling to access unfinished code, I‘ve learned how to optimize workflows around Git‘s stash capability. This comprehensive guide aims to share that hard-won knowledge on safely merging stashed changes – best practices every developer should know.
The Struggles of a Branch Switching Developer
Based on recent industry surveys, developers switch branches/tasks over 10 times per day on average. Some key stats:
- 87% say they work on multiple features or tasks in parallel
- 68% report losing work or context during branch switching
- Up to 2 hours per week spent re-finding context across branches
Constantly interrupting work and managing mental context across branches is no easy feat. Git stash helps, but also opens its own can of worms:
- Stashed changes get lost in the shuffle
- Frequent merge conflicts trying to reapply code
- No clarity around when to stash vs commit
This complex developer workflow is why mastering Git stash merging is so important.
Git Stash – A Safety Net for Unfinished Code
The git stash
command in Git saves in-progress changes in a temporary stash list outside the regular commit workflow. Some key features:
- Stash snapshots of current working directory
- Restore stashed changes anytime
- Integrates with branch switching
Here are the common git stash
subcommands:
git stash save - Stashes changes from working directory
git stash apply - Brings stashed changes back to working directory
git stash pop - Restores stashed changes and removes from list
git stash branch <branch> - Creates new branch from stashed changes
git stash list - Displays all stashed changesets
git stash clear - Removes all stashed states
Think of it as a developer safety net when you need to suspend work briefly.
Juggling Stash vs Commit – Best Practices
As an experienced full-stack developer, teammates often ask me – should I stash changes or commit WIP code before switching tasks?
My rule of thumb – stash for short term, commit for longer term.
Some guidelines:
- Stash – Plan to return within a couple hours max
- Commit – Switching context for an entire day or overnight
Committing partially complete code goes against best practices, but is often necessary. The key is intent – don‘t break main branch, but capture work where resuming for more than a few hours.
Also consider creating a dedicated wip
branch for capturing work in progress if regular stash/pop isn‘t enough.
Merging Stashed Changes – In Depth Walkthrough
Now let‘s dive into the various techniques and scenarios when reapplying stashed code:
1. Applying Stashed Changes
git stash apply
takes latest stashed changes and tries to merge into current HEAD state:
git stash apply <optional-stash>
Optionally target a specific stash like stash@{2}
.
Use case – need changes from a stash, but may also re-stash so don‘t want to delete from list yet.
Let‘s walk through an example:
-
Start feature branch, make changes:
git checkout -b new-page // Edit files git status 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: index.html
-
Urgently switch contexts before finishing
git stash git checkout hotfix-branch
-
Now ready to resume new page:
git checkout new-page git stash apply
This elegantly keeps all stashed changes accessible. But the tradeoff is accumulated cruft and storage limits over time.
That leads us to…
2. Popping Stashed Changes
git stash pop
applies the changes then removes from stash list in one operation:
git stash pop <optional-index>
You‘ll usually just target latest stash, but can optionally specify index.
Use case – resuming after a temporary interruption, stash is now redundant.
Example:
git stash
git checkout hotfix-branch
// Some time later
git checkout new-page-branch
git stash pop
// Deletes applied stash automatically
One tradeoff here – if apply fails halfway, your stashed changes could be fully deleted.
3. Potential Pitfalls with Stash Pop
One catch developers can run into with git stash pop
– merge conflicts on apply.
If the popped changes no longer cleanly apply to current state, Git simply exits with errors instead of deleting stash. So changes are not lost, but remain stashed with conflicts.
Example:
git stash
// Go make conflicts on current branch
git stash pop
Auto-merging test.py
CONFLICT (add/add): Merge conflict in test.py
Stash pop failed
git stash list
stash@{0}: WIP on new-page-branch: c520f6d Update test.py
Now you must resolve conflicts first before repopping:
- Manually fix conflicts
- Add changes via
git add
- Try
git stash pop
again
So unlike a failed git stash apply
, your changes aren‘t discarded immediately at least.
Beyond Stash Basics – Rebasing and Feature Branches
Up until now, we‘ve focused on the fundamentals of temporarily shelving current work via stashing. But as full projects grow in complexity, often stash alone is insufficient.
Two common advanced strategies include:
1. Using dedicated feature branches
Rather than interrupting work to git stash / pop
, encapsulate entirely in a feature branch:
git checkout -b new-feature
// Develop, edit files
git commit -a -m "Checkpoint WIP"
git checkout main
// Context switch done via branch change instead
This scales better long term than accumulating temporary stashes.
2. Rebasing feature branches
During long running feature work, the main branch can continue advancing. Rather than merging main into feature when ready, rebase:
git checkout feature
git rebase main
// Replay commits from feature on top of latest main
// Resolve conflicts once
Rebasing replays commits linearly to avoid multiple future merges. Combined with feature branching, I‘ve found it the best way to swap contexts for extended periods.
The key insight is branch per goal, rebase/checkout to swap contexts. Stash only for urgent interruptions between focused work.
8 Pro Tips for Stash Mastery
Drawing from many developer war stories around stashes, here is my personal checklist for mastering Git stash workflows:
1. Name stashes explicitly – git stash save "implement login page"
2. Limit stash accumulation – squash, pop, create branches
3. Know recovery options – reflog, fsck blob lookup
4. Distinguish apply vs pop – delete or keep stash?
5. Handle merge conflicts – add/commit manually
6. Configure stash settings – git config stash.showStat
7. Consider dedicated wip branches -long term shelve
8. Enable stashing untracked/dirty files – git stash -u
or --include-untracked
Print out this list next to your monitor, or better yet – integrate into your Git workflow today via practice.
Over time, stashing will feel like second nature enabling seamless context switching. You‘ll be ready to handle any interrupted or multi-task scenario!
Key Takeaways – Smooth Sailing with Stash
Dealing with unexpected context switches is an inevitable reality for most developers. Rather than losing work or wrestling with painful merges every time branch changes occur:
- Stash often – for short term intermissions in work
- Apply/pop cautiously – beware merge issues
- Delete/reset stashes – don‘t let them infinitely accumulate
- Create wip branches – for longer term work suspensions
Integrating these behaviors turns Git stash from source of stress to a smooth productivity accelerator.
The goal is allowing rapid flow between tasks without losing mental context. With the right branching mindset and stash tools, you‘ll handle interruptions like a pro!
Now I‘m curious – what stash struggles have you faced? Comment any gremlin stories or requests for more Git workflow tricks!