# # # delete "tests/show_conflicts" # # delete "tests/show_conflicts/__driver__.lua" # # rename "tests/non_content_conflicts" # to "tests/conflict_messages" # # patch "cmd_merging.cc" # from [62ecbbf6a981beb3b9612e34dd7c4804df43e9f1] # to [e13d083c6ec5a0bb84b72a793b3fefccf5fe980f] # # patch "merge.cc" # from [748d0fae376a9804138837a6a1e7006d57f0bdb7] # to [76da4cf756a8b84f177c0540bf1cf66286662878] # # patch "roster_merge.cc" # from [3608b823761f8f700e73bf2013fbae536e9d0712] # to [3cae80e9fd925941eda7b626de9cc8542a44f628] # # patch "roster_merge.hh" # from [34fd64bd0dc1ef9bf7158f71aeb69230caa0462e] # to [9110ec12f5d3d21a193067a1937b8d7c2d750546] # # patch "sanity.hh" # from [7c69292b7148dbd84d3f9a8924f791fca9a10682] # to [5ba1f5f71bc2a3d6c53f27bb7bbcd896d3e8155f] # # patch "tests/conflict_messages/__driver__.lua" # from [fc66cec8d78d1c02e6e30824e058a1cce6b7dddd] # to [32d64b7bea2cf1e7c1c98ad6a1579762a4f6e5b1] # ============================================================ --- cmd_merging.cc 62ecbbf6a981beb3b9612e34dd7c4804df43e9f1 +++ cmd_merging.cc e13d083c6ec5a0bb84b72a793b3fefccf5fe980f @@ -693,6 +693,9 @@ CMD(merge_into_workspace, "merge_into_wo app.db.get_roster(right_id, right); N(!(left_id == right_id), F("workspace is already at revision %s") % left_id); + P(F("[left] %s") % left_id); + P(F("[right] %s") % right_id); + set left_uncommon_ancestors, right_uncommon_ancestors; app.db.get_uncommon_ancestors(left_id, right_id, left_uncommon_ancestors, @@ -800,20 +803,32 @@ CMD(show_conflicts, "show_conflicts", "" r_roster, r_marking, r_uncommon_ancestors, result); - P(F("There are %s multiple_name_conflicts.") - % result.multiple_name_conflicts.size()); - P(F("There are %s file_content_conflicts.") - % result.file_content_conflicts.size()); - P(F("There are %s attribute_conflicts.") - % result.attribute_conflicts.size()); - P(F("There are %s orphaned_node_conflicts.") - % result.orphaned_node_conflicts.size()); - P(F("There are %s duplicate_name_conflicts.") - % result.duplicate_name_conflicts.size()); - P(F("There are %s directory_loop_conflicts.") - % result.directory_loop_conflicts.size()); - P(F("There are %s invalid_name_conflicts.") - % result.invalid_name_conflicts.size()); + // note that left and right are in the order specified on the command line + // they are not in lexical order as they are with other merge commands + // so they may appear swapped here. perhaps we should sort left and right + // before using them? + + P(F("[left] %s") % l_id); + P(F("[right] %s") % r_id); + + if (result.is_clean()) + { + P(F("no conflicts detected")); + } + else + { + content_merge_database_adaptor adaptor(app, l_id, r_id, + l_marking, r_marking); + + result.report_multiple_name_conflicts(l_roster, r_roster, adaptor); + result.report_file_content_conflicts(l_roster, r_roster, adaptor); + result.report_attribute_conflicts(l_roster, r_roster, adaptor); + result.report_orphaned_node_conflicts(l_roster, r_roster, adaptor); + result.report_duplicate_name_conflicts(l_roster, r_roster, adaptor); + result.report_directory_loop_conflicts(l_roster, r_roster, adaptor); + result.report_invalid_name_conflicts(l_roster, r_roster, adaptor); + result.report_missing_root_conflicts(l_roster, r_roster, adaptor); + } } CMD(pluck, "pluck", "", CMD_REF(workspace), N_("[-r FROM] -r TO [PATH...]"), ============================================================ --- merge.cc 748d0fae376a9804138837a6a1e7006d57f0bdb7 +++ merge.cc 76da4cf756a8b84f177c0540bf1cf66286662878 @@ -56,7 +56,14 @@ resolve_merge_conflicts(roster_t const & if (result.has_non_content_conflicts()) { - result.warn_non_content_conflicts(left_roster, right_roster, adaptor); + result.report_multiple_name_conflicts(left_roster, right_roster, adaptor); + result.report_file_content_conflicts(left_roster, right_roster, adaptor); + result.report_attribute_conflicts(left_roster, right_roster, adaptor); + result.report_orphaned_node_conflicts(left_roster, right_roster, adaptor); + result.report_duplicate_name_conflicts(left_roster, right_roster, adaptor); + result.report_directory_loop_conflicts(left_roster, right_roster, adaptor); + result.report_invalid_name_conflicts(left_roster, right_roster, adaptor); + result.report_missing_root_conflicts(left_roster, right_roster, adaptor); } else if (result.has_content_conflicts()) { @@ -64,6 +71,7 @@ resolve_merge_conflicts(roster_t const & // To do this requires finding a merge ancestor. L(FL("examining content conflicts")); + result.report_file_content_conflicts(left_roster, right_roster, adaptor); size_t cnt; size_t total_conflicts = result.file_content_conflicts.size(); ============================================================ --- roster_merge.cc 3608b823761f8f700e73bf2013fbae536e9d0712 +++ roster_merge.cc 3cae80e9fd925941eda7b626de9cc8542a44f628 @@ -29,13 +29,11 @@ dump(multiple_name_conflict const & conf dump(multiple_name_conflict const & conflict, string & out) { ostringstream oss; - oss << "node: " << conflict.nid << "\n" - << "left\n" - << " parent: " << conflict.left.first << "\n" - << " basename: " << conflict.left.second << "\n" - << "right\n" - << " parent: " << conflict.right.first << "\n" - << " basename: " << conflict.right.second << "\n"; + oss << "multiple_name_conflict on node: " << conflict.nid << " " + << "left parent: " << conflict.left.first << " " + << "basename: " << conflict.left.second << " " + << "right parent: " << conflict.right.first << " " + << "basename: " << conflict.right.second << "\n"; out = oss.str(); } @@ -43,8 +41,8 @@ dump(file_content_conflict const & confl dump(file_content_conflict const & conflict, string & out) { ostringstream oss; - oss << "node: " << conflict.nid << "\n" - << "left: " << conflict.left << "\n" + oss << "file_content_conflict on node: " << conflict.nid << " " + << "left: " << conflict.left << " " << "right: " << conflict.right << "\n"; out = oss.str(); } @@ -53,9 +51,9 @@ dump(attribute_conflict const & conflict dump(attribute_conflict const & conflict, string & out) { ostringstream oss; - oss << "node: " << conflict.nid << "\n" - << "attr: '" << conflict.key << "'\n" - << "left: " << conflict.left.first << " '" << conflict.left.second << "'\n" + oss << "attribute_conflict on node: " << conflict.nid << " " + << "attr: '" << conflict.key << "' " + << "left: " << conflict.left.first << " '" << conflict.left.second << "' " << "right: " << conflict.right.first << " '" << conflict.right.second << "'\n"; out = oss.str(); } @@ -64,8 +62,8 @@ dump(orphaned_node_conflict const & conf dump(orphaned_node_conflict const & conflict, string & out) { ostringstream oss; - oss << "node: " << conflict.nid << "\n" - << "parent: " << conflict.parent_name.first << "\n" + oss << "orphaned_node_conflict on node: " << conflict.nid << " " + << "parent: " << conflict.parent_name.first << " " << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -74,9 +72,9 @@ dump(duplicate_name_conflict const & con dump(duplicate_name_conflict const & conflict, string & out) { ostringstream oss; - oss << "left: " << conflict.left_nid << "\n" - << "right: " << conflict.right_nid << "\n" - << "parent: " << conflict.parent_name.first << "\n" + oss << "duplicate_name_conflict between left node: " << conflict.left_nid << " " + << "and right node: " << conflict.right_nid << " " + << "parent: " << conflict.parent_name.first << " " << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -85,8 +83,8 @@ dump(directory_loop_conflict const & con dump(directory_loop_conflict const & conflict, string & out) { ostringstream oss; - oss << "node: " << conflict.nid << "\n" - << "parent: " << conflict.parent_name.first << "\n" + oss << "directory_loop_conflict on node: " << conflict.nid << " " + << "parent: " << conflict.parent_name.first << " " << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -95,8 +93,8 @@ dump(invalid_name_conflict const & confl dump(invalid_name_conflict const & conflict, string & out) { ostringstream oss; - oss << "node: " << conflict.nid << "\n" - << "parent: " << conflict.parent_name.first << "\n" + oss << "invalid_name_conflict on node: " << conflict.nid << " " + << "parent: " << conflict.parent_name.first << " " << "basename: " << conflict.parent_name.second << "\n"; out = oss.str(); } @@ -133,94 +131,26 @@ roster_merge_result::has_non_content_con || !invalid_name_conflicts.empty() || missing_root_dir; } - static void -debug_describe_conflicts(roster_merge_result const & result, string & out) +dump_conflicts(roster_merge_result const & result, string & out) { + dump(result.multiple_name_conflicts, out); + dump(result.file_content_conflicts, out); + dump(result.attribute_conflicts, out); + dump(result.orphaned_node_conflicts, out); + dump(result.duplicate_name_conflicts, out); + dump(result.directory_loop_conflicts, out); + dump(result.invalid_name_conflicts, out); - // file content conflicts first - - out = (FL("unclean roster_merge: " - "%d multiple name conflicts, " - "%d content conflicts, " - "%d attribute conflicts, " - "%d orphaned node conflicts, " - "%d duplicate name conflicts, " - "%d directory loop conflicts\n") - % result.multiple_name_conflicts.size() - % result.file_content_conflicts.size() - % result.attribute_conflicts.size() - % result.orphaned_node_conflicts.size() - % result.duplicate_name_conflicts.size() - % result.directory_loop_conflicts.size()) - .str(); - - for (size_t i = 0; i < result.multiple_name_conflicts.size(); ++i) - out += (FL("multiple name conflict on node %d: [parent %d, self %s] vs. [parent %d, self %s]") - % result.multiple_name_conflicts[i].nid - % result.multiple_name_conflicts[i].left.first - % result.multiple_name_conflicts[i].left.second - % result.multiple_name_conflicts[i].right.first - % result.multiple_name_conflicts[i].right.second) - .str(); - - // put this first - - for (size_t i = 0; i < result.file_content_conflicts.size(); ++i) - out += (FL("content conflict on node %d: [%s] vs. [%s]") - % result.file_content_conflicts[i].nid - % result.file_content_conflicts[i].left - % result.file_content_conflicts[i].right) - .str(); - - for (size_t i = 0; i < result.attribute_conflicts.size(); ++i) - out += (FL("attribute conflict on node %d, key %s: [%d, %s] vs. [%d, %s]") - % result.attribute_conflicts[i].nid - % result.attribute_conflicts[i].key - % result.attribute_conflicts[i].left.first - % result.attribute_conflicts[i].left.second - % result.attribute_conflicts[i].right.first - % result.attribute_conflicts[i].right.second) - .str(); - - for (size_t i = 0; i < result.orphaned_node_conflicts.size(); ++i) - out += (FL("orphaned node conflict on node %d, dead parent %d, name %s") - % result.orphaned_node_conflicts[i].nid - % result.orphaned_node_conflicts[i].parent_name.first - % result.orphaned_node_conflicts[i].parent_name.second) - .str(); - - for (size_t i = 0; i < result.duplicate_name_conflicts.size(); ++i) - out += (FL("duplicate name conflict: nodes %d, %d, both want parent %d, name %s") - % result.duplicate_name_conflicts[i].left_nid - % result.duplicate_name_conflicts[i].right_nid - % result.duplicate_name_conflicts[i].parent_name.first - % result.duplicate_name_conflicts[i].parent_name.second) - .str(); - - for (size_t i = 0; i < result.directory_loop_conflicts.size(); ++i) - out += (FL("directory loop conflict: node %d, wanted parent %d, name %s") - % result.directory_loop_conflicts[i].nid - % result.directory_loop_conflicts[i].parent_name.first - % result.directory_loop_conflicts[i].parent_name.second) - .str(); - - for (size_t i = 0; i < result.invalid_name_conflicts.size(); ++i) - out += (FL("illegal name conflict: node %d, wanted parent %d, name %s") - % result.invalid_name_conflicts[i].nid - % result.invalid_name_conflicts[i].parent_name.first - % result.invalid_name_conflicts[i].parent_name.second) - .str(); - if (result.missing_root_dir) out += (FL("missing root conflict: root directory has been removed")).str(); - } template <> void dump(roster_merge_result const & result, string & out) { - debug_describe_conflicts(result, out); + dump_conflicts(result, out); + string roster_part; dump(result.roster, roster_part); out += "\n\n"; @@ -231,7 +161,7 @@ roster_merge_result::log_conflicts() con roster_merge_result::log_conflicts() const { string str; - debug_describe_conflicts(*this, str); + dump_conflicts(*this, str); L(FL("%s") % str); } @@ -254,11 +184,10 @@ namespace } } - void -roster_merge_result::warn_non_content_conflicts(roster_t const & left_roster, - roster_t const & right_roster, - content_merge_adaptor & adaptor) const +roster_merge_result::report_multiple_name_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const { // TODO: // - W on each conflict type and then P further details @@ -292,7 +221,63 @@ roster_merge_result::warn_non_content_co P(F("renamed to '%s' on the left") % left_name); P(F("renamed to '%s' on the right") % right_name); } +} +void +roster_merge_result::report_file_content_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ + MM(left_roster); + MM(right_roster); + + for (size_t i = 0; i < file_content_conflicts.size(); ++i) + { + file_content_conflict const & conflict = file_content_conflicts[i]; + MM(conflict); + + if (roster.is_attached(conflict.nid)) + { + file_path name; + roster.get_name(conflict.nid, name); + + P(F("conflict: content conflict on file '%s'") + % name); + P(F("content hash is %s on the left") % conflict.left); + P(F("content hash is %s on the right") % conflict.right); + } + else + { + // this node isn't attached in the merged roster and there + // isn't really a good name for it so report both the left + // and right names using a slightly different format + + file_path left_name, right_name; + left_roster.get_name(conflict.nid, left_name); + right_roster.get_name(conflict.nid, right_name); + + shared_ptr lca_roster; + revision_id lca_rid; + file_path lca_name; + + adaptor.get_ancestral_roster(conflict.nid, lca_rid, lca_roster); + lca_roster->get_name(conflict.nid, lca_name); + + P(F("conflict: content conflict on file '%s' from revision %s") + % lca_name % lca_rid); + P(F("content hash is %s on the left in file '%s'") + % conflict.left % left_name); + P(F("content hash is %s on the right in file '%s'") + % conflict.right % right_name); + } + } +} + +void +roster_merge_result::report_attribute_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ for (size_t i = 0; i < attribute_conflicts.size(); ++i) { attribute_conflict const & conflict = attribute_conflicts[i]; @@ -353,7 +338,13 @@ roster_merge_result::warn_non_content_co % type % right_name); } } +} +void +roster_merge_result::report_orphaned_node_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ for (size_t i = 0; i < orphaned_node_conflicts.size(); ++i) { orphaned_node_conflict const & conflict = orphaned_node_conflicts[i]; @@ -418,7 +409,13 @@ roster_merge_result::warn_non_content_co else I(false); } +} +void +roster_merge_result::report_duplicate_name_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ for (size_t i = 0; i < duplicate_name_conflicts.size(); ++i) { duplicate_name_conflict const & conflict = duplicate_name_conflicts[i]; @@ -487,7 +484,13 @@ roster_merge_result::warn_non_content_co else I(false); } +} +void +roster_merge_result::report_directory_loop_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ for (size_t i = 0; i < directory_loop_conflicts.size(); ++i) { directory_loop_conflict const & conflict = directory_loop_conflicts[i]; @@ -529,7 +532,13 @@ roster_merge_result::warn_non_content_co P(F("'%s' renamed to '%s' on the right") % lca_parent_name % right_parent_name); } +} +void +roster_merge_result::report_invalid_name_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ for (size_t i = 0; i < invalid_name_conflicts.size(); ++i) { invalid_name_conflict const & conflict = invalid_name_conflicts[i]; @@ -589,7 +598,13 @@ roster_merge_result::warn_non_content_co else I(false); } +} +void +roster_merge_result::report_missing_root_conflicts(roster_t const & left_roster, + roster_t const & right_roster, + content_merge_adaptor & adaptor) const +{ if (missing_root_dir) { node_id left_root, right_root; ============================================================ --- roster_merge.hh 34fd64bd0dc1ef9bf7158f71aeb69230caa0462e +++ roster_merge.hh 9110ec12f5d3d21a193067a1937b8d7c2d750546 @@ -111,20 +111,20 @@ struct invalid_name_conflict std::pair parent_name; }; -template <> void dump(multiple_name_conflict const & val, std::string & out); -template <> void dump(file_content_conflict const & val, std::string & out); -template <> void dump(attribute_conflict const & val, std::string & out); -template <> void dump(orphaned_node_conflict const & val, std::string & out); -template <> void dump(duplicate_name_conflict const & val, std::string & out); -template <> void dump(directory_loop_conflict const & val, std::string & out); -template <> void dump(invalid_name_conflict const & val, std::string & out); +template <> void dump(multiple_name_conflict const & conflict, std::string & out); +template <> void dump(file_content_conflict const & conflict, std::string & out); +template <> void dump(attribute_conflict const & conflict, std::string & out); +template <> void dump(orphaned_node_conflict const & conflict, std::string & out); +template <> void dump(duplicate_name_conflict const & conflict, std::string & out); +template <> void dump(directory_loop_conflict const & conflict, std::string & out); +template <> void dump(invalid_name_conflict const & conflict, std::string & out); struct roster_merge_result { // three main types of conflicts // - content conflicts // - attribute conflicts - // - tree layout conflicts (which have the following subtypes) + // - structural conflicts (which have the following subtypes) // - duplicate name conflicts // - multiple name conflicts // - orphaned node conflicts @@ -146,9 +146,32 @@ struct roster_merge_result bool has_content_conflicts() const; bool has_non_content_conflicts() const; void log_conflicts() const; - void warn_non_content_conflicts(roster_t const & left, + + void report_multiple_name_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void report_file_content_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void report_attribute_conflicts(roster_t const & left, roster_t const & right, content_merge_adaptor & adaptor) const; + void report_orphaned_node_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void report_duplicate_name_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void report_directory_loop_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void report_invalid_name_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void report_missing_root_conflicts(roster_t const & left, + roster_t const & right, + content_merge_adaptor & adaptor) const; + void clear(); }; ============================================================ --- sanity.hh 7c69292b7148dbd84d3f9a8924f791fca9a10682 +++ sanity.hh 5ba1f5f71bc2a3d6c53f27bb7bbcd896d3e8155f @@ -12,6 +12,7 @@ #include #include +#include #include "boost/current_function.hpp" @@ -435,6 +436,18 @@ template <> void dump(std::string const template <> void dump(std::string const & obj, std::string & out); +template void +dump(std::vector const & vec, std::string & out) +{ + for (size_t i = 0; i < vec.size(); ++i) + { + T const & val = vec[i]; + std::string msg; + dump(val, msg); + out += msg; + } +}; + // debugging utility to dump out vars like MM but without requiring a crash extern void print_var(std::string const & value, ============================================================ --- tests/conflict_messages/__driver__.lua fc66cec8d78d1c02e6e30824e058a1cce6b7dddd +++ tests/conflict_messages/__driver__.lua 32d64b7bea2cf1e7c1c98ad6a1579762a4f6e5b1 @@ -5,141 +5,157 @@ mtn_setup() --- divergent name conflict +-- multiple name conflict remove("_MTN") -check(mtn("setup", ".", "--branch", "divergent"), 0, false, false) +check(mtn("setup", ".", "--branch", "multiple"), 0, false, false) -addfile("foo", "divergent foo") -commit("divergent") +addfile("foo", "multiple foo") +commit("multiple") base = base_revision() check(mtn("mv", "foo", "bar"), 0, false, false) -commit("divergent") -other = base_revision() +commit("multiple") +first = base_revision() revert_to(base) check(mtn("mv", "foo", "baz"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: multiple names", "stderr")) -commit("divergent") +commit("multiple") +second = base_revision() -check(mtn("merge", "--branch", "divergent"), 1, false, true) +check(mtn("show_conflicts", first, second), 0, false, true) check(qgrep("conflict: multiple names", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("merge", "--branch", "multiple"), 1, false, true) check(qgrep("conflict: multiple names", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: multiple names", "stderr")) +check(mtn("merge_into_workspace", first), 1, false, true) +check(qgrep("conflict: multiple names", "stderr")) --- convergent name conflict (adds) +-- duplicate name conflict (adds) + remove("_MTN") -check(mtn("setup", ".", "--branch", "convergent-adds"), 0, false, false) +check(mtn("setup", ".", "--branch", "duplicate-adds"), 0, false, false) -addfile("foo", "convergent add foo") -commit("convergent-adds") +addfile("foo", "duplicate add foo") +commit("duplicate-adds") base = base_revision() -addfile("xxx", "convergent add xxx") -commit("convergent-adds") +addfile("xxx", "duplicate add xxx") +commit("duplicate-adds") check(mtn("mv", "xxx", "bar"), 0, false, false) ---addfile("bar", "convergent add bar1") -commit("convergent-adds") -other = base_revision() +--addfile("bar", "duplicate add bar1") +commit("duplicate-adds") +first = base_revision() revert_to(base) -addfile("bar", "convergent add bar2") +addfile("bar", "duplicate add bar2") -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) -commit("convergent-adds") +commit("duplicate-adds") +second = base_revision() -check(mtn("merge", "--branch", "convergent-adds"), 1, false, true) +check(mtn("show_conflicts", first, second), 0, false, true) check(qgrep("conflict: duplicate name", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("merge", "--branch", "duplicate-adds"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("merge_into_workspace", first), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) --- convergent name conflict (renames) +-- duplicate name conflict (renames) + remove("_MTN") -check(mtn("setup", ".", "--branch", "convergent-renames"), 0, false, false) +check(mtn("setup", ".", "--branch", "duplicate-renames"), 0, false, false) -addfile("foo", "convergent rename foo") -addfile("bar", "convergent rename bar") +addfile("foo", "duplicate rename foo") +addfile("bar", "duplicate rename bar") -commit("convergent-renames") +commit("duplicate-renames") base = base_revision() check(mtn("mv", "foo", "abc"), 0, false, false) -commit("convergent-renames") -other = base_revision() +commit("duplicate-renames") +first = base_revision() revert_to(base) check(mtn("mv", "bar", "abc"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) -commit("convergent-renames") +commit("duplicate-renames") +second = base_revision() -check(mtn("merge", "--branch", "convergent-renames"), 1, false, true) +check(mtn("show_conflicts", first, second), 0, false, true) check(qgrep("conflict: duplicate name", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("merge", "--branch", "duplicate-renames"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("merge_into_workspace", first), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) --- convergent name conflict (add-rename) +-- duplicate name conflict (add-rename) + remove("_MTN") -check(mtn("setup", ".", "--branch", "convergent-add-rename"), 0, false, false) +check(mtn("setup", ".", "--branch", "duplicate-add-rename"), 0, false, false) -addfile("foo", "convergent add rename foo") +addfile("foo", "duplicate add rename foo") -commit("convergent-add-rename") +commit("duplicate-add-rename") base = base_revision() check(mtn("mv", "foo", "bar"), 0, false, false) -commit("convergent-add-rename") -other = base_revision() +commit("duplicate-add-rename") +first = base_revision() revert_to(base) addfile("bar", "convervent add rename bar") -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) -commit("convergent-add-rename") +commit("duplicate-add-rename") +second = base_revision() -check(mtn("merge", "--branch", "convergent-add-rename"), 1, false, true) +check(mtn("show_conflicts", first, second), 0, false, true) check(qgrep("conflict: duplicate name", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("merge", "--branch", "duplicate-add-rename"), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: duplicate name", "stderr")) +check(mtn("merge_into_workspace", first), 1, false, true) +check(qgrep("conflict: duplicate name", "stderr")) + -- directory loop conflict remove("_MTN") @@ -157,24 +173,28 @@ commit("loop") check(mtn("mv", "foo", "bar"), 0, false, false) commit("loop") -other = base_revision() +first = base_revision() revert_to(base) check(mtn("mv", "bar", "foo"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: directory loop", "stderr")) commit("loop") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: directory loop", "stderr")) + check(mtn("merge", "--branch", "loop"), 1, false, true) check(qgrep("conflict: directory loop", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: directory loop", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: directory loop", "stderr")) @@ -196,25 +216,29 @@ commit("orphaned-add") check(mtn("mv", "foo/bar", "foo/baz"), 0, false, false) commit("orphaned-add") -other = base_revision() +first = base_revision() revert_to(base) remove("foo") check(mtn("drop", "--recursive", "foo"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) commit("orphaned-add") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: orphaned file", "stderr")) + check(mtn("merge", "--branch", "orphaned-add"), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) @@ -236,25 +260,29 @@ commit("orphaned-rename") commit("orphaned-rename") check(mtn("mv", "foo/bar", "foo/baz"), 0, false, false) commit("orphaned-rename") -other = base_revision() +first = base_revision() revert_to(base) remove("foo") check(mtn("drop", "--recursive", "foo"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) commit("orphaned-rename") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: orphaned file", "stderr")) + check(mtn("merge", "--branch", "orphaned-rename"), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: orphaned file", "stderr")) @@ -273,24 +301,28 @@ check(indir("invalid", mtn("commit", "-- check(indir("invalid", mtn("pivot_root", "foo", "bar")), 0, true, true) check(indir("invalid", mtn("commit", "--message", "commit")), 0, false, false) -other = indir("invalid", {base_revision})[1]() +first = indir("invalid", {base_revision})[1]() mkdir("foo/_MTN") addfile("foo/_MTN/foo", "invalid foo") addfile("foo/_MTN/bar", "invalid bar") -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) commit("invalid-add") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: invalid name", "stderr")) + check(mtn("merge", "--branch", "invalid-add"), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) @@ -311,22 +343,26 @@ check(indir("invalid", mtn("commit", "-- check(mtn("co", "--branch", "invalid-rename", "invalid"), 0, false, false) check(indir("invalid", mtn("pivot_root", "foo", "bar")), 0, true, true) check(indir("invalid", mtn("commit", "--message", "commit")), 0, false, false) -other = indir("invalid", {base_revision})[1]() +first = indir("invalid", {base_revision})[1]() check(mtn("mv", "bad/_MTN", "foo/_MTN"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) commit("invalid-rename") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: invalid name", "stderr")) + check(mtn("merge", "--branch", "invalid-rename"), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: invalid name", "stderr")) @@ -347,22 +383,26 @@ check(indir("missing", mtn("commit", "-- --check(indir("missing", mtn("drop", "--recursive", "bar")), 0, true, true) check(indir("missing", mtn("commit", "--message", "commit")), 0, false, false) -other = indir("missing", {base_revision})[1]() +first = indir("missing", {base_revision})[1]() check(mtn("drop", "--recursive", "foo"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: missing root directory", "stderr")) commit("missing") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: missing root directory", "stderr")) + check(mtn("merge", "--branch", "missing"), 1, false, true) check(qgrep("conflict: missing root directory", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: missing root directory", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: missing root directory", "stderr")) @@ -382,25 +422,29 @@ commit("attribute-attached") check(mtn("attr", "set", "foo", "attr1", "valueX"), 0, false, false) check(mtn("attr", "set", "foo", "attr2", "valueY"), 0, false, false) commit("attribute-attached") -other = base_revision() +first = base_revision() revert_to(base) check(mtn("attr", "set", "foo", "attr1", "valueZ"), 0, false, false) check(mtn("attr", "drop", "foo", "attr2"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) commit("attribute-attached") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + check(mtn("merge", "--branch", "attribute-attached"), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) @@ -421,7 +465,7 @@ commit("attribute-detached") check(mtn("attr", "set", "foo", "attr2", "valueY"), 0, false, false) check(mtn("mv", "foo", "bar"), 0, false, false) commit("attribute-detached") -other = base_revision() +first = base_revision() revert_to(base) @@ -429,16 +473,97 @@ check(mtn("mv", "foo", "baz"), 0, false, check(mtn("attr", "drop", "foo", "attr2"), 0, false, false) check(mtn("mv", "foo", "baz"), 0, false, false) -check(mtn("update"), 1, false, true) +check(mtn("update", "--debug"), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) commit("attribute-detached") +second = base_revision() +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: multiple values for attribute", "stderr")) + check(mtn("merge", "--branch", "attribute-detached"), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) -check(mtn("pluck", "--revision", base, "--revision", other), 1, false, true) +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) -check(mtn("merge_into_workspace", other), 1, false, true) +check(mtn("merge_into_workspace", first), 1, false, true) check(qgrep("conflict: multiple values for attribute", "stderr")) + + +-- content conflict on attached node + +remove("_MTN") +check(mtn("setup", ".", "--branch", "content-attached"), 0, false, false) +remove("foo") + +addfile("foo", "content foo attached") +commit("content-attached") +base = base_revision() + +writefile("foo", "foo first revision") +commit("content-attached") +first = base_revision() + +revert_to(base) + +writefile("foo", "foo second revision") + +check(mtn("update", "--debug"), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +commit("content-attached") +second = base_revision() + +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +check(mtn("merge", "--branch", "content-attached"), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +check(mtn("merge_into_workspace", first), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + + +-- content conflict on detached node + +remove("_MTN") +check(mtn("setup", ".", "--branch", "content-detached"), 0, false, false) +remove("foo") + +addfile("foo", "content foo detached") +commit("content-detached") +base = base_revision() + +writefile("foo", "foo first revision") +check(mtn("mv", "foo", "bar"), 0, false, false) + +commit("content-detached") +first = base_revision() + +revert_to(base) + +writefile("foo", "foo second revision") +check(mtn("mv", "foo", "baz"), 0, false, false) + +check(mtn("update", "--debug"), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +commit("content-detached") +second = base_revision() + +check(mtn("show_conflicts", first, second), 0, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +check(mtn("merge", "--branch", "content-detached"), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +check(mtn("pluck", "--revision", base, "--revision", first), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr")) + +check(mtn("merge_into_workspace", first), 1, false, true) +check(qgrep("conflict: content conflict on file", "stderr"))