[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Monotone-commits-diffs] net.venge.monotone.issue-209: f33065689b915304e
From: |
code |
Subject: |
[Monotone-commits-diffs] net.venge.monotone.issue-209: f33065689b915304ecbc095df537751e12ebd3dd |
Date: |
Sat, 9 Jun 2012 17:32:36 +0200 (CEST) |
revision: f33065689b915304ecbc095df537751e12ebd3dd
date: 2012-06-06T06:47:14
author: address@hidden
branch: net.venge.monotone.issue-209
changelog:
handle dropped/modified conflict due to deleted directory.
* doc/monotone.texi: improve discussion of dropped/modified conflict due to
deleted directory.
* src/cmd_conflicts.cc (show_conflicts): add dropped_modifed_conflict.orphaned
(set_first_conflict): add dropped_modifed_conflict.orphaned resolutions of
rename, user_rename
* src/merge_conflict.cc (put_file_resolution): renamed from put_resolution;
dropped_modified has more fields in the resolution. Add content_user_rename
case.
(report_dropped_modified_conflicts, read_dropped_modified_conflict,
validate_dropped_modified_conflicts): handle conflict.orphaned
(resolve_dropped_modified_conflicts): add content_user_rename, rename.
* src/merge_roster.cc (image): add content_user_rename
(dump): add conflict.orphaned, conflict.rename
(assign_name): set conflict.orphaned
* src/merge_roster.hh (resolve_conflicts::resolution_t): add content_user_rename
(dropped_modified_conflict): add orphaned, rename
* test/func/(imp)_merge((patch_foo_a),_(delete_foo_)):
* test/func/merge((drop_a),_(rename_a_b,_patch_b)):
* test/func/merge((patch_a),_(drop_a)): deleted; merged with
resolve_conflicts_dropped_modified
* test/func/resolve_conflicts_dropped_modified/__driver__.lua: test dropped
directory case (passing). test drop, add vs modify; not passing.
* test/func/resolve_conflicts_dropped_modified/conflicts-orphaned: New file.
* test/func/resolve_conflicts_dropped_modified/conflicts-orphaned-resolved: New
file.
* test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned: New
file.
* test/func/update_with_pending_modification/__driver__.lua: change to show
unresolved conflict.
manifest:
format_version "1"
new_manifest [6457704d6a19512a9b8f4b362ddef41421b5233c]
old_revision [329d1fe78cc665997e872034520b09d0309f98eb]
delete "test/func/(imp)_merge((patch_foo_a),_(delete_foo_))"
delete "test/func/(imp)_merge((patch_foo_a),_(delete_foo_))/__driver__.lua"
delete "test/func/merge((drop_a),_(rename_a_b,_patch_b))"
delete "test/func/merge((drop_a),_(rename_a_b,_patch_b))/__driver__.lua"
delete "test/func/merge((patch_a),_(drop_a))"
delete "test/func/merge((patch_a),_(drop_a))/__driver__.lua"
add_file "test/func/resolve_conflicts_dropped_modified/conflicts-orphaned"
content [1d2aa9cc3444a9002bca7ba6d74335e943fbed3c]
add_file
"test/func/resolve_conflicts_dropped_modified/conflicts-orphaned-resolved"
content [203dc22e1122af927193f34e7186bb650b77302f]
add_file "test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned"
content [3fd23fd24470d5755be8e083666afadf9f9aad58]
patch "doc/monotone.texi"
from [3f52411f8776e632a9b6c1d7e5e588bb1cc8b1da]
to [f22f349d0207a09ae6806f8a57c86991a4143028]
patch "src/cmd_conflicts.cc"
from [c88107b417e03c5d6b8b916830ba1e9c898f47c8]
to [a4ebd8012db61009bdc9b24fc677c489b9812661]
patch "src/merge_conflict.cc"
from [3289a8141136c7f57982a06bd6dfeac3f1251a47]
to [b2d9fd8f7f7614af23106048c8810ae7e3c2ec60]
patch "src/merge_roster.cc"
from [4db179b2bb8e140d9ff9bd49f09306c578348759]
to [d68470addacbe005680b1f66a69f8a9edd4e6ea4]
patch "src/merge_roster.hh"
from [90740a700bceeecc6f662663246ddbe655f2edcb]
to [4bd3be5251736b3b0987a2179c6defbcd7d0b188]
patch "test/func/resolve_conflicts_dropped_modified/__driver__.lua"
from [7f16460e30c39738b2cf25239f1b9522b6c87fa1]
to [bcfc3ea32eb2bc76edc978567c24731402967120]
patch "test/func/update_with_pending_modification/__driver__.lua"
from [03be28a852978808341205ba2e2f713ce8dcaf35]
to [ac866e80c2aebb3803c42ad8ca275316050b9675]
============================================================
--- doc/monotone.texi 3f52411f8776e632a9b6c1d7e5e588bb1cc8b1da
+++ doc/monotone.texi f22f349d0207a09ae6806f8a57c86991a4143028
@@ -3489,7 +3489,7 @@ @subheading Dropped/Modified file Confli
@subheading Dropped/Modified file Conflict
This conflict occurs when a file is dropped in one merge parent,
-and modified on the other.
+and modified in the other.
@command{conflicts} supports resolving this conflict; the possible
resolutions are to drop the file in the result, keep the modified
@@ -3505,9 +3505,12 @@ @subheading Dropped/Modified file Confli
There is no such thing as a dropped/modified directory; if the
directory is empty, the only possible change is rename, which is
-ignored. If the directory is not empty, that creates orphaned file
-conflicts.
+ignored.
+If the directory is not empty, that creates a special case of
+dropped/modified file conflict; if the file is kept, it must also be
+renamed to an existing directory.
+
@subheading Invalid Name Conflict
Monotone reserves the name @file{_MTN} in a workspace root directory
@@ -10435,6 +10438,20 @@ @section Automation
right_file_id [fe6d523f607e2f2fc0f0defad3bda0351a95a337]
@end verbatim
+File orphaned and modified (and possibly renamed):
address@hidden
+ conflict dropped_modified
+ ancestor_name "foo"
+ancestor_file_id [e80910e54d0bdea1b6d295ada320b87aaf9fdc23]
+ left_type "orphaned file"
+ right_type "modified file"
+ right_name "baz"
+ right_file_id [fe6d523f607e2f2fc0f0defad3bda0351a95a337]
address@hidden verbatim
+Orphaned/modified is different from dropped/modified because the
+possible resolutions are different; orphaned requires a rename if the
+file is kept.
+
Invalid file name (@file{_MTN} in root directory):
@verbatim
conflict invalid_name
============================================================
--- src/cmd_conflicts.cc c88107b417e03c5d6b8b916830ba1e9c898f47c8
+++ src/cmd_conflicts.cc a4ebd8012db61009bdc9b24fc677c489b9812661
@@ -109,25 +109,52 @@ show_conflicts(database & db, conflicts_
}
P(F("conflict: file '%s'") % modified_name);
- if (conflict.left_nid == the_null_node)
+ if (conflict.orphaned)
{
- P(F("dropped on the left"));
- P(F("modified on the right"));
+ if (conflict.left_nid == the_null_node)
+ {
+ P(F("orphaned on the left"));
+ P(F("modified on the right"));
+ }
+ else
+ {
+ P(F("modified on the left"));
+ P(F("orphaned on the right"));
+ }
}
else
{
- P(F("modified on the left"));
- P(F("dropped on the right"));
+ 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;
+ if (conflict.orphaned)
+ {
+ P(F("possible resolutions:"));
+ P(F("resolve_first drop"));
+ P(F("resolve_first rename"));
+ P(F("resolve_first user_rename \"new_content_name\" \"new_file_name\""));
+ return;
+ }
+ else
+ {
+ P(F("possible resolutions:"));
+ P(F("resolve_first drop"));
+ P(F("resolve_first keep"));
+ P(F("resolve_first user \"name\""));
+ return;
+ }
case remaining:
break;
@@ -427,16 +454,35 @@ set_first_conflict(database & db,
else if ("keep" == idx(args,0)())
{
E(args.size() == 1, origin::user, F("wrong number of arguments"));
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
conflict.resolution.first = resolve_conflicts::keep;
}
else if ("user" == idx(args,0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
conflict.resolution.first = resolve_conflicts::content_user;
conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
}
+ else if ("rename" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+ E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+
+ conflict.resolution.first = resolve_conflicts::rename;
+ conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("user_rename" == idx(args,0)())
+ {
+ E(args.size() == 3, origin::user, F("wrong number of arguments"));
+ E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+
+ conflict.resolution.first = resolve_conflicts::content_user_rename;
+ conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+ conflict.rename = resolve_conflicts::new_file_path(idx(args,2)());
+ }
else
{
E(false, origin::user,
============================================================
--- src/merge_conflict.cc 3289a8141136c7f57982a06bd6dfeac3f1251a47
+++ src/merge_conflict.cc b2d9fd8f7f7614af23106048c8810ae7e3c2ec60
@@ -397,9 +397,9 @@ static void
enum side_t {left_side, right_side};
static void
-put_resolution(basic_io::stanza & st,
- side_t side,
- resolve_conflicts::file_resolution_t const & resolution)
+put_file_resolution(basic_io::stanza & st,
+ side_t side,
+ resolve_conflicts::file_resolution_t const & resolution)
{
// We output any resolution for any conflict; only valid resolutions
// should get into the data structures. To enforce that, when reading
@@ -424,6 +424,20 @@ put_resolution(basic_io::stanza & st,
}
break;
+ case resolve_conflicts::content_user_rename:
+ switch (side)
+ {
+ case left_side:
+ st.push_str_pair(syms::resolved_user_left, resolution.second->as_external());
+ break;
+
+ case right_side:
+ st.push_str_pair(syms::resolved_user_right, resolution.second->as_external());
+ break;
+ }
+ // value for rename is put by caller
+ break;
+
case resolve_conflicts::content_internal:
st.push_symbol(syms::resolved_internal);
break;
@@ -519,7 +533,7 @@ put_content_conflict (basic_io::stanza &
st.push_file_pair(syms::left_name, left_name);
st.push_file_pair(syms::right_name, right_name);
}
- put_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, left_side, conflict.resolution);
}
static void
@@ -985,7 +999,7 @@ roster_merge_result::report_orphaned_nod
if (basic_io)
{
- put_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, left_side, conflict.resolution);
put_stanza (st, output);
}
}
@@ -1104,7 +1118,14 @@ roster_merge_result::report_dropped_modi
if (conflict.left_nid == the_null_node)
{
- st.push_str_pair(syms::left_type, "dropped file");
+ if (conflict.orphaned)
+ {
+ st.push_str_pair(syms::left_type, "orphaned file");
+ }
+ else
+ {
+ st.push_str_pair(syms::left_type, "dropped file");
+ }
}
else
{
@@ -1116,7 +1137,14 @@ roster_merge_result::report_dropped_modi
if (conflict.right_nid == the_null_node)
{
- st.push_str_pair(syms::right_type, "dropped file");
+ if (conflict.orphaned)
+ {
+ st.push_str_pair(syms::right_type, "orphaned file");
+ }
+ else
+ {
+ st.push_str_pair(syms::right_type, "dropped file");
+ }
}
else
{
@@ -1126,7 +1154,26 @@ roster_merge_result::report_dropped_modi
st.push_binary_pair(syms::right_file_id, fid.inner());
}
- put_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, left_side, conflict.resolution);
+ if (conflict.orphaned)
+ {
+ switch (conflict.resolution.first)
+ {
+ case resolve_conflicts::none:
+ case resolve_conflicts::rename:
+ case resolve_conflicts::drop:
+ break;
+
+ case resolve_conflicts::content_user_rename:
+ st.push_str_pair(syms::resolved_rename_left, conflict.rename->as_external());
+ break;
+
+ default:
+ // FIXME: debugging
+ E(false, origin::user, F("conflict.resolution.first: %s") % conflict.resolution.first);
+ I(false);
+ }
+ }
put_stanza(st, output);
}
else
@@ -1134,13 +1181,27 @@ roster_merge_result::report_dropped_modi
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"));
+ if (conflict.orphaned)
+ {
+ P(F("orphaned on the left"));
+ }
+ else
+ {
+ 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"));
+ if (conflict.orphaned)
+ {
+ P(F("orphaned on the right"));
+ }
+ else
+ {
+ P(F("dropped on the right"));
+ }
}
}
}
@@ -1320,8 +1381,8 @@ roster_merge_result::report_duplicate_na
if (basic_io)
{
- put_resolution (st, left_side, conflict.left_resolution);
- put_resolution (st, right_side, conflict.right_resolution);
+ put_file_resolution (st, left_side, conflict.left_resolution);
+ put_file_resolution (st, right_side, conflict.right_resolution);
put_stanza(st, output);
}
}
@@ -1865,6 +1926,11 @@ read_dropped_modified_conflict(basic_io:
{
// no more data for left
}
+ else if (tmp == "orphaned file")
+ {
+ // no more data for left
+ conflict.orphaned = true;
+ }
else
{
// modified file
@@ -1880,6 +1946,11 @@ read_dropped_modified_conflict(basic_io:
{
// no more data for right
}
+ else if (tmp == "orphaned file")
+ {
+ // no more data for right
+ conflict.orphaned = true;
+ }
else
{
// modified file
@@ -1898,6 +1969,8 @@ read_dropped_modified_conflict(basic_io:
}
else if (pars.symp (syms::resolved_keep_left))
{
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
conflict.resolution.first = resolve_conflicts::keep;
pars.sym();
}
@@ -1907,7 +1980,24 @@ read_dropped_modified_conflict(basic_io:
pars.sym();
conflict.resolution.second = new_optimal_path(pars.token, false);
pars.str();
+
+ if (conflict.orphaned)
+ {
+ pars.esym (syms::resolved_rename_left);
+ conflict.resolution.first = resolve_conflicts::content_user_rename;
+ pars.str(tmp);
+ conflict.rename = new_optimal_path(tmp, false);
+ }
}
+ else if (pars.symp (syms::resolved_rename_left))
+ {
+ E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+
+ conflict.resolution.first = resolve_conflicts::rename;
+ pars.sym();
+ conflict.resolution.second = new_optimal_path(pars.token, false);
+ pars.str();
+ }
else
E(false, origin::user,
F(conflict_resolution_not_supported_msg) % pars.token % "dropped_modified");
@@ -1958,6 +2048,7 @@ validate_dropped_modified_conflicts(basi
F(conflicts_mismatch_msg));
merge_conflict.resolution = file_conflict.resolution;
+ merge_conflict.rename = file_conflict.rename;
if (pars.tok.in.lookahead != EOF)
pars.esym (syms::conflict);
@@ -2586,6 +2677,34 @@ roster_merge_result::resolve_orphaned_no
orphaned_node_conflicts.clear();
}
+static void
+resolve_dropped_modified_user(roster_t & roster,
+ node_id & nid,
+ file_id modified_fid,
+ dropped_modified_conflict const conflict,
+ content_merge_adaptor & adaptor,
+ temp_node_id_source & nis)
+{
+ // See comments in keep below on why we drop first
+ roster.drop_detached_node(nid);
+
+ file_data result_data;
+ data result_raw_data;
+ file_id result_fid;
+ read_data(*conflict.resolution.second, result_raw_data);
+
+ result_data = file_data(result_raw_data);
+ calculate_ident(result_data, result_fid);
+
+ nid = roster.create_file_node(result_fid, nis);
+
+ // User could specify no changes
+ if (result_fid != modified_fid)
+ {
+ adaptor.record_file(result_fid, result_data);
+ }
+}
+
void
roster_merge_result::resolve_dropped_modified_conflicts(lua_hooks & lua,
roster_t const & left_roster,
@@ -2632,33 +2751,32 @@ roster_merge_result::resolve_dropped_mod
P(F("replacing content of '%s' with '%s'") %
modified_name % conflict.resolution.second->as_external());
- {
- // See comments in keep below on why we drop first
- roster.drop_detached_node(nid);
+ resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
+ attach_node(lua, roster, nid, modified_name);
+ break;
- file_data result_data;
- data result_raw_data;
- file_id result_fid;
- read_data(*conflict.resolution.second, result_raw_data);
+ case resolve_conflicts::content_user_rename:
+ I(conflict.rename != 0);
+ P(F("replacing content of '%s' (renamed to '%s') with '%s'") %
+ modified_name % conflict.rename->as_external() % conflict.resolution.second->as_external());
- result_data = file_data(result_raw_data);
- calculate_ident(result_data, result_fid);
+ resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
+ attach_node(lua, roster, nid, file_path_internal (conflict.rename->as_internal()));
+ break;
- nid = roster.create_file_node(result_fid, nis);
+ case resolve_conflicts::drop:
+ P(F("dropping '%s'") % modified_name);
- // User could specify no changes
- if (result_fid != modified_fid)
- {
- adaptor.record_file(result_fid, result_data);
- }
- attach_node(lua, roster, nid, modified_name);
- }
+ roster.drop_detached_node(nid);
break;
- case resolve_conflicts::drop:
- P(F("dropping '%s'") % modified_name);
+ case resolve_conflicts::rename:
+ P(F("renaming '%s' to '%s'") % modified_name % conflict.resolution.second->as_external());
+ // See comment in keep below on why we drop first.
roster.drop_detached_node(nid);
+ nid = roster.create_file_node(modified_fid, nis);
+ attach_node (lua, roster, nid, file_path_internal (conflict.resolution.second->as_internal()));
break;
case resolve_conflicts::keep:
============================================================
--- src/merge_roster.cc 4db179b2bb8e140d9ff9bd49f09306c578348759
+++ src/merge_roster.cc d68470addacbe005680b1f66a69f8a9edd4e6ea4
@@ -42,6 +42,8 @@ image(resolve_conflicts::resolution_t re
return "keep";
case resolve_conflicts::rename:
return "rename";
+ case resolve_conflicts::content_user_rename:
+ return "content_user_rename";
}
I(false); // keep compiler happy
}
@@ -94,10 +96,12 @@ dump(dropped_modified_conflict const & c
ostringstream oss;
oss << "dropped_modified_conflict on node: " <<
conflict.left_nid == the_null_node ? conflict.right_nid : conflict.left_nid;
+ oss << " orphaned: " << conflict.orphaned;
if (conflict.resolution.first != resolve_conflicts::none)
{
oss << " resolution: " << image(conflict.resolution.first);
- oss << " name: " << conflict.resolution.second;
+ oss << " new_content_name: " << conflict.resolution.second;
+ oss << " rename: " << conflict.rename;
}
oss << "\n";
out = oss.str();
@@ -435,14 +439,33 @@ namespace
}
else
{
+ // We need this in two places
+ std::vector<dropped_modified_conflict>::iterator dropped_modified =
+ find(result.dropped_modified_conflicts.begin(),
+ result.dropped_modified_conflicts.end(),
+ nid);
+
// orphan:
if (!result.roster.has_node(parent))
{
- orphaned_node_conflict c;
- c.nid = nid;
- c.parent_name = make_pair(parent, name);
- result.orphaned_node_conflicts.push_back(c);
- return;
+ // If the orphaned node is due to the parent directory being
+ // dropped, and the orphaned node is modified, then it already
+ // has a dropped_modified conflict; add the orphaned information
+ // to that.
+
+ if (result.dropped_modified_conflicts.end() != dropped_modified)
+ {
+ dropped_modified->orphaned = true;
+ return;
+ }
+ else
+ {
+ orphaned_node_conflict c;
+ c.nid = nid;
+ c.parent_name = make_pair(parent, name);
+ result.orphaned_node_conflicts.push_back(c);
+ return;
+ }
}
dir_t p = downcast_to_dir_t(result.roster.get_node_for_update(parent));
@@ -490,10 +513,7 @@ namespace
return;
}
- if (result.dropped_modified_conflicts.end() !=
- find(result.dropped_modified_conflicts.begin(),
- result.dropped_modified_conflicts.end(),
- nid))
+ if (result.dropped_modified_conflicts.end() != dropped_modified)
{
// conflict already entered, just don't attach
return;
============================================================
--- src/merge_roster.hh 90740a700bceeecc6f662663246ddbe655f2edcb
+++ src/merge_roster.hh 4bd3be5251736b3b0987a2179c6defbcd7d0b188
@@ -29,7 +29,7 @@ namespace resolve_conflicts
namespace resolve_conflicts
{
- enum resolution_t {none, content_user, content_internal, drop, keep, rename};
+ enum resolution_t {none, content_user, content_internal, drop, keep, rename, content_user_rename};
typedef std::pair<resolve_conflicts::resolution_t, boost::shared_ptr<any_path> > file_resolution_t;
@@ -95,9 +95,19 @@ struct dropped_modified_conflict
struct dropped_modified_conflict
{
node_id left_nid, right_nid; // the dropped side is the null node, modified is valid.
+
+ bool orphaned; // if true, the dropped side is due to a dropped parent directory
+
resolve_conflicts::file_resolution_t resolution;
+ boost::shared_ptr<any_path> rename;
+ // if orphaned is true, the resolutions are 'drop' and 'user rename'; the
+ // latter requires two paths; content in resolution->second, filename in
+ // rename.
- dropped_modified_conflict(node_id left_nid, node_id right_nid) : left_nid(left_nid), right_nid(right_nid)
+ dropped_modified_conflict(node_id left_nid, node_id right_nid) :
+ left_nid(left_nid),
+ right_nid(right_nid),
+ orphaned(false)
{resolution.first = resolve_conflicts::none;}
bool operator==(node_id n) {return left_nid == n || right_nid == n;}
============================================================
--- test/func/(imp)_merge((patch_foo_a),_(delete_foo_))/__driver__.lua 7369a583460c9839c752d40173538c32ea635a0a
+++ /dev/null
@@ -1,24 +0,0 @@
-
-mtn_setup()
-
-mkdir("foo")
-addfile("foo/a", "blah blah")
-commit()
-base = base_revision()
-
-check(mtn("drop", "--bookkeep-only", "--recursive", "foo"), 0, false, false)
-commit()
-
-remove("foo")
-revert_to(base)
-
-writefile("foo/a", "some other stuff")
-commit()
-
-check(mtn("--branch=testbranch", "merge"), 0, false, false)
-
-check(mtn("checkout", "--revision", base, "test_dir"), 0, false, false)
-check(indir("test_dir", mtn("update", "--branch=testbranch")), 0, false, false)
-
-check(not exists("test_dir/foo/a"))
-check(not exists("test_dir/bar/a"))
============================================================
--- test/func/merge((drop_a),_(rename_a_b,_patch_b))/__driver__.lua 7c6a662fa620c7515804cb6e5e513549429015c5
+++ /dev/null
@@ -1,27 +0,0 @@
-
-mtn_setup()
-
-writefile("original", "some stuff here")
-
-check(mtn("add", "original"), 0, false, false)
-commit()
-base = base_revision()
-
--- drop it
-check(mtn("drop", "--bookkeep-only", "original"), 0, false, false)
-commit()
-
-revert_to(base)
-
--- patch and rename it
-rename("original", "different")
-check(mtn("rename", "--bookkeep-only", "original", "different"), 0, false, false)
-append("different", "more\n")
-commit()
-
-check(mtn("merge"), 0, false, false)
-check(mtn("checkout", "-b", "testbranch", "clean"), 0, false, false)
-
--- check that the file doesn't exist
-check(not exists("clean/original"))
-check(not exists("clean/different"))
============================================================
--- test/func/merge((patch_a),_(drop_a))/__driver__.lua 336ee81dc87b3f5843cfcbc94b0e2c899f965523
+++ /dev/null
@@ -1,27 +0,0 @@
-
-mtn_setup()
-
-writefile("base", "foo blah")
-writefile("left", "bar blah")
-
-copy("base", "testfile")
-check(mtn("add", "testfile"), 0, false, false)
-commit()
-base = base_revision()
-
-copy("left", "testfile")
-commit()
-left = base_revision()
-
-revert_to(base)
-
-check(mtn("drop", "testfile"), 0, false, false)
-commit()
-
-check(mtn("merge"), 0, false, true)
-
--- check that we're warned about the changes being dropped...
-
-check(qgrep("content changes to the file", "stderr"))
-check(qgrep(left, "stderr"))
-
============================================================
--- test/func/resolve_conflicts_dropped_modified/__driver__.lua 7f16460e30c39738b2cf25239f1b9522b6c87fa1
+++ test/func/resolve_conflicts_dropped_modified/__driver__.lua bcfc3ea32eb2bc76edc978567c24731402967120
@@ -8,6 +8,8 @@ mtn_setup()
-- Six conflicts to test the three possible resolutions, with drop on
-- both left and right. Number in file name is the node number (helps
-- in debugging; node 1 is the root directory).
+--
+-- The case of a modified file in a dropped directory is tested below.
addfile("file_2", "file_2 base") -- modify/rename left, drop right; drop
addfile("file_3", "file_3 base") -- drop left, modify/rename right; drop
@@ -166,12 +168,7 @@ check(not qgrep("warning", "stderr"))
check(qgrep("replacing content of 'file_7_renamed' with '_MTN/resolutions/file_7_resolved", "stderr"))
check(not qgrep("warning", "stderr"))
--- There is no such thing as a dropped/modified directory; if the
--- directory is empty, the only possible change is rename, which is
--- ignored. If the directory is not empty, that creates orphaned file
--- conflicts.
---
--- Similarly, if a file is renamed (without other change) and dropped,
+-- If a file is renamed (without other change) and dropped,
-- the change is ignored:
addfile("file_8", "file_8 base") -- rename left, drop right
@@ -191,4 +188,123 @@ check(qgrep("0 conflicts", "stderr"))
check(mtn("show_conflicts", left_2, right_2), 0, nil, true)
check(qgrep("0 conflicts", "stderr"))
+-- There is no such thing as a dropped/modified directory; if the
+-- directory is empty, the only possible change is rename, which is
+-- ignored.
+--
+-- If the directory is not empty, that creates a dropped/modified file
+-- conflict (not an orphaned file conflict, although that would also
+-- make sense). This used to be the test
+-- "(imp)_merge((patch_foo_a),_(delete_foo_))"
+--
+-- We create three potential conflicts; one ignored, three with different resolutions:
+
+adddir("dir1") -- empty, dropped and renamed (not a conflict; just dropped)
+mkdir("dir2") -- not empty, dropped, contents modified
+addfile("dir2/file_9", "file_9 base") -- resolved by rename
+addfile("dir2/file_10", "file_10 base") -- resolved by user_rename
+addfile("dir2/file_11", "file_11 base") -- resolved by drop
+commit("testbranch", "base 3")
+base_3 = base_revision()
+
+check(mtn("mv", "dir1", "dir3"), 0, false, false)
+
+writefile("dir2/file_9", "file_9 left")
+writefile("dir2/file_10", "file_10 left")
+writefile("dir2/file_11", "file_11 left")
+commit("testbranch", "left 3")
+left_3 = base_revision()
+
+revert_to(base_3)
+
+check(mtn("drop", "dir1", "--no-recursive"), 0, false, false)
+
+check(mtn("drop", "--recursive", "dir2"), 0, false, false)
+
+commit("testbranch", "right 3")
+right_3 = base_revision()
+
+check(mtn("show_conflicts", left_3, right_3), 0, nil, true)
+canonicalize("stderr")
+check(samefilestd("show_conflicts-orphaned", "stderr"))
+
+-- Show these conflicts can be resolved
+check(mtn("conflicts", "store", left_3, right_3), 0, nil, true)
+
+canonicalize("_MTN/conflicts")
+check(samefilestd("conflicts-orphaned", "_MTN/conflicts"))
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'dir2/file_10'",
+ "mtn: modified on the left",
+ "mtn: orphaned on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first drop",
+ "mtn: resolve_first rename",
+ "mtn: resolve_first user_rename \"new_content_name\" \"new_file_name\""}))
+
+mkdir("_MTN")
+mkdir("_MTN/resolutions")
+writefile("_MTN/resolutions/file_10", "file_10 user")
+check(mtn("conflicts", "resolve_first", "user_rename", "_MTN/resolutions/file_10", "file_10"), 0, nil, true)
+
+check(mtn("conflicts", "resolve_first", "drop"), 0, nil, nil)
+
+check(mtn("conflicts", "resolve_first", "rename", "file_9"), 0, nil, nil)
+
+check(samefilestd("conflicts-orphaned-resolved", "_MTN/conflicts"))
+
+check(mtn("explicit_merge", "--resolve-conflicts", left_3, right_3, "testbranch"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: [left] 5ac4e947066417642f5404b9a54d4d8487bda002",
+ "mtn: [right] d542a5d8e86dc29448a27449688d6f4fffcec72b",
+ "mtn: replacing content of 'dir2/file_10' (renamed to 'file_10') with '_MTN/resolutions/file_10'",
+ "mtn: dropping 'dir2/file_11'",
+ "mtn: renaming 'dir2/file_9' to 'file_9'",
+ "mtn: [merged] 202584446f5184430d1f8320eb702a5f81134505"}))
+
+
+-- A special case; drop then re-add vs modify. This used to be the test
+-- "merge((patch_a),_(drop_a,_add_a))"
+addfile("file_10", "file_10 base")
+commit("testbranch", "base 4")
+base_4 = base_revision()
+
+writefile("file_10", "file_10 left")
+commit("testbranch", "left 4")
+left_4 = base_revision()
+
+revert_to(base_4)
+
+check(mtn("drop", "file_10"), 0, false, false)
+commit("testbranch", "right 4a")
+
+addfile("file_10", "file_10 right re-add")
+commit("testbranch", "right 4b")
+right_4 = base_revision()
+
+check(mtn("show_conflicts", left_4, right_4), 0, nil, true)
+check(qgrep("mtn: conflict: file 'file_10'", "stderr"))
+check(qgrep("mtn: modified on the left", "stderr"))
+check(qgrep("mtn: dropped on the right", "stderr"))
+check(qgrep("mtn: 1 conflict with supported resolutions.", "stderr"))
+
+-- FIXME: Show this conflict can't be resolved by keep; two new nodes with same name
+check(mtn("conflicts", "store", left_4, right_4), 0, nil, true)
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_10'",
+ "mtn: modified on the left",
+ "mtn: dropped on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first drop",
+ "mtn: resolve_first keep",
+ "mtn: resolve_first user \"name\""}))
+
+check(mtn("conflicts", "resolve_first", "keep"), 0, nil, true)
+
+check(mtn("explicit_merge", "--resolve-conflicts", left_4, right_4, "testbranch"), 0, nil)
+
-- end of file
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified/conflicts-orphaned 1d2aa9cc3444a9002bca7ba6d74335e943fbed3c
@@ -0,0 +1,27 @@
+ left [5ac4e947066417642f5404b9a54d4d8487bda002]
+ right [d542a5d8e86dc29448a27449688d6f4fffcec72b]
+ancestor [70ef90574731a834d932669e77be7f89662e9097]
+
+ conflict dropped_modified
+ ancestor_name "dir2/file_10"
+ancestor_file_id [7368a4340573dca149c05db6f49638fafee766d0]
+ left_type "modified file"
+ left_name "dir2/file_10"
+ left_file_id [080c590e6e671b1b9ca0e752e1bc468c5167e2a9]
+ right_type "orphaned file"
+
+ conflict dropped_modified
+ ancestor_name "dir2/file_11"
+ancestor_file_id [498b49fddbd0418f62eb19d2096de816f3e34116]
+ left_type "modified file"
+ left_name "dir2/file_11"
+ left_file_id [ea74c930ce75ac43380f520f9cdd4e85f56ed049]
+ right_type "orphaned file"
+
+ conflict dropped_modified
+ ancestor_name "dir2/file_9"
+ancestor_file_id [6259d1132e063364597e6ee84a431b432f0e9cf9]
+ left_type "modified file"
+ left_name "dir2/file_9"
+ left_file_id [d1c21ac76fd433b5f1daead0438938b45f9e13a8]
+ right_type "orphaned file"
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified/conflicts-orphaned-resolved 203dc22e1122af927193f34e7186bb650b77302f
@@ -0,0 +1,31 @@
+ left [5ac4e947066417642f5404b9a54d4d8487bda002]
+ right [d542a5d8e86dc29448a27449688d6f4fffcec72b]
+ancestor [70ef90574731a834d932669e77be7f89662e9097]
+
+ conflict dropped_modified
+ ancestor_name "dir2/file_10"
+ ancestor_file_id [7368a4340573dca149c05db6f49638fafee766d0]
+ left_type "modified file"
+ left_name "dir2/file_10"
+ left_file_id [080c590e6e671b1b9ca0e752e1bc468c5167e2a9]
+ right_type "orphaned file"
+ resolved_user_left "_MTN/resolutions/file_10"
+resolved_rename_left "file_10"
+
+ conflict dropped_modified
+ ancestor_name "dir2/file_11"
+ ancestor_file_id [498b49fddbd0418f62eb19d2096de816f3e34116]
+ left_type "modified file"
+ left_name "dir2/file_11"
+ left_file_id [ea74c930ce75ac43380f520f9cdd4e85f56ed049]
+ right_type "orphaned file"
+resolved_drop_left
+
+ conflict dropped_modified
+ ancestor_name "dir2/file_9"
+ ancestor_file_id [6259d1132e063364597e6ee84a431b432f0e9cf9]
+ left_type "modified file"
+ left_name "dir2/file_9"
+ left_file_id [d1c21ac76fd433b5f1daead0438938b45f9e13a8]
+ right_type "orphaned file"
+resolved_rename_left "file_9"
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned 3fd23fd24470d5755be8e083666afadf9f9aad58
@@ -0,0 +1,13 @@
+mtn: [left] 5ac4e947066417642f5404b9a54d4d8487bda002
+mtn: [right] d542a5d8e86dc29448a27449688d6f4fffcec72b
+mtn: [ancestor] 70ef90574731a834d932669e77be7f89662e9097
+mtn: conflict: file 'dir2/file_10' from revision 70ef90574731a834d932669e77be7f89662e9097
+mtn: modified on the left, named dir2/file_10
+mtn: orphaned on the right
+mtn: conflict: file 'dir2/file_11' from revision 70ef90574731a834d932669e77be7f89662e9097
+mtn: modified on the left, named dir2/file_11
+mtn: orphaned on the right
+mtn: conflict: file 'dir2/file_9' from revision 70ef90574731a834d932669e77be7f89662e9097
+mtn: modified on the left, named dir2/file_9
+mtn: orphaned on the right
+mtn: 3 conflicts with supported resolutions.
============================================================
--- test/func/update_with_pending_modification/__driver__.lua 03be28a852978808341205ba2e2f713ce8dcaf35
+++ test/func/update_with_pending_modification/__driver__.lua ac866e80c2aebb3803c42ad8ca275316050b9675
@@ -1,3 +1,4 @@
+-- Test the case of update where there is a dropped/modified conflict
mtn_setup()
@@ -5,28 +6,25 @@ commit()
addfile("file1", "contents of file1")
commit()
--- store the newly created revision id
REV1=base_revision()
--- check(mtn("--branch", "testbranch", "co", "codir"), 0, false, false)
--- writefile("codir/file2", "contents of file2")
-
--- add another file and commit
+-- add another file, then change it
addfile("file2", "contents of file2")
commit()
--- change that new file
writefile("file2", "new contents of file2")
--- .. and upadte to the previous revision, which didn't have file2.
--- At the moment, this simply drops file2 and all changes to it.
---
--- See bug #15058
+-- update to the previous revision, which didn't have file2. This
+-- looks like file2 is dropped on one side (in rev 1), and modified on
+-- the other (the workspace), so we get a dropped/modified conflict.
-xfail(mtn("update", "-r", REV1), 1, true, true)
+check(mtn("update", "-r", REV1), 1, true, true)
+check(qgrep("mtn: conflict: file 'file2'"), "stderr")
+check(qgrep("mtn: modified on the left, named file2"), "stderr")
+check(qgrep("mtn: dropped on the right"), "stderr")
+check(qgrep("mtn: misuse: merge failed due to unresolved conflicts"), "stderr")
--- IMO, the correct curse of action should be to fail updating due to
--- a conflict.
-check(exists("file2"))
-check(samelines("file2", {"new contents of file2"}))
+-- Since this is a workspace merge, we can't resolve the conflict; the
+-- modified file must be committed first.
+-- end of file
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Monotone-commits-diffs] net.venge.monotone.issue-209: f33065689b915304ecbc095df537751e12ebd3dd,
code <=