merge-ort: store more specific conflict information

It is all fine and dandy for a regular Git command that is intended to be run interactively to produce a bunch of messages upon an error. However, in `merge-ort`'s case, we want to call the command e.g. in server-side software, where the actual error messages are not quite as interesting as machine-readable, immutable terms that describe the exact nature of any given conflict. With this patch, the `merge-ort` machinery records the exact type (as specified via an `enum` value) as well as the involved path(s) together with the conflict's message. Signed-off-by: Elijah Newren <newren@gmail.com> Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>

Elijah Newren committed Jun 18, 2022 at 00:20 UTC cb2607759e27627aca614726dc50e98ac0ba6d19
1 file changed +212 -55
merge-ort.c
+212 -55
@@ -483,6 +483,100 @@ struct conflict_info {
483 unsigned match_mask:3;
484 };
485
486 +enum conflict_and_info_types {
487 + /* "Simple" conflicts and informational messages */
488 + INFO_AUTO_MERGING = 0,
489 + CONFLICT_CONTENTS, /* text file that failed to merge */
490 + CONFLICT_BINARY,
491 + CONFLICT_FILE_DIRECTORY,
492 + CONFLICT_DISTINCT_MODES,
493 + CONFLICT_MODIFY_DELETE,
494 + CONFLICT_PRESENT_DESPITE_SKIPPED,
495 +
496 + /* Regular rename */
497 + CONFLICT_RENAME_RENAME, /* same file renamed differently */
498 + CONFLICT_RENAME_COLLIDES, /* rename/add or two files renamed to 1 */
499 + CONFLICT_RENAME_DELETE,
500 +
501 + /* Basic directory rename */
502 + CONFLICT_DIR_RENAME_SUGGESTED,
503 + INFO_DIR_RENAME_APPLIED,
504 +
505 + /* Special directory rename cases */
506 + INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME,
507 + CONFLICT_DIR_RENAME_FILE_IN_WAY,
508 + CONFLICT_DIR_RENAME_COLLISION,
509 + CONFLICT_DIR_RENAME_SPLIT,
510 +
511 + /* Basic submodule */
512 + INFO_SUBMODULE_FAST_FORWARDING,
513 + CONFLICT_SUBMODULE_FAILED_TO_MERGE,
514 +
515 + /* Special submodule cases broken out from FAILED_TO_MERGE */
516 + CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION,
517 + CONFLICT_SUBMODULE_NOT_INITIALIZED,
518 + CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE,
519 + CONFLICT_SUBMODULE_MAY_HAVE_REWINDS,
520 +
521 + /* Keep this entry _last_ in the list */
522 + NB_CONFLICT_TYPES,
523 +};
524 +
525 +/*
526 + * Short description of conflict type, relied upon by external tools.
527 + *
528 + * We can add more entries, but DO NOT change any of these strings. Also,
529 + * Order MUST match conflict_info_and_types.
530 + */
531 +static const char *type_short_descriptions[] = {
532 + /*** "Simple" conflicts and informational messages ***/
533 + [INFO_AUTO_MERGING] = "Auto-merging",
534 + [CONFLICT_CONTENTS] = "CONFLICT (contents)",
535 + [CONFLICT_BINARY] = "CONFLICT (binary)",
536 + [CONFLICT_FILE_DIRECTORY] = "CONFLICT (file/directory)",
537 + [CONFLICT_DISTINCT_MODES] = "CONFLICT (distinct modes)",
538 + [CONFLICT_MODIFY_DELETE] = "CONFLICT (modify/delete)",
539 + [CONFLICT_PRESENT_DESPITE_SKIPPED] =
540 + "CONFLICT (upgrade your version of git)",
541 +
542 + /*** Regular rename ***/
543 + [CONFLICT_RENAME_RENAME] = "CONFLICT (rename/rename)",
544 + [CONFLICT_RENAME_COLLIDES] = "CONFLICT (rename involved in collision)",
545 + [CONFLICT_RENAME_DELETE] = "CONFLICT (rename/delete)",
546 +
547 + /*** Basic directory rename ***/
548 + [CONFLICT_DIR_RENAME_SUGGESTED] =
549 + "CONFLICT (directory rename suggested)",
550 + [INFO_DIR_RENAME_APPLIED] = "Path updated due to directory rename",
551 +
552 + /*** Special directory rename cases ***/
553 + [INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME] =
554 + "Directory rename skipped since directory was renamed on both sides",
555 + [CONFLICT_DIR_RENAME_FILE_IN_WAY] =
556 + "CONFLICT (file in way of directory rename)",
557 + [CONFLICT_DIR_RENAME_COLLISION] = "CONFLICT(directory rename collision)",
558 + [CONFLICT_DIR_RENAME_SPLIT] = "CONFLICT(directory rename unclear split)",
559 +
560 + /*** Basic submodule ***/
561 + [INFO_SUBMODULE_FAST_FORWARDING] = "Fast forwarding submodule",
562 + [CONFLICT_SUBMODULE_FAILED_TO_MERGE] = "CONFLICT (submodule)",
563 +
564 + /*** Special submodule cases broken out from FAILED_TO_MERGE ***/
565 + [CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION] =
566 + "CONFLICT (submodule with possible resolution)",
567 + [CONFLICT_SUBMODULE_NOT_INITIALIZED] =
568 + "CONFLICT (submodule not initialized)",
569 + [CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE] =
570 + "CONFLICT (submodule history not available)",
571 + [CONFLICT_SUBMODULE_MAY_HAVE_REWINDS] =
572 + "CONFLICT (submodule may have rewinds)",
573 +};
574 +
575 +struct logical_conflict_info {
576 + enum conflict_and_info_types type;
577 + struct strvec paths;
578 +};
579 +
580 /*** Function Grouping: various utility functions ***/
581
582 /*
@@ -571,6 +665,11 @@ static void clear_or_reinit_internal_opts(struct merge_options_internal *opti,
665 /* Release and free each strbuf found in output */
666 strmap_for_each_entry(&opti->conflicts, &iter, e) {
667 struct string_list *list = e->value;
668 + for (int i = 0; i < list->nr; i++) {
669 + struct logical_conflict_info *info =
670 + list->items[i].util;
671 + strvec_clear(&info->paths);
672 + }
673 /*
674 * While strictly speaking we don't need to
675 * free(conflicts) here because we could pass
@@ -629,31 +728,56 @@ static void format_commit(struct strbuf *sb,
728 strbuf_addch(sb, '\n');
729 }
730
632 -__attribute__((format (printf, 4, 5)))
731 +__attribute__((format (printf, 8, 9)))
732 static void path_msg(struct merge_options *opt,
634 - const char *path,
733 + enum conflict_and_info_types type,
734 int omittable_hint, /* skippable under --remerge-diff */
735 + const char *primary_path,
736 + const char *other_path_1, /* may be NULL */
737 + const char *other_path_2, /* may be NULL */
738 + struct string_list *other_paths, /* may be NULL */
739 const char *fmt, ...)
740 {
741 va_list ap;
742 struct string_list *path_conflicts;
743 + struct logical_conflict_info *info;
744 struct strbuf buf = STRBUF_INIT;
745 struct strbuf *dest;
746 struct strbuf tmp = STRBUF_INIT;
747
748 + /* Sanity checks */
749 + assert(omittable_hint ==
750 + !starts_with(type_short_descriptions[type], "CONFLICT") ||
751 + type == CONFLICT_DIR_RENAME_SUGGESTED ||
752 + type == CONFLICT_PRESENT_DESPITE_SKIPPED);
753 if (opt->record_conflict_msgs_as_headers && omittable_hint)
754 return; /* Do not record mere hints in headers */
755 if (opt->priv->call_depth && opt->verbosity < 5)
756 return; /* Ignore messages from inner merges */
757
758 /* Ensure path_conflicts (ptr to array of logical_conflict) allocated */
650 - path_conflicts = strmap_get(&opt->priv->conflicts, path);
759 + path_conflicts = strmap_get(&opt->priv->conflicts, primary_path);
760 if (!path_conflicts) {
761 path_conflicts = xmalloc(sizeof(*path_conflicts));
762 string_list_init_dup(path_conflicts);
654 - strmap_put(&opt->priv->conflicts, path, path_conflicts);
763 + strmap_put(&opt->priv->conflicts, primary_path, path_conflicts);
764 }
765
766 + /* Add a logical_conflict at the end to store info from this call */
767 + info = xcalloc(1, sizeof(*info));
768 + info->type = type;
769 + strvec_init(&info->paths);
770 +
771 + /* Handle the list of paths */
772 + strvec_push(&info->paths, primary_path);
773 + if (other_path_1)
774 + strvec_push(&info->paths, other_path_1);
775 + if (other_path_2)
776 + strvec_push(&info->paths, other_path_2);
777 + if (other_paths)
778 + for (int i = 0; i < other_paths->nr; i++)
779 + strvec_push(&info->paths, other_paths->items[i].string);
780 +
781 /* Handle message and its format, in normal case */
782 dest = (opt->record_conflict_msgs_as_headers ? &tmp : &buf);
783
@@ -690,7 +814,8 @@ static void path_msg(struct merge_options *opt,
814
815 strbuf_release(&tmp);
816 }
693 - string_list_append_nodup(path_conflicts, strbuf_detach(&buf, NULL));
817 + string_list_append_nodup(path_conflicts, strbuf_detach(&buf, NULL))
818 + ->util = info;
819 }
820
821 static struct diff_filespec *pool_alloc_filespec(struct mem_pool *pool,
@@ -1632,16 +1757,18 @@ static int merge_submodule(struct merge_options *opt,
1757 return 0;
1758
1759 if (repo_submodule_init(&subrepo, opt->repo, path, null_oid())) {
1635 - path_msg(opt, path, 0,
1636 - _("Failed to merge submodule %s (not checked out)"),
1637 - path);
1760 + path_msg(opt, CONFLICT_SUBMODULE_NOT_INITIALIZED, 0,
1761 + path, NULL, NULL, NULL,
1762 + _("Failed to merge submodule %s (not checked out)"),
1763 + path);
1764 return 0;
1765 }
1766
1767 if (!(commit_o = lookup_commit_reference(&subrepo, o)) ||
1768 !(commit_a = lookup_commit_reference(&subrepo, a)) ||
1769 !(commit_b = lookup_commit_reference(&subrepo, b))) {
1644 - path_msg(opt, path, 0,
1770 + path_msg(opt, CONFLICT_SUBMODULE_HISTORY_NOT_AVAILABLE, 0,
1771 + path, NULL, NULL, NULL,
1772 _("Failed to merge submodule %s (commits not present)"),
1773 path);
1774 goto cleanup;
@@ -1650,7 +1777,8 @@ static int merge_submodule(struct merge_options *opt,
1777 /* check whether both changes are forward */
1778 if (!repo_in_merge_bases(&subrepo, commit_o, commit_a) ||
1779 !repo_in_merge_bases(&subrepo, commit_o, commit_b)) {
1653 - path_msg(opt, path, 0,
1780 + path_msg(opt, CONFLICT_SUBMODULE_MAY_HAVE_REWINDS, 0,
1781 + path, NULL, NULL, NULL,
1782 _("Failed to merge submodule %s "
1783 "(commits don't follow merge-base)"),
1784 path);
@@ -1660,7 +1788,8 @@ static int merge_submodule(struct merge_options *opt,
1788 /* Case #1: a is contained in b or vice versa */
1789 if (repo_in_merge_bases(&subrepo, commit_a, commit_b)) {
1790 oidcpy(result, b);
1663 - path_msg(opt, path, 1,
1791 + path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
1792 + path, NULL, NULL, NULL,
1793 _("Note: Fast-forwarding submodule %s to %s"),
1794 path, oid_to_hex(b));
1795 ret = 1;
@@ -1668,7 +1797,8 @@ static int merge_submodule(struct merge_options *opt,
1797 }
1798 if (repo_in_merge_bases(&subrepo, commit_b, commit_a)) {
1799 oidcpy(result, a);
1671 - path_msg(opt, path, 1,
1800 + path_msg(opt, INFO_SUBMODULE_FAST_FORWARDING, 1,
1801 + path, NULL, NULL, NULL,
1802 _("Note: Fast-forwarding submodule %s to %s"),
1803 path, oid_to_hex(a));
1804 ret = 1;
@@ -1691,13 +1821,16 @@ static int merge_submodule(struct merge_options *opt,
1821 &merges);
1822 switch (parent_count) {
1823 case 0:
1694 - path_msg(opt, path, 0, _("Failed to merge submodule %s"), path);
1824 + path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE, 0,
1825 + path, NULL, NULL, NULL,
1826 + _("Failed to merge submodule %s"), path);
1827 break;
1828
1829 case 1:
1830 format_commit(&sb, 4, &subrepo,
1831 (struct commit *)merges.objects[0].item);
1700 - path_msg(opt, path, 0,
1832 + path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, 0,
1833 + path, NULL, NULL, NULL,
1834 _("Failed to merge submodule %s, but a possible merge "
1835 "resolution exists: %s"),
1836 path, sb.buf);
@@ -1707,7 +1840,8 @@ static int merge_submodule(struct merge_options *opt,
1840 for (i = 0; i < merges.nr; i++)
1841 format_commit(&sb, 4, &subrepo,
1842 (struct commit *)merges.objects[i].item);
1710 - path_msg(opt, path, 0,
1843 + path_msg(opt, CONFLICT_SUBMODULE_FAILED_TO_MERGE_BUT_POSSIBLE_RESOLUTION, 0,
1844 + path, NULL, NULL, NULL,
1845 _("Failed to merge submodule %s, but multiple "
1846 "possible merges exist:\n%s"), path, sb.buf);
1847 strbuf_release(&sb);
@@ -1833,7 +1967,8 @@ static int merge_3way(struct merge_options *opt,
1967 &src1, name1, &src2, name2,
1968 &opt->priv->attr_index, &ll_opts);
1969 if (merge_status == LL_MERGE_BINARY_CONFLICT)
1836 - path_msg(opt, path, 0,
1970 + path_msg(opt, CONFLICT_BINARY, 0,
1971 + path, NULL, NULL, NULL,
1972 "warning: Cannot merge binary files: %s (%s vs. %s)",
1973 path, name1, name2);
1974
@@ -1945,7 +2080,8 @@ static int handle_content_merge(struct merge_options *opt,
2080 if (ret)
2081 return -1;
2082 clean &= (merge_status == 0);
1948 - path_msg(opt, path, 1, _("Auto-merging %s"), path);
2083 + path_msg(opt, INFO_AUTO_MERGING, 1, path, NULL, NULL, NULL,
2084 + _("Auto-merging %s"), path);
2085 } else if (S_ISGITLINK(a->mode)) {
2086 int two_way = ((S_IFMT & o->mode) != (S_IFMT & a->mode));
2087 clean = merge_submodule(opt, pathnames[0],
@@ -2083,21 +2219,24 @@ static char *handle_path_level_conflicts(struct merge_options *opt,
2219 c_info->reported_already = 1;
2220 strbuf_add_separated_string_list(&collision_paths, ", ",
2221 &c_info->source_files);
2086 - path_msg(opt, new_path, 0,
2087 - _("CONFLICT (implicit dir rename): Existing file/dir "
2088 - "at %s in the way of implicit directory rename(s) "
2089 - "putting the following path(s) there: %s."),
2090 - new_path, collision_paths.buf);
2222 + path_msg(opt, CONFLICT_DIR_RENAME_FILE_IN_WAY, 0,
2223 + new_path, NULL, NULL, &c_info->source_files,
2224 + _("CONFLICT (implicit dir rename): Existing "
2225 + "file/dir at %s in the way of implicit "
2226 + "directory rename(s) putting the following "
2227 + "path(s) there: %s."),
2228 + new_path, collision_paths.buf);
2229 clean = 0;
2230 } else if (c_info->source_files.nr > 1) {
2231 c_info->reported_already = 1;
2232 strbuf_add_separated_string_list(&collision_paths, ", ",
2233 &c_info->source_files);
2096 - path_msg(opt, new_path, 0,
2097 - _("CONFLICT (implicit dir rename): Cannot map more "
2098 - "than one path to %s; implicit directory renames "
2099 - "tried to put these paths there: %s"),
2100 - new_path, collision_paths.buf);
2234 + path_msg(opt, CONFLICT_DIR_RENAME_COLLISION, 0,
2235 + new_path, NULL, NULL, &c_info->source_files,
2236 + _("CONFLICT (implicit dir rename): Cannot map "
2237 + "more than one path to %s; implicit directory "
2238 + "renames tried to put these paths there: %s"),
2239 + new_path, collision_paths.buf);
2240 clean = 0;
2241 }
2242
@@ -2151,13 +2290,14 @@ static void get_provisional_directory_renames(struct merge_options *opt,
2290 continue;
2291
2292 if (bad_max == max) {
2154 - path_msg(opt, source_dir, 0,
2155 - _("CONFLICT (directory rename split): "
2156 - "Unclear where to rename %s to; it was "
2157 - "renamed to multiple other directories, with "
2158 - "no destination getting a majority of the "
2159 - "files."),
2160 - source_dir);
2293 + path_msg(opt, CONFLICT_DIR_RENAME_SPLIT, 0,
2294 + source_dir, NULL, NULL, NULL,
2295 + _("CONFLICT (directory rename split): "
2296 + "Unclear where to rename %s to; it was "
2297 + "renamed to multiple other directories, "
2298 + "with no destination getting a majority of "
2299 + "the files."),
2300 + source_dir);
2301 *clean = 0;
2302 } else {
2303 strmap_put(&renames->dir_renames[side],
@@ -2305,7 +2445,8 @@ static char *check_for_directory_rename(struct merge_options *opt,
2445 */
2446 otherinfo = strmap_get_entry(dir_rename_exclusions, new_dir);
2447 if (otherinfo) {
2308 - path_msg(opt, rename_info->key, 1,
2448 + path_msg(opt, INFO_DIR_RENAME_SKIPPED_DUE_TO_RERENAME, 1,
2449 + rename_info->key, path, new_dir, NULL,
2450 _("WARNING: Avoiding applying %s -> %s rename "
2451 "to %s, because %s itself was renamed."),
2452 rename_info->key, new_dir, path, new_dir);
@@ -2445,14 +2586,16 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
2586 if (opt->detect_directory_renames == MERGE_DIRECTORY_RENAMES_TRUE) {
2587 /* Notify user of updated path */
2588 if (pair->status == 'A')
2448 - path_msg(opt, new_path, 1,
2589 + path_msg(opt, INFO_DIR_RENAME_APPLIED, 1,
2590 + new_path, old_path, NULL, NULL,
2591 _("Path updated: %s added in %s inside a "
2592 "directory that was renamed in %s; moving "
2593 "it to %s."),
2594 old_path, branch_with_new_path,
2595 branch_with_dir_rename, new_path);
2596 else
2455 - path_msg(opt, new_path, 1,
2597 + path_msg(opt, INFO_DIR_RENAME_APPLIED, 1,
2598 + new_path, old_path, NULL, NULL,
2599 _("Path updated: %s renamed to %s in %s, "
2600 "inside a directory that was renamed in %s; "
2601 "moving it to %s."),
@@ -2465,7 +2608,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
2608 */
2609 ci->path_conflict = 1;
2610 if (pair->status == 'A')
2468 - path_msg(opt, new_path, 1,
2611 + path_msg(opt, CONFLICT_DIR_RENAME_SUGGESTED, 1,
2612 + new_path, old_path, NULL, NULL,
2613 _("CONFLICT (file location): %s added in %s "
2614 "inside a directory that was renamed in %s, "
2615 "suggesting it should perhaps be moved to "
@@ -2473,7 +2617,8 @@ static void apply_directory_rename_modifications(struct merge_options *opt,
2617 old_path, branch_with_new_path,
2618 branch_with_dir_rename, new_path);
2619 else
2476 - path_msg(opt, new_path, 1,
2620 + path_msg(opt, CONFLICT_DIR_RENAME_SUGGESTED, 1,
2621 + new_path, old_path, NULL, NULL,
2622 _("CONFLICT (file location): %s renamed to %s "
2623 "in %s, inside a directory that was renamed "
2624 "in %s, suggesting it should perhaps be "
@@ -2629,7 +2774,8 @@ static int process_renames(struct merge_options *opt,
2774 * and remove the setting of base->path_conflict to 1.
2775 */
2776 base->path_conflict = 1;
2632 - path_msg(opt, oldpath, 0,
2777 + path_msg(opt, CONFLICT_RENAME_RENAME, 0,
2778 + pathnames[0], pathnames[1], pathnames[2], NULL,
2779 _("CONFLICT (rename/rename): %s renamed to "
2780 "%s in %s and to %s in %s."),
2781 pathnames[0],
@@ -2724,7 +2870,8 @@ static int process_renames(struct merge_options *opt,
2870 memcpy(&newinfo->stages[target_index], &merged,
2871 sizeof(merged));
2872 if (!clean) {
2727 - path_msg(opt, newpath, 0,
2873 + path_msg(opt, CONFLICT_RENAME_COLLIDES, 0,
2874 + newpath, oldpath, NULL, NULL,
2875 _("CONFLICT (rename involved in "
2876 "collision): rename of %s -> %s has "
2877 "content conflicts AND collides "
@@ -2743,7 +2890,8 @@ static int process_renames(struct merge_options *opt,
2890 */
2891
2892 newinfo->path_conflict = 1;
2746 - path_msg(opt, newpath, 0,
2893 + path_msg(opt, CONFLICT_RENAME_DELETE, 0,
2894 + newpath, oldpath, NULL, NULL,
2895 _("CONFLICT (rename/delete): %s renamed "
2896 "to %s in %s, but deleted in %s."),
2897 oldpath, newpath, rename_branch, delete_branch);
@@ -2767,7 +2915,8 @@ static int process_renames(struct merge_options *opt,
2915 } else if (source_deleted) {
2916 /* rename/delete */
2917 newinfo->path_conflict = 1;
2770 - path_msg(opt, newpath, 0,
2918 + path_msg(opt, CONFLICT_RENAME_DELETE, 0,
2919 + newpath, oldpath, NULL, NULL,
2920 _("CONFLICT (rename/delete): %s renamed"
2921 " to %s in %s, but deleted in %s."),
2922 oldpath, newpath,
@@ -3688,7 +3837,8 @@ static void process_entry(struct merge_options *opt,
3837 path = unique_path(opt, path, branch);
3838 strmap_put(&opt->priv->paths, path, new_ci);
3839
3691 - path_msg(opt, path, 0,
3840 + path_msg(opt, CONFLICT_FILE_DIRECTORY, 0,
3841 + path, old_path, NULL, NULL,
3842 _("CONFLICT (file/directory): directory in the way "
3843 "of %s from %s; moving it to %s instead."),
3844 old_path, branch, path);
@@ -3764,15 +3914,23 @@ static void process_entry(struct merge_options *opt,
3914 rename_b = 1;
3915 }
3916
3917 + if (rename_a)
3918 + a_path = unique_path(opt, path, opt->branch1);
3919 + if (rename_b)
3920 + b_path = unique_path(opt, path, opt->branch2);
3921 +
3922 if (rename_a && rename_b) {
3768 - path_msg(opt, path, 0,
3923 + path_msg(opt, CONFLICT_DISTINCT_MODES, 0,
3924 + path, a_path, b_path, NULL,
3925 _("CONFLICT (distinct types): %s had "
3926 "different types on each side; "
3927 "renamed both of them so each can "
3928 "be recorded somewhere."),
3929 path);
3930 } else {
3775 - path_msg(opt, path, 0,
3931 + path_msg(opt, CONFLICT_DISTINCT_MODES, 0,
3932 + path, rename_a ? a_path : b_path,
3933 + NULL, NULL,
3934 _("CONFLICT (distinct types): %s had "
3935 "different types on each side; "
3936 "renamed one of them so each can be "
@@ -3809,14 +3967,10 @@ static void process_entry(struct merge_options *opt,
3967
3968 /* Insert entries into opt->priv_paths */
3969 assert(rename_a || rename_b);
3812 - if (rename_a) {
3813 - a_path = unique_path(opt, path, opt->branch1);
3970 + if (rename_a)
3971 strmap_put(&opt->priv->paths, a_path, ci);
3815 - }
3972
3817 - if (rename_b)
3818 - b_path = unique_path(opt, path, opt->branch2);
3819 - else
3973 + if (!rename_b)
3974 b_path = path;
3975 strmap_put(&opt->priv->paths, b_path, new_ci);
3976
@@ -3867,7 +4021,8 @@ static void process_entry(struct merge_options *opt,
4021 reason = _("add/add");
4022 if (S_ISGITLINK(merged_file.mode))
4023 reason = _("submodule");
3870 - path_msg(opt, path, 0,
4024 + path_msg(opt, CONFLICT_CONTENTS, 0,
4025 + path, NULL, NULL, NULL,
4026 _("CONFLICT (%s): Merge conflict in %s"),
4027 reason, path);
4028 }
@@ -3911,7 +4066,8 @@ static void process_entry(struct merge_options *opt,
4066 * since the contents were not modified.
4067 */
4068 } else {
3914 - path_msg(opt, path, 0,
4069 + path_msg(opt, CONFLICT_MODIFY_DELETE, 0,
4070 + path, NULL, NULL, NULL,
4071 _("CONFLICT (modify/delete): %s deleted in %s "
4072 "and modified in %s. Version %s of %s left "
4073 "in tree."),
@@ -4207,7 +4363,8 @@ static int record_conflicted_index_entries(struct merge_options *opt)
4363 path,
4364 "cruft");
4365
4210 - path_msg(opt, path, 1,
4366 + path_msg(opt, CONFLICT_PRESENT_DESPITE_SKIPPED, 1,
4367 + path, NULL, NULL, NULL,
4368 _("Note: %s not up to date and in way of checking out conflicted version; old copy renamed to %s"),
4369 path, new_name);
4370 errs |= rename(path, new_name);