format-patch: teach --no-encode-email-headers

When commit subjects or authors have non-ASCII characters, git
format-patch Q-encodes them so they can be safely sent over email.
However, if the patch transfer method is something other than email (web
review tools, sneakernet), this only serves to make the patch metadata
harder to read without first applying it (unless you can decode RFC 2047
in your head). git am as well as some email software supports
non-Q-encoded mail as described in RFC 6531.

Add --[no-]encode-email-headers and format.encodeEmailHeaders to let the
user control this behavior.

Signed-off-by: Emma Brooks <me@pluvano.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Emma Brooks 2020-04-08 04:31:38 +00:00 committed by Junio C Hamano
parent 9fadedd637
commit 19d097e3d7
9 changed files with 85 additions and 3 deletions

View File

@ -57,6 +57,11 @@ format.suffix::
`.patch`. Use this variable to change that suffix (make sure to
include the dot if you want it).
format.encodeEmailHeaders::
Encode email headers that have non-ASCII characters with
"Q-encoding" (described in RFC 2047) for email transmission.
Defaults to true.
format.pretty::
The default pretty format for log/show/whatchanged command,
See linkgit:git-log[1], linkgit:git-show[1],

View File

@ -24,6 +24,7 @@ SYNOPSIS
[(--reroll-count|-v) <n>]
[--to=<email>] [--cc=<email>]
[--[no-]cover-letter] [--quiet]
[--[no-]encode-email-headers]
[--no-notes | --notes[=<ref>]]
[--interdiff=<previous>]
[--range-diff=<previous> [--creation-factor=<percent>]]
@ -253,6 +254,13 @@ feeding the result to `git send-email`.
containing the branch description, shortlog and the overall diffstat. You can
fill in a description in the file before sending it out.
--encode-email-headers::
--no-encode-email-headers::
Encode email headers that have non-ASCII characters with
"Q-encoding" (described in RFC 2047), instead of outputting the
headers verbatim. Defaults to the value of the
`format.encodeEmailHeaders` configuration variable.
--interdiff=<previous>::
As a reviewer aid, insert an interdiff into the cover letter,
or as commentary of the lone patch of a 1-patch series, showing

View File

@ -46,6 +46,7 @@ static int default_abbrev_commit;
static int default_show_root = 1;
static int default_follow;
static int default_show_signature;
static int default_encode_email_headers = 1;
static int decoration_style;
static int decoration_given;
static int use_mailmap_config = 1;
@ -151,6 +152,7 @@ static void cmd_log_init_defaults(struct rev_info *rev)
rev->show_root_diff = default_show_root;
rev->subject_prefix = fmt_patch_subject_prefix;
rev->show_signature = default_show_signature;
rev->encode_email_headers = default_encode_email_headers;
rev->diffopt.flags.allow_textconv = 1;
if (default_date_mode)
@ -438,6 +440,10 @@ static int git_log_config(const char *var, const char *value, void *cb)
return git_config_string(&fmt_pretty, var, value);
if (!strcmp(var, "format.subjectprefix"))
return git_config_string(&fmt_patch_subject_prefix, var, value);
if (!strcmp(var, "format.encodeemailheaders")) {
default_encode_email_headers = git_config_bool(var, value);
return 0;
}
if (!strcmp(var, "log.abbrevcommit")) {
default_abbrev_commit = git_config_bool(var, value);
return 0;
@ -1719,6 +1725,7 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)
rev.show_notes = show_notes;
memcpy(&rev.notes_opt, &notes_opt, sizeof(notes_opt));
rev.commit_format = CMIT_FMT_EMAIL;
rev.encode_email_headers = default_encode_email_headers;
rev.expand_tabs_in_log_default = 0;
rev.verbose_header = 1;
rev.diff = 1;

View File

@ -693,6 +693,7 @@ void show_log(struct rev_info *opt)
ctx.abbrev = opt->diffopt.abbrev;
ctx.after_subject = extra_headers;
ctx.preserve_subject = opt->preserve_subject;
ctx.encode_email_headers = opt->encode_email_headers;
ctx.reflog_info = opt->reflog_info;
ctx.fmt = opt->commit_format;
ctx.mailmap = opt->mailmap;

View File

@ -474,7 +474,8 @@ void pp_user_info(struct pretty_print_context *pp,
}
strbuf_addstr(sb, "From: ");
if (needs_rfc2047_encoding(namebuf, namelen)) {
if (pp->encode_email_headers &&
needs_rfc2047_encoding(namebuf, namelen)) {
add_rfc2047(sb, namebuf, namelen,
encoding, RFC2047_ADDRESS);
max_length = 76; /* per rfc2047 */
@ -1767,7 +1768,8 @@ void pp_title_line(struct pretty_print_context *pp,
if (pp->print_email_subject) {
if (pp->rev)
fmt_output_email_subject(sb, pp->rev);
if (needs_rfc2047_encoding(title.buf, title.len))
if (pp->encode_email_headers &&
needs_rfc2047_encoding(title.buf, title.len))
add_rfc2047(sb, title.buf, title.len,
encoding, RFC2047_SUBJECT);
else

View File

@ -43,6 +43,7 @@ struct pretty_print_context {
struct string_list *mailmap;
int color;
struct ident_split *from_ident;
unsigned encode_email_headers:1;
/*
* Fields below here are manipulated internally by pp_* functions and

View File

@ -2241,6 +2241,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
revs->topo_order = 1;
revs->rewrite_parents = 1;
revs->graph = graph_init(revs);
} else if (!strcmp(arg, "--encode-email-headers")) {
revs->encode_email_headers = 1;
} else if (!strcmp(arg, "--no-encode-email-headers")) {
revs->encode_email_headers = 0;
} else if (!strcmp(arg, "--root")) {
revs->show_root_diff = 1;
} else if (!strcmp(arg, "--no-commit-id")) {

View File

@ -203,7 +203,8 @@ struct rev_info {
use_terminator:1,
missing_newline:1,
date_mode_explicit:1,
preserve_subject:1;
preserve_subject:1,
encode_email_headers:1;
unsigned int disable_stdin:1;
/* --show-linear-break */
unsigned int track_linear:1,

View File

@ -1160,6 +1160,59 @@ test_expect_success 'format-patch wraps extremely long from-header (rfc2047)' '
check_author "Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar"
'
cat >expect <<'EOF'
From: Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar
Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo
Bar Foo Bar Foo Bar Foo Bar <author@example.com>
EOF
test_expect_success 'format-patch wraps extremely long from-header (non-ASCII without Q-encoding)' '
echo content >>file &&
git add file &&
GIT_AUTHOR_NAME="Foö Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar Foo Bar" \
git commit -m author-check &&
git format-patch --no-encode-email-headers --stdout -1 >patch &&
sed -n "/^From: /p; /^ /p; /^$/q" patch >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
Subject: [PATCH] Foö
EOF
test_expect_success 'subject lines are unencoded with --no-encode-email-headers' '
echo content >>file &&
git add file &&
git commit -m "Foö" &&
git format-patch --no-encode-email-headers -1 --stdout >patch &&
grep ^Subject: patch >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
Subject: [PATCH] Foö
EOF
test_expect_success 'subject lines are unencoded with format.encodeEmailHeaders=false' '
echo content >>file &&
git add file &&
git commit -m "Foö" &&
git config format.encodeEmailHeaders false &&
git format-patch -1 --stdout >patch &&
grep ^Subject: patch >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
Subject: [PATCH] =?UTF-8?q?Fo=C3=B6?=
EOF
test_expect_success '--encode-email-headers overrides format.encodeEmailHeaders' '
echo content >>file &&
git add file &&
git commit -m "Foö" &&
git config format.encodeEmailHeaders false &&
git format-patch --encode-email-headers -1 --stdout >patch &&
grep ^Subject: patch >actual &&
test_cmp expect actual
'
cat >expect <<'EOF'
Subject: header with . in it
EOF