merge-recursive: Consolidate process_entry() and process_df_entry()

The whole point of adding process_df_entry() was to ensure that files of D/F conflicts were processed after paths under the corresponding directory. However, given that the entries are in sorted order, all we need to do is iterate through them in reverse order to achieve the same effect. That lets us remove some duplicated code, and lets us keep track of one less thing as we read the code ("do we need to make sure this is processed before process_df_entry() or do we need to defer it until then?"). Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Aug 11, 2011 at 23:20 UTC edd2faf52eda344eca2c01bc0b1d9f7f2f002a42
1 file changed +57 -131
merge-recursive.c
+57 -131
@@ -116,7 +116,6 @@ static inline void setup_rename_df_conflict_info(enum rename_type rename_type,
116 ci->dst_entry2 = dst_entry2;
117 ci->pair2 = pair2;
118 dst_entry2->rename_df_conflict_info = ci;
119 - dst_entry2->processed = 0;
119 }
120 }
121
@@ -365,20 +364,17 @@ static void record_df_conflict_files(struct merge_options *o,
364 struct string_list *entries)
365 {
366 /* If there is a D/F conflict and the file for such a conflict
368 - * currently exist in the working copy, we want to allow it to
369 - * be removed to make room for the corresponding directory if
370 - * needed. The files underneath the directories of such D/F
371 - * conflicts will be handled in process_entry(), while the
372 - * files of such D/F conflicts will be processed later in
373 - * process_df_entry(). If the corresponding directory ends up
374 - * being removed by the merge, then no additional work needs
375 - * to be done by process_df_entry() for the conflicting file.
376 - * If the directory needs to be written to the working copy,
377 - * then the conflicting file will simply be removed (e.g. in
378 - * make_room_for_path). If the directory is written to the
379 - * working copy but the file also has a conflict that needs to
380 - * be resolved, then process_df_entry() will reinstate the
381 - * file with a new unique name.
367 + * currently exist in the working copy, we want to allow it to be
368 + * removed to make room for the corresponding directory if needed.
369 + * The files underneath the directories of such D/F conflicts will
370 + * be processed before the corresponding file involved in the D/F
371 + * conflict. If the D/F directory ends up being removed by the
372 + * merge, then we won't have to touch the D/F file. If the D/F
373 + * directory needs to be written to the working copy, then the D/F
374 + * file will simply be removed (in make_room_for_path()) to make
375 + * room for the necessary paths. Note that if both the directory
376 + * and the file need to be present, then the D/F file will be
377 + * reinstated with a new unique name at the time it is processed.
378 */
379 const char *last_file = NULL;
380 int last_len = 0;
@@ -1323,17 +1319,17 @@ static void handle_delete_modify(struct merge_options *o,
1319 "and modified in %s. Version %s of %s left in tree%s%s.",
1320 path, o->branch1,
1321 o->branch2, o->branch2, path,
1326 - path == new_path ? "" : " at ",
1327 - path == new_path ? "" : new_path);
1328 - update_file(o, 0, b_sha, b_mode, new_path);
1322 + NULL == new_path ? "" : " at ",
1323 + NULL == new_path ? "" : new_path);
1324 + update_file(o, 0, b_sha, b_mode, new_path ? new_path : path);
1325 } else {
1326 output(o, 1, "CONFLICT (delete/modify): %s deleted in %s "
1327 "and modified in %s. Version %s of %s left in tree%s%s.",
1328 path, o->branch2,
1329 o->branch1, o->branch1, path,
1334 - path == new_path ? "" : " at ",
1335 - path == new_path ? "" : new_path);
1336 - update_file(o, 0, a_sha, a_mode, new_path);
1330 + NULL == new_path ? "" : " at ",
1331 + NULL == new_path ? "" : new_path);
1332 + update_file(o, 0, a_sha, a_mode, new_path ? new_path : path);
1333 }
1334 }
1335
@@ -1431,93 +1427,6 @@ static int process_entry(struct merge_options *o,
1427 unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
1428 unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
1429
1434 - if (entry->rename_df_conflict_info)
1435 - return 1; /* Such cases are handled elsewhere. */
1436 -
1437 - entry->processed = 1;
1438 - if (o_sha && (!a_sha || !b_sha)) {
1439 - /* Case A: Deleted in one */
1440 - if ((!a_sha && !b_sha) ||
1441 - (!b_sha && blob_unchanged(o_sha, a_sha, normalize, path)) ||
1442 - (!a_sha && blob_unchanged(o_sha, b_sha, normalize, path))) {
1443 - /* Deleted in both or deleted in one and
1444 - * unchanged in the other */
1445 - if (a_sha)
1446 - output(o, 2, "Removing %s", path);
1447 - /* do not touch working file if it did not exist */
1448 - remove_file(o, 1, path, !a_sha);
1449 - } else if (dir_in_way(path, 0 /*check_wc*/)) {
1450 - entry->processed = 0;
1451 - return 1; /* Assume clean until processed */
1452 - } else {
1453 - /* Deleted in one and changed in the other */
1454 - clean_merge = 0;
1455 - handle_delete_modify(o, path, path,
1456 - a_sha, a_mode, b_sha, b_mode);
1457 - }
1458 -
1459 - } else if ((!o_sha && a_sha && !b_sha) ||
1460 - (!o_sha && !a_sha && b_sha)) {
1461 - /* Case B: Added in one. */
1462 - unsigned mode;
1463 - const unsigned char *sha;
1464 -
1465 - if (a_sha) {
1466 - mode = a_mode;
1467 - sha = a_sha;
1468 - } else {
1469 - mode = b_mode;
1470 - sha = b_sha;
1471 - }
1472 - if (dir_in_way(path, 0 /*check_wc*/)) {
1473 - /* Handle D->F conflicts after all subfiles */
1474 - entry->processed = 0;
1475 - return 1; /* Assume clean until processed */
1476 - } else {
1477 - output(o, 2, "Adding %s", path);
1478 - update_file(o, 1, sha, mode, path);
1479 - }
1480 - } else if (a_sha && b_sha) {
1481 - /* Case C: Added in both (check for same permissions) and */
1482 - /* case D: Modified in both, but differently. */
1483 - clean_merge = merge_content(o, entry->involved_in_rename, path,
1484 - o_sha, o_mode, a_sha, a_mode, b_sha, b_mode,
1485 - NULL);
1486 - } else if (!o_sha && !a_sha && !b_sha) {
1487 - /*
1488 - * this entry was deleted altogether. a_mode == 0 means
1489 - * we had that path and want to actively remove it.
1490 - */
1491 - remove_file(o, 1, path, !a_mode);
1492 - } else
1493 - die("Fatal merge failure, shouldn't happen.");
1494 -
1495 - return clean_merge;
1496 -}
1497 -
1498 -/*
1499 - * Per entry merge function for D/F (and/or rename) conflicts. In the
1500 - * cases we can cleanly resolve D/F conflicts, process_entry() can
1501 - * clean out all the files below the directory for us. All D/F
1502 - * conflict cases must be handled here at the end to make sure any
1503 - * directories that can be cleaned out, are.
1504 - *
1505 - * Some rename conflicts may also be handled here that don't necessarily
1506 - * involve D/F conflicts, since the code to handle them is generic enough
1507 - * to handle those rename conflicts with or without D/F conflicts also
1508 - * being involved.
1509 - */
1510 -static int process_df_entry(struct merge_options *o,
1511 - const char *path, struct stage_data *entry)
1512 -{
1513 - int clean_merge = 1;
1514 - unsigned o_mode = entry->stages[1].mode;
1515 - unsigned a_mode = entry->stages[2].mode;
1516 - unsigned b_mode = entry->stages[3].mode;
1517 - unsigned char *o_sha = stage_sha(entry->stages[1].sha, o_mode);
1518 - unsigned char *a_sha = stage_sha(entry->stages[2].sha, a_mode);
1519 - unsigned char *b_sha = stage_sha(entry->stages[3].sha, b_mode);
1520 -
1430 entry->processed = 1;
1431 if (entry->rename_df_conflict_info) {
1432 struct rename_df_conflict_info *conflict_info = entry->rename_df_conflict_info;
@@ -1552,24 +1461,38 @@ static int process_df_entry(struct merge_options *o,
1461 conflict_info->branch1,
1462 conflict_info->pair2,
1463 conflict_info->branch2);
1555 - conflict_info->dst_entry2->processed = 1;
1464 break;
1465 default:
1466 entry->processed = 0;
1467 break;
1468 }
1469 } else if (o_sha && (!a_sha || !b_sha)) {
1562 - /* Modify/delete; deleted side may have put a directory in the way */
1563 - char *renamed = NULL;
1564 - if (dir_in_way(path, !o->call_depth)) {
1565 - renamed = unique_path(o, path, a_sha ? o->branch1 : o->branch2);
1470 + /* Case A: Deleted in one */
1471 + if ((!a_sha && !b_sha) ||
1472 + (!b_sha && blob_unchanged(o_sha, a_sha, normalize, path)) ||
1473 + (!a_sha && blob_unchanged(o_sha, b_sha, normalize, path))) {
1474 + /* Deleted in both or deleted in one and
1475 + * unchanged in the other */
1476 + if (a_sha)
1477 + output(o, 2, "Removing %s", path);
1478 + /* do not touch working file if it did not exist */
1479 + remove_file(o, 1, path, !a_sha);
1480 + } else {
1481 + /* Modify/delete; deleted side may have put a directory in the way */
1482 + char *renamed = NULL;
1483 + clean_merge = 0;
1484 + if (dir_in_way(path, !o->call_depth)) {
1485 + renamed = unique_path(o, path, a_sha ? o->branch1 : o->branch2);
1486 + }
1487 + handle_delete_modify(o, path, renamed,
1488 + a_sha, a_mode, b_sha, b_mode);
1489 + free(renamed);
1490 }
1567 - clean_merge = 0;
1568 - handle_delete_modify(o, path, renamed ? renamed : path,
1569 - a_sha, a_mode, b_sha, b_mode);
1570 - free(renamed);
1571 - } else if (!o_sha && !!a_sha != !!b_sha) {
1572 - /* directory -> (directory, file) or <nothing> -> (directory, file) */
1491 + } else if ((!o_sha && a_sha && !b_sha) ||
1492 + (!o_sha && !a_sha && b_sha)) {
1493 + /* Case B: Added in one. */
1494 + /* [nothing|directory] -> ([nothing|directory], file) */
1495 +
1496 const char *add_branch;
1497 const char *other_branch;
1498 unsigned mode;
@@ -1605,10 +1528,20 @@ static int process_df_entry(struct merge_options *o,
1528 output(o, 2, "Adding %s", path);
1529 update_file(o, 1, sha, mode, path);
1530 }
1608 - } else {
1609 - entry->processed = 0;
1610 - return 1; /* not handled; assume clean until processed */
1611 - }
1531 + } else if (a_sha && b_sha) {
1532 + /* Case C: Added in both (check for same permissions) and */
1533 + /* case D: Modified in both, but differently. */
1534 + clean_merge = merge_content(o, entry->involved_in_rename, path,
1535 + o_sha, o_mode, a_sha, a_mode, b_sha, b_mode,
1536 + NULL);
1537 + } else if (!o_sha && !a_sha && !b_sha) {
1538 + /*
1539 + * this entry was deleted altogether. a_mode == 0 means
1540 + * we had that path and want to actively remove it.
1541 + */
1542 + remove_file(o, 1, path, !a_mode);
1543 + } else
1544 + die("Fatal merge failure, shouldn't happen.");
1545
1546 return clean_merge;
1547 }
@@ -1656,20 +1589,13 @@ int merge_trees(struct merge_options *o,
1589 re_head = get_renames(o, head, common, head, merge, entries);
1590 re_merge = get_renames(o, merge, common, head, merge, entries);
1591 clean = process_renames(o, re_head, re_merge);
1659 - for (i = 0; i < entries->nr; i++) {
1592 + for (i = entries->nr-1; 0 <= i; i--) {
1593 const char *path = entries->items[i].string;
1594 struct stage_data *e = entries->items[i].util;
1595 if (!e->processed
1596 && !process_entry(o, path, e))
1597 clean = 0;
1598 }
1666 - for (i = 0; i < entries->nr; i++) {
1667 - const char *path = entries->items[i].string;
1668 - struct stage_data *e = entries->items[i].util;
1669 - if (!e->processed
1670 - && !process_df_entry(o, path, e))
1671 - clean = 0;
1672 - }
1599 for (i = 0; i < entries->nr; i++) {
1600 struct stage_data *e = entries->items[i].util;
1601 if (!e->processed)