Friday, July 25, 2014
I cannot stand reviewing patches with gmail or any GUI e-mail client. I use mutt. On my last post I explained how you can apply patches directly from within mutt onto a git tree with a few shortcuts without leaving the terminal. This small post provides the next step to allow you to grow a mustache... I mean, get you to enjoy your mutt experience even more when reviewing patches by getting you colored diffs to match the same colors provided to you by good 'ol 'git diff'. Edit your .muttrc file and add these.
# Patch syntax highlighting
color normal white default
color body brightwhite default ^[[:space:]].*
color body brightwhite default ^(diff).*
color body white default ^[\-\-\-].*
color body white default ^[\+\+\+].*
color body green default ^[\+].*
color body red default ^[\-].*
color body brightblue default [@@].*
color body brightwhite default ^(\s).*
color body brightwhite default ^(Signed-off-by).*
color body brightwhite default ^(Cc)
Thursday, July 17, 2014
This post is for project maintainers using git who wish to merge patches easily into a project directly from mutt. Projects using git vary in size and there many different ways to merge patches from contributors. What strategy you use can depend on whether or not you are expecting to merge hundreds of patches, or just a few. If you happen to be very unfortunate and are forced to use Gerrit a mechanism was chosen for you for review and how patches will get merged / pushed. If you're just using raw git directly you can do whatever you like. For big projects git pull requests are commonly used. Small projects can instead live with manual patch application from an mailbox inbox. Even large projects can't realistically expect folks to be submitting every patch with pull requests, and so manual patch application also applies to large projects. How you get your patch out of your inbox and get it merged will vary depending on what software you are using to read your mailbox. Tons of folks are using gmail these days and even there it's not that easy: you'd have to go to the right pane, go to drop down menu and select "Show original", then save that page as a text file, edit it to remove the top junk right before the From: and finally you can then git am that file.
This doesn't scale well. A plugin can surely help but bleh, the command line is so much better. For that you can use Mutt. The typical approach on mutt is to use the default hooks to save a file onto disk and then go and 'git am' it. It'd be much easier if we just had hooks to apply patches directly into a git tree though. The following are configuration options you can use and a bit of shell that will allow that. Ben Hutchings's blog post on git and mutt in 2011 described a way to extract patches into a directory and then you'd just git am them. Those instructions no longer work on newer versions of mutt, I'll provide updated settings and also extended these hooks to allow you to apply patches without even having to drop down to another shell, while also giving you the option to inspect them manually if you wish.
Here's what I have on my .muttrc :
macro index (t '
macro index (a '
macro index (g '
macro index (r '
macro index (l '
macro index ,t '
macro index ,g '
macro index ,a '
macro index ,r '
The first hook (t allows you to dump patches you tag into an ~/incoming/ directory, mutt will show you what those are. The (a will apply all the patches that you just took out into that directory. The (g hook will merge the two steps into one and just dump the tagged patches and apply them immediately. If you have to clear the ~/incoming/ directory just use the (r hook. If you'd like to review what's in that directory you can use the (l hook. With ,t you can dump the currently viewed patch into ~/incoming/, this lets you extract a patch without tagging it. The ,g hook will also skip having to tag a patch and just apply it. If you want to abort a 'git am' operation you can use ,a. Finally to reset your tree to origin, just use the ,r hook.
This all depends on 5 small scripts, the ones that change directory obviously are making these scripts depend on one single projects so the question arises as to how to generalize this so that mutt is aware of the project a patch was sent for and you can apply it to that right tree so that we don't have to stuff mutt with tons of different project specific hooks. There are two approaches that come to mind, one is to have the shell script read the List-ID tag, for example List-ID:
formail -cds ~/mailtogit/procmail -
ls -l ~/incoming/
git am ~/incoming/*.mbox
rm -f ~/incoming/*
git am -s ~/incoming/*.mbox
git am --abort
rm -f ~/incoming/*
git reset --hard origin
rm -f ~/incoming/*