git.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
From: Jeff King <peff@peff.net>
To: Stefan Beller <sbeller@google.com>
Cc: Junio C Hamano <gitster@pobox.com>,
	Alexander Kuleshov <kuleshovmail@gmail.com>,
	"git@vger.kernel.org" <git@vger.kernel.org>
Subject: my hacky mutt-specific format-patch workflow
Date: Tue, 13 Jan 2015 20:28:19 -0500	[thread overview]
Message-ID: <20150114012819.GA7520@peff.net> (raw)
In-Reply-To: <CAGZ79kZ87ZKT5-OMTEHAMEAmZVOfku_D4vZ9jcWJ4cHrA06cSw@mail.gmail.com>

[retitling in case there is a wider audience]

On Tue, Jan 13, 2015 at 02:48:15PM -0800, Stefan Beller wrote:

> Would you mind to share (parts of) the wrapper script? We could see if that
> makes sense to incorporate into format-patch as well.

Sure, but I'll warn you it's kind of gross and specific to my workflow. :)

The script (which I call mpatch) is at the end of this message. The main
thing which may be of interest to other people is the cover-letter
handling. I write my cover letters in my normal MUA (mutt), and then
generate the series as a reply to that. The two ways it supports that
are:

  1. It generates the list of patches that I include in my cover letter
     from the mbox.  This _should_ be a "git log" one-liner, but our
     --pretty placeholders do not know how to count. Ideally I could say
     "[%i/%n]: %s", but neither of those first two exist (and %n would
     require counting all of the commits first, which might require some
     surgery to git-log).

  2. Given an existing message, it will pick out the to, cc, and
     message-id headers, and generate corresponding --to, --cc, and
     --in-reply-to arguments to feed to format-patch. I do it hackily in
     perl, but probably format-patch could do it internally if it built
     on git-mailinfo.

I typically have my MUA in one terminal and a shell running git in the
other. Even though I could run mpatch directly from the MUA, it is often
missing the context of which repo I am working in. So instead, I
typically use ~/patch as a go-between for the two sessions (both for
generating patch series, but also for applying with git-am). So I have
this in my muttrc:

  macro pager,index D '<shell-escape>rm -f $HOME/patch<enter>'
  macro pager,index A '<copy-message>~/patch<enter><enter>'

Applying a patch series from the list is just 'D' to clear the state,
then 'A' to collect whatever patches. And then I "git am ~/patch" from
the terminal window.

Generating a patch series is more like:

  1. "mpatch >~/patch" from the git terminal to generate the list of
      commits. No arguments necessary, because it uses @{upstream} as
      the base (but occasionally I use "-3" or similar if I am sending
      out new patches on top of somebody else's work).

  2. Reply or start a new thread in mutt, as normal. This becomes the
     cover letter (the to/cc comes from the reply, or I have mutt
     aliases for the list and frequent contributors, and/or I may cut
     and paste from "git log" in some cases).  Mutt dumps me in vim to
     write the actual message, and I ":r ~/patch" to pull it in.

  3. Finish and send off the cover letter. This gives it a message-id.

  4. Drop the newly-sent message into ~/patch. I usually just open my
     sent folder and use 'D', 'A' to copy it there.

  5. "mpatch" from the git terminal. The headers are picked up from
     ~/patch. Sometimes I use "-v2", which is passed to format-patch
     to get "[PATCH v2 i/n]".

After that, I'm in mutt with an mbox full of the patches. I have this
hotkey in mutt:

  macro index,pager b ":set edit_headers=yes<enter><resend-message>:set edit_headers=no<enter>"

which dumps me vim, with the headers. From there I give a final
proofread, write any comments below the "---", and then send it.

I imagine for the last bit many people have a similar workflow without
mutt that is something like:

  1. format-patch into ~/patch/*

  2. $EDITOR ~/patch/*

  3. git send-email ~/patch/*

Those people would potentially benefit from the format-patch in step 1
picking up the headers from an existing message.

-Peff

-- >8 --
#!/bin/sh

upstream_branch() {
  current=`git symbolic-ref HEAD`
  upstream=`git for-each-ref --format='%(upstream)' "$current"`
  if test -n "$upstream"; then
    echo $upstream
  else
    echo origin
  fi
}

get_reply_headers() {
  perl -ne '
    if (defined $opt && /^\s+(.*)/) {
      $val .= " $1";
      next;
    }
    if (defined $opt) {
      print "--$opt=", quotemeta($val), " ";
      $opt = $val = undef;
    }
    if (/^(cc|to):\s*(.*)/i) {
      $opt = lc($1);
      $val = $2;
    }
    elsif (/^message-id:\s*(.*)/i) {
      $opt = "in-reply-to";
      $val = $1;
    }
  '
}

has_nonoption=
for i in "$@"; do
  case "$i" in
    -[0-9]) has_nonoption=yes ;;
    -*) ;;
     *) has_nonoption=yes
  esac
done

: ${REPLY:=$HOME/patch}
test -n "$REPLY" && eval "set -- `get_reply_headers <\"$REPLY\"` \"\$@\""
test "$has_nonoption" = "yes" || set -- "$@" `upstream_branch`

git format-patch -s --stdout --from "$@" >.mbox
if test -t 1; then
  mutt -f .mbox
else
  perl -lne '
    if (/^Subject: (.*)/) {
      $subject = $1;
    }
    elsif ($subject && /^\s+(.*)/) {
      $subject .= " $1";
    }
    elsif ($subject) {
      print $subject;
      $subject = undef;
    }
  ' .mbox |
  sed -e 's/\[PATCH /[/' \
      -e 's/]/]:/' \
      -e 's/^/  /'
fi
rm -f .mbox

  reply	other threads:[~2015-01-14  1:28 UTC|newest]

Thread overview: 10+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2015-01-13 17:54 [PATCH] format-patch: print format-patch usage if there are no arguments Alexander Kuleshov
2015-01-13 18:43 ` Junio C Hamano
2015-01-13 18:52   ` Alexander Kuleshov
2015-01-13 19:17     ` Junio C Hamano
2015-01-13 20:00       ` Stefan Beller
2015-01-13 22:28         ` Junio C Hamano
2015-01-13 22:45           ` Jeff King
2015-01-13 22:48             ` Stefan Beller
2015-01-14  1:28               ` Jeff King [this message]
2015-01-13 23:41             ` Junio C Hamano

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=20150114012819.GA7520@peff.net \
    --to=peff@peff.net \
    --cc=git@vger.kernel.org \
    --cc=gitster@pobox.com \
    --cc=kuleshovmail@gmail.com \
    --cc=sbeller@google.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).