# # # patch "cmd_merging.cc" # from [aad61ffd84255e1446ad469c6fa607a05c0757ae] # to [473026835519b620a06b47b9386b4bd739a68350] # # patch "diff_patch.cc" # from [007f6d5be298e952730a10f970a8905df32f5d17] # to [adf43e9fcc6b0a828e7deb3280ad76b5ae1489e4] # # patch "diff_patch.hh" # from [f04e39dfc101c83a107775115405eca963f04466] # to [1fdf49ab99f9d3a6ca15c08f5c5e7828533e5fa2] # # patch "merge.cc" # from [0fe162b99691ba1ed73b3222bb787fcf3189fd3e] # to [81b4bfcb4523d510efedd8c5758b4decc10e6095] # # patch "roster.hh" # from [8130ebfcc8a1324e6a3db3b10fe8d8e61e714a46] # to [d02b407aeb462016c8aa3f392e328471204b229a] # # patch "roster_merge.cc" # from [cb125c57bf3a35e88f1e43e143aa289260526e11] # to [49b49de7d0d89f40cc774d6237e7d4a6ff0ec999] # # patch "roster_merge.hh" # from [2ea251ea72b44a75a48fd80db8ea0e0742110a7b] # to [7e40959f06f4dc24ebec108a2a9f2cdfe1e6eb4c] # # patch "tests/automate_show_conflicts/expected-content-attached.stdout" # from [6c39a0131b22693f4086fb68970e827a3241a287] # to [ceb9cfaedb114a93f123024bb477148f1c0c5bd4] # # patch "work.cc" # from [c63f3ae3c3e6f7f24ffd23e49e83f4283f788ceb] # to [9a983dae8945a34b7c4fa73e911997f0baba72e3] # # patch "work.hh" # from [4cfe384959018bee9efae3c232ad5e64615b8bb9] # to [daf5045e3e50f76d66b2e3b53289a105d31ab04e] # ============================================================ --- cmd_merging.cc aad61ffd84255e1446ad469c6fa607a05c0757ae +++ cmd_merging.cc 473026835519b620a06b47b9386b4bd739a68350 @@ -46,7 +46,6 @@ three_way_merge(revision_id const & ance three_way_merge(revision_id const & ancestor_rid, roster_t const & ancestor_roster, revision_id const & left_rid, roster_t const & left_roster, revision_id const & right_rid, roster_t const & right_roster, - content_merge_adaptor & adaptor, roster_merge_result & result, marking_map & left_markings, marking_map & right_markings) @@ -86,7 +85,7 @@ three_way_merge(revision_id const & ance // And do the merge roster_merge(left_roster, left_markings, left_uncommon_ancestors, right_roster, right_markings, right_uncommon_ancestors, - adaptor, result); + result); } static bool @@ -251,12 +250,6 @@ CMD(update, "update", "", CMD_REF(worksp roster_merge_result result; - map paths; - get_content_paths(*working_roster, paths); - - content_merge_workspace_adaptor wca(db, base_rid, base_roster, - chosen_markings, working_markings, paths); - // If we are not switching branches, and the user has not specified a // specific revision, we treat the workspace as a revision that has not // yet been committed, and do a normal merge. This supports sutures and @@ -274,7 +267,7 @@ CMD(update, "update", "", CMD_REF(worksp safe_insert(working_uncommon_ancestors, working_rid); roster_merge(*working_roster, working_markings, working_uncommon_ancestors, - chosen_roster, chosen_markings, chosen_uncommon_ancestors, wca, + chosen_roster, chosen_markings, chosen_uncommon_ancestors, result); } else @@ -305,13 +298,18 @@ CMD(update, "update", "", CMD_REF(worksp // And finally do the merge three_way_merge(base_rid, *base_roster, working_rid, *working_roster, - chosen_rid, chosen_roster, wca, + chosen_rid, chosen_roster, result, working_markings, chosen_markings); } roster_t & merged_roster = result.roster; + map paths; + get_content_paths(*working_roster, paths); + + content_merge_workspace_adaptor wca(db, base_rid, base_roster, + chosen_markings, working_markings, paths); wca.cache_roster(working_rid, working_roster); resolve_merge_conflicts(app.lua, *working_roster, chosen_roster, result, wca, false); @@ -661,18 +659,17 @@ CMD(merge_into_dir, "merge_into_dir", "" } roster_merge_result result; - content_merge_database_adaptor - dba(db, left_rid, right_rid, left_marking_map, right_marking_map); - roster_merge(left_roster, left_marking_map, left_uncommon_ancestors, right_roster, right_marking_map, right_uncommon_ancestors, - dba, result); + content_merge_database_adaptor + dba(db, left_rid, right_rid, left_marking_map, right_marking_map); + bool resolutions_given; parse_resolve_conflicts_opts (app.opts, left_roster, right_roster, result, resolutions_given); @@ -776,6 +773,12 @@ CMD(merge_into_workspace, "merge_into_wo left_uncommon_ancestors, right_uncommon_ancestors); + roster_merge_result merge_result; + MM(merge_result); + roster_merge(*left.first, *left.second, left_uncommon_ancestors, + *right.first, *right.second, right_uncommon_ancestors, + merge_result); + revision_id lca_id; cached_roster lca; find_common_ancestor_for_merge(db, left_id, right_id, lca_id); @@ -787,13 +790,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); - - roster_merge_result merge_result; - MM(merge_result); - roster_merge(*left.first, *left.second, left_uncommon_ancestors, - *right.first, *right.second, right_uncommon_ancestors, - wca, merge_result); - resolve_merge_conflicts(app.lua, *left.first, *right.first, merge_result, wca, false); // Make sure it worked... @@ -875,7 +871,12 @@ static void } static void -show_conflicts_core (database & db, revision_id const & l_id, revision_id const & r_id, bool const basic_io, std::ostream & output) +show_conflicts_core (database & db, + lua_hooks & lua, + revision_id const & l_id, + revision_id const & r_id, + bool const basic_io, + std::ostream & output) { N(!is_ancestor(db, l_id, r_id), F("%s is an ancestor of %s; no merge is needed.") @@ -891,11 +892,9 @@ show_conflicts_core (database & db, revi set l_uncommon_ancestors, r_uncommon_ancestors; db.get_uncommon_ancestors(l_id, r_id, l_uncommon_ancestors, r_uncommon_ancestors); roster_merge_result result; - content_merge_database_adaptor adaptor(db, l_id, r_id, l_marking, r_marking); - roster_merge(*l_roster, l_marking, l_uncommon_ancestors, *r_roster, r_marking, r_uncommon_ancestors, - adaptor, result); + result); // 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 @@ -928,6 +927,9 @@ show_conflicts_core (database & db, revi } else { + content_merge_database_adaptor adaptor(db, l_id, r_id, + l_marking, r_marking); + { basic_io::printer pr; st.push_binary_pair(syms::ancestor, adaptor.lca.inner()); @@ -949,7 +951,7 @@ show_conflicts_core (database & db, revi result.report_duplicate_name_conflicts(*l_roster, *r_roster, adaptor, basic_io, output); result.report_attribute_conflicts(*l_roster, *r_roster, adaptor, basic_io, output); - result.report_file_content_conflicts(*l_roster, *r_roster, adaptor, basic_io, output); + result.report_file_content_conflicts(lua, *l_roster, *r_roster, adaptor, basic_io, output); } } @@ -968,7 +970,7 @@ CMD(show_conflicts, "show_conflicts", "" complete(app.opts, app.lua, project, idx(args,0)(), l_id); complete(app.opts, app.lua, project, idx(args,1)(), r_id); - show_conflicts_core(db, l_id, r_id, false, std::cout); + show_conflicts_core(db, app.lua, l_id, r_id, false, std::cout); } // Name: show_conflicts @@ -1033,7 +1035,7 @@ CMD_AUTOMATE(show_conflicts, N_("[LEFT_R else N(false, F("wrong argument count")); - show_conflicts_core(db, l_id, r_id, true, output); + show_conflicts_core(db, app.lua, l_id, r_id, true, output); } CMD(pluck, "pluck", "", CMD_REF(workspace), N_("[-r FROM] -r TO [PATH...]"), @@ -1161,19 +1163,19 @@ CMD(pluck, "pluck", "", CMD_REF(workspac // Now do the merge roster_merge_result result; marking_map left_markings, right_markings; + three_way_merge(from_rid, *from_roster, + working_rid, *working_roster, + to_rid, *to_roster, + result, left_markings, right_markings); + + roster_t & merged_roster = result.roster; + map paths; get_content_paths(*working_roster, paths); content_merge_workspace_adaptor wca(db, from_rid, from_roster, left_markings, right_markings, paths); - three_way_merge(from_rid, *from_roster, - working_rid, *working_roster, - to_rid, *to_roster, - wca, result, left_markings, right_markings); - - roster_t & merged_roster = result.roster; - wca.cache_roster(working_rid, working_roster); // cache the synthetic to_roster under the to_rid so that the real // to_roster is not fetched from the db which does not have temporary nids ============================================================ --- diff_patch.cc 007f6d5be298e952730a10f970a8905df32f5d17 +++ diff_patch.cc adf43e9fcc6b0a828e7deb3280ad76b5ae1489e4 @@ -1,3 +1,4 @@ +// Copyright (C) 2008 Stephen Leake // Copyright (C) 2002 Graydon Hoare // // This program is made available under the GNU GPL version 2.0 or @@ -869,8 +870,7 @@ bool } bool -content_merger::try_user_merge(lua_hooks & lua, - file_path const & anc_path, +content_merger::try_user_merge(file_path const & anc_path, file_path const & left_path, file_path const & right_path, file_path const & merged_path, ============================================================ --- diff_patch.hh f04e39dfc101c83a107775115405eca963f04466 +++ diff_patch.hh 1fdf49ab99f9d3a6ca15c08f5c5e7828533e5fa2 @@ -161,17 +161,20 @@ struct content_merger struct content_merger { + lua_hooks & lua; roster_t const & anc_ros; roster_t const & left_ros; roster_t const & right_ros; content_merge_adaptor & adaptor; - content_merger(roster_t const & anc_ros, + content_merger(lua_hooks & lua, + roster_t const & anc_ros, roster_t const & left_ros, roster_t const & right_ros, content_merge_adaptor & adaptor) - : anc_ros(anc_ros), + : lua(lua), + anc_ros(anc_ros), left_ros(left_ros), right_ros(right_ros), adaptor(adaptor) @@ -201,8 +204,7 @@ struct content_merger file_id const & right, file_id & merged_id); - bool try_user_merge(lua_hooks & lua, - file_path const & anc_path, + bool try_user_merge(file_path const & anc_path, file_path const & left_path, file_path const & right_path, file_path const & merged_path, ============================================================ --- merge.cc 0fe162b99691ba1ed73b3222bb787fcf3189fd3e +++ merge.cc 81b4bfcb4523d510efedd8c5758b4decc10e6095 @@ -67,7 +67,7 @@ namespace file_id merged_id; - content_merger cm(*ancestor_roster, left_roster, right_roster, adaptor); + content_merger cm(lua, *ancestor_roster, left_roster, right_roster, adaptor); bool merged = false; @@ -80,7 +80,7 @@ namespace break; case user_merge: - merged = cm.try_user_merge(lua, anc_path, left_path, right_path, + merged = cm.try_user_merge(anc_path, left_path, right_path, right_path, anc_id, left_id, right_id, merged_id); @@ -155,7 +155,7 @@ resolve_merge_conflicts(lua_hooks & lua, result.report_duplicate_name_conflicts(left_roster, right_roster, adaptor, false, std::cout); result.report_attribute_conflicts(left_roster, right_roster, adaptor, false, std::cout); - result.report_file_content_conflicts(left_roster, right_roster, adaptor, false, std::cout); + result.report_file_content_conflicts(lua, left_roster, right_roster, adaptor, false, std::cout); } else if (result.has_content_conflicts()) { @@ -173,7 +173,7 @@ resolve_merge_conflicts(lua_hooks & lua, P(FP("%d content conflict requires user intervention", "%d content conflicts require user intervention", remaining) % remaining); - result.report_file_content_conflicts(left_roster, right_roster, adaptor, false, std::cout); + result.report_file_content_conflicts(lua, left_roster, right_roster, adaptor, false, std::cout); try_to_merge_files(lua, left_roster, right_roster, result, adaptor, user_merge); @@ -202,14 +202,15 @@ interactive_merge_and_store(lua_hooks & left_uncommon_ancestors, right_uncommon_ancestors); roster_merge_result result; - content_merge_database_adaptor dba(db, left_rid, right_rid, - left_marking_map, right_marking_map); roster_merge(left_roster, left_marking_map, left_uncommon_ancestors, right_roster, right_marking_map, right_uncommon_ancestors, - dba, result); + result); bool resolutions_given; + content_merge_database_adaptor dba(db, left_rid, right_rid, + left_marking_map, right_marking_map); + parse_resolve_conflicts_opts (opts, left_roster, right_roster, result, resolutions_given); resolve_merge_conflicts(lua, left_roster, right_roster, result, dba, resolutions_given); ============================================================ --- roster.hh 8130ebfcc8a1324e6a3db3b10fe8d8e61e714a46 +++ roster.hh d02b407aeb462016c8aa3f392e328471204b229a @@ -145,12 +145,17 @@ struct marking_t typedef enum {add, suture, split} birth_cause_t; revision_id birth_revision; - std::pair > birth_cause; + // if suture, the node_ids indicate the ancestors. If split, the first // node_id indicates the ancestor. + std::pair > birth_cause; + + // These sets hold the minimal marking map for the merge scalars; see + // ss-mark-merge.text. std::set parent_name; std::set file_content; std::map > attrs; + marking_t() : birth_cause (std::make_pair (add, null_ancestors)) {}; bool operator==(marking_t const & other) const { ============================================================ --- roster_merge.cc cb125c57bf3a35e88f1e43e143aa289260526e11 +++ roster_merge.cc 49b49de7d0d89f40cc774d6237e7d4a6ff0ec999 @@ -1318,25 +1318,62 @@ file_content_conflict::get_ancestor_rost adaptor.get_ancestral_roster (ancestor_nid, ancestor_rid, ancestor_roster); } +namespace +{ + bool + auto_merge_succeeds(lua_hooks & lua, + file_content_conflict conflict, + content_merge_adaptor & adaptor, + roster_t const & left_roster, + roster_t const & right_roster) + { + node_id ancestor_nid; + revision_id ancestor_rid; + shared_ptr ancestor_roster; + conflict.get_ancestor_roster(adaptor, ancestor_nid, ancestor_rid, ancestor_roster); + + I(ancestor_roster); + I(ancestor_roster->has_node(ancestor_nid)); // this fails if there is no least common ancestor + + file_id anc_id, left_id, right_id; + file_path anc_path, left_path, right_path; + ancestor_roster->get_file_details(ancestor_nid, anc_id, anc_path); + left_roster.get_file_details(conflict.left_nid, left_id, left_path); + right_roster.get_file_details(conflict.right_nid, right_id, right_path); + + content_merger cm(lua, *ancestor_roster, left_roster, right_roster, adaptor); + + file_data left_data, right_data, merge_data; + + return cm.attempt_auto_merge(anc_path, left_path, right_path, + anc_id, left_id, right_id, + left_data, right_data, merge_data); + } +} + void -roster_merge_result::report_file_content_conflicts(roster_t const & left_roster, +roster_merge_result::report_file_content_conflicts(lua_hooks & lua, + roster_t const & left_roster, roster_t const & right_roster, content_merge_adaptor & adaptor, bool basic_io, - std::ostream & output) const + std::ostream & output) { 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]; + file_content_conflict & conflict = file_content_conflicts[i]; MM(conflict); if (basic_io) { 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()); + st.push_str_pair(syms::conflict, syms::content); put_content_conflict (st, left_roster, right_roster, adaptor, conflict); put_stanza (st, output); @@ -1410,7 +1447,8 @@ namespace resolve_conflicts } bool - do_auto_merge(file_content_conflict const & conflict, + do_auto_merge(lua_hooks & lua, + file_content_conflict const & conflict, content_merge_adaptor & adaptor, roster_t const & left_roster, roster_t const & right_roster, @@ -1432,7 +1470,7 @@ namespace resolve_conflicts right_roster.get_file_details(conflict.right_nid, right_id, right_path); result_roster.get_file_details(conflict.result_nid, merged_id, merged_path); - content_merger cm(*ancestor_roster, left_roster, right_roster, adaptor); + content_merger cm(lua, *ancestor_roster, left_roster, right_roster, adaptor); return cm.try_auto_merge(anc_path, left_path, right_path, merged_path, anc_id, left_id, right_id, merged_id); @@ -1878,7 +1916,7 @@ roster_merge_result::resolve_file_conten { file_id merged_id; - N(resolve_conflicts::do_auto_merge(conflict, adaptor, left_roster, + N(resolve_conflicts::do_auto_merge(lua, conflict, adaptor, left_roster, right_roster, this->roster, merged_id), F("merge of %s, %s failed") % left_name % right_name); @@ -2260,47 +2298,15 @@ namespace assign_name(result, n->self, old_n->parent, old_n->name, side); } - bool - auto_merge_succeeds(file_content_conflict conflict, - content_merge_adaptor & adaptor, - roster_t const & left_roster, - roster_t const & right_roster) - { - node_id ancestor_nid; - revision_id ancestor_rid; - shared_ptr ancestor_roster; - conflict.get_ancestor_roster(adaptor, ancestor_nid, ancestor_rid, ancestor_roster); - - I(ancestor_roster); - I(ancestor_roster->has_node(ancestor_nid)); // this fails if there is no least common ancestor - - file_id anc_id, left_id, right_id; - file_path anc_path, left_path, right_path; - ancestor_roster->get_file_details(ancestor_nid, anc_id, anc_path); - left_roster.get_file_details(conflict.left_nid, left_id, left_path); - right_roster.get_file_details(conflict.right_nid, right_id, right_path); - - content_merger cm(*ancestor_roster, left_roster, right_roster, adaptor); - - file_data left_data, right_data, merge_data; - - return cm.attempt_auto_merge(anc_path, left_path, right_path, - anc_id, left_id, right_id, - left_data, right_data, merge_data); - } - void merge_nodes(node_t const left_n, marking_t const & left_marking, set const & left_uncommon_ancestors, - roster_t const & left_roster, node_t const right_n, marking_t const & right_marking, set const & right_uncommon_ancestors, - roster_t const & right_roster, node_t const new_n, - roster_merge_result & result, - content_merge_adaptor & adaptor) + roster_merge_result & result) { // merge name pair left_name, right_name, new_name; @@ -2351,9 +2357,6 @@ namespace } else { - if (auto_merge_succeeds(conflict, adaptor, left_roster, right_roster)) - conflict.resolution = make_pair(resolve_conflicts::content_internal, file_path()); - downcast_to_file_t(new_n)->content = file_id(); result.file_content_conflicts.push_back(conflict); } @@ -2418,7 +2421,6 @@ roster_merge(roster_t const & left_paren roster_t const & right_parent, marking_map const & right_markings, set const & right_uncommon_ancestors, - content_merge_adaptor & adaptor, roster_merge_result & result) { set already_handled; @@ -2507,14 +2509,11 @@ roster_merge(roster_t const & left_paren merge_nodes(left_n, left_mi->second, // left_marking left_uncommon_ancestors, - left_parent, right_n, right_mi->second, right_uncommon_ancestors, - right_parent, new_i->second, // new_n - result, - adaptor); + result); ++new_i; } else @@ -2556,14 +2555,11 @@ roster_merge(roster_t const & left_paren merge_nodes(left_n, left_mi->second, // left_marking left_uncommon_ancestors, - left_parent, i.right_data(), // right_n right_mi->second, // right_marking right_uncommon_ancestors, - right_parent, new_i->second, // new_n - result, - adaptor); + result); ++new_i; } else @@ -2590,14 +2586,11 @@ roster_merge(roster_t const & left_paren merge_nodes(i.left_data(), // left_n left_mi->second, // left_marking left_uncommon_ancestors, - left_parent, i.right_data(), // right_n right_mi->second, // right_marking right_uncommon_ancestors, - right_parent, new_i->second, // new_n - result, - adaptor); + result); } ++left_mi; ++right_mi; ============================================================ --- roster_merge.hh 2ea251ea72b44a75a48fd80db8ea0e0742110a7b +++ roster_merge.hh 7e40959f06f4dc24ebec108a2a9f2cdfe1e6eb4c @@ -227,11 +227,16 @@ struct roster_merge_result content_merge_adaptor & adaptor, bool const basic_io, std::ostream & output) const; - void report_file_content_conflicts(roster_t const & left, + + // not 'const' because this sets resolution to 'resolved_internal' if the + // internal merger would succeed. + void report_file_content_conflicts(lua_hooks & lua, + roster_t const & left, roster_t const & right, content_merge_adaptor & adaptor, bool const basic_io, - std::ostream & output) const; + std::ostream & output); + void resolve_file_content_conflicts(lua_hooks & lua, roster_t const & left_roster, roster_t const & right_roster, @@ -249,7 +254,6 @@ roster_merge(roster_t const & left_paren roster_t const & right_parent, marking_map const & right_markings, std::set const & right_uncommon_ancestors, - content_merge_adaptor & adaptor, roster_merge_result & result); void ============================================================ --- tests/automate_show_conflicts/expected-content-attached.stdout 6c39a0131b22693f4086fb68970e827a3241a287 +++ tests/automate_show_conflicts/expected-content-attached.stdout ceb9cfaedb114a93f123024bb477148f1c0c5bd4 @@ -1,24 +1,26 @@ ancestor [7d854bf031420b7a5c1cafcb908f10 left [0b9e5111f3e13ccb1727bc936aff962020dc9809] 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" ============================================================ --- work.cc c63f3ae3c3e6f7f24ffd23e49e83f4283f788ceb +++ work.cc 9a983dae8945a34b7c4fa73e911997f0baba72e3 @@ -318,7 +318,7 @@ workspace::get_current_roster(database & else { make_roster_for_revision(db, nis, rev, rid, ros, markings); - update_current_roster_from_filesystem(ros); + update_from_filesystem(ros, markings, rid); } } @@ -1379,6 +1379,92 @@ void } void +workspace::update_from_filesystem(roster_t & ros, + marking_map & markings, + revision_id const & rid) +{ + temp_node_id_source nis; + inodeprint_map ipm; + + if (in_inodeprints_mode()) + { + data dat; + read_inodeprints(dat); + read_inodeprint_map(dat, ipm); + } + + size_t missing_items = 0; + + // this code is speed critical, hence the use of inode fingerprints so be + // careful when making changes in here and preferably do some timing tests + + if (!ros.has_root()) + return; + + node_map const & nodes = ros.all_nodes(); + for (node_map::const_iterator i = nodes.begin(); i != nodes.end(); ++i) + { + node_id nid = i->first; + node_t node = i->second; + + file_path fp; + ros.get_name(nid, fp); + + const path::status status(get_path_status(fp)); + + if (is_dir_t(node)) + { + if (status == path::nonexistent) + { + W(F("missing directory '%s'") % (fp)); + missing_items++; + } + else if (status != path::directory) + { + W(F("not a directory '%s'") % (fp)); + missing_items++; + } + } + else + { + // Only analyze changed files (or all files if inodeprints mode + // is disabled). + if (inodeprint_unchanged(ipm, fp)) + continue; + + if (status == path::nonexistent) + { + W(F("missing file '%s'") % (fp)); + missing_items++; + } + else if (status != path::file) + { + W(F("not a file '%s'") % (fp)); + missing_items++; + } + + file_t file = downcast_to_file_t(node); + ident_existing_file(fp, file->content, status); + + marking_t & marking = markings.find(nid)->second; + marking.file_content.clear(); + marking.file_content.insert(rid); + } + } + + N(missing_items == 0, + F("%d missing items; use '%s ls missing' to view\n" + "To restore consistency, on each missing item run either\n" + " '%s drop ITEM' to remove it permanently, or\n" + " '%s revert ITEM' to restore it.\n" + "To handle all at once, simply use\n" + " '%s drop --missing' or\n" + " '%s revert --missing'") + % missing_items % ui.prog_name % ui.prog_name % ui.prog_name + % ui.prog_name % ui.prog_name); +} + +void workspace::find_missing(roster_t const & new_roster_shape, node_restriction const & mask, set & missing) ============================================================ --- work.hh 4cfe384959018bee9efae3c232ad5e64615b8bb9 +++ work.hh daf5045e3e50f76d66b2e3b53289a105d31ab04e @@ -194,7 +194,12 @@ public: void update_current_roster_from_filesystem(roster_t & ros, node_restriction const & mask); + // Update roster and markings from workspace + void update_from_filesystem(roster_t & ros, + marking_map & markings, + revision_id const & rid); + // the "user log" is a file the user can edit as they program to record // changes they make to their source code. Upon commit the file is read // and passed to the edit_comment lua hook. If the commit is a success,