git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: git-send-email: Send with mutt(1)

From
Jeff King <peff@peff.net>
Date
Nov 7, 2023, 17:48 UTC
Message-ID
<20231107174803.GA507007@coredump.intra.peff.net>
In-Reply-To
<ZUocFhmPHstwKCkZ@devuan>
On Tue, Nov 07, 2023 at 12:14:21PM +0100, Alejandro Colomar wrote:
> I'm trying to use mutt(1) with git-send-email(1).  Is that possible?
> I tried --sendmail-cmd=mutt, but am getting strange errors.
> The reason I want to send with mutt(1) is because it can encrypt and
> sign mail (with some tweaks), which git-send-mail(1) doesn't.

I think there's a lot of overlap between what git-send-email does and what mutt does, to the point that you probably don't need to use send-email at all.

I assume what you want out of send-email here is the actual generation of patch emails. But under the hood that is all done by git-format-patch anyway. So for example if you do:

  git format-patch --stdout origin..HEAD >patches
  mutt -f patches

And then you can use mutt's "resend-message" function to send each one. I use config like this:

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

If you're sending a long series, it's helpful to pre-populate various headers in the format-patch command with "--to", etc. I usually do so by sending the cover letter directly via mutt, and then using some perl hackery to convert those headers into format-patch args. The script I use is below (it will also, when run without a terminal, generate the patch summary for the cover letter; I use it with "r!my-script" while writing the cover letter in vim).

(This script is what I use every day, so it should be fairly robust. But it is also over 15 years old, so I don't promise there isn't a simpler way to do some of what it does ;) ).

-- >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) {
      if (/^\s+(.*)/) {
        $val .= " $1";
        next;
      }
      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;
    }
    elsif (/^subject:\s*\[PATCH v(\d+)/i) {
      print "-v$1 ";
    }
    elsif (/^$/) {
      last;
    }
  '
}
format_patch() {
  git format-patch -s --stdout --from "$@"
}
has_nonoption=
for i in "$@"; do
  case "$i" in
    -[0-9]*) has_nonoption=yes ;;
    -*) ;;
     *) has_nonoption=yes
  esac
done

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

if test -t 1; then
  format_patch "$@" >.mbox
  mutt -e 'set sort=mailbox-order' -f .mbox
  rm -f .mbox
else
  format_patch "$@" |
  perl -lne '
    if (/^Subject: (.*)/) {
      $subject = $1;
    }
    elsif ($subject && /^\s+(.*)/) {
      $subject .= " $1";
    }
    elsif ($subject) {
      print $subject;
      $subject = undef;
    }
  ' |
  sed -e 's/\[PATCH /[/' \
      -e 's/]/]:/' \
      -e 's/^/  /'
  echo
  format_patch --cover-letter "$@" |
  sed -ne '/|/,/^$/p; /^-- /q'
fi
Previous: Alejandro ColomarNext: Alejandro Colomar
Message 2 of 17 in “git-send-email: Send with mutt(1)”
  1. Alejandro ColomarNov 7, 2023
  2. Jeff KingNov 7, 2023
  3. Alejandro ColomarNov 7, 2023
  4. Jeff KingNov 7, 2023
  5. Alejandro ColomarNov 8, 2023
  6. Jeff KingNov 8, 2023
  7. Alejandro ColomarNov 9, 2023
  8. Konstantin RyabitsevNov 9, 2023
  9. Alejandro ColomarNov 9, 2023
  10. Konstantin RyabitsevNov 9, 2023
  11. Alejandro ColomarNov 10, 2023
  12. Jeff KingNov 9, 2023
  13. Alejandro ColomarNov 9, 2023
  14. Alejandro ColomarNov 10, 2023
  15. Alejandro ColomarNov 10, 2023
  16. Jeff KingNov 10, 2023
  17. Junio C HamanoNov 10, 2023

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.