As I mentioned before, I’ve been working on and off on adding Python scripting support to GDB, with Tom Tromey and Vladimir Prus. We did the work in a git repository, separate from the GDB main repo (which still uses CVS, by the way). Now came the time to get the work we did there, separate it in patches and post them for review on the gdb-patches mailing list.
This is the tale of my patch-producing efforts. I’m sorry, it is most likely boring for everyone but me. Still, I wanted to write it down so you are free to stop reading the post here.
Anyway, back to where I was: I (foolishly, perhaps?) volunteered to create the patches. One reason for me to do that is that I actually enjoy working with and learning about source code management and related issues, and this was a good opportunity for me to improve my git-fu (since I thought git could help me do the job in a sane way, which fortunately proved to be the case).
I say foolishly because I thought it wouldn’t take too much time to cut out the patches, since I knew what I would have to do… The task of course took longer than I expected, in part because of unforeseen autotools woes, but of course also because I underestimated the effort (I am an optimist).
Here is the method I used:
First of all, I wanted to update the code to the latest CVS version of GDB, because the work in the git repo was done based on a CVS version from February… Nothing to see here, actually. I just created a new branch with the latest CVS update, and rebased the commits on top of that. In hindsight, I should have merged the new CVS update into the python branch, which would have made me deal with less conflicts. I used rebase because I thought I would cherry pick the commits later, so I wanted each of them refreshed.
Then the real fun began. I started using interactive mode of git rebase to squash related commits together (to form the patches), and reorder them. I quickly realised that with this approach I would have a bit of difficulty with commits which touched different areas of the code and crossed the borders I had in my mind for the patches I wanted to generate. I would have to first split those into smaller, more behaving commits and only then squash them with other similar changes. That seemed to be more work than really necessary.
Also, the older commits did things in ways and places which were later changed, and it looked like I would have some trouble reconciling older and newer code to fit in one patch (maybe not though, maybe that would be taken care of more or less naturally). Also, I would need to take some time to familiarise myself with the commits in the branch, because I only authored some of them. The “shuffle commits around” approach wasn’t looking very promising.
I then turned to a different strategy: I generated a big patch containing all of the code in the branch, and applied it (using the plain old patch command) on top of a clean branch which contained only the CVS HEAD version I was using as a base. All I needed to do now was to selectively add to the index the changes that I wanted to include in a patch and then commit those changes together. And repeat the process for the next patch and so on.
It proved to be a good approach, especially because of the interactive mode of git-add. This mode asks you about each change inside a modified file, letting you add that change to the index or skip it, leaving it in the working directory for a future commit. git add -i streamlined the “change picking” process quite a lot, and made the patch-cutting almost mechanical. (By the way, this feature is also available in Mercurial, with the Record extension. I even believe (not sure though) that the Mercurial extension predates git add -i) (I don’t know if Bazaar has it, would be nice to know).
In this phase of the process, git rebase -i was useful. Sometimes I came accross a change in the working directory which would fit better in a patch which I had already committed. It was simply a matter of committing that change and then shuflling it back and squashing with the proper patch.
At each commit I pushed the changes to a pristine repo which I used to build GDB and guarantee that each patch included all the changes it needed.
Voilà, at the end of the process I had a git branch where each commit corresponded to one patch which I wanted to send to the mailing list.