Lesson 5 of 7 in Branching & Merging

Switching with uncommitted work

Story: Half-finished work doesn't travel well between timelines. Juno keeps a pocket for it.

Changes you haven't committed come along when you switch branches, as you saw in Branches. But when the other branch has a different version of a file you changed, git refuses rather than overwrite your work:

$ git switch title
error: Your local changes to the following files would be overwritten by checkout:
	index.html
Please commit your changes or stash them before you switch branches.
Aborting

You could commit the change, but it isn't finished, and it may not even belong on this branch. The other way out is the stash: a place to set changes aside and bring them back later, on any branch.

Setting changes aside: git stash

$ git stash
Saved working directory and index state WIP on main: a4b8d97 Style the heading

git stash saves your changes, staged or not, in a new stash entry. Then it puts your files and the staging area back as the last commit has them. Nothing is in the way any more, so git switch title works. git stash is short for git stash push.

A stash entry is stored as a commit of its own, on no branch. Your branch doesn't move.

A new file that git doesn't track yet isn't stashed: it stays in your files, and comes along when you switch. git stash -u (for "untracked") stashes new files too. When new files are all you've changed, plain git stash says No local changes to save and does nothing.

Seeing what's stashed: git stash list

You can stash more than once. Each entry goes on top of the ones before, and git stash list lists them, newest first:

$ git stash list
stash@{0}: On main: Purple heading
stash@{1}: On main: New heading

stash@{0} is the newest entry, and stash@{1} the one before it. Give each entry a message with -m, as in git stash push -m "Purple heading", so you can tell them apart later. Without one, git writes WIP on the branch you were on, and the last commit.

Bringing changes back: pop and apply

git stash pop puts the newest entry's changes back in your files and drops the entry from the stash. git stash pop stash@{1} takes that entry instead.

You can pop on any branch, not just the one you stashed on. git merges the entry's changes into the files you have now, so changes with an unchanged line between them combine, as in a merge. When they can't combine, the pop stops with a conflict in that file, as a merge does. The entry stays in the stash: The stash entry is kept in case you need it again. Fix the file as you would after a merge, then drop the entry yourself.

Changes come back unstaged, even ones you had staged. Only a new file you'd staged comes back staged. And if you've changed a file since you stashed, and the entry changes it too, git refuses to pop, and keeps the entry.

git stash apply does what pop does, but keeps the entry. git stash drop throws an entry away: the newest, unless you name another. A dropped entry is gone from the list, so drop only what you're done with.

Command What it does
git stash Sets your changes aside in a new stash entry and puts your files back as the last commit has them. Short for git stash push.
git stash push -m "<message>" The same, with a message to tell the entry apart.
git stash -u Stashes new, untracked files too.
git stash list Lists the entries, newest first: stash@{0}, stash@{1}, and so on.
git stash pop Brings the newest entry's changes back and drops it. Name an entry to take that one.
git stash apply Brings the changes back and keeps the entry.
git stash drop Throws an entry away: the newest, unless you name another.

New commands

  • git stash push
  • git stash push -m
  • git stash push -u
  • git stash list
  • git stash pop
  • git stash apply
  • git stash drop

Explainer: Setting changes aside to switch

project: your repo, you are here37d7cf7 Add a README37d7cf7ab89288 Add the home pageab89288a4b8d97 Style the headinga4b8d9766c87ab Name the page66c87abcd6e8fd index on main: a4b8d97 Style the heading (unreachable)cd6e8fdd6c407a WIP on main: a4b8d97 Style the heading (unreachable)d6c407amainHEAD → title
The repository at the end of the Explainer.
Graph as text

project: your repo, you are here

  • HEAD → title at 66c87ab "Name the page"

Branches and tags

  • main at a4b8d97 "Style the heading"
  • title at 66c87ab "Name the page"

Commits, newest first

  1. 66c87ab "Name the page"; parent a4b8d97; refs: HEAD → title
  2. a4b8d97 "Style the heading"; parent ab89288; refs: main
  3. ab89288 "Add the home page"; parent 37d7cf7
  4. 37d7cf7 "Add a README"; no parent

Unreachable

  • d6c407a "WIP on main: a4b8d97 Style the heading"; parents a4b8d97 and cd6e8fd
  • cd6e8fd "index on main: a4b8d97 Style the heading"; parent a4b8d97

Challenge 1 of 3

Story: You've been rewriting the welcome in the wrong timeline, Agent. Carry it over to the right one, and drop nothing on the way.

You started changing the welcome line in index.html on main, but the change belongs on the branch title. git switch title refuses, because title changes index.html too.

Move your change over to title, without committing it, and leave nothing in the stash.

Unlocks after Basics.

Terminal

Unlocks after Basics.

This Lesson can be played once Basics is complete. Its text and Explainer are open to everyone.