Skip to content
academia.sh

Lesson 14 / 15

Stash

Temporarily setting aside unfinished work; the stash stack, inspecting its content, including untracked files, and what the stash corresponds to in the object model.

Published Updated

In this lesson

  • Sets aside an unfinished change without committing it, and brings it back
  • Lists stash entries and inspects their content
  • Shows how the stash is represented in the object database
Contents

The tools covered so far were about completed changes: a change is either committed or undone. There is a third situation — the change is unfinished, and it becomes necessary to switch to other work. Committing is premature, because there is no working whole yet; undoing is a loss.

The stash is a holding area defined for exactly this situation: the working directory and the staging area are cleaned, their content is set aside, and it is brought back later.

Unfinished Work

An option that lists all the terms is being added to the search script. The usage line has been updated, the implementation has not been written yet; an untracked file has also been created as a to-do list. To set this state up, the usage line is changed and the to-do file is written:

sed -i.bak 's/ara.sh ARANAN/ara.sh ARANAN | ara.sh -l/' ara.sh
rm ara.sh.bak
echo "- [ ] -l seçeneğini gerçekleştir" > TODO.md
git status --short
 M ara.sh
?? TODO.md

Meanwhile a gap in the documentation is reported, and it needs to be fixed first. The unfinished work cannot be committed.

Putting Work in the Stash

A stash entry is a commit too and carries a timestamp like one; so that your outputs stay the same as in this lesson, the date is written first (the date variables stay defined in the open session; retype them if you opened a new terminal):

export GIT_AUTHOR_DATE="2024-03-12 09:30:00 +0300"
export GIT_COMMITTER_DATE="2024-03-12 09:30:00 +0300"
git stash push -m "listeleme seçeneği, yarım"
Saved working directory and index state On main: listeleme seçeneği, yarım
git status --short
?? TODO.md

The change in the tracked file disappeared; the working directory returned to its state at the last commit. The untracked TODO.md stayed in place: by default, the stash takes only tracked files.

The -m option attaches a description to the entry. If no description is given, the last commit’s subject line is put in its place; once multiple entries pile up, these descriptions stop being distinctive.

The Stash Is a Stack

git stash list
stash@{0}: On main: listeleme seçeneği, yarım

Entries behave like a stack: the most recently added one becomes stash@{0}, earlier entries shift back by one position. The last-in-first-out order defined in the Data Structures course is applied here directly. Access is not limited to the stack, though: any entry can be named by its index number and taken or deleted on its own.

Inspecting the Content

git stash show
 ara.sh | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)
git stash show -p
diff --git a/ara.sh b/ara.sh
index 582ddde..078ea08 100755
--- a/ara.sh
+++ b/ara.sh
@@ -2,7 +2,7 @@
 # terimler.txt içinde arama yapar.
 
 if [ $# -ne 1 ]; then
-    echo "kullanım: ara.sh ARANAN" >&2
+    echo "kullanım: ara.sh ARANAN | ara.sh -l" >&2
     exit 1
 fi
 

The second command gives the full diff. If no entry is specified, stash@{0} is assumed; for another entry, its name is written.

Interrupting Work

Because the working directory is clean, the urgent fix is made comfortably and committed:

cat >> README.md <<'END'

Arama büyük/küçük harfe duyarlı değildir.
END
export GIT_AUTHOR_DATE="2024-03-12 09:48:00 +0300"
export GIT_COMMITTER_DATE="2024-03-12 09:48:00 +0300"
git commit -a -m "Aramanın harf duyarsızlığını README'de belirt"
[main 11fe7e8] Aramanın harf duyarsızlığını README'de belirt
 1 file changed, 2 insertions(+)

Bringing It Back

git stash pop
On branch main
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:   ara.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	TODO.md

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (f319b5815214cb386c16d3fe061c284d6ff9936d)

The unfinished work came back, and the stash entry was deleted. The last line reports the deleted entry’s object ID; if this ID is saved, the entry can be brought back even if it is deleted by mistake.

The distinction between the two commands matters:

Command Effect
git stash apply Applies the content, leaves the entry in the list
git stash pop Applies the content and drops the entry from the list
git stash drop Deletes the entry without applying it
git stash clear Deletes every entry

Because a conflict can arise while applying, apply is preferred in cases where the outcome is uncertain: if the application fails, the entry is still in the list.

Including Untracked Files

export GIT_AUTHOR_DATE="2024-03-12 10:05:00 +0300"
export GIT_COMMITTER_DATE="2024-03-12 10:05:00 +0300"
git stash push -u -m "listeleme seçeneği, yarım"
Saved working directory and index state On main: listeleme seçeneği, yarım
git status --short

The output is empty; TODO.md has been stashed too. The -u option covers untracked files as well. Ignored files need a separate option; the default behavior leaves them in place.

What the Stash Is in the Object Model

The stash is not a separate data structure. It is a ref named refs/stash, and what it points to is a commit:

git rev-parse stash@{0}
48acf5295ce885fe839291522c1d8e48d7ad73e1
git cat-file -p stash@{0}
tree fa90a8ed35bd3b7bad8a3f7048186a030b33df2e
parent 11fe7e8840e866dda55da81f522f27f3268f1751
parent 22beea37c86e26d1cbe008233684b5d656b87945
parent f5310757c803a7c475d9ee8c0a7f972b8db76418
author Deniz Kaya <[email protected]> 1710227100 +0300
committer Deniz Kaya <[email protected]> 1710227100 +0300

On main: listeleme seçeneği, yarım

There are three parent lines. The first is the branch tip at the moment the stash was taken; the second is a commit storing the staging area’s state at that moment; the third, because -u was used, is a commit storing the untracked files. Without -u there would have been two parents.

This structure answers the lesson’s opening question at the level of the object model: the stash is not “a temporary area” — it is a small piece of history made of ordinary commits, just attached to no branch. Stash entries also stand in the object database, and once they become unreachable, they fall within the scope of garbage collection.

Limits

The stash is local and is not shared; entries in one copy of the repository do not show up in other copies. It carries no structure beyond descriptions: entries are neither sorted nor grouped. For this reason it is not suitable for long-term holding — which piece of work an accumulated entry belongs to becomes unclear before long.

If unfinished work needs to be held for days, the right tool is not the stash but commits written on a separate branch. Branches are the subject of the Branching and Collaboration course.

In the example repository, the entry is brought back:

git stash pop
On branch main
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:   ara.sh

Untracked files:
  (use "git add <file>..." to include in what will be committed)
	TODO.md

no changes added to commit (use "git add" and/or "git commit -a")
Dropped refs/stash@{0} (48acf5295ce885fe839291522c1d8e48d7ad73e1)

The option is then completed: the script is rewritten so that it prints only the Turkish column when -l is given, TODO.md is deleted, and the change is committed:

cat > ara.sh <<'END'
#!/bin/sh
# terimler.txt içinde arama yapar.

if [ $# -ne 1 ]; then
    echo "kullanım: ara.sh ARANAN | ara.sh -l" >&2
    exit 1
fi

if [ "$1" = "-l" ]; then
    cut -d '|' -f 1 terimler.txt
    exit 0
fi

if ! grep -i -- "$1" terimler.txt; then
    echo "eşleşme yok: $1" >&2
    exit 2
fi
END
rm TODO.md
export GIT_AUTHOR_DATE="2024-03-12 10:20:00 +0300"
export GIT_COMMITTER_DATE="2024-03-12 10:20:00 +0300"
git commit -a -m "Tüm terimleri listeleyen -l seçeneğini ekle"
[main a0e3bfe] Tüm terimleri listeleyen -l seçeneğini ekle
 1 file changed, 6 insertions(+), 1 deletion(-)

Summary

  • The stash sets aside changes in tracked files and returns the working directory to its state at the last commit.
  • Entries are held in stack order; stash@{0} is the most recently added.
  • apply leaves the entry in the list, pop drops it, drop deletes it without applying it.
  • The -u option covers untracked files too.
  • A stash entry is a commit with two or three parents, attached to no branch.

Next Step

Specific points in history have not been given human-readable names; everything has been referred to by forty-character IDs or by relative notation. When a release is published, that point needs a permanent name. The course’s last lesson takes up tags, the fourth object type, and their relationship with semantic versioning.

To keep your progress and take notes, Log in

My notes

Log in to take notes.

Start typing to search.

↑↓ ↵ Esc navigate · open · close