{"thread":{"id":"40087","subject":"[PATCH v5 1/4] notes: document cat_sort_uniq rewriteMode","startedAt":"2015-08-14T17:50:16Z","lastAt":"2015-08-14T18:07:03Z","messageCount":6,"participants":["Jacob Keller","Eric Sunshine"],"isPatch":true,"patchVersion":5,"patchTotal":4},"messages":[{"id":"268051","messageId":"1439574620-25249-1-git-send-email-jacob.e.keller@intel.com","threadId":"40087","inReplyTo":null,"subject":"[PATCH v5 0/4] notes mergestrategy configuration option","fromName":"Jacob Keller","fromEmail":"jacob.e.keller@intel.com","sentAt":"2015-08-14T17:50:16Z","receivedAt":"2015-08-14T17:50:16Z","isPatch":true,"sender":{"key":"jacob.e.keller@intel.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.keller@gmail.com>\n\nI have tried to cover all of the comments since the last sending of\nthis series. I am not 100% sure if I got everything, so please feel free\nto respond again if I missed something.\n\nThis series implements the notes.mergestrategy option, as well as a\nnotes.<ref>.mergestrategy option which can be used to customize what\nstrategy is used to merge into a particular ref. I chose to use the\nlocal ref instead of the remote reference, as it is most likely that you\nwill merge into a given ref with the same strategy rather than always\nusing the same strategy to merge from a ref.\n\nThe notes.<ref>.mergestrategy option uses the short name under\nrefs/notes/ and does not allow arbitrary references. Today git-notes\ndoes not allow *any* arbitrary ref as a notes ref for either merge or\nany other operation, (see init_notes_check!). Due to this, we can force\nthe config to use the shorthand name instead of the full name.\n\nIn the future we may wish to allow non-write operations to reference an\narbitrary ref (such as refs/remote-notes/* or refs/tracking/*/notes/)\nbut this is not today supported, and in anycase merge is a destructive\nwrite operation so it should always require refs/notes/ references.\n\n\nChanges since v4\n* renamed option to mergestrategy for both per-ref and general option\n  for consistency and to keep the notes.merge and notes.<ref>.merge\n  available as keys for future notes enhancements\n\n* use shortrefs for notes.<ref>.mergestrategy\n\nJacob Keller (4):\n  notes: document cat_sort_uniq rewriteMode\n  notes: add tests for --commit/--abort/--strategy exclusivity\n  notes: add notes.mergestrategy option to select default strategy\n  notes: teach git-notes about notes.<ref>.mergestrategy option\n\n Documentation/config.txt              | 18 ++++++++--\n Documentation/git-notes.txt           | 23 ++++++++++--\n builtin/notes.c                       | 46 +++++++++++++++++-------\n notes-merge.h                         | 16 +++++----\n t/t3309-notes-merge-auto-resolve.sh   | 68 +++++++++++++++++++++++++++++++++++\n t/t3310-notes-merge-manual-resolve.sh | 12 +++++++\n 6 files changed, 159 insertions(+), 24 deletions(-)\n\n-- \n2.5.0.280.g4aaba03\n"},{"id":"268050","messageId":"1439574620-25249-2-git-send-email-jacob.e.keller@intel.com","threadId":"40087","inReplyTo":"1439574620-25249-1-git-send-email-jacob.e.keller@intel.com","subject":"[PATCH v5 1/4] notes: document cat_sort_uniq rewriteMode","fromName":"Jacob Keller","fromEmail":"jacob.e.keller@intel.com","sentAt":"2015-08-14T17:50:17Z","receivedAt":"2015-08-14T17:50:17Z","isPatch":true,"sender":{"key":"jacob.e.keller@intel.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.keller@gmail.com>\n\nTeach documentation about the cat_sort_uniq rewriteMode that got added\nat the same time as the equivalent merge strategy.\n\nSigned-off-by: Jacob Keller <jacob.keller@gmail.com>\n---\n Documentation/config.txt    | 4 ++--\n Documentation/git-notes.txt | 3 ++-\n 2 files changed, 4 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 75ec02e8e90a..de67ad1fdedf 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1947,8 +1947,8 @@ notes.rewriteMode::\n \tWhen copying notes during a rewrite (see the\n \t\"notes.rewrite.<command>\" option), determines what to do if\n \tthe target commit already has a note.  Must be one of\n-\t`overwrite`, `concatenate`, or `ignore`.  Defaults to\n-\t`concatenate`.\n+\t`overwrite`, `concatenate`, `cat_sort_uniq`, or `ignore`.\n+\tDefaults to `concatenate`.\n +\n This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`\n environment variable.\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 851518d531b5..674682b34b83 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -331,7 +331,8 @@ environment variable.\n notes.rewriteMode::\n \tWhen copying notes during a rewrite, what to do if the target\n \tcommit already has a note.  Must be one of `overwrite`,\n-\t`concatenate`, and `ignore`.  Defaults to `concatenate`.\n+\t`concatenate`, `cat_sort_uniq`, or `ignore`.  Defaults to\n+\t`concatenate`.\n +\n This setting can be overridden with the `GIT_NOTES_REWRITE_MODE`\n environment variable.\n-- \n2.5.0.280.g4aaba03\n"},{"id":"268052","messageId":"1439574620-25249-3-git-send-email-jacob.e.keller@intel.com","threadId":"40087","inReplyTo":"1439574620-25249-1-git-send-email-jacob.e.keller@intel.com","subject":"[PATCH v5 2/4] notes: add tests for --commit/--abort/--strategy exclusivity","fromName":"Jacob Keller","fromEmail":"jacob.e.keller@intel.com","sentAt":"2015-08-14T17:50:18Z","receivedAt":"2015-08-14T17:50:18Z","isPatch":true,"sender":{"key":"jacob.e.keller@intel.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.keller@gmail.com>\n\nAdd new tests to ensure that --commit, --abort, and --strategy are\nmutually exclusive.\n\nSigned-off-by: Jacob Keller <jacob.keller@gmail.com>\n---\n t/t3310-notes-merge-manual-resolve.sh | 12 ++++++++++++\n 1 file changed, 12 insertions(+)\n\ndiff --git a/t/t3310-notes-merge-manual-resolve.sh b/t/t3310-notes-merge-manual-resolve.sh\nindex 195bb97f859d..d5572121da69 100755\n--- a/t/t3310-notes-merge-manual-resolve.sh\n+++ b/t/t3310-notes-merge-manual-resolve.sh\n@@ -314,6 +314,18 @@ y and z notes on 1st commit\n \n EOF\n \n+test_expect_success 'do not allow mixing --commit and --abort' '\n+\ttest_must_fail git notes merge --commit --abort\n+'\n+\n+test_expect_success 'do not allow mixing --commit and --strategy' '\n+\ttest_must_fail git notes merge --commit --strategy theirs\n+'\n+\n+test_expect_success 'do not allow mixing --abort and --strategy' '\n+\ttest_must_fail git notes merge --abort --strategy theirs\n+'\n+\n test_expect_success 'finalize conflicting merge (z => m)' '\n \t# Resolve conflicts and finalize merge\n \tcat >.git/NOTES_MERGE_WORKTREE/$commit_sha1 <<EOF &&\n-- \n2.5.0.280.g4aaba03\n"},{"id":"268054","messageId":"1439574620-25249-4-git-send-email-jacob.e.keller@intel.com","threadId":"40087","inReplyTo":"1439574620-25249-1-git-send-email-jacob.e.keller@intel.com","subject":"[PATCH v5 3/4] notes: add notes.mergestrategy option to select default strategy","fromName":"Jacob Keller","fromEmail":"jacob.e.keller@intel.com","sentAt":"2015-08-14T17:50:19Z","receivedAt":"2015-08-14T17:50:19Z","isPatch":true,"sender":{"key":"jacob.e.keller@intel.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.keller@gmail.com>\n\nTeach git-notes about \"notes.mergestrategy\" to select a general strategy\nfor all notes merges. This enables a user to always get expected merge\nstrategy such as \"cat_sort_uniq\" without having to pass the \"-s\" option\nmanually.\n\nSigned-off-by: Jacob Keller <jacob.keller@gmail.com>\n---\n Documentation/config.txt            |  7 +++++++\n Documentation/git-notes.txt         | 14 +++++++++++++-\n builtin/notes.c                     | 37 +++++++++++++++++++++++++------------\n notes-merge.h                       | 16 +++++++++-------\n t/t3309-notes-merge-auto-resolve.sh | 29 +++++++++++++++++++++++++++++\n 5 files changed, 83 insertions(+), 20 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex de67ad1fdedf..5e3e03459de7 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1919,6 +1919,13 @@ mergetool.writeToTemp::\n mergetool.prompt::\n \tPrompt before each invocation of the merge resolution program.\n \n+notes.mergestrategy::\n+\tWhich merge strategy to choose by default when resolving notes\n+\tconflicts. Must be one of `manual`, `ours`, `theirs`, `union`,\n+\tor `cat_sort_uniq`. Defaults to `manual`. See \"NOTES MERGE\n+\tSTRATEGIES\" section of linkgit:git-notes[1] for more information\n+\ton each strategy.\n+\n notes.displayRef::\n \tThe (fully qualified) refname from which to show notes when\n \tshowing commit messages.  The value of this variable can be set\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 674682b34b83..89c8829a0543 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -101,7 +101,7 @@ merge::\n \tany) into the current notes ref (called \"local\").\n +\n If conflicts arise and a strategy for automatically resolving\n-conflicting notes (see the -s/--strategy option) is not given,\n+conflicting notes (see the \"NOTES MERGE STRATEGIES\" section) is not given,\n the \"manual\" resolver is used. This resolver checks out the\n conflicting notes in a special worktree (`.git/NOTES_MERGE_WORKTREE`),\n and instructs the user to manually resolve the conflicts there.\n@@ -183,6 +183,7 @@ OPTIONS\n \tWhen merging notes, resolve notes conflicts using the given\n \tstrategy. The following strategies are recognized: \"manual\"\n \t(default), \"ours\", \"theirs\", \"union\" and \"cat_sort_uniq\".\n+\tThis option overrides the \"notes.mergestrategy\" configuration setting.\n \tSee the \"NOTES MERGE STRATEGIES\" section below for more\n \tinformation on each notes merge strategy.\n \n@@ -247,6 +248,9 @@ When done, the user can either finalize the merge with\n 'git notes merge --commit', or abort the merge with\n 'git notes merge --abort'.\n \n+Users may select an automated merge strategy from among the following using\n+either -s/--strategy option or configuring notes.mergestrategy accordingly:\n+\n \"ours\" automatically resolves conflicting notes in favor of the local\n version (i.e. the current notes ref).\n \n@@ -310,6 +314,14 @@ core.notesRef::\n \tThis setting can be overridden through the environment and\n \tcommand line.\n \n+notes.mergestrategy::\n+\tWhich merge strategy to choose by default when resolving notes\n+\tconflicts. Must be one of `manual`, `ours`, `theirs`, `union`,\n+\tor `cat_sort_uniq`. Defaults to `manual`. See \"NOTES MERGE\n+\tSTRATEGIES\" section above for more information on each strategy.\n++\n+This setting can be overridden by passing the `--strategy` option.\n+\n notes.displayRef::\n \tWhich ref (or refs, if a glob or specified more than once), in\n \taddition to the default set by `core.notesRef` or\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 042348082709..97109f8d419c 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -738,6 +738,24 @@ static int merge_commit(struct notes_merge_options *o)\n \treturn ret;\n }\n \n+static int parse_notes_strategy(const char *arg, enum notes_merge_strategy *strategy)\n+{\n+\tif (!strcmp(arg, \"manual\"))\n+\t\t*strategy = NOTES_MERGE_RESOLVE_MANUAL;\n+\telse if (!strcmp(arg, \"ours\"))\n+\t\t*strategy = NOTES_MERGE_RESOLVE_OURS;\n+\telse if (!strcmp(arg, \"theirs\"))\n+\t\t*strategy = NOTES_MERGE_RESOLVE_THEIRS;\n+\telse if (!strcmp(arg, \"union\"))\n+\t\t*strategy = NOTES_MERGE_RESOLVE_UNION;\n+\telse if (!strcmp(arg, \"cat_sort_uniq\"))\n+\t\t*strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ;\n+\telse\n+\t\treturn -1;\n+\n+\treturn 0;\n+}\n+\n static int merge(int argc, const char **argv, const char *prefix)\n {\n \tstruct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;\n@@ -746,7 +764,7 @@ static int merge(int argc, const char **argv, const char *prefix)\n \tstruct notes_merge_options o;\n \tint do_merge = 0, do_commit = 0, do_abort = 0;\n \tint verbosity = 0, result;\n-\tconst char *strategy = NULL;\n+\tconst char *strategy = NULL, *configured_strategy = NULL;\n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"General options\")),\n \t\tOPT__VERBOSITY(&verbosity),\n@@ -796,21 +814,16 @@ static int merge(int argc, const char **argv, const char *prefix)\n \texpand_notes_ref(&remote_ref);\n \to.remote_ref = remote_ref.buf;\n \n+\tgit_config_get_string_const(\"notes.mergestrategy\", &configured_strategy);\n+\n \tif (strategy) {\n-\t\tif (!strcmp(strategy, \"manual\"))\n-\t\t\to.strategy = NOTES_MERGE_RESOLVE_MANUAL;\n-\t\telse if (!strcmp(strategy, \"ours\"))\n-\t\t\to.strategy = NOTES_MERGE_RESOLVE_OURS;\n-\t\telse if (!strcmp(strategy, \"theirs\"))\n-\t\t\to.strategy = NOTES_MERGE_RESOLVE_THEIRS;\n-\t\telse if (!strcmp(strategy, \"union\"))\n-\t\t\to.strategy = NOTES_MERGE_RESOLVE_UNION;\n-\t\telse if (!strcmp(strategy, \"cat_sort_uniq\"))\n-\t\t\to.strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ;\n-\t\telse {\n+\t\tif (parse_notes_strategy(strategy, &o.strategy)) {\n \t\t\terror(\"Unknown -s/--strategy: %s\", strategy);\n \t\t\tusage_with_options(git_notes_merge_usage, options);\n \t\t}\n+\t} else if (configured_strategy) {\n+\t\tif (parse_notes_strategy(configured_strategy, &o.strategy))\n+\t\t\tdie(\"Unknown notes merge strategy: %s\", configured_strategy);\n \t}\n \n \tt = init_notes_check(\"merge\");\ndiff --git a/notes-merge.h b/notes-merge.h\nindex 1d01f6aacf54..bda8c0c8d348 100644\n--- a/notes-merge.h\n+++ b/notes-merge.h\n@@ -8,18 +8,20 @@ enum notes_merge_verbosity {\n \tNOTES_MERGE_VERBOSITY_MAX = 5\n };\n \n+enum notes_merge_strategy {\n+\tNOTES_MERGE_RESOLVE_MANUAL = 0,\n+\tNOTES_MERGE_RESOLVE_OURS,\n+\tNOTES_MERGE_RESOLVE_THEIRS,\n+\tNOTES_MERGE_RESOLVE_UNION,\n+\tNOTES_MERGE_RESOLVE_CAT_SORT_UNIQ\n+};\n+\n struct notes_merge_options {\n \tconst char *local_ref;\n \tconst char *remote_ref;\n \tstruct strbuf commit_msg;\n \tint verbosity;\n-\tenum {\n-\t\tNOTES_MERGE_RESOLVE_MANUAL = 0,\n-\t\tNOTES_MERGE_RESOLVE_OURS,\n-\t\tNOTES_MERGE_RESOLVE_THEIRS,\n-\t\tNOTES_MERGE_RESOLVE_UNION,\n-\t\tNOTES_MERGE_RESOLVE_CAT_SORT_UNIQ\n-\t} strategy;\n+\tenum notes_merge_strategy strategy;\n \tunsigned has_worktree:1;\n };\n \ndiff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh\nindex 461fd84755d7..476b9f5306f1 100755\n--- a/t/t3309-notes-merge-auto-resolve.sh\n+++ b/t/t3309-notes-merge-auto-resolve.sh\n@@ -298,6 +298,13 @@ test_expect_success 'merge z into y with invalid strategy => Fail/No changes' '\n \tverify_notes y y\n '\n \n+test_expect_success 'merge z into y with invalid configuration option => Fail/No changes' '\n+\tgit config core.notesRef refs/notes/y &&\n+\ttest_must_fail git -c notes.mergestrategy=\"foo\" notes merge z &&\n+\t# Verify no changes (y)\n+\tverify_notes y y\n+'\n+\n cat <<EOF | sort >expect_notes_ours\n 68b8630d25516028bed862719855b3d6768d7833 $commit_sha15\n 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14\n@@ -365,6 +372,17 @@ test_expect_success 'reset to pre-merge state (y)' '\n \tverify_notes y y\n '\n \n+test_expect_success 'merge z into y with \"ours\" configuration option => Non-conflicting 3-way merge' '\n+\tgit -c notes.mergestrategy=\"ours\" notes merge z &&\n+\tverify_notes y ours\n+'\n+\n+test_expect_success 'reset to pre-merge state (y)' '\n+\tgit update-ref refs/notes/y refs/notes/y^1 &&\n+\t# Verify pre-merge state\n+\tverify_notes y y\n+'\n+\n cat <<EOF | sort >expect_notes_theirs\n 9b4b2c61f0615412da3c10f98ff85b57c04ec765 $commit_sha15\n 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14\n@@ -432,6 +450,17 @@ test_expect_success 'reset to pre-merge state (y)' '\n \tverify_notes y y\n '\n \n+test_expect_success 'merge z into y with \"theirs\" strategy overriding configuration option \"ours\" => Non-conflicting 3-way merge' '\n+\tgit -c notes.mergestrategy=\"ours\" notes merge --strategy=theirs z &&\n+\tverify_notes y theirs\n+'\n+\n+test_expect_success 'reset to pre-merge state (y)' '\n+\tgit update-ref refs/notes/y refs/notes/y^1 &&\n+\t# Verify pre-merge state\n+\tverify_notes y y\n+'\n+\n cat <<EOF | sort >expect_notes_union\n 7c4e546efd0fe939f876beb262ece02797880b54 $commit_sha15\n 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14\n-- \n2.5.0.280.g4aaba03\n"},{"id":"268053","messageId":"1439574620-25249-5-git-send-email-jacob.e.keller@intel.com","threadId":"40087","inReplyTo":"1439574620-25249-1-git-send-email-jacob.e.keller@intel.com","subject":"[PATCH v5 4/4] notes: teach git-notes about notes.<ref>.mergestrategy option","fromName":"Jacob Keller","fromEmail":"jacob.e.keller@intel.com","sentAt":"2015-08-14T17:50:20Z","receivedAt":"2015-08-14T17:50:20Z","isPatch":true,"sender":{"key":"jacob.e.keller@intel.com","avatar":"https://avatars.githubusercontent.com/u/874719?v=4"},"body":"From: Jacob Keller <jacob.keller@gmail.com>\n\nAdd new option \"notes.<ref>.mergestrategy\" option which specifies the merge\nstrategy for merging into a given notes ref. This option enables\nselection of merge strategy for particular notes refs, rather than all\nnotes ref merges, as user may not want cat_sort_uniq for all refs, but\nonly some. Note that the <ref> is the local reference we are merging\ninto, not the remote ref we merged from. The assumption is that users\nwill mostly want to configure separate local ref merge strategies rather\nthan strategies depending on which remote ref they merge from. Also,\nnotes.<ref>.merge overrides the general behavior as it is more specific.\n\nSigned-off-by: Jacob Keller <jacob.keller@gmail.com>\n---\n Documentation/config.txt            |  7 +++++++\n Documentation/git-notes.txt         |  6 ++++++\n builtin/notes.c                     | 13 ++++++++++---\n t/t3309-notes-merge-auto-resolve.sh | 39 +++++++++++++++++++++++++++++++++++++\n 4 files changed, 62 insertions(+), 3 deletions(-)\n\ndiff --git a/Documentation/config.txt b/Documentation/config.txt\nindex 5e3e03459de7..47478311367e 100644\n--- a/Documentation/config.txt\n+++ b/Documentation/config.txt\n@@ -1926,6 +1926,13 @@ notes.mergestrategy::\n \tSTRATEGIES\" section of linkgit:git-notes[1] for more information\n \ton each strategy.\n \n+notes.<localref>.mergestrategy::\n+\tWhich merge strategy to choose if the local ref for a notes merge\n+\tmatches <localref>, overriding \"notes.mergestrategy\". <localref> must\n+\tbe the short name of a ref under refs/notes/. See \"NOTES MERGE\n+\tSTRATEGIES\" section in linkgit:git-notes[1] for more information on the\n+\tavailable strategies.\n+\n notes.displayRef::\n \tThe (fully qualified) refname from which to show notes when\n \tshowing commit messages.  The value of this variable can be set\ndiff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt\nindex 89c8829a0543..b99809fc81a6 100644\n--- a/Documentation/git-notes.txt\n+++ b/Documentation/git-notes.txt\n@@ -322,6 +322,12 @@ notes.mergestrategy::\n +\n This setting can be overridden by passing the `--strategy` option.\n \n+notes.<localref>.mergestrategy::\n+\tWhich strategy to choose when merging into <localref>. The set of\n+\tallowed values is the same as \"notes.mergestrategy\". <localref> must be\n+\tthe short name of a ref under refs/notes/. See \"NOTES MERGE STRATEGIES\"\n+\tsection above for more information about each strategy.\n+\n notes.displayRef::\n \tWhich ref (or refs, if a glob or specified more than once), in\n \taddition to the default set by `core.notesRef` or\ndiff --git a/builtin/notes.c b/builtin/notes.c\nindex 97109f8d419c..00c9ae402bab 100644\n--- a/builtin/notes.c\n+++ b/builtin/notes.c\n@@ -758,13 +758,13 @@ static int parse_notes_strategy(const char *arg, enum notes_merge_strategy *stra\n \n static int merge(int argc, const char **argv, const char *prefix)\n {\n-\tstruct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;\n+\tstruct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT, merge_key = STRBUF_INIT;\n \tunsigned char result_sha1[20];\n \tstruct notes_tree *t;\n \tstruct notes_merge_options o;\n \tint do_merge = 0, do_commit = 0, do_abort = 0;\n \tint verbosity = 0, result;\n-\tconst char *strategy = NULL, *configured_strategy = NULL;\n+\tconst char *strategy = NULL, *configured_strategy = NULL, *short_ref = NULL;\n \tstruct option options[] = {\n \t\tOPT_GROUP(N_(\"General options\")),\n \t\tOPT__VERBOSITY(&verbosity),\n@@ -814,7 +814,14 @@ static int merge(int argc, const char **argv, const char *prefix)\n \texpand_notes_ref(&remote_ref);\n \to.remote_ref = remote_ref.buf;\n \n-\tgit_config_get_string_const(\"notes.mergestrategy\", &configured_strategy);\n+\tif (!skip_prefix(o.local_ref, \"refs/notes/\", &short_ref))\n+\t\tdie(\"Refusing to merge notes into %s (outside of refs/notes/)\",\n+\t\t    o.local_ref);\n+\n+\tstrbuf_addf(&merge_key, \"notes.%s.mergestrategy\", short_ref);\n+\n+\tif (git_config_get_string_const(merge_key.buf, &configured_strategy))\n+\t\tgit_config_get_string_const(\"notes.mergestrategy\", &configured_strategy);\n \n \tif (strategy) {\n \t\tif (parse_notes_strategy(strategy, &o.strategy)) {\ndiff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh\nindex 476b9f5306f1..560e75259798 100755\n--- a/t/t3309-notes-merge-auto-resolve.sh\n+++ b/t/t3309-notes-merge-auto-resolve.sh\n@@ -383,6 +383,17 @@ test_expect_success 'reset to pre-merge state (y)' '\n \tverify_notes y y\n '\n \n+test_expect_success 'merge z into y with \"ours\" per-ref configuration option => Non-conflicting 3-way merge' '\n+\tgit -c notes.y.mergestrategy=\"ours\" notes merge z &&\n+\tverify_notes y ours\n+'\n+\n+test_expect_success 'reset to pre-merge state (y)' '\n+\tgit update-ref refs/notes/y refs/notes/y^1 &&\n+\t# Verify pre-merge state\n+\tverify_notes y y\n+'\n+\n cat <<EOF | sort >expect_notes_theirs\n 9b4b2c61f0615412da3c10f98ff85b57c04ec765 $commit_sha15\n 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14\n@@ -534,6 +545,34 @@ test_expect_success 'reset to pre-merge state (y)' '\n \tverify_notes y y\n '\n \n+test_expect_success 'merge z into y with \"union\" strategy overriding per-ref configuration => Non-conflicting 3-way merge' '\n+\tgit -c notes.y.mergestrategy=\"theirs\" notes merge --strategy=union z &&\n+\tverify_notes y union\n+'\n+\n+test_expect_success 'reset to pre-merge state (y)' '\n+\tgit update-ref refs/notes/y refs/notes/y^1 &&\n+\t# Verify pre-merge state\n+\tverify_notes y y\n+'\n+\n+test_expect_success 'merge z into y with \"union\" per-ref overriding general configuration => Non-conflicting 3-way merge' '\n+\tgit -c notes.y.mergestrategy=\"union\" -c notes.mergestrategy=\"theirs\" notes merge z &&\n+\tverify_notes y union\n+'\n+\n+test_expect_success 'reset to pre-merge state (y)' '\n+\tgit update-ref refs/notes/y refs/notes/y^1 &&\n+\t# Verify pre-merge state\n+\tverify_notes y y\n+'\n+\n+test_expect_success 'merge z into y with \"manual\" per-ref only checks specific ref configuration => Conflicting 3-way merge' '\n+\ttest_must_fail git -c notes.z.mergestrategy=\"union\" notes merge z &&\n+\tgit notes merge --abort &&\n+\tverify_notes y y\n+'\n+\n cat <<EOF | sort >expect_notes_union2\n d682107b8bf7a7aea1e537a8d5cb6a12b60135f1 $commit_sha15\n 5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14\n-- \n2.5.0.280.g4aaba03\n"},{"id":"268056","messageId":"CAPig+cQN9bszBiW4dxp8cz+aJUf=70V-vLQio_6OX9ry1cOYRw@mail.gmail.com","threadId":"40087","inReplyTo":"1439574620-25249-4-git-send-email-jacob.e.keller@intel.com","subject":"Re: [PATCH v5 3/4] notes: add notes.mergestrategy option to select default strategy","fromName":"Eric Sunshine","fromEmail":"sunshine@sunshineco.com","sentAt":"2015-08-14T18:07:03Z","receivedAt":"2015-08-14T18:07:03Z","isPatch":true,"sender":{"key":"sunshine@sunshineco.com","avatar":"https://avatars.githubusercontent.com/u/163641?v=4"},"body":"On Fri, Aug 14, 2015 at 1:50 PM, Jacob Keller <jacob.e.keller@intel.com> wrote:\n> Teach git-notes about \"notes.mergestrategy\" to select a general strategy\n> for all notes merges. This enables a user to always get expected merge\n> strategy such as \"cat_sort_uniq\" without having to pass the \"-s\" option\n> manually.\n>\n> Signed-off-by: Jacob Keller <jacob.keller@gmail.com>\n> ---\n> diff --git a/builtin/notes.c b/builtin/notes.c\n> index 042348082709..97109f8d419c 100644\n> --- a/builtin/notes.c\n> +++ b/builtin/notes.c\n> @@ -796,21 +814,16 @@ static int merge(int argc, const char **argv, const char *prefix)\n>         expand_notes_ref(&remote_ref);\n>         o.remote_ref = remote_ref.buf;\n>\n> +       git_config_get_string_const(\"notes.mergestrategy\", &configured_strategy);\n> +\n>         if (strategy) {\n> -               if (!strcmp(strategy, \"manual\"))\n> -                       o.strategy = NOTES_MERGE_RESOLVE_MANUAL;\n> -               else if (!strcmp(strategy, \"ours\"))\n> -                       o.strategy = NOTES_MERGE_RESOLVE_OURS;\n> -               else if (!strcmp(strategy, \"theirs\"))\n> -                       o.strategy = NOTES_MERGE_RESOLVE_THEIRS;\n> -               else if (!strcmp(strategy, \"union\"))\n> -                       o.strategy = NOTES_MERGE_RESOLVE_UNION;\n> -               else if (!strcmp(strategy, \"cat_sort_uniq\"))\n> -                       o.strategy = NOTES_MERGE_RESOLVE_CAT_SORT_UNIQ;\n> -               else {\n> +               if (parse_notes_strategy(strategy, &o.strategy)) {\n>                         error(\"Unknown -s/--strategy: %s\", strategy);\n\nThis error message points the user at the source of the problem\n(\"--strategy\"). Good.\n\n>                         usage_with_options(git_notes_merge_usage, options);\n>                 }\n> +       } else if (configured_strategy) {\n> +               if (parse_notes_strategy(configured_strategy, &o.strategy))\n> +                       die(\"Unknown notes merge strategy: %s\", configured_strategy);\n\nThis error message doesn't. Perhaps it should mention the config\nvariable \"notes.mergestrategy\" to help the user track down the problem\nmore quickly?\n\n>         }\n>\n>         t = init_notes_check(\"merge\");\n"}]}