loading...

git deep dive part 9: Save the current work

kenakamu profile image Kenichiro Nakamura ・4 min read

In the previous article, I explain how to revert the commit. In this article, I explain how to save the current work by git stash.

Why and when do I need to save my work?

Whenever I modify the file, all the changes are happened in working tree. I need to issue git add to create snapshot which we all know already. However, there is a time I want to save my work without git add.

One of the reason is to switch branch while doing something

Create a branch

Let's simulate the situation. I add new branch "feature1" on top of master.

git checkout master
git checkout -b feature1

I am on feature1 branch now.

gitDeepDive> git log --oneline --graph --all
* 3705a85 (HEAD -> feature1, master) Revert "cherry-pick 367c2d0"
* 8618d72 cherry-pick 367c2d0
* c36490a update docs
| * 867d90c (dev) update hello.txt
| * 367c2d0 Update news
|/
* 2adbcac (test) Add doc folder and files
* 16f1fa8 commit hello.txt

Start working on feature1 branch and switch branch

I start working by adding new feature.

echo 'great feature'>feature1.txt

Once I created the file, git status shows the file as untracked files.

gitDeepDive> git status
On branch feature1
Untracked files:
  (use "git add <file>..." to include in what will be committed)
        feature1.txt

nothing added to commit but untracked files present (use "git add" to track)

Now I remember that I need to fix a bug in dev branch. I added the change to index and switched to dev and see the status. I can see the feature1.txt remains in index.

gitDeepDive> git switch dev
Switched to branch 'dev'
A       feature1.txt
gitDeepDive> git status
On branch dev
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   feature1.txt

This is when I need to save my work.

Save the work by stashing

To save the current work before switching to dev branch, I can run git stash or git stash push. Go back to feature1 branch and save the work.

git switch feature1
git stash

I can see that working tree is clean now. So I can switch to dev and do whatever I need to.

gitDeepDive> git status
On branch feature1
nothing to commit, working tree clean

When I stash, .git directory has following changes.

  • 8090065fde748fe2f374bc33bc8ddb228673aa in objects\21 folder
  • d5a21babf40bd5073e426e5582706654495458 in objects\03 folder
  • 5be8da0b67ba020ca6f330ff83cdaef9b985f2 in objects\86 folder
  • stash in refs\stash
  • several files in logs folder

stash file contains pointer to object

gitDeepDive> cat .\.git\refs\stash
218090065fde748fe2f374bc33bc8ddb228673aa

The object is a commit. The first parent is the current commit. The second one is just created.

gitDeepDive> git cat-file -p 218090065fde748fe2f374bc33bc8ddb228673aa
tree 03d5a21babf40bd5073e426e5582706654495458
parent 3705a85be1fa12a67c1f8f628a9c71cc0a3c4cdd
parent 865be8da0b67ba020ca6f330ff83cdaef9b985f2
author Kenichiro Nakamura <kenakamu@microsoft.com> 1588925120 +0900
committer Kenichiro Nakamura <kenakamu@microsoft.com> 1588925120 +0900

WIP on feature1: 3705a85 Revert "cherry-pick 367c2d0"

The second commit contains current commit as parent. Both commits references same tree object which is another object just created.

gitDeepDive> git cat-file -p 865be8da0b67ba020ca6f330ff83cdaef9b985f2
tree 03d5a21babf40bd5073e426e5582706654495458
parent 3705a85be1fa12a67c1f8f628a9c71cc0a3c4cdd
author Kenichiro Nakamura <kenakamu@microsoft.com> 1588925120 +0900
committer Kenichiro Nakamura <kenakamu@microsoft.com> 1588925120 +0900

index on feature1: 3705a85 Revert "cherry-pick 367c2d0"

This concludes stash is just another git object.

Apply the saved work

When I completed my work in dev branch, I come back to feature1 to resume my work. I can see what's stashed with git stash list.

gitDeepDive> git stash list
stash@{0}: WIP on feature1: 3705a85 Revert "cherry-pick 367c2d0"

I can restore the change by git stash apply or git stash pop. The difference is that apply take the change back but won't delete the stash, whereas pop delete the stash.

gitDeepDive> git stash apply
On branch feature1
Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   feature1.txt

I see the feature1.txt is back now.

More options

If you are familiar with first-in/last-out array or queue, stash works in a same way. That's why it uses push and pop command. If I don't need a stash anymore, I can do git stash drop or delete all by git stash clear.

Another useful feature is to use -m when push as default message may not make sense.

gitDeepDive> git stash push -m "add feature1.txt"
Saved working directory and index state On feature1: add feature1.txt
gitDeepDive> git stash list
stash@{0}: On feature1: add feature1.txt

Summary

There are other scenarios when I need to run stash to save work, but important thing to remember is that stash command can save my work.

Okay, that's it. There so many more things you need to know but I believe this is good enough information to start git.

Reference

Official document is always good to read.
Git Book

Discussion

pic
Editor guide