From: Jacob Keller <jacob.e.keller@intel.com>
To: git@vger.kernel.org
Cc: Jacob Keller <jacob.keller@gmail.com>,
Johan Herland <johan@herland.net>,
Michael Haggerty <mhagger@alum.mit.edu>,
Eric Sunshine <sunshine@sunshineco.com>
Subject: [PATCH RFC 4/4] notes: add per-ref configuration of merge strategy
Date: Sun, 2 Aug 2015 03:10:26 -0700 [thread overview]
Message-ID: <1438510226-1163-5-git-send-email-jacob.e.keller@intel.com> (raw)
In-Reply-To: <1438510226-1163-1-git-send-email-jacob.e.keller@intel.com>
From: Jacob Keller <jacob.keller@gmail.com>
Teach git-notes about a new configuration option
"notes.<localref>.merge" which selects the merge strategy for a
particular ref. This allows selection of merge strategy different for
each note reference, in addition to the default strategy for all
references.
Signed-off-by: Jacob Keller <jacob.keller@gmail.com>
Cc: Johan Herland <johan@herland.net>
Cc: Michael Haggerty <mhagger@alum.mit.edu>
Cc: Eric Sunshine <sunshine@sunshineco.com>
---
Documentation/config.txt | 7 +++
Documentation/git-notes.txt | 6 ++
builtin/notes.c | 115 +++++++++++++++++++++++++++++++++++-
t/t3309-notes-merge-auto-resolve.sh | 50 ++++++++++++++++
4 files changed, 176 insertions(+), 2 deletions(-)
diff --git a/Documentation/config.txt b/Documentation/config.txt
index 0fa88a29dd65..c53ec4538cd3 100644
--- a/Documentation/config.txt
+++ b/Documentation/config.txt
@@ -1918,6 +1918,13 @@ notes.merge::
STRATEGIES" section of linkgit:git-notes[1] for more information
on each strategy.
+notes.<localref>.merge::
+ Which merge strategy to choose if the local ref for a notes merge
+ matches <localref>. Is overridden by notes.merge and takes the same
+ values. <localref> may be fully qualified or just under refs/notes/.
+ See "NOTES MERGE STRATEGIES" section in linkgit:git-notes[1] for more
+ information on each strategy.
+
notes.displayRef::
The (fully qualified) refname from which to show notes when
showing commit messages. The value of this variable can be set
diff --git a/Documentation/git-notes.txt b/Documentation/git-notes.txt
index 9c4f8536182f..1e001807f9d9 100644
--- a/Documentation/git-notes.txt
+++ b/Documentation/git-notes.txt
@@ -322,6 +322,12 @@ notes.merge::
+
This setting can be overridden by passing the `--strategy` option.
+notes.<localref>.merge::
+ Which strategy to choose when merging into <localref>. Uses the same
+ values as notes.merge. <localref> may be either a fully qualified ref
+ or the shortname under "refs/notes/". See "NOTES MERGE STRATEGIES"
+ section above for more information about each strategy.
+
notes.displayRef::
Which ref (or refs, if a glob or specified more than once), in
addition to the default set by `core.notesRef` or
diff --git a/builtin/notes.c b/builtin/notes.c
index de0caa00df1b..b0174d1024dc 100644
--- a/builtin/notes.c
+++ b/builtin/notes.c
@@ -92,6 +92,10 @@ static const char * const git_notes_get_ref_usage[] = {
static const char note_template[] =
"\nWrite/edit the notes for the following object:\n";
+static struct note_ref **note_refs;
+static int note_refs_alloc;
+static int note_refs_nr;
+static struct hashmap note_refs_hash;
static enum notes_merge_strategy merge_strategy;
struct note_data {
@@ -757,12 +761,87 @@ static int parse_notes_strategy(const char *arg, enum notes_merge_strategy *stra
return 0;
}
+struct note_refs_hash_key {
+ const char *str;
+ int len;
+};
+
+struct note_ref {
+ struct hashmap_entry ent; /* must be first */
+
+ const char *name;
+ enum notes_merge_strategy merge_strategy;
+};
+
+static int note_refs_hash_cmp(const struct note_ref *a, const struct note_ref *b, const struct note_refs_hash_key *key)
+{
+ if (key)
+ return strncmp(a->name, key->str, key->len) || a->name[key->len];
+ else
+ return strcmp(a->name, b->name);
+}
+
+static inline void init_note_refs_hash(void)
+{
+ if (!note_refs_hash.cmpfn)
+ hashmap_init(¬e_refs_hash, (hashmap_cmp_fn)note_refs_hash_cmp, 0);
+}
+
+static struct note_ref *make_note_ref(const char *name, int len)
+{
+ struct note_ref *ret, *replaced;
+ struct note_refs_hash_key lookup;
+ struct hashmap_entry lookup_entry;
+
+ if (!len)
+ len = strlen(name);
+
+ init_note_refs_hash();
+ lookup.str = name;
+ lookup.len = len;
+ hashmap_entry_init(&lookup_entry, memhash(name, len));
+
+ if ((ret = hashmap_get(¬e_refs_hash, &lookup_entry, &lookup)) != NULL)
+ return ret;
+
+ ret = xcalloc(1, sizeof(struct note_ref));
+ ALLOC_GROW(note_refs, note_refs_nr + 1, note_refs_alloc);
+ note_refs[note_refs_nr++] = ret;
+ ret->name = xstrndup(name, len);
+
+ hashmap_entry_init(ret, lookup_entry.hash);
+ replaced = hashmap_put(¬e_refs_hash, ret);
+ assert(replaced == NULL); /* no previous entry overwritten */
+ return ret;
+}
+
+static void set_strategy_for_ref(const char *ref)
+{
+ const char *name = ref;
+ struct note_refs_hash_key lookup;
+ struct hashmap_entry lookup_entry;
+ struct note_ref *note;
+
+ skip_prefix(ref, "refs/notes/", &name);
+
+ init_note_refs_hash();
+ lookup.str = name;
+ lookup.len = strlen(name);
+
+ hashmap_entry_init(&lookup_entry, memhash(name, lookup.len));
+
+ note = hashmap_get(¬e_refs_hash, &lookup_entry, &lookup);
+ if (note != NULL)
+ merge_strategy = note->merge_strategy;
+}
+
static int merge(int argc, const char **argv, const char *prefix)
{
struct strbuf remote_ref = STRBUF_INIT, msg = STRBUF_INIT;
unsigned char result_sha1[20];
struct notes_tree *t;
struct notes_merge_options o;
+ struct note_ref;
int do_merge = 0, do_commit = 0, do_abort = 0;
int verbosity = 0, result;
const char *strategy = NULL;
@@ -815,6 +894,8 @@ static int merge(int argc, const char **argv, const char *prefix)
expand_notes_ref(&remote_ref);
o.remote_ref = remote_ref.buf;
+ set_strategy_for_ref(o.local_ref);
+
if (strategy && parse_notes_strategy(strategy, &merge_strategy)) {
error("Unknown -s/--strategy: %s", strategy);
usage_with_options(git_notes_merge_usage, options);
@@ -957,7 +1038,16 @@ static int get_ref(int argc, const char **argv, const char *prefix)
static int git_notes_config(const char *var, const char *value, void *cb)
{
- if (!strcmp(var, "notes.merge")) {
+ const char *ref;
+ const char *subkey;
+ struct note_ref *note;
+
+ if (!starts_with(var, "notes."))
+ return git_default_config(var, value, cb);
+ ref = var + 6;
+
+ /* Handle notes.* variables */
+ if (!strcmp(ref, "merge")) {
if (!value)
return config_error_nonbool(var);
if (parse_notes_strategy(value, &merge_strategy))
@@ -966,7 +1056,28 @@ static int git_notes_config(const char *var, const char *value, void *cb)
return 0;
}
- return git_default_config(var, value, cb);
+ if (*ref == '/') {
+ warning("Config notes ref cannot begin with '/': %s", ref);
+ return 0;
+ }
+ subkey = strrchr(ref, '.');
+ if (!subkey)
+ return 0;
+
+ /* skip refs/notes prefix if provided */
+ skip_prefix(ref, "refs/notes/", &ref);
+
+ note = make_note_ref(ref, subkey - ref);
+ if (!strcmp(subkey, ".merge")) {
+ if (!value)
+ return config_error_nonbool(var);
+ if (parse_notes_strategy(value, ¬e->merge_strategy))
+ return error("Unknown notes merge strategy: %s", value);
+ else
+ return 0;
+ }
+
+ return 0;
}
int cmd_notes(int argc, const char **argv, const char *prefix)
diff --git a/t/t3309-notes-merge-auto-resolve.sh b/t/t3309-notes-merge-auto-resolve.sh
index a773b01b73db..15dd539cd141 100755
--- a/t/t3309-notes-merge-auto-resolve.sh
+++ b/t/t3309-notes-merge-auto-resolve.sh
@@ -383,6 +383,28 @@ test_expect_success 'reset to pre-merge state (y)' '
verify_notes y y
'
+test_expect_success 'merge z into y with "ours" per-ref configuration option => Non-conflicting 3-way merge' '
+ git -c notes.y.merge="ours" notes merge z &&
+ verify_notes y ours
+'
+
+test_expect_success 'reset to pre-merge state (y)' '
+ git update-ref refs/notes/y refs/notes/y^1 &&
+ # Verify pre-merge state
+ verify_notes y y
+'
+
+test_expect_success 'merge z into y with "ours" per-ref configuration option prefixed with "refs/notes" => Non-conflicting 3-way merge' '
+ git -c notes.refs/notes/y.merge="ours" notes merge z &&
+ verify_notes y ours
+'
+
+test_expect_success 'reset to pre-merge state (y)' '
+ git update-ref refs/notes/y refs/notes/y^1 &&
+ # Verify pre-merge state
+ verify_notes y y
+'
+
cat <<EOF | sort >expect_notes_theirs
9b4b2c61f0615412da3c10f98ff85b57c04ec765 $commit_sha15
5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14
@@ -534,6 +556,34 @@ test_expect_success 'reset to pre-merge state (y)' '
verify_notes y y
'
+test_expect_success 'merge z into y with "union" strategy overriding per-ref configuration => Non-conflicting 3-way merge' '
+ git -c notes.refs/notes/y.merge="theirs" notes merge --strategy=union z &&
+ verify_notes y union
+'
+
+test_expect_success 'reset to pre-merge state (y)' '
+ git update-ref refs/notes/y refs/notes/y^1 &&
+ # Verify pre-merge state
+ verify_notes y y
+'
+
+test_expect_success 'merge z into y with "union" per-ref overriding general configuration => Non-conflicting 3-way merge' '
+ git -c notes.refs/notes/y.merge="union" -c notes.merge="theirs" notes merge z &&
+ verify_notes y union
+'
+
+test_expect_success 'reset to pre-merge state (y)' '
+ git update-ref refs/notes/y refs/notes/y^1 &&
+ # Verify pre-merge state
+ verify_notes y y
+'
+
+test_expect_success 'merge z into y with "manual" per-ref only checks specific ref configuration => Conflicting 3-way merge' '
+ test_must_fail git -c notes.refs/notes/z.merge="union" notes merge z &&
+ git notes merge --abort &&
+ verify_notes y y
+'
+
cat <<EOF | sort >expect_notes_union2
d682107b8bf7a7aea1e537a8d5cb6a12b60135f1 $commit_sha15
5de7ea7ad4f47e7ff91989fb82234634730f75df $commit_sha14
--
2.5.0.482.gfcd5645
next prev parent reply other threads:[~2015-08-02 10:10 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-08-02 10:10 [PATCH v3 0/4] notes: add support for notes.merge option Jacob Keller
2015-08-02 10:10 ` [PATCH v3 1/4] notes: document cat_sort_uniq rewriteMode Jacob Keller
2015-08-02 10:10 ` [PATCH v3 2/4] notes: add tests for --commit/--abort/--strategy exclusivity Jacob Keller
2015-08-02 10:10 ` [PATCH v3 3/4] notes: add notes.merge option to select default strategy Jacob Keller
2015-08-05 20:47 ` Junio C Hamano
2015-08-06 22:37 ` Eric Sunshine
2015-08-02 10:10 ` Jacob Keller [this message]
2015-08-05 21:10 ` [PATCH RFC 4/4] notes: add per-ref configuration of merge strategy Junio C Hamano
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=1438510226-1163-5-git-send-email-jacob.e.keller@intel.com \
--to=jacob.e.keller@intel.com \
--cc=git@vger.kernel.org \
--cc=jacob.keller@gmail.com \
--cc=johan@herland.net \
--cc=mhagger@alum.mit.edu \
--cc=sunshine@sunshineco.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).