merge-recursive: switch from (oid,mode) pairs to a diff_filespec

There was a significant inconsistency in the various parts of the API used in merge-recursive; many places used a pair of (oid, mode) to track file version/contents, while other parts used a diff_filespec (which have an oid and mode embedded in it). This inconsistency caused lots of places to need to pack and unpack data to call into other functions. This has been the subject of some past cleanups (see e.g. commit 0270a07ad0b2 ("merge-recursive: remove final remaining caller of merge_file_one()", 2018-09-19)), but let's just remove the underlying mess altogether by switching to use diff_filespec. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Apr 5, 2019 at 08:00 UTC 8daec1df03de7db13d5d551a8b54f32fc6021132
1 file changed +215 -268
merge-recursive.c
+215 -268
@@ -201,10 +201,7 @@ enum rename_type {
201 * for these (temporary) data.
202 */
203 struct stage_data {
204 - struct {
205 - unsigned short mode;
206 - struct object_id oid;
207 - } stages[4];
204 + struct diff_filespec stages[4]; /* mostly for oid & mode; maybe path */
205 struct rename_conflict_info *rename_conflict_info;
206 unsigned processed:1;
207 };
@@ -269,7 +266,6 @@ static inline void setup_rename_conflict_info(enum rename_type rename_type,
266
267 ci->ren1->dst_entry->processed = 0;
268 ci->ren1->dst_entry->rename_conflict_info = ci;
272 -
269 if (ren2) {
270 ci->ren2->dst_entry->rename_conflict_info = ci;
271 }
@@ -326,14 +322,14 @@ static void output_commit_title(struct merge_options *opt, struct commit *commit
322 }
323
324 static int add_cacheinfo(struct merge_options *opt,
329 - unsigned int mode, const struct object_id *oid,
325 + const struct diff_filespec *blob,
326 const char *path, int stage, int refresh, int options)
327 {
328 struct index_state *istate = opt->repo->index;
329 struct cache_entry *ce;
330 int ret;
331
336 - ce = make_cache_entry(istate, mode, oid ? oid : &null_oid, path, stage, 0);
332 + ce = make_cache_entry(istate, blob->mode, &blob->oid, path, stage, 0);
333 if (!ce)
334 return err(opt, _("add_cacheinfo failed for path '%s'; merge aborting."), path);
335
@@ -464,15 +460,14 @@ static void get_files_dirs(struct merge_options *opt, struct tree *tree)
460
461 static int get_tree_entry_if_blob(const struct object_id *tree,
462 const char *path,
467 - struct object_id *hashy,
468 - unsigned short *mode_o)
463 + struct diff_filespec *dfs)
464 {
465 int ret;
466
472 - ret = get_tree_entry(tree, path, hashy, mode_o);
473 - if (S_ISDIR(*mode_o)) {
474 - oidcpy(hashy, &null_oid);
475 - *mode_o = 0;
467 + ret = get_tree_entry(tree, path, &dfs->oid, &dfs->mode);
468 + if (S_ISDIR(dfs->mode)) {
469 + oidcpy(&dfs->oid, &null_oid);
470 + dfs->mode = 0;
471 }
472 return ret;
473 }
@@ -487,12 +482,9 @@ static struct stage_data *insert_stage_data(const char *path,
482 {
483 struct string_list_item *item;
484 struct stage_data *e = xcalloc(1, sizeof(struct stage_data));
490 - get_tree_entry_if_blob(&o->object.oid, path,
491 - &e->stages[1].oid, &e->stages[1].mode);
492 - get_tree_entry_if_blob(&a->object.oid, path,
493 - &e->stages[2].oid, &e->stages[2].mode);
494 - get_tree_entry_if_blob(&b->object.oid, path,
495 - &e->stages[3].oid, &e->stages[3].mode);
485 + get_tree_entry_if_blob(&o->object.oid, path, &e->stages[1]);
486 + get_tree_entry_if_blob(&a->object.oid, path, &e->stages[2]);
487 + get_tree_entry_if_blob(&b->object.oid, path, &e->stages[3]);
488 item = string_list_insert(entries, path);
489 item->util = e;
490 return e;
@@ -648,13 +640,13 @@ static int update_stages(struct merge_options *opt, const char *path,
640 if (remove_file_from_index(opt->repo->index, path))
641 return -1;
642 if (o)
651 - if (add_cacheinfo(opt, o->mode, &o->oid, path, 1, 0, options))
643 + if (add_cacheinfo(opt, o, path, 1, 0, options))
644 return -1;
645 if (a)
654 - if (add_cacheinfo(opt, a->mode, &a->oid, path, 2, 0, options))
646 + if (add_cacheinfo(opt, a, path, 2, 0, options))
647 return -1;
648 if (b)
657 - if (add_cacheinfo(opt, b->mode, &b->oid, path, 3, 0, options))
649 + if (add_cacheinfo(opt, b, path, 3, 0, options))
650 return -1;
651 return 0;
652 }
@@ -767,7 +759,7 @@ static int dir_in_way(struct index_state *istate, const char *path,
759 * and its oid and mode match the specified values
760 */
761 static int was_tracked_and_matches(struct merge_options *opt, const char *path,
770 - const struct object_id *oid, unsigned mode)
762 + const struct diff_filespec *blob)
763 {
764 int pos = index_name_pos(&opt->orig_index, path, strlen(path));
765 struct cache_entry *ce;
@@ -778,7 +770,7 @@ static int was_tracked_and_matches(struct merge_options *opt, const char *path,
770
771 /* See if the file we were tracking before matches */
772 ce = opt->orig_index.cache[pos];
781 - return (oid_eq(&ce->oid, oid) && ce->ce_mode == mode);
773 + return (oid_eq(&ce->oid, &blob->oid) && ce->ce_mode == blob->mode);
774 }
775
776 /*
@@ -903,8 +895,7 @@ static int make_room_for_path(struct merge_options *opt, const char *path)
895 }
896
897 static int update_file_flags(struct merge_options *opt,
906 - const struct object_id *oid,
907 - unsigned mode,
898 + const struct diff_filespec *contents,
899 const char *path,
900 int update_cache,
901 int update_wd)
@@ -919,7 +910,7 @@ static int update_file_flags(struct merge_options *opt,
910 void *buf;
911 unsigned long size;
912
922 - if (S_ISGITLINK(mode)) {
913 + if (S_ISGITLINK(contents->mode)) {
914 /*
915 * We may later decide to recursively descend into
916 * the submodule directory and update its index
@@ -929,14 +920,16 @@ static int update_file_flags(struct merge_options *opt,
920 goto update_index;
921 }
922
932 - buf = read_object_file(oid, &type, &size);
923 + buf = read_object_file(&contents->oid, &type, &size);
924 if (!buf)
934 - return err(opt, _("cannot read object %s '%s'"), oid_to_hex(oid), path);
925 + return err(opt, _("cannot read object %s '%s'"),
926 + oid_to_hex(&contents->oid), path);
927 if (type != OBJ_BLOB) {
936 - ret = err(opt, _("blob expected for %s '%s'"), oid_to_hex(oid), path);
928 + ret = err(opt, _("blob expected for %s '%s'"),
929 + oid_to_hex(&contents->oid), path);
930 goto free_buf;
931 }
939 - if (S_ISREG(mode)) {
932 + if (S_ISREG(contents->mode)) {
933 struct strbuf strbuf = STRBUF_INIT;
934 if (convert_to_working_tree(opt->repo->index, path, buf, size, &strbuf)) {
935 free(buf);
@@ -949,12 +942,11 @@ static int update_file_flags(struct merge_options *opt,
942 update_wd = 0;
943 goto free_buf;
944 }
952 - if (S_ISREG(mode) || (!has_symlinks && S_ISLNK(mode))) {
945 + if (S_ISREG(contents->mode) ||
946 + (!has_symlinks && S_ISLNK(contents->mode))) {
947 int fd;
954 - if (mode & 0100)
955 - mode = 0777;
956 - else
957 - mode = 0666;
948 + int mode = (contents->mode & 0100 ? 0777 : 0666);
949 +
950 fd = open(path, O_WRONLY | O_TRUNC | O_CREAT, mode);
951 if (fd < 0) {
952 ret = err(opt, _("failed to open '%s': %s"),
@@ -963,7 +955,7 @@ static int update_file_flags(struct merge_options *opt,
955 }
956 write_in_full(fd, buf, size);
957 close(fd);
966 - } else if (S_ISLNK(mode)) {
958 + } else if (S_ISLNK(contents->mode)) {
959 char *lnk = xmemdupz(buf, size);
960 safe_create_leading_directories_const(path);
961 unlink(path);
@@ -974,13 +966,13 @@ static int update_file_flags(struct merge_options *opt,
966 } else
967 ret = err(opt,
968 _("do not know what to do with %06o %s '%s'"),
977 - mode, oid_to_hex(oid), path);
969 + contents->mode, oid_to_hex(&contents->oid), path);
970 free_buf:
971 free(buf);
972 }
973 update_index:
974 if (!ret && update_cache)
983 - if (add_cacheinfo(opt, mode, oid, path, 0, update_wd,
975 + if (add_cacheinfo(opt, contents, path, 0, update_wd,
976 ADD_CACHE_OK_TO_ADD))
977 return -1;
978 return ret;
@@ -988,18 +980,17 @@ update_index:
980
981 static int update_file(struct merge_options *opt,
982 int clean,
991 - const struct object_id *oid,
992 - unsigned mode,
983 + const struct diff_filespec *contents,
984 const char *path)
985 {
995 - return update_file_flags(opt, oid, mode, path, opt->call_depth || clean, !opt->call_depth);
986 + return update_file_flags(opt, contents, path,
987 + opt->call_depth || clean, !opt->call_depth);
988 }
989
990 /* Low level file merging, update and removal */
991
992 struct merge_file_info {
1001 - struct object_id oid;
1002 - unsigned mode;
993 + struct diff_filespec blob; /* mostly use oid & mode; sometimes path */
994 unsigned clean:1,
995 merge:1;
996 };
@@ -1039,6 +1030,7 @@ static int merge_3way(struct merge_options *opt,
1030 }
1031 }
1032
1033 + assert(a->path && b->path);
1034 if (strcmp(a->path, b->path) ||
1035 (opt->ancestor != NULL && strcmp(a->path, o->path) != 0)) {
1036 base_name = opt->ancestor == NULL ? NULL :
@@ -1140,6 +1132,11 @@ static void print_commit(struct commit *commit)
1132 strbuf_release(&sb);
1133 }
1134
1135 +static int is_valid(const struct diff_filespec *dfs)
1136 +{
1137 + return dfs->mode != 0 && !is_null_oid(&dfs->oid);
1138 +}
1139 +
1140 static int merge_submodule(struct merge_options *opt,
1141 struct object_id *result, const char *path,
1142 const struct object_id *base, const struct object_id *a,
@@ -1278,11 +1275,11 @@ static int merge_mode_and_contents(struct merge_options *opt,
1275 if ((S_IFMT & a->mode) != (S_IFMT & b->mode)) {
1276 result->clean = 0;
1277 if (S_ISREG(a->mode)) {
1281 - result->mode = a->mode;
1282 - oidcpy(&result->oid, &a->oid);
1278 + result->blob.mode = a->mode;
1279 + oidcpy(&result->blob.oid, &a->oid);
1280 } else {
1284 - result->mode = b->mode;
1285 - oidcpy(&result->oid, &b->oid);
1281 + result->blob.mode = b->mode;
1282 + oidcpy(&result->blob.oid, &b->oid);
1283 }
1284 } else {
1285 if (!oid_eq(&a->oid, &o->oid) && !oid_eq(&b->oid, &o->oid))
@@ -1292,9 +1289,9 @@ static int merge_mode_and_contents(struct merge_options *opt,
1289 * Merge modes
1290 */
1291 if (a->mode == b->mode || a->mode == o->mode)
1295 - result->mode = b->mode;
1292 + result->blob.mode = b->mode;
1293 else {
1297 - result->mode = a->mode;
1294 + result->blob.mode = a->mode;
1295 if (b->mode != o->mode) {
1296 result->clean = 0;
1297 result->merge = 1;
@@ -1302,9 +1299,9 @@ static int merge_mode_and_contents(struct merge_options *opt,
1299 }
1300
1301 if (oid_eq(&a->oid, &b->oid) || oid_eq(&a->oid, &o->oid))
1305 - oidcpy(&result->oid, &b->oid);
1302 + oidcpy(&result->blob.oid, &b->oid);
1303 else if (oid_eq(&b->oid, &o->oid))
1307 - oidcpy(&result->oid, &a->oid);
1304 + oidcpy(&result->blob.oid, &a->oid);
1305 else if (S_ISREG(a->mode)) {
1306 mmbuffer_t result_buf;
1307 int ret = 0, merge_status;
@@ -1318,7 +1315,7 @@ static int merge_mode_and_contents(struct merge_options *opt,
1315
1316 if (!ret &&
1317 write_object_file(result_buf.ptr, result_buf.size,
1321 - blob_type, &result->oid))
1318 + blob_type, &result->blob.oid))
1319 ret = err(opt, _("Unable to add %s to database"),
1320 a->path);
1321
@@ -1327,7 +1324,7 @@ static int merge_mode_and_contents(struct merge_options *opt,
1324 return ret;
1325 result->clean = (merge_status == 0);
1326 } else if (S_ISGITLINK(a->mode)) {
1330 - result->clean = merge_submodule(opt, &result->oid,
1327 + result->clean = merge_submodule(opt, &result->blob.oid,
1328 o->path,
1329 &o->oid,
1330 &a->oid,
@@ -1335,15 +1332,15 @@ static int merge_mode_and_contents(struct merge_options *opt,
1332 } else if (S_ISLNK(a->mode)) {
1333 switch (opt->recursive_variant) {
1334 case MERGE_RECURSIVE_NORMAL:
1338 - oidcpy(&result->oid, &a->oid);
1335 + oidcpy(&result->blob.oid, &a->oid);
1336 if (!oid_eq(&a->oid, &b->oid))
1337 result->clean = 0;
1338 break;
1339 case MERGE_RECURSIVE_OURS:
1343 - oidcpy(&result->oid, &a->oid);
1340 + oidcpy(&result->blob.oid, &a->oid);
1341 break;
1342 case MERGE_RECURSIVE_THEIRS:
1346 - oidcpy(&result->oid, &b->oid);
1343 + oidcpy(&result->blob.oid, &b->oid);
1344 break;
1345 }
1346 } else
@@ -1379,7 +1376,7 @@ static int handle_rename_via_dir(struct merge_options *opt,
1376 * index. Instead, write to dest->path for the index but
1377 * only at the higher appropriate stage.
1378 */
1382 - if (update_file(opt, 0, &dest->oid, dest->mode, alt_path))
1379 + if (update_file(opt, 0, dest, alt_path))
1380 return -1;
1381 free(alt_path);
1382 return update_stages(opt, dest->path, NULL,
@@ -1388,16 +1385,15 @@ static int handle_rename_via_dir(struct merge_options *opt,
1385 }
1386
1387 /* Update dest->path both in index and in worktree */
1391 - if (update_file(opt, 1, &dest->oid, dest->mode, dest->path))
1388 + if (update_file(opt, 1, dest, dest->path))
1389 return -1;
1390 return 0;
1391 }
1392
1393 static int handle_change_delete(struct merge_options *opt,
1394 const char *path, const char *old_path,
1398 - const struct object_id *o_oid, int o_mode,
1399 - const struct object_id *changed_oid,
1400 - int changed_mode,
1395 + const struct diff_filespec *o,
1396 + const struct diff_filespec *changed,
1397 const char *change_branch,
1398 const char *delete_branch,
1399 const char *change, const char *change_past)
@@ -1419,7 +1415,7 @@ static int handle_change_delete(struct merge_options *opt,
1415 */
1416 ret = remove_file_from_index(opt->repo->index, path);
1417 if (!ret)
1422 - ret = update_file(opt, 0, o_oid, o_mode, update_path);
1418 + ret = update_file(opt, 0, o, update_path);
1419 } else {
1420 /*
1421 * Despite the four nearly duplicate messages and argument
@@ -1468,7 +1464,7 @@ static int handle_change_delete(struct merge_options *opt,
1464 * and update_wd=0, but that's a no-op.
1465 */
1466 if (change_branch != opt->branch1 || alt_path)
1471 - ret = update_file(opt, 0, changed_oid, changed_mode, update_path);
1467 + ret = update_file(opt, 0, changed, update_path);
1468 }
1469 free(alt_path);
1470
@@ -1488,8 +1484,7 @@ static int handle_rename_delete(struct merge_options *opt,
1484 if (handle_change_delete(opt,
1485 opt->call_depth ? orig->path : dest->path,
1486 opt->call_depth ? NULL : orig->path,
1491 - &orig->oid, orig->mode,
1492 - &dest->oid, dest->mode,
1487 + orig, dest,
1488 rename_branch, delete_branch,
1489 _("rename"), _("renamed")))
1490 return -1;
@@ -1502,31 +1497,16 @@ static int handle_rename_delete(struct merge_options *opt,
1497 rename_branch == opt->branch1 ? NULL : dest);
1498 }
1499
1505 -static struct diff_filespec *filespec_from_entry(struct diff_filespec *target,
1506 - struct stage_data *entry,
1507 - int stage)
1508 -{
1509 - struct object_id *oid = &entry->stages[stage].oid;
1510 - unsigned mode = entry->stages[stage].mode;
1511 - if (mode == 0 || is_null_oid(oid))
1512 - return NULL;
1513 - oidcpy(&target->oid, oid);
1514 - target->mode = mode;
1515 - return target;
1516 -}
1517 -
1500 static int handle_file_collision(struct merge_options *opt,
1501 const char *collide_path,
1502 const char *prev_path1,
1503 const char *prev_path2,
1504 const char *branch1, const char *branch2,
1523 - const struct object_id *a_oid,
1524 - unsigned int a_mode,
1525 - const struct object_id *b_oid,
1526 - unsigned int b_mode)
1505 + struct diff_filespec *a,
1506 + struct diff_filespec *b)
1507 {
1508 struct merge_file_info mfi;
1529 - struct diff_filespec null, a, b;
1509 + struct diff_filespec null;
1510 char *alt_path = NULL;
1511 const char *update_path = collide_path;
1512
@@ -1540,29 +1520,28 @@ static int handle_file_collision(struct merge_options *opt,
1520 return handle_file_collision(opt, collide_path,
1521 prev_path2, prev_path1,
1522 branch2, branch1,
1543 - b_oid, b_mode,
1544 - a_oid, a_mode);
1523 + b, a);
1524 }
1525
1526 /*
1527 * In the recursive case, we just opt to undo renames
1528 */
1529 if (opt->call_depth && (prev_path1 || prev_path2)) {
1551 - /* Put first file (a_oid, a_mode) in its original spot */
1530 + /* Put first file (a->oid, a->mode) in its original spot */
1531 if (prev_path1) {
1553 - if (update_file(opt, 1, a_oid, a_mode, prev_path1))
1532 + if (update_file(opt, 1, a, prev_path1))
1533 return -1;
1534 } else {
1556 - if (update_file(opt, 1, a_oid, a_mode, collide_path))
1535 + if (update_file(opt, 1, a, collide_path))
1536 return -1;
1537 }
1538
1560 - /* Put second file (b_oid, b_mode) in its original spot */
1539 + /* Put second file (b->oid, b->mode) in its original spot */
1540 if (prev_path2) {
1562 - if (update_file(opt, 1, b_oid, b_mode, prev_path2))
1541 + if (update_file(opt, 1, b, prev_path2))
1542 return -1;
1543 } else {
1565 - if (update_file(opt, 1, b_oid, b_mode, collide_path))
1544 + if (update_file(opt, 1, b, collide_path))
1545 return -1;
1546 }
1547
@@ -1616,26 +1595,18 @@ static int handle_file_collision(struct merge_options *opt,
1595 }
1596
1597 /* Store things in diff_filespecs for functions that need it */
1619 - memset(&a, 0, sizeof(struct diff_filespec));
1620 - memset(&b, 0, sizeof(struct diff_filespec));
1621 - null.path = a.path = b.path = (char *)collide_path;
1598 + null.path = (char *)collide_path;
1599 oidcpy(&null.oid, &null_oid);
1600 null.mode = 0;
1624 - oidcpy(&a.oid, a_oid);
1625 - a.mode = a_mode;
1626 - a.oid_valid = 1;
1627 - oidcpy(&b.oid, b_oid);
1628 - b.mode = b_mode;
1629 - b.oid_valid = 1;
1630 -
1631 - if (merge_mode_and_contents(opt, &null, &a, &b, collide_path,
1601 +
1602 + if (merge_mode_and_contents(opt, &null, a, b, collide_path,
1603 branch1, branch2, opt->call_depth * 2, &mfi))
1604 return -1;
1605 mfi.clean &= !alt_path;
1635 - if (update_file(opt, mfi.clean, &mfi.oid, mfi.mode, update_path))
1606 + if (update_file(opt, mfi.clean, &mfi.blob, update_path))
1607 return -1;
1608 if (!mfi.clean && !opt->call_depth &&
1638 - update_stages(opt, collide_path, NULL, &a, &b))
1609 + update_stages(opt, collide_path, NULL, a, b))
1610 return -1;
1611 free(alt_path);
1612 /*
@@ -1654,7 +1625,6 @@ static int handle_rename_add(struct merge_options *opt,
1625 /* a was renamed to c, and a separate c was added. */
1626 struct diff_filespec *a = ci->ren1->pair->one;
1627 struct diff_filespec *c = ci->ren1->pair->two;
1657 - struct diff_filespec tmp;
1628 char *path = c->path;
1629 char *prev_path_desc;
1630 struct merge_file_info mfi;
@@ -1669,23 +1639,21 @@ static int handle_rename_add(struct merge_options *opt,
1639 a->path, c->path, rename_branch,
1640 c->path, add_branch);
1641
1672 - filespec_from_entry(&tmp, ci->ren1->src_entry, other_stage);
1673 - tmp.path = a->path;
1674 -
1642 prev_path_desc = xstrfmt("version of %s from %s", path, a->path);
1676 - if (merge_mode_and_contents(opt, a, c, &tmp,
1643 + if (merge_mode_and_contents(opt, a, c,
1644 + &ci->ren1->src_entry->stages[other_stage],
1645 prev_path_desc,
1646 opt->branch1, opt->branch2,
1647 1 + opt->call_depth * 2, &mfi))
1648 return -1;
1649 free(prev_path_desc);
1650
1651 + ci->ren1->dst_entry->stages[other_stage].path = mfi.blob.path = c->path;
1652 return handle_file_collision(opt,
1653 c->path, a->path, NULL,
1654 rename_branch, add_branch,
1686 - &mfi.oid, mfi.mode,
1687 - &ci->ren1->dst_entry->stages[other_stage].oid,
1688 - ci->ren1->dst_entry->stages[other_stage].mode);
1655 + &mfi.blob,
1656 + &ci->ren1->dst_entry->stages[other_stage]);
1657 }
1658
1659 static char *find_path_for_conflict(struct merge_options *opt,
@@ -1714,7 +1682,6 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
1682 {
1683 /* One file was renamed in both branches, but to different names. */
1684 struct merge_file_info mfi;
1717 - struct diff_filespec other;
1685 struct diff_filespec *add;
1686 struct diff_filespec *o = ci->ren1->pair->one;
1687 struct diff_filespec *a = ci->ren1->pair->two;
@@ -1743,7 +1710,7 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
1710 * pathname and then either rename the add-source file to that
1711 * unique path, or use that unique path instead of src here.
1712 */
1746 - if (update_file(opt, 0, &mfi.oid, mfi.mode, o->path))
1713 + if (update_file(opt, 0, &mfi.blob, o->path))
1714 return -1;
1715
1716 /*
@@ -1754,16 +1721,16 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
1721 * such cases, we should keep the added file around,
1722 * resolving the conflict at that path in its favor.
1723 */
1757 - add = filespec_from_entry(&other, ci->ren1->dst_entry, 2 ^ 1);
1758 - if (add) {
1759 - if (update_file(opt, 0, &add->oid, add->mode, a->path))
1724 + add = &ci->ren1->dst_entry->stages[2 ^ 1];
1725 + if (is_valid(add)) {
1726 + if (update_file(opt, 0, add, a->path))
1727 return -1;
1728 }
1729 else
1730 remove_file_from_index(opt->repo->index, a->path);
1764 - add = filespec_from_entry(&other, ci->ren2->dst_entry, 3 ^ 1);
1765 - if (add) {
1766 - if (update_file(opt, 0, &add->oid, add->mode, b->path))
1731 + add = &ci->ren2->dst_entry->stages[3 ^ 1];
1732 + if (is_valid(add)) {
1733 + if (update_file(opt, 0, add, b->path))
1734 return -1;
1735 }
1736 else
@@ -1774,40 +1741,42 @@ static int handle_rename_rename_1to2(struct merge_options *opt,
1741 * rename/add collision. If not, we can write the file out
1742 * to the specified location.
1743 */
1777 - add = filespec_from_entry(&other, ci->ren1->dst_entry, 2 ^ 1);
1778 - if (add) {
1744 + add = &ci->ren1->dst_entry->stages[2 ^ 1];
1745 + if (is_valid(add)) {
1746 + add->path = mfi.blob.path = a->path;
1747 if (handle_file_collision(opt, a->path,
1748 NULL, NULL,
1749 ci->ren1->branch,
1750 ci->ren2->branch,
1783 - &mfi.oid, mfi.mode,
1784 - &add->oid, add->mode) < 0)
1751 + &mfi.blob, add) < 0)
1752 return -1;
1753 } else {
1754 char *new_path = find_path_for_conflict(opt, a->path,
1755 ci->ren1->branch,
1756 ci->ren2->branch);
1790 - if (update_file(opt, 0, &mfi.oid, mfi.mode, new_path ? new_path : a->path))
1757 + if (update_file(opt, 0, &mfi.blob,
1758 + new_path ? new_path : a->path))
1759 return -1;
1760 free(new_path);
1761 if (update_stages(opt, a->path, NULL, a, NULL))
1762 return -1;
1763 }
1764
1797 - add = filespec_from_entry(&other, ci->ren2->dst_entry, 3 ^ 1);
1798 - if (add) {
1765 + add = &ci->ren2->dst_entry->stages[3 ^ 1];
1766 + if (is_valid(add)) {
1767 + add->path = mfi.blob.path = b->path;
1768 if (handle_file_collision(opt, b->path,
1769 NULL, NULL,
1770 ci->ren1->branch,
1771 ci->ren2->branch,
1803 - &add->oid, add->mode,
1804 - &mfi.oid, mfi.mode) < 0)
1772 + add, &mfi.blob) < 0)
1773 return -1;
1774 } else {
1775 char *new_path = find_path_for_conflict(opt, b->path,
1776 ci->ren2->branch,
1777 ci->ren1->branch);
1810 - if (update_file(opt, 0, &mfi.oid, mfi.mode, new_path ? new_path : b->path))
1778 + if (update_file(opt, 0, &mfi.blob,
1779 + new_path ? new_path : b->path))
1780 return -1;
1781 free(new_path);
1782 if (update_stages(opt, b->path, NULL, NULL, b))
@@ -1826,12 +1795,12 @@ static int handle_rename_rename_2to1(struct merge_options *opt,
1795 struct diff_filespec *b = ci->ren2->pair->one;
1796 struct diff_filespec *c1 = ci->ren1->pair->two;
1797 struct diff_filespec *c2 = ci->ren2->pair->two;
1829 - struct diff_filespec tmp1, tmp2;
1798 char *path = c1->path; /* == c2->path */
1799 char *path_side_1_desc;
1800 char *path_side_2_desc;
1801 struct merge_file_info mfi_c1;
1802 struct merge_file_info mfi_c2;
1803 + int ostage1, ostage2;
1804
1805 output(opt, 1, _("CONFLICT (rename/rename): "
1806 "Rename %s->%s in %s. "
@@ -1839,27 +1808,31 @@ static int handle_rename_rename_2to1(struct merge_options *opt,
1808 a->path, c1->path, ci->ren1->branch,
1809 b->path, c2->path, ci->ren2->branch);
1810
1842 - filespec_from_entry(&tmp1, ci->ren1->src_entry, 3);
1843 - tmp1.path = a->path;
1844 - filespec_from_entry(&tmp2, ci->ren2->src_entry, 2);
1845 - tmp2.path = b->path;
1846 -
1811 path_side_1_desc = xstrfmt("version of %s from %s", path, a->path);
1812 path_side_2_desc = xstrfmt("version of %s from %s", path, b->path);
1849 - if (merge_mode_and_contents(opt, a, c1, &tmp1, path_side_1_desc,
1813 + ostage1 = ci->ren1->branch == opt->branch1 ? 3 : 2;
1814 + ostage2 = ostage1 ^ 1;
1815 + ci->ren1->src_entry->stages[ostage1].path = a->path;
1816 + ci->ren2->src_entry->stages[ostage2].path = b->path;
1817 + if (merge_mode_and_contents(opt, a, c1,
1818 + &ci->ren1->src_entry->stages[ostage1],
1819 + path_side_1_desc,
1820 opt->branch1, opt->branch2,
1821 1 + opt->call_depth * 2, &mfi_c1) ||
1852 - merge_mode_and_contents(opt, b, &tmp2, c2, path_side_2_desc,
1822 + merge_mode_and_contents(opt, b,
1823 + &ci->ren2->src_entry->stages[ostage2],
1824 + c2, path_side_2_desc,
1825 opt->branch1, opt->branch2,
1826 1 + opt->call_depth * 2, &mfi_c2))
1827 return -1;
1828 free(path_side_1_desc);
1829 free(path_side_2_desc);
1830 + mfi_c1.blob.path = path;
1831 + mfi_c2.blob.path = path;
1832
1833 return handle_file_collision(opt, path, a->path, b->path,
1834 ci->ren1->branch, ci->ren2->branch,
1861 - &mfi_c1.oid, mfi_c1.mode,
1862 - &mfi_c2.oid, mfi_c2.mode);
1835 + &mfi_c1.blob, &mfi_c2.blob);
1836 }
1837
1838 /*
@@ -2722,7 +2695,6 @@ static int process_renames(struct merge_options *opt,
2695
2696 setup_rename_conflict_info(RENAME_TWO_FILES_TO_ONE,
2697 opt, ren1, ren2);
2725 -
2698 } else {
2699 /* Renamed in 1, maybe changed in 2 */
2700 /* we only use sha1 and mode of these */
@@ -2771,8 +2743,7 @@ static int process_renames(struct merge_options *opt,
2743 * update_file().
2744 */
2745 if (update_file_flags(opt,
2774 - &ren1->pair->two->oid,
2775 - ren1->pair->two->mode,
2746 + ren1->pair->two,
2747 ren1_dst,
2748 1, /* update_cache */
2749 0 /* update_wd */))
@@ -2923,11 +2894,6 @@ static void final_cleanup_renames(struct rename_info *re_info)
2894 final_cleanup_rename(re_info->merge_renames);
2895 }
2896
2926 -static struct object_id *stage_oid(const struct object_id *oid, unsigned mode)
2927 -{
2928 - return (is_null_oid(oid) || mode == 0) ? NULL: (struct object_id *)oid;
2929 -}
2930 -
2897 static int read_oid_strbuf(struct merge_options *opt,
2898 const struct object_id *oid,
2899 struct strbuf *dst)
@@ -2947,10 +2913,8 @@ static int read_oid_strbuf(struct merge_options *opt,
2913 }
2914
2915 static int blob_unchanged(struct merge_options *opt,
2950 - const struct object_id *o_oid,
2951 - unsigned o_mode,
2952 - const struct object_id *a_oid,
2953 - unsigned a_mode,
2916 + const struct diff_filespec *o,
2917 + const struct diff_filespec *a,
2918 int renormalize, const char *path)
2919 {
2920 struct strbuf obuf = STRBUF_INIT;
@@ -2958,16 +2922,15 @@ static int blob_unchanged(struct merge_options *opt,
2922 int ret = 0; /* assume changed for safety */
2923 const struct index_state *idx = opt->repo->index;
2924
2961 - if (a_mode != o_mode)
2925 + if (a->mode != o->mode)
2926 return 0;
2963 - if (oid_eq(o_oid, a_oid))
2927 + if (oid_eq(&o->oid, &a->oid))
2928 return 1;
2929 if (!renormalize)
2930 return 0;
2931
2968 - assert(o_oid && a_oid);
2969 - if (read_oid_strbuf(opt, o_oid, &obuf) ||
2970 - read_oid_strbuf(opt, a_oid, &abuf))
2932 + if (read_oid_strbuf(opt, &o->oid, &obuf) ||
2933 + read_oid_strbuf(opt, &a->oid, &abuf))
2934 goto error_return;
2935 /*
2936 * Note: binary | is used so that both renormalizations are
@@ -2986,30 +2949,26 @@ error_return:
2949
2950 static int handle_modify_delete(struct merge_options *opt,
2951 const char *path,
2989 - struct object_id *o_oid, int o_mode,
2990 - struct object_id *a_oid, int a_mode,
2991 - struct object_id *b_oid, int b_mode)
2952 + const struct diff_filespec *o,
2953 + const struct diff_filespec *a,
2954 + const struct diff_filespec *b)
2955 {
2956 const char *modify_branch, *delete_branch;
2994 - struct object_id *changed_oid;
2995 - int changed_mode;
2957 + const struct diff_filespec *changed;
2958
2997 - if (a_oid) {
2959 + if (is_valid(a)) {
2960 modify_branch = opt->branch1;
2961 delete_branch = opt->branch2;
3000 - changed_oid = a_oid;
3001 - changed_mode = a_mode;
2962 + changed = a;
2963 } else {
2964 modify_branch = opt->branch2;
2965 delete_branch = opt->branch1;
3005 - changed_oid = b_oid;
3006 - changed_mode = b_mode;
2966 + changed = b;
2967 }
2968
2969 return handle_change_delete(opt,
2970 path, NULL,
3011 - o_oid, o_mode,
3012 - changed_oid, changed_mode,
2971 + o, changed,
2972 modify_branch, delete_branch,
2973 _("modify"), _("modified"));
2974 }
@@ -3017,50 +2976,24 @@ static int handle_modify_delete(struct merge_options *opt,
2976 static int handle_content_merge(struct merge_options *opt,
2977 const char *path,
2978 int is_dirty,
3020 - struct object_id *o_oid, int o_mode,
3021 - struct object_id *a_oid, int a_mode,
3022 - struct object_id *b_oid, int b_mode,
2979 + const struct diff_filespec *o,
2980 + const struct diff_filespec *a,
2981 + const struct diff_filespec *b,
2982 struct rename_conflict_info *ci)
2983 {
2984 const char *reason = _("content");
3026 - const char *path1 = NULL, *path2 = NULL;
2985 struct merge_file_info mfi;
3028 - struct diff_filespec one, a, b;
2986 unsigned df_conflict_remains = 0;
2987
3031 - if (!o_oid) {
2988 + if (!is_valid(o))
2989 reason = _("add/add");
3033 - o_oid = (struct object_id *)&null_oid;
3034 - }
3035 - one.path = a.path = b.path = (char *)path;
3036 - oidcpy(&one.oid, o_oid);
3037 - one.mode = o_mode;
3038 - oidcpy(&a.oid, a_oid);
3039 - a.mode = a_mode;
3040 - oidcpy(&b.oid, b_oid);
3041 - b.mode = b_mode;
3042 -
3043 - if (ci) {
3044 - struct diff_filepair *pair1 = ci->ren1->pair;
3045 -
3046 - path1 = (opt->branch1 == ci->ren1->branch) ?
3047 - pair1->two->path : pair1->one->path;
3048 - /* If ci->ren2->pair != NULL, we are in
3049 - * RENAME_ONE_FILE_TO_ONE case. Otherwise, we have a
3050 - * normal rename.
3051 - */
3052 - path2 = ((ci->ren2 && ci->ren2->pair) ||
3053 - opt->branch2 == ci->ren1->branch) ?
3054 - pair1->two->path : pair1->one->path;
3055 - one.path = pair1->one->path;
3056 - a.path = (char *)path1;
3057 - b.path = (char *)path2;
3058 -
3059 - if (dir_in_way(opt->repo->index, path, !opt->call_depth,
3060 - S_ISGITLINK(pair1->two->mode)))
3061 - df_conflict_remains = 1;
3062 - }
3063 - if (merge_mode_and_contents(opt, &one, &a, &b, path,
2990 +
2991 + assert(o->path && a->path && b->path);
2992 + if (ci && dir_in_way(opt->repo->index, path, !opt->call_depth,
2993 + S_ISGITLINK(ci->ren1->pair->two->mode)))
2994 + df_conflict_remains = 1;
2995 +
2996 + if (merge_mode_and_contents(opt, o, a, b, path,
2997 opt->branch1, opt->branch2,
2998 opt->call_depth * 2, &mfi))
2999 return -1;
@@ -3071,14 +3004,13 @@ static int handle_content_merge(struct merge_options *opt,
3004 * b) The merge matches what was in HEAD (content, mode, pathname)
3005 * c) The target path is usable (i.e. not involved in D/F conflict)
3006 */
3074 - if (mfi.clean &&
3075 - was_tracked_and_matches(opt, path, &mfi.oid, mfi.mode) &&
3007 + if (mfi.clean && was_tracked_and_matches(opt, path, &mfi.blob) &&
3008 !df_conflict_remains) {
3009 int pos;
3010 struct cache_entry *ce;
3011
3012 output(opt, 3, _("Skipped %s (merged same as existing)"), path);
3081 - if (add_cacheinfo(opt, mfi.mode, &mfi.oid, path,
3013 + if (add_cacheinfo(opt, &mfi.blob, path,
3014 0, (!opt->call_depth && !is_dirty), 0))
3015 return -1;
3016 /*
@@ -3098,12 +3030,12 @@ static int handle_content_merge(struct merge_options *opt,
3030 }
3031
3032 if (!mfi.clean) {
3101 - if (S_ISGITLINK(mfi.mode))
3033 + if (S_ISGITLINK(mfi.blob.mode))
3034 reason = _("submodule");
3035 output(opt, 1, _("CONFLICT (%s): Merge conflict in %s"),
3036 reason, path);
3037 if (ci && !df_conflict_remains)
3106 - if (update_stages(opt, path, &one, &a, &b))
3038 + if (update_stages(opt, path, o, a, b))
3039 return -1;
3040 }
3041
@@ -3113,17 +3045,14 @@ static int handle_content_merge(struct merge_options *opt,
3045 remove_file_from_index(opt->repo->index, path);
3046 } else {
3047 if (!mfi.clean) {
3116 - if (update_stages(opt, path, &one, &a, &b))
3048 + if (update_stages(opt, path, o, a, b))
3049 return -1;
3050 } else {
3051 int file_from_stage2 = was_tracked(opt, path);
3120 - struct diff_filespec merged;
3121 - oidcpy(&merged.oid, &mfi.oid);
3122 - merged.mode = mfi.mode;
3052
3053 if (update_stages(opt, path, NULL,
3125 - file_from_stage2 ? &merged : NULL,
3126 - file_from_stage2 ? NULL : &merged))
3054 + file_from_stage2 ? &mfi.blob : NULL,
3055 + file_from_stage2 ? NULL : &mfi.blob))
3056 return -1;
3057 }
3058
@@ -3134,28 +3063,27 @@ static int handle_content_merge(struct merge_options *opt,
3063 path);
3064 }
3065 output(opt, 1, _("Adding as %s instead"), new_path);
3137 - if (update_file(opt, 0, &mfi.oid, mfi.mode, new_path)) {
3066 + if (update_file(opt, 0, &mfi.blob, new_path)) {
3067 free(new_path);
3068 return -1;
3069 }
3070 free(new_path);
3071 mfi.clean = 0;
3143 - } else if (update_file(opt, mfi.clean, &mfi.oid, mfi.mode, path))
3072 + } else if (update_file(opt, mfi.clean, &mfi.blob, path))
3073 return -1;
3074 return !is_dirty && mfi.clean;
3075 }
3076
3077 static int handle_rename_normal(struct merge_options *opt,
3078 const char *path,
3150 - struct object_id *o_oid, unsigned int o_mode,
3151 - struct object_id *a_oid, unsigned int a_mode,
3152 - struct object_id *b_oid, unsigned int b_mode,
3079 + const struct diff_filespec *o,
3080 + const struct diff_filespec *a,
3081 + const struct diff_filespec *b,
3082 struct rename_conflict_info *ci)
3083 {
3084 /* Merge the content and write it out */
3085 return handle_content_merge(opt, path, was_dirty(opt, path),
3157 - o_oid, o_mode, a_oid, a_mode, b_oid, b_mode,
3158 - ci);
3086 + o, a, b, ci);
3087 }
3088
3089 /* Per entry merge function */
@@ -3164,24 +3092,36 @@ static int process_entry(struct merge_options *opt,
3092 {
3093 int clean_merge = 1;
3094 int normalize = opt->renormalize;
3167 - unsigned o_mode = entry->stages[1].mode;
3168 - unsigned a_mode = entry->stages[2].mode;
3169 - unsigned b_mode = entry->stages[3].mode;
3170 - struct object_id *o_oid = stage_oid(&entry->stages[1].oid, o_mode);
3171 - struct object_id *a_oid = stage_oid(&entry->stages[2].oid, a_mode);
3172 - struct object_id *b_oid = stage_oid(&entry->stages[3].oid, b_mode);
3095 +
3096 + struct diff_filespec *o = &entry->stages[1];
3097 + struct diff_filespec *a = &entry->stages[2];
3098 + struct diff_filespec *b = &entry->stages[3];
3099 + int o_valid = is_valid(o);
3100 + int a_valid = is_valid(a);
3101 + int b_valid = is_valid(b);
3102 + o->path = a->path = b->path = (char*)path;
3103
3104 entry->processed = 1;
3105 if (entry->rename_conflict_info) {
3106 struct rename_conflict_info *ci = entry->rename_conflict_info;
3107 + struct diff_filespec *temp;
3108 +
3109 + /*
3110 + * For cases with a single rename, {o,a,b}->path have all been
3111 + * set to the rename target path; we need to set two of these
3112 + * back to the rename source.
3113 + * For rename/rename conflicts, we'll manually fix paths below.
3114 + */
3115 + temp = (opt->branch1 == ci->ren1->branch) ? b : a;
3116 + o->path = temp->path = ci->ren1->pair->one->path;
3117 + if (ci->ren2) {
3118 + assert(opt->branch1 == ci->ren1->branch);
3119 + }
3120 +
3121 switch (ci->rename_type) {
3122 case RENAME_NORMAL:
3123 case RENAME_ONE_FILE_TO_ONE:
3180 - clean_merge = handle_rename_normal(opt,
3181 - path,
3182 - o_oid, o_mode,
3183 - a_oid, a_mode,
3184 - b_oid, b_mode,
3124 + clean_merge = handle_rename_normal(opt, path, o, a, b,
3125 ci);
3126 break;
3127 case RENAME_VIA_DIR:
@@ -3204,11 +3144,27 @@ static int process_entry(struct merge_options *opt,
3144 clean_merge = -1;
3145 break;
3146 case RENAME_ONE_FILE_TO_TWO:
3147 + /*
3148 + * Manually fix up paths; note:
3149 + * ren[12]->pair->one->path are equal.
3150 + */
3151 + o->path = ci->ren1->pair->one->path;
3152 + a->path = ci->ren1->pair->two->path;
3153 + b->path = ci->ren2->pair->two->path;
3154 +
3155 clean_merge = 0;
3156 if (handle_rename_rename_1to2(opt, ci))
3157 clean_merge = -1;
3158 break;
3159 case RENAME_TWO_FILES_TO_ONE:
3160 + /*
3161 + * Manually fix up paths; note,
3162 + * ren[12]->pair->two->path are actually equal.
3163 + */
3164 + o->path = NULL;
3165 + a->path = ci->ren1->pair->two->path;
3166 + b->path = ci->ren2->pair->two->path;
3167 +
3168 /*
3169 * Probably unclean merge, but if the two renamed
3170 * files merge cleanly and the two resulting files
@@ -3221,57 +3177,53 @@ static int process_entry(struct merge_options *opt,
3177 entry->processed = 0;
3178 break;
3179 }
3224 - } else if (o_oid && (!a_oid || !b_oid)) {
3180 + } else if (o_valid && (!a_valid || !b_valid)) {
3181 /* Case A: Deleted in one */
3226 - if ((!a_oid && !b_oid) ||
3227 - (!b_oid && blob_unchanged(opt, o_oid, o_mode, a_oid, a_mode, normalize, path)) ||
3228 - (!a_oid && blob_unchanged(opt, o_oid, o_mode, b_oid, b_mode, normalize, path))) {
3182 + if ((!a_valid && !b_valid) ||
3183 + (!b_valid && blob_unchanged(opt, o, a, normalize, path)) ||
3184 + (!a_valid && blob_unchanged(opt, o, b, normalize, path))) {
3185 /* Deleted in both or deleted in one and
3186 * unchanged in the other */
3231 - if (a_oid)
3187 + if (a_valid)
3188 output(opt, 2, _("Removing %s"), path);
3189 /* do not touch working file if it did not exist */
3234 - remove_file(opt, 1, path, !a_oid);
3190 + remove_file(opt, 1, path, !a_valid);
3191 } else {
3192 /* Modify/delete; deleted side may have put a directory in the way */
3193 clean_merge = 0;
3238 - if (handle_modify_delete(opt, path, o_oid, o_mode,
3239 - a_oid, a_mode, b_oid, b_mode))
3194 + if (handle_modify_delete(opt, path, o, a, b))
3195 clean_merge = -1;
3196 }
3242 - } else if ((!o_oid && a_oid && !b_oid) ||
3243 - (!o_oid && !a_oid && b_oid)) {
3197 + } else if ((!o_valid && a_valid && !b_valid) ||
3198 + (!o_valid && !a_valid && b_valid)) {
3199 /* Case B: Added in one. */
3200 /* [nothing|directory] -> ([nothing|directory], file) */
3201
3202 const char *add_branch;
3203 const char *other_branch;
3249 - unsigned mode;
3250 - const struct object_id *oid;
3204 const char *conf;
3205 + const struct diff_filespec *contents;
3206
3253 - if (a_oid) {
3207 + if (a_valid) {
3208 add_branch = opt->branch1;
3209 other_branch = opt->branch2;
3256 - mode = a_mode;
3257 - oid = a_oid;
3210 + contents = a;
3211 conf = _("file/directory");
3212 } else {
3213 add_branch = opt->branch2;
3214 other_branch = opt->branch1;
3262 - mode = b_mode;
3263 - oid = b_oid;
3215 + contents = b;
3216 conf = _("directory/file");
3217 }
3218 if (dir_in_way(opt->repo->index, path,
3267 - !opt->call_depth && !S_ISGITLINK(a_mode),
3219 + !opt->call_depth && !S_ISGITLINK(a->mode),
3220 0)) {
3221 char *new_path = unique_path(opt, path, add_branch);
3222 clean_merge = 0;
3223 output(opt, 1, _("CONFLICT (%s): There is a directory with name %s in %s. "
3224 "Adding %s as %s"),
3225 conf, path, other_branch, path, new_path);
3274 - if (update_file(opt, 0, oid, mode, new_path))
3226 + if (update_file(opt, 0, contents, new_path))
3227 clean_merge = -1;
3228 else if (opt->call_depth)
3229 remove_file_from_index(opt->repo->index, path);
@@ -3279,11 +3231,11 @@ static int process_entry(struct merge_options *opt,
3231 } else {
3232 output(opt, 2, _("Adding %s"), path);
3233 /* do not overwrite file if already present */
3282 - if (update_file_flags(opt, oid, mode, path, 1, !a_oid))
3234 + if (update_file_flags(opt, contents, path, 1, !a_valid))
3235 clean_merge = -1;
3236 }
3285 - } else if (a_oid && b_oid) {
3286 - if (!o_oid) {
3237 + } else if (a_valid && b_valid) {
3238 + if (!o_valid) {
3239 /* Case C: Added in both (check for same permissions) */
3240 output(opt, 1,
3241 _("CONFLICT (add/add): Merge conflict in %s"),
@@ -3292,24 +3244,19 @@ static int process_entry(struct merge_options *opt,
3244 path, NULL, NULL,
3245 opt->branch1,
3246 opt->branch2,
3295 - a_oid, a_mode,
3296 - b_oid, b_mode);
3247 + a, b);
3248 } else {
3249 /* case D: Modified in both, but differently. */
3250 int is_dirty = 0; /* unpack_trees would have bailed if dirty */
3300 - clean_merge = handle_content_merge(opt, path,
3301 - is_dirty,
3302 - o_oid, o_mode,
3303 - a_oid, a_mode,
3304 - b_oid, b_mode,
3305 - NULL);
3251 + clean_merge = handle_content_merge(opt, path, is_dirty,
3252 + o, a, b, NULL);
3253 }
3307 - } else if (!o_oid && !a_oid && !b_oid) {
3254 + } else if (!o_valid && !a_valid && !b_valid) {
3255 /*
3256 * this entry was deleted altogether. a_mode == 0 means
3257 * we had that path and want to actively remove it.
3258 */
3312 - remove_file(opt, 1, path, !a_mode);
3259 + remove_file(opt, 1, path, !a->mode);
3260 } else
3261 BUG("fatal merge failure, shouldn't happen.");
3262