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.
Initial situation
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 git help
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 git rebase
--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
structure now:
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
like this:
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!
If you want to comment this blog post, just send mail to my firstname + blog @ thisdomain.tld. If the question is a proper one, it might get answered. Good ones might even end up on the site.
Tags: git version-control howto