git/list[1] front-page[2] threads[3] people[4] search[5] about
 

Re: [PATCH v4] Add default merge options for all branches

From
Michael Grubb <devel@dailyvoid.com>
Date
May 4, 2011, 18:58 UTC
Message-ID
<4DC1A1BC.5010601@dailyvoid.com>
In-Reply-To
<20110504045802.GF8187@elie>
Well, it certainly serves *my* immediate needs and addresses the specific use case that I was originally working on.  Though I think that what we've come up with would benefit the codebase in general if for no other reason than it lays some ground work for future features and is a bit more generic.  I also wouldn't mind going a step further and working on the globbing feature in a separate series.
Here are some corrections to the previous patch:

This patch makes the branch specific options more flexible by laying the ground work for supporting globs for the branch names. At this time only the value '*' is supported which will set default values for all branches. In the future this may be expanded to support true globbing.

Signed-off-by: Michael Grubb <devel@dailyvoid.com>
---
 builtin/merge.c  |  120 ++++++++++++++++++++++++++++++++++-------------------
 t/t7600-merge.sh |   27 ++++++++----
 2 files changed, 95 insertions(+), 52 deletions(-)
diff --git a/builtin/merge.c b/builtin/merge.c
index fa56205..9e6ec5f 100644
--- a/builtin/merge.c
+++ b/builtin/merge.c
@@ -31,20 +31,12 @@
 #define DEFAULT_OCTOPUS (1<<1)
 #define NO_FAST_FORWARD (1<<2)
 #define NO_TRIVIAL      (1<<3)
+#define MERGE_OPTIONS_INIT {NULL, NULL, NULL}
 
-/* This is for branch.<foo>. blocks
- * the vote member holds a value between
- * 0.0 and 1.0 which measures how closely
- * a branch name matches the key member.
- * where branch.*.mergeoptions would be 0.1 and
- * branch.<name>.mergeoptions would be 1.0
- * Also it is called vote because I couldn't come
- * up with a better name.
- */
 struct merge_options_cb {
-	char *key;
-	char *value;
-	float vote;
+	char *option;
+	char *spec;
+	char *name;
 };
 
 struct strategy {
@@ -518,30 +510,11 @@ cleanup:
 	strbuf_release(&bname);
 }
 
-static void parse_git_merge_options(const char *k, const char *v,
-			void *cb)
+static void free_merge_options_cb(struct merge_options_cb *data)
 {
-	struct merge_options_cb *merge_options = cb;
-	int changed = 0;
-
-	/* We only handle mergeoptions for now */
-	if (suffixcmp(k, ".mergeoptions"))
-		return;
-
-	if (!prefixcmp(k, "branch.*") && merge_options->vote <= 0.1 ) {
-		merge_options->vote = 0.1;
-		changed = 1;
-	} else if (branch && !prefixcmp(k, "branch.") &&
-				!prefixcmp(k + 7, branch) &&
-				merge_options->vote < 1.0) {
-		merge_options->vote = 1.0;
-		changed = 1;
-	}
-
-	if (changed) {
-		merge_options->key = (char *)k;
-		merge_options->value = (char *)v;
-	}
+	free(data->option);
+	free(data->spec);
+	free(data->name);
 }
 
 static void apply_merge_options(struct merge_options_cb *opts)
@@ -550,26 +523,85 @@ static void apply_merge_options(struct merge_options_cb *opts)
 	int argc;
 	char *buf;
 
-	if ( opts == NULL )
+	if (!opts)
 		return;
 
-	buf = xstrdup(opts->value);
+	buf = xstrdup(opts->option);
 	argc = split_cmdline(buf, &argv);
 	if (argc < 0)
-		die(_("Bad %s string: %s"),
-			opts->key, split_cmdline_strerror(argc));
+		die(_("Bad branch.%s.%s string: %s"),
+			opts->spec, opts->name, split_cmdline_strerror(argc));
 
 	argv = xrealloc(argv, sizeof(*argv) * (argc + 2));
 	memmove(argv + 1, argv, sizeof(*argv) * (argc + 1));
 	argc++;
 	parse_options(argc, argv, NULL, builtin_merge_options,
-			  builtin_merge_usage, 0);
+		builtin_merge_usage, 0);
 	free(buf);
 }
 
+/*
+ * This function returns -1 if the first argument is less specific
+ * than the second, and 1 vice versa. Returns -1 if both arguments
+ * are the same.
+ */
+static int cmp_specificity(const char *a, const char *b)
+{
+	switch((!strcmp(a, "*") ? 2 : 0) |
+		(!strcmp(b, "*") ? 1 : 0)) {
+	case 3:
+	case 0:
+		return -1; /* later one wins if they are the same */
+	case 1:
+		return 1;
+	case 2:
+		return -1;
+	}
+	return 0; /* should never happen */
+}
+
+static void parse_git_merge_options(const char *k, const char *v,
+			void *cb)
+{
+	struct merge_options_cb *merge_options = cb;
+	char *spec, *eon; /* end-of-name */
+
+	k += 7; /* not interested in the leading "branch." */
+	eon = strrchr(k, '.');
+	if (!eon || strcmp(eon, ".mergeoptions"))
+		return;
+
+	/* k through eon is name or glob */
+	spec = xmemdupz(k, eon - k);
+	/*
+	 * NEEDSWORK: for now we say "*" matches; we would need
+	 * to turn the following into something like:
+	 *	if (has_wildcard(spec)
+	 *		? !glob_matches(spec, branch)
+	 *		: strcmp(spec, branch)) {
+	 *		free(spec);
+	 *		return;
+	 *	}
+	 */
+	if (strcmp(spec, "*") && strcmp(spec, branch)) {
+		free(spec);
+		return;
+	}
+
+	if (!merge_options->option ||
+			cmp_specificity(merge_options->spec, spec) < 0) {
+		free_merge_options_cb(merge_options);
+		merge_options->option = xstrdup(v);
+		merge_options->name = xstrdup(eon + 1);
+		merge_options->spec = spec;
+		return;
+	}
+	free(spec);
+}
+
 static int git_merge_config(const char *k, const char *v, void *cb)
 {
-	if (cb != NULL && branch && !prefixcmp(k, "branch."))
+	if (branch && !prefixcmp(k, "branch."))
 		parse_git_merge_options(k, v, cb);
 
 	if (!strcmp(k, "merge.diffstat") || !strcmp(k, "merge.stat"))
@@ -1034,7 +1066,7 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 	const char *head_arg;
 	int flag, head_invalid = 0, i;
 	int best_cnt = -1, merge_was_ok = 0, automerge_was_ok = 0;
-	struct merge_options_cb merge_options = {NULL, NULL, 0.0};
+	struct merge_options_cb merge_options = MERGE_OPTIONS_INIT;
 	struct commit_list *common = NULL;
 	const char *best_strategy = NULL, *wt_strategy = NULL;
 	struct commit_list **remotes = &remoteheads;
@@ -1053,8 +1085,10 @@ int cmd_merge(int argc, const char **argv, const char *prefix)
 		head_invalid = 1;
 
 	git_config(git_merge_config, &merge_options);
-	if (merge_options.key != NULL && merge_options.value != NULL)
+	if (merge_options.option) {
 		apply_merge_options(&merge_options);
+		free_merge_options_cb(&merge_options);
+	}
 
 	/* for color.ui */
 	if (diff_use_color_default == -1)
diff --git a/t/t7600-merge.sh b/t/t7600-merge.sh
index 5b1f8e1..d7a60b2 100755
--- a/t/t7600-merge.sh
+++ b/t/t7600-merge.sh
@@ -417,37 +417,46 @@ test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'merge c0 with c1 (default no-ff)' '
 	git reset --hard c0 &&
-	test_might_fail git config --unset branch.master.mergeoptions &&
-	git config "branch.*.mergeoptions" "--no-ff" &&
+	cat >.git/config <<-\EOF &&
+	[branch "*"]
+		mergeoptions = --no-ff
+	EOF
 	test_tick &&
 	git merge c1 &&
 	git config --remove-section "branch.*" &&
 	verify_merge file result.1 &&
 	verify_parents $c0 $c1
 '
-
 test_debug 'git log --graph --decorate --oneline --all'
 
 test_expect_success 'combine branch.*.mergeoptions with branch.x.mergeoptions' '
 	git reset --hard c0 &&
-	test_might_fail git config --remove-section branch.master &&
-	git config "branch.*.mergeoptions" "--no-ff" &&
-	git config branch.master.mergeoptions "--ff" &&
+	cat >.git/config <<-\EOF &&
+	[branch "*"]
+		mergeoptions = --no-ff
+	[branch "master"]
+		mergeoptions = --ff
+	EOF
 	test_tick &&
 	git merge c1 &&
 	git config --remove-section "branch.*" &&
+	git config --remove-section "branch.master" &&
 	verify_merge file result.1 &&
 	verify_parents "$c0"
 '
 
 test_expect_success 'reverse branch.x.mergeoptions with branch.*.mergeoptions' '
 	git reset --hard c0 &&
-	test_might_fail git config --remove-section branch.master &&
-	git config branch.master.mergeoptions "--ff" &&
-	git config "branch.*.mergeoptions" "--no-ff" &&
+	cat >.git/config <<-\EOF &&
+	[branch "master"]
+		mergeoptions = --ff
+	[branch "*"]
+		mergeoptions = --no-ff
+	EOF
 	test_tick &&
 	git merge c1 &&
 	git config --remove-section "branch.*" &&
+	git config --remove-section "branch.master" &&
 	verify_merge file result.1 &&
 	verify_parents "$c0"
 '
-- 
1.7.5



On 5/3/11 11:58 PM, Jonathan Nieder wrote:
> Michael Grubb wrote:
> 
>> I take this to mean that my patch is no longer needed/wanted?
> 
> No, as usual it means that Junio was thinking and sent us his
> thoughts.
> 
> Do you like it?  If so, the way to move it forward would be to add
> tests and write a commit log message.  If not, the way to move things
> forward would be to explain what use case it misses and work on a
> better patch that takes care of them.
> 
> Hope that helps,
> Jonathan
> --
> To unsubscribe from this list: send the line "unsubscribe git" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at  http://vger.kernel.org/majordomo-info.html
> 
Previous: Jonathan NiederNext: Junio C Hamano
Message 20 of 46 in “Add default merge options for all branches”
  1. Add default merge options for all branchesMichael Grubb, May 2, 2011
  2. Miklos VajnaMay 2, 2011
  3. Junio C HamanoMay 2, 2011
  4. Michael GrubbMay 3, 2011
  5. Add default merge options for all branchesMichael Grubb, May 3, 2011
  6. Jonathan NiederMay 3, 2011
  7. Jonathan NiederMay 3, 2011
  8. Michael GrubbMay 3, 2011
  9. Junio C HamanoMay 3, 2011
  10. Michael GrubbMay 3, 2011
  11. Jonathan NiederMay 3, 2011
  12. Jens LehmannMay 3, 2011
  13. Add default merge options for all branchesMichael Grubb, May 3, 2011
  14. Michael GrubbMay 3, 2011
  15. Jonathan NiederMay 3, 2011
  16. Junio C HamanoMay 3, 2011
  17. Junio C HamanoMay 4, 2011
  18. Michael GrubbMay 4, 2011
  19. Jonathan NiederMay 4, 2011
  20. Michael GrubbMay 4, 2011
  21. Junio C HamanoMay 4, 2011
  22. John SzakmeisterMay 4, 2011
  23. Junio C HamanoMay 3, 2011
  24. Add default merge options for all branchesMichael Grubb, May 3, 2011
  25. Add default merge options for all branchesMichael Grubb, May 4, 2011
  26. Junio C HamanoMay 5, 2011
  27. Junio C HamanoMay 6, 2011
  28. Jonathan NiederMay 6, 2011
  29. 0/2 tests: make verify_merge check that the number of parents is rightJonathan Nieder, May 6, 2011
  30. 1/2 tests: eliminate unnecessary setup test assertionsJonathan Nieder, May 6, 2011
  31. Jeff KingMay 6, 2011
  32. Jeff KingMay 6, 2011
  33. Junio C HamanoMay 6, 2011
  34. Jeff KingMay 6, 2011
  35. Junio C HamanoMay 7, 2011
  36. 0/3 blame --line-porcelainJeff King, May 9, 2011
  37. 1/3 add tests for various blame formatsJeff King, May 9, 2011
  38. 2/3 blame: refactor porcelain outputJeff King, May 9, 2011
  39. Thiago FarinaMay 9, 2011
  40. 3/3 blame: add --line-porcelain output formatJeff King, May 9, 2011
  41. Jonathan NiederMay 6, 2011
  42. 2/2 tests: teach verify_parents to check for extra parentsJonathan Nieder, May 6, 2011
  43. Junio C HamanoMay 6, 2011
  44. Jonathan NiederMay 6, 2011
  45. Jonathan NiederMay 6, 2011
  46. Junio C HamanoMay 6, 2011

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.