I've taken a look at these previous questions already:
They don't exactly address a particular issue though - there are other changes in the index! When running the rebase
command, git complains: Cannot rebase: You have unstaged changes.
Scenario:
The commit previous to the last one (do I refer to that as "2 HEADs ago"?) was a refactor commit. I currently have in the index many unstaged changes, but only some of which I want to add to the previous to last commit.
I'm imagining the way to do this would be to:
stash
all of my current changesrebase -i
to the previous to last commit (changing index and moving Head, right?)- load the stash into my index without changing Head (how?)
- use
add -p
andcommit --amend
to selectively modify this old commit rebase --continue
to finish (updates children, moves Head back to where I started, what happens to index?)- then pop/clear the stash (index back to where I started).
Is this correct? If it is, how do I do step 3? If it isn't, what should I be doing instead?
Also, note that I'm still learning about git and am still not 100% sure I'm referencing things in git (Head, index, stash, etc) properly.
Solution:
For anyone else this may help, these are the steps I actually took:
git stash
all of my current changesgit rebase -i <ID>
to the parent of the previous to last commit, changing index and moving Headgit stash apply
load the stash into my index without changing Head- if you have conflicts,
git reset HEAD <file>
to unload files staging. Make sure staging is clear.
- if you have conflicts,
- use
add -p
andcommit --amend
to selectively stage changes and commit them git reset --hard
to discard index so it matches Headgit rebase --continue
to finish. updates children, moves Head back to very start, but with changes- history is now forked into two versions. The other branch ends at the WIP previously stashed
- then pop the stash to bring index back to where I started. The other branch is also cleared.
Your plan sounds good. A
git stash apply
orgit stash pop
will modify the working tree and/or index, but will not change HEAD, so you should be able to do it while in a rebase edit.With git1.8.4 (July 2013), you can choose to:
So in your case, this could work (and save your work in progress in the meantime):
See commit 587947750bd73544a6a99811f0ddfd64e1ff1445:
Note: git 2.0.1 (Jult 25th, 2014) handle the autostash case.
See commit e4244eb from Ramkumar Ramachandra (
artagnon
) (also in his blog):rebase -i
: handle "Nothing to do" case withautostash
With the latest git, simply do
git config rebase.autostash true
to makerebase [-i]
work in a dirty worktree.If I understand what you want to do, it's not much different than the answer on your first link, you just need to stash the changes you don't want to add to the older commit. You can do it like this:
aaaaaaa
and its parent isbbbbbbb
, you wantbbbbbbb
.git rebase -i bbbbbbb
(substituting the correct commit as determined in step 3). Move the most recent commit ("add this") up to just below the commit you're modifying and change it frompick
tofixup
. This will add it to that commit without change that commit's message.This will open a text editor with a list of commits--one commit per row. Delete the first row, which is the old commit that you want to replace. Save and close.