merge-ort: flesh out implementation of handle_content_merge()
This implementation is based heavily on merge_mode_and_contents() from merge-recursive.c, though it has some fixes for recursive merges (i.e. when call_depth > 0), and has a number of changes throughout based on slight differences in data structures and in how the functions are called. It is, however, based on two new helper functions -- merge_3way() and merge_submodule -- for which we only provide die-not-implemented stubs at this point. Future commits will add implementations of these functions. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
parent
991bbdcab9
commit
62fdec17a1
149
merge-ort.c
149
merge-ort.c
@ -631,6 +631,28 @@ static int collect_merge_info(struct merge_options *opt,
|
|||||||
|
|
||||||
/*** Function Grouping: functions related to threeway content merges ***/
|
/*** Function Grouping: functions related to threeway content merges ***/
|
||||||
|
|
||||||
|
static int merge_submodule(struct merge_options *opt,
|
||||||
|
const char *path,
|
||||||
|
const struct object_id *o,
|
||||||
|
const struct object_id *a,
|
||||||
|
const struct object_id *b,
|
||||||
|
struct object_id *result)
|
||||||
|
{
|
||||||
|
die("Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
|
static int merge_3way(struct merge_options *opt,
|
||||||
|
const char *path,
|
||||||
|
const struct object_id *o,
|
||||||
|
const struct object_id *a,
|
||||||
|
const struct object_id *b,
|
||||||
|
const char *pathnames[3],
|
||||||
|
const int extra_marker_size,
|
||||||
|
mmbuffer_t *result_buf)
|
||||||
|
{
|
||||||
|
die("Not yet implemented.");
|
||||||
|
}
|
||||||
|
|
||||||
static int handle_content_merge(struct merge_options *opt,
|
static int handle_content_merge(struct merge_options *opt,
|
||||||
const char *path,
|
const char *path,
|
||||||
const struct version_info *o,
|
const struct version_info *o,
|
||||||
@ -640,14 +662,129 @@ static int handle_content_merge(struct merge_options *opt,
|
|||||||
const int extra_marker_size,
|
const int extra_marker_size,
|
||||||
struct version_info *result)
|
struct version_info *result)
|
||||||
{
|
{
|
||||||
int clean = 0;
|
|
||||||
/*
|
/*
|
||||||
* TODO: Needs a two-way or three-way content merge, but we're
|
* path is the target location where we want to put the file, and
|
||||||
* just being lazy and copying the version from HEAD and
|
* is used to determine any normalization rules in ll_merge.
|
||||||
* leaving it as conflicted.
|
*
|
||||||
|
* The normal case is that path and all entries in pathnames are
|
||||||
|
* identical, though renames can affect which path we got one of
|
||||||
|
* the three blobs to merge on various sides of history.
|
||||||
|
*
|
||||||
|
* extra_marker_size is the amount to extend conflict markers in
|
||||||
|
* ll_merge; this is neeed if we have content merges of content
|
||||||
|
* merges, which happens for example with rename/rename(2to1) and
|
||||||
|
* rename/add conflicts.
|
||||||
*/
|
*/
|
||||||
result->mode = a->mode;
|
unsigned clean = 1;
|
||||||
oidcpy(&result->oid, &a->oid);
|
|
||||||
|
/*
|
||||||
|
* handle_content_merge() needs both files to be of the same type, i.e.
|
||||||
|
* both files OR both submodules OR both symlinks. Conflicting types
|
||||||
|
* needs to be handled elsewhere.
|
||||||
|
*/
|
||||||
|
assert((S_IFMT & a->mode) == (S_IFMT & b->mode));
|
||||||
|
|
||||||
|
/* Merge modes */
|
||||||
|
if (a->mode == b->mode || a->mode == o->mode)
|
||||||
|
result->mode = b->mode;
|
||||||
|
else {
|
||||||
|
/* must be the 100644/100755 case */
|
||||||
|
assert(S_ISREG(a->mode));
|
||||||
|
result->mode = a->mode;
|
||||||
|
clean = (b->mode == o->mode);
|
||||||
|
/*
|
||||||
|
* FIXME: If opt->priv->call_depth && !clean, then we really
|
||||||
|
* should not make result->mode match either a->mode or
|
||||||
|
* b->mode; that causes t6036 "check conflicting mode for
|
||||||
|
* regular file" to fail. It would be best to use some other
|
||||||
|
* mode, but we'll confuse all kinds of stuff if we use one
|
||||||
|
* where S_ISREG(result->mode) isn't true, and if we use
|
||||||
|
* something like 0100666, then tree-walk.c's calls to
|
||||||
|
* canon_mode() will just normalize that to 100644 for us and
|
||||||
|
* thus not solve anything.
|
||||||
|
*
|
||||||
|
* Figure out if there's some kind of way we can work around
|
||||||
|
* this...
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Trivial oid merge.
|
||||||
|
*
|
||||||
|
* Note: While one might assume that the next four lines would
|
||||||
|
* be unnecessary due to the fact that match_mask is often
|
||||||
|
* setup and already handled, renames don't always take care
|
||||||
|
* of that.
|
||||||
|
*/
|
||||||
|
if (oideq(&a->oid, &b->oid) || oideq(&a->oid, &o->oid))
|
||||||
|
oidcpy(&result->oid, &b->oid);
|
||||||
|
else if (oideq(&b->oid, &o->oid))
|
||||||
|
oidcpy(&result->oid, &a->oid);
|
||||||
|
|
||||||
|
/* Remaining rules depend on file vs. submodule vs. symlink. */
|
||||||
|
else if (S_ISREG(a->mode)) {
|
||||||
|
mmbuffer_t result_buf;
|
||||||
|
int ret = 0, merge_status;
|
||||||
|
int two_way;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* If 'o' is different type, treat it as null so we do a
|
||||||
|
* two-way merge.
|
||||||
|
*/
|
||||||
|
two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));
|
||||||
|
|
||||||
|
merge_status = merge_3way(opt, path,
|
||||||
|
two_way ? &null_oid : &o->oid,
|
||||||
|
&a->oid, &b->oid,
|
||||||
|
pathnames, extra_marker_size,
|
||||||
|
&result_buf);
|
||||||
|
|
||||||
|
if ((merge_status < 0) || !result_buf.ptr)
|
||||||
|
ret = err(opt, _("Failed to execute internal merge"));
|
||||||
|
|
||||||
|
if (!ret &&
|
||||||
|
write_object_file(result_buf.ptr, result_buf.size,
|
||||||
|
blob_type, &result->oid))
|
||||||
|
ret = err(opt, _("Unable to add %s to database"),
|
||||||
|
path);
|
||||||
|
|
||||||
|
free(result_buf.ptr);
|
||||||
|
if (ret)
|
||||||
|
return -1;
|
||||||
|
clean &= (merge_status == 0);
|
||||||
|
path_msg(opt, path, 1, _("Auto-merging %s"), path);
|
||||||
|
} else if (S_ISGITLINK(a->mode)) {
|
||||||
|
int two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));
|
||||||
|
clean = merge_submodule(opt, pathnames[0],
|
||||||
|
two_way ? &null_oid : &o->oid,
|
||||||
|
&a->oid, &b->oid, &result->oid);
|
||||||
|
if (opt->priv->call_depth && two_way && !clean) {
|
||||||
|
result->mode = o->mode;
|
||||||
|
oidcpy(&result->oid, &o->oid);
|
||||||
|
}
|
||||||
|
} else if (S_ISLNK(a->mode)) {
|
||||||
|
if (opt->priv->call_depth) {
|
||||||
|
clean = 0;
|
||||||
|
result->mode = o->mode;
|
||||||
|
oidcpy(&result->oid, &o->oid);
|
||||||
|
} else {
|
||||||
|
switch (opt->recursive_variant) {
|
||||||
|
case MERGE_VARIANT_NORMAL:
|
||||||
|
clean = 0;
|
||||||
|
oidcpy(&result->oid, &a->oid);
|
||||||
|
break;
|
||||||
|
case MERGE_VARIANT_OURS:
|
||||||
|
oidcpy(&result->oid, &a->oid);
|
||||||
|
break;
|
||||||
|
case MERGE_VARIANT_THEIRS:
|
||||||
|
oidcpy(&result->oid, &b->oid);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
BUG("unsupported object type in the tree: %06o for %s",
|
||||||
|
a->mode, path);
|
||||||
|
|
||||||
return clean;
|
return clean;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user