What is the shortest way to swap staged and unstaged changes in git?

If some changes are added to the index and there are some changes that are not added to the index, how do I swap this two sets of changes?

  • Git unable to push to remote repository: “Read-only file system”
  • Why git under cygwin asks for password?
  • Git produces “BUG: There are unmerged index entries”
  • How do I update my forked repo using SourceTree?
  • Unable to track files within Git submodules
  • Git: definition of upward/downward directions between branches feels counterintuitive
  • git equivalent to hg mq?
  • How do I share Protocol Buffer .proto files between multiple repositories
  • How do I add my whole project on GitHub?
  • Update local master to remote master from another branch
  • Should I remove merged branches?
  • Does a svn frontend for git exist
  • 5 Solutions collect form web for “What is the shortest way to swap staged and unstaged changes in git?”

    It think that this is easiest to do with temporary commits. When you have staged and unstaged commits, you have the possibility of conflicts when trying to reorder the changes.

    Make a commit with the staged changes, create a branch for later use:

    git commit -m "Saved staged"
    git branch save-staged

    Make a commit with the unstaged changes (if the unstaged changes include new files you may need to explicitly git add them first):

    git commit -a -m "Unstaged changes"

    Rebase the unstaged changes onto the original HEAD (may involve conflict resolution):

    git rebase --onto HEAD^^ HEAD^

    Rebase the staged changes onto the unstaged changes (may involve conflict resolution):

    git reset --hard save-staged
    git rebase --onto HEAD@{1} HEAD^

    Finally, reset the index to the (originally) unstaged changes:

    git reset HEAD^

    And move the branch pointer back to the original HEAD:

    git reset --soft HEAD^

    Removed temporary branch:

    git branch -D save-staged

    For a lower-level solution, you can use a bit of plumbing to talk directly to the index:

    INDEXTREE=`git write-tree`
    git add -A
    WORKTREE=`git write-tree`
    git checkout $INDEXTREE -- .
    git clean -f
    git read-tree $WORKTREE

    What that does is build a couple of temporary tree objects in the git store, one for the index and one for the working copy. Then, it restores the old index and checks it out into the working tree. Finally. it resets the index to the version representing the old working tree.

    I haven’t tested this, so I’m not sure how well it handles added files in either the index or the working tree.

    This is based on Walter Mundt’s answer, but works better when new files are staged. This is intended to be used as a script, e.g. git-invert-index

    # first, go to the root of the git repo
    cd `git rev-parse --show-toplevel`
    # write out a tree with only the stuff in staging
    INDEXTREE=`git write-tree`
    # now write out a tree with everything
    git add -A
    ALL=`git write-tree`
    # get back to a clean state with no changes, staged or otherwise
    git reset -q --hard
    git clean -fd
    # apply the changes that were originally staged, that we want to
    # be unstaged
    git checkout $INDEXTREE -- .
    git reset
    # apply the originally unstaged changes to the index
    git diff-tree -p $INDEXTREE $ALL | git apply --index --reject

    The way with patches (it doesn’t work for binary changes):

    Save patches for both staged and unstaged states

    git diff >> unstaged.patch
    git diff --cached >> staged.patch

    Apply originally unstaged changes

    git reset --hard
    git apply unstaged.patch

    Stage this changes except the patch files

    git add -A
    git reset -- staged.patch unstaged.patch

    Apply originally staged changes

    git apply staged.patch

    Remove patch files

    rm staged.patch unstaged.patch

    Charles Bailey has a more complete solution involving commits and managing potential conflict resolution.

    I am trying to use only git stash, except what I initially overlooked was that git stash save will save both the index and the private files (which is inconvenient when you want to swap the index content with the private files content)

    You could:

    • git commit -m “temp commit” (create a commit for the current index)
    • git stash (stashing obviously what is not yet added to the index)
    • git reset --soft HEAD^ (preserve the files previously committed)
    • git stash again
    • git drop stash@{1} (applying not what you just stashed, but what you stashed before, i.e the initial changes that weren’t yet added to the index)
    • git add -A

    At the end:

    • what was initially in the index ends up being stashed
    • what was not added to the index is now added.
    Git Baby is a git and github fan, let's start git clone.