diff options
| -rw-r--r-- | Documentation/git-format-patch.txt | 11 | ||||
| -rw-r--r-- | builtin/log.c | 100 | ||||
| -rwxr-xr-x | git-send-email.perl | 14 | ||||
| -rwxr-xr-x | t/t4014-format-patch.sh | 52 | ||||
| -rwxr-xr-x | t/t9001-send-email.sh | 66 | 
5 files changed, 197 insertions, 46 deletions
| diff --git a/Documentation/git-format-patch.txt b/Documentation/git-format-patch.txt index 9674f9de67..835fb7135b 100644 --- a/Documentation/git-format-patch.txt +++ b/Documentation/git-format-patch.txt @@ -18,7 +18,7 @@ SYNOPSIS  		   [--in-reply-to=Message-Id] [--suffix=.<sfx>]  		   [--ignore-if-in-upstream]  		   [--subject-prefix=Subject-Prefix] -		   [--cc=<email>] +		   [--to=<email>] [--cc=<email>]  		   [--cover-letter]  		   [<common diff options>]  		   [ <since> | <revision range> ] @@ -162,6 +162,10 @@ will want to ensure that threading is disabled for `git send-email`.  	allows for useful naming of a patch series, and can be  	combined with the `--numbered` option. +--to=<email>:: +	Add a `To:` header to the email headers. This is in addition +	to any configured headers, and may be used multiple times. +  --cc=<email>::  	Add a `Cc:` header to the email headers. This is in addition  	to any configured headers, and may be used multiple times. @@ -202,8 +206,8 @@ CONFIGURATION  -------------  You can specify extra mail header lines to be added to each message,  defaults for the subject prefix and file suffix, number patches when -outputting more than one patch, add "Cc:" headers, configure attachments, -and sign off patches with configuration variables. +outputting more than one patch, add "To" or "Cc:" headers, configure +attachments, and sign off patches with configuration variables.  ------------  [format] @@ -211,6 +215,7 @@ and sign off patches with configuration variables.  	subjectprefix = CHANGE  	suffix = .txt  	numbered = auto +	to = <email>  	cc = <email>  	attach [ = mime-boundary-string ]  	signoff = true diff --git a/builtin/log.c b/builtin/log.c index e0d5caa61b..9fbc7ab9ce 100644 --- a/builtin/log.c +++ b/builtin/log.c @@ -458,35 +458,28 @@ static int auto_number = 1;  static char *default_attach = NULL; -static char **extra_hdr; -static int extra_hdr_nr; -static int extra_hdr_alloc; - -static char **extra_to; -static int extra_to_nr; -static int extra_to_alloc; - -static char **extra_cc; -static int extra_cc_nr; -static int extra_cc_alloc; +static struct string_list extra_hdr; +static struct string_list extra_to; +static struct string_list extra_cc;  static void add_header(const char *value)  { +	struct string_list_item *item;  	int len = strlen(value);  	while (len && value[len - 1] == '\n')  		len--; +  	if (!strncasecmp(value, "to: ", 4)) { -		ALLOC_GROW(extra_to, extra_to_nr + 1, extra_to_alloc); -		extra_to[extra_to_nr++] = xstrndup(value + 4, len - 4); -		return; -	} -	if (!strncasecmp(value, "cc: ", 4)) { -		ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); -		extra_cc[extra_cc_nr++] = xstrndup(value + 4, len - 4); -		return; +		item = string_list_append(value + 4, &extra_to); +		len -= 4; +	} else if (!strncasecmp(value, "cc: ", 4)) { +		item = string_list_append(value + 4, &extra_cc); +		len -= 4; +	} else { +		item = string_list_append(value, &extra_hdr);  	} -	ALLOC_GROW(extra_hdr, extra_hdr_nr + 1, extra_hdr_alloc); -	extra_hdr[extra_hdr_nr++] = xstrndup(value, len); + +	item->string[len] = '\0';  }  #define THREAD_SHALLOW 1 @@ -504,11 +497,16 @@ static int git_format_config(const char *var, const char *value, void *cb)  	}  	if (!strcmp(var, "format.suffix"))  		return git_config_string(&fmt_patch_suffix, var, value); +	if (!strcmp(var, "format.to")) { +		if (!value) +			return config_error_nonbool(var); +		string_list_append(value, &extra_to); +		return 0; +	}  	if (!strcmp(var, "format.cc")) {  		if (!value)  			return config_error_nonbool(var); -		ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); -		extra_cc[extra_cc_nr++] = xstrdup(value); +		string_list_append(value, &extra_cc);  		return 0;  	}  	if (!strcmp(var, "diff.color") || !strcmp(var, "color.diff")) { @@ -871,14 +869,31 @@ static int inline_callback(const struct option *opt, const char *arg, int unset)  static int header_callback(const struct option *opt, const char *arg, int unset)  { -	add_header(arg); +	if (unset) { +		string_list_clear(&extra_hdr, 0); +		string_list_clear(&extra_to, 0); +		string_list_clear(&extra_cc, 0); +	} else { +	    add_header(arg); +	} +	return 0; +} + +static int to_callback(const struct option *opt, const char *arg, int unset) +{ +	if (unset) +		string_list_clear(&extra_to, 0); +	else +		string_list_append(arg, &extra_to);  	return 0;  }  static int cc_callback(const struct option *opt, const char *arg, int unset)  { -	ALLOC_GROW(extra_cc, extra_cc_nr + 1, extra_cc_alloc); -	extra_cc[extra_cc_nr++] = xstrdup(arg); +	if (unset) +		string_list_clear(&extra_cc, 0); +	else +		string_list_append(arg, &extra_cc);  	return 0;  } @@ -937,10 +952,11 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)  		  PARSE_OPT_NONEG | PARSE_OPT_NOARG },  		OPT_GROUP("Messaging"),  		{ OPTION_CALLBACK, 0, "add-header", NULL, "header", -			    "add email header", PARSE_OPT_NONEG, -			    header_callback }, +			    "add email header", 0, header_callback }, +		{ OPTION_CALLBACK, 0, "to", NULL, "email", "add To: header", +			    0, to_callback },  		{ OPTION_CALLBACK, 0, "cc", NULL, "email", "add Cc: header", -			    PARSE_OPT_NONEG, cc_callback }, +			    0, cc_callback },  		OPT_STRING(0, "in-reply-to", &in_reply_to, "message-id",  			    "make first mail a reply to <message-id>"),  		{ OPTION_CALLBACK, 0, "attach", &rev, "boundary", @@ -956,6 +972,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)  		OPT_END()  	}; +	extra_hdr.strdup_strings = 1; +	extra_to.strdup_strings = 1; +	extra_cc.strdup_strings = 1;  	git_config(git_format_config, NULL);  	init_revisions(&rev, prefix);  	rev.commit_format = CMIT_FMT_EMAIL; @@ -992,29 +1011,29 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)  		add_signoff = xmemdupz(committer, endpos - committer + 1);  	} -	for (i = 0; i < extra_hdr_nr; i++) { -		strbuf_addstr(&buf, extra_hdr[i]); +	for (i = 0; i < extra_hdr.nr; i++) { +		strbuf_addstr(&buf, extra_hdr.items[i].string);  		strbuf_addch(&buf, '\n');  	} -	if (extra_to_nr) +	if (extra_to.nr)  		strbuf_addstr(&buf, "To: "); -	for (i = 0; i < extra_to_nr; i++) { +	for (i = 0; i < extra_to.nr; i++) {  		if (i)  			strbuf_addstr(&buf, "    "); -		strbuf_addstr(&buf, extra_to[i]); -		if (i + 1 < extra_to_nr) +		strbuf_addstr(&buf, extra_to.items[i].string); +		if (i + 1 < extra_to.nr)  			strbuf_addch(&buf, ',');  		strbuf_addch(&buf, '\n');  	} -	if (extra_cc_nr) +	if (extra_cc.nr)  		strbuf_addstr(&buf, "Cc: "); -	for (i = 0; i < extra_cc_nr; i++) { +	for (i = 0; i < extra_cc.nr; i++) {  		if (i)  			strbuf_addstr(&buf, "    "); -		strbuf_addstr(&buf, extra_cc[i]); -		if (i + 1 < extra_cc_nr) +		strbuf_addstr(&buf, extra_cc.items[i].string); +		if (i + 1 < extra_cc.nr)  			strbuf_addch(&buf, ',');  		strbuf_addch(&buf, '\n');  	} @@ -1223,6 +1242,9 @@ int cmd_format_patch(int argc, const char **argv, const char *prefix)  			fclose(stdout);  	}  	free(list); +	string_list_clear(&extra_to, 0); +	string_list_clear(&extra_cc, 0); +	string_list_clear(&extra_hdr, 0);  	if (ignore_if_in_upstream)  		free_patch_ids(&ids);  	return 0; diff --git a/git-send-email.perl b/git-send-email.perl index e05455f74c..d612ae8729 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -47,9 +47,9 @@ git send-email [options] <file | directory | rev-list options >    Composing:      --from                  <str>  * Email From: -    --to                    <str>  * Email To: -    --cc                    <str>  * Email Cc: -    --bcc                   <str>  * Email Bcc: +    --[no-]to               <str>  * Email To: +    --[no-]cc               <str>  * Email Cc: +    --[no-]bcc              <str>  * Email Bcc:      --subject               <str>  * Email "Subject:"      --in-reply-to           <str>  * Email "In-Reply-To:"      --annotate                     * Review each patch that will be sent in an editor. @@ -135,7 +135,7 @@ sub unique_email_list(@);  sub cleanup_compose_files();  # Variables we fill in automatically, or via prompting: -my (@to,@cc,@initial_cc,@bcclist,@xh, +my (@to,$no_to,@cc,$no_cc,@initial_cc,@bcclist,$no_bcc,@xh,  	$initial_reply_to,$initial_subject,@files,  	$author,$sender,$smtp_authpass,$annotate,$compose,$time); @@ -261,8 +261,11 @@ my $rc = GetOptions("sender|from=s" => \$sender,                      "in-reply-to=s" => \$initial_reply_to,  		    "subject=s" => \$initial_subject,  		    "to=s" => \@to, +		    "no-to" => \$no_to,  		    "cc=s" => \@initial_cc, +		    "no-cc" => \$no_cc,  		    "bcc=s" => \@bcclist, +		    "no-bcc" => \$no_bcc,  		    "chain-reply-to!" => \$chain_reply_to,  		    "smtp-server=s" => \$smtp_server,  		    "smtp-server-port=s" => \$smtp_server_port, @@ -305,6 +308,9 @@ sub read_config {  	foreach my $setting (keys %config_settings) {  		my $target = $config_settings{$setting}; +		next if $setting eq "to" and defined $no_to; +		next if $setting eq "cc" and defined $no_cc; +		next if $setting eq "bcc" and defined $no_bcc;  		if (ref($target) eq "ARRAY") {  			unless (@$target) {  				my @values = Git::config(@repo, "$prefix.$setting"); diff --git a/t/t4014-format-patch.sh b/t/t4014-format-patch.sh index f2a2aaa2b9..c7b625642d 100755 --- a/t/t4014-format-patch.sh +++ b/t/t4014-format-patch.sh @@ -143,6 +143,58 @@ test_expect_success 'configuration headers and command line headers' '  	grep "^ *S. E. Cipient <scipient@example.com>\$" patch7  ' +test_expect_success 'command line To: header' ' + +	git config --unset-all format.headers && +	git format-patch --to="R. E. Cipient <rcipient@example.com>" --stdout master..side | sed -e "/^\$/q" >patch8 && +	grep "^To: R. E. Cipient <rcipient@example.com>\$" patch8 +' + +test_expect_success 'configuration To: header' ' + +	git config format.to "R. E. Cipient <rcipient@example.com>" && +	git format-patch --stdout master..side | sed -e "/^\$/q" >patch9 && +	grep "^To: R. E. Cipient <rcipient@example.com>\$" patch9 +' + +test_expect_success '--no-to overrides config.to' ' + +	git config --replace-all format.to \ +		"R. E. Cipient <rcipient@example.com>" && +	git format-patch --no-to --stdout master..side | +	sed -e "/^\$/q" >patch10 && +	! grep "^To: R. E. Cipient <rcipient@example.com>\$" patch10 +' + +test_expect_success '--no-to and --to replaces config.to' ' + +	git config --replace-all format.to \ +		"Someone <someone@out.there>" && +	git format-patch --no-to --to="Someone Else <else@out.there>" \ +		--stdout master..side | +	sed -e "/^\$/q" >patch11 && +	! grep "^To: Someone <someone@out.there>\$" patch11 && +	grep "^To: Someone Else <else@out.there>\$" patch11 +' + +test_expect_success '--no-cc overrides config.cc' ' + +	git config --replace-all format.cc \ +		"C. E. Cipient <rcipient@example.com>" && +	git format-patch --no-cc --stdout master..side | +	sed -e "/^\$/q" >patch12 && +	! grep "^Cc: C. E. Cipient <rcipient@example.com>\$" patch12 +' + +test_expect_success '--no-add-headers overrides config.headers' ' + +	git config --replace-all format.headers \ +		"Header1: B. E. Cipient <rcipient@example.com>" && +	git format-patch --no-add-headers --stdout master..side | +	sed -e "/^\$/q" >patch13 && +	! grep "^Header1: B. E. Cipient <rcipient@example.com>\$" patch13 +' +  test_expect_success 'multiple files' '  	rm -rf patches/ && diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index c09f375288..640b3d2bb4 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -852,4 +852,70 @@ test_expect_success 'no warning with sendemail.chainreplyto = true' '  	! grep "no-chain-reply-to" errors  ' +test_expect_success 'sendemail.to works' ' +	git config --replace-all sendemail.to "Somebody <somebody@ex.com>" && +	git send-email \ +		--dry-run \ +		--from="Example <nobody@example.com>" \ +		$patches $patches >stdout && +	grep "To: Somebody <somebody@ex.com>" stdout +' + +test_expect_success '--no-to overrides sendemail.to' ' +	git send-email \ +		--dry-run \ +		--from="Example <nobody@example.com>" \ +		--no-to \ +		--to=nobody@example.com \ +		$patches $patches >stdout && +	grep "To: nobody@example.com" stdout && +	! grep "To: Somebody <somebody@ex.com>" stdout +' + +test_expect_success 'sendemail.cc works' ' +	git config --replace-all sendemail.cc "Somebody <somebody@ex.com>" && +	git send-email \ +		--dry-run \ +		--from="Example <nobody@example.com>" \ +		--to=nobody@example.com \ +		$patches $patches >stdout && +	grep "Cc: Somebody <somebody@ex.com>" stdout +' + +test_expect_success '--no-cc overrides sendemail.cc' ' +	git send-email \ +		--dry-run \ +		--from="Example <nobody@example.com>" \ +		--no-cc \ +		--cc=bodies@example.com \ +		--to=nobody@example.com \ +		$patches $patches >stdout && +	grep "Cc: bodies@example.com" stdout && +	! grep "Cc: Somebody <somebody@ex.com>" stdout +' + +test_expect_success 'sendemail.bcc works' ' +	git config --replace-all sendemail.bcc "Other <other@ex.com>" && +	git send-email \ +		--dry-run \ +		--from="Example <nobody@example.com>" \ +		--to=nobody@example.com \ +		--smtp-server relay.example.com \ +		$patches $patches >stdout && +	grep "RCPT TO:<other@ex.com>" stdout +' + +test_expect_success '--no-bcc overrides sendemail.bcc' ' +	git send-email \ +		--dry-run \ +		--from="Example <nobody@example.com>" \ +		--no-bcc \ +		--bcc=bodies@example.com \ +		--to=nobody@example.com \ +		--smtp-server relay.example.com \ +		$patches $patches >stdout && +	grep "RCPT TO:<bodies@example.com>" stdout && +	! grep "RCPT TO:<other@ex.com>" stdout +' +  test_done | 
