Git is a slick revision control tool – if you haven’t used it yet, check out (IMHO) the best resource/tutorial on it: the Pro Git book.
Not only is it slick for people to use, it’s also really easy to write shell scripts to do repetitive work for you. The two examples I’m showing today come from my work on VR Juggler.
Moving branches between equivalent but not matching git-svn clones
I had been working with the VR Juggler source code using an automated git-svn mirror for some time (run using Jenkins and the scripts in my jenkins-svn2git repository), which worked pretty well. At least, a lot better than when I was just using SVN directly, since I don’t have commit access on the project. Eventually, upstream decided to switch to git (yay!) which they did a nice job of doing (authors all right, branches, tags, etc.), but now I had a problem – since they didn’t use git-svn exactly the same way I did, they had no commits in common with my mirror. (In addition to the authors thing, in this case, they had a https google code svn address, and mine was the http anonymous address.) I wanted to be able to relatively easily move my “work in progress” branches from my old mirror to the new official one (so that they branched from the same original SVN commit), so I wrote a little script to do it. Step 0 is to add the new official upstream as a remote to a clone of your own repo and fetch. You’ll see a no commit commits warning which you can smile and ignore. I made a fresh clone so that if something went wrong, nothing was lost.
I’ve posted my git-svn port-branch script as a Gist for your enjoyment and use. It’s easily the most involved git-related script I’ve ever written, but it follows essentially just these steps:
- Accept up to two inputs:
- <newupstreambranch>: the name of the new upstream (remote tracking) branch where we’ll be able to search the log to find a good commit to move to
- <yourbranch>: the name of the branch you’d like to move. (If the latter isn’t specified, the currently-checked-out branch is used.)
- If the branch <yourbranch> doesn’t exist as a local branch, create it from origin/<yourbranch>
- Use git log to find the most recent parent of your branch that includes a “git-svn-id:” line, and save that commit hash
- Extract a portion of the git-svn-id: line (everything after the domain name), and search the history of <newupstreambranch> for a commit that includes that text. If everything goes right, this should be the “new” git equivalent of the same svn commit as the git commit found in step 3.
- Do a git rebase –onto to transplant the non-svn commits over to the new parent.
Forward/backporting feature branches automatically
I’m used to the process of working on a fix, getting a nice topic branch with just those changes, then using a bug tracker/pull request/git format-patch to submit them. On some projects, such as VR Juggler, patches are most appreciated if provided in matching form for both the development version (master, formerly trunk) and the stable maintenance branch (in this case, 3.0). I had done a fairly mechanical process of a git rebase –onto to transplant my topic branches back and forth for some time. Since I had accumulated a number of unsubmitted patches, however, I realized I should just automate the process.
Thus I present another shell script as a Gist: port-patch.sh automatically forward-ports or backports your patches in topic branches. This one is more likely to need a little manual tweaking for use outside of VR Juggler, since I wanted it to figure out whether I was porting from 3.0 to master or vice-versa, but it’s a definite timesaver. Its basic process is the following:
- Figure out whether the branch we’re porting is for stable or development based on the name. (probably could have used merge-base or something, but this gets the job done)
- Compute the name of the root branch we’re porting from, the name of the root branch we’re porting to, and the name of the topic branch we’ll create.
- Create our new branch at our old branch.
- Do a git rebase –onto of our new branch to change its parent.
- And, for my own ease of bug filing, if the user name is rpavlik, echo the github compare URLs that I’ll paste into the report. 🙂