Git ... oh my


In recent projects I’ve been using a lot of git and I love it. As a distributed source control tool it’s brilliant. This is particularly true when you need to gather and manage a wide variety of disparate patches and commits. On the projects I work on we get patches via a lot of paths:

  • Diffs attached to tickets
  • Diffs sent via email
  • Git branches and cherry picks

With the former two paths we (mostly me) have been cutting and pasting patch diffs into files or using wget. We then use the patch command to apply the diffs to various branches and then commit the results. With this approach we often lose track of the patches ownership and author. This is problematic from two perspectives - we can’t allocate credit where it is due and when something goes wrong with a commit it’s often hard to track down the original author. We obviously don’t have this issue with Git repositories and merging branches or cherry picking specific commits. With the latter it is easy to track patch authors and ownership - even through multiple merges and rebasing. So I like it when people fork the Github repo and provide a commit or feature/ticket branch when supplying code. But for the others I’m trying to bring our process a little closer to Git by using the git am and git apply commands (also git-am and git-apply - though the git-command syntax is being deprecated) to pull in diffs and patches. The git am command processes mailboxes (mbox and Maildir), mail messages or RFC 2822 formatted messages provided via standard input. The git apply command applies a unified diff file to the current working tree. Let’s start with the easy to use git apply command. Let’s take one of our use cases: downloading a patch from our tracker and applying it. First, we wget our patch file: $ cd /tmp $ wget We then change directory into our Git repo and check what branch we’re in. $ cd ~/src/puppet $ git branch * master We can now feed our patch file into git apply using something like cat and a pipe. $ cat /tmp/patch2222.diff | git apply This will add the patch to the current branch and commit it. Another useful trick is the –amend option. If your current commit is not yet pushed you can amend it. Just make your required edits, git add the updated files: $ git add _filename_ And then run: $ git commit --amend Git will populate your editor with the last commit message and you can update the commit. We could also create a separate branch for our new commit. $ git checkout -b tickets/master/2222 $ git apply < /tmp/patch2222.diff Here we’ve directed the file straight into git apply rather than piped the output of the cat command. We can then merge this into the appropriate branch when ready. $ git merge tickets/master/2222 Don’t forget you can also use the git rebase command to ensure your branch is rebased against the branch you’re merging into, to squash multiple commits or to redo the commits - git rebase (especially the –interactive switch) is the business. :) Using our second command, git am, we can also pull patches straight from a mail client. For example, on Thunderbird, I open up the message I want to import then (on OSX - on PC it’s basically the same commands prefixed with Ctrl not Command):

  1. Command-U to show the full message including headers
  2. Command-A to select all of the message
  3. Command-C to copy the selection

I can then go to the command line and do: $ cat | git am Followed by a Command-V to paste the content, and then Control-D to end the cat and submit my patch to be committed. The git am command is quite clever. The author of the commit will be pulled from the From line of the message, the date and time of the commit from the date and time the message was sent and the Subject and Body are used as the title and body of the commit message. We can also add the -s switch to the git am command. This adds a “Signed-off-by” line to the commit message using your details (usually name and email address). $ cat | git am -s It’s not perfect model yet - I probably should be using git am on a Maildir or mbox file which contains our patches but in our small development team I have the luxury of just selecting the patches and emails I want.