tags:

views:

59

answers:

3

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?

A: 

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.
VonC
`git stash` implies a `git reset --hard` so `git reset --mixed` is a no-op and the second `git stash` has nothing to do?
Charles Bailey
@Charles: right. I have updated the answer to use `git stash --keep-index`. That way, the `git reset --mixed` has something to do ;)
VonC
OK, but not `git drop stash@{1}` surely isn't correct and if the last step in your process is `git add -A` then your not going to end up with any unstaged changes? I'm not convinced stash is the answer, it seems way to complex to get it right ;-) .
Charles Bailey
first step should be `git stash save --keep-index`, and I guess I have to apply the first stash before dropping it in step 4. Anyway this way does not work for me, because if I have 2 stashes and try to apply one of them, both of them become applied unexplainable
whitered
I just can't get the stash approach to work. The problem is that the second stash saves both changes (the working tree and HEAD never change between the two stashes), even if it records whether these were staged or not. Applying the second stash always applies both changes.
Charles Bailey
Charles Bailey
@Charles: "Use git stash when you want to record the current state of the working directory **and the index** ". I had completely missed that little fact ;) Just for the fun of it, I have published another '`git stash`' version.
VonC
+2  A: 

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
Charles Bailey
yes, this way is too complex to understand or remember it, but it really works. I guess is there an easier way, maybe using patches?
whitered
@whitered: Open question: what are you having difficulty understanding? The man pages for reset, rebase and commit should describe all the options I've used in detail and the steps I use are supposed to be step-by-step logical actions?
Charles Bailey
+1  A: 

The way with patches:

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
whitered
Interesting solution as well. +1. Just out of curiosity, did you re-try the updated version of my `git stash` answer?
VonC
Yes, I have re-tried it, it works fine unless there are some new (untracked before) files staged. My variant with patches fails in this case too.
whitered