Git, the popular distributed version control system, that offers developers a multitude of powerful commands to efficiently manage their codebases, which is also a cornerstone of modern DevOps workflows. One such command that plays a crucial role in the daily workflow of developers and DevOps professionals is ‘Git Stash’. As a developer, you’re probably familiar with scenarios where you need to switch branches or save your changes temporarily without committing them. That’s where Git Stash comes into play, providing a convenient solution to store your work-in-progress without cluttering your commit history. In this comprehensive guide, we’ll delve into the intricacies of the Git Stash command, exploring its syntax, various options, and real-world use cases. Whether you’re a seasoned Git expert or just starting your journey into version control, this article will equip you with the knowledge to leverage Git Stash effectively and streamline your development process.
- Note: This article uses
git version 2.30.1
Stashing on-going work
- With
git stash
command, you can save the uncommitted changes (both staged and unstaged), separately for later use, and then revert them from your working copy.
$ git status
On branch main
Changes to be committed:
new file: new_class.cpp
Changes not staged for commit:
modified: new_class.hpp
$ git stash
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
nothing to commit, working tree clean
- With this, you’re now free to make changes, create new commits, switch branches, and perform any other Git operations; then come back and re-apply your stash whenever necessary.
- A stash is local to your Git repository; stashes are not transferred to the server when you push.
Re-Applying & Deleting stashed changes
- You can reapply previously stashed changes with
git stash pop
: - Pop operation removes the changes from your
stash list
and reapplies them to the working copy.
$ git status
On branch main
nothing to commit, working tree clean
$ git stash pop
On branch main
Changes to be committed:
new file: new_class.cpp
Changes not staged for commit:
modified: new_class.hpp
Dropped refs/stash@{0} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)
Re-Applying but Keeping stashed changes in stash list
- Alternative to
stash pop
operation, you can reapply the stashed changes to the working copy and also keep them in thestash list
withgit stash apply
. - This is useful if you want to apply the same stashed changes to multiple branches. For example, some configuration settings used for build & deployment.
$ git stash apply
On branch main
Changes to be committed:
new file: new_class.cpp
Changes not staged for commit:
modified: new_class.hpp
Re-apply a specific stash
- Get the stash version using
git stash list
. - And just specify this version while using
git stash apply <version>
as:$ git stash apply stash@{2}
Stashing Untracked & ignored files
- By default Git won't stash changes made to untracked or ignored files.</b>
git stash
only stash:- Staged changes: that have been added with
git add
command. - Unstaged changes: that are made to files that are currently tracked by Git.
- Staged changes: that have been added with
git stash
does not stash:- New files in your working copy that have not yet been staged with
git add
command. - Files that have been ignored in
.gitignore
files.
- New files in your working copy that have not yet been staged with
$ touch README.md
$ git status
On branch main
Changes to be committed:
new file: new_class.cpp
Changes not staged for commit:
modified: new_class.hpp
Untracked files:
README.md
$ git stash
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
Untracked files:
README.md
- Adding the
-u
or--include-untracked
option tellsgit stash
to also stash your untracked files:
$ git status
On branch main
Changes to be committed:
new file: new_class.cpp
Changes not staged for commit:
modified: new_class.hpp
Untracked files:
README.md
$ git stash -u
Saved working directory and index state WIP on main: 5002d47 our new homepage
HEAD is now at 5002d47 our new homepage
$ git status
On branch main
nothing to commit, working tree clean
- Use
-a
or--all
option to include ignored files as well ingit stash
.
Multiple Stashes
- You can run
git stash
several times to create multiple stashes, and then usegit stash list
to view them. - By default, stashes are identified simply as a “WIP” – work in progress – on top of the branch and commit that you created the stash from.
$ git stash list
stash@{0}: WIP on main: 5002d47 our new homepage
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 5002d47 our new homepage
Rename a Git Stash
- Before Renaming the stash, you must remove the stash entry which you want to rename using as:
$ git stash drop stash@{1} Dropped stash@{1} (feb72485026d71f7363983c886d6e66d1b5f40f2)
- Then add it again with new message using sha of commit returned after dropping:
$ git stash store -m "Renamed Git Stash" feb72485026d71f7363983c886d6e66d1b5f40f2
- Check the renamed stash:
$ git stash list stash@{0}: WIP on main: 5002d47 our new homepage stash@{1}: Renamed Git Stash stash@{2}: WIP on main: 5002d47 our new homepage
Save Stashes with custom messages
- If you create multiple stashes to backup different work-in-progress items, after a while it will be difficult to remember what each stash contains.
- So, to provide a bit more context, it’s good practice to annotate your stashes with a description, using
git stash save "message"
:
$ git stash save "add style to our site"
Saved working directory and index state On main: add style to our site
HEAD is now at 5002d47 our new homepage
$ git stash list
stash@{0}: On main: add style to our site
stash@{1}: WIP on main: 5002d47 our new homepage
stash@{2}: WIP on main: 5002d47 our new homepage
- By default,
git stash pop
will re-apply the most recently created stash:stash@{0}
. - You can choose which stash to re-apply by passing its identifier as the last argument, for example:
$ git stash pop stash@{2}
Viewing what’s in a stash
- You can view a summary of a stash with
git stash show
:
$ git stash show
index.html | 1 +
style.css | 3 +++
2 files changed, 4 insertions(+)
- Pass the
-p
or--patch
option to view the full diff of a stash:
$ git stash show -p
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..d92368b
--- /dev/null
+++ b/style.css
@@ -0,0 +1,3 @@
+* {
+ text-decoration: blink;
+}
diff --git a/index.html b/index.html
index 9daeafb..ebdcbd2 100644
--- a/index.html
+++ b/index.html
@@ -1 +1,2 @@
+<link rel="stylesheet" href="style.css"/>
Stash files or changes in files selectively
- You can also choose to stash just a single file, a collection of files, or individual changes from within files.
git stash
with-p
option (or--patch
) will iterate through each changed “hunk” in your working copy and ask whether you wish to stash it:- Commonly used commands to selectively stash files or changes:
/
- search for a hunk by regex?
- helpn
- don’t stash this hunkq
- quit (any hunks that have already been selected will be stashed)s
- split this hunk into smaller hunksy
- stash this hunk
- Use
CTRL+C
to abort the stashing process.
Create new branch from stash for merging
- If the changes on your branch diverge from the changes in your stash, you may run into conflicts when applying your stash.
- Instead, you can use git stash branch to create a new branch to apply your stashed changes to:
- This checks out a new branch based on the commit that you created your stash from, and then pops your stashed changes onto it.
$ git stash branch add-stylesheet stash@{1}
Switched to a new branch 'add-stylesheet'
On branch add-stylesheet
Changes to be committed:
new file: style.css
Changes not staged for commit:
modified: index.html
Dropped refs/stash@{1} (32b3aa1d185dfe6d57b3c3cc3b32cbf3e380cc6a)
Deleting the stashed changes
- You can delete it with git stash drop:
$ git stash drop stash@{1}
Dropped stash@{1} (17e2697fd8251df6163117cb3d58c1f62a5e7cdb)
- Or you can delete all of your stashes with:
$ git stash clear
Git Stash - under the hood
- Stashes are actually encoded in your repository as commit objects.
- The special
ref
at.git/refs/stash
points to your most recently created stash. - Previously created stashes are referenced by the stash ref’s reflog. This is why you refer to stashes by
stash@{n}:
you’re actually referring to the nth reflog entry for the stash ref. - Since a stash is just a commit, you can inspect it with git log:
$ git log --oneline --graph stash@{0}
*-. 953ddde WIP on main: 5002d47 our new homepage
|\ \
| | * 24b35a1 untracked files on main: 5002d47 our new homepage
| * 7023dd4 index on main: 5002d47 our new homepage
|/
* 5002d47 our new homepage
- for further details, please read: How git stash works