[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Monotone-commits-diffs] net.venge.monotone.issue-209: bf033095aaea2a927
From: |
code |
Subject: |
[Monotone-commits-diffs] net.venge.monotone.issue-209: bf033095aaea2a9278e5f869efb4dc3116ff5a12 |
Date: |
Sun, 3 Jun 2012 17:47:18 +0200 (CEST) |
revision: bf033095aaea2a9278e5f869efb4dc3116ff5a12
date: 2012-05-16T19:16:04
author: address@hidden
branch: net.venge.monotone.issue-209
changelog:
add support for dropped/modified conflict; first test passes
* doc/monotone.texi: add dropped/modified
* src/merge_roster.hh:
* src/merge_roster.cc:
* src/merge_content.cc (resolve_merge_conflicts):
* src/merge_conflict.cc:
* src/cmd_merging.cc (show_conflicts_core):
* src/cmd_conflicts.cc (show_conflicts, set_first_conflict): add
dropped/modified
* test/func/resolve_conflicts_dropped_modified: New directory.
manifest:
format_version "1"
new_manifest [927e3f56a044a768857efa1392e262e4d780a131]
old_revision [53e02eaa302bc05e96a18e3882b0e9843b53cf9a]
add_dir "test/func/resolve_conflicts_dropped_modified"
add_file "test/func/resolve_conflicts_dropped_modified/__driver__.lua"
content [5cc8d92ebd6d5590401e902cfaccf8d8252c996a]
add_file "test/func/resolve_conflicts_dropped_modified/conflicts-1"
content [f67001a294d492e4e3c0a2196e37c2a23077e27a]
add_file "test/func/resolve_conflicts_dropped_modified/conflicts-1-resolved"
content [ecb345496807dd3a509bc7f4ef751abf55c8233a]
patch "doc/monotone.texi"
from [d1293584f8a36c591fec36bc00427f77512c9876]
to [c4b06dbfa4640e9358dbbfadf36c78de7d9a2f64]
patch "src/cmd_conflicts.cc"
from [86bf4eb2e0608a8b9814cef8b416626b4aa0ca90]
to [c88107b417e03c5d6b8b916830ba1e9c898f47c8]
patch "src/cmd_merging.cc"
from [84b177469ecb60664be23c42c38cc649d23899a7]
to [7050a2b91ad9a15d6b8066c2b5e54bb96c87265c]
patch "src/merge_conflict.cc"
from [1c09dc4a20532ce040c429d7fb5ed2a25a199856]
to [9921b266cef59c6e2b3d3fd5fda16cf2c48fced1]
patch "src/merge_content.cc"
from [76d5a0997d9217b309d75806f8059d8f56f2ca49]
to [f3b9e82e6c46b53d17147068607cec03d581957b]
patch "src/merge_roster.cc"
from [98297d6264f77d540fc8e1578b1ebc5b2f36ec38]
to [8f846a5a40e36dba86f99f8ed48b3579c3bbe494]
patch "src/merge_roster.hh"
from [cd2da3b06f595187a27622a98580b0636aabea4b]
to [605b6f3f2a3e674e8542864523660ca86e797693]
============================================================
--- doc/monotone.texi d1293584f8a36c591fec36bc00427f77512c9876
+++ doc/monotone.texi c4b06dbfa4640e9358dbbfadf36c78de7d9a2f64
@@ -3560,6 +3560,15 @@ @subheading Multiple Name Conflict
In earlier versions of monotone (those before version 0.39) this type
of conflict was referred to as a @emph{name conflict}.
address@hidden Dropped/Modified Conflict
+
+A dropped/modified conflict occurs when a single file has
+been dropped in one merge parent, and modified in the other.
+
address@hidden supports resolving this conflict; the possible
+resolutions are to drop the file in the result, keep the modified
+version, or keep a user supplied version.
+
@subheading Attribute Conflict
An attribute conflict occurs when a versioned attribute on a file or
@@ -5125,11 +5134,11 @@ @subheading Commands
@item mtn conflicts show_remaining address@hidden
Show remaining unresolved conflicts in the conflicts file.
address@hidden mtn conflicts resolve_first address@hidden @var{resolution}
address@hidden conflicts address@hidden mtn conflicts resolve_first address@hidden @var{resolution}
Specify a resolution for the first conflict in the conflicts file; it
must be a single file conflict. The conflicts file is updated.
address@hidden conflicts address@hidden mtn conflicts resolve_first_left address@hidden @var{resolution}
address@hidden mtn conflicts resolve_first_left address@hidden @var{resolution}
@itemx mtn conflicts resolve_first_right address@hidden @var{resolution}
Specify a resolution for one of the files in the first conflict in the
conflicts file; it must be a two file conflict. The conflicts file is
@@ -10214,6 +10223,8 @@ @section Automation
@itemize
@item
+FIXME: -- Add reporting and resolution for dropped/modified conflicts.
address@hidden
11.0 -- Add resolution for orphaned node conflicts. Deleted
@code{resolved_user} conflict resolution; use @code{resolved_*_left}
for single file conflicts. Add @code{resolved_keep_left,
@@ -10426,6 +10437,17 @@ @section Automation
right_file_id [e80910e54d0bdea1b6d295ada320b87aaf9fdc23]
@end verbatim
+File dropped and modified (and possibly renamed):
address@hidden
+ conflict drop_modified
+ ancestor_name "foo"
+ancestor_file_id [e80910e54d0bdea1b6d295ada320b87aaf9fdc23]
+ left_type "dropped file"
+ right_type "modified file"
+ right_name "baz"
+ right_file_id [fe6d523f607e2f2fc0f0defad3bda0351a95a337]
address@hidden verbatim
+
Invalid file name (@file{_MTN} in root directory):
@verbatim
conflict invalid_name
============================================================
--- src/cmd_conflicts.cc 86bf4eb2e0608a8b9814cef8b416626b4aa0ca90
+++ src/cmd_conflicts.cc c88107b417e03c5d6b8b916830ba1e9c898f47c8
@@ -84,6 +84,57 @@ show_conflicts(database & db, conflicts_
}
}
+ for (std::vector<dropped_modified_conflict>::iterator i = conflicts.result.dropped_modified_conflicts.begin();
+ i != conflicts.result.dropped_modified_conflicts.end();
+ ++i)
+ {
+ dropped_modified_conflict & conflict = *i;
+
+ if (conflict.resolution.first == resolve_conflicts::none)
+ {
+ node_id nid;
+ file_path modified_name;
+
+ if (conflict.left_nid == the_null_node)
+ {
+ // left side dropped, right side modified
+ nid = conflict.right_nid;
+ conflicts.right_roster->get_name(conflict.right_nid, modified_name);
+ }
+ else
+ {
+ // left side modified, right side dropped
+ nid = conflict.left_nid;
+ conflicts.left_roster->get_name(conflict.left_nid, modified_name);
+ }
+
+ P(F("conflict: file '%s'") % modified_name);
+ if (conflict.left_nid == the_null_node)
+ {
+ P(F("dropped on the left"));
+ P(F("modified on the right"));
+ }
+ else
+ {
+ P(F("modified on the left"));
+ P(F("dropped on the right"));
+ }
+
+ switch (show_case)
+ {
+ case first:
+ P(F("possible resolutions:"));
+ P(F("resolve_first drop"));
+ P(F("resolve_first keep"));
+ P(F("resolve_first user \"name\""));
+ return;
+
+ case remaining:
+ break;
+ }
+ }
+ }
+
for (std::vector<duplicate_name_conflict>::iterator i = conflicts.result.duplicate_name_conflicts.begin();
i != conflicts.result.duplicate_name_conflicts.end();
++i)
@@ -187,6 +238,8 @@ show_conflicts(database & db, conflicts_
(*conflicts.left_roster, *conflicts.right_roster, adaptor, false, std::cout);
conflicts.result.report_multiple_name_conflicts
(*conflicts.left_roster, *conflicts.right_roster, adaptor, false, std::cout);
+ conflicts.result.report_dropped_modified_conflicts
+ (*conflicts.left_roster, *conflicts.right_roster, adaptor, false, std::cout);
conflicts.result.report_attribute_conflicts
(*conflicts.left_roster, *conflicts.right_roster, adaptor, false, std::cout);
}
@@ -357,6 +410,42 @@ set_first_conflict(database & db,
}
}
+ for (std::vector<dropped_modified_conflict>::iterator i = conflicts.result.dropped_modified_conflicts.begin();
+ i != conflicts.result.dropped_modified_conflicts.end();
+ ++i)
+ {
+ dropped_modified_conflict & conflict = *i;
+
+ if (conflict.resolution.first == resolve_conflicts::none)
+ {
+ if ("drop" == idx(args,0)())
+ {
+ E(args.size() == 1, origin::user, F("wrong number of arguments"));
+
+ conflict.resolution.first = resolve_conflicts::drop;
+ }
+ else if ("keep" == idx(args,0)())
+ {
+ E(args.size() == 1, origin::user, F("wrong number of arguments"));
+
+ conflict.resolution.first = resolve_conflicts::keep;
+ }
+ else if ("user" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+
+ conflict.resolution.first = resolve_conflicts::content_user;
+ conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+ }
+ else
+ {
+ E(false, origin::user,
+ F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
+ }
+ return;
+ }
+ }
+
for (std::vector<file_content_conflict>::iterator i = conflicts.result.file_content_conflicts.begin();
i != conflicts.result.file_content_conflicts.end();
++i)
============================================================
--- src/cmd_merging.cc 84b177469ecb60664be23c42c38cc649d23899a7
+++ src/cmd_merging.cc 7050a2b91ad9a15d6b8066c2b5e54bb96c87265c
@@ -1,5 +1,5 @@
// Copyright (C) 2002 Graydon Hoare <address@hidden>
-// 2008, 2010 Stephen Leake <address@hidden>
+// 2008, 2010, 2012 Stephen Leake <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
// greater. See the accompanying file COPYING for details.
@@ -1064,6 +1064,7 @@ show_conflicts_core (database & db,
result.report_orphaned_node_conflicts(*l_roster, *r_roster, adaptor, basic_io, output);
result.report_multiple_name_conflicts(*l_roster, *r_roster, adaptor, basic_io, output);
+ result.report_dropped_modified_conflicts(*l_roster, *r_roster, adaptor, basic_io, output);
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);
============================================================
--- src/merge_conflict.cc 1c09dc4a20532ce040c429d7fb5ed2a25a199856
+++ src/merge_conflict.cc 9921b266cef59c6e2b3d3fd5fda16cf2c48fced1
@@ -1,5 +1,5 @@
// Copyright (C) 2005 Nathaniel Smith <address@hidden>
-// 2008, 2009 Stephen Leake <address@hidden>
+// 2008, 2009, 2012 Stephen Leake <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
// greater. See the accompanying file COPYING for details.
@@ -50,6 +50,7 @@ namespace
symbol const conflict("conflict");
symbol const content("content");
symbol const directory_loop("directory_loop");
+ symbol const dropped_modified("dropped_modified");
symbol const duplicate_name("duplicate_name");
symbol const invalid_name("invalid_name");
symbol const left("left");
@@ -1048,6 +1049,104 @@ void
}
void
+roster_merge_result::report_dropped_modified_conflicts(roster_t const & left_roster,
+ roster_t const & right_roster,
+ content_merge_adaptor & adaptor,
+ const bool basic_io,
+ std::ostream & output) const
+{
+ MM(left_roster);
+ MM(right_roster);
+
+ for (size_t i = 0; i < dropped_modified_conflicts.size(); ++i)
+ {
+ dropped_modified_conflict const & conflict = dropped_modified_conflicts[i];
+ MM(conflict);
+
+ node_id nid;
+ file_path modified_name;
+
+ if (conflict.left_nid == the_null_node)
+ {
+ // left side dropped, right side modified
+ I(!roster.is_attached(conflict.right_nid));
+
+ nid = conflict.right_nid;
+ right_roster.get_name(conflict.right_nid, modified_name);
+ }
+ else
+ {
+ // left side modified, right side dropped
+ I(!roster.is_attached(conflict.left_nid));
+
+ nid = conflict.left_nid;
+ left_roster.get_name(conflict.left_nid, modified_name);
+ }
+
+ shared_ptr<roster_t const> lca_roster;
+ revision_id lca_rid;
+ file_path ancestor_name;
+
+ adaptor.get_ancestral_roster(nid, lca_rid, lca_roster);
+ lca_roster->get_name(nid, ancestor_name);
+
+ if (basic_io)
+ {
+ basic_io::stanza st;
+
+ content_merge_database_adaptor & db_adaptor (dynamic_cast<content_merge_database_adaptor &>(adaptor));
+ file_id fid;
+
+ st.push_str_pair(syms::conflict, syms::dropped_modified);
+ st.push_str_pair(syms::ancestor_name, ancestor_name.as_external());
+ db_adaptor.db.get_file_content (db_adaptor.lca, nid, fid);
+ st.push_binary_pair(syms::ancestor_file_id, fid.inner());
+
+ if (conflict.left_nid == the_null_node)
+ {
+ st.push_str_pair(syms::left_type, "dropped file");
+ }
+ else
+ {
+ st.push_str_pair(syms::left_type, "modified file");
+ st.push_str_pair(syms::left_name, modified_name.as_external());
+ db_adaptor.db.get_file_content (db_adaptor.left_rid, nid, fid);
+ st.push_binary_pair(syms::left_file_id, fid.inner());
+ }
+
+ if (conflict.right_nid == the_null_node)
+ {
+ st.push_str_pair(syms::right_type, "dropped file");
+ }
+ else
+ {
+ st.push_str_pair(syms::right_type, "modified file");
+ st.push_str_pair(syms::right_name, modified_name.as_external());
+ db_adaptor.db.get_file_content (db_adaptor.right_rid, nid, fid);
+ st.push_binary_pair(syms::right_file_id, fid.inner());
+ }
+
+ put_resolution (st, left_side, conflict.resolution);
+ put_stanza(st, output);
+ }
+ else
+ {
+ P(F("conflict: file '%s' from revision %s") % ancestor_name % lca_rid);
+ if (conflict.left_nid == the_null_node)
+ {
+ P(F("dropped on the left"));
+ P(F("modified on the right, named %s") % modified_name);
+ }
+ else
+ {
+ P(F("modified on the left, named %s") % modified_name);
+ P(F("dropped on the right"));
+ }
+ }
+ }
+}
+
+void
roster_merge_result::report_duplicate_name_conflicts(roster_t const & left_roster,
roster_t const & right_roster,
content_merge_adaptor & adaptor,
@@ -1749,6 +1848,124 @@ static void
} // read_multiple_name_conflicts
static void
+read_dropped_modified_conflict(basic_io::parser & pars,
+ dropped_modified_conflict & conflict,
+ roster_t const & left_roster,
+ roster_t const & right_roster)
+{
+ string tmp;
+
+ pars.esym(syms::ancestor_name); pars.str();
+ pars.esym(syms::ancestor_file_id); pars.hex();
+
+ pars.esym(syms::left_type);
+ pars.str(tmp);
+
+ if (tmp == "dropped file")
+ {
+ // no more data for left
+ }
+ else
+ {
+ // modified file
+ pars.esym(syms::left_name); pars.str(tmp);
+ conflict.left_nid = left_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ pars.esym(syms::left_file_id); pars.hex();
+ }
+
+ pars.esym(syms::right_type);
+ pars.str(tmp);
+
+ if (tmp == "dropped file")
+ {
+ // no more data for right
+ }
+ else
+ {
+ // modified file
+ pars.esym(syms::right_name); pars.str(tmp);
+ conflict.right_nid = right_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ pars.esym(syms::right_file_id); pars.hex();
+ }
+
+ // check for a resolution
+ if ((!pars.symp (syms::conflict)) && pars.tok.in.lookahead != EOF)
+ {
+ if (pars.symp (syms::resolved_drop_left))
+ {
+ conflict.resolution.first = resolve_conflicts::drop;
+ pars.sym();
+ }
+ else if (pars.symp (syms::resolved_rename_left))
+ {
+ conflict.resolution.first = resolve_conflicts::rename;
+ pars.sym();
+ conflict.resolution.second = new_optimal_path(pars.token, true);
+ pars.str();
+ }
+ else
+ E(false, origin::user,
+ F(conflict_resolution_not_supported_msg) % pars.token % "dropped_modified");
+ }
+} // read_dropped_modified_conflict
+
+static void
+read_dropped_modified_conflicts(basic_io::parser & pars,
+ std::vector<dropped_modified_conflict> & conflicts,
+ roster_t const & left_roster,
+ roster_t const & right_roster)
+{
+ while (pars.tok.in.lookahead != EOF && pars.symp(syms::dropped_modified))
+ {
+ dropped_modified_conflict conflict(the_null_node, the_null_node);
+
+ pars.sym();
+
+ read_dropped_modified_conflict(pars, conflict, left_roster, right_roster);
+
+ conflicts.push_back(conflict);
+
+ if (pars.tok.in.lookahead != EOF)
+ pars.esym (syms::conflict);
+ }
+} // read_dropped_modified_conflicts
+static void
+validate_dropped_modified_conflicts(basic_io::parser & pars,
+ std::vector<dropped_modified_conflict> & conflicts,
+ roster_t const & left_roster,
+ roster_t const & right_roster)
+{
+ for (std::vector<dropped_modified_conflict>::iterator i = conflicts.begin();
+ i != conflicts.end();
+ ++i)
+ {
+ dropped_modified_conflict & merge_conflict = *i;
+ dropped_modified_conflict file_conflict (the_null_node, the_null_node);
+
+ pars.esym(syms::dropped_modified);
+
+ read_dropped_modified_conflict(pars, file_conflict, left_roster, right_roster);
+
+ // Note that we do not confirm the file ids.
+ E(merge_conflict.left_nid == file_conflict.left_nid &&
+ merge_conflict.right_nid == file_conflict.right_nid,
+ origin::user,
+ F(conflicts_mismatch_msg));
+
+ merge_conflict.resolution = file_conflict.resolution;
+
+ if (pars.tok.in.lookahead != EOF)
+ pars.esym (syms::conflict);
+ else
+ {
+ std::vector<dropped_modified_conflict>::iterator tmp = i;
+ E(++tmp == conflicts.end(), origin::user,
+ F(conflicts_mismatch_msg));
+ }
+ }
+} // validate_dropped_modified_conflicts
+
+static void
read_duplicate_name_conflict(basic_io::parser & pars,
duplicate_name_conflict & conflict,
roster_t const & left_roster,
@@ -2110,6 +2327,7 @@ read_conflict_file_core(basic_io::parser
// order as non-validate, below.
validate_orphaned_node_conflicts(pars, result.orphaned_node_conflicts, left_roster, right_roster);
+ validate_dropped_modified_conflicts(pars, result.dropped_modified_conflicts, left_roster, right_roster);
validate_duplicate_name_conflicts(pars, result.duplicate_name_conflicts, left_roster, right_roster);
validate_file_content_conflicts(pars, result.file_content_conflicts, left_roster, right_roster);
}
@@ -2122,6 +2340,7 @@ read_conflict_file_core(basic_io::parser
read_directory_loop_conflicts(pars, result.directory_loop_conflicts, left_roster, right_roster);
read_orphaned_node_conflicts(pars, result.orphaned_node_conflicts, left_roster, right_roster);
read_multiple_name_conflicts(pars, result.multiple_name_conflicts, left_roster, right_roster);
+ read_dropped_modified_conflicts(pars, result.dropped_modified_conflicts, left_roster, right_roster);
read_duplicate_name_conflicts(pars, result.duplicate_name_conflicts, left_roster, right_roster);
read_attribute_conflicts(pars, result.attribute_conflicts, left_roster, right_roster);
read_file_content_conflicts(pars, result.file_content_conflicts, left_roster, right_roster);
@@ -2212,6 +2431,7 @@ roster_merge_result::write_conflict_file
report_directory_loop_conflicts(*left_roster, *right_roster, adaptor, true, output);
report_orphaned_node_conflicts(*left_roster, *right_roster, adaptor, true, output);
report_multiple_name_conflicts(*left_roster, *right_roster, adaptor, true, output);
+ report_dropped_modified_conflicts(*left_roster, *right_roster, adaptor, true, output);
report_duplicate_name_conflicts(*left_roster, *right_roster, adaptor, true, output);
report_attribute_conflicts(*left_roster, *right_roster, adaptor, true, output);
report_file_content_conflicts(lua, *left_roster, *right_roster, adaptor, true, output);
@@ -2361,6 +2581,91 @@ roster_merge_result::resolve_orphaned_no
orphaned_node_conflicts.clear();
}
+void
+roster_merge_result::resolve_dropped_modified_conflicts(lua_hooks & lua,
+ roster_t const & left_roster,
+ roster_t const & right_roster,
+ content_merge_adaptor & adaptor)
+{
+ MM(left_roster);
+ MM(right_roster);
+ MM(this->roster); // New roster
+
+ // Conflict node is absent in the new roster
+
+ for (std::vector<dropped_modified_conflict>::const_iterator i = dropped_modified_conflicts.begin();
+ i != dropped_modified_conflicts.end();
+ ++i)
+ {
+ dropped_modified_conflict const & conflict = *i;
+ MM(conflict);
+
+ node_id nid;
+ file_path modified_name;
+ file_id modified_fid;
+
+ if (conflict.left_nid == the_null_node)
+ {
+ nid = conflict.right_nid;
+ right_roster.get_file_details(nid, modified_fid, modified_name);
+ }
+ else
+ {
+ nid = conflict.left_nid;
+ left_roster.get_file_details(nid, modified_fid, modified_name);
+ }
+
+ switch (conflict.resolution.first)
+ {
+ case resolve_conflicts::none:
+ E(false, origin::user,
+ F("no resolution provided for dropped_modifed '%s'") % modified_name);
+ break;
+
+ case resolve_conflicts::content_user:
+ P(F("replacing content of '%s' with '%s'") %
+ modified_name % conflict.resolution.second->as_external());
+
+ {
+ file_data modified_data, result_data;
+ data result_raw_data;
+ file_id result_fid;
+ adaptor.get_version(modified_fid, modified_data);
+
+ read_data(*conflict.resolution.second, result_raw_data);
+
+ result_data = file_data(result_raw_data);
+ calculate_ident(result_data, result_fid);
+
+ file_t result_node = downcast_to_file_t(roster.get_node_for_update(nid));
+ result_node->content = result_fid;
+
+ adaptor.record_file(modified_fid, result_fid, modified_data, result_data);
+
+ attach_node(lua, roster, nid, modified_name);
+ }
+ break;
+
+ case resolve_conflicts::drop:
+ P(F("dropping '%s'") % modified_name);
+
+ // already dropped; nothing to do
+ break;
+
+ case resolve_conflicts::keep:
+ P(F("keeping '%s'") % modified_name);
+ attach_node (lua, roster, nid, modified_name);
+ break;
+
+ default:
+ I(false);
+ }
+
+ } // end for
+
+ dropped_modified_conflicts.clear();
+}
+
static void
resolve_duplicate_name_one_side(lua_hooks & lua,
resolve_conflicts::file_resolution_t const & resolution,
@@ -2433,11 +2738,6 @@ resolve_duplicate_name_one_side(lua_hook
F("no resolution provided for duplicate_name '%s'") % name);
break;
- case resolve_conflicts::content_internal:
- E(false, origin::user,
- F("invalid resolution for duplicate_name '%s'") % name);
- break;
-
default:
I(false);
}
============================================================
--- src/merge_content.cc 76d5a0997d9217b309d75806f8059d8f56f2ca49
+++ src/merge_content.cc f3b9e82e6c46b53d17147068607cec03d581957b
@@ -1,5 +1,5 @@
// Copyright (C) 2008 Nathaniel Smith <address@hidden>
-// 2008, 2010 Stephen Leake <address@hidden>
+// 2008, 2010, 2012 Stephen Leake <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
// greater. See the accompanying file COPYING for details.
@@ -667,8 +667,9 @@ resolve_merge_conflicts(lua_hooks & lua,
E(result.attribute_conflicts.size() == 0, origin::user,
F(msg) % "attribute_conflicts");
- // resolve the ones we can.
+ // resolve the ones we can, if they have resolutions specified
result.resolve_orphaned_node_conflicts(lua, left_roster, right_roster, adaptor);
+ result.resolve_dropped_modified_conflicts(lua, left_roster, right_roster, adaptor);
result.resolve_duplicate_name_conflicts(lua, left_roster, right_roster, adaptor);
result.resolve_file_content_conflicts(lua, left_roster, right_roster, adaptor);
}
@@ -682,6 +683,7 @@ resolve_merge_conflicts(lua_hooks & lua,
result.report_orphaned_node_conflicts(left_roster, right_roster, adaptor, false, std::cout);
result.report_multiple_name_conflicts(left_roster, right_roster, adaptor, false, std::cout);
+ result.report_dropped_modified_conflicts(left_roster, right_roster, adaptor, false, std::cout);
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);
============================================================
--- src/merge_roster.cc 98297d6264f77d540fc8e1578b1ebc5b2f36ec38
+++ src/merge_roster.cc 8f846a5a40e36dba86f99f8ed48b3579c3bbe494
@@ -1,4 +1,4 @@
-// Copyright (C) 2008, 2010 Stephen Leake <address@hidden>
+// Copyright (C) 2008, 2010, 2012 Stephen Leake <address@hidden>
// 2005 Nathaniel Smith <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
@@ -89,6 +89,21 @@ template <> void
}
template <> void
+dump(dropped_modified_conflict const & conflict, string & out)
+{
+ ostringstream oss;
+ oss << "dropped_modified_conflict on node: " <<
+ conflict.left_nid == the_null_node ? conflict.right_nid : conflict.left_nid;
+ if (conflict.resolution.first != resolve_conflicts::none)
+ {
+ oss << " resolution: " << image(conflict.resolution.first);
+ oss << " name: " << conflict.resolution.second;
+ }
+ oss << "\n";
+ out = oss.str();
+}
+
+template <> void
dump(duplicate_name_conflict const & conflict, string & out)
{
ostringstream oss;
@@ -146,6 +161,7 @@ roster_merge_result::clear()
orphaned_node_conflicts.clear();
multiple_name_conflicts.clear();
+ dropped_modified_conflicts.clear();
duplicate_name_conflicts.clear();
attribute_conflicts.clear();
@@ -175,6 +191,7 @@ roster_merge_result::has_non_content_con
|| !directory_loop_conflicts.empty()
|| !orphaned_node_conflicts.empty()
|| !multiple_name_conflicts.empty()
+ || !dropped_modified_conflicts.empty()
|| !duplicate_name_conflicts.empty()
|| !attribute_conflicts.empty();
}
@@ -183,6 +200,7 @@ roster_merge_result::count_supported_res
roster_merge_result::count_supported_resolution() const
{
return orphaned_node_conflicts.size()
+ + dropped_modified_conflicts.size()
+ file_content_conflicts.size()
+ duplicate_name_conflicts.size();
}
@@ -209,6 +227,7 @@ dump_conflicts(roster_merge_result const
dump(result.orphaned_node_conflicts, out);
dump(result.multiple_name_conflicts, out);
+ dump(result.dropped_modified_conflicts, out);
dump(result.duplicate_name_conflicts, out);
dump(result.attribute_conflicts, out);
@@ -316,34 +335,42 @@ namespace
marking_map const & markings,
set<revision_id> const & uncommon_ancestors,
roster_t const & parent_roster,
- roster_t & new_roster)
+ side_t const present_in,
+ roster_merge_result & result)
{
const_marking_t const & m = markings.get_marking(n->self);
revision_id const & birth = m->birth_revision;
if (uncommon_ancestors.find(birth) != uncommon_ancestors.end())
- create_node_for(n, new_roster);
+ create_node_for(n, result.roster);
else
{
// In this branch we are NOT inserting the node into the new roster as it
// has been deleted from the other side of the merge.
- // In this case, output a warning if there are changes to the file on the
+ // In this case, create a conflict if there are changes to the file on the
// side of the merge where it still exists.
set<revision_id> const & content_marks = m->file_content;
bool found_one_ignored_content = false;
- for (set<revision_id>::const_iterator it = content_marks.begin(); it != content_marks.end(); it++)
+ for (set<revision_id>::const_iterator it = content_marks.begin();
+ (!found_one_ignored_content) && (it != content_marks.end());
+ it++)
{
if (uncommon_ancestors.find(*it) != uncommon_ancestors.end())
{
if (!found_one_ignored_content)
{
- file_path fp;
- parent_roster.get_name(n->self, fp);
- W(F("content changes to the file '%s'\n"
- "will be ignored during this merge as the file has been\n"
- "removed on one side of the merge. Affected revisions include:") % fp);
+ switch (present_in)
+ {
+ case left_side:
+ result.dropped_modified_conflicts.push_back
+ (dropped_modified_conflict(n->self, the_null_node));
+ break;
+ case right_side:
+ result.dropped_modified_conflicts.push_back
+ (dropped_modified_conflict(the_null_node, n->self));
+ break;
+ }
}
found_one_ignored_content = true;
- W(F("Revision: %s") % (*it));
}
}
}
@@ -515,13 +542,15 @@ roster_merge(roster_t const & left_paren
case parallel::in_left:
insert_if_unborn(i.left_data(),
left_markings, left_uncommon_ancestors, left_parent,
- result.roster);
+ left_side, // present_in
+ result);
break;
case parallel::in_right:
insert_if_unborn(i.right_data(),
right_markings, right_uncommon_ancestors, right_parent,
- result.roster);
+ right_side, // present_in
+ result);
break;
case parallel::in_both:
============================================================
--- src/merge_roster.hh cd2da3b06f595187a27622a98580b0636aabea4b
+++ src/merge_roster.hh 605b6f3f2a3e674e8542864523660ca86e797693
@@ -1,5 +1,5 @@
// Copyright (C) 2005, 2010 Nathaniel Smith <address@hidden>
-// 2008, 2009 Stephen Leake <address@hidden>
+// 2008, 2009, 2012 Stephen Leake <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
// greater. See the accompanying file COPYING for details.
@@ -90,6 +90,17 @@ struct multiple_name_conflict
std::pair<node_id, path_component> left, right;
};
+// nodes with drop/modified conflicts are left detached in the resulting
+// roster, with null parent and name fields.
+struct dropped_modified_conflict
+{
+ node_id left_nid, right_nid; // the dropped side is the null node, modified is valid.
+ resolve_conflicts::file_resolution_t resolution;
+
+ dropped_modified_conflict(node_id left_nid, node_id right_nid) : left_nid(left_nid), right_nid(right_nid)
+ {resolution.first = resolve_conflicts::none;}
+};
+
// this is when two distinct nodes want to have the same name. these nodes
// always each merged their names cleanly. the nodes in the resulting roster
// are both detached.
@@ -152,6 +163,7 @@ template <> void dump(multiple_name_conf
template <> void dump(orphaned_node_conflict const & conflict, std::string & out);
template <> void dump(multiple_name_conflict const & conflict, std::string & out);
+template <> void dump(dropped_modified_conflict const & conflict, std::string & out);
template <> void dump(duplicate_name_conflict const & conflict, std::string & out);
template <> void dump(attribute_conflict const & conflict, std::string & out);
@@ -166,16 +178,18 @@ struct roster_merge_result
// - duplicate name conflicts
// - orphaned node conflicts
// - multiple name conflicts
+ // - drop/modified conflicts
// - directory loop conflicts
// - attribute conflicts
// - file content conflicts
- bool missing_root_conflict;
+ bool missing_root_conflict; // there can only be one of these
std::vector<invalid_name_conflict> invalid_name_conflicts;
std::vector<directory_loop_conflict> directory_loop_conflicts;
std::vector<orphaned_node_conflict> orphaned_node_conflicts;
std::vector<multiple_name_conflict> multiple_name_conflicts;
+ std::vector<dropped_modified_conflict> dropped_modified_conflicts;
std::vector<duplicate_name_conflict> duplicate_name_conflicts;
std::vector<attribute_conflict> attribute_conflicts;
@@ -223,6 +237,16 @@ struct roster_merge_result
bool const basic_io,
std::ostream & output) const;
+ void report_dropped_modified_conflicts(roster_t const & left,
+ roster_t const & right,
+ content_merge_adaptor & adaptor,
+ bool const basic_io,
+ std::ostream & output) const;
+ void resolve_dropped_modified_conflicts(lua_hooks & lua,
+ roster_t const & left_roster,
+ roster_t const & right_roster,
+ content_merge_adaptor & adaptor);
+
void report_duplicate_name_conflicts(roster_t const & left,
roster_t const & right,
content_merge_adaptor & adaptor,
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified/__driver__.lua 5cc8d92ebd6d5590401e902cfaccf8d8252c996a
@@ -0,0 +1,62 @@
+-- Test reporting and resolving drop/modified conflicts
+--
+-- this is currently not supported; we are documenting a test case
+-- that must be considered when implementing it.
+
+mtn_setup()
+
+-- Create conflict; modify and rename file in one head, drop in other
+addfile("foo", "foo base")
+commit("testbranch", "base")
+base = base_revision()
+
+writefile("foo", "foo left")
+check(mtn("mv", "foo", "bar"), 0, false, false)
+
+commit("testbranch", "left 1")
+left_1 = base_revision()
+
+revert_to(base)
+
+writefile("foo", "foo right")
+commit("testbranch", "right 1")
+right_1 = base_revision()
+
+check(mtn("drop", "foo"), 0, false, false)
+commit("testbranch", "right 2")
+right_2 = base_revision()
+
+check(mtn("conflicts", "store"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: 1 conflict with supported resolutions.",
+ "mtn: stored in '_MTN/conflicts'"}))
+
+canonicalize("_MTN/conflicts")
+check(samefilestd("conflicts-1", "_MTN/conflicts"))
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'bar'",
+ "mtn: dropped on the left",
+ "mtn: modified on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first drop",
+ "mtn: resolve_first keep",
+ "mtn: resolve_first user \"name\""}))
+
+check(mtn("merge", "--resolve-conflicts"), 1, nil, true)
+check(qgrep("no resolution provided for", "stderr"))
+
+check(mtn("conflicts", "resolve_first", "drop"), 0, nil, true)
+
+canonicalize("_MTN/conflicts")
+check(samefilestd("conflicts-1-resolved", "_MTN/conflicts"))
+
+check(mtn("merge", "--resolve-conflicts"), 0, nil, true)
+check(qgrep("dropping 'bar'", "stderr"))
+
+-- FIXME: do three files at once: swap left/right, resolve keep; resolve user
+
+-- FIXME: add dropped_modified to 'show_conflicts' test (etc?)
+
+-- end of file
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified/conflicts-1 f67001a294d492e4e3c0a2196e37c2a23077e27a
@@ -0,0 +1,11 @@
+ left [92ea0d12182ab4761f8fe56a103aed9d65aff68d]
+ right [f5b4b65976746d1a2aa203ceaa67701353cc4172]
+ancestor [871b706565c414aa20f58f5f6db56778d64ece88]
+
+ conflict dropped_modified
+ ancestor_name "foo"
+ancestor_file_id [b02b6245b4b750465e12f65148d5369536b1b780]
+ left_type "dropped file"
+ right_type "modified file"
+ right_name "bar"
+ right_file_id [abd7d750f84aafa7c0b1f26540e2da28095bc082]
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified/conflicts-1-resolved ecb345496807dd3a509bc7f4ef751abf55c8233a
@@ -0,0 +1,12 @@
+ left [92ea0d12182ab4761f8fe56a103aed9d65aff68d]
+ right [f5b4b65976746d1a2aa203ceaa67701353cc4172]
+ancestor [871b706565c414aa20f58f5f6db56778d64ece88]
+
+ conflict dropped_modified
+ ancestor_name "foo"
+ ancestor_file_id [b02b6245b4b750465e12f65148d5369536b1b780]
+ left_type "dropped file"
+ right_type "modified file"
+ right_name "bar"
+ right_file_id [abd7d750f84aafa7c0b1f26540e2da28095bc082]
+resolved_drop_left
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Monotone-commits-diffs] net.venge.monotone.issue-209: bf033095aaea2a9278e5f869efb4dc3116ff5a12,
code <=