Editing git commits with rebase, in particular splitting commits

Posted by Tim Connor Mon, 13 Oct 2008 04:44:00 GMT

So I have a project on github that I wanted to rework some of the commits before anyone sees them. I used to manage the project via svk, so the commits are squashed down into less granular blocks than I want for reviewing via an interface like githubs. ‘git commit —amends’ for, well, amending the last commit you made, but if the changes are further back than that, you get into the deep magic of rebasing. Much of this is discussed in the man pages, and docs for git-rebase but that can be hard to follow until you really understand what is happening.

‘git-rebase -i SHA_OF_PARENT’ lets you rollback to the commit before where you want to start mucking with stuff, mark which commits you want to edit, and then recommit them. For the simplest use case, just editing the commit messages, you just ‘commit —amend’ each time git-rebase pauses, ‘git-rebase —continue’ and repeat until done. This workflow is explained reasonably well in the docs, the only thing to emphasize that will help you understand the more complex cases is that it works by rebase pausing just after each commit you marked for editing, so that you can amend (which amends that last commit) and continue.

This segues into how splitting up of commits works. You mark for editing and rebase as usual. When it pauses after the commit you want to split up, you ‘git reset HEAD^’ to rewind one commit, while keeping the changes in the filesystem. So at this point, if you committed and continued, it’s be exactly like the simpler workflow. Instead, though, you can split up the changes: git add each subset of changes, committing them with the appropriate message. Then when you are done, rebase —continue again.

With these techniques you can rework the history completely into a better organized, more easily follow-able set of chunks. It does leave a couple problems, if it is a repo you have already pushed you will get a ‘not strictly subset’ error. If you know nobody has pulled from it, you can just push —force, but I make no guarantees what this might do to the state of other peoples repos that are pulling from the same master, especially if they are mucking about similarly.

The other problem is that this resets the authored by date on the commits, since it’s essentially nuking one commit and making a new one. I’ll discuss this in the next post manually setting the authored date in a git commit


Leave a comment