Git Stash

Introduction

From this article you can learn how to use git stash.

Example

master branch has calc.py file with the following code:

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass

Let's create a new branch

git checkout -b add

Switched to a new branch 'add'

Edit the add() functions:

def add(a, b): return a + b …

git diff calc.py

warning: in the working copy of 'calc.py', LF will be replaced by CRLF the next time Git touches it diff --git a/calc.py b/calc.py index 74480ae..92116e4 100644 --- a/calc.py +++ b/calc.py @@ -1,5 +1,5 @@ def add(a, b): - pass + return a + b

If we check out master now, there will be no error. The file will be visible as modified in master as well.

There would be a problem if someone had hurried and edited the file in master while we were on add, but right now everything is fine.

git checkout master

M calc.py Switched to branch 'master'

git status

On branch master 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: calc.py no changes added to commit (use "git add" and/or "git commit -a")

Let's go back to add and make a stash there

git checkout add

M calc.py Switched to branch 'add'

git stash save "Worked on add function"

warning: in the working copy of 'calc.py', LF will be replaced by CRLF the next time Git touches it Saved working directory and index state On add: Worked on add function

git diff

git status

On branch add nothing to commit, working tree clean

The changes in the file are reverted

def add(a, b): pass …

To see the list of existing stashes, use the list command

git stash list

stash@{0}: On add: Worked on add function

To pull the data from a stash, use the apply command

git stash apply stash@{0}

On branch add 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: calc.py no changes added to commit (use "git add" and/or "git commit -a")

The changes are back.

def add(a, b): return a + b …

The stash itself is not deleted

git stash list

stash@{0}: On add: Worked on add function

git checkout -- .

The changes in the file are reverted

def add(a, b): pass …

The stash itself is still in place.

git stash list

stash@{0}: On add: Worked on add function

With pop you can apply the last of the stashes made and delete it

git stash pop

On branch add 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: calc.py no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (2a2b5c77599d40413526b90929787c3b24d48158)

The changes will come back and the stash itself will be deleted.

git stash list

git diff calc.py

warning: in the working copy of 'calc.py', LF will be replaced by CRLF the next time Git touches it diff --git a/calc.py b/calc.py index 74480ae..92116e4 100644 --- a/calc.py +++ b/calc.py @@ -1,5 +1,5 @@ def add(a, b): - pass + return a + b

Let's make new changes to the file

def add(a, b): return a + b def subtract(a, b): return a - b def multipy(a, b): return a * b def divide(a, b): return a / b

git diff

diff --git a/calc.py b/calc.py index 74480ae..073159f 100644 --- a/calc.py +++ b/calc.py @@ -1,12 +1,12 @@ def add(a, b): - pass + return a + b def subtract(a, b): - pass + return a - b def multipy(a, b): - pass + return a * b def divide(a, b): - pass + return a / b

git stash save "Calc Functions"

Saved working directory and index state On add: Calc Functions

git stash list

stash@{0}: On add: Calc Functions

The changes in the file are reverted

def add(a, b): pass …

Let's add the function square()

… def square(a, b): pass

git diff

diff --git a/calc.py b/calc.py index 74480ae..f6e6a9e 100644 --- a/calc.py +++ b/calc.py @@ -10,3 +10,5 @@ def multipy(a, b): def divide(a, b): pass +def square(a, b): + pass

git stash save "Added Square function"

Saved working directory and index state On add: Added Square function

git stash list

stash@{0}: On add: Added Square function stash@{1}: On add: Calc Functions

git stash pop

On branch add 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: calc.py no changes added to commit (use "git add" and/or "git commit -a") Dropped refs/stash@{0} (6766bae510aad02144b79b4e03d4a58defe6479e)

git diff

diff --git a/calc.py b/calc.py index 74480ae..f6e6a9e 100644 --- a/calc.py +++ b/calc.py @@ -10,3 +10,5 @@ def multipy(a, b): def divide(a, b): pass +def square(a, b): + pass

git stash list

stash@{0}: On add: Calc Functions

git stash save "Added Square function"

Saved working directory and index state On add: Added Square function

git stash list

stash@{0}: On add: Added Square function stash@{1}: On add: Calc Functions

git stash drop stash@{0}

Dropped stash@{0} (1650ddf3181da30f0842dc3c103590c132cb34f0)

git stash list

stash@{0}: On add: Calc Functions

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass

Let's bring back square() manually and stash it

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass def square(a, b): pass

git stash save "Added Square function"

Saved working directory and index state On add: Added Square function

git stash list

stash@{0}: On add: Added Square function stash@{1}: On add: Calc Functions

git stash clear

The file has returned to its original state.

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass

git stash list

git status

On branch add nothing to commit, working tree clean

git checkout master

Switched to branch 'master'

git status

On branch master nothing to commit, working tree clean

We make changes to the code of the function add()

def add(a, b): return a + b …

git status

On branch master 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: calc.py no changes added to commit (use "git add" and/or "git commit -a")

git diff

warning: in the working copy of 'calc.py', LF will be replaced by CRLF the next time Git touches it diff --git a/calc.py b/calc.py index 74480ae..92116e4 100644 --- a/calc.py +++ b/calc.py @@ -1,5 +1,5 @@ def add(a, b): - pass + return a + b

git checkout add

M calc.py Switched to branch 'add'

git status

On branch add 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: calc.py no changes added to commit (use "git add" and/or "git commit -a")

Resolving a conflict with stash

Our branch was created from master at the moment when the file looked like this

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass

Let's go back to master and add return to divide()

git checkout master

M calc.py Switched to branch 'master'

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): return a / b

git status

On branch master 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: calc.py no changes added to commit (use "git add" and/or "git commit -a")

git add calc.py
git commit -m "Adding return to divide"

[master 1c57998] Adding return to divide 1 file changed, 2 insertions(+), 2 deletions(-)

Let's switch to the add branch and add return to add() there

git checkout add

Switched to branch 'add'

git status

On branch add nothing to commit, working tree clean

cat calc.py

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass

Let's edit the code

def add(a, b): return a + b def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): pass

git checkout master

error: Your local changes to the following files would be overwritten by checkout: calc.py Please commit your changes or stash them before you switch branches. Aborting

Now master has return in subtract() and the add branch has return in add(), so we cannot switch painlessly

git stash save "Adding return to add()"

Saved working directory and index state On add: Adding return to add()

git stash list

stash@{0}: On add: Adding return to add()

git checkout master

Switched to branch 'master'

git stash list

stash@{0}: On add: Adding return to add()

git checkout add

Switched to branch 'add'

git rebase master

Successfully rebased and updated refs/heads/add.

The return for divide was pulled in from master

cat calc.py

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): return a / b

git stash pop

Auto-merging calc.py CONFLICT (content): Merge conflict in calc.py On branch add Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: calc.py no changes added to commit (use "git add" and/or "git commit -a") The stash entry is kept in case you need it again.

cat calc.py

def add(a, b): <<<<<<< Updated upstream pass ======= return a + b >>>>>>> Stashed changes def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): return a / b

Now we edit the file manually, keeping what is above >>>>>>> Stashed changes

vi calc.py

def add(a, b): return a + b def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): return a / b

git status

On branch add Unmerged paths: (use "git restore --staged <file>..." to unstage) (use "git add <file>..." to mark resolution) both modified: calc.py no changes added to commit (use "git add" and/or "git commit -a")

git add calc.py

git status

On branch add Changes to be committed: (use "git restore --staged <file>..." to unstage) modified: calc.py

git commit -m "Adds return to add()"

[add 15a3130] Adds return to add() 1 file changed, 1 insertion(+), 1 deletion(-)

git status

On branch add nothing to commit, working tree clean

git checkout master

Switched to branch 'master'

cat calc.py

def add(a, b): pass def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): return a / b

git merge -m "Merging add branch to master" add

Updating 1c57998..15a3130 Fast-forward (no commit created; -m option ignored) calc.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-)

git status

On branch master nothing to commit, working tree clean

cat calc.py

def add(a, b): return a + b def subtract(a, b): pass def multipy(a, b): pass def divide(a, b): return a / b

Article author: Andrei Olegovich