Git stash uncached: how to put away all unstaged changes?

Learn git stash uncached: how to put away all unstaged changes? with practical examples, diagrams, and best practices. Covers git, git-stash development techniques with visual explanations.

Git Stash Uncached: How to Put Away All Unstaged Changes

Hero image for Git stash uncached: how to put away all unstaged changes?

Learn how to effectively use git stash to temporarily save only your unstaged modifications, leaving staged changes intact. This guide covers common scenarios and practical commands.

Git's stash command is an incredibly powerful tool for temporarily shelving changes you're not ready to commit. While git stash by default saves both staged and unstaged changes, there are scenarios where you might want to stash only the unstaged modifications, leaving your carefully prepared staged changes untouched. This article will guide you through the process of selectively stashing unstaged changes, explaining why and how to do it effectively.

Understanding Git Stash Behavior

Before diving into selective stashing, it's crucial to understand how git stash operates by default. When you run git stash (or git stash save), Git takes all changes in your working directory that are tracked by Git (both staged and unstaged) and saves them onto a stack of stashes. It then reverts your working directory to the HEAD commit, leaving it clean. Untracked files are not stashed by default, but can be included with the -u or --include-untracked option, or even ignored files with -a or --all.

flowchart TD
    A[Working Directory] --> B{git stash?}
    B -- Yes --> C[Staged Changes]
    B -- Yes --> D[Unstaged Changes]
    C --> E[Stash Stack]
    D --> E[Stash Stack]
    E --> F[Working Directory Clean]

Default Git Stash Behavior

The Need for Selective Stashing

Why would you want to stash only unstaged changes? Consider these common situations:

  1. Interruption during staging: You've carefully staged a set of changes for a specific commit, but then an urgent bug fix or context switch comes up. You want to save your current work-in-progress (the unstaged changes) without losing your staged changes.
  2. Refining a commit: You've staged some changes, but then made additional experimental modifications that you're not sure about. You want to stash these new, unstaged changes to focus on committing only the staged ones.
  3. Keeping a clean staging area: You prefer to keep your staging area pristine for a specific commit, but need to temporarily remove other modifications from your working directory.

How to Stash Only Unstaged Changes

The trick to stashing only unstaged changes involves temporarily staging all your changes, then stashing, and finally unstaging the original changes. Here's the step-by-step process:

1. Stage all current changes

First, stage all changes in your working directory, including both those you originally intended to stage and the new unstaged ones. This ensures that git stash will capture everything.

2. Stash all changes

Now, perform a regular git stash. Since all changes are staged, this will stash everything, effectively cleaning your working directory.

3. Unstage the original changes

After stashing, your working directory is clean. The next step is to bring back the changes you originally had staged. You can do this by applying the stash, but immediately resetting the index to the HEAD commit. This will unstage the changes that were part of the stash, leaving them as unstaged modifications in your working directory.

4. Re-apply the stash (optional)

If you want to bring back the unstaged changes you just stashed, you can now apply the stash. Since your original staged changes are now unstaged, applying the stash will reintroduce the other changes as unstaged, effectively achieving your goal.

# 1. Stage all current changes (including those you want to stash)
git add .

# 2. Stash all changes
git stash save "Temporarily stashing all changes"

# 3. Unstage the original changes (the ones you wanted to keep staged)
git reset HEAD^

# 4. Now, your original staged changes are unstaged.
#    If you want to bring back the *other* changes you stashed, apply the stash:
git stash pop

Commands to selectively stash unstaged changes

# Stash only unstaged changes, leaving staged changes intact
git stash --keep-index

Using git stash --keep-index for direct unstaged stashing

flowchart TD
    A[Working Directory] --> B{Staged Changes}
    A --> C{Unstaged Changes}
    B -- Kept --> D[Staging Area]
    C -- Stashed --> E[Stash Stack]
    D --> F[Ready for Commit]

Git Stash with --keep-index Behavior