Skip to content

Commit 6bf4f1b

Browse files
committed
format-patch: generate MIME header as needed even when there is format.header
Earlier, the callchain from pretty_print_commit() down to pp_title_line() had an unwarranted assumption that the presense of "after_subject" parameter, means the caller has already output MIME headers for attachments. The parameter's primary purpose is to give extra header lines the caller wants to place after pp_title_line() generates the "Subject: " line. This assumption does not hold when the user used the format.header configuration variable to pass extra headers, and caused a message with non-ASCII character to lack proper MIME headers (e.g. 8-bit CTE header). The earlier logic also failed to suppress duplicated MIME headers when "format-patch -s --attach" is asked for and the signer's name demanded 8-bit clean transport. This patch fixes the logic by introducing a separate need_8bit_cte parameter passed down the callchain. This can have one of these values: -1 : we've already done MIME crap and we do not want to add extra header to say this is 8bit in pp_title_line(); 0 : we haven't done MIME and we have not seen anything that is 8bit yet; 1 : we haven't done MIME and we have seen something that is 8bit; pp_title_line() must add MIME header. It adds two tests by Jeff King who independently diagnosed this issue. Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent a0b54e7 commit 6bf4f1b

File tree

5 files changed

+57
-16
lines changed

5 files changed

+57
-16
lines changed

commit.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -70,7 +70,7 @@ extern void pretty_print_commit(enum cmit_fmt fmt, const struct commit*,
7070
struct strbuf *,
7171
int abbrev, const char *subject,
7272
const char *after_subject, enum date_mode,
73-
int non_ascii_present);
73+
int need_8bit_cte);
7474

7575
/** Removes the first commit from a list sorted by date, and adds all
7676
* of its parents.

log-tree.c

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,6 +146,7 @@ void show_log(struct rev_info *opt, const char *sep)
146146
int abbrev_commit = opt->abbrev_commit ? opt->abbrev : 40;
147147
const char *extra;
148148
const char *subject = NULL, *extra_headers = opt->extra_headers;
149+
int need_8bit_cte = 0;
149150

150151
opt->loginfo = NULL;
151152
if (!opt->verbose_header) {
@@ -214,6 +215,8 @@ void show_log(struct rev_info *opt, const char *sep)
214215
if (opt->mime_boundary) {
215216
static char subject_buffer[1024];
216217
static char buffer[1024];
218+
219+
need_8bit_cte = -1; /* never */
217220
snprintf(subject_buffer, sizeof(subject_buffer) - 1,
218221
"%s"
219222
"MIME-Version: 1.0\n"
@@ -282,9 +285,11 @@ void show_log(struct rev_info *opt, const char *sep)
282285
* And then the pretty-printed message itself
283286
*/
284287
strbuf_init(&msgbuf, 0);
288+
if (need_8bit_cte >= 0)
289+
need_8bit_cte = has_non_ascii(opt->add_signoff);
285290
pretty_print_commit(opt->commit_format, commit, &msgbuf,
286291
abbrev, subject, extra_headers, opt->date_mode,
287-
has_non_ascii(opt->add_signoff));
292+
need_8bit_cte);
288293

289294
if (opt->add_signoff)
290295
append_signoff(&msgbuf, opt->add_signoff);

pretty.c

Lines changed: 11 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -659,7 +659,7 @@ static void pp_title_line(enum cmit_fmt fmt,
659659
const char *subject,
660660
const char *after_subject,
661661
const char *encoding,
662-
int plain_non_ascii)
662+
int need_8bit_cte)
663663
{
664664
struct strbuf title;
665665

@@ -692,7 +692,7 @@ static void pp_title_line(enum cmit_fmt fmt,
692692
}
693693
strbuf_addch(sb, '\n');
694694

695-
if (plain_non_ascii) {
695+
if (need_8bit_cte > 0) {
696696
const char *header_fmt =
697697
"MIME-Version: 1.0\n"
698698
"Content-Type: text/plain; charset=%s\n"
@@ -741,9 +741,9 @@ static void pp_remainder(enum cmit_fmt fmt,
741741
}
742742

743743
void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
744-
struct strbuf *sb, int abbrev,
745-
const char *subject, const char *after_subject,
746-
enum date_mode dmode, int plain_non_ascii)
744+
struct strbuf *sb, int abbrev,
745+
const char *subject, const char *after_subject,
746+
enum date_mode dmode, int need_8bit_cte)
747747
{
748748
unsigned long beginning_of_body;
749749
int indent = 4;
@@ -769,13 +769,11 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
769769
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
770770
indent = 0;
771771

772-
/* After-subject is used to pass in Content-Type: multipart
773-
* MIME header; in that case we do not have to do the
774-
* plaintext content type even if the commit message has
775-
* non 7-bit ASCII character. Otherwise, check if we need
776-
* to say this is not a 7-bit ASCII.
772+
/*
773+
* We need to check and emit Content-type: to mark it
774+
* as 8-bit if we haven't done so.
777775
*/
778-
if (fmt == CMIT_FMT_EMAIL && !after_subject) {
776+
if (fmt == CMIT_FMT_EMAIL && need_8bit_cte == 0) {
779777
int i, ch, in_body;
780778

781779
for (in_body = i = 0; (ch = msg[i]); i++) {
@@ -788,7 +786,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
788786
in_body = 1;
789787
}
790788
else if (non_ascii(ch)) {
791-
plain_non_ascii = 1;
789+
need_8bit_cte = 1;
792790
break;
793791
}
794792
}
@@ -813,7 +811,7 @@ void pretty_print_commit(enum cmit_fmt fmt, const struct commit *commit,
813811
/* These formats treat the title line specially. */
814812
if (fmt == CMIT_FMT_ONELINE || fmt == CMIT_FMT_EMAIL)
815813
pp_title_line(fmt, &msg, sb, subject,
816-
after_subject, encoding, plain_non_ascii);
814+
after_subject, encoding, need_8bit_cte);
817815

818816
beginning_of_body = sb->len;
819817
if (fmt != CMIT_FMT_ONELINE)

t/t4021-format-patch-signer-mime.sh

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,11 +32,19 @@ test_expect_success 'format with signoff without funny signer name' '
3232

3333
test_expect_success 'format with non ASCII signer name' '
3434
35-
GIT_COMMITTER_NAME="$B$O$^$N(B $B$U$K$*$&(B" \
35+
GIT_COMMITTER_NAME="はまの ふにおう" \
3636
git format-patch -s --stdout -1 >output &&
3737
grep Content-Type output
3838
3939
'
4040

41+
test_expect_success 'attach and signoff do not duplicate mime headers' '
42+
43+
GIT_COMMITTER_NAME="はまの ふにおう" \
44+
git format-patch -s --stdout -1 --attach >output &&
45+
test `grep -ci ^MIME-Version: output` = 1
46+
47+
'
48+
4149
test_done
4250

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
#!/bin/sh
2+
3+
test_description='format-patch mime headers and extra headers do not conflict'
4+
. ./test-lib.sh
5+
6+
test_expect_success 'create commit with utf-8 body' '
7+
echo content >file &&
8+
git add file &&
9+
git commit -m one &&
10+
echo more >>file &&
11+
git commit -a -m "two
12+
13+
utf-8 body: ñ"
14+
'
15+
16+
test_expect_success 'patch has mime headers' '
17+
rm -f 0001-two.patch &&
18+
git format-patch HEAD^ &&
19+
grep -i "content-type: text/plain; charset=utf-8" 0001-two.patch
20+
'
21+
22+
test_expect_success 'patch has mime and extra headers' '
23+
rm -f 0001-two.patch &&
24+
git config format.headers "x-foo: bar" &&
25+
git format-patch HEAD^ &&
26+
grep -i "x-foo: bar" 0001-two.patch &&
27+
grep -i "content-type: text/plain; charset=utf-8" 0001-two.patch
28+
'
29+
30+
test_done

0 commit comments

Comments
 (0)