Rewinding during rebase
A fellow pythonaut asked a question on #python.fi IRC channel: would
it be possible to "rewind" during
git rebase --interactive? He
wanted to go back and edit a few commits during his massive rebase
operation and then continue the operation from the same point.
I assume you know in general what
rebase does (too bad the kernel.org
has no longer the man pages, or anything to that matter, served). If
not, I suggest to check that previous link or to run
rebase on your commandline.
Now, let's assume you have following repository structure:
D - E - F (*another-branch) / A - B - C (master)
You want to rebase
another-branch on top of the
master and edit
every one of those commits on the way. Naturally, you use
--interactive master while checked in
another-branch. Now you edit
commits D and E, transforming them to D' and E' respectively, and you
have a following repository structure (in middle of the rebase):
D - E - F (another-branch) / A - B - C - D' - E' - F' (HEAD) ^ master
Now, while editing F, you notice that you forgot to add something in D while rebasing it. Traditionally, the two options here are to abort rebase, rebase again and correct mistakes or to skip remaining commits and manually cherry-pick them back after rebase. But let's assume you've modified a load of commits and need to modify yet another load of commits in this rebase, so you don't want to abort. The solution? Let's just mimic how the rebase works!
Magic part: Rewinding in rebase!
First: Let's create us a point to return to by creating a temporary
branch in the F commit:
git branch continue. So you have following
D - E - F (another-branch) / A - B - C - D' - E' - F' (HEAD/continue) ^ master
Next we'll check out the commit we want to modify:
git checkout D'
and hack it for the parts needed. After hacking, we'll
replay the rebase: Technically rebase with edits is just cherry
picking of commits, so well do that. First let's see what to
cherry-pick by running
git log continue, which returns something
486106d edit edit (F) ea857b6 Moar edits (E')
While repository looks like this:
D - E - F (another-branch) / A - B - C - D'' - E' - F' (continue) ^ ^ master HEAD
Now we just replay the rebase by issuing
git cherry-pick ea857b6 and
git-cherry-pick 486106d. Now we're back at the point where we
rewinded to the D' and can continue rebase normally! Just do the edits
on the F you need to do and say
git rebase --continue and you'll get
on with your rebase, and finally the tree looks like this:
A - B - C - D'' - E' - F (HEAD/another-branch) ^ master
Word of caution
This is more of a proof of concept trick and has worked on one real
life scenario (and I've tested it on simulated environment), but I
recommend you to back up your working directory /
.git before trying
this at home.
Or (thanks Akheron) true warrior just digs through reflog and does not waste extra disk space for puny backups!