From: Junio C Hamano Date: Thu, 15 Nov 2012 18:25:05 +0000 (-0800) Subject: Merge branch 'jc/prettier-pretty-note' X-Git-Tag: v1.8.1-rc0~58 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/4ad4fce63a67cde3a93e6678724ed79b06109ad6?ds=inline;hp=-c Merge branch 'jc/prettier-pretty-note' Emit the notes attached to the commit in "format-patch --notes" output after three-dashes. * jc/prettier-pretty-note: format-patch: add a blank line between notes and diffstat Doc User-Manual: Patch cover letter, three dashes, and --notes Doc format-patch: clarify --notes use case Doc notes: Include the format-patch --notes option Doc SubmittingPatches: Mention --notes option after "cover letter" Documentation: decribe format-patch --notes format-patch --notes: show notes after three-dashes format-patch: append --signature after notes pretty_print_commit(): do not append notes message pretty: prepare notes message at a centralized place format_note(): simplify API pretty: remove reencode_commit_message() --- 4ad4fce63a67cde3a93e6678724ed79b06109ad6 diff --combined commit.h index c4cd046160,7b43e45017..b6ad8f3f30 --- a/commit.h +++ b/commit.h @@@ -86,7 -86,7 +86,7 @@@ struct pretty_print_context enum date_mode date_mode; unsigned date_mode_explicit:1; int need_8bit_cte; - int show_notes; + char *notes_message; struct reflog_walk_info *reflog_info; const char *output_encoding; }; @@@ -99,8 -99,6 +99,6 @@@ extern int has_non_ascii(const char *te struct rev_info; /* in revision.h, it circularly uses enum cmit_fmt */ extern char *logmsg_reencode(const struct commit *commit, const char *output_encoding); - extern char *reencode_commit_message(const struct commit *commit, - const char **encoding_p); extern void get_commit_format(const char *arg, struct rev_info *); extern const char *format_subject(struct strbuf *sb, const char *msg, const char *line_separator); @@@ -222,8 -220,4 +220,8 @@@ struct commit *get_merge_parent(const c extern int parse_signed_commit(const unsigned char *sha1, struct strbuf *message, struct strbuf *signature); +extern void print_commit_list(struct commit_list *list, + const char *format_cur, + const char *format_last); + #endif /* COMMIT_H */ diff --combined notes.c index 19b0eaada2,97097db9dc..f63fd572d6 --- a/notes.c +++ b/notes.c @@@ -848,16 -848,15 +848,16 @@@ int combine_notes_ignore(unsigned char return 0; } -static int string_list_add_note_lines(struct string_list *sort_uniq_list, +/* + * Add the lines from the named object to list, with trailing + * newlines removed. + */ +static int string_list_add_note_lines(struct string_list *list, const unsigned char *sha1) { char *data; unsigned long len; enum object_type t; - struct strbuf buf = STRBUF_INIT; - struct strbuf **lines = NULL; - int i, list_index; if (is_null_sha1(sha1)) return 0; @@@ -869,14 -868,24 +869,14 @@@ return t != OBJ_BLOB || !data; } - strbuf_attach(&buf, data, len, len + 1); - lines = strbuf_split(&buf, '\n'); - - for (i = 0; lines[i]; i++) { - if (lines[i]->buf[lines[i]->len - 1] == '\n') - strbuf_setlen(lines[i], lines[i]->len - 1); - if (!lines[i]->len) - continue; /* skip empty lines */ - list_index = string_list_find_insert_index(sort_uniq_list, - lines[i]->buf, 0); - if (list_index < 0) - continue; /* skip duplicate lines */ - string_list_insert_at_index(sort_uniq_list, list_index, - lines[i]->buf); - } - - strbuf_list_free(lines); - strbuf_release(&buf); + /* + * If the last line of the file is EOL-terminated, this will + * add an empty string to the list. But it will be removed + * later, along with any empty strings that came from empty + * lines within the file. + */ + string_list_split(list, data, '\n', -1); + free(data); return 0; } @@@ -892,7 -901,7 +892,7 @@@ static int string_list_join_lines_helpe int combine_notes_cat_sort_uniq(unsigned char *cur_sha1, const unsigned char *new_sha1) { - struct string_list sort_uniq_list = { NULL, 0, 0, 1 }; + struct string_list sort_uniq_list = STRING_LIST_INIT_DUP; struct strbuf buf = STRBUF_INIT; int ret = 1; @@@ -901,9 -910,6 +901,9 @@@ goto out; if (string_list_add_note_lines(&sort_uniq_list, new_sha1)) goto out; + string_list_remove_empty_items(&sort_uniq_list, 0); + sort_string_list(&sort_uniq_list); + string_list_remove_duplicates(&sort_uniq_list, 0); /* create a new blob object from sort_uniq_list */ if (for_each_string_list(&sort_uniq_list, @@@ -943,18 -949,23 +943,18 @@@ void string_list_add_refs_by_glob(struc void string_list_add_refs_from_colon_sep(struct string_list *list, const char *globs) { - struct strbuf globbuf = STRBUF_INIT; - struct strbuf **split; + struct string_list split = STRING_LIST_INIT_NODUP; + char *globs_copy = xstrdup(globs); int i; - strbuf_addstr(&globbuf, globs); - split = strbuf_split(&globbuf, ':'); + string_list_split_in_place(&split, globs_copy, ':', -1); + string_list_remove_empty_items(&split, 0); - for (i = 0; split[i]; i++) { - if (!split[i]->len) - continue; - if (split[i]->buf[split[i]->len-1] == ':') - strbuf_setlen(split[i], split[i]->len-1); - string_list_add_refs_by_glob(list, split[i]->buf); - } + for (i = 0; i < split.nr; i++) + string_list_add_refs_by_glob(list, split.items[i].string); - strbuf_list_free(split); - strbuf_release(&globbuf); + string_list_clear(&split, 0); + free(globs_copy); } static int notes_display_config(const char *k, const char *v, void *cb) @@@ -1193,10 -1204,11 +1193,11 @@@ void free_notes(struct notes_tree *t * If the given notes_tree is NULL, the internal/default notes_tree will be * used instead. * - * 'flags' is a bitwise combination of the flags for format_display_notes. + * (raw != 0) gives the %N userformat; otherwise, the note message is given + * for human consumption. */ static void format_note(struct notes_tree *t, const unsigned char *object_sha1, - struct strbuf *sb, const char *output_encoding, int flags) + struct strbuf *sb, const char *output_encoding, int raw) { static const char utf8[] = "utf-8"; const unsigned char *sha1; @@@ -1220,7 -1232,7 +1221,7 @@@ } if (output_encoding && *output_encoding && - strcmp(utf8, output_encoding)) { + !is_encoding_utf8(output_encoding)) { char *reencoded = reencode_string(msg, output_encoding, utf8); if (reencoded) { free(msg); @@@ -1233,7 -1245,7 +1234,7 @@@ if (msglen && msg[msglen - 1] == '\n') msglen--; - if (flags & NOTES_SHOW_HEADER) { + if (!raw) { const char *ref = t->ref; if (!ref || !strcmp(ref, GIT_NOTES_DEFAULT_REF)) { strbuf_addstr(sb, "\nNotes:\n"); @@@ -1249,7 -1261,7 +1250,7 @@@ for (msg_p = msg; msg_p < msg + msglen; msg_p += linelen + 1) { linelen = strchrnul(msg_p, '\n') - msg_p; - if (flags & NOTES_INDENT) + if (!raw) strbuf_addstr(sb, " "); strbuf_add(sb, msg_p, linelen); strbuf_addch(sb, '\n'); @@@ -1259,13 -1271,13 +1260,13 @@@ } void format_display_notes(const unsigned char *object_sha1, - struct strbuf *sb, const char *output_encoding, int flags) + struct strbuf *sb, const char *output_encoding, int raw) { int i; assert(display_notes_trees); for (i = 0; display_notes_trees[i]; i++) format_note(display_notes_trees[i], object_sha1, sb, - output_encoding, flags); + output_encoding, raw); } int copy_note(struct notes_tree *t, diff --combined pretty.c index dba682828c,1925e9c3e4..5bdc2e70bc --- a/pretty.c +++ b/pretty.c @@@ -231,7 -231,7 +231,7 @@@ static int is_rfc822_special(char ch } } -static int has_rfc822_specials(const char *s, int len) +static int needs_rfc822_quoting(const char *s, int len) { int i; for (i = 0; i < len; i++) @@@ -240,17 -240,6 +240,17 @@@ return 0; } +static int last_line_length(struct strbuf *sb) +{ + int i; + + /* How many bytes are already used on the last line? */ + for (i = sb->len - 1; i >= 0; i--) + if (sb->buf[i] == '\n') + break; + return sb->len - (i + 1); +} + static void add_rfc822_quoted(struct strbuf *out, const char *s, int len) { int i; @@@ -272,110 -261,57 +272,110 @@@ strbuf_addch(out, '"'); } -static int is_rfc2047_special(char ch) +enum rfc2047_type { + RFC2047_SUBJECT, + RFC2047_ADDRESS, +}; + +static int is_rfc2047_special(char ch, enum rfc2047_type type) { - return (non_ascii(ch) || (ch == '=') || (ch == '?') || (ch == '_')); + /* + * rfc2047, section 4.2: + * + * 8-bit values which correspond to printable ASCII characters other + * than "=", "?", and "_" (underscore), MAY be represented as those + * characters. (But see section 5 for restrictions.) In + * particular, SPACE and TAB MUST NOT be represented as themselves + * within encoded words. + */ + + /* + * rule out non-ASCII characters and non-printable characters (the + * non-ASCII check should be redundant as isprint() is not localized + * and only knows about ASCII, but be defensive about that) + */ + if (non_ascii(ch) || !isprint(ch)) + return 1; + + /* + * rule out special printable characters (' ' should be the only + * whitespace character considered printable, but be defensive and use + * isspace()) + */ + if (isspace(ch) || ch == '=' || ch == '?' || ch == '_') + return 1; + + /* + * rfc2047, section 5.3: + * + * As a replacement for a 'word' entity within a 'phrase', for example, + * one that precedes an address in a From, To, or Cc header. The ABNF + * definition for 'phrase' from RFC 822 thus becomes: + * + * phrase = 1*( encoded-word / word ) + * + * In this case the set of characters that may be used in a "Q"-encoded + * 'encoded-word' is restricted to: . An 'encoded-word' that appears within a + * 'phrase' MUST be separated from any adjacent 'word', 'text' or + * 'special' by 'linear-white-space'. + */ + + if (type != RFC2047_ADDRESS) + return 0; + + /* '=' and '_' are special cases and have been checked above */ + return !(isalnum(ch) || ch == '!' || ch == '*' || ch == '+' || ch == '-' || ch == '/'); } -static void add_rfc2047(struct strbuf *sb, const char *line, int len, - const char *encoding) +static int needs_rfc2047_encoding(const char *line, int len, + enum rfc2047_type type) { - static const int max_length = 78; /* per rfc2822 */ int i; - int line_len; - - /* How many bytes are already used on the current line? */ - for (i = sb->len - 1; i >= 0; i--) - if (sb->buf[i] == '\n') - break; - line_len = sb->len - (i+1); for (i = 0; i < len; i++) { int ch = line[i]; if (non_ascii(ch) || ch == '\n') - goto needquote; + return 1; if ((i + 1 < len) && (ch == '=' && line[i+1] == '?')) - goto needquote; + return 1; } - strbuf_add_wrapped_bytes(sb, line, len, 0, 1, max_length - line_len); - return; -needquote: + return 0; +} + +static void add_rfc2047(struct strbuf *sb, const char *line, int len, + const char *encoding, enum rfc2047_type type) +{ + static const int max_encoded_length = 76; /* per rfc2047 */ + int i; + int line_len = last_line_length(sb); + strbuf_grow(sb, len * 3 + strlen(encoding) + 100); strbuf_addf(sb, "=?%s?q?", encoding); line_len += strlen(encoding) + 5; /* 5 for =??q? */ for (i = 0; i < len; i++) { unsigned ch = line[i] & 0xFF; + int is_special = is_rfc2047_special(ch, type); + + /* + * According to RFC 2047, we could encode the special character + * ' ' (space) with '_' (underscore) for readability. But many + * programs do not understand this and just leave the + * underscore in place. Thus, we do nothing special here, which + * causes ' ' to be encoded as '=20', avoiding this problem. + */ - if (line_len >= max_length - 2) { + if (line_len + 2 + (is_special ? 3 : 1) > max_encoded_length) { strbuf_addf(sb, "?=\n =?%s?q?", encoding); line_len = strlen(encoding) + 5 + 1; /* =??q? plus SP */ } - /* - * We encode ' ' using '=20' even though rfc2047 - * allows using '_' for readability. Unfortunately, - * many programs do not understand this and just - * leave the underscore in place. - */ - if (is_rfc2047_special(ch) || ch == ' ' || ch == '\n') { + if (is_special) { strbuf_addf(sb, "=%02X", ch); line_len += 3; - } - else { + } else { strbuf_addch(sb, ch); line_len++; } @@@ -387,7 -323,6 +387,7 @@@ void pp_user_info(const struct pretty_p const char *what, struct strbuf *sb, const char *line, const char *encoding) { + int max_length = 78; /* per rfc2822 */ char *date; int namelen; unsigned long time; @@@ -405,27 -340,25 +405,27 @@@ if (pp->fmt == CMIT_FMT_EMAIL) { char *name_tail = strchr(line, '<'); int display_name_length; - int final_line; if (!name_tail) return; while (line < name_tail && isspace(name_tail[-1])) name_tail--; display_name_length = name_tail - line; strbuf_addstr(sb, "From: "); - if (!has_rfc822_specials(line, display_name_length)) { - add_rfc2047(sb, line, display_name_length, encoding); - } else { + if (needs_rfc2047_encoding(line, display_name_length, RFC2047_ADDRESS)) { + add_rfc2047(sb, line, display_name_length, + encoding, RFC2047_ADDRESS); + max_length = 76; /* per rfc2047 */ + } else if (needs_rfc822_quoting(line, display_name_length)) { struct strbuf quoted = STRBUF_INIT; add_rfc822_quoted("ed, line, display_name_length); - add_rfc2047(sb, quoted.buf, quoted.len, encoding); + strbuf_add_wrapped_bytes(sb, quoted.buf, quoted.len, + -6, 1, max_length); strbuf_release("ed); + } else { + strbuf_add_wrapped_bytes(sb, line, display_name_length, + -6, 1, max_length); } - for (final_line = 0; final_line < sb->len; final_line++) - if (sb->buf[sb->len - final_line - 1] == '\n') - break; - if (namelen - display_name_length + final_line > 78) { + if (namelen - display_name_length + last_line_length(sb) > max_length) { strbuf_addch(sb, '\n'); if (!isspace(name_tail[0])) strbuf_addch(sb, ' '); @@@ -571,7 -504,7 +571,7 @@@ char *logmsg_reencode(const struct comm return NULL; encoding = get_header(commit, "encoding"); use_encoding = encoding ? encoding : utf8; - if (!strcmp(use_encoding, output_encoding)) + if (same_encoding(use_encoding, output_encoding)) if (encoding) /* we'll strip encoding header later */ out = xstrdup(commit->buffer); else @@@ -1100,9 -1033,8 +1100,8 @@@ static size_t format_commit_one(struct } return 0; /* unknown %g placeholder */ case 'N': - if (c->pretty_ctx->show_notes) { - format_display_notes(commit->object.sha1, sb, - get_log_output_encoding(), 0); + if (c->pretty_ctx->notes_message) { + strbuf_addstr(sb, c->pretty_ctx->notes_message); return 1; } return 0; @@@ -1345,7 -1277,6 +1344,7 @@@ void pp_title_line(const struct pretty_ const char *encoding, int need_8bit_cte) { + static const int max_length = 78; /* per rfc2047 */ struct strbuf title; strbuf_init(&title, 80); @@@ -1355,12 -1286,7 +1354,12 @@@ strbuf_grow(sb, title.len + 1024); if (pp->subject) { strbuf_addstr(sb, pp->subject); - add_rfc2047(sb, title.buf, title.len, encoding); + if (needs_rfc2047_encoding(title.buf, title.len, RFC2047_SUBJECT)) + add_rfc2047(sb, title.buf, title.len, + encoding, RFC2047_SUBJECT); + else + strbuf_add_wrapped_bytes(sb, title.buf, title.len, + -last_line_length(sb), 1, max_length); } else { strbuf_addbuf(sb, &title); } @@@ -1414,16 -1340,6 +1413,6 @@@ void pp_remainder(const struct pretty_p } } - char *reencode_commit_message(const struct commit *commit, const char **encoding_p) - { - const char *encoding; - - encoding = get_log_output_encoding(); - if (encoding_p) - *encoding_p = encoding; - return logmsg_reencode(commit, encoding); - } - void pretty_print_commit(const struct pretty_print_context *pp, const struct commit *commit, struct strbuf *sb) @@@ -1440,7 -1356,8 +1429,8 @@@ return; } - reencoded = reencode_commit_message(commit, &encoding); + encoding = get_log_output_encoding(); + reencoded = logmsg_reencode(commit, encoding); if (reencoded) { msg = reencoded; } @@@ -1500,10 -1417,6 +1490,6 @@@ if (pp->fmt == CMIT_FMT_EMAIL && sb->len <= beginning_of_body) strbuf_addch(sb, '\n'); - if (pp->show_notes) - format_display_notes(commit->object.sha1, sb, encoding, - NOTES_SHOW_HEADER | NOTES_INDENT); - free(reencoded); } diff --combined revision.c index d7d621cdbf,ddfba11ca8..95d21e6472 --- a/revision.c +++ b/revision.c @@@ -1048,9 -1048,9 +1048,9 @@@ void init_revisions(struct rev_info *re revs->commit_format = CMIT_FMT_DEFAULT; + init_grep_defaults(); + grep_init(&revs->grep_filter, prefix); revs->grep_filter.status_only = 1; - revs->grep_filter.pattern_tail = &(revs->grep_filter.pattern_list); - revs->grep_filter.header_tail = &(revs->grep_filter.header_list); revs->grep_filter.regflags = REG_NEWLINE; diff_setup(&revs->diffopt); @@@ -1603,17 -1603,13 +1603,17 @@@ static int handle_revision_opt(struct r return argcount; } else if (!strcmp(arg, "--grep-debug")) { revs->grep_filter.debug = 1; + } else if (!strcmp(arg, "--basic-regexp")) { + grep_set_pattern_type_option(GREP_PATTERN_TYPE_BRE, &revs->grep_filter); } else if (!strcmp(arg, "--extended-regexp") || !strcmp(arg, "-E")) { - revs->grep_filter.regflags |= REG_EXTENDED; + grep_set_pattern_type_option(GREP_PATTERN_TYPE_ERE, &revs->grep_filter); } else if (!strcmp(arg, "--regexp-ignore-case") || !strcmp(arg, "-i")) { revs->grep_filter.regflags |= REG_ICASE; DIFF_OPT_SET(&revs->diffopt, PICKAXE_IGNORE_CASE); } else if (!strcmp(arg, "--fixed-strings") || !strcmp(arg, "-F")) { - revs->grep_filter.fixed = 1; + grep_set_pattern_type_option(GREP_PATTERN_TYPE_FIXED, &revs->grep_filter); + } else if (!strcmp(arg, "--perl-regexp")) { + grep_set_pattern_type_option(GREP_PATTERN_TYPE_PCRE, &revs->grep_filter); } else if (!strcmp(arg, "--all-match")) { revs->grep_filter.all_match = 1; } else if ((argcount = parse_long_opt("encoding", argv, &optarg))) { @@@ -1897,8 -1893,6 +1897,8 @@@ int setup_revisions(int argc, const cha revs->diffopt.abbrev = revs->abbrev; diff_setup_done(&revs->diffopt); + grep_commit_pattern_type(GREP_PATTERN_TYPE_UNSPECIFIED, + &revs->grep_filter); compile_grep_patterns(&revs->grep_filter); if (revs->reverse && revs->reflog_info) @@@ -2242,7 -2236,7 +2242,7 @@@ static int commit_match(struct commit * if (!buf.len) strbuf_addstr(&buf, commit->buffer); format_display_notes(commit->object.sha1, &buf, - get_log_output_encoding(), 0); + get_log_output_encoding(), 1); } /* Find either in the commit object, or in the temporary */ diff --combined t/t4014-format-patch.sh index ad9f69e607,9750ba6996..16a4ca1d60 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@@ -110,107 -110,73 +110,107 @@@ test_expect_success 'replay did not scr test_expect_success 'extra headers' ' - git config format.headers "To: R. E. Cipient + git config format.headers "To: R E Cipient " && - git config --add format.headers "Cc: S. E. Cipient + git config --add format.headers "Cc: S E Cipient " && git format-patch --stdout master..side > patch2 && sed -e "/^\$/q" patch2 > hdrs2 && - grep "^To: R. E. Cipient \$" hdrs2 && - grep "^Cc: S. E. Cipient \$" hdrs2 + grep "^To: R E Cipient \$" hdrs2 && + grep "^Cc: S E Cipient \$" hdrs2 ' test_expect_success 'extra headers without newlines' ' - git config --replace-all format.headers "To: R. E. Cipient " && - git config --add format.headers "Cc: S. E. Cipient " && + git config --replace-all format.headers "To: R E Cipient " && + git config --add format.headers "Cc: S E Cipient " && git format-patch --stdout master..side >patch3 && sed -e "/^\$/q" patch3 > hdrs3 && - grep "^To: R. E. Cipient \$" hdrs3 && - grep "^Cc: S. E. Cipient \$" hdrs3 + grep "^To: R E Cipient \$" hdrs3 && + grep "^Cc: S E Cipient \$" hdrs3 ' test_expect_success 'extra headers with multiple To:s' ' - git config --replace-all format.headers "To: R. E. Cipient " && - git config --add format.headers "To: S. E. Cipient " && + git config --replace-all format.headers "To: R E Cipient " && + git config --add format.headers "To: S E Cipient " && git format-patch --stdout master..side > patch4 && sed -e "/^\$/q" patch4 > hdrs4 && - grep "^To: R. E. Cipient ,\$" hdrs4 && - grep "^ *S. E. Cipient \$" hdrs4 + grep "^To: R E Cipient ,\$" hdrs4 && + grep "^ *S E Cipient \$" hdrs4 ' -test_expect_success 'additional command line cc' ' +test_expect_success 'additional command line cc (ascii)' ' - git config --replace-all format.headers "Cc: R. E. Cipient " && + git config --replace-all format.headers "Cc: R E Cipient " && + git format-patch --cc="S E Cipient " --stdout master..side | sed -e "/^\$/q" >patch5 && + grep "^Cc: R E Cipient ,\$" patch5 && + grep "^ *S E Cipient \$" patch5 +' + +test_expect_failure 'additional command line cc (rfc822)' ' + + git config --replace-all format.headers "Cc: R E Cipient " && git format-patch --cc="S. E. Cipient " --stdout master..side | sed -e "/^\$/q" >patch5 && - grep "^Cc: R. E. Cipient ,\$" patch5 && - grep "^ *S. E. Cipient \$" patch5 + grep "^Cc: R E Cipient ,\$" patch5 && + grep "^ *"S. E. Cipient" \$" patch5 ' test_expect_success 'command line headers' ' git config --unset-all format.headers && - git format-patch --add-header="Cc: R. E. Cipient " --stdout master..side | sed -e "/^\$/q" >patch6 && - grep "^Cc: R. E. Cipient \$" patch6 + git format-patch --add-header="Cc: R E Cipient " --stdout master..side | sed -e "/^\$/q" >patch6 && + grep "^Cc: R E Cipient \$" patch6 ' test_expect_success 'configuration headers and command line headers' ' - git config --replace-all format.headers "Cc: R. E. Cipient " && - git format-patch --add-header="Cc: S. E. Cipient " --stdout master..side | sed -e "/^\$/q" >patch7 && - grep "^Cc: R. E. Cipient ,\$" patch7 && - grep "^ *S. E. Cipient \$" patch7 + git config --replace-all format.headers "Cc: R E Cipient " && + git format-patch --add-header="Cc: S E Cipient " --stdout master..side | sed -e "/^\$/q" >patch7 && + grep "^Cc: R E Cipient ,\$" patch7 && + grep "^ *S E Cipient \$" patch7 ' -test_expect_success 'command line To: header' ' +test_expect_success 'command line To: header (ascii)' ' git config --unset-all format.headers && + git format-patch --to="R E Cipient " --stdout master..side | sed -e "/^\$/q" >patch8 && + grep "^To: R E Cipient \$" patch8 +' + +test_expect_failure 'command line To: header (rfc822)' ' + git format-patch --to="R. E. Cipient " --stdout master..side | sed -e "/^\$/q" >patch8 && - grep "^To: R. E. Cipient \$" patch8 + grep "^To: "R. E. Cipient" \$" patch8 ' -test_expect_success 'configuration To: header' ' +test_expect_failure 'command line To: header (rfc2047)' ' + + git format-patch --to="R Ä Cipient " --stdout master..side | sed -e "/^\$/q" >patch8 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= \$" patch8 +' + +test_expect_success 'configuration To: header (ascii)' ' + + git config format.to "R E Cipient " && + git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && + grep "^To: R E Cipient \$" patch9 +' + +test_expect_failure 'configuration To: header (rfc822)' ' git config format.to "R. E. Cipient " && git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && - grep "^To: R. E. Cipient \$" patch9 + grep "^To: "R. E. Cipient" \$" patch9 +' + +test_expect_failure 'configuration To: header (rfc2047)' ' + + git config format.to "R Ä Cipient " && + git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && + grep "^To: =?UTF-8?q?R=20=C3=84=20Cipient?= \$" patch9 ' # check_patch : Verify that looks like a half-sane @@@ -224,11 -190,11 +224,11 @@@ check_patch () test_expect_success '--no-to overrides config.to' ' git config --replace-all format.to \ - "R. E. Cipient " && + "R E Cipient " && git format-patch --no-to --stdout master..side | sed -e "/^\$/q" >patch10 && check_patch patch10 && - ! grep "^To: R. E. Cipient \$" patch10 + ! grep "^To: R E Cipient \$" patch10 ' test_expect_success '--no-to and --to replaces config.to' ' @@@ -246,21 -212,21 +246,21 @@@ test_expect_success '--no-cc overrides config.cc' ' git config --replace-all format.cc \ - "C. E. Cipient " && + "C E Cipient " && git format-patch --no-cc --stdout master..side | sed -e "/^\$/q" >patch12 && check_patch patch12 && - ! grep "^Cc: C. E. Cipient \$" patch12 + ! grep "^Cc: C E Cipient \$" patch12 ' test_expect_success '--no-add-header overrides config.headers' ' git config --replace-all format.headers \ - "Header1: B. E. Cipient " && + "Header1: B E Cipient " && git format-patch --no-add-header --stdout master..side | sed -e "/^\$/q" >patch13 && check_patch patch13 && - ! grep "^Header1: B. E. Cipient \$" patch13 + ! grep "^Header1: B E Cipient \$" patch13 ' test_expect_success 'multiple files' ' @@@ -650,8 -616,19 +650,19 @@@ test_expect_success 'format-patch --in- ' test_expect_success 'format-patch --signoff' ' - git format-patch -1 --signoff --stdout | - grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" + git format-patch -1 --signoff --stdout >out && + grep "^Signed-off-by: $GIT_COMMITTER_NAME <$GIT_COMMITTER_EMAIL>" out + ' + + test_expect_success 'format-patch --notes --signoff' ' + git notes --ref test add -m "test message" HEAD && + git format-patch -1 --signoff --stdout --notes=test >out && + # Three dashes must come after S-o-b + ! sed "/^Signed-off-by: /q" out | grep "test message" && + sed "1,/^Signed-off-by: /d" out | grep "test message" && + # Notes message must come after three dashes + ! sed "/^---$/q" out | grep "test message" && + sed "1,/^---$/d" out | grep "test message" ' echo "fatal: --name-only does not make sense" > expect.name-only @@@ -786,14 -763,16 +797,14 @@@ M64=$M8$M8$M8$M8$M8$M8$M8$M M512=$M64$M64$M64$M64$M64$M64$M64$M64 cat >expect <<'EOF' Subject: [PATCH] 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 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 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 foo bar + 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 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 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 EOF -test_expect_success 'format-patch wraps extremely long headers (ascii)' ' +test_expect_success 'format-patch wraps extremely long subject (ascii)' ' echo content >>file && git add file && git commit -m "$M512" && @@@ -806,31 -785,30 +817,31 @@@ M8="föö bar M64=$M8$M8$M8$M8$M8$M8$M8$M8 M512=$M64$M64$M64$M64$M64$M64$M64$M64 cat >expect <<'EOF' -Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= - =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= +Subject: [PATCH] =?UTF-8?q?f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= + =?UTF-8?q?=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20?= + =?UTF-8?q?bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6?= + =?UTF-8?q?=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3?= + =?UTF-8?q?=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6?= + =?UTF-8?q?=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3?= + =?UTF-8?q?=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar=20f?= + =?UTF-8?q?=C3=B6=C3=B6=20bar=20f=C3=B6=C3=B6=20bar?= EOF -test_expect_success 'format-patch wraps extremely long headers (rfc2047)' ' +test_expect_success 'format-patch wraps extremely long subject (rfc2047)' ' rm -rf patches/ && echo content >>file && git add file && @@@ -840,80 -818,52 +851,80 @@@ test_cmp expect subject ' -M8="foo_bar_" -M64=$M8$M8$M8$M8$M8$M8$M8$M8 -cat >expect < -EOF -test_expect_success 'format-patch wraps non-quotable headers' ' - rm -rf patches/ && - echo content >>file && - git add file && - git commit -mfoo --author "$M64 " && - git format-patch --stdout -1 >patch && - sed -n "/^From: /p; /^ /p; /^$/q" from && - test_cmp expect from -' - check_author() { echo content >>file && git add file && GIT_AUTHOR_NAME=$1 git commit -m author-check && git format-patch --stdout -1 >patch && - grep ^From: patch >actual && + sed -n "/^From: /p; /^ /p; /^$/q" actual && test_cmp expect actual } cat >expect <<'EOF' From: "Foo B. Bar" EOF -test_expect_success 'format-patch quotes dot in headers' ' +test_expect_success 'format-patch quotes dot in from-headers' ' check_author "Foo B. Bar" ' cat >expect <<'EOF' From: "Foo \"The Baz\" Bar" EOF -test_expect_success 'format-patch quotes double-quote in headers' ' +test_expect_success 'format-patch quotes double-quote in from-headers' ' check_author "Foo \"The Baz\" Bar" ' cat >expect <<'EOF' -From: =?UTF-8?q?"F=C3=B6o=20B.=20Bar"?= +From: =?UTF-8?q?F=C3=B6o=20Bar?= +EOF +test_expect_success 'format-patch uses rfc2047-encoded from-headers when necessary' ' + check_author "Föo Bar" +' + +cat >expect <<'EOF' +From: =?UTF-8?q?F=C3=B6o=20B=2E=20Bar?= EOF -test_expect_success 'rfc2047-encoded headers also double-quote 822 specials' ' +test_expect_success 'rfc2047-encoded from-headers leave no rfc822 specials' ' check_author "Föo B. Bar" ' +cat >expect < +EOF +test_expect_success 'format-patch wraps moderately long from-header (ascii)' ' + check_author "foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_foo_bar_" +' + +cat >expect <<'EOF' +From: 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 Foo Bar +EOF +test_expect_success 'format-patch wraps extremely long from-header (ascii)' ' + check_author "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 Foo Bar" +' + +cat >expect <<'EOF' +From: "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 Foo Bar" +EOF +test_expect_success 'format-patch wraps extremely long from-header (rfc822)' ' + check_author "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 Foo Bar" +' + +cat >expect <<'EOF' +From: =?UTF-8?q?Fo=C3=B6=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo?= + =?UTF-8?q?=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20?= + =?UTF-8?q?Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar?= + =?UTF-8?q?=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20Foo=20Bar=20?= + =?UTF-8?q?Foo=20Bar=20Foo=20Bar?= +EOF +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' Subject: header with . in it EOF