# # # patch "cmd_list.cc" # from [f7c5a9b2e25b2844298957bed0e3fe8cdaf2618f] # to [e3b9fe24c7b0aa279113cfbc2fe6ad504013e2dc] # # patch "cmd_ws_commit.cc" # from [de9046ac0c7db82e46c4369f4c8413085eef6f41] # to [05dc686d75988aba3d5d9abfce6d5eacd42ee1ae] # # patch "revision.cc" # from [82fd3fbadae41518da08611c887c7a323ebf4fdd] # to [19dcc24d7b030f67d63819674d1e218c95c77cf0] # # patch "revision.hh" # from [61f99762bde409557c3acbe6bcc89efe66e2f789] # to [13ef420b76868de35dca3208102304daa2d4593e] # # patch "tests/two_parent_workspace_commands_that_fail/__driver__.lua" # from [46ab6700635529ab40a24d2df3a79053bc7eeafe] # to [b93321cf3c64ca3d4e65aa71a1d17ade6248a97c] # ============================================================ --- cmd_list.cc f7c5a9b2e25b2844298957bed0e3fe8cdaf2618f +++ cmd_list.cc e3b9fe24c7b0aa279113cfbc2fe6ad504013e2dc @@ -439,8 +439,7 @@ ls_changed(app_state & app, vector parents, new_roster, app); revision_t rrev; - cset dummy; - make_restricted_revision(parents, new_roster, mask, rrev, dummy); + make_restricted_revision(parents, new_roster, mask, rrev); // to be printed sorted, with duplicates removed set print_paths; ============================================================ --- cmd_ws_commit.cc de9046ac0c7db82e46c4369f4c8413085eef6f41 +++ cmd_ws_commit.cc 05dc686d75988aba3d5d9abfce6d5eacd42ee1ae @@ -421,7 +421,6 @@ CMD(status, N_("informative"), N_("[PATH parent_map old_rosters; revision_t rev; temp_node_id_source nis; - cset dummy; app.require_workspace(); app.work.get_parent_rosters(old_rosters); @@ -433,7 +432,7 @@ CMD(status, N_("informative"), N_("[PATH old_rosters, new_roster, app); app.work.update_current_roster_from_filesystem(new_roster, mask); - make_restricted_revision(old_rosters, new_roster, mask, rev, dummy); + make_restricted_revision(old_rosters, new_roster, mask, rev); // We intentionally do not collapse the final \n into the format // strings here, for consistency with newline conventions used by most @@ -737,7 +736,7 @@ CMD(commit, N_("workspace"), N_("[PATH]. app.work.update_current_roster_from_filesystem(new_roster, mask); make_restricted_revision(old_rosters, new_roster, mask, restricted_rev, - excluded); + excluded, name); restricted_rev.check_sane(); N(restricted_rev.is_nontrivial(), F("no changes to commit")); ============================================================ --- revision.cc 82fd3fbadae41518da08611c887c7a323ebf4fdd +++ revision.cc 19dcc24d7b030f67d63819674d1e218c95c77cf0 @@ -667,40 +667,77 @@ make_revision(parent_map const & old_ros L(FL("new manifest_id is %s") % rev.new_manifest); } +static void +recalculate_manifest_id_for_restricted_rev(parent_map const & old_rosters, + edge_map & edges, + revision_t & rev) +{ + // In order to get the correct manifest ID, recalculate the new roster + // using one of the restricted csets. It doesn't matter which of the + // parent roster/cset pairs we use for this; by construction, they must + // all produce the same result. + revision_id id = parent_id(old_rosters.begin()); + roster_t restricted_roster = *(safe_get(old_rosters, id).first); + + temp_node_id_source nis; + editable_roster_base er(restricted_roster, nis); + safe_get(edges, id)->apply_to(er); + + calculate_ident(restricted_roster, rev.new_manifest); + rev.edges = edges; + L(FL("new manifest_id is %s") % rev.new_manifest); +} + void make_restricted_revision(parent_map const & old_rosters, roster_t const & new_roster, node_restriction const & mask, - revision_t & rev, - cset & excluded) + revision_t & rev) { edge_map edges; + cset dummy; for (parent_map::const_iterator i = old_rosters.begin(); i != old_rosters.end(); i++) { shared_ptr included(new cset()); - // ??? May not do the right thing with 'excluded' when there's more than - // one parent roster. - make_restricted_csets(parent_roster(i), new_roster, *included, excluded, mask); + make_restricted_csets(parent_roster(i), new_roster, + *included, dummy, mask); check_restricted_cset(parent_roster(i), *included); safe_insert(edges, make_pair(parent_id(i), included)); } - // In order to get the correct manifest ID, recalculate the new roster - // using one of the restricted csets. It doesn't matter which of the - // parent roster/cset pairs we use for this; by construction, they must - // all produce the same result. - revision_id id = parent_id(old_rosters.begin()); - roster_t restricted_roster = *(safe_get(old_rosters, id).first); + recalculate_manifest_id_for_restricted_rev(old_rosters, edges, rev); +} - temp_node_id_source nis; - editable_roster_base er(restricted_roster, nis); - safe_get(edges, id)->apply_to(er); +void +make_restricted_revision(parent_map const & old_rosters, + roster_t const & new_roster, + node_restriction const & mask, + revision_t & rev, + cset & excluded, + string const & cmd_name) +{ + edge_map edges; + bool no_excludes = true; + for (parent_map::const_iterator i = old_rosters.begin(); + i != old_rosters.end(); + i++) + { + shared_ptr included(new cset()); + make_restricted_csets(parent_roster(i), new_roster, + *included, excluded, mask); + check_restricted_cset(parent_roster(i), *included); + safe_insert(edges, make_pair(parent_id(i), included)); + if (!excluded.empty()) + no_excludes = false; + } - calculate_ident(restricted_roster, rev.new_manifest); - rev.edges = edges; - L(FL("new manifest_id is %s") % rev.new_manifest); + N(old_rosters.size() == 1 || no_excludes, + F("the command '%s %s' cannot be restricted in a two-parent workspace") + % ui.prog_name % cmd_name); + + recalculate_manifest_id_for_restricted_rev(old_rosters, edges, rev); } // Workspace-only revisions, with fake rev.new_manifest and content ============================================================ --- revision.hh 61f99762bde409557c3acbe6bcc89efe66e2f789 +++ revision.hh 13ef420b76868de35dca3208102304daa2d4593e @@ -202,20 +202,19 @@ make_revision_for_workspace(parent_map c roster_t const & new_roster, revision_t & rev); -#if 0 // hopefully we won't need this one void -make_restricted_revision(revision_id const & old_rev_id, - roster_t const & old_roster, +make_restricted_revision(parent_map const & old_rosters, + roster_t const & new_roster, node_restriction const & mask, revision_t & rev); -#endif void make_restricted_revision(parent_map const & old_rosters, roster_t const & new_roster, node_restriction const & mask, revision_t & rev, - cset & excluded); + cset & excluded, + string const & cmd_name); void build_changesets_from_manifest_ancestry(app_state & app); ============================================================ --- tests/two_parent_workspace_commands_that_fail/__driver__.lua 46ab6700635529ab40a24d2df3a79053bc7eeafe +++ tests/two_parent_workspace_commands_that_fail/__driver__.lua b93321cf3c64ca3d4e65aa71a1d17ade6248a97c @@ -6,10 +6,12 @@ addfile("testfile", "ancestor\nancestor" mtn_setup() addfile("testfile", "ancestor\nancestor") +addfile("otherfile", "blah blah") commit() anc = base_revision() writefile("testfile", "left\nancestor") +writefile("otherfile", "modified too") commit() left = base_revision() @@ -51,3 +53,10 @@ check(mtn("automate", "attributes", "tes check(mtn("automate", "get_base_revision_id"), 1, nil, diag) check(mtn("automate", "inventory"), 1, nil, diag) check(mtn("automate", "attributes", "testfile"), 1, nil, diag) + +-- commit cannot be restricted +check(mtn("commit", "testfile", "--message", "blah-blah"), + 1, nil, true) +check(qgrep("cannot be restricted", "stderr")) + +commit() -- unrestricted commit succeeds