Skip to content
/ git Public
forked from git/git

Commit

Permalink
git notes merge: Add automatic conflict resolvers (ours, theirs, union)
Browse files Browse the repository at this point in the history
The new -s/--strategy command-line option to 'git notes merge' allow the user
to choose how notes merge conflicts should be resolved. There are four valid
strategies to choose from:

1. "manual" (the default): This will let the user manually resolve conflicts.
   This option currently fails with an error message. It will be implemented
   properly in future patches.

2. "ours": This automatically chooses the local version of a conflict, and
   discards the remote version.

3. "theirs": This automatically chooses the remote version of a conflict, and
   discards the local version.

4. "union": This automatically resolves the conflict by appending the remote
   version to the local version.

The strategies are implemented using the combine_notes_* functions from the
notes.h API.

The patch also includes testcases verifying the correct implementation of
these strategies.

This patch has been improved by the following contributions:
- Jonathan Nieder: Future-proof by always checking add_note() return value
- Stephen Boyd: Use test_commit
- Stephen Boyd: Use correct option name

Thanks-to: Jonathan Nieder <jrnieder@gmail.com>
Thanks-to: Stephen Boyd <bebarino@gmail.com>
Signed-off-by: Johan Herland <johan@herland.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
  • Loading branch information
jherland authored and gitster committed Nov 17, 2010
1 parent 2085b16 commit 3228e67
Show file tree
Hide file tree
Showing 4 changed files with 559 additions and 2 deletions.
21 changes: 20 additions & 1 deletion builtin/notes.c
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,7 @@ static const char * const git_notes_usage[] = {
"git notes [--ref <notes_ref>] append [-m <msg> | -F <file> | (-c | -C) <object>] [<object>]",
"git notes [--ref <notes_ref>] edit [<object>]",
"git notes [--ref <notes_ref>] show [<object>]",
"git notes [--ref <notes_ref>] merge [-v | -q] <notes_ref>",
"git notes [--ref <notes_ref>] merge [-v | -q] [-s <strategy> ] <notes_ref>",
"git notes [--ref <notes_ref>] remove [<object>]",
"git notes [--ref <notes_ref>] prune [-n | -v]",
NULL
Expand Down Expand Up @@ -768,8 +768,12 @@ static int merge(int argc, const char **argv, const char *prefix)
struct notes_tree *t;
struct notes_merge_options o;
int verbosity = 0, result;
const char *strategy = NULL;
struct option options[] = {
OPT__VERBOSITY(&verbosity),
OPT_STRING('s', "strategy", &strategy, "strategy",
"resolve notes conflicts using the given "
"strategy (manual/ours/theirs/union)"),
OPT_END()
};

Expand All @@ -789,6 +793,21 @@ static int merge(int argc, const char **argv, const char *prefix)
expand_notes_ref(&remote_ref);
o.remote_ref = remote_ref.buf;

if (strategy) {
if (!strcmp(strategy, "manual"))
o.strategy = NOTES_MERGE_RESOLVE_MANUAL;
else if (!strcmp(strategy, "ours"))
o.strategy = NOTES_MERGE_RESOLVE_OURS;
else if (!strcmp(strategy, "theirs"))
o.strategy = NOTES_MERGE_RESOLVE_THEIRS;
else if (!strcmp(strategy, "union"))
o.strategy = NOTES_MERGE_RESOLVE_UNION;
else {
error("Unknown -s/--strategy: %s", strategy);
usage_with_options(git_notes_merge_usage, options);
}
}

t = init_notes_check("merge");

strbuf_addf(&msg, "notes: Merged notes from %s into %s",
Expand Down
32 changes: 31 additions & 1 deletion notes-merge.c
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,36 @@ static void diff_tree_local(struct notes_merge_options *o,
diff_tree_release_paths(&opt);
}

static int merge_one_change(struct notes_merge_options *o,
struct notes_merge_pair *p, struct notes_tree *t)
{
/*
* Return 0 if change was resolved (and added to notes_tree),
* 1 if conflict
*/
switch (o->strategy) {
case NOTES_MERGE_RESOLVE_MANUAL:
return 1;
case NOTES_MERGE_RESOLVE_OURS:
OUTPUT(o, 2, "Using local notes for %s", sha1_to_hex(p->obj));
/* nothing to do */
return 0;
case NOTES_MERGE_RESOLVE_THEIRS:
OUTPUT(o, 2, "Using remote notes for %s", sha1_to_hex(p->obj));
if (add_note(t, p->obj, p->remote, combine_notes_overwrite))
die("BUG: combine_notes_overwrite failed");
return 0;
case NOTES_MERGE_RESOLVE_UNION:
OUTPUT(o, 2, "Concatenating local and remote notes for %s",
sha1_to_hex(p->obj));
if (add_note(t, p->obj, p->remote, combine_notes_concatenate))
die("failed to concatenate notes "
"(combine_notes_concatenate)");
return 0;
}
die("Unknown strategy (%i).", o->strategy);
}

static int merge_changes(struct notes_merge_options *o,
struct notes_merge_pair *changes, int *num_changes,
struct notes_tree *t)
Expand Down Expand Up @@ -292,7 +322,7 @@ static int merge_changes(struct notes_merge_options *o,
} else {
/* need file-level merge between local and remote */
trace_printf("\t\t\tneed content-level merge\n");
conflicts += 1; /* TODO */
conflicts += merge_one_change(o, p, t);
}
}

Expand Down
6 changes: 6 additions & 0 deletions notes-merge.h
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,12 @@ struct notes_merge_options {
const char *remote_ref;
const char *commit_msg;
int verbosity;
enum {
NOTES_MERGE_RESOLVE_MANUAL = 0,
NOTES_MERGE_RESOLVE_OURS,
NOTES_MERGE_RESOLVE_THEIRS,
NOTES_MERGE_RESOLVE_UNION
} strategy;
};

void init_notes_merge_options(struct notes_merge_options *o);
Expand Down
Loading

0 comments on commit 3228e67

Please sign in to comment.