#
#
# add_file "tests/resolve_duplicate_name_conflict/expected-merge-messages-abe_2-jim_1-conflicts"
# content [c505d776680d4278cfbb27e0cb850ba8486e86bd]
#
# add_file "tests/resolve_duplicate_name_conflict/merge-abe_2-jim_1-resolve_conflicts"
# content [bb50072864e1404e1da5597bca04c486c33bf2ed]
#
# patch "revision.cc"
# from [9b166019d4923fd6219b72fb7563aa914238f81d]
# to [f036e8be10fd46153b5d7169b808833631ea743c]
#
# patch "roster.cc"
# from [478a80fbf93015f064209e4222be626726dcbb47]
# to [9989ba61bf9d98cdc3551daaa3666cd37a752695]
#
# patch "roster.hh"
# from [249507b96d4cd90e81b8903cbcbb044f0c40510a]
# to [e752044dc5fb4183c3118daa8c8da40ef86ee3c7]
#
# patch "roster_delta.cc"
# from [195d0d3dc4bc6a59e8fbb3e46f85f446e731f989]
# to [eec178e2824304d6ab5201abab47fdb157c15884]
#
# patch "roster_merge.cc"
# from [cd5f29d931fffca5e7e5f6874f9832c4edb1e0be]
# to [4fdb63c868ad20c20d95cde69bddc987316eac0d]
#
# patch "tests/resolve_duplicate_name_conflict/expected-merge-messages-abe_1-beth_1"
# from [b40e0b77db581192a3751a3c267177e1451dfe0e]
# to [8cc5c13905078a96dd1e308964537c69ed78f4e8]
#
============================================================
--- tests/resolve_duplicate_name_conflict/expected-merge-messages-abe_2-jim_1-conflicts c505d776680d4278cfbb27e0cb850ba8486e86bd
+++ tests/resolve_duplicate_name_conflict/expected-merge-messages-abe_2-jim_1-conflicts c505d776680d4278cfbb27e0cb850ba8486e86bd
@@ -0,0 +1,13 @@
+mtn: 2 heads on branch 'testbranch'
+mtn: [left] 257729bebdb32819cd1fc059806e0fb4144f7ec7
+mtn: [right] 3bb925aabafadcdbdc502699024ee282fef0c512
+mtn: 1 content conflict requires user intervention
+mtn: conflict: content conflict on file 'checkout.sh'
+mtn: content hash is 3390893b9a31eaa9ef0e9364b27ee1e617e6891a on the left
+mtn: content hash is a8acbc7472178c5e87c3f0a6953ac5db954e1205 on the right
+mtn: help required for 3-way merge
+mtn: [ancestor] checkout.sh
+mtn: [ left] checkout.sh
+mtn: [ right] checkout.sh
+mtn: [ merged] checkout.sh
+mtn: error: merge failed due to unresolved conflicts
============================================================
--- tests/resolve_duplicate_name_conflict/merge-abe_2-jim_1-resolve_conflicts bb50072864e1404e1da5597bca04c486c33bf2ed
+++ tests/resolve_duplicate_name_conflict/merge-abe_2-jim_1-resolve_conflicts bb50072864e1404e1da5597bca04c486c33bf2ed
@@ -0,0 +1,13 @@
+ left [257729bebdb32819cd1fc059806e0fb4144f7ec7]
+ right [3bb925aabafadcdbdc502699024ee282fef0c512]
+ancestor [5285636b9d9f988e79b3dcd9a40e64d15fb7fc9f]
+
+ conflict content
+ node_type "file"
+ ancestor_name "checkout.sh"
+ancestor_file_id [61b8d4fb0e5d78be111f691b955d523c782fa92e]
+ left_name "checkout.sh"
+ left_file_id [3390893b9a31eaa9ef0e9364b27ee1e617e6891a]
+ right_name "checkout.sh"
+ right_file_id [a8acbc7472178c5e87c3f0a6953ac5db954e1205]
+resolved_content "checkout.sh"
============================================================
--- revision.cc 9b166019d4923fd6219b72fb7563aa914238f81d
+++ revision.cc f036e8be10fd46153b5d7169b808833631ea743c
@@ -1,4 +1,4 @@
-// Copyright (C) 2004 Graydon Hoare
+// Copyright (C) 2004, 2008 Graydon Hoare
//
// This program is made available under the GNU GPL version 2.0 or
// greater. See the accompanying file COPYING for details.
@@ -67,14 +67,13 @@ using boost::shared_ptr;
// monotone release. Note that this is _not_ the database schema format; see
// schema_migration for that.
//
-// We use the oldest format number possible when writing each revision. That
-// means that if an old revision is regenerated, it has the same revid
-// (revision_format is included in the text that is hashed to compute the
-// revid). That maintains history, maximizes interoperability between
-// monotone versions, and simplifies maintaining the test suite; there are
-// many tests that have hard-coded revision ids, that would spuriously break
-// if the revision_format number changed. schema_migration and
-// workspace_migration in particular have this problem.
+// The revision format number is included in the revision text that is
+// hashed to compute the revid. Therefore we use the oldest format number
+// possible when writing each revision. That maintains history, maximizes
+// interoperability between monotone versions, and simplifies maintaining
+// the test suite; there are many tests that have hard-coded revision ids,
+// that would spuriously break if the revision_format number changed.
+// schema_migration and workspace_migration in particular have this problem.
static const unsigned int current_revision_format = 2;
static const unsigned int oldest_supported_revision_format = 1;
@@ -84,7 +83,7 @@ revision_t::required_revision_format() c
// Format 2 supports file suturing, so check the edges to see if there are
// any sutures.
unsigned int result = oldest_supported_revision_format;
-
+
for (edge_map::const_iterator i = edges.begin(); i != edges.end(); ++i)
if (i->second->nodes_sutured.size() > 0)
result = 2;
============================================================
--- roster.cc 478a80fbf93015f064209e4222be626726dcbb47
+++ roster.cc 9989ba61bf9d98cdc3551daaa3666cd37a752695
@@ -64,11 +64,37 @@ namespace
}
}
-// The marking_map format number must be incremented whenever any basic_io
-// format used for marking_map data in the database changes, but only once
-// per monotone release.
-static const unsigned int current_marking_map_format = 2;
+// The roster format number must be incremented whenever any basic_io format
+// used for roster or marking_map data in the database changes, but only
+// once per monotone release.
+//
+// A hash of the manifest text is included in the revision text that is
+// hashed to compute the revid, and we want to produce the same revision id
+// when an old revision is regenerated. Therefore we use the oldest format
+// number possible when writing each manifest.
+static const unsigned int current_roster_format = 2;
+static const unsigned int oldest_supported_roster_format = 1;
+unsigned int
+roster_t::required_roster_format(marking_map const & mm) const
+{
+ // Format 2 supports birth_cause in the marking_map. This only matters if
+ // there is a suture or split, so check the marking map for those.
+ unsigned int result = oldest_supported_roster_format;
+
+ for (marking_map::const_iterator i = mm.begin(); i != mm.end(); ++i)
+ if (i->second.birth_cause.first != marking_t::add)
+ result = 2;
+
+ return result;
+}
+
+unsigned int
+roster_current_roster_format()
+{
+ return current_roster_format;
+}
+
template <> void
dump(node_id const & val, string & out)
{
@@ -93,10 +119,6 @@ dump(std::pairself != b->self)
return false;
@@ -531,8 +554,13 @@ shallow_equal(node_t a, node_t b,
if (a->attrs != b->attrs)
return false;
- if (a->ancestors != b->ancestors)
- return false;
+ if (compare_ancestors)
+ // compare_ancestors is set false in unit tests when comparing a merge
+ // to a parent; in that case, the ancestors may be different; the child
+ // has the parent as an ancestor, but the parent is probably the birth
+ // revision, and has no ancestor.
+ if (a->ancestors != b->ancestors)
+ return false;
if (! same_type(a,b))
return false;
@@ -1155,7 +1183,6 @@ roster_t::check_sane_against(marking_map
++ri, ++mi)
{
I(!null_id(mi->second.birth_revision));
- I(mi->second.birth_cause.first != marking_t::invalid);
I(!mi->second.parent_name.empty());
if (is_file_t(ri->second))
@@ -1830,9 +1857,6 @@ mark_merge_roster(roster_t const & left_
switch (left_marking.birth_cause.first)
{
- case marking_t::invalid:
- I(false);
-
case marking_t::add:
// Must be unborn on the right (as opposed to dead);
// otherwise it would not be in the merge. Therefore the
@@ -2731,7 +2755,8 @@ push_marking(basic_io::stanza & st,
void
push_marking(basic_io::stanza & st,
bool is_file,
- marking_t const & mark)
+ marking_t const & mark,
+ int const marking_format)
{
I(!null_id(mark.birth_revision));
@@ -2739,16 +2764,14 @@ push_marking(basic_io::stanza & st,
switch (mark.birth_cause.first)
{
- case marking_t::invalid:
- I(false);
- break;
-
case marking_t::add:
- st.push_str_pair(syms::birth_cause, syms::birth_add);
+ if (marking_format > 1)
+ st.push_str_pair(syms::birth_cause, syms::birth_add);
break;
case marking_t::suture:
{
+ I(marking_format > 1);
std::vector data;
data.push_back(lexical_cast(mark.birth_cause.second.first));
data.push_back(lexical_cast(mark.birth_cause.second.second));
@@ -2758,6 +2781,7 @@ push_marking(basic_io::stanza & st,
case marking_t::split:
{
+ I(marking_format > 1);
std::vector data;
data.push_back(lexical_cast(mark.birth_cause.second.first));
st.push_str_multi(syms::birth_cause, syms::birth_split, data);
@@ -2803,6 +2827,9 @@ parse_marking(basic_io::parser & pa,
}
else if (pa.symp(syms::birth_cause))
{
+ // If the current roster_format is 1, there will be no birth_cause
+ // line, and marking.birth_cause will default to marking_t::add,
+ // which is correct.
std::string tmp_1, tmp_2;
pa.sym();
@@ -2869,9 +2896,11 @@ roster_t::print_to(basic_io::printer & p
bool print_local_parts) const
{
I(has_root());
+
+ int const marking_format = required_roster_format(mm);
{
basic_io::stanza st;
- st.push_str_pair(basic_io::syms::format_version, lexical_cast(current_marking_map_format));
+ st.push_str_pair(basic_io::syms::format_version, lexical_cast(marking_format));
pr.print_stanza(st);
}
for (dfs_iter i(root_dir, true); !i.finished(); ++i)
@@ -2924,7 +2953,7 @@ roster_t::print_to(basic_io::printer & p
marking_map::const_iterator m = mm.find(curr->self);
I(m != mm.end());
- push_marking(st, is_file_t(curr), m->second);
+ push_marking(st, is_file_t(curr), m->second, marking_format);
}
pr.print_stanza(st);
@@ -2969,7 +2998,12 @@ roster_t::parse_from(basic_io::parser &
pa.esym(basic_io::syms::format_version);
string vers;
pa.str(vers);
- I(vers == lexical_cast(current_marking_map_format));
+ unsigned int format = boost::lexical_cast(vers);
+ E(format <= current_roster_format,
+ F("encountered a roster with unknown format version %s\n"
+ "I only understand formats up to version %s\n"
+ "a newer version of monotone is required to complete this operation")
+ % vers % current_roster_format);
}
while(pa.symp())
============================================================
--- roster.hh 249507b96d4cd90e81b8903cbcbb044f0c40510a
+++ roster.hh e752044dc5fb4183c3118daa8c8da40ef86ee3c7
@@ -133,14 +133,16 @@ bool
}
bool
-shallow_equal(node_t a, node_t b, bool shallow_compare_dir_children,
- bool compare_file_contents = true);
+shallow_equal(node_t a, node_t b,
+ bool shallow_compare_dir_children,
+ bool compare_file_contents = true,
+ bool compare_ancestors = true);
template <> void dump(node_t const & n, std::string & out);
struct marking_t
{
- typedef enum {invalid, add, suture, split} birth_cause_t;
+ typedef enum {add, suture, split} birth_cause_t;
revision_id birth_revision;
std::pair > birth_cause;
@@ -149,7 +151,7 @@ struct marking_t
std::set parent_name;
std::set file_content;
std::map > attrs;
- marking_t() : birth_cause (std::make_pair (invalid, null_ancestors)) {};
+ marking_t() : birth_cause (std::make_pair (add, null_ancestors)) {};
bool operator==(marking_t const & other) const
{
return birth_revision == other.birth_revision
@@ -242,6 +244,8 @@ public:
// marking map
void check_sane_against(marking_map const & marks, bool temp_nodes_ok=false) const;
+ unsigned int required_roster_format(marking_map const & mm) const;
+
void print_to(basic_io::printer & pr,
marking_map const & mm,
bool print_local_parts) const;
@@ -422,7 +426,8 @@ void calculate_ident(roster_t const & ro
manifest_id & ident);
// for roster_delta
-void push_marking(basic_io::stanza & st, bool is_file, marking_t const & mark);
+unsigned int roster_current_roster_format();
+void push_marking(basic_io::stanza & st, bool is_file, marking_t const & mark, int const marking_format);
void parse_marking(basic_io::parser & pa, marking_t & marking);
#ifdef BUILD_UNIT_TESTS
============================================================
--- roster_delta.cc 195d0d3dc4bc6a59e8fbb3e46f85f446e731f989
+++ roster_delta.cc eec178e2824304d6ab5201abab47fdb157c15884
@@ -1,3 +1,4 @@
+// Copyright (C) 2008 Stephen Leake
// Copyright (C) 2006 Nathaniel Smith
//
// This program is made available under the GNU GPL version 2.0 or
@@ -28,7 +29,7 @@ using std::make_pair;
using std::pair;
using std::make_pair;
-namespace
+namespace
{
struct roster_delta_t
@@ -82,10 +83,10 @@ namespace
// Add the new things.
for (dirs_added_t::const_iterator
i = dirs_added.begin(); i != dirs_added.end(); ++i)
- roster.create_dir_node(i->second);
+ roster.create_dir_node(i->second, null_ancestors);
for (files_added_t::const_iterator
i = files_added.begin(); i != files_added.end(); ++i)
- roster.create_file_node(i->second.second, i->second.first);
+ roster.create_file_node(i->second.second, i->second.first, null_ancestors);
// Attach everything.
for (dirs_added_t::const_iterator
@@ -206,17 +207,17 @@ namespace
{
case parallel::invalid:
I(false);
-
+
case parallel::in_left:
// deleted
safe_insert(d.nodes_deleted, i.left_key());
break;
-
+
case parallel::in_right:
// added
do_delta_for_node_only_in_dest(i.right_data(), d);
break;
-
+
case parallel::in_both:
// moved/patched/attribute changes
do_delta_for_node_in_both(i.left_data(), i.right_data(), d);
@@ -233,17 +234,17 @@ namespace
{
case parallel::invalid:
I(false);
-
+
case parallel::in_left:
// deleted; don't need to do anything (will be handled by
// nodes_deleted set
break;
-
+
case parallel::in_right:
// added
safe_insert(d.markings_changed, i.right_value());
break;
-
+
case parallel::in_both:
// maybe changed
if (!(i.left_data() == i.right_data()))
@@ -264,7 +265,7 @@ namespace
symbol const attr_cleared("attr_cleared");
symbol const attr_changed("attr_changed");
symbol const marking("marking");
-
+
symbol const content("content");
symbol const location("location");
symbol const attr("attr");
@@ -355,7 +356,7 @@ namespace
basic_io::stanza st;
push_nid(syms::marking, i->first, st);
// ...this second argument is a bit odd...
- push_marking(st, !i->second.file_content.empty(), i->second);
+ push_marking(st, !i->second.file_content.empty(), i->second, roster_current_roster_format());
printer.print_stanza(st);
}
}
@@ -459,7 +460,7 @@ namespace
safe_insert(d.markings_changed, make_pair(nid, m));
}
}
-
+
} // end anonymous namespace
void
@@ -536,7 +537,7 @@ try_get_content_from_roster_delta(roster
{
roster_delta_t d;
read_roster_delta(del, d);
-
+
roster_delta_t::deltas_applied_t::const_iterator i = d.deltas_applied.find(nid);
if (i != d.deltas_applied.end())
{
@@ -563,7 +564,7 @@ try_get_content_from_roster_delta(roster
return true;
}
}
-
+
return false;
}
============================================================
--- roster_merge.cc cd5f29d931fffca5e7e5f6874f9832c4edb1e0be
+++ roster_merge.cc 4fdb63c868ad20c20d95cde69bddc987316eac0d
@@ -1865,9 +1865,6 @@ namespace
switch (birth_cause.first)
{
- case marking_t::invalid:
- I(false);
-
case marking_t::add:
// case ii, iv; if ii, conflict will be discovered in next phase
create_node_for(n, new_roster);
@@ -2572,7 +2569,7 @@ struct base_scalar
void
make_dir(char const * name, node_id nid, roster_t & r, marking_map & markings)
{
- r.create_dir_node(nid);
+ r.create_dir_node(nid, null_ancestors);
r.attach_node(nid, file_path_internal(name));
marking_t marking;
marking.birth_revision = root_rid;
@@ -2583,7 +2580,7 @@ struct base_scalar
void
make_file(char const * name, node_id nid, roster_t & r, marking_map & markings)
{
- r.create_file_node(arbitrary_file, nid);
+ r.create_file_node(arbitrary_file, nid, null_ancestors);
r.attach_node(nid, file_path_internal(name));
marking_t marking;
marking.birth_revision = root_rid;
@@ -2813,7 +2810,9 @@ struct file_content_scalar : public virt
break;
case scalar_conflict:
file_content_conflict const & c = idx(result.file_content_conflicts, 0);
- I(c.nid == thing_nid);
+ I(c.left_nid == thing_nid);
+ I(c.right_nid == thing_nid);
+ I(c.result_nid == thing_nid);
I(c.left == content_for(left_val));
I(c.right == content_for(right_val));
file_id & content = downcast_to_file_t(result.roster.get_node(thing_nid))->content;
@@ -2987,7 +2986,7 @@ make_dir(roster_t & r, marking_map & mar
revision_id const & birth_rid, revision_id const & parent_name_rid,
string const & name, node_id nid)
{
- r.create_dir_node(nid);
+ r.create_dir_node(nid, null_ancestors);
r.attach_node(nid, file_path_internal(name));
marking_t marking;
marking.birth_revision = birth_rid;
@@ -3002,7 +3001,7 @@ make_file(roster_t & r, marking_map & ma
string const & name, file_id const & content,
node_id nid)
{
- r.create_file_node(content, nid);
+ r.create_file_node(content, nid, null_ancestors);
r.attach_node(nid, file_path_internal(name));
marking_t marking;
marking.birth_revision = birth_rid;
@@ -3060,22 +3059,25 @@ UNIT_TEST(roster_merge, node_lifecycle)
// 7 = 1 root + 2 common + 2 safe a + 2 safe b
I(result.roster.all_nodes().size() == 7);
// check that they're the right ones...
+ MM(result.roster);
+ MM(a_roster);
+ MM(b_roster);
I(shallow_equal(result.roster.get_node(common_dir_nid),
- a_roster.get_node(common_dir_nid), false));
+ a_roster.get_node(common_dir_nid), false, true, false));
I(shallow_equal(result.roster.get_node(common_file_nid),
- a_roster.get_node(common_file_nid), false));
+ a_roster.get_node(common_file_nid), false, true, false));
I(shallow_equal(result.roster.get_node(common_dir_nid),
- b_roster.get_node(common_dir_nid), false));
+ b_roster.get_node(common_dir_nid), false, true, false));
I(shallow_equal(result.roster.get_node(common_file_nid),
- b_roster.get_node(common_file_nid), false));
+ b_roster.get_node(common_file_nid), false, true, false));
I(shallow_equal(result.roster.get_node(a_safe_dir_nid),
- a_roster.get_node(a_safe_dir_nid), false));
+ a_roster.get_node(a_safe_dir_nid), false, true, false));
I(shallow_equal(result.roster.get_node(a_safe_file_nid),
- a_roster.get_node(a_safe_file_nid), false));
+ a_roster.get_node(a_safe_file_nid), false, true, false));
I(shallow_equal(result.roster.get_node(b_safe_dir_nid),
- b_roster.get_node(b_safe_dir_nid), false));
+ b_roster.get_node(b_safe_dir_nid), false, true, false));
I(shallow_equal(result.roster.get_node(b_safe_file_nid),
- b_roster.get_node(b_safe_file_nid), false));
+ b_roster.get_node(b_safe_file_nid), false, true, false));
}
UNIT_TEST(roster_merge, attr_lifecycle)
============================================================
--- tests/resolve_duplicate_name_conflict/expected-merge-messages-abe_1-beth_1 b40e0b77db581192a3751a3c267177e1451dfe0e
+++ tests/resolve_duplicate_name_conflict/expected-merge-messages-abe_1-beth_1 8cc5c13905078a96dd1e308964537c69ed78f4e8
@@ -1,8 +1,8 @@ mtn: 2 heads on branch 'testbranch'
mtn: 2 heads on branch 'testbranch'
-mtn: [left] c898aad0501a43b1cc6d5138afdbc7844e4efc91
-mtn: [right] ff5f7c356494ecf4c447701cc0c31b59b14981eb
+mtn: [left] 5285636b9d9f988e79b3dcd9a40e64d15fb7fc9f
+mtn: [right] e9ad84a3fc40ef1109251c308428439c21ad1de9
mtn: suturing checkout.sh, checkout.sh into checkout.sh
mtn: renaming thermostat.c to thermostat-westinghouse.c
mtn: renaming thermostat.c to thermostat-honeywell.c
-mtn: [merged] 80f7e6f31b93c075aa76eed810925f1c45a593c8
+mtn: [merged] 257729bebdb32819cd1fc059806e0fb4144f7ec7
mtn: note: your workspaces have not been updated