# # patch "ChangeLog" # from [c21fba304d06e2f3a724a17ed2cf85b49a3e4cd2] # to [69d8cc3b1214855d6424b4dce05283294eafd230] # # patch "NEWS" # from [4e6e48c7d84b9e778412486592d47032638dff3f] # to [ef7e6cd276057ab21594eb5f3c7831a011000484] # # patch "change_set.cc" # from [ac5f6d85330f8287a66d747e06d414b9120cb2cd] # to [e963e597bcc9c332da6ff0d2593ac2c6e6e183ca] # # patch "revision.cc" # from [e3df88382e4fd3be836ca176063ae93244f6f268] # to [b90b4de954657d808ecfec14c81b182dd103ce83] # --- ChangeLog +++ ChangeLog @@ -1,3 +1,15 @@ +2005-04-29 Nathaniel Smith + + * change_set.cc (dump_change_set): Don't truncate output. + (invert_change_test): New unit test. + (invert_change_set): Make it pass. This fixes (some?) + isect.empty() invariant failures. + + * NEWS: Start updating for 0.19. + + * revision.cc (check_sane_history): Make comment more + informative. + 2005-04-28 Nathaniel Smith * tests/t_netsync_error.at: New test. --- NEWS +++ NEWS @@ -1,3 +1,72 @@ +???????????????????????????? + + 0.19 release. performance improvements, features, ui + improvements, and bug fixes. + + - many operations sped up by another factor of 2 or better. + - special thanks to Matt Johnston . + - new major features: + - "annotate" command; still requires optimization. + Thanks to Emile Snyder . + - "inodeprints" for fast change detection in large + working dirs now fully supported; see manual for + details. + - new minor features: + - new selector "c:name=value" for selecting on + arbitrary certs. Thanks to Richard Levitte + . + - new automate command "select", to do selector + expansion. Thanks to Richard Levitte + . + - new automate commands "graph", "parents", + "children", "ancestors", to easily inspect history. + Special thanks to Sebastian Spaeth + . + - new command "db kill_rev_locally". Thanks to + Sebastian Spaeth . + - new arguments to "commit": --author, --date; useful + for patch attribution and importing history. + - ui improvements: + - netsync progress ticker in kilobytes/megabytes. + Thanks to Matt Johnston , + - tickers do not cause annoying scrolling when wider + than window. Special thanks to Matthew Gregan + . + - warn users when a commit creates divergence, and + when an update ignores it. Thanks to Jeremy Cowgar + . + - many bug fixes: + - many cvs_import bugs fixed. Special thanks to Jon + Bright , Emile Snyder + , Hansjoerg Lipp + , Matthew Gregan + . + - windows/unix working copy line conversion now works + correctly. Thanks to Emile Snyder + . + - many fixes to locale-specific filename support + - "drop" and "rename" now affect file attributes as + well. Thanks to Richard Levitte + and Joel Reed + . + - better error reporting in netsync. Thanks to + Grahame Bowland . + - only set working directory's default branch on some + commands (update, commit). Thanks to Florian Weimer + . + - "db check" now sets exit status correctly, for use + in scripts. Thanks to Derek Scherger + . + - many others... + - fantastic emacs integration in contrib/monotone.el. Thanks + to Harley Gorrell . + + - upgrading from 0.18: database and working copies are + fully compatible. NOTE that the configuration file + is now ~/.monotone/monotonerc, rather than old + ~/.monotonerc. Simply create ~/.monotone, and + rename any existing configuration file. + Sun Apr 10 17:49:25 PDT 2005 0.18 release. performance improvements, features, and bug fixes. --- change_set.cc +++ change_set.cc @@ -2273,6 +2273,8 @@ b2a.deltas.clear(); + std::set moved_deltas; + // existing deltas are in "b space" for (path_state::const_iterator b = b2a_analysis.first.begin(); b != b2a_analysis.first.end(); ++b) @@ -2310,7 +2312,7 @@ get_full_path(b2a_analysis.first, path_state_tid(b), b_pth); get_full_path(b2a_analysis.second, path_state_tid(a), a_pth); change_set::delta_map::const_iterator del = a2b.deltas.find(b_pth); - if (del == a2b.deltas.end()) + if (del == a2b.deltas.end()) continue; file_id src_id(delta_entry_src(del)), dst_id(delta_entry_dst(del)); L(F("converting delta %s -> %s on %s\n") @@ -2318,6 +2320,7 @@ L(F("inverse is delta %s -> %s on %s\n") % dst_id % src_id % a_pth); b2a.deltas.insert(std::make_pair(a_pth, std::make_pair(dst_id, src_id))); + moved_deltas.insert(b_pth); } } } @@ -2331,8 +2334,11 @@ if (null_id(delta_entry_src(del))) continue; // check to make sure this isn't one of the already-moved deltas - if (b2a.deltas.find(delta_entry_path(del)) != b2a.deltas.end()) + if (moved_deltas.find(delta_entry_path(del)) != moved_deltas.end()) continue; + // we shouldn't have created a delta earlier, if this file really is + // untouched... + I(b2a.deltas.find(delta_entry_path(del)) == b2a.deltas.end()); b2a.deltas.insert(std::make_pair(delta_entry_path(del), std::make_pair(delta_entry_dst(del), delta_entry_src(del)))); @@ -2893,6 +2899,7 @@ #ifdef BUILD_UNIT_TESTS #include "unit_tests.hh" #include "sanity.hh" +#include "transforms.hh" static void dump_change_set(std::string const & ctx, change_set const & cs) @@ -2900,7 +2907,11 @@ data tmp; write_change_set(cs, tmp); L(F("[begin changeset %s]\n") % ctx); - L(F("%s") % tmp); + std::vector lines; + split_into_lines(tmp(), lines); + for (std::vector::const_iterator i = lines.begin(); + i != lines.end(); ++i) + L(F("%s") % *i); L(F("[end changeset %s]\n") % ctx); } @@ -3031,6 +3042,46 @@ } } +static void +invert_change_test() +{ + L(F("STARTING invert_change_test\n")); + change_set cs; + manifest_map a; + + a.insert(std::make_pair(file_path("usr/lib/zombie"), + file_id(hexenc("92ceb3cd922db36e48d5c30764e0f5488cdfca28")))); + cs.delete_file(file_path("usr/lib/zombie")); + cs.add_file(file_path("usr/bin/cat"), + file_id(hexenc("adc83b19e793491b1c6ea0fd8b46cd9f32e592fc"))); + cs.add_file(file_path("usr/local/dog"), + file_id(hexenc("adc83b19e793491b1c6ea0fd8b46cd9f32e592fc"))); + a.insert(std::make_pair(file_path("usr/foo"), + file_id(hexenc("9a4d3ae90b0cc26758e17e1f80229a13f57cad6e")))); + cs.rename_file(file_path("usr/foo"), file_path("usr/bar")); + cs.apply_delta(file_path("usr/bar"), + file_id(hexenc("9a4d3ae90b0cc26758e17e1f80229a13f57cad6e")), + file_id(hexenc("fe18ec0c55cbc72e4e51c58dc13af515a2f3a892"))); + a.insert(std::make_pair(file_path("usr/quuux"), + file_id(hexenc("fe18ec0c55cbc72e4e51c58dc13af515a2f3a892")))); + cs.apply_delta(file_path("usr/quuux"), + file_id(hexenc("fe18ec0c55cbc72e4e51c58dc13af515a2f3a892")), + file_id(hexenc("c6a4a6196bb4a744207e1a6e90273369b8c2e925"))); + + manifest_map b; + apply_change_set(a, cs, b); + + dump_change_set("invert_change_test, cs", cs); + change_set cs2, cs3; + invert_change_set(cs, a, cs2); + dump_change_set("invert_change_test, cs2", cs2); + invert_change_set(cs2, b, cs3); + dump_change_set("invert_change_test, cs3", cs3); + BOOST_CHECK(cs.rearrangement == cs3.rearrangement); + BOOST_CHECK(cs.deltas == cs3.deltas); + L(F("ENDING invert_change_test\n")); +} + static void neutralize_change_test() { @@ -3527,6 +3578,7 @@ suite->add(BOOST_TEST_CASE(&non_interfering_change_test)); suite->add(BOOST_TEST_CASE(&disjoint_merge_tests)); suite->add(BOOST_TEST_CASE(&bad_concatenate_change_tests)); + suite->add(BOOST_TEST_CASE(&invert_change_test)); } --- revision.cc +++ revision.cc @@ -90,6 +90,11 @@ // change sets can be applied to the old manifests to create the new // manifest. // +// We also make a special check for merge nodes, where if the previous +// paragraph wasn't enough to get us back to a common ancestor, we also search +// all the way up to a common ancestor and make the same check, because that's +// the invariant that merge is actually required to preserve. +// // NB: While this function has some invariants in it itself, a lot of its // purpose is just to exercise all the invariants inside change_set.cc. So // don't remove those invariants. (As if you needed another reason...)