Subject: [PATCH v2 3/3] builtin-merge: add support for default merge options

From: Jay Soffian <[email-masked]>
Date: Fri, 6 Mar 2009 19:44:35 -0500

This patch teaches merge a new setting, merge.options, which is
processed before any of the other merge configuration settings. It may
be used to establish a default which can then be overridden by more
specific branch.<name>.mergeoptions (or, obviously, command-line
switches).

Signed-off-by: Jay Soffian <[email-masked]>
---
On Fri, Mar 6, 2009 at 5:46 PM, Junio C Hamano <[email-masked]> wrote:
> If for some reason you would want to have cumulative options across
> branch.*.merge, merge.options and the command line, then you would instead
> keep two separate strings, and call git_config_option_string() for both of
> them, before processing the real command line options.

Which is what this version does. I also made the explanation of this behavior
in the man page more explicit.

 Documentation/git-merge.txt |   12 +++++--
 builtin-merge.c             |   22 +++++++++++--
 t/t7600-merge.sh            |   69 +++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 96 insertions(+), 7 deletions(-)

diff --git a/Documentation/git-merge.txt b/Documentation/git-merge.txt
index f7be584..5d80a78 100644
--- a/Documentation/git-merge.txt
+++ b/Documentation/git-merge.txt
@@ -47,10 +47,16 @@ CONFIGURATION
 -------------
 include::merge-config.txt[]
 
+merge.options::
+	Sets default options for merging. The syntax and supported options are
+	equal to that of 'git-merge'. Arguments are split by spaces, and may be
+	quoted in the same way as alias.* config options.
+
 branch.<name>.mergeoptions::
-	Sets default options for merging into branch <name>. The syntax and
-	supported options are equal to that of 'git-merge', but option values
-	containing whitespace characters are currently not supported.
+	Sets default options for merging into branch <name>. This setting is
+	handled after and is cumulative to `merge.options`. So it may override,
+	but does replace, any settings appearing there. The syntax is identical
+	to `merge.options`.
 
 HOW MERGE WORKS
 ---------------
diff --git a/builtin-merge.c b/builtin-merge.c
index 504f2be..d4dc4fe 100644
--- a/builtin-merge.c
+++ b/builtin-merge.c
@@ -50,6 +50,8 @@ static unsigned char head[20], stash[20];
 static struct strategy **use_strategies;
 static size_t use_strategies_nr, use_strategies_alloc;
 static const char *branch;
+static const char *branch_option_string = NULL;
+static const char *default_option_string = NULL;
 static int verbosity;
 
 static struct strategy all_strategy[] = {
@@ -451,10 +453,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 {
 	if (branch && !prefixcmp(k, "branch.") &&
 		!prefixcmp(k + 7, branch) &&
-		!strcmp(k + 7 + strlen(branch), ".mergeoptions")) {
-		if (git_config_option_string(builtin_merge_options, 0, k, v))
-			die("Bad branch.%s.mergeoptions string", branch);
-	}
+		!strcmp(k + 7 + strlen(branch), ".mergeoptions"))
+			return git_config_string(&branch_option_string, k, v);
 
 	if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
 		show_diffstat = git_config_bool(k, v);
@@ -462,6 +462,8 @@ static int git_merge_config(const char *k, const char *v, void *cb)
 		return git_config_string(&pull_twohead, k, v);
 	else if (!strcmp(k, "pull.octopus"))
 		return git_config_string(&pull_octopus, k, v);
+	else if (!strcmp(k, "merge.options"))
+		return git_config_string(&default_option_string, k, v);
 	else if (!strcmp(k, "merge.log") || !strcmp(k, "merge.summary"))
 		option_log = git_config_bool(k, v);
 	return git_diff_ui_config(k, v, cb);
@@ -839,6 +841,18 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		head_invalid = 1;
 
 	git_config(git_merge_config, NULL);
+	if (default_option_string) {
+		if (git_config_option_string(builtin_merge_options, 0,
+		    "merge.options", default_option_string))
+			die("Bad merge.options string");
+	}
+	if (branch_option_string) {
+		strbuf_addf(&buf, "branch.%s.mergeoptions", branch);
+		if (git_config_option_string(builtin_merge_options, 0,
+		     buf.buf, branch_option_string))
+			die("Bad %s string", buf.buf);
+		strbuf_reset(&buf);
+	}
 
 	/* for color.ui */
 	if (diff_use_color_default == -1)
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 9db8bb4..aaecdab 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -367,6 +367,16 @@ test_expect_success 'merge c1 with c2 (no-commit in config)' '
 
 test_debug 'gitk --all'
 
+test_expect_success 'merge c1 with c2 (no-commit in merge.options)' '
+	git reset --hard c1 &&
+	with_config merge.options --no-commit -- merge c2 &&
+	verify_merge file result.1-5 &&
+	verify_head $c1 &&
+	verify_mergeheads $c2
+'
+
+test_debug 'gitk --all'
+
 test_expect_success 'merge c1 with c2 (squash in config)' '
 	git reset --hard c1 &&
 	with_config branch.master.mergeoptions --squash -- \
@@ -379,6 +389,17 @@ test_expect_success 'merge c1 with c2 (squash in config)' '
 
 test_debug 'gitk --all'
 
+test_expect_success 'merge c1 with c2 (squash in merge.options)' '
+	git reset --hard c1 &&
+	with_config merge.options --squash -- merge c2 &&
+	verify_merge file result.1-5 &&
+	verify_head $c1 &&
+	verify_no_mergehead &&
+	verify_diff squash.1-5 .git/SQUASH_MSG "[OOPS] bad squash message"
+'
+
+test_debug 'gitk --all'
+
 test_expect_success 'override config option -n with --summary' '
 	git reset --hard c1 &&
 	test_tick &&
@@ -425,6 +446,54 @@ test_expect_success 'override config option --stat' '
 
 test_debug 'gitk --all'
 
+test_expect_success 'override merge.options -n with branch mergeoptions --summary' '
+	git reset --hard c1 &&
+	test_tick &&
+	with_config merge.options -n branch.master.mergeoptions --summary -- \
+		merge c2 >diffstat.txt &&
+	verify_merge file result.1-5 msg.1-5 &&
+	verify_parents $c1 $c2 &&
+	if ! grep "^ file |  *2 +-$" diffstat.txt
+	then
+		echo "[OOPS] diffstat was not generated with --summary"
+		false
+	fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'override merge.options -n with branch mergeoptions --stat' '
+	git reset --hard c1 &&
+	test_tick &&
+	with_config merge.options -n branch.master.mergeoptions --stat -- \
+		merge c2 >diffstat.txt &&
+	verify_merge file result.1-5 msg.1-5 &&
+	verify_parents $c1 $c2 &&
+	if ! grep "^ file |  *2 +-$" diffstat.txt
+	then
+		echo "[OOPS] diffstat was not generated with --stat"
+		false
+	fi
+'
+
+test_debug 'gitk --all'
+
+test_expect_success 'override merge.options --stat' '
+	git reset --hard c1 &&
+	test_tick &&
+	with_config merge.options --stat branch.master.mergeoptions -n -- \
+		merge c2 >diffstat.txt &&
+	verify_merge file result.1-5 msg.1-5 &&
+	verify_parents $c1 $c2 &&
+	if grep "^ file |  *2 +-$" diffstat.txt
+	then
+		echo "[OOPS] diffstat was generated"
+		false
+	fi
+'
+
+test_debug 'gitk --all'
+
 test_expect_success 'merge c1 with c2 (override --no-commit)' '
 	git reset --hard c1 &&
 	test_tick &&
-- 
1.6.2.rc2.332.g5d21b