Skip to content

Commit 4ef88fc

Browse files
newrengitster
authored andcommitted
merge-ort: add handling for different types of files at same path
Add some handling that explicitly considers collisions of the following types: * file/submodule * file/symlink * submodule/symlink Leaving them as conflicts at the same path are hard for users to resolve, so move one or both of them aside so that they each get their own path. Note that in the case of recursive handling (i.e. call_depth > 0), we can just use the merge base of the two merge bases as the merge result much like we do with modify/delete conflicts, binary files, conflicting submodule values, and so on. Signed-off-by: Elijah Newren <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 4204cd5 commit 4ef88fc

File tree

1 file changed

+103
-4
lines changed

1 file changed

+103
-4
lines changed

merge-ort.c

Lines changed: 103 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1521,10 +1521,109 @@ static void process_entry(struct merge_options *opt,
15211521
} else if (ci->filemask >= 6 &&
15221522
(S_IFMT & ci->stages[1].mode) !=
15231523
(S_IFMT & ci->stages[2].mode)) {
1524-
/*
1525-
* Two different items from (file/submodule/symlink)
1526-
*/
1527-
die("Not yet implemented.");
1524+
/* Two different items from (file/submodule/symlink) */
1525+
if (opt->priv->call_depth) {
1526+
/* Just use the version from the merge base */
1527+
ci->merged.clean = 0;
1528+
oidcpy(&ci->merged.result.oid, &ci->stages[0].oid);
1529+
ci->merged.result.mode = ci->stages[0].mode;
1530+
ci->merged.is_null = (ci->merged.result.mode == 0);
1531+
} else {
1532+
/* Handle by renaming one or both to separate paths. */
1533+
unsigned o_mode = ci->stages[0].mode;
1534+
unsigned a_mode = ci->stages[1].mode;
1535+
unsigned b_mode = ci->stages[2].mode;
1536+
struct conflict_info *new_ci;
1537+
const char *a_path = NULL, *b_path = NULL;
1538+
int rename_a = 0, rename_b = 0;
1539+
1540+
new_ci = xmalloc(sizeof(*new_ci));
1541+
1542+
if (S_ISREG(a_mode))
1543+
rename_a = 1;
1544+
else if (S_ISREG(b_mode))
1545+
rename_b = 1;
1546+
else {
1547+
rename_a = 1;
1548+
rename_b = 1;
1549+
}
1550+
1551+
path_msg(opt, path, 0,
1552+
_("CONFLICT (distinct types): %s had different "
1553+
"types on each side; renamed %s of them so "
1554+
"each can be recorded somewhere."),
1555+
path,
1556+
(rename_a && rename_b) ? _("both") : _("one"));
1557+
1558+
ci->merged.clean = 0;
1559+
memcpy(new_ci, ci, sizeof(*new_ci));
1560+
1561+
/* Put b into new_ci, removing a from stages */
1562+
new_ci->merged.result.mode = ci->stages[2].mode;
1563+
oidcpy(&new_ci->merged.result.oid, &ci->stages[2].oid);
1564+
new_ci->stages[1].mode = 0;
1565+
oidcpy(&new_ci->stages[1].oid, &null_oid);
1566+
new_ci->filemask = 5;
1567+
if ((S_IFMT & b_mode) != (S_IFMT & o_mode)) {
1568+
new_ci->stages[0].mode = 0;
1569+
oidcpy(&new_ci->stages[0].oid, &null_oid);
1570+
new_ci->filemask = 4;
1571+
}
1572+
1573+
/* Leave only a in ci, fixing stages. */
1574+
ci->merged.result.mode = ci->stages[1].mode;
1575+
oidcpy(&ci->merged.result.oid, &ci->stages[1].oid);
1576+
ci->stages[2].mode = 0;
1577+
oidcpy(&ci->stages[2].oid, &null_oid);
1578+
ci->filemask = 3;
1579+
if ((S_IFMT & a_mode) != (S_IFMT & o_mode)) {
1580+
ci->stages[0].mode = 0;
1581+
oidcpy(&ci->stages[0].oid, &null_oid);
1582+
ci->filemask = 2;
1583+
}
1584+
1585+
/* Insert entries into opt->priv_paths */
1586+
assert(rename_a || rename_b);
1587+
if (rename_a) {
1588+
a_path = unique_path(&opt->priv->paths,
1589+
path, opt->branch1);
1590+
strmap_put(&opt->priv->paths, a_path, ci);
1591+
}
1592+
1593+
if (rename_b)
1594+
b_path = unique_path(&opt->priv->paths,
1595+
path, opt->branch2);
1596+
else
1597+
b_path = path;
1598+
strmap_put(&opt->priv->paths, b_path, new_ci);
1599+
1600+
if (rename_a && rename_b) {
1601+
strmap_remove(&opt->priv->paths, path, 0);
1602+
/*
1603+
* We removed path from opt->priv->paths. path
1604+
* will also eventually need to be freed, but
1605+
* it may still be used by e.g. ci->pathnames.
1606+
* So, store it in another string-list for now.
1607+
*/
1608+
string_list_append(&opt->priv->paths_to_free,
1609+
path);
1610+
}
1611+
1612+
/*
1613+
* Do special handling for b_path since process_entry()
1614+
* won't be called on it specially.
1615+
*/
1616+
strmap_put(&opt->priv->conflicted, b_path, new_ci);
1617+
record_entry_for_tree(dir_metadata, b_path,
1618+
&new_ci->merged);
1619+
1620+
/*
1621+
* Remaining code for processing this entry should
1622+
* think in terms of processing a_path.
1623+
*/
1624+
if (a_path)
1625+
path = a_path;
1626+
}
15281627
} else if (ci->filemask >= 6) {
15291628
/* Need a two-way or three-way content merge */
15301629
struct version_info merged_file;

0 commit comments

Comments
 (0)