{"id":624,"date":"2025-07-09T09:00:00","date_gmt":"2025-07-08T23:00:00","guid":{"rendered":"https:\/\/jm.armijo.au\/dev\/?p=624"},"modified":"2025-07-08T19:15:52","modified_gmt":"2025-07-08T09:15:52","slug":"a-practical-guide-to-git-stash","status":"publish","type":"post","link":"https:\/\/jm.armijo.au\/dev\/blog\/2025\/07\/09\/a-practical-guide-to-git-stash\/","title":{"rendered":"A Practical Guide To Git Stash"},"content":{"rendered":"\n<p>Several years ago, while pairing with a teammate, I noticed he was taking a lot of time to perform a simple task, because his working environment was not clean.<\/p>\n\n\n\n<p>To help him save some time, I suggested he use <code>git stash<\/code>, a Git command that saves local changes for later in a stack-like structure, so we can switch branches without losing our work. However, he told me that he had once tried to use it and ended up losing his work without knowing why. As a result, he decided to never use this <em>evil<\/em> command ever again, even though it could save him lots of time when switching between tasks.<\/p>\n\n\n\n<p>I am sure that losing the work of an entire day must be painful. However, the lessons should not be to avoid a useful command, but to learn how to use it to prevent those accidents. You can read more about this mindset in my article <em>The Impact Of Mastering Our Day to Day Tools<\/em>:<\/p>\n\n\n\n<figure class=\"wp-block-embed is-type-wp-embed is-provider-practical-software-development wp-block-embed-practical-software-development\"><div class=\"wp-block-embed__wrapper\">\n<blockquote class=\"wp-embedded-content\" data-secret=\"N9T1DTHTwU\"><a href=\"https:\/\/jm.armijo.au\/dev\/blog\/2024\/10\/30\/the-impact-of-mastering-our-day-to-day-tools\/\">The impact of mastering our day to day tools<\/a><\/blockquote><iframe loading=\"lazy\" class=\"wp-embedded-content\" sandbox=\"allow-scripts\" security=\"restricted\" style=\"position: absolute; visibility: hidden;\" title=\"&#8220;The impact of mastering our day to day tools&#8221; &#8212; Practical Software Development\" src=\"https:\/\/jm.armijo.au\/dev\/blog\/2024\/10\/30\/the-impact-of-mastering-our-day-to-day-tools\/embed\/#?secret=23KRDpOILf#?secret=N9T1DTHTwU\" data-secret=\"N9T1DTHTwU\" width=\"500\" height=\"282\" frameborder=\"0\" marginwidth=\"0\" marginheight=\"0\" scrolling=\"no\"><\/iframe>\n<\/div><\/figure>\n\n\n\n<p>In this article, I&#8217;d like to describe not only how to use the <code>git stash<\/code> command with all its different options, but also when we can take advantage of this powerful yet simple tool. If you or someone you know is facing an issue like this, I hope this guide helps you understand how and when to use this command with confidence.<\/p>\n\n\n\n<p><strong>Disclaimer:<\/strong> This guide is based on the latest version of Git available at the time of writing (v2.50). For the official documentation, see: <a href=\"https:\/\/git-scm.com\/docs\/git-stash\/2.43.0\">https:\/\/git-scm.com\/docs\/git-stash\/2.43.0<\/a> (latest version where stash was updated).<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Background<\/h3>\n\n\n\n<p>This is a very brief introduction into the different working areas that Git uses to handle our work:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><strong>Staged<\/strong>: These are the changes we\u2019ve told Git we want to include in the next commit. We add them using <code>git add<\/code>. This area is also called the <strong>index<\/strong>: it\u2019s like Git\u2019s \u201cready to commit\u201d list.<\/li>\n\n\n\n<li><strong>Unstaged<\/strong>: These are changes we\u2019ve made to files Git already knows about, but we haven\u2019t added them yet.<\/li>\n\n\n\n<li><strong>Untracked<\/strong>: These are new files Git doesn\u2019t know about yet, because we haven\u2019t added them to version control.<\/li>\n<\/ul>\n\n\n\n<p>You can see all of these areas by running <code>git status<\/code>. That\u2019s what we\u2019ll use in the examples below.<\/p>\n\n\n\n<p>Note that we can also tell Git to ignore certain files on purpose (like build output, logs, or temp files). These are listed in a <code>.gitignore<\/code> file and don\u2019t show up in <code>git status<\/code> or get tracked at all. This will be important, as <code>git stash<\/code> provides a way to bypass this.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Examples<\/h3>\n\n\n\n<p>Consider the following example repository, where we have three files: <code>file<\/code>1.txt in the staging area (ready to be committed), <code>file2.txt<\/code> not staged yet, <code>file3.txt<\/code> that is not even tracked by Git, and <code>file4.txt<\/code>, which is ignored by Git:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git status\nChanges to be committed:\n  modified:   file1.txt\n\nChanges not staged for commit:\n  modified:   file2.txt\n\nUntracked files:\n  file3.txt\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">git stash<\/h5>\n\n\n\n<p>Let&#8217;s pretend there was a change in priorities or we need to fix a bug in production. In that case, we need to stop what we are doing and start working on something else in the same repository. But, for some reason, we do not want to commit our changes just yet. This is one of the most common scenarios where we will want to do:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash\n$ git status\nUntracked files:\n  file3.txt\n<\/pre><\/div>\n\n\n<p>This command tells git to move <strong>staged<\/strong> and <strong>unstaged<\/strong> changes to a special area called the <strong>stash<\/strong>. Untracked and ignored files are skipped. So, when we do <code>git status<\/code>, we will only see the untracked files.<\/p>\n\n\n\n<p>Although the default behaviour is to exclude untracked files, we can be explicit by saying:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash --no-include-untracked\n$ git status\nUntracked files:\n  file3.txt\n<\/pre><\/div>\n\n\n<p>If instead, we want to include untracked files, we can include the <code>--include-untracked<\/code> option. Note that the ignored file will still be present in our file system:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash --include-untracked # or\n$ git stash -u\n$ git status\nnothing to commit, working tree clean\n$ ls file4.txt\nfile4.txt\n<\/pre><\/div>\n\n\n<p>If we want to also include ignored files, we can use the <code>--all<\/code> option:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash --all # or\n$ git stash -a\n$ git status\nnothing to commit, working tree clean\n$ ls file4.txt\nls: file4.txt: No such file or directory\n<\/pre><\/div>\n\n\n<p>Note that we cannot do <code>git stash<\/code> if our repository doesn&#8217;t have any commits yet, but I don&#8217;t think this will ever be a problem.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">git stash list<\/h5>\n\n\n\n<p>To see what you have stashed, you can do:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash list\n stash@{0}: WIP on branch1: 1b4635d Last commit\n stash@{1}: WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<p>As mentioned before, the stash area is a stack, where each new stash is added on top. Every stash entry has a pre-established format:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nstash@{&lt;number&gt;}: WIP on &lt;branch name&gt;: &lt;last commit ID&gt; &lt;last commit message&gt;\n<\/pre><\/div>\n\n\n<p>This is useful because, since there is a single stash area per repository (i.e. all branches share the same stash), this format let us to know the branch and commit we were working on when we stashed our changes.<\/p>\n\n\n\n<p>You can use any of the <code>git log<\/code> options on this command as well. Since they are out of scope for this article, I&#8217;ve let a link to the <a href=\"https:\/\/git-scm.com\/docs\/git-log\">official documentation<\/a> so you can have a look.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">git stash show<\/h5>\n\n\n\n<p>If we want to see the list of files in our stash area, rather than just the stash info, we can do:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash show\n file1.txt | 1 +\n file2.txt | 1 +\n 2 files changed, 2 insertions(+)\n<\/pre><\/div>\n\n\n<p>This will show both staged and unstaged files, and I use it quite often when I want to remember exactly what files I was working on at the time.<\/p>\n\n\n\n<p>By default, <code>git stash show<\/code> will show the content of the top of the stack, but we can specify what item we can to see by appending the stack number. This example shows another file, <code>file5.txt<\/code>, which was added previously to the stash area:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash show 1\n file5.txt | 5 +\n 1 files changed, 5 insertions(+)\n<\/pre><\/div>\n\n\n<p>By default, untracked files are not shown even if they were stashed. We can use the <code>--include-untracked<\/code> option to see untracked (and ignored) files:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash show --include-untracked # or\n$ git stash show -u\n file1.txt | 1 +\n file2.txt | 1 +\n file3.txt | 1 +\n file4.txt | 0\n 4 files changed, 3 insertions(+)\n<\/pre><\/div>\n\n\n<p>When we&#8217;re only interested in seeing untracked (and ignored) files, we can use the <code>--only-untracked<\/code> options:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash show --only-untracked\n file3.txt | 1 +\n file4.txt | 0\n 2 files changed, 1 insertion(+)\n<\/pre><\/div>\n\n\n<p>As already mentioned, <code>git stash show<\/code> shows the changes recorded in the stash entry as a diff between the stashed contents and the commit back when the stash entry was first created. However, this shows some basic information only.<\/p>\n\n\n\n<p>Fortunately, <code>git stash show<\/code> also supports all the options of the <code>git diff<\/code> command, so we can enrich the output. You can refer the <code>git diff<\/code> <a href=\"https:\/\/git-scm.com\/docs\/git-diff\">official documentation<\/a> for details on these options, but the <code>--patch<\/code> option is too important not to cover here.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">git stash show &#8211;patch<\/h5>\n\n\n\n<p>Sometimes seeing the file names is not enough. We also want to see the actual changes that we were making in those files. I usually do this for two reasons: I want to make sure that&#8217;s the stash I want, or I want to copy some code in that stash to use somewhere else. In those cases, we can do:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash show --patch # or\n$ git stash show -p # or\n$ git stash show -u\ndiff --git a\/file1.txt b\/file1.txt\nindex 02aa577..fa49a36 100644\n--- a\/file1.txt\n+++ b\/file1.txt\n@@ -1 +1,2 @@\n content of file1.txt\n+new changes of file1.txt\ndiff --git a\/file2.txt b\/file2.txt\nindex fda4ec9..3dbe8fb 100644\n--- a\/file2.txt\n+++ b\/file2.txt\n@@ -1 +1,2 @@\n content of file2.txt\n+new changes of file2.txt\n<\/pre><\/div>\n\n\n<p>This returns a diff between the code in the stash, and the commit when the stash was saved. As mentioned earlier, the output&#8217;s format can be improved further by using the same options available for <code>git diff<\/code>.<\/p>\n\n\n\n<p>If we want to see the specific code changes of another entry of the stack, we can specify the stack entry in the command. For example:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash show -p 1\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">git stash pop<\/h5>\n\n\n\n<p>When we&#8217;re ready to go back to our original work, we need to recover the changes that we stashed for later using the <code>git stash pop<\/code> command.<\/p>\n\n\n\n<p>This command applies the changes at the top of the stash stack, and then removes the entry from the stack.<\/p>\n\n\n\n<p>Note that <strong>staged<\/strong> and <strong>unstaged<\/strong> files are restored in the unstaged area, and that untracked files are left untracked.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash pop\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n        modified:   file1.txt\n        modified:   file2.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nno changes added to commit (use &quot;git add&quot; and\/or &quot;git commit -a&quot;)\nDropped refs\/stash@{0} (b0488a)\n<\/pre><\/div>\n\n\n<p>If we want staged files to be restored in the staged area, we must use the <code>--index<\/code> option:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash pop --index\nChanges to be committed:\n  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)\n        modified:   file1.txt\n\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n        modified:   file2.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nDropped refs\/stash@{0} (b0488a)\n<\/pre><\/div>\n\n\n<p>When <code>git stash pop<\/code> encounters conflicts trying to apply the changes, it will do as much as it can to apply the changes, and then report the conflict. The entry in the stash will NOT be removed.<\/p>\n\n\n\n<p>This was unexpected to me the first time that I saw this behaviour, but I think it is practical. Sometimes I&#8217;ve encountered difficult conflicts and having the chance to clear my mess and start again fresh, knowing that my changes are still saved, it&#8217;s a relief.<\/p>\n\n\n\n<p>This is an example of using the <code>git stash pop<\/code> command when encountering conflicts. Note the message at the bottom saying the stash is being kept.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash pop\nAuto-merging file1.txt\nCONFLICT (content): Merge conflict in file1.txt\nOn branch main\nChanges to be committed:\n  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)\n        modified:   file2.txt\n\nUnmerged paths:\n  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)\n  (use &quot;git add &lt;file&gt;...&quot; to mark resolution)\n        both modified:   file1.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nThe stash entry is kept in case you need it again.\n<\/pre><\/div>\n\n\n<p>I find that <code>git stash pop<\/code> is sometimes overly verbose. Luckily for us, we can solve that with the <code>--quiet<\/code> option.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash pop --quiet # or\n$ git stash pop -q\n\n<\/pre><\/div>\n\n\n<p>If there&#8217;s a conflict we&#8217;ll still be informed of it though:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash pop --quiet # or\n$ git stash pop -q\nAuto-merging file1.txt\nCONFLICT (content): Merge conflict in file1.txt\nThe stash entry is kept in case you need it again.\n<\/pre><\/div>\n\n\n<p>Finally, we can specify any item in the stash area. That means that we can apply any item in the stash, not just the one at the top, and also remove it from the stash area if it was successfully applied. This is why I consider the stash area to be a stack-like structure, and not plainly a stack.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash pop 1\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n        modified:   file5.txt\n\nno changes added to commit (use &quot;git add&quot; and\/or &quot;git commit -a&quot;)\nDropped refs\/stash@{0} (88ab04)\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">git stash drop<\/h5>\n\n\n\n<p>Sometimes we will want to remove items from the stash area. This can happen after solving the conflicts of a <code>pop<\/code> operation, or if we decide that those changes are no longer needed.<\/p>\n\n\n\n<p>In those cases, we can use the <code>git stash drop<\/code> command, which by default removes the element at the top of the stack:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash drop\nDropped refs\/stash@{0} (b0488a)\n$ git stash list\n stash@{0}: WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<p>We can remove any element from the stash by just specifying it&#8217;s number:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash drop 1\nDropped refs\/stash@{1} (12a876f)\n$ git stash list\n stash@{0}: WIP on branch1: 1b4635d Last commit\n<\/pre><\/div>\n\n\n<p>Although not particularly annoying, we can still remove the command&#8217;s output with the <code>--quiet<\/code> option:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash drop --quiet # or\n$ git stash drop -q\n$ git stash list\n stash@{0}: WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">GIT STASH APPLY<\/h5>\n\n\n\n<p>The <code>git stash apply<\/code> command does the same as the <code>git stash pop<\/code> command, except that it does NOT remove the stash entry from the stash area.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash apply\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n        modified:   file1.txt\n        modified:   file2.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nno changes added to commit (use &quot;git add&quot; and\/or &quot;git commit -a&quot;)\n<\/pre><\/div>\n\n\n<p>I find this particularly useful when I want to split some code changes into different pull requests, as I can apply the changes into a branch and commit only some of the changes. Then, I can go to a different branch, do <code>git stash apply<\/code>, and commit another subset of the changes. And so on.<\/p>\n\n\n\n<p>This command accepts the same options as <code>git stash pop<\/code>, so I won&#8217;t list them here.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">git stash branch<\/h5>\n\n\n\n<p>The <code>git stash branch<\/code> command creates and checks out a new branch with the name that we specify. Just like <code>git stash pop<\/code>, the stash entry will be removed from the stash area only if the operation succeeds.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash branch my-new-branch\nSwitched to a new branch 'my-new-branch'\nOn branch my-new-branch\nChanges to be committed:\n  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)\n        modified:   file1.txt\n\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n        modified:   file2.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nDropped refs\/stash@{0} (b0488a)\n<\/pre><\/div>\n\n\n<p>The branch will start from the commit at which the&nbsp;stash entry was originally created, and will then apply the changes on the working area. Staged files will be applied in the staged area, as if we had run the <code>git stash pop --index<\/code> command.<\/p>\n\n\n\n<p>I find this command also very useful for splitting large pull requests. Another use case for this command is when applying the changes on another branch will cause conflicts: we may prefer to apply the changes, and then solve the conflicts separately, if needed.<\/p>\n\n\n\n<h5 class=\"wp-block-heading\">git stash push<\/h5>\n\n\n\n<p>The <code>git stash push<\/code> command is a more explicit version of <code>git stash<\/code>: it does the same thing and supports the same options:<\/p>\n\n\n\n<ul class=\"wp-block-list\">\n<li><code>--include-untracked<\/code> or <code>-u<\/code><\/li>\n\n\n\n<li><code>--no-include-untracked<\/code><\/li>\n\n\n\n<li><code>--all<\/code> or <code>-a<\/code><\/li>\n<\/ul>\n\n\n\n<p>But it also supports a few extra options, which we\u2019ll explore here.<\/p>\n\n\n\n<p>If we find <code>git stash<\/code> to be too verbose, we can just use the <code>--quiet<\/code> option to silent it:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --quiet # or\n$ git stash push -q\n\n<\/pre><\/div>\n\n\n<p>By default, <code>git stash push<\/code> will stash files in the staged and unstaged areas only (same behaviour as <code>git stash<\/code>).<\/p>\n\n\n\n<p>If we do <code>--no-keep-index<\/code>, we&#8217;ll stash staged and unstaged files. This is the default option.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --no-keep-index\nSaved working directory and index state WIP on branch2: 12a876f Another commit\n$ git status\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nnothing added to commit but untracked files present (use &quot;git add&quot; to track)\n<\/pre><\/div>\n\n\n<p>To only include unstaged files (i.e. exclude staged files), we can use the <code>--keep-index<\/code> option.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --keep-index # or\n$ git stash push -k\nSaved working directory and index state WIP on branch2: 12a876f Another commit\n$ git status\nChanges to be committed:\n  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)\n        modified:   file1.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n<\/pre><\/div>\n\n\n<p><code>git stash push<\/code> also allows us to only stash staged files:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --staged # or\n$ git stash push -S\nSaved working directory and index state WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<p>And if we find that the default stash message is not clear enough, we can specify our own message!<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --message &quot;my cool message&quot; # or\n$ git stash push -m &quot;my cool message&quot;\nSaved working directory and index state On branch2: my cool message\n$ git stash list\nstash@{0}: On branch1: my cool message\n<\/pre><\/div>\n\n\n<p>If you want even finer control on which files to stash, you can specify a list of files and\/or directories separated by space using this command. I also find this to be particularly useful when making smaller pull requests, or anytime we want to work on some changes, but want to save some particular files for later.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push -- file1.txt file2.txt\nSaved working directory and index state WIP on branch2: 12a876f Another commit\n$ git status\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n\nno changes added to commit (use &quot;git add&quot; and\/or &quot;git commit -a&quot;)\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">git stash clear<\/h5>\n\n\n\n<p>Use this command with caution. This is one of the few commands in Git that can permanently delete our work. If you are sure you want to remove all elements from your stash, do:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\ngit stash clear\n<\/pre><\/div>\n\n\n<p>Just as a reminder, this will delete ALL entries in your repository stash, irrespective of the branch where you create it.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Advanced Usage<\/h3>\n\n\n\n<h5 class=\"wp-block-heading\">git stash push (advanced)<\/h5>\n\n\n\n<p>There are a few options we can use with <code>git stash push<\/code> that I find slightly advanced. I have never found the need to put them into practice, but I like to be aware of them for whenever they become handy, probably when writing some automation tools.<\/p>\n\n\n\n<p>For example, we can have a file to specify what files to stash. If we have a file like this, where every file to stash is listed in a new line:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: plain; gutter: false; title: ; notranslate\" title=\"\">\nfile1.txt\nfile2.txt\n<\/pre><\/div>\n\n\n<p>We can stash our changes using this command instead:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --pathspec-from-file=files-to-stash.txt\nSaved working directory and index state WIP on branch2: 12a876f Another commit\n$ git status\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n        files-to-stash.txt\n\nnothing added to commit but untracked files present (use &quot;git add&quot; to track)\n<\/pre><\/div>\n\n\n<p>However, that command will not work properly if the file names have spaces (like <code>file 1.txt<\/code>. To account for this, we can separate files with a null character rather than a newline character.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\nprintf &quot;file 1.txt\\0file 2.txt\\0&quot; &gt; files-to-stash.txt\n<\/pre><\/div>\n\n\n<p>And pass option <code>--pathspec-file-nul<\/code> to our previous command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash push --pathspec-file-nul --pathspec-from-file=files-to-stash.txt\nSaved working directory and index state WIP on branch2: 12a876f Another commit\n$ git status\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n        files-to-stash.txt\n\nnothing added to commit but untracked files present (use &quot;git add&quot; to track)\n<\/pre><\/div>\n\n\n<h5 class=\"wp-block-heading\">git stash create + git stash store<\/h5>\n\n\n\n<p>I don&#8217;t intend to trick anyone. This is the first time I&#8217;ve ever looked at these options, and my knowledge is quite limited. However, I still wanted to try and understand what&#8217;s the purpose of these commands, and how to use them. In this section, I share with you what I&#8217;ve uncovered, which may be just the tip of the iceberg.<\/p>\n\n\n\n<p>Whether we use <code>git stash<\/code> or <code>git stash push<\/code> to create a stash entry in the stash area, our working area will be cleared in the process. That is, any staged, unstaged and\/or untracked objects will be removed from our working space as they are moved into the stash. And If we don&#8217;t want to revert these changes, we can do <code>git stash apply<\/code> to move things back into our working area.<\/p>\n\n\n\n<p>There is, however, a way to achieve the same result without ever moving things out of the working area.<\/p>\n\n\n\n<p>First, we need to bring up the concept of a Git object. We don&#8217;t usually need to know about these objects, so this may be a hard concept to grasp. When we commit some changes, we can identify the commit by its hash id. This is a Git object that can be referenced by that id. Similarly, every entry in the stash is also a Git object with a hash id (only that it is not shown to us).<\/p>\n\n\n\n<p>So, we will create a new Git object with this command, which will return the hash of the newly created object.<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash create\n1e9b483d1f9477de5c99a708f4aa512ba\n$ git stash list\n stash@{0}: WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<p>The stash is still empty. This object is not tied to anything, and it will eventually be deleted by git&#8217;s garbage collector if we don&#8217;t do something with this. So, let&#8217;s add this object to the stash area with the <code>store<\/code> command:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash store 1e9b483d1f9477de5c99a708f4aa512ba\n$ git stash list\n stash@{0}: Created via &quot;git stash store&quot;.\n stash@{1}: WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<p>Our working area remained unchanged this whole time:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git status\nChanges to be committed:\n  (use &quot;git restore --staged &lt;file&gt;...&quot; to unstage)\n        modified:   file1.txt\n\nChanges not staged for commit:\n  (use &quot;git add &lt;file&gt;...&quot; to update what will be committed)\n  (use &quot;git restore &lt;file&gt;...&quot; to discard changes in working directory)\n        modified:   file2.txt\n\nUntracked files:\n  (use &quot;git add &lt;file&gt;...&quot; to include in what will be committed)\n        file3.txt\n<\/pre><\/div>\n\n\n<p>According to the documentation, we can pass a message when doing <code>create<\/code>.  Although the command accepts the option, I could not understand what the use of it. I raised a ticket with Git to either fix the behaviour (based on the behaviour that I expected), or to improve the documentation. Hopefully someone who understand the intent will explain what&#8217;s the idea of that option.<\/p>\n\n\n\n<p>In any case, we can pass a message to the <code>store<\/code> command, and this time the argument is used as expected:<\/p>\n\n\n<div class=\"wp-block-syntaxhighlighter-code \"><pre class=\"brush: bash; gutter: false; title: ; notranslate\" title=\"\">\n$ git stash store --message &quot;example&quot; 1e9b48 # or\n$ git stash store -m &quot;example&quot; 1e9b48\n$ git stash list\n stash@{0}: example\n stash@{1}: WIP on branch2: 12a876f Another commit\n<\/pre><\/div>\n\n\n<p><code>git stash store<\/code> also supports a <code>--quiet<\/code> option, but I&#8217;m not sure what for since the command doesn&#8217;t output anything.<\/p>\n\n\n\n<p>My spider-sense tells me that maybe these commands are not used a lot, which would explain the presence of these <s>bugs<\/s> odd behaviours.<\/p>\n\n\n\n<h3 class=\"wp-block-heading\">Final thoughts<\/h3>\n\n\n\n<p>If you change teams or jobs, even if the new place uses different technologies or programming languages, it&#8217;s very likely that you will continue using Git. This is why mastering this tool beyond the basic commands everyone knows is so important.<\/p>\n\n\n\n<p>I find that Git is a very simple tool when considering all the features that it provides. Maybe the complexity lays in learning all the options it provides, and how to use them properly and at the right time.<\/p>\n\n\n\n<p>If these options are new to you, I hope that the examples provided are a good starting point, but nothing will replace doing some hands-on learning by yourself. So, I&#8217;d like to invite you to try one of these commands next time you work in your repository. If you do this, you will be one step closer to mastering this important tool for our craft.<\/p>\n\n\n\n<p>Happy coding!<br>Jos\u00e9 Miguel<\/p>\n\n\n\n<p><em>Share if you find this content useful.<\/em><br><em>Follow me on&nbsp;<a href=\"http:\/\/www.linkedin.com\/comm\/mynetwork\/discovery-see-all?usecase=PEOPLE_FOLLOWS&amp;followMember=jmarmijo\">LinkedIn<\/a>&nbsp;to be notified of new articles.<\/em><\/p>\n","protected":false},"excerpt":{"rendered":"<p>Several years ago, while pairing with a teammate, I noticed he was taking a lot of time to perform a simple task, because his working environment was not clean. To help him save some time, I suggested he use git stash, a Git command that saves local changes for later in a stack-like structure, so [&hellip;]<\/p>\n","protected":false},"author":2,"featured_media":650,"comment_status":"open","ping_status":"open","sticky":false,"template":"","format":"standard","meta":{"footnotes":""},"categories":[9],"tags":[10,14,6,11],"class_list":["post-624","post","type-post","status-publish","format-standard","has-post-thumbnail","hentry","category-tools","tag-git","tag-pull-request","tag-tools","tag-version-control"],"_links":{"self":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts\/624","targetHints":{"allow":["GET"]}}],"collection":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts"}],"about":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/types\/post"}],"author":[{"embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/users\/2"}],"replies":[{"embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/comments?post=624"}],"version-history":[{"count":27,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts\/624\/revisions"}],"predecessor-version":[{"id":653,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/posts\/624\/revisions\/653"}],"wp:featuredmedia":[{"embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/media\/650"}],"wp:attachment":[{"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/media?parent=624"}],"wp:term":[{"taxonomy":"category","embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/categories?post=624"},{"taxonomy":"post_tag","embeddable":true,"href":"https:\/\/jm.armijo.au\/dev\/wp-json\/wp\/v2\/tags?post=624"}],"curies":[{"name":"wp","href":"https:\/\/api.w.org\/{rel}","templated":true}]}}