Version control is an inseparable part of the daily lives of software developers. It’s hard to imagine any team developing software without using a version control tool. It’s equally hard to imagine any developer who hasn’t worked with (or at least heard of) Git. In the 2018 Stackoverflow developer survey, 87.2% of the 74,298 participants use Git for version control.
Linus Torvalds created git in 2005 to develop the Linux kernel. This article walks through the git stash command and explores some useful options for saving changes. It assumes that you have basic familiarity with Git concepts and a good understanding of the worktree, staging area, and associated commands.
Why is the git stash important?
The first thing to understand is why it’s important to save changes to Git. Let’s assume for a moment that Git doesn’t have a command to save changes. Suppose you are working in a repository with two branches, A and B. Branches A and B have diverged from each other for quite some time and have different heads. While working on some files in branch A, your computer prompts you to fix a bug in branch B. Quickly save changes to A and try to check out branch B with git checkout B. Git immediately aborts the operation and produces the error, “Local changes to the following files would be overwritten by checking out… Please commit your changes or save them before changing branches.”
There are few ways to enable branch switching in this case:
- create a commit at that point in branch A, commit and submit your changes to fix the error in B, then check A again and run git reset HEAD^ to retrieve your changes
- Manually keep changes to files not tracked by Git.
.
The second method is a bad idea. The first method, while it seems conventional, is less flexible because unfinished saved changes are treated as a checkpoint rather than a patch that remains a work in progress. This is exactly the kind of scenario git stoil is designed for.
Git stash saves uncommitted changes locally, allowing you to make changes, change branches, and perform other Git operations. You can then reapply the hidden changes when you need them. A stash has a local scope and is not pushed to the remote using git push.
How to use git stash
Here is the sequence to follow when using
git stash: Save changes to branch A. Run git stash. Take a look at branch B.
- Fix the bug in branch B.
- Confirm and (optionally) push to remote
- Check
- A Run branch
- pop to retrieve your saved
- in the
- .
.
out the
git stash
changes. Git stash stores changes made
working directory locally (inside your project’s .git directory; /
git/refs/stash, to be precise) and allows you to retrieve changes when you need them. It’s useful when you need to switch between contexts. It allows you to save the changes you may need at a later stage and is the fastest way to clean up your working directory while keeping the changes intact.
How to create a
stash
The simplest command to save changes is git stash: $ git
stash Saved working directory and WIP index status in master; d7435644 Feat: Configure the graphql endpoint
By default, git stash stores (or “stashes”) uncommitted changes (preconfigured and non-staging files) and ignores untracked and ignored files. There’s usually no need to save untracked and ignored files, but sometimes they can interfere with other things you want to do in your codebase.
You can use additional options to allow git stash
to take care of
untracked and ignored files: git stash -u or git stash -include-untracked stash untracked files. git stash –
- a or git stash –
- hidden files not tracked and files ignored.
all
To save specific files, you can use the
git stash -p or git stash -patch: $ git stash -patch diff -git a/.gitignore b/.gitignore index 32174593..8d81be6e 100644 – a/.gitignore +++ b/.gitignore @@ -3.6 +3.7 @@ # dependencies node_modules/ /.pnp +f,fmfm .pnp.js # testing (1/1) Save this chunk [y,n,q,a,d,e,?]?
List
your stash
You can view your stash with the git stash list command. Caches are saved in a LIFO (last in, first out) approach
: $ List of git caches stash@{0}: WIP on master: d7435644 Feat: Configure graphql endpoint
By default, caches are marked as WIP at the top of the branch and confirm that you created the stash from which it was made. However, this limited amount of information is not useful when you have multiple storages, as it becomes difficult to individually remember or verify its contents. To add a description to the stash, you can use the command
git stash save <description>: $ git stash save “remove semi-colon from schema” Saved working directory and index state In master: remove semicolon from schema $ git stash list stash@{0}: In master: remove semicolon from schema stash@{1}: Work in progress in master: d7435644 Feat: Configure the graphql endpoint
Hidden change recovery
You can reapply hidden changes using the git stash apply and git stash pop commands. Both commands reapply the changes saved in the last stash (that is, stash@{0}). A stash reapplies the changes, while pop removes the changes from the stash and reapplies them to the working copy. Popping is preferred if you do not need saved changes to be reapplied more than once.
You can choose which stash you want to pop or apply by passing the identifier as the last argument:
$ git stash pop stash@{1}
or
$ git stash apply stash@{1}
Cleaning the stash
It is a good practice to remove stash that is no longer needed. You must do this manually with the following commands:
Git stash Clear empties the
- hiding list by deleting all hiding places. Git
- drop <stash_id> removes a particular stash from the stash list.
stash
Checking
for stash differences The git stash show command
<stash_id> allows you to see the diff of a stash: $ git stash show
stash@{1} console/console-init/ui/.graphqlrc.yml | 4 +- console/console-init/ui/generated-frontend.ts | 742 ++++++++++- console/console-init/ui/package.json | 2 +-
For a more detailed difference, pass the -patch or -p:
$ git stash show stash@{0} -patch diff -git a/console/console-init/ui/package.json b/console/console-init/ui/package.json index 755912b97.. 5b5af1bd6 100644 – a/console/console-init/ui/package.json +++ b/console/console-init/ui/package.json @@ -1.5 +1.5 @@ { – “name”: “my-usepatternfly”, + “name”: “my-usepatternfly-2”, “version”: “0.1.0”, “private”: true, “proxy”: “http://localhost:4000” diff -git a/console/console-init/ui/src/AppNavHeader.tsx b/console/console-init/ui/src/AppNavHeader.tsx index a4764d2f3.. da72b7e2b 100644 – a/console/console-init/ui/src/AppNavHeader.tsx +++ b/console/console-init/ui/src/AppNavHeader.tsx @@ -9.8 +9.8 @@ import { css } from “@patternfly/react-styles”; IAppNavHeaderProps interface extend PageHeaderProps { – toolbar?: React.ReactNode; – avatar?: React.ReactNode; + toolbar?: React.ReactNode; + avatar?: React.ReactNode; } export class AppNavHeader extend React.Component<IAppNavHeaderProps>{ render()Check out to a
new
branch
You might encounter a situation where changes to a branch and its stash diverge, causing a conflict when you try to reapply the stash. A clean solution for this is to use the git stash branch <new_branch_name stash_id> command, which creates a new branch based on the commit from which the stash was created and displays the hidden changes in it: $ git stash
branch test_2 stash@{0} Changed to a new branch ‘test_2’ In the branch test_2 Untentative changes to commit: (use “git add <file>…” to update what will be committed) (use “git restore <file>…” to discard working directory changes) modified: .graphqlrc.yml modified: generated-frontend.ts modified: package.json No changes were added to commit (use “git add” and/or “git commit -a”) Removed stash@{0} (fe4bf8f79175b8fbd3df3c4558249834ecb75cd1)
Storage without disturbing
stash
reflog On rare occasions, you may need to create a stash while keeping the reflog intact. These cases can arise when you need a script to hide as a deployment detail. This is accomplished by the git stash create command; It creates a stash entry and returns its object name without pushing it to
the reflog hideout: $ git stash create “sample stash” 63a711cd3c7f8047662007490723e26ae9d4acf9
Sometimes, you may decide to push the stash entry created through git stash create al stash reflog: $ git
stash store -m “sample stash testing.. ” “63a711cd3c7f8047662007490723e26ae9d4acf9” $ git stash list stash @{0}: sample stash testing..
Conclusion
I hope you found this article useful and learned something new. If I missed any useful options for using stash, let me know in the comments.