# # patch "commands.cc" # from [c5859590d6dd5b3e9e7a7224ab53a463d04e694a] # to [7bf613f88b2dfc594f3d8509395e5f59fc2921f2] # # patch "diff_patch.cc" # from [3255afd06951ac28adafe13c7cea7437c6fd3db7] # to [2e608b14d84626fe2df4da13b645e298698e9982] # # patch "diff_patch.hh" # from [b94e63ba12f09789dcc416ea61ec621774d25557] # to [5c0943c0c2620c840461f1f0850a7a80f5da8c10] # # patch "merge.cc" # from [506f5389c61de30a65a1d0b4a47a85bf0dd767a5] # to [12f6e60553fa38edc3ed1adc0741e2c4286b3f8e] # # patch "restrictions.cc" # from [dcae40914ab7b0071e9f9a7bd4b093a7ae0ec327] # to [f00567c24894c679fba09faa5e02598e37f0fe77] # ======================================================================== --- commands.cc c5859590d6dd5b3e9e7a7224ab53a463d04e694a +++ commands.cc 7bf613f88b2dfc594f3d8509395e5f59fc2921f2 @@ -2774,7 +2774,8 @@ OPT_BRANCH_NAME % OPT_REVISION) { revision_set r_old, r_working, r_new; - roster_t old_roster, working_roster, chosen_roster; + roster_t working_roster, chosen_roster; + boost::shared_ptr old_roster = boost::shared_ptr(new roster_t()); marking_map working_mm, chosen_mm, merged_mm; revision_id r_old_id, r_working_id, r_chosen_id; @@ -2792,13 +2793,12 @@ // intolerable. get_unrestricted_working_revision_and_rosters(app, r_working, - old_roster, + *old_roster, working_roster); calculate_ident(r_working, r_working_id); make_roster_for_revision(r_working, r_working_id, working_roster, working_mm, app); - I(r_working.edges.size() == 1); r_old_id = edge_old_revision(r_working.edges.begin()); @@ -2882,16 +2882,6 @@ app.db.get_roster(r_chosen_id, chosen_roster, chosen_mm); - // Note that, as far as "uncommon ancestors" go, the working's "uncommon - // ancestors" are the same as the base revision's "uncommon ancestors" - // relative to the chosen target: it's an empty set. The only "uncommon - // ancestors" we're really interested in finding are those above the - // chosen target and not above the base revision; so we can use the - // database function here using the base revision id, not the working - // copy revision id. - // - // This will stop being true when we have merge-into-dir support. - std::set working_uncommon_ancestors, chosen_uncommon_ancestors; @@ -2900,6 +2890,12 @@ working_uncommon_ancestors, chosen_uncommon_ancestors); + // Note that under the definition of mark-merge, the working copy is an + // "uncommon ancestor" if itself too, even though it was not present in + // the database (hence not returned by the query above). + + working_uncommon_ancestors.insert(r_working_id); + // Now merge the working roster with the chosen target. roster_merge_result result; @@ -2909,7 +2905,7 @@ roster_t & merged_roster = result.roster; - content_merge_working_copy_adaptor wca(app); + content_merge_working_copy_adaptor wca(app, old_roster); resolve_merge_conflicts (r_old_id, r_chosen_id, working_roster, chosen_roster, working_mm, chosen_mm, ======================================================================== --- diff_patch.cc 3255afd06951ac28adafe13c7cea7437c6fd3db7 +++ diff_patch.cc 2e608b14d84626fe2df4da13b645e298698e9982 @@ -1,25 +1,30 @@ // copyright (C) 2002, 2003 graydon hoare // all rights reserved. // licensed to the public under the terms of the GNU GPL (>= 2) // see the file COPYING for details #include +#include #include -#include +#include #include -#include +#include +#include + #include "config.h" #include "diff_patch.hh" #include "interner.hh" #include "lcs.hh" #include "roster.hh" #include "packet.hh" +#include "safe_map.hh" #include "sanity.hh" #include "transforms.hh" #include "vocab.hh" using namespace std; +using boost::shared_ptr; // // a 3-way merge works like this: @@ -460,6 +465,19 @@ // content_merge_database_adaptor /////////////////////////////////////////////////////////////////////////// + +content_merge_database_adaptor::content_merge_database_adaptor(app_state & app, + revision_id const & left, + revision_id const & right, + marking_map const & mm) + : app(app), mm(mm) +{ + // FIXME: possibly refactor to run this lazily, as we don't + // need to find common ancestors if we're never actually + // called on to do content merging. + find_common_ancestor_for_merge(left, right, lca, app); +} + void content_merge_database_adaptor::record_merge(file_id const & left_ident, file_id const & right_ident, @@ -479,7 +497,46 @@ guard.commit(); } +static void +load_and_cache_roster(revision_id const & rid, + map > & rmap, + shared_ptr & rout, + app_state & app) +{ + map >::const_iterator i = rmap.find(rid); + if (i != rmap.end()) + rout = i->second; + else + { + rout = shared_ptr(new roster_t()); + app.db.get_roster(rid, *rout); + safe_insert(rmap, make_pair(rid, rout)); + } +} + void +content_merge_database_adaptor::get_ancestral_roster(node_id nid, + boost::shared_ptr & anc) +{ + // Given a file, if the lca is nonzero and its roster contains the file, + // then we use its roster. Otherwise we use the roster at the file's + // birth revision, which is the "per-file worst case" lca. + + // Begin by loading any non-empty file lca roster + if (!lca.inner()().empty()) + load_and_cache_roster(lca, rosters, anc, app); + + // If this roster doesn't contain the file, replace it with + // the file's birth roster. + if (!anc->has_node(nid)) + { + marking_map::const_iterator j = mm.find(nid); + I(j != mm.end()); + load_and_cache_roster(j->second.birth_revision, rosters, anc, app); + } +} + +void content_merge_database_adaptor::get_version(file_path const & path, file_id const & ident, file_data & dat) @@ -506,6 +563,15 @@ } void +content_merge_working_copy_adaptor::get_ancestral_roster(node_id nid, + boost::shared_ptr & anc) +{ + // When doing an update, the base revision is always the ancestor to + // use for content merging. + anc = base; +} + +void content_merge_working_copy_adaptor::get_version(file_path const & path, file_id const & ident, file_data & dat) ======================================================================== --- diff_patch.hh b94e63ba12f09789dcc416ea61ec621774d25557 +++ diff_patch.hh 5c0943c0c2620c840461f1f0850a7a80f5da8c10 @@ -10,9 +10,12 @@ #include "cert.hh" #include "vocab.hh" +#include + +#include +#include #include #include -#include struct roster_t; @@ -43,6 +46,9 @@ file_id const & merged_ident, file_data const & left_data, file_data const & merged_data) = 0; + + virtual void get_ancestral_roster(node_id nid, + boost::shared_ptr & anc) = 0; virtual void get_version(file_path const & path, file_id const & ident, @@ -56,12 +62,21 @@ : public content_merge_adaptor { app_state & app; - content_merge_database_adaptor (app_state & app) : app(app) {} + revision_id lca; + marking_map const & mm; + std::map > rosters; + content_merge_database_adaptor (app_state & app, + revision_id const & left, + revision_id const & right, + marking_map const & mm); void record_merge(file_id const & left_ident, file_id const & right_ident, file_id const & merged_ident, file_data const & left_data, file_data const & merged_data); + + void get_ancestral_roster(node_id nid, + boost::shared_ptr & anc); void get_version(file_path const & path, file_id const & ident, @@ -74,12 +89,19 @@ { std::map temporary_store; app_state & app; - content_merge_working_copy_adaptor (app_state & app) : app(app) {} + boost::shared_ptr base; + content_merge_working_copy_adaptor (app_state & app, + boost::shared_ptr base) + : app(app), base(base) + {} void record_merge(file_id const & left_ident, file_id const & right_ident, file_id const & merged_ident, file_data const & left_data, file_data const & merged_data); + + void get_ancestral_roster(node_id nid, + boost::shared_ptr & anc); void get_version(file_path const & path, file_id const & ident, ======================================================================== --- merge.cc 506f5389c61de30a65a1d0b4a47a85bf0dd767a5 +++ merge.cc 12f6e60553fa38edc3ed1adc0741e2c4286b3f8e @@ -21,23 +21,6 @@ using boost::shared_ptr; static void -load_and_cache_roster(revision_id const & rid, - map > & rmap, - shared_ptr & rout, - app_state & app) -{ - map >::const_iterator i = rmap.find(rid); - if (i != rmap.end()) - rout = i->second; - else - { - rout = shared_ptr(new roster_t()); - app.db.get_roster(rid, *rout); - safe_insert(rmap, make_pair(rid, rout)); - } -} - -static void get_file_details(roster_t const & ros, node_id nid, file_id & fid, file_path & pth) @@ -104,35 +87,15 @@ L(F("examining content conflicts\n")); std::vector residual_conflicts; - revision_id lca; - map > lca_rosters; - find_common_ancestor_for_merge(left_rid, right_rid, lca, app); - for (size_t i = 0; i < result.file_content_conflicts.size(); ++i) { file_content_conflict const & conflict = result.file_content_conflicts[i]; - // For each file, if the lca is nonzero and its roster - // contains the file, then we use its roster. Otherwise - // we use the roster at the file's birth revision, which - // is the "per-file worst case" lca. - shared_ptr roster_for_file_lca; + boost::shared_ptr roster_for_file_lca; + adaptor.get_ancestral_roster(conflict.nid, roster_for_file_lca); - // Begin by loading any non-empty file lca roster - if (!lca.inner()().empty()) - load_and_cache_roster(lca, lca_rosters, roster_for_file_lca, app); - - // If this roster doesn't contain the file, replace it with - // the file's birth roster. - if (!roster_for_file_lca->has_node(conflict.nid)) - { - marking_map::const_iterator j = left_marking_map.find(conflict.nid); - I(j != left_marking_map.end()); - load_and_cache_roster(j->second.birth_revision, lca_rosters, - roster_for_file_lca, app); - } - - // Now we should certainly have the node. + // Now we should certainly have a roster, which has the node. + I(roster_for_file_lca); I(roster_for_file_lca->has_node(conflict.nid)); file_id anc_id, left_id, right_id; @@ -186,7 +149,7 @@ roster_t & merged_roster = result.roster; - content_merge_database_adaptor dba(app); + content_merge_database_adaptor dba(app, left_rid, right_rid, left_marking_map); resolve_merge_conflicts (left_rid, right_rid, left_roster, right_roster, left_marking_map, right_marking_map, ======================================================================== --- restrictions.cc dcae40914ab7b0071e9f9a7bd4b093a7ae0ec327 +++ restrictions.cc f00567c24894c679fba09faa5e02598e37f0fe77 @@ -10,6 +10,7 @@ #include "manifest.hh" #include "restrictions.hh" #include "revision.hh" +#include "safe_map.hh" #include "transforms.hh" void @@ -56,13 +57,16 @@ cset & excluded, app_state & app) { + included.clear(); + excluded.clear(); + for (std::set::const_iterator i = cs.nodes_deleted.begin(); i != cs.nodes_deleted.end(); ++i) { if (app.restriction_includes(*i)) - included.nodes_deleted.insert(*i); + safe_insert(included.nodes_deleted, *i); else - excluded.nodes_deleted.insert(*i); + safe_insert(excluded.nodes_deleted, *i); } for (std::map::const_iterator i = cs.nodes_renamed.begin(); @@ -70,54 +74,54 @@ { if (app.restriction_includes(i->first) || app.restriction_includes(i->second)) - included.nodes_renamed.insert(*i); + safe_insert(included.nodes_renamed, *i); else - excluded.nodes_renamed.insert(*i); + safe_insert(excluded.nodes_renamed, *i); } for (std::set::const_iterator i = cs.dirs_added.begin(); i != cs.dirs_added.end(); ++i) { if (app.restriction_includes(*i)) - included.dirs_added.insert(*i); + safe_insert(included.dirs_added, *i); else - excluded.dirs_added.insert(*i); + safe_insert(excluded.dirs_added, *i); } for (std::map::const_iterator i = cs.files_added.begin(); i != cs.files_added.end(); ++i) { if (app.restriction_includes(i->first)) - included.files_added.insert(*i); + safe_insert(included.files_added, *i); else - excluded.files_added.insert(*i); + safe_insert(excluded.files_added, *i); } for (std::map >::const_iterator i = cs.deltas_applied.begin(); i != cs.deltas_applied.end(); ++i) { if (app.restriction_includes(i->first)) - included.deltas_applied.insert(*i); + safe_insert(included.deltas_applied, *i); else - excluded.deltas_applied.insert(*i); + safe_insert(excluded.deltas_applied, *i); } for (std::set >::const_iterator i = cs.attrs_cleared.begin(); i != cs.attrs_cleared.end(); ++i) { if (app.restriction_includes(i->first)) - included.attrs_cleared.insert(*i); + safe_insert(included.attrs_cleared, *i); else - excluded.attrs_cleared.insert(*i); + safe_insert(excluded.attrs_cleared, *i); } for (std::map, attr_value>::const_iterator i = cs.attrs_set.begin(); i != cs.attrs_set.end(); ++i) { if (app.restriction_includes(i->first.first)) - included.attrs_set.insert(*i); + safe_insert(included.attrs_set, *i); else - excluded.attrs_set.insert(*i); + safe_insert(excluded.attrs_set, *i); } } @@ -234,8 +238,8 @@ restrict_cset(tmp_full, *cs, tmp_excluded, app); } - rev.edges.insert(std::make_pair(old_revision_id, - std::make_pair(old_manifest_id, cs))); + safe_insert(rev.edges, std::make_pair(old_revision_id, + std::make_pair(old_manifest_id, cs))); } void