# # # add_dir "tests/automate_file_merge" # # add_dir "tests/resolve_conflicts_all_merge_commands" # # add_file "tests/automate_file_merge/__driver__.lua" # content [b3f8fc5291e23981a76c9c30352978ae1127d488] # # add_file "tests/resolve_conflicts_all_merge_commands/__driver__.lua" # content [d544bcdd64081b676047e33257159bcecc88329b] # # patch "cmd_merging.cc" # from [88fd8e589c2fbbf1d0eed179260bdafbdf12f77b] # to [17336c78322596cd4cbce0492c646acf9fcf9ded] # # patch "monotone.texi" # from [2f6f14a68447e9b3418c328cd350db9c54c0d616] # to [4f79edcde5ea9be779fe3651ec9390585bba4612] # # patch "roster_merge.cc" # from [2904442eb8835e76182b01daed84ac42f16bc258] # to [0b686863088ab9897a3412e0feb7041d0accf527] # # patch "roster_merge.hh" # from [8f0603774befb2458b9e6a2660a90f31104a9a22] # to [4ec07d04f5be97555137df722f44f990aa560a91] # # patch "tests/automate_show_conflicts/expected-content-attached.stdout" # from [6c39a0131b22693f4086fb68970e827a3241a287] # to [ceb9cfaedb114a93f123024bb477148f1c0c5bd4] # # patch "tests/resolve_content_conflict/__driver__.lua" # from [96bf801b85023fa84035c19133bd3f6fc339a7e1] # to [abb091bca68a0823b1636225d3f40069d539b986] # # patch "tests/resolve_content_conflict/conflicts-1" # from [d0d2e52fdf8329d3cf0ba5644454a931a30cacf2] # to [a22968fd0a299175d4444e778b712bbcf8a4377a] # # patch "tests/resolve_content_conflict/merge-1" # from [8ab8aad3487a1e247c5edcb01f5f50813f01fa07] # to [a1052f7f29160f099cd7781b8c4f4feabeba0551] # # patch "tests/resolve_content_conflict/resolve-conflicts-1" # from [8651ee547db93b1ee41e0ee6309144d4e955b9cc] # to [3eb53a39fb89990b37289518600c27530a2f543f] # # patch "tests/resolve_content_conflict/update-1" # from [4ee9b94a8bc3f20abd7191ea65cbb7cf85ab46c6] # to [b0c1d97b8941efb8fae0cbc51b76db27d6ee91e6] # # patch "tests/resolve_duplicate_name_conflict/__driver__.lua" # from [fd81c83e6371e4065e784cb8dbf3b2bdf0c0d0cb] # to [3d62e380338471ba08f7a7fb7b186bbfa259ba76] # ============================================================ --- tests/automate_file_merge/__driver__.lua b3f8fc5291e23981a76c9c30352978ae1127d488 +++ tests/automate_file_merge/__driver__.lua b3f8fc5291e23981a76c9c30352978ae1127d488 @@ -0,0 +1,38 @@ +-- Test automate file_merge + +mtn_setup() + +addfile("foo", "foo") +addfile("bar", "bar\none\ntwo\nthree") +addfile("baz", "baz\naaa\nbbb\nccc") +commit("testbranch", "base") +base = base_revision() + +writefile("foo", "foo\nfirst\nrevision") +writefile("bar", "bar\nzero\none\ntwo\nthree") +writefile("baz", "baz\nAAA\nbbb\nccc") +commit("testbranch", "first") +first = base_revision() + +revert_to(base) + +writefile("foo", "foo\nsecond\nrevision") +writefile("bar", "bar\none\ntwo\nthree\nfour") +writefile("baz", "baz\naaa\nbbb\nCCC") +commit("testbranch", "second") +second = base_revision() + +check(mtn("automate", "file_merge", first, "foo", second, "foo"), 1, nil, true) +check(qgrep("internal line merger failed", "stderr")) + +writefile("expected_bar", "bar\nzero\none\ntwo\nthree\nfour\n") +check(mtn("automate", "file_merge", first, "bar", second, "bar"), 0, true, nil) +canonicalize("stdout") +check(samefile("expected_bar", "stdout")) + +writefile("expected_baz", "baz\nAAA\nbbb\nCCC\n") +check(mtn("automate", "file_merge", first, "baz", second, "baz"), 0, true, nil) +canonicalize("stdout") +check(samefile("expected_baz", "stdout")) + +-- end of file ============================================================ --- tests/resolve_conflicts_all_merge_commands/__driver__.lua d544bcdd64081b676047e33257159bcecc88329b +++ tests/resolve_conflicts_all_merge_commands/__driver__.lua d544bcdd64081b676047e33257159bcecc88329b @@ -0,0 +1,68 @@ +-- Demonstrate that all merge commands support --resolve-conflicts. +-- +-- We don't explicitly test --resolve-conflicts-file, because that is +-- handled by the same code, and other tests show it works. +-- +-- See other resolve_conflicts_* tests for individual conflict +-- resolutions. + +-- The test structure is borrowed from ../conflict_messages/__driver__.lua + +-- Note that 'propagate' is implemented by calling 'merge_into_dir', +-- so we don't need to test the latter explicitly. + +mtn_setup() + +function setup(branch) + remove("_MTN") + remove("foo") + remove("bar") + remove("baz") + remove(branch) + check(mtn("setup", ".", "--branch", branch), 0, false, false) +end + +function merged_revision() + local workrev = readfile("stderr") + local extract = string.gsub(workrev, "^.*mtn: %[merged%] (%x*).*$", "%1") + if extract == workrev then + err("failed to extract merged revision from stderr") + end + return extract +end + +branch = "content-attached" +resolution = "resolved_user \"foo\"" +setup(branch) + +addfile("foo", branch .. "-foo") +commit(branch) +base = base_revision() + +writefile("foo", branch .. "-foo first revision") +commit(branch) +first = base_revision() + +revert_to(base) + +writefile("foo", branch .. "-foo second revision") + +commit(branch .. "-propagate") +second = base_revision() + +check(mtn("propagate", branch , branch .. "-propagate", "--resolve-conflicts", resolution), 0, nil, true) +merged = merged_revision() +check(mtn("db", "kill_rev_locally", merged), 0, nil, true) + +check(mtn("explicit_merge", first, second, branch, "--resolve-conflicts", resolution), 0, nil, true) +merged = merged_revision() +check(mtn("db", "kill_rev_locally", merged), 0, nil, true) + +-- create a second head on 'branch' +writefile("foo", branch .. "-foo third revision") +commit(branch) +check(mtn("merge", "--branch", branch, "--resolve-conflicts", resolution), 0, nil, true) +merged = merged_revision() +check(mtn("db", "kill_rev_locally", merged), 0, nil, true) + +-- end of file ============================================================ --- cmd_merging.cc 88fd8e589c2fbbf1d0eed179260bdafbdf12f77b +++ cmd_merging.cc 17336c78322596cd4cbce0492c646acf9fcf9ded @@ -143,8 +143,7 @@ CMD(update, "update", "", CMD_REF(worksp "different revision, preserving uncommitted changes as it does so. " "If a revision is given, update the workspace to that revision. " "If not, update the workspace to the head of the branch."), - options::opts::branch | options::opts::revision | - options::opts::resolve_conflicts_opts) + options::opts::branch | options::opts::revision) { if (args.size() > 0) throw usage(execid); @@ -282,7 +281,6 @@ CMD(update, "update", "", CMD_REF(worksp content_merge_workspace_adaptor wca(db, old_rid, old_roster, left_markings, right_markings, paths); wca.cache_roster(working_rid, working_roster); - // FIXME_RESOLVE_CONFLICTS: add conflict resolutions here resolve_merge_conflicts(app.lua, *working_roster, chosen_roster, result, wca, false); @@ -652,7 +650,7 @@ CMD(merge_into_dir, "merge_into_dir", "" parse_resolve_conflicts_opts (app.opts, left_roster, right_roster, result, resolutions_given); resolve_merge_conflicts(app.lua, left_roster, right_roster, - result, dba, false); + result, dba, resolutions_given); { dir_t moved_root = left_roster.root(); @@ -695,8 +693,7 @@ CMD(merge_into_workspace, "merge_into_wo "pending changes in the current workspace. Both OTHER-REVISION and " "the workspace's base revision will be recorded as parents on commit. " "The workspace's selected branch is not changed."), - options::opts::none | - options::opts::resolve_conflicts_opts) + options::opts::none) { revision_id left_id, right_id; cached_roster left, right; @@ -767,7 +764,6 @@ CMD(merge_into_workspace, "merge_into_wo content_merge_workspace_adaptor wca(db, lca_id, lca.first, *left.second, *right.second, paths); wca.cache_roster(working_rid, working_roster); - // FIXME_RESOLVE_CONFLICTS: add conflict resolutions here resolve_merge_conflicts(app.lua, *left.first, *right.first, merge_result, wca, false); // Make sure it worked... @@ -1006,6 +1002,63 @@ CMD_AUTOMATE(show_conflicts, N_("[LEFT_R show_conflicts_core(db, app.lua, l_id, r_id, true, output); } +CMD_AUTOMATE(file_merge, N_("[LEFT_REVID LEFT_FILENAME RIGHT_REVID RIGHT_FILENAME]"), + N_("Prints the results of the internal line merger, given two child revisions and file names"), + "", + options::opts::none) +{ + // We would have liked to take arguments of ancestor, left, right revision + // and file ids; those are provided by show_conflicts and would save + // computing the common ancestor and searching for file names. But we need + // the file names to get the manual merge and file encoding attributes, + // and there is no way to go from file id to file name. And there is no + // way to specify the ancestor id for a merge adaptor; why should we trust + // the user? + + N(args.size() == 4, + F("wrong argument count")); + + database db(app); + project_t project(db); + + revision_id left_rid; + complete(app.opts, app.lua, project, idx(args,0)(), left_rid); + file_path const left_path = file_path_external(idx(args,1)); + + revision_id right_rid; + complete(app.opts, app.lua, project, idx(args,2)(), right_rid); + file_path const right_path = file_path_external(idx(args,3)); + + roster_t left_roster; + roster_t right_roster; + marking_map left_marking, right_marking; + db.get_roster(left_rid, left_roster, left_marking); + db.get_roster(right_rid, right_roster, right_marking); + + content_merge_database_adaptor adaptor(db, left_rid, right_rid, + left_marking, right_marking); + + file_t left_n = downcast_to_file_t(left_roster.get_node(left_path)); + file_t right_n = downcast_to_file_t(right_roster.get_node(right_path)); + + revision_id ancestor_rid; + file_path ancestor_path; + file_id ancestor_fid; + shared_ptr ancestor_roster; + adaptor.get_ancestral_roster(left_n->self, ancestor_rid, ancestor_roster); + ancestor_roster->get_file_details(left_n->self, ancestor_fid, ancestor_path); + + content_merger cm(app.lua, *ancestor_roster, left_roster, right_roster, adaptor); + file_data ancestor_data, left_data, right_data, merge_data; + + N(cm.attempt_auto_merge(ancestor_path, left_path, right_path, + ancestor_fid, left_n->content, right_n->content, + left_data, right_data, merge_data), + F("internal line merger failed")); + + output << merge_data; +} + CMD(pluck, "pluck", "", CMD_REF(workspace), N_("[-r FROM] -r TO [PATH...]"), N_("Applies changes made at arbitrary places in history"), N_("This command takes changes made at any point in history, and " @@ -1017,8 +1070,7 @@ CMD(pluck, "pluck", "", CMD_REF(workspac "compared to its parent.\n" "If two revisions are given, applies the changes made to get from the " "first revision to the second."), - options::opts::revision | options::opts::depth | options::opts::exclude | - options::opts::resolve_conflicts_opts) + options::opts::revision | options::opts::depth | options::opts::exclude) { database db(app); workspace work(app); @@ -1148,7 +1200,6 @@ CMD(pluck, "pluck", "", CMD_REF(workspac // to_roster is not fetched from the db which does not have temporary nids wca.cache_roster(to_rid, to_roster); - // FIXME_RESOLVE_CONFLICTS: add conflict resolutions here resolve_merge_conflicts(app.lua, *working_roster, *to_roster, result, wca, false); ============================================================ --- monotone.texi 2f6f14a68447e9b3418c328cd350db9c54c0d616 +++ monotone.texi 4f79edcde5ea9be779fe3651ec9390585bba4612 @@ -8026,6 +8026,49 @@ @section Automation @end table address@hidden mtn automate file_merge @var{left-rid} @var{left-path} @var{right-rid} @var{right-path} + address@hidden @strong address@hidden Arguments: + address@hidden, @var{left-fid}, @var{right-rid}, @var{right-fid} +specify two files to merge, by revision and file path. + address@hidden Added in: + +8.0 + address@hidden Purpose: + +Prints the result of the internal line merge on the contents of the +specified files. + +This command does not just take two file ids, because the revision ids +and paths are needed to check for manual merge and file encoding +attributes. + address@hidden Sample output: + address@hidden +If you've downloaded a release, see INSTALL for installation +instructions. If you've checked this out, the generated files are not +included, and you must use "autoreconf --install" to create them. + +"make html" for docs, or read the .info file and / or man page. address@hidden verbatim + address@hidden Output format: + +The file merge results are output without modification. + address@hidden Error conditions: + +If either file id is unknown or invalid, or if the internal line +merger fails, prints an error message to stderr and exits with status +1. + address@hidden table + @item mtn automate get_option @var{option} @table @strong ============================================================ --- roster_merge.cc 2904442eb8835e76182b01daed84ac42f16bc258 +++ roster_merge.cc 0b686863088ab9897a3412e0feb7041d0accf527 @@ -507,7 +507,7 @@ put_content_conflict (basic_io::stanza & break; case resolve_conflicts::content_user: - st.push_file_pair(syms::resolved_user, conflict.resolution.second); + st.push_str_pair(syms::resolved_user, conflict.resolution.second); break; default: @@ -1385,7 +1385,7 @@ roster_merge_result::report_file_content basic_io::stanza st; if (auto_merge_succeeds(lua, conflict, adaptor, left_roster, right_roster)) - conflict.resolution = make_pair(resolve_conflicts::content_internal, file_path()); + conflict.resolution = make_pair(resolve_conflicts::content_internal, std::string()); st.push_str_pair(syms::conflict, syms::content); put_content_conflict (st, left_roster, right_roster, adaptor, conflict); @@ -1505,14 +1505,15 @@ parse_duplicate_name_conflicts(basic_io: { conflict.left_resolution.first = resolve_conflicts::rename; pars.sym(); - conflict.left_resolution.second = file_path_internal (pars.token); + // File path is specified by the user, so it's an external string. + conflict.left_resolution.second = file_path_external (utf8(pars.token)); pars.str(); } else if (pars.symp (syms::resolved_rename_right)) { conflict.right_resolution.first = resolve_conflicts::rename; pars.sym(); - conflict.right_resolution.second = file_path_internal (pars.token); + conflict.right_resolution.second = file_path_external (utf8(pars.token)); pars.str(); } else @@ -1579,7 +1580,7 @@ parse_file_content_conflicts(basic_io::p { conflict.resolution.first = resolve_conflicts::content_user; pars.sym(); - conflict.resolution.second = file_path_internal (pars.token); + conflict.resolution.second = pars.token; pars.str(); } else @@ -1619,7 +1620,7 @@ parse_resolve_conflicts_str(basic_io::pa conflict.left_resolution.first = resolve_conflicts::rename; pars.sym(); - conflict.left_resolution.second = file_path_internal (pars.token); + conflict.left_resolution.second = file_path_external (utf8(pars.token)); pars.str(); } else if (pars.symp (syms::resolved_rename_right)) @@ -1631,7 +1632,7 @@ parse_resolve_conflicts_str(basic_io::pa conflict.right_resolution.first = resolve_conflicts::rename; pars.sym(); - conflict.right_resolution.second = file_path_internal (pars.token); + conflict.right_resolution.second = file_path_external (utf8(pars.token)); pars.str(); } else if (pars.symp (syms::resolved_user)) @@ -1643,7 +1644,7 @@ parse_resolve_conflicts_str(basic_io::pa conflict.resolution.first = resolve_conflicts::content_user; pars.sym(); - conflict.resolution.second = file_path_internal (pars.token); + conflict.resolution.second = pars.token; pars.str(); } else @@ -1869,7 +1870,19 @@ roster_merge_result::resolve_file_conten data result_raw_data; adaptor.get_version(conflict.left, left_data); adaptor.get_version(conflict.right, right_data); - read_data(conflict.resolution.second, result_raw_data); + + // FIXME: there aught to be a simpler way to read an arbitrary file! + if (bookkeeping_path::external_string_is_bookkeeping_path(utf8(conflict.resolution.second))) + { + bookkeeping_path p(conflict.resolution.second); + read_data(p, result_raw_data); + } + else + { + file_path p(file_path_external(utf8(conflict.resolution.second))); + read_data(p, result_raw_data); + } + result_data = file_data(result_raw_data); calculate_ident(result_data, result_id); ============================================================ --- roster_merge.hh 8f0603774befb2458b9e6a2660a90f31104a9a22 +++ roster_merge.hh 4ec07d04f5be97555137df722f44f990aa560a91 @@ -121,14 +121,18 @@ struct file_content_conflict { node_id nid; file_id left, right; - std::pair resolution; + // The second item is a file path. We don't use type 'file_path' because + // that can't be in _MTN. We don't specify 'bookkeeping_path' because that + // _must_ be in _MTN. We want users to have a choice of workflow. This is + // local data only, so it is in system encoding. + std::pair resolution; file_content_conflict () : nid(the_null_node), - resolution(std::make_pair(resolve_conflicts::none, file_path())) {}; + resolution(std::make_pair(resolve_conflicts::none, std::string())) {}; file_content_conflict(node_id nid) : - nid(nid), resolution(std::make_pair(resolve_conflicts::none, file_path())) {}; + nid(nid), resolution(std::make_pair(resolve_conflicts::none, std::string())) {}; }; template <> void dump(invalid_name_conflict const & conflict, std::string & out); ============================================================ --- tests/automate_show_conflicts/expected-content-attached.stdout 6c39a0131b22693f4086fb68970e827a3241a287 +++ tests/automate_show_conflicts/expected-content-attached.stdout ceb9cfaedb114a93f123024bb477148f1c0c5bd4 @@ -2,23 +2,25 @@ ancestor [7d854bf031420b7a5c1cafcb908f10 right [49d6a10f5f09b064a35f1700966795ae698f0555] ancestor [7d854bf031420b7a5c1cafcb908f1020593196a8] - conflict content - node_type "file" - ancestor_name "bar" -ancestor_file_id [f0ef49fe92167fe2a086588019ffcff7ea561786] - left_name "bar" - left_file_id [08cd878106a93ce2ef036a32499c1432adb3ee0d] - right_name "bar" - right_file_id [0cf419dd93d38b2daaaf1f5e0f3ec647745b9690] + conflict content + node_type "file" + ancestor_name "bar" + ancestor_file_id [f0ef49fe92167fe2a086588019ffcff7ea561786] + left_name "bar" + left_file_id [08cd878106a93ce2ef036a32499c1432adb3ee0d] + right_name "bar" + right_file_id [0cf419dd93d38b2daaaf1f5e0f3ec647745b9690] +resolved_internal - conflict content - node_type "file" - ancestor_name "baz" -ancestor_file_id [55320c8cee4b87edb47ec6d7e678af53eed2c717] - left_name "baz" - left_file_id [4ba6aabe8949871079bb70b5ae0cd64d502def46] - right_name "baz" - right_file_id [ac923b3bc65d6638cdee243bd46b57d3e14ce4ee] + conflict content + node_type "file" + ancestor_name "baz" + ancestor_file_id [55320c8cee4b87edb47ec6d7e678af53eed2c717] + left_name "baz" + left_file_id [4ba6aabe8949871079bb70b5ae0cd64d502def46] + right_name "baz" + right_file_id [ac923b3bc65d6638cdee243bd46b57d3e14ce4ee] +resolved_internal conflict content node_type "file" ============================================================ --- tests/resolve_content_conflict/__driver__.lua 96bf801b85023fa84035c19133bd3f6fc339a7e1 +++ tests/resolve_content_conflict/__driver__.lua abb091bca68a0823b1636225d3f40069d539b986 @@ -17,7 +17,7 @@ writefile("bar", "bar\none\ntwo\nthree\n writefile("foo", "foo\nsecond\nrevision") writefile("bar", "bar\none\ntwo\nthree\nfour") -writefile("baz", "baz\naaa\nbbb\nCCC") +writefile("baz", "baz\nAaa\nbbb\nCCC") commit("testbranch", "second") second = base_revision() @@ -26,7 +26,11 @@ writefile("foo", "foo\nmerged\nrevision" check(samefilestd("conflicts-1", "stdout")) writefile("foo", "foo\nmerged\nrevision") +mkdir("_MTN/result") +writefile("_MTN/result/baz", "baz\nAaa\nBbb\nCcc") +-- foo and baz can't be handled by the internal line merger. We +-- specify one user file in _MTN, one out, to ensure mtn handles both. check(get("resolve-conflicts-1", "_MTN/conflicts")) check(mtn("merge", "--resolve-conflicts-file=_MTN/conflicts"), 0, nil, true) canonicalize("stderr") @@ -38,5 +42,5 @@ check(readfile("bar") == "bar\nzero\none check(readfile("foo") == "foo\nmerged\nrevision") check(readfile("bar") == "bar\nzero\none\ntwo\nthree\nfour\n") -check(readfile("baz") == "baz\nAAA\nbbb\nCCC\n") +check(readfile("baz") == "baz\nAaa\nBbb\nCcc") -- end of file ============================================================ --- tests/resolve_content_conflict/conflicts-1 d0d2e52fdf8329d3cf0ba5644454a931a30cacf2 +++ tests/resolve_content_conflict/conflicts-1 a22968fd0a299175d4444e778b712bbcf8a4377a @@ -1,5 +1,5 @@ left [c28c3c0f5a7f9cde848be91f79d86a6dd63e88ca] - right [9340b41fa26b20293292cb37449cc722b1b55a5a] + right [92bba9973b061f3617638edbc32610f7712b7a51] ancestor [4c059d3a8bbe8e624e46a50b298b4f301caf380d] conflict content @@ -12,15 +12,14 @@ resolved_internal right_file_id [5fd4e3cf64e24e969cfcd2380cf244aee9e52d5d] resolved_internal - conflict content - node_type "file" - ancestor_name "baz" - ancestor_file_id [ae708173915e11248629c18d16c96c3a34f87d16] - left_name "baz" - left_file_id [c438704db55b0d6f819e7e79c1622e5d757b926b] - right_name "baz" - right_file_id [f0ef173c31428d85dcca6399de12c6352f8b72b3] -resolved_internal + conflict content + node_type "file" + ancestor_name "baz" +ancestor_file_id [ae708173915e11248629c18d16c96c3a34f87d16] + left_name "baz" + left_file_id [c438704db55b0d6f819e7e79c1622e5d757b926b] + right_name "baz" + right_file_id [b87f48c43f61d258cc0b12d07bd53a7ddde357a9] conflict content node_type "file" ============================================================ --- tests/resolve_content_conflict/merge-1 8ab8aad3487a1e247c5edcb01f5f50813f01fa07 +++ tests/resolve_content_conflict/merge-1 a1052f7f29160f099cd7781b8c4f4feabeba0551 @@ -1,10 +1,10 @@ mtn: calculating best pair of heads to m mtn: 2 heads on branch 'testbranch' mtn: merge 1 / 1: mtn: calculating best pair of heads to merge next -mtn: [left] 9340b41fa26b20293292cb37449cc722b1b55a5a +mtn: [left] 92bba9973b061f3617638edbc32610f7712b7a51 mtn: [right] c28c3c0f5a7f9cde848be91f79d86a6dd63e88ca mtn: merged bar, bar -mtn: merged baz, baz +mtn: replacing content of baz, baz with _MTN/result/baz mtn: replacing content of foo, foo with foo -mtn: [merged] c63027af0230a9bf587088ec08fd60318308730d +mtn: [merged] ad3e91f197b102b27435049513a87778550dfd89 mtn: note: your workspaces have not been updated ============================================================ --- tests/resolve_content_conflict/resolve-conflicts-1 8651ee547db93b1ee41e0ee6309144d4e955b9cc +++ tests/resolve_content_conflict/resolve-conflicts-1 3eb53a39fb89990b37289518600c27530a2f543f @@ -10,7 +10,7 @@ ancestor [4c059d3a8bbe8e624e46a50b298b4f left_file_id [bf227d19bccee7740bb58219910ff0930b6200c1] right_name "bar" right_file_id [5fd4e3cf64e24e969cfcd2380cf244aee9e52d5d] -resolved_internal +resolved_internal conflict content node_type "file" @@ -20,7 +20,7 @@ resolved_internal left_file_id [c438704db55b0d6f819e7e79c1622e5d757b926b] right_name "baz" right_file_id [f0ef173c31428d85dcca6399de12c6352f8b72b3] -resolved_internal +resolved_user "_MTN/result/baz" conflict content node_type "file" ============================================================ --- tests/resolve_content_conflict/update-1 4ee9b94a8bc3f20abd7191ea65cbb7cf85ab46c6 +++ tests/resolve_content_conflict/update-1 b0c1d97b8941efb8fae0cbc51b76db27d6ee91e6 @@ -1,7 +1,7 @@ mtn: updating along branch 'testbranch' mtn: updating along branch 'testbranch' -mtn: selected update target c63027af0230a9bf587088ec08fd60318308730d -mtn: [left] 834637991b7d5e28d893a4e29285b20442d87225 -mtn: [right] c63027af0230a9bf587088ec08fd60318308730d +mtn: selected update target ad3e91f197b102b27435049513a87778550dfd89 +mtn: [left] 97cdd788b32b8b7c3a43883a39ff8e213960eb42 +mtn: [right] ad3e91f197b102b27435049513a87778550dfd89 mtn: modifying bar mtn: modifying baz -mtn: updated to base revision c63027af0230a9bf587088ec08fd60318308730d +mtn: updated to base revision ad3e91f197b102b27435049513a87778550dfd89 ============================================================ --- tests/resolve_duplicate_name_conflict/__driver__.lua fd81c83e6371e4065e784cb8dbf3b2bdf0c0d0cb +++ tests/resolve_duplicate_name_conflict/__driver__.lua 3d62e380338471ba08f7a7fb7b186bbfa259ba76 @@ -30,40 +30,55 @@ beth_1 = base_revision() beth_1 = base_revision() -- This fails due to duplicate name conflicts -check(mtn("merge"), 1, false, false) +check(mtn("merge"), 1, nil, false) -- Beth fixes the conflicts. -- -- For checkout.sh, she retrieves Abe's version to merge with hers, --- using 'automate get_file_of'. This requires knowing the revision id +-- using 'automate get_file'. This requires knowing the file id -- of Abe's commit, which we get from 'automate show_conflicts'. +-- +-- mtn is not up to actually doing the merge of checkout.sh yet (that +-- requires sutures), so we specify a conflict resolution that drops +-- Abe's version and keeps Beth's manual merge. -- --- For thermostat.c, she renames her version, letting Abe rename his. +-- For thermostat.c, she specifies a conflict resolution that renames +-- both versions. -check (mtn("automate", "show_conflicts"), 0, true, false) -parsed = parse_basic_io(readfile("stdout")) +check (mtn("automate", "show_conflicts"), 0, true, nil) +canonicalize("stdout") +check(samefilestd("conflicts-1", "stdout")) --- The Lua parser returns the 'conflict ' line as two lines --- with no values, so the line count here seems odd. -check_basic_io_line (1, parsed[1], "left", abe_1) -- 1337.. -check_basic_io_line (2, parsed[2], "right", beth_1) -- d5f1.. -check_basic_io_line (3, parsed[3], "ancestor", base) +-- Save the conflicts file so we can edit it later +mkdir("resolutions") +rename("stdout", "resolutions/conflicts") -check_basic_io_line (8, parsed[8], "left_file_id", "61b8d4fb0e5d78be111f691b955d523c782fa92e") +-- Retrieve Abe's version of checkout.sh, and pretend we did a manual +-- merge, using our favorite merge tool. We put the files outside the +-- workspace, so 'update' doesn't complain. +check(mtn("automate", "get_file", "61b8d4fb0e5d78be111f691b955d523c782fa92e"), 0, true, nil) +rename("stdout", "resolutions/checkout.sh-abe") +check(readfile("resolutions/checkout.sh-abe") == "checkout.sh abe 1") --- mtn is not up to actually doing the merge of checkout.sh yet, so we --- just drop beth's version +writefile("resolutions/checkout.sh", "checkout.sh beth 2") -check (mtn ("drop", "checkout.sh"), 0, false, false) -check (mtn ("rename", "thermostat.c", "thermostat-honeywell.c"), 0, false, false) -commit() +-- 'resolve_conflict' specifies a resolution for the first unresolved +-- conflict in the file. +resolution = "resolved_drop_left\n resolved_user_right \"resolutions/checkout.sh\"" +check(mtn("resolve_conflict", "resolutions/conflicts", resolution), 0, nil, nil) +resolution = "resolved_rename_left \"thermostat-westinghouse.c\"\n resolved_rename_right \"thermostat-honeywell.c\"" +check(mtn("resolve_conflict", "resolutions/conflicts", resolution), 0, nil, nil) + +check(samefilestd("conflicts-2", "resolutions/conflicts")) + -- This succeeds -check(mtn("merge"), 0, false, false) +check(mtn("merge", "--resolve-conflicts-file", "resolutions/conflicts"), 0, true, nil) +canonicalize("stdout") +check(samefilestd("merge-1", "stdout")) -check(mtn("update"), 0, false, false) +check(mtn("update"), 0, nil, false) -check("checkout.sh abe 1" == readfile("checkout.sh")) +check("checkout.sh beth 2" == readfile("checkout.sh")) -- end of file -