[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[Monotone-commits-diffs] net.venge.monotone: 806715c5ce888b7dbbce7752a7f
From: |
code |
Subject: |
[Monotone-commits-diffs] net.venge.monotone: 806715c5ce888b7dbbce7752a7ff35868ee3bcfa |
Date: |
Sat, 4 Aug 2012 14:26:32 +0200 (CEST) |
revision: 806715c5ce888b7dbbce7752a7ff35868ee3bcfa
date: 2012-07-23T09:14:16
author: address@hidden
branch: net.venge.monotone
changelog:
propagate from branch 'net.venge.monotone.issue-209' (head
215eae872b62927248079d06e3dc23e2c2d31787)
to branch 'net.venge.monotone' (head
1f323fadb24c032518db433178c7cc757914a564)
manifest:
format_version "1"
new_manifest [b18e7ae7b45c52907489c015eef6fccf53eb7663]
old_revision [1f323fadb24c032518db433178c7cc757914a564]
rename "test/func/resolve_conflicts_dropped_modified"
to "test/func/resolve_conflicts_dropped_modified_1"
rename "test/func/resolve_conflicts_dropped_modified_upstream_vs_local"
to "test/func/resolve_conflicts_dropped_modified_upstream_vs_local_attr"
add_dir "test/func/resolve_conflicts_dropped_modified_3"
add_dir "test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2"
add_file "test/func/resolve_conflicts_dropped_modified_3/__driver__.lua"
content [fd2a4dd0c38dff10bd3ff2f20e983f3f548b3d18]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/__driver__.lua"
content [80f056dd3773dab5d5019d78cbb0f7393d66bde3]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_2_3"
content [1f257fa6e99abf93229af189109b9efe3cfae88f]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_2_3_resolved"
content [d8b9a96fdaf210a4d1bc495c62c3dcf40114d39e]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2"
content [bb23f1fbf87e4f1dcb8aa7c4c3fcb90e1fc84fed]
add_file
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2_resolved"
content [4482ad2e755308ce8a546191348cc648ad13d782]
patch "doc/monotone.texi"
from [d1225486c4df3ec2023d0e303aac65b8ff10a54e]
to [0f1e2230272b68614efad33648dbf436e0d6f729]
patch "src/cmd_conflicts.cc"
from [e1b7feca5acd314d85498cabedf888f5293bf30e]
to [28995825acadb97eaa4b5cda378c66e548e9ad16]
patch "src/merge_conflict.cc"
from [34fbc891bc8455202d9c0d0a495beb690fd8a5a0]
to [b47a70720f836809f06347360ee91ddf587b5721]
patch "src/merge_content.cc"
from [662433acaf08fc1f3f3417389a9bc3b3d2bd9bf1]
to [095c2d20ac8d8d495806f6463c311d253cb6a686]
patch "src/merge_roster.cc"
from [5fbc50c114df22f4753f444aa137c06ea0f06195]
to [c3eb70578a3b8b88c4d1b7af43b7685d6f636c23]
patch "src/merge_roster.hh"
from [34d382b0ad333fa0f052e8640a88c1ece03caaa9]
to [c782f7684e380f4583ed7ea88b0b2967f89d1d23]
patch "src/roster.cc"
from [3f81121ce80b42565e6e5e4bbe3e6186b85e9b10]
to [b0608d6ec3e3f2d23a5c97bb64c4354eeb01773a]
patch "test/func/resolve_conflicts_dropped_modified_1/__driver__.lua"
from [e4f973e6cb8e3494c4b498f68f7cd4b2a6d20fa6]
to [2c87a2a5810a34019c4ca4148eb2b9bede764267]
patch "test/func/resolve_conflicts_dropped_modified_1/conflicts-recreated"
from [26f633aeeee82440eea41f8e1747f2c4262ce9bb]
to [3f43d9d13d0149e3be0fa3a7a8695182dbc871ea]
patch
"test/func/resolve_conflicts_dropped_modified_1/conflicts-recreated-resolved"
from [5082532e55e68bc93610d1e8936fe790bb048d3d]
to [7937832db9408aeadbbeed472d86f29ef3394a06]
patch "test/func/resolve_conflicts_dropped_modified_1/conflicts-resolved"
from [dd892da237ef4f3a0ee30fa3989374a65d092d68]
to [b2fe24f2d19a8d539c0c89c305a7b58a36ead63e]
patch "test/func/resolve_conflicts_dropped_modified_1/show_conflicts"
from [74f0f311dee5ce970396bed354b6ab0fd97077f0]
to [cce385ec522c8e4885cac7d3375896aaa507f0e0]
patch "test/func/resolve_conflicts_dropped_modified_1/show_conflicts-orphaned"
from [fbe2c5cc2c59c6fec1121e3be9469d370b9ed5cb]
to [e343653ac3989164acb2dbb54f3f97b035d28de6]
patch "test/func/resolve_conflicts_dropped_modified_2/__driver__.lua"
from [e1bd2fed5032ea4cb911ffc1289b1830e2195e1c]
to [81b11d9ab24ad470156b95e8be8efd9dc1645156]
patch
"test/func/resolve_conflicts_dropped_modified_upstream_vs_local_attr/__driver__.lua"
from [e7f37ed8b1a65325390ad4f1ade33904e7535381]
to [abe2836cc2dfbae368820e3b5515ad587911c71b]
patch "test/func/resolve_conflicts_errors/__driver__.lua"
from [9a130c83d4a7e3545f18d089542603c8d0bb72fa]
to [0819ba223855d9814a7420c7412166b1109ed20f]
patch "test/func/resolve_conflicts_orphaned_file/__driver__.lua"
from [fe6a4618be2793d18ee2f97adf94cd564763164f]
to [beb41b901c1e08bbef25e87fe0b2ef36e74a2a8b]
old_revision [215eae872b62927248079d06e3dc23e2c2d31787]
patch "innosetup/README.txt"
from [6f92ce9f01c75b83994b690bb8b00c549c368965]
to [d306d15f4bba8011dd1fa01dd9522b93c8ce8920]
patch "src/automate.cc"
from [919e3df52514d0877aeafc67791aae6a3faa33b4]
to [30e9bb3567e320f83ce5c1b4817dc9ad90fe8423]
============================================================
--- doc/monotone.texi d1225486c4df3ec2023d0e303aac65b8ff10a54e
+++ doc/monotone.texi 0f1e2230272b68614efad33648dbf436e0d6f729
@@ -1,4 +1,4 @@
-0\input texinfo @c -*-texinfo-*-
+\input texinfo @c -*-texinfo-*-
@c %**start of header
@setfilename monotone.info
@settitle monotone documentation
@@ -5232,6 +5232,16 @@ @subheading Conflict resolutions
@command{resolved_rename_right @var{filename}} conflict resolution in
the conflicts file.
address@hidden user_rename @var{contents_file} @var{rename_file}
+The file contents are replaced by the contents of the specified file,
+and renamed.
+
+This inserts a @command{resolved_user_left @var{contents_file}} or
address@hidden @var{contents_file}} conflict resolution
+in the conflicts file, and a @command{resolved_rename_left
address@hidden or @command{resolved_rename_right
address@hidden conflict resolution.
+
@item keep
The file is kept in the merge.
============================================================
--- src/cmd_conflicts.cc e1b7feca5acd314d85498cabedf888f5293bf30e
+++ src/cmd_conflicts.cc 28995825acadb97eaa4b5cda378c66e548e9ad16
@@ -50,6 +50,16 @@ static void
typedef enum {first, remaining} show_conflicts_case_t;
static void
+show_resolution(resolve_conflicts::file_resolution_t resolution, char const * const prefix)
+{
+
+ if (resolution.resolution != resolve_conflicts::none)
+ {
+ P(F(string(prefix).append(image(resolution)).c_str()));
+ }
+}
+
+static void
show_conflicts(database & db, conflicts_t conflicts, show_conflicts_case_t show_case)
{
// Go thru the conflicts we know how to resolve in the same order
@@ -60,7 +70,7 @@ show_conflicts(database & db, conflicts_
{
orphaned_node_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
file_path name;
if (conflicts.left_roster->has_node(conflict.nid))
@@ -90,83 +100,124 @@ show_conflicts(database & db, conflicts_
{
dropped_modified_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if ((conflict.left_nid != the_null_node &&
+ conflict.left_resolution.resolution == resolve_conflicts::none) ||
+ (conflict.right_nid != the_null_node &&
+ conflict.right_resolution.resolution == resolve_conflicts::none))
{
- node_id nid;
file_path modified_name;
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
- // left side dropped, right side modified
- nid = conflict.right_nid;
+ case resolve_conflicts::left_side:
conflicts.right_roster->get_name(conflict.right_nid, modified_name);
- }
- else
- {
- // left side modified, right side dropped
- nid = conflict.left_nid;
+ break;
+
+ case resolve_conflicts::right_side:
conflicts.left_roster->get_name(conflict.left_nid, modified_name);
+ break;
}
P(F("conflict: file '%s'") % modified_name);
if (conflict.orphaned)
{
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
P(F("orphaned on the left"));
P(F("modified on the right"));
- }
- else
- {
+ break;
+
+ case resolve_conflicts::right_side:
P(F("modified on the left"));
P(F("orphaned on the right"));
}
}
else
{
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
- if (conflict.recreated == the_null_node)
+ case resolve_conflicts::left_side:
+ if (conflict.left_nid == the_null_node)
P(F("dropped on the left"));
else
- P(F("dropped and recreated on the left"));
+ {
+ // we can't distinguish duplicate name from recreated
+ P(F("dropped and recreated on the left"));
+ }
P(F("modified on the right"));
- }
- else
- {
+ break;
+
+ case resolve_conflicts::right_side:
P(F("modified on the left"));
- if (conflict.recreated == the_null_node)
+ if (conflict.right_nid == the_null_node)
P(F("dropped on the right"));
else
- P(F("dropped and recreated on the right"));
+ {
+ P(F("dropped and recreated on the right"));
+ }
}
}
- switch (show_case)
+ show_resolution(conflict.left_resolution, "left_");
+ show_resolution(conflict.right_resolution, "right_");
+
+ if (show_case == remaining) return;
+
+ if (conflict.left_nid == the_null_node || conflict.right_nid == the_null_node)
{
- case first:
+ // only one file involved; only need one resolution
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\""));
- if (conflict.recreated == the_null_node)
- P(F("resolve_first drop"));
+ if (!conflict.orphaned)
+ {
+ P(F("resolve_first keep"));
+ P(F("resolve_first user \"name\""));
+ }
+ return;
+ }
+ else
+ {
+ // recreated or repeated duplicate name; need two resolutions
- if (conflict.orphaned)
+ P(F("possible resolutions:"));
+
+ if (conflict.left_nid != the_null_node &&
+ conflict.left_resolution.resolution == resolve_conflicts::none)
{
- P(F("resolve_first rename"));
- P(F("resolve_first user_rename \"new_content_name\" \"new_file_name\""));
- return;
+ P(F("resolve_first_left drop"));
+ P(F("resolve_first_left rename"));
+ P(F("resolve_first_left user_rename \"new_content_name\" \"new_file_name\""));
+
+ if (!conflict.orphaned &&
+ conflict.right_resolution.resolution != resolve_conflicts::keep &&
+ conflict.right_resolution.resolution != resolve_conflicts::content_user)
+ {
+ P(F("resolve_first_left keep"));
+ P(F("resolve_first_left user \"name\""));
+ }
}
- else
+
+ if (conflict.right_nid != the_null_node &&
+ conflict.right_resolution.resolution == resolve_conflicts::none)
{
- P(F("resolve_first keep"));
- P(F("resolve_first user \"name\""));
- return;
+ P(F("resolve_first_right drop"));
+ P(F("resolve_first_right rename"));
+ P(F("resolve_first_right user_rename \"new_content_name\" \"new_file_name\""));
+ if (!conflict.orphaned &&
+ conflict.left_resolution.resolution != resolve_conflicts::keep &&
+ conflict.left_resolution.resolution != resolve_conflicts::content_user)
+ {
+ P(F("resolve_first_right keep"));
+ P(F("resolve_first_right user \"name\""));
+ }
}
-
- case remaining:
- break;
+ return;
}
}
}
@@ -177,8 +228,8 @@ show_conflicts(database & db, conflicts_
{
duplicate_name_conflict & conflict = *i;
- if (conflict.left_resolution.first == resolve_conflicts::none ||
- conflict.right_resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none ||
+ conflict.right_resolution.resolution == resolve_conflicts::none)
{
file_path left_name;
conflicts.left_roster->get_name(conflict.left_nid, left_name);
@@ -189,7 +240,7 @@ show_conflicts(database & db, conflicts_
case first:
P(F("possible resolutions:"));
- if (conflict.left_resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
{
P(F("resolve_first_left drop"));
P(F("resolve_first_left keep"));
@@ -197,7 +248,7 @@ show_conflicts(database & db, conflicts_
P(F("resolve_first_left user \"name\""));
}
- if (conflict.right_resolution.first == resolve_conflicts::none)
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
{
P(F("resolve_first_right drop"));
P(F("resolve_first_right keep"));
@@ -218,7 +269,7 @@ show_conflicts(database & db, conflicts_
{
file_content_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
file_path name;
conflicts.left_roster->get_name(conflict.nid, name);
@@ -330,48 +381,60 @@ static void
} // do_interactive_merge
static void
-set_duplicate_name_conflict(resolve_conflicts::file_resolution_t & resolution,
- resolve_conflicts::file_resolution_t const & other_resolution,
- args_vector const & args)
+set_resolution(resolve_conflicts::file_resolution_t & resolution,
+ resolve_conflicts::file_resolution_t const & other_resolution,
+ args_vector const & args)
{
if ("drop" == idx(args, 0)())
{
E(args.size() == 1, origin::user, F("too many arguments"));
- resolution.first = resolve_conflicts::drop;
+ resolution.resolution = resolve_conflicts::drop;
}
else if ("keep" == idx(args, 0)())
{
E(args.size() == 1, origin::user, F("too many arguments"));
- E(other_resolution.first == resolve_conflicts::none ||
- other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::none ||
+ other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename ||
+ other_resolution.resolution == resolve_conflicts::content_user_rename,
origin::user,
- F("other resolution must be 'drop' or 'rename'"));
- resolution.first = resolve_conflicts::keep;
+ F("other resolution is %s; specify 'drop', 'rename', or 'user_rename'") %
+ image(other_resolution.resolution));
+ resolution.resolution = resolve_conflicts::keep;
}
else if ("rename" == idx(args, 0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- resolution.first = resolve_conflicts::rename;
- resolution.second = resolve_conflicts::new_file_path(idx(args,1)());
+ resolution.resolution = resolve_conflicts::rename;
+ resolution.rename = file_path_external(idx(args,1));
}
else if ("user" == idx(args, 0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- E(other_resolution.first == resolve_conflicts::none ||
- other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::none ||
+ other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename ||
+ other_resolution.resolution == resolve_conflicts::content_user_rename,
origin::user,
- F("other resolution must be 'drop' or 'rename'"));
+ F("other resolution is %s; specify 'drop', 'rename', or 'user_rename'") %
+ image(other_resolution.resolution));
- resolution.first = resolve_conflicts::content_user;
- resolution.second = new_optimal_path(idx(args,1)(), false);
+ resolution.resolution = resolve_conflicts::content_user;
+ resolution.content = 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"));
+
+ resolution.resolution = resolve_conflicts::content_user_rename;
+ resolution.content = new_optimal_path(idx(args,1)(), false);
+ resolution.rename = file_path_external(idx(args,2));
+ }
else
E(false, origin::user,
F(conflict_resolution_not_supported_msg) % idx(args,0) % "duplicate_name");
-} //set_duplicate_name_conflict
+} // set_resolution
static void
set_first_conflict(database & db,
@@ -384,6 +447,48 @@ set_first_conflict(database & db,
if (side != neither)
{
+ 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;
+
+ // here we only allow two resolutions; single resolutions are handled below
+
+ switch (side)
+ {
+ case left:
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
+ {
+ E(conflict.left_nid != the_null_node, origin::user,
+ F("must specify resolve_first (not _left or _right)"));
+
+ if ("keep" == idx(args,0)())
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ set_resolution(conflict.left_resolution, conflict.right_resolution, args);
+ return;
+ }
+ break;
+ case right:
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
+ {
+ E(conflict.right_nid != the_null_node, origin::user,
+ F("must specify resolve_first (not _left or _right)"));
+
+ if ("keep" == idx(args,0)())
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ set_resolution(conflict.right_resolution, conflict.left_resolution, args);
+ return;
+ }
+ break;
+ case neither:
+ // can't get here
+ break;
+ }
+ }
+
for (std::vector<duplicate_name_conflict>::iterator i = conflicts.result.duplicate_name_conflicts.begin();
i != conflicts.result.duplicate_name_conflicts.end();
++i)
@@ -393,17 +498,17 @@ set_first_conflict(database & db,
switch (side)
{
case left:
- if (conflict.left_resolution.first == resolve_conflicts::none)
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
{
- set_duplicate_name_conflict(conflict.left_resolution, conflict.right_resolution, args);
+ set_resolution(conflict.left_resolution, conflict.right_resolution, args);
return;
}
break;
case right:
- if (conflict.right_resolution.first == resolve_conflicts::none)
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
{
- set_duplicate_name_conflict(conflict.right_resolution, conflict.left_resolution, args);
+ set_resolution(conflict.right_resolution, conflict.left_resolution, args);
return;
}
break;
@@ -422,20 +527,20 @@ set_first_conflict(database & db,
{
orphaned_node_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == 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;
+ conflict.resolution.resolution = resolve_conflicts::drop;
}
else if ("rename" == idx(args,0)())
{
E(args.size() == 2, origin::user, F("wrong number of arguments"));
- conflict.resolution.first = resolve_conflicts::rename;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
+ conflict.resolution.resolution = resolve_conflicts::rename;
+ conflict.resolution.rename = file_path_external(idx(args,1));
}
else
{
@@ -452,53 +557,113 @@ set_first_conflict(database & db,
{
dropped_modified_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ // Here we only allow single resolutions; two resolutions are handled above
+
+ switch (conflict.dropped_side)
{
- if ("drop" == idx(args,0)())
+ case resolve_conflicts::left_side:
+ E(conflict.left_nid == the_null_node, origin::user,
+ F("must specify 'resolve_first_left' or 'resolve_first_right' (not just 'resolve_first')"));
+
+ // the left side stays dropped; we either drop, keep or replace the right side
+ if (conflict.right_resolution.resolution == resolve_conflicts::none)
{
- E(args.size() == 1, origin::user, F("wrong number of arguments"));
- E(conflict.recreated == the_null_node, origin::user, F("recreated files may not be dropped"));
+ 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"));
- E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
+ }
+ 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.right_resolution.resolution = 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);
+ conflict.right_resolution.resolution = resolve_conflicts::content_user;
+ conflict.right_resolution.content = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("rename" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+
+ conflict.right_resolution.resolution = resolve_conflicts::rename;
+ conflict.right_resolution.rename = file_path_external(idx(args,1));
+ }
+ else if ("user_rename" == idx(args,0)())
+ {
+ E(args.size() == 3, origin::user, F("wrong number of arguments"));
+
+ conflict.right_resolution.resolution = resolve_conflicts::content_user_rename;
+ conflict.right_resolution.content = new_optimal_path(idx(args,1)(), false);
+ conflict.right_resolution.rename = file_path_external(idx(args,2));
+ }
+ else
+ {
+ E(false, origin::user,
+ F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
+ }
+ return;
}
- else if ("rename" == idx(args,0)())
+ break;
+
+ case resolve_conflicts::right_side:
+ E(conflict.right_nid == the_null_node, origin::user,
+ F("must specify 'resolve_first_left' or 'resolve_first_right' (not just 'resolve_first')"));
+
+ // the right side stays dropped; we either drop, keep or replace the left side
+ if (conflict.left_resolution.resolution == resolve_conflicts::none)
{
- E(args.size() == 2, origin::user, F("wrong number of arguments"));
- E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
+ if ("drop" == idx(args,0)())
+ {
+ E(args.size() == 1, origin::user, F("wrong number of arguments"));
- 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.left_resolution.resolution = resolve_conflicts::drop;
+ }
+ 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::content_user_rename;
- conflict.resolution.second = new_optimal_path(idx(args,1)(), false);
- conflict.rename = file_path_external(utf8(idx(args,2)(), origin::user));
+ conflict.left_resolution.resolution = 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.left_resolution.resolution = resolve_conflicts::content_user;
+ conflict.left_resolution.content = new_optimal_path(idx(args,1)(), false);
+ }
+ else if ("rename" == idx(args,0)())
+ {
+ E(args.size() == 2, origin::user, F("wrong number of arguments"));
+
+ conflict.left_resolution.resolution = resolve_conflicts::rename;
+ conflict.left_resolution.rename = file_path_external(idx(args,1));
+ }
+ else if ("user_rename" == idx(args,0)())
+ {
+ E(args.size() == 3, origin::user, F("wrong number of arguments"));
+
+ conflict.left_resolution.resolution = resolve_conflicts::content_user_rename;
+ conflict.left_resolution.content = new_optimal_path(idx(args,1)(), false);
+ conflict.left_resolution.rename = file_path_external(idx(args,2));
+ }
+ else
+ {
+ E(false, origin::user,
+ F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
+ }
+ return;
}
- else
- {
- E(false, origin::user,
- F(conflict_resolution_not_supported_msg) % idx(args,0) % "dropped_modified");
- }
- return;
+ break;
}
}
@@ -508,7 +673,7 @@ set_first_conflict(database & db,
{
file_content_conflict & conflict = *i;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
{
if ("interactive" == idx(args,0)())
{
@@ -543,8 +708,8 @@ set_first_conflict(database & db,
if (do_interactive_merge(db, lua, conflicts, conflict.nid,
conflict.ancestor, conflict.left, conflict.right, result_path))
{
- conflict.resolution.first = resolve_conflicts::content_user;
- conflict.resolution.second = boost::shared_ptr<any_path>(new bookkeeping_path(result_path));
+ conflict.resolution.resolution = resolve_conflicts::content_user;
+ conflict.resolution.content = boost::shared_ptr<any_path>(new bookkeeping_path(result_path));
P(F("interactive merge result saved in '%s'") % result_path.as_internal());
}
else
@@ -554,8 +719,8 @@ set_first_conflict(database & db,
{
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);
+ conflict.resolution.resolution = resolve_conflicts::content_user;
+ conflict.resolution.content = new_optimal_path(idx(args,1)(), false);
}
else
{
============================================================
--- src/merge_conflict.cc 34fbc891bc8455202d9c0d0a495beb690fd8a5a0
+++ src/merge_conflict.cc b47a70720f836809f06347360ee91ddf587b5721
@@ -1,4 +1,4 @@
-// Copyright (C) 2005 Nathaniel Smith <address@hidden>
+// Copyright (C) 2005, 2012 Nathaniel Smith <address@hidden>
// 2008, 2009, 2012 Stephen Leake <address@hidden>
//
// This program is made available under the GNU GPL version 2.0 or
@@ -86,11 +86,9 @@ namespace resolve_conflicts
namespace resolve_conflicts
{
- shared_ptr<any_path>
- new_file_path(string path)
+ file_path file_path_external(string path)
{
- return shared_ptr<any_path>
- (new file_path(file_path_external(utf8(path, origin::user))));
+ return file_path_external(utf8(path, origin::user));
};
}
@@ -396,11 +394,9 @@ put_attr_conflict (basic_io::stanza & st
}
}
-enum side_t {left_side, right_side};
-
static void
-put_file_resolution(basic_io::stanza & st,
- side_t side,
+put_file_resolution(basic_io::stanza & st,
+ resolve_conflicts::side_t side,
resolve_conflicts::file_resolution_t const & resolution)
{
// We output any resolution for any conflict; only valid resolutions
@@ -408,7 +404,7 @@ put_file_resolution(basic_io::stanza & s
// resolutions from files we check that the resolution is valid for the
// conflict. Hence there is no read_resolution.
- switch (resolution.first)
+ switch (resolution.resolution)
{
case resolve_conflicts::none:
break;
@@ -416,12 +412,12 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::content_user:
switch (side)
{
- case left_side:
- st.push_str_pair(syms::resolved_user_left, resolution.second->as_external());
+ case resolve_conflicts::left_side:
+ st.push_str_pair(syms::resolved_user_left, resolution.content->as_external());
break;
- case right_side:
- st.push_str_pair(syms::resolved_user_right, resolution.second->as_external());
+ case resolve_conflicts::right_side:
+ st.push_str_pair(syms::resolved_user_right, resolution.content->as_external());
break;
}
break;
@@ -429,15 +425,16 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::content_user_rename:
switch (side)
{
- case left_side:
- st.push_str_pair(syms::resolved_user_left, resolution.second->as_external());
+ case resolve_conflicts::left_side:
+ st.push_str_pair(syms::resolved_user_left, resolution.content->as_external());
+ st.push_str_pair(syms::resolved_rename_left, resolution.rename.as_external());
break;
- case right_side:
- st.push_str_pair(syms::resolved_user_right, resolution.second->as_external());
+ case resolve_conflicts::right_side:
+ st.push_str_pair(syms::resolved_user_right, resolution.content->as_external());
+ st.push_str_pair(syms::resolved_rename_right, resolution.rename.as_external());
break;
}
- // value for rename is put by caller
break;
case resolve_conflicts::content_internal:
@@ -447,12 +444,12 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::rename:
switch (side)
{
- case left_side:
- st.push_str_pair(syms::resolved_rename_left, resolution.second->as_external());
+ case resolve_conflicts::left_side:
+ st.push_str_pair(syms::resolved_rename_left, resolution.rename.as_external());
break;
- case right_side:
- st.push_str_pair(syms::resolved_rename_right, resolution.second->as_external());
+ case resolve_conflicts::right_side:
+ st.push_str_pair(syms::resolved_rename_right, resolution.rename.as_external());
break;
}
break;
@@ -460,11 +457,11 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::drop:
switch (side)
{
- case left_side:
+ case resolve_conflicts::left_side:
st.push_symbol(syms::resolved_drop_left);
break;
- case right_side:
+ case resolve_conflicts::right_side:
st.push_symbol(syms::resolved_drop_right);
break;
}
@@ -473,11 +470,11 @@ put_file_resolution(basic_io::stanza & s
case resolve_conflicts::keep:
switch (side)
{
- case left_side:
+ case resolve_conflicts::left_side:
st.push_symbol(syms::resolved_keep_left);
break;
- case right_side:
+ case resolve_conflicts::right_side:
st.push_symbol(syms::resolved_keep_right);
break;
}
@@ -535,7 +532,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_file_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.resolution);
}
static void
@@ -1001,7 +998,7 @@ roster_merge_result::report_orphaned_nod
if (basic_io)
{
- put_file_resolution (st, left_side, conflict.resolution);
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.resolution);
put_stanza (st, output);
}
}
@@ -1101,21 +1098,21 @@ roster_merge_result::report_dropped_modi
node_id nid;
file_path modified_name;
- if (conflict.left_nid == the_null_node)
+ switch (conflict.dropped_side)
{
- // left side dropped, right side modified
+ case resolve_conflicts::left_side:
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
+ break;
+
+ case resolve_conflicts::right_side:
I(!roster.is_attached(conflict.left_nid));
nid = conflict.left_nid;
left_roster.get_name(conflict.left_nid, modified_name);
+ break;
}
shared_ptr<roster_t const> lca_roster;
@@ -1137,8 +1134,9 @@ roster_merge_result::report_dropped_modi
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)
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
if (conflict.orphaned)
{
st.push_str_pair(syms::left_type, "orphaned file");
@@ -1147,7 +1145,7 @@ roster_merge_result::report_dropped_modi
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.left_nid == the_null_node)
{
st.push_str_pair(syms::left_type, "dropped file");
push_dropped_details(db_adaptor, syms::left_rev, syms::left_name, syms::left_file_id,
@@ -1157,21 +1155,23 @@ roster_merge_result::report_dropped_modi
{
st.push_str_pair(syms::left_type, "recreated file");
st.push_str_pair(syms::left_name, modified_name.as_external());
- db_adaptor.db.get_file_content (db_adaptor.left_rid, conflict.recreated, fid);
+ db_adaptor.db.get_file_content (db_adaptor.left_rid, conflict.left_nid, fid);
st.push_binary_pair(syms::left_file_id, fid.inner());
}
}
- }
- 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());
+ break;
+
+ case resolve_conflicts::right_side:
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)
- {
if (conflict.orphaned)
{
st.push_str_pair(syms::right_type, "orphaned file");
@@ -1180,7 +1180,7 @@ roster_merge_result::report_dropped_modi
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.right_nid == the_null_node)
{
st.push_str_pair(syms::right_type, "dropped file");
push_dropped_details(db_adaptor, syms::right_rev, syms::right_name, syms::right_file_id,
@@ -1190,59 +1190,39 @@ roster_merge_result::report_dropped_modi
{
st.push_str_pair(syms::right_type, "recreated file");
st.push_str_pair(syms::right_name, modified_name.as_external());
- db_adaptor.db.get_file_content (db_adaptor.right_rid, conflict.recreated, fid);
+ db_adaptor.db.get_file_content (db_adaptor.right_rid, conflict.right_nid, fid);
st.push_binary_pair(syms::right_file_id, fid.inner());
}
}
+ break;
}
- 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_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;
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.left_resolution);
+ put_file_resolution (st, resolve_conflicts::right_side, conflict.right_resolution);
- case resolve_conflicts::content_user_rename:
- st.push_str_pair(syms::resolved_rename_left, conflict.rename.as_external());
- break;
-
- default:
- I(false);
- }
- }
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("conflict: file '%s'") % ancestor_name);
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
if (conflict.orphaned)
{
P(F("orphaned on the left"));
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.left_nid == the_null_node)
P(F("dropped on the left"));
else
P(F("dropped and recreated on the left"));
}
P(F("modified on the right, named %s") % modified_name);
- }
- else
- {
+ break;
+
+ case resolve_conflicts::right_side:
P(F("modified on the left, named %s") % modified_name);
if (conflict.orphaned)
{
@@ -1250,43 +1230,49 @@ roster_merge_result::report_dropped_modi
}
else
{
- if (conflict.recreated == the_null_node)
+ if (conflict.right_nid == the_null_node)
P(F("dropped on the right"));
else
P(F("dropped and recreated on the right"));
}
+ break;
}
- // We can have a resolution from a mtn:resolve_conflict attribute.
- switch (conflict.resolution.first)
+ // We can have a resolution from a mtn:resolve_conflict attribute
+ // (so far, that only supports drop).
+ switch (conflict.left_resolution.resolution)
{
case resolve_conflicts::none:
break;
case resolve_conflicts::content_user:
- P(F("resolution: user file '%s'") % conflict.resolution.second->as_external());
- break;
-
case resolve_conflicts::content_user_rename:
- P(F("resolution: user '%s' rename '%s'") %
- conflict.resolution.second->as_external() %
- conflict.rename.as_external());
- break;
-
case resolve_conflicts::rename:
- P(F("resolution: rename '%s'") % conflict.resolution.second->as_external());
+ case resolve_conflicts::keep:
+ case resolve_conflicts::content_internal:
+ I(false);
break;
case resolve_conflicts::drop:
- P(F("resolution: drop"));
+ P(F("left_resolution: drop"));
break;
+ }
+ switch (conflict.right_resolution.resolution)
+ {
+ case resolve_conflicts::none:
+ break;
+ case resolve_conflicts::content_user:
+ case resolve_conflicts::content_user_rename:
+ case resolve_conflicts::rename:
case resolve_conflicts::keep:
- P(F("resolution: keep"));
+ case resolve_conflicts::content_internal:
+ I(false);
break;
- default:
- I(false);
+ case resolve_conflicts::drop:
+ P(F("right_resolution: drop"));
+ break;
}
}
}
@@ -1466,8 +1452,8 @@ roster_merge_result::report_duplicate_na
if (basic_io)
{
- put_file_resolution (st, left_side, conflict.left_resolution);
- put_file_resolution (st, right_side, conflict.right_resolution);
+ put_file_resolution (st, resolve_conflicts::left_side, conflict.left_resolution);
+ put_file_resolution (st, resolve_conflicts::right_side, conflict.right_resolution);
put_stanza(st, output);
}
}
@@ -1643,9 +1629,9 @@ roster_merge_result::report_file_content
{
basic_io::stanza st;
- if (conflict.resolution.first == resolve_conflicts::none)
+ if (conflict.resolution.resolution == resolve_conflicts::none)
if (auto_merge_succeeds(lua, conflict, adaptor, left_roster, right_roster))
- conflict.resolution.first = resolve_conflicts::content_internal;
+ conflict.resolution.resolution = resolve_conflicts::content_internal;
st.push_str_pair(syms::conflict, syms::content);
put_content_conflict (st, left_roster, right_roster, adaptor, conflict);
@@ -1727,6 +1713,7 @@ static char const * const conflict_resol
static char const * const conflicts_mismatch_msg = N_("conflicts file does not match current conflicts");
static char const * const conflict_resolution_not_supported_msg = N_("%s is not a supported conflict resolution for %s");
+static char const * const history_lost_msg = N_("history for '%s' from %s will be lost; see user manual Merge Conflicts section");
static char const * const conflict_extra = N_("extra chars at end of conflict");
static void
@@ -1886,14 +1873,14 @@ read_orphaned_node_conflict(basic_io::pa
{
if (pars.symp (syms::resolved_drop_left))
{
- conflict.resolution.first = resolve_conflicts::drop;
+ conflict.resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
else if (pars.symp (syms::resolved_rename_left))
{
- conflict.resolution.first = resolve_conflicts::rename;
+ conflict.resolution.resolution = resolve_conflicts::rename;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, true);
+ conflict.resolution.rename = resolve_conflicts::file_path_external(pars.token);
pars.str();
}
else
@@ -1994,10 +1981,12 @@ static void
} // read_multiple_name_conflicts
static void
-read_dropped_modified_conflict(basic_io::parser & pars,
+read_dropped_modified_conflict(basic_io::parser & pars,
dropped_modified_conflict & conflict,
- roster_t const & left_roster,
- roster_t const & right_roster)
+ revision_id left_rid,
+ roster_t const & left_roster,
+ revision_id right_rid,
+ roster_t const & right_roster)
{
string tmp;
@@ -2009,28 +1998,38 @@ read_dropped_modified_conflict(basic_io:
if (tmp == "dropped file")
{
- pars.esym(syms::left_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::left_side;
+
+ pars.esym(syms::left_rev); pars.hex(tmp);
+ conflict.left_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::left_name); pars.str();
pars.esym(syms::left_file_id); pars.hex();
}
else if (tmp == "orphaned file")
{
- pars.esym(syms::left_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::left_side;
+ conflict.orphaned = true;
+
+ pars.esym(syms::left_rev); pars.hex(tmp);
+ conflict.left_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::left_name); pars.str();
pars.esym(syms::left_file_id); pars.hex();
-
- conflict.orphaned = true;
}
else if (tmp == "recreated file")
{
+ conflict.dropped_side = resolve_conflicts::left_side;
+ conflict.left_rid = left_rid;
+
pars.esym(syms::left_name); pars.str(tmp);
- conflict.recreated = left_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.left_nid = left_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::left_file_id); pars.hex();
}
else if (tmp == "modified file")
{
+ conflict.left_rid = left_rid;
+
pars.esym(syms::left_name); pars.str(tmp);
- conflict.left_nid = left_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.left_nid = left_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::left_file_id); pars.hex();
}
else
@@ -2041,70 +2040,108 @@ read_dropped_modified_conflict(basic_io:
if (tmp == "dropped file")
{
- pars.esym(syms::right_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::right_side;
+
+ pars.esym(syms::right_rev); pars.hex(tmp);
+ conflict.right_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::right_name); pars.str();
pars.esym(syms::right_file_id); pars.hex();
}
else if (tmp == "orphaned file")
{
- pars.esym(syms::right_rev); pars.hex();
+ conflict.dropped_side = resolve_conflicts::right_side;
+ conflict.orphaned = true;
+
+ pars.esym(syms::right_rev); pars.hex(tmp);
+ conflict.right_rid = decode_hexenc_as<revision_id>(tmp, pars.tok.in.made_from);
pars.esym(syms::right_name); pars.str();
pars.esym(syms::right_file_id); pars.hex();
-
- conflict.orphaned = true;
}
else if (tmp == "recreated file")
{
+ conflict.dropped_side = resolve_conflicts::right_side;
+ conflict.right_rid = right_rid;
+
pars.esym(syms::right_name); pars.str(tmp);
- conflict.recreated = right_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.right_nid = right_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::right_file_id); pars.hex();
}
else if (tmp == "modified file")
{
+ conflict.right_rid = right_rid;
+
pars.esym(syms::right_name); pars.str(tmp);
- conflict.right_nid = right_roster.get_node(file_path_external(utf8(tmp, origin::internal)))->self;
+ conflict.right_nid = right_roster.get_node(resolve_conflicts::file_path_external(tmp))->self;
pars.esym(syms::right_file_id); pars.hex();
}
else
I(false);
- // check for a resolution
- if ((!pars.symp (syms::conflict)) && pars.tok.in.lookahead != EOF)
+ // check for resolutions
+ while ((!pars.symp (syms::conflict)) && pars.tok.in.lookahead != EOF)
{
if (pars.symp (syms::resolved_drop_left))
{
- conflict.resolution.first = resolve_conflicts::drop;
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
+ else if (pars.symp (syms::resolved_drop_right))
+ {
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
+ pars.sym();
+ }
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;
+ conflict.left_resolution.resolution = resolve_conflicts::keep;
pars.sym();
}
+ else if (pars.symp (syms::resolved_keep_right))
+ {
+ E(!conflict.orphaned, origin::user, F("orphaned files must be renamed"));
+
+ conflict.right_resolution.resolution = resolve_conflicts::keep;
+ pars.sym();
+ }
+ else if (pars.symp (syms::resolved_rename_left))
+ {
+ if (conflict.left_resolution.resolution == resolve_conflicts::content_user)
+ conflict.left_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.left_resolution.resolution = resolve_conflicts::rename;
+ pars.sym();
+ conflict.left_resolution.rename = resolve_conflicts::file_path_external(pars.token);
+ pars.str();
+ }
+ else if (pars.symp (syms::resolved_rename_right))
+ {
+ if (conflict.right_resolution.resolution == resolve_conflicts::content_user)
+ conflict.right_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.right_resolution.resolution = resolve_conflicts::rename;
+ pars.sym();
+ conflict.right_resolution.rename = resolve_conflicts::file_path_external(pars.token);
+ pars.str();
+ }
else if (pars.symp (syms::resolved_user_left))
{
- conflict.resolution.first = resolve_conflicts::content_user;
+ if (conflict.left_resolution.resolution == resolve_conflicts::rename)
+ conflict.left_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.left_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, false);
+ conflict.left_resolution.content = 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 = file_path_external_ws(utf8(tmp, origin::user));
- }
}
- else if (pars.symp (syms::resolved_rename_left))
+ else if (pars.symp (syms::resolved_user_right))
{
- E(conflict.orphaned, origin::user, F("non-orphaned files cannot be renamed"));
-
- conflict.resolution.first = resolve_conflicts::rename;
+ if (conflict.right_resolution.resolution == resolve_conflicts::rename)
+ conflict.right_resolution.resolution = resolve_conflicts::content_user_rename;
+ else
+ conflict.right_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, false);
+ conflict.right_resolution.content = new_optimal_path(pars.token, false);
pars.str();
}
else
@@ -2114,18 +2151,20 @@ static void
} // 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)
+read_dropped_modified_conflicts(basic_io::parser & pars,
+ std::vector<dropped_modified_conflict> & conflicts,
+ revision_id left_rid,
+ roster_t const & left_roster,
+ revision_id right_rid,
+ 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);
+ dropped_modified_conflict conflict;
pars.sym();
- read_dropped_modified_conflict(pars, conflict, left_roster, right_roster);
+ read_dropped_modified_conflict(pars, conflict, left_rid, left_roster, right_rid, right_roster);
conflicts.push_back(conflict);
@@ -2133,11 +2172,14 @@ read_dropped_modified_conflicts(basic_io
pars.esym (syms::conflict);
}
} // read_dropped_modified_conflicts
+
static void
-validate_dropped_modified_conflicts(basic_io::parser & pars,
+validate_dropped_modified_conflicts(basic_io::parser & pars,
std::vector<dropped_modified_conflict> & conflicts,
- roster_t const & left_roster,
- roster_t const & right_roster)
+ revision_id left_rid,
+ roster_t const & left_roster,
+ revision_id right_rid,
+ roster_t const & right_roster)
{
for (std::vector<dropped_modified_conflict>::iterator i = conflicts.begin();
i != conflicts.end();
@@ -2148,17 +2190,19 @@ validate_dropped_modified_conflicts(basi
pars.esym(syms::dropped_modified);
- read_dropped_modified_conflict(pars, file_conflict, left_roster, right_roster);
+ read_dropped_modified_conflict(pars, file_conflict, left_rid, left_roster, right_rid, 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 &&
- merge_conflict.recreated == file_conflict.recreated,
+ E(merge_conflict.dropped_side == file_conflict.dropped_side &&
+ 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;
- merge_conflict.rename = file_conflict.rename;
+ merge_conflict.left_rid = file_conflict.left_rid;
+ merge_conflict.right_rid = file_conflict.right_rid;
+ merge_conflict.left_resolution = file_conflict.left_resolution;
+ merge_conflict.right_resolution = file_conflict.right_resolution;
if (pars.tok.in.lookahead != EOF)
pars.esym (syms::conflict);
@@ -2185,50 +2229,50 @@ read_duplicate_name_conflict(basic_io::p
{
if (pars.symp (syms::resolved_drop_left))
{
- conflict.left_resolution.first = resolve_conflicts::drop;
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
else if (pars.symp (syms::resolved_drop_right))
{
- conflict.right_resolution.first = resolve_conflicts::drop;
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
pars.sym();
}
else if (pars.symp (syms::resolved_keep_left))
{
- conflict.left_resolution.first = resolve_conflicts::keep;
+ conflict.left_resolution.resolution = resolve_conflicts::keep;
pars.sym();
}
else if (pars.symp (syms::resolved_keep_right))
{
- conflict.right_resolution.first = resolve_conflicts::keep;
+ conflict.right_resolution.resolution = resolve_conflicts::keep;
pars.sym();
}
else if (pars.symp (syms::resolved_rename_left))
{
- conflict.left_resolution.first = resolve_conflicts::rename;
+ conflict.left_resolution.resolution = resolve_conflicts::rename;
pars.sym();
- conflict.left_resolution.second = resolve_conflicts::new_file_path(pars.token);
+ conflict.left_resolution.rename = resolve_conflicts::file_path_external(pars.token);
pars.str();
}
else if (pars.symp (syms::resolved_rename_right))
{
- conflict.right_resolution.first = resolve_conflicts::rename;
+ conflict.right_resolution.resolution = resolve_conflicts::rename;
pars.sym();
- conflict.right_resolution.second = resolve_conflicts::new_file_path(pars.token);
+ conflict.right_resolution.rename = resolve_conflicts::file_path_external(pars.token);
pars.str();
}
else if (pars.symp (syms::resolved_user_left))
{
- conflict.left_resolution.first = resolve_conflicts::content_user;
+ conflict.left_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.left_resolution.second = new_optimal_path(pars.token, true);
+ conflict.left_resolution.content = new_optimal_path(pars.token, true);
pars.str();
}
else if (pars.symp (syms::resolved_user_right))
{
- conflict.right_resolution.first = resolve_conflicts::content_user;
+ conflict.right_resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.right_resolution.second = new_optimal_path(pars.token, true);
+ conflict.right_resolution.content = new_optimal_path(pars.token, true);
pars.str();
}
else
@@ -2433,14 +2477,14 @@ read_file_content_conflict(basic_io::par
{
if (pars.symp (syms::resolved_internal))
{
- conflict.resolution.first = resolve_conflicts::content_internal;
+ conflict.resolution.resolution = resolve_conflicts::content_internal;
pars.sym();
}
else if (pars.symp (syms::resolved_user_left))
{
- conflict.resolution.first = resolve_conflicts::content_user;
+ conflict.resolution.resolution = resolve_conflicts::content_user;
pars.sym();
- conflict.resolution.second = new_optimal_path(pars.token, true);
+ conflict.resolution.content = new_optimal_path(pars.token, true);
pars.str();
}
else
@@ -2506,7 +2550,9 @@ read_conflict_file_core(basic_io::parser
static void
read_conflict_file_core(basic_io::parser pars,
+ revision_id left_rid,
roster_t const & left_roster,
+ revision_id right_rid,
roster_t const & right_roster,
roster_merge_result & result,
bool validate)
@@ -2533,7 +2579,8 @@ 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_dropped_modified_conflicts
+ (pars, result.dropped_modified_conflicts, left_rid, left_roster, right_rid, 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);
}
@@ -2546,7 +2593,8 @@ 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_dropped_modified_conflicts
+ (pars, result.dropped_modified_conflicts, left_rid, left_roster, right_rid, 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);
@@ -2596,7 +2644,7 @@ roster_merge_result::read_conflict_file(
db.get_roster(left_rid, left_roster, left_marking);
db.get_roster(right_rid, right_roster, right_marking);
- read_conflict_file_core(pars, left_roster, right_roster, *this, false);
+ read_conflict_file_core(pars, left_rid, left_roster, right_rid, right_roster, *this, false);
}
// else no conflicts
@@ -2694,9 +2742,12 @@ parse_resolve_conflicts_opts (options co
pars.sym();
pars.hex(temp);
+ read_conflict_file_core (pars, left_rid, left_roster, right_rid, right_roster, result, true);
+ }
+ else
+ {
// if there is no ancestor revision, then left is an ancestor of
// right, or vice versa, and there can be no conflicts.
- read_conflict_file_core (pars, left_roster, right_roster, result, true);
}
}
else
@@ -2761,7 +2812,7 @@ roster_merge_result::resolve_orphaned_no
right_roster.get_name(conflict.nid, name);
}
- switch (conflict.resolution.first)
+ switch (conflict.resolution.resolution)
{
case resolve_conflicts::drop:
if (is_dir_t(roster.get_node(conflict.nid)))
@@ -2775,9 +2826,8 @@ roster_merge_result::resolve_orphaned_no
break;
case resolve_conflicts::rename:
- P(F("renaming '%s' to '%s'") % name % *conflict.resolution.second);
- attach_node
- (lua, roster, conflict.nid, file_path_internal (conflict.resolution.second->as_internal()));
+ P(F("renaming '%s' to '%s'") % name % conflict.resolution.rename);
+ attach_node (lua, roster, conflict.nid, conflict.resolution.rename);
break;
case resolve_conflicts::none:
@@ -2794,194 +2844,313 @@ roster_merge_result::resolve_orphaned_no
orphaned_node_conflicts.clear();
}
+static node_id
+create_new_node(roster_t const & parent_roster,
+ string const & side_image,
+ node_id const & parent_nid,
+ roster_t & result_roster,
+ boost::shared_ptr<any_path> new_content,
+ content_merge_adaptor & adaptor,
+ temp_node_id_source & nis)
+{
+ file_path parent_name;
+ file_id parent_fid;
+ file_data parent_data;
+
+ parent_roster.get_file_details(parent_nid, parent_fid, parent_name);
+ adaptor.get_version(parent_fid, parent_data);
+
+ P(F("replacing content of '%s' from %s with '%s'") % parent_name % side_image % new_content->as_external());
+
+ P(F(history_lost_msg) % parent_name % side_image);
+
+ data result_raw_data;
+ read_data(*new_content, result_raw_data);
+
+ file_data result_data = file_data(result_raw_data);
+ file_id result_fid;
+ calculate_ident(result_data, result_fid);
+
+ // User could specify no changes in content
+ if (result_fid != parent_fid)
+ {
+ adaptor.record_file(parent_fid, result_fid, parent_data, result_data);
+ }
+
+ return result_roster.create_file_node(result_fid, nis);
+}
+
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)
+replace_content(roster_t const & parent_roster,
+ string const & side_image,
+ node_id const & nid,
+ roster_t & result_roster,
+ boost::shared_ptr<any_path> new_content,
+ content_merge_adaptor & adaptor)
{
- // See comments in keep below on why we drop first
- roster.drop_detached_node(nid);
+ file_path parent_name;
+ file_id parent_fid;
- file_data result_data;
+ parent_roster.get_file_details(nid, parent_fid, parent_name);
+
+ P(F("replacing content of '%s' from %s with '%s'") % parent_name % side_image % new_content->as_external());
+
+ file_data parent_data;
+ adaptor.get_version(parent_fid, parent_data);
+
data result_raw_data;
- file_id result_fid;
- read_data(*conflict.resolution.second, result_raw_data);
+ read_data(*new_content, result_raw_data);
- result_data = file_data(result_raw_data);
+ file_data result_data = file_data(result_raw_data);
+ file_id result_fid;
calculate_ident(result_data, result_fid);
- nid = roster.create_file_node(result_fid, nis);
+ file_t result_node = downcast_to_file_t(result_roster.get_node_for_update(nid));
+ result_node->content = result_fid;
- // User could specify no changes
- if (result_fid != modified_fid)
+ // User could specify no changes in content
+ if (result_fid != parent_fid)
{
- adaptor.record_file(result_fid, result_data);
+ adaptor.record_file(parent_fid, result_fid, parent_data, result_data);
}
}
-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,
- temp_node_id_source & nis)
+static void
+resolve_dropped_modified_one(lua_hooks & lua,
+ string side_image,
+ bool handling_dropped_side,
+ resolve_conflicts::file_resolution_t const & resolution,
+ resolve_conflicts::file_resolution_t const & other_resolution,
+ roster_t const & side_roster,
+ file_path const & name,
+ file_id const & fid,
+ node_id const nid,
+ content_merge_database_adaptor & adaptor,
+ temp_node_id_source & nis,
+ roster_t & result_roster)
{
- 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)
+ if (nid == the_null_node)
{
- dropped_modified_conflict const & conflict = *i;
- MM(conflict);
+ E(resolution.resolution == resolve_conflicts::none, origin::user,
+ F("extra %s_resolution provided for dropped_modified '%s'") % side_image % name);
+ return;
+ }
+ else
+ {
+ E(resolution.resolution != resolve_conflicts::none, origin::user,
+ (other_resolution.resolution == resolve_conflicts::none) ?
+ F("no resolution provided for dropped_modified '%s'") % name :
+ F("no %s_resolution provided for dropped_modified '%s'") % side_image % name);
+ }
- node_id nid;
- file_path modified_name;
- file_id modified_fid;
- file_path recreated_name;
- file_id recreated_fid;
+ switch (resolution.resolution)
+ {
+ case resolve_conflicts::none:
+ // handled above; can't get here
+ break;
- if (conflict.left_nid == the_null_node)
+ case resolve_conflicts::content_user:
+ // FIXME: check other_resolution for consistency
+ if (handling_dropped_side)
{
- nid = conflict.right_nid;
- right_roster.get_file_details(nid, modified_fid, modified_name);
-
- if (conflict.recreated != the_null_node)
- {
- roster.get_file_details(conflict.recreated, recreated_fid, recreated_name);
- }
+ // recreated; replace the contents of the recreated node
+ replace_content(side_roster, side_image, nid, result_roster, resolution.content, adaptor);
+ attach_node(lua, result_roster, nid, name);
}
else
{
- nid = conflict.left_nid;
- left_roster.get_file_details(nid, modified_fid, modified_name);
+ // modified; drop and create a new node
+ // See comments in keep below on why we drop first
+ result_roster.drop_detached_node(nid);
- if (conflict.recreated != the_null_node)
- {
- roster.get_file_details(conflict.recreated, recreated_fid, recreated_name);
- }
+ node_id new_nid = create_new_node
+ (side_roster, side_image, nid, result_roster, resolution.content, adaptor, nis);
+
+ attach_node(lua, result_roster, new_nid, name);
}
+ break;
- switch (conflict.resolution.first)
+ case resolve_conflicts::content_internal:
+ // not valid for dropped_modified
+ I(false);
+
+ case resolve_conflicts::drop:
+ // The node is either modified, recreated or duplicate name; in
+ // any case, it is present but detached in the result roster, so drop it
+ P(F("dropping '%s' from %s") % name % side_image);
+ result_roster.drop_detached_node(nid);
+ break;
+
+ case resolve_conflicts::keep:
+ if (handling_dropped_side)
{
- case resolve_conflicts::none:
- E(false, origin::user,
- F("no resolution provided for dropped_modifed '%s'") % modified_name);
- break;
+ // recreated; keep the recreated contents
+ P(F("keeping '%s' from %s") % name % side_image);
+ attach_node(lua, result_roster, nid, name);
+ }
+ else
+ {
+ // modified; keep the modified contents
- case resolve_conflicts::content_user:
- P(F("replacing content of '%s' with '%s'") %
- modified_name % conflict.resolution.second->as_external());
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ P(F("keeping '%s' from %s") % name % side_image);
+ P(F(history_lost_msg) % name % side_image);
- if (conflict.recreated == the_null_node)
- {
- resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
- attach_node(lua, roster, nid, modified_name);
- }
- else
- {
- // See comments in keep below on why we drop first
- roster.drop_detached_node(nid);
+ // We'd like to just attach_node here, but that violates a
+ // fundamental design principle of mtn; nodes are born once,
+ // and die once. If we attach here, the node is born, died,
+ // and then born again.
+ //
+ // So we have to drop the old node, and create a new node with
+ // the same contents. That loses history; 'mtn log <path>'
+ // will end here, not showing the history of the original
+ // node.
+ result_roster.drop_detached_node(nid);
+ node_id nid = result_roster.create_file_node(fid, nis);
+ attach_node (lua, result_roster, nid, name);
+ }
+ break;
- file_id result_fid;
- file_data parent_data, result_data;
- data result_raw_data;
- adaptor.get_version(recreated_fid, parent_data);
+ case resolve_conflicts::rename:
+ if (handling_dropped_side)
+ {
+ // recreated; rename the recreated contents
+ P(F("renaming '%s' from %s to '%s'") % name % side_image % resolution.rename.as_external());
+ attach_node(lua, result_roster, nid, resolution.rename);
+ }
+ else
+ {
+ // modified; drop, create new node with the modified contents, rename
+ // See comment in keep above on why we drop first.
+ result_roster.drop_detached_node(nid);
- read_data(*conflict.resolution.second, result_raw_data);
+ P(F("renaming '%s' from %s to '%s'") % name % side_image % resolution.rename.as_external());
+ P(F(history_lost_msg) % name % side_image);
- result_data = file_data(result_raw_data);
- calculate_ident(result_data, result_fid);
+ node_id new_nid = result_roster.create_file_node(fid, nis);
+ attach_node (lua, result_roster, new_nid, resolution.rename);
+ }
+ break;
- file_t result_node = downcast_to_file_t(roster.get_node_for_update(conflict.recreated));
- result_node->content = result_fid;
+ case resolve_conflicts::content_user_rename:
+ if (handling_dropped_side)
+ {
+ // recreated; rename and replace the recreated contents
+ replace_content(side_roster, side_image, nid, result_roster, resolution.content, adaptor);
- adaptor.record_file(recreated_fid, result_fid, parent_data, result_data);
- }
- break;
+ P(F("renaming '%s' from %s to '%s'") % name % side_image % resolution.rename.as_external());
- case resolve_conflicts::content_user_rename:
- I(conflict.rename.as_external().length() != 0);
- P(F("replacing content of '%s' (renamed to '%s') with '%s'") %
- modified_name % conflict.rename.as_external() % conflict.resolution.second->as_external());
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ attach_node (lua, result_roster, nid, resolution.rename);
+ }
+ else
+ {
+ // modified; drop, rename and replace the modified contents
+ result_roster.drop_detached_node(nid);
- resolve_dropped_modified_user(roster, nid, modified_fid, conflict, adaptor, nis);
- attach_node(lua, roster, nid, file_path_internal (conflict.rename.as_internal()));
- break;
+ node_id new_nid = create_new_node
+ (side_roster, side_image, nid, result_roster, resolution.content, adaptor, nis);
- case resolve_conflicts::drop:
- P(F("dropping '%s'") % modified_name);
+ P(F("renaming '%s' from %s to '%s'") % name % side_image % resolution.rename.as_external());
- roster.drop_detached_node(nid);
- break;
+ attach_node(lua, result_roster, new_nid, resolution.rename);
+ }
+ break;
+ }
+} // resolve_dropped_modified_one
- case resolve_conflicts::rename:
- P(F("renaming '%s' to '%s'") % modified_name % conflict.resolution.second->as_external());
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+void
+roster_merge_result::resolve_dropped_modified_conflicts(lua_hooks & lua,
+ roster_t const & left_roster,
+ roster_t const & right_roster,
+ content_merge_database_adaptor & adaptor,
+ temp_node_id_source & nis)
+{
+ MM(left_roster);
+ MM(right_roster);
+ MM(this->roster); // New roster
- // 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;
+ for (std::vector<dropped_modified_conflict>::iterator i = dropped_modified_conflicts.begin();
+ i != dropped_modified_conflicts.end();
+ ++i)
+ {
+ dropped_modified_conflict & conflict = *i;
+ MM(conflict);
- case resolve_conflicts::keep:
- if (conflict.recreated == the_null_node)
+ file_path left_name;
+ file_id left_fid;
+ file_path right_name;
+ file_id right_fid;
+
+ if (conflict.left_nid != the_null_node)
+ {
+ if (conflict.left_rid == adaptor.left_rid)
{
- P(F("keeping '%s'") % modified_name);
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ left_roster.get_file_details(conflict.left_nid, left_fid, left_name);
+ }
+ else
+ {
+ if (null_id(conflict.left_rid))
+ {
+ // attr mtn::resolve_conflict drop does not set rid; find it now
+ adaptor.get_dropped_details
+ (adaptor.left_rid, conflict.left_nid, conflict.left_rid, left_name, left_fid);
+ }
+ else
+ {
+ roster_t tmp;
+ adaptor.db.get_roster(conflict.left_rid, tmp);
+ tmp.get_file_details(conflict.left_nid, left_fid, left_name);
+ }
+ }
+ }
- // We'd like to just attach_node here, but that violates a
- // fundamental design principle of mtn; nodes are born once,
- // and die once. If we attach here, the node is born, died,
- // and then born again.
- //
- // So we have to drop the old node, and create a new node with
- // the same contents. That loses history; 'mtn log <path>'
- // will end here, not showing the history of the original
- // node.
- roster.drop_detached_node(nid);
- nid = roster.create_file_node(modified_fid, nis);
- attach_node (lua, roster, nid, modified_name);
+ if (conflict.right_nid != the_null_node)
+ {
+ if (conflict.right_rid == adaptor.right_rid)
+ {
+ right_roster.get_file_details(conflict.right_nid, right_fid, right_name);
}
else
{
- P(F("keeping '%s' from %s") % modified_name % ((conflict.left_nid == the_null_node) ? "right" : "left"));
- P(F("history for '%s' will be lost; see user manual Merge Conflicts section") %
- modified_name);
+ if (null_id(conflict.left_rid))
+ {
+ adaptor.get_dropped_details
+ (adaptor.right_rid, conflict.right_nid, conflict.right_rid, right_name, right_fid);
+ }
+ else
+ {
+ roster_t tmp;
+ adaptor.db.get_roster(conflict.right_rid, tmp);
+ tmp.get_file_details(conflict.right_nid, right_fid, right_name);
+ }
+ }
+ }
- roster.drop_detached_node(nid);
+ resolve_dropped_modified_one (lua,
+ string("left"),
+ conflict.dropped_side == resolve_conflicts::left_side,
+ conflict.left_resolution,
+ conflict.right_resolution,
+ left_roster,
+ left_name,
+ left_fid,
+ conflict.left_nid,
+ adaptor,
+ nis,
+ roster);
- // keep the modified content, not the recreated content
- file_data parent_data, result_data;
- adaptor.get_version(recreated_fid, parent_data);
+ resolve_dropped_modified_one (lua,
+ string("right"),
+ conflict.dropped_side == resolve_conflicts::right_side,
+ conflict.right_resolution,
+ conflict.left_resolution,
+ right_roster,
+ right_name,
+ right_fid,
+ conflict.right_nid,
+ adaptor,
+ nis,
+ roster);
- adaptor.get_version(modified_fid, result_data);
-
- file_t result_node = downcast_to_file_t(roster.get_node_for_update(conflict.recreated));
- result_node->content = modified_fid;
-
- adaptor.record_file(recreated_fid, modified_fid, parent_data, result_data);
- }
- break;
-
- default:
- I(false);
- }
-
} // end for
dropped_modified_conflicts.clear();
@@ -2997,23 +3166,23 @@ resolve_duplicate_name_one_side(lua_hook
content_merge_adaptor & adaptor,
roster_t & result_roster)
{
- switch (resolution.first)
+ switch (resolution.resolution)
{
case resolve_conflicts::content_user:
{
- E(other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename,
origin::user,
F("inconsistent left/right resolutions for '%s'") % name);
- P(F("replacing content of '%s' with '%s'") % name % resolution.second->as_external());
+ P(F("replacing content of '%s' with '%s'") % name % resolution.content->as_external());
file_id result_fid;
file_data parent_data, result_data;
data result_raw_data;
adaptor.get_version(fid, parent_data);
- read_data(*resolution.second, result_raw_data);
+ read_data(*resolution.content, result_raw_data);
result_data = file_data(result_raw_data);
calculate_ident(result_data, result_fid);
@@ -3039,8 +3208,8 @@ resolve_duplicate_name_one_side(lua_hook
break;
case resolve_conflicts::keep:
- E(other_resolution.first == resolve_conflicts::drop ||
- other_resolution.first == resolve_conflicts::rename,
+ E(other_resolution.resolution == resolve_conflicts::drop ||
+ other_resolution.resolution == resolve_conflicts::rename,
origin::user,
F("inconsistent left/right resolutions for '%s'") % name);
@@ -3049,9 +3218,8 @@ resolve_duplicate_name_one_side(lua_hook
break;
case resolve_conflicts::rename:
- P(F("renaming '%s' to '%s'") % name % *resolution.second);
- attach_node
- (lua, result_roster, nid, file_path_internal (resolution.second->as_internal()));
+ P(F("renaming '%s' to '%s'") % name % resolution.rename);
+ attach_node (lua, result_roster, nid, resolution.rename);
break;
case resolve_conflicts::none:
@@ -3146,7 +3314,7 @@ roster_merge_result::resolve_file_conten
left_roster.get_name(conflict.nid, left_name);
right_roster.get_name(conflict.nid, right_name);
- switch (conflict.resolution.first)
+ switch (conflict.resolution.resolution)
{
case resolve_conflicts::content_internal:
case resolve_conflicts::none:
@@ -3168,7 +3336,7 @@ roster_merge_result::resolve_file_conten
case resolve_conflicts::content_user:
{
P(F("replacing content of '%s', '%s' with '%s'") %
- left_name % right_name % conflict.resolution.second->as_external());
+ left_name % right_name % conflict.resolution.content->as_external());
file_id result_id;
file_data left_data, right_data, result_data;
@@ -3176,7 +3344,7 @@ roster_merge_result::resolve_file_conten
adaptor.get_version(conflict.left, left_data);
adaptor.get_version(conflict.right, right_data);
- read_data(*conflict.resolution.second, result_raw_data);
+ read_data(*conflict.resolution.content, result_raw_data);
result_data = file_data(result_raw_data);
calculate_ident(result_data, result_id);
============================================================
--- src/merge_content.cc 662433acaf08fc1f3f3417389a9bc3b3d2bd9bf1
+++ src/merge_content.cc 095c2d20ac8d8d495806f6463c311d253cb6a686
@@ -189,8 +189,9 @@ content_merge_database_adaptor::get_drop
set<revision_id> parents;
db.get_revision_parents(rev_id, parents);
- for (set<revision_id>::iterator i = parents.begin(); i != parents.end(); i++)
+ while (parents.begin() != parents.end())
{
+ set<revision_id>::iterator i = parents.begin();
roster_t roster;
marking_map marking_map;
@@ -203,6 +204,7 @@ content_merge_database_adaptor::get_drop
}
else
{
+ parents.erase (i);
set<revision_id> more_parents;
db.get_revision_parents(*i, more_parents);
parents.insert(more_parents.begin(), more_parents.end());
@@ -745,7 +747,8 @@ resolve_merge_conflicts(lua_hooks & lua,
// Resolve the ones we can, if they have resolutions specified. Each
// conflict list is deleted once all are resolved.
result.resolve_orphaned_node_conflicts(lua, left_roster, right_roster, adaptor);
- result.resolve_dropped_modified_conflicts(lua, left_roster, right_roster, adaptor, nis);
+ result.resolve_dropped_modified_conflicts(lua, left_roster, right_roster,
+ dynamic_cast <content_merge_database_adaptor&>(adaptor), nis);
result.resolve_duplicate_name_conflicts(lua, left_roster, right_roster, adaptor);
result.resolve_file_content_conflicts (lua, left_roster, right_roster, adaptor);
============================================================
--- src/merge_roster.cc 5fbc50c114df22f4753f444aa137c06ea0f06195
+++ src/merge_roster.cc c3eb70578a3b8b88c4d1b7af43b7685d6f636c23
@@ -26,27 +26,61 @@ enum side_t {left_side, right_side};
enum side_t {left_side, right_side};
-static char const *
-image(resolve_conflicts::resolution_t resolution)
+namespace resolve_conflicts
{
- switch (resolution)
- {
- case resolve_conflicts::none:
- return "none";
- case resolve_conflicts::content_user:
- return "content_user";
- case resolve_conflicts::content_internal:
- return "content_internal";
- case resolve_conflicts::drop:
- return "drop";
- case resolve_conflicts::keep:
- return "keep";
- case resolve_conflicts::rename:
- return "rename";
- case resolve_conflicts::content_user_rename:
- return "content_user_rename";
- }
- I(false); // keep compiler happy
+ char const *
+ image(side_t item)
+ {
+ switch (item)
+ {
+ case resolve_conflicts::left_side:
+ return "left_side";
+ case resolve_conflicts::right_side:
+ return "right_side";
+ }
+ I(false); // keep compiler happy
+ }
+
+ char const *
+ image(resolution_t resolution)
+ {
+ switch (resolution)
+ {
+ case resolve_conflicts::none:
+ return "none";
+ case resolve_conflicts::content_user:
+ return "content_user";
+ case resolve_conflicts::content_internal:
+ return "content_internal";
+ case resolve_conflicts::drop:
+ return "drop";
+ case resolve_conflicts::keep:
+ return "keep";
+ case resolve_conflicts::rename:
+ return "rename";
+ case resolve_conflicts::content_user_rename:
+ return "content_user_rename";
+ }
+ I(false); // keep compiler happy
+ }
+
+ string
+ image(file_resolution_t res)
+ {
+ if (res.resolution == resolve_conflicts::none)
+ return string("\n");
+ else
+ {
+ ostringstream oss;
+ oss << "resolution: " << image(res.resolution);
+ if (res.content != 0)
+ oss << ", content: '" << res.content->as_external() << "'";
+ if (res.rename.as_internal().length()>0)
+ oss << ", rename: '" << res.rename.as_external() << "'";
+ oss << "\n";
+ return oss.str();
+ }
+ }
}
template <> void
@@ -95,16 +129,15 @@ dump(dropped_modified_conflict const & c
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;
- oss << " orphaned: " << conflict.orphaned;
- if (conflict.resolution.first != resolve_conflicts::none)
- {
- oss << " resolution: " << image(conflict.resolution.first);
- oss << " new_content_name: " << conflict.resolution.second;
- oss << " rename: " << conflict.rename;
- }
- oss << "\n";
+ oss << "dropped_modified_conflict -\n";
+ oss << " dropped_side : " << image(conflict.dropped_side) << "\n";
+ oss << " left_nid : " << conflict.left_nid << "\n";
+ oss << " right_nid : " << conflict.right_nid << "\n";
+ oss << " orphaned : " << conflict.orphaned << "\n";
+ oss << " left_rid : " << conflict.left_rid << "\n";
+ oss << " right_rid : " << conflict.right_rid << "\n";
+ oss << " left_resolution : " << image(conflict.left_resolution);
+ oss << " right_resolution: " << image(conflict.right_resolution);
out = oss.str();
}
@@ -115,19 +148,10 @@ dump(duplicate_name_conflict const & con
oss << "duplicate_name_conflict between left node: " << conflict.left_nid << " "
<< "and right node: " << conflict.right_nid << " "
<< "parent: " << conflict.parent_name.first << " "
- << "basename: " << conflict.parent_name.second;
-
- if (conflict.left_resolution.first != resolve_conflicts::none)
- {
- oss << " left_resolution: " << image(conflict.left_resolution.first);
- oss << " left_name: " << conflict.left_resolution.second;
- }
- if (conflict.right_resolution.first != resolve_conflicts::none)
- {
- oss << " right_resolution: " << image(conflict.right_resolution.first);
- oss << " right_name: " << conflict.right_resolution.second;
- }
- oss << "\n";
+ << "basename: " << conflict.parent_name.second << " "
+ << "left_resolution: " << image(conflict.left_resolution)
+ << "right_resolution: " << image(conflict.right_resolution)
+ << "\n";
out = oss.str();
}
@@ -147,12 +171,7 @@ dump(file_content_conflict const & confl
{
ostringstream oss;
oss << "file_content_conflict on node: " << conflict.nid;
-
- if (conflict.resolution.first != resolve_conflicts::none)
- {
- oss << " resolution: " << image(conflict.resolution.first);
- oss << " name: " << conflict.resolution.second;
- }
+ oss << " resolution: " << image(conflict.resolution);
oss << "\n";
out = oss.str();
}
@@ -374,7 +393,7 @@ namespace
switch (present_in)
{
case left_side:
- conflict = dropped_modified_conflict(n->self, the_null_node);
+ conflict = dropped_modified_conflict(n->self, the_null_node);
break;
case right_side:
conflict = dropped_modified_conflict(the_null_node, n->self);
@@ -385,7 +404,15 @@ namespace
{
if (i->second.second == typecast_vocab<attr_value>(utf8("drop")))
{
- conflict.resolution.first = resolve_conflicts::drop;
+ switch (present_in)
+ {
+ case left_side:
+ conflict.left_resolution.resolution = resolve_conflicts::drop;
+ break;
+ case right_side:
+ conflict.right_resolution.resolution = resolve_conflicts::drop;
+ break;
+ }
}
else
{
@@ -791,26 +818,83 @@ roster_merge(roster_t const & left_paren
I(new_i == result.roster.all_nodes().end());
}
- // now we can look for dropped_modified conflicts with recreated nodes
+ // now we can look for dropped_modified conflicts with recreated nodes or
+ // duplicate names
for (size_t i = 0; i < result.dropped_modified_conflicts.size(); ++i)
{
dropped_modified_conflict & conflict = result.dropped_modified_conflicts[i];
+ // If the file name was recreated, it is present in the result with
+ // the modified_name but different node id; find that and unattach it.
+ // Or, it may now subject to a duplicate_name conflict (see
+ // test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2).
+ // In which case modified_name will be present in the other parent,
+ // but not in the result.
+
file_path modified_name;
- if (conflict.left_nid == the_null_node)
+ node_id nid;
+ bool duplicate_name = false;
+
+ switch (conflict.dropped_side)
{
+ case resolve_conflicts::left_side:
right_parent.get_name(conflict.right_nid, modified_name);
- }
- else
- {
+
+ if (result.roster.has_node(modified_name))
+ {
+ // recreated; we need to detach the node for the conflict
+ // resolution process. We'd like to just do:
+ // result.roster.detach_node(modified_name);
+ // but that doesn't erase result.roster.old_locations properly
+
+ const_node_t const & left_node = left_parent.get_node(modified_name);
+ node_id parent = left_node->parent;
+ path_component component_name = left_node->name;
+ dir_t p = downcast_to_dir_t(result.roster.get_node_for_update(parent));
+ conflict.left_nid = left_node->self;
+ p->detach_child(component_name);
+ }
+ else if (left_parent.has_node (modified_name))
+ {
+ conflict.left_nid = left_parent.get_node(modified_name)->self;
+ nid = conflict.left_nid;
+ duplicate_name = true;
+ }
+ break;
+
+ case resolve_conflicts::right_side:
left_parent.get_name(conflict.left_nid, modified_name);
+
+ if (result.roster.has_node(modified_name))
+ {
+ // recreated; see comment in left_side above
+ const_node_t const & right_node = right_parent.get_node(modified_name);
+ node_id parent = right_node->parent;
+ path_component component_name = right_node->name;
+ dir_t p = downcast_to_dir_t(result.roster.get_node_for_update(parent));
+ conflict.right_nid = right_node->self;
+ p->detach_child(component_name);
+ }
+ else if (right_parent.has_node (modified_name))
+ {
+ conflict.right_nid = right_parent.get_node(modified_name)->self;
+ nid = conflict.right_nid;
+ duplicate_name = true;
+ }
+ break;
}
- if (result.roster.has_node(modified_name))
+ if (duplicate_name)
{
- conflict.recreated = result.roster.get_node(modified_name)->self;
+ // delete the duplicate name conflict; it will be handled by dropped_modified.
+ std::vector<duplicate_name_conflict>::iterator i =
+ find(result.duplicate_name_conflicts.begin(),
+ result.duplicate_name_conflicts.end(),
+ nid);
+
+ result.duplicate_name_conflicts.erase(i);
}
- }
+ } // end dropped_modified loop
// now check for the possible global problems
if (!result.roster.has_root())
============================================================
--- src/merge_roster.hh 34d382b0ad333fa0f052e8640a88c1ece03caaa9
+++ src/merge_roster.hh c782f7684e380f4583ed7ea88b0b2967f89d1d23
@@ -31,10 +31,31 @@ namespace resolve_conflicts
{
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;
+ char const * image(resolution_t item);
- boost::shared_ptr<any_path> new_file_path(std::string path);
+ enum side_t {left_side, right_side};
+ char const * image(side_t item);
+
+ struct file_resolution_t
+ {
+ resolution_t resolution;
+ boost::shared_ptr<any_path> content;
+ file_path rename;
+
+ file_resolution_t() :
+ resolution(none),
+ content(),
+ rename()
+ {}
+ };
+
+ std::string image(file_resolution_t res);
+
+ // For filename read from conflicts file; converts path to utf8. basic_io
+ // parser should return utf8 in the first place.
+ file_path file_path_external(std::string path);
+
}
// renaming the root dir allows these:
@@ -94,34 +115,54 @@ struct dropped_modified_conflict
// 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.
+ // A dropped_modified conflict can be the result of a repeated
+ // duplicate_name conflict (see
+ // ../test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2)
+ //
+ // If the user has recreated the dropped node, that also looks like a
+ // duplicate name conflict.
+ //
+ // In either case both nids are non-null.
+ //
+ // Dropped_modified can also be due to a dropped directory, in which case
+ // this looks like an orphaned_node conflict.
+ //
+ // If the resolution for the dropped node is 'keep', we need the revision
+ // that contains the node id, which is an ancestor of the merge parent.
+ // That information is also useful for an external front end, that wants to
+ // retreive the file contents for a merge tool.
- bool orphaned; // if true, the dropped side is due to a dropped parent directory
+ resolve_conflicts::side_t dropped_side;
- node_id recreated; // by user, or in a previous drop/modified resolution
+ // If nid is set, it is in corresponding merge parent.
+ node_id left_nid, right_nid;
- resolve_conflicts::file_resolution_t resolution;
- file_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.
+ bool orphaned; // if true, the dropped side is due to a dropped parent directory
+ revision_id left_rid, right_rid;
+ resolve_conflicts::file_resolution_t left_resolution, right_resolution;
+
dropped_modified_conflict(node_id left_nid, node_id right_nid) :
left_nid(left_nid),
right_nid(right_nid),
orphaned(false),
- recreated(the_null_node)
- // rename is implicitly null
- {resolution.first = resolve_conflicts::none;}
+ left_rid(),
+ right_rid(),
+ left_resolution(),
+ right_resolution()
+ {dropped_side = (left_nid == the_null_node ? resolve_conflicts::left_side : resolve_conflicts::right_side);}
dropped_modified_conflict() :
left_nid(the_null_node),
right_nid(the_null_node),
orphaned(false),
- recreated(the_null_node)
- // rename is implicitly null
- {resolution.first = resolve_conflicts::none;}
+ left_rid(),
+ right_rid(),
+ left_resolution(),
+ right_resolution()
+ {}
+ // for find
bool operator==(node_id n) {return left_nid == n || right_nid == n;}
};
@@ -147,9 +188,10 @@ struct duplicate_name_conflict
// it may be a bookkeeping or system path if resolution is 'user'.
resolve_conflicts::file_resolution_t left_resolution, right_resolution;
- duplicate_name_conflict ()
- {left_resolution.first = resolve_conflicts::none;
- right_resolution.first = resolve_conflicts::none;};
+ duplicate_name_conflict() {};
+
+ // for find
+ bool operator==(node_id n) {return left_nid == n || right_nid == n;}
};
// nodes with attribute conflicts are left attached in the resulting tree (unless
@@ -174,12 +216,15 @@ struct file_content_conflict
file_id ancestor, left, right; // ancestor is set only when reading in a conflicts file
resolve_conflicts::file_resolution_t resolution;
- file_content_conflict () :
- nid(the_null_node)
- {resolution.first = resolve_conflicts::none;};
+ file_content_conflict() :
+ nid(the_null_node),
+ resolution()
+ {};
file_content_conflict(node_id nid) :
- nid(nid) {resolution.first = resolve_conflicts::none;};
+ nid(nid),
+ resolution()
+ {};
};
template <> void dump(invalid_name_conflict const & conflict, std::string & out);
@@ -269,7 +314,7 @@ struct roster_merge_result
void resolve_dropped_modified_conflicts(lua_hooks & lua,
roster_t const & left_roster,
roster_t const & right_roster,
- content_merge_adaptor & adaptor,
+ content_merge_database_adaptor & adaptor,
temp_node_id_source & nis);
void report_duplicate_name_conflicts(roster_t const & left,
============================================================
--- src/roster.cc 3f81121ce80b42565e6e5e4bbe3e6186b85e9b10
+++ src/roster.cc b0608d6ec3e3f2d23a5c97bb64c4354eeb01773a
@@ -1188,14 +1188,30 @@ dump(roster_t const & val, string & out)
out = oss.str();
}
+template <> void
+dump(std::map<node_id, std::pair<node_id, path_component> > const & val, string & out)
+{
+ ostringstream oss;
+ for (std::map<node_id, std::pair<node_id, path_component> >::const_iterator i = val.begin();
+ i != val.end();
+ ++i)
+ {
+ oss << "Node " << i->first;
+ oss << " node " << i->second.first;
+ oss << " path " << i->second.second << "\n";
+ }
+ out = oss.str();
+}
+
void
roster_t::check_sane(bool temp_nodes_ok) const
{
MM(*this);
+ MM(old_locations);
node_id parent_id(the_null_node);
const_dir_t parent_dir;
- I(old_locations.empty());
+ I(old_locations.empty()); // if fail, some renamed node is still present and detached
I(has_root());
size_t maxdepth = nodes.size();
bool is_first = true;
@@ -1235,7 +1251,7 @@ roster_t::check_sane(bool temp_nodes_ok)
I(n == get_node(nid));
I(maxdepth-- > 0);
}
- I(maxdepth == 0);
+ I(maxdepth == 0); // if fails, some newly created node is not attached
}
void
============================================================
--- test/func/resolve_conflicts_dropped_modified/__driver__.lua e4f973e6cb8e3494c4b498f68f7cd4b2a6d20fa6
+++ test/func/resolve_conflicts_dropped_modified_1/__driver__.lua 2c87a2a5810a34019c4ca4148eb2b9bede764267
@@ -1,25 +1,55 @@
-- Test reporting and resolving drop/modified conflicts
--
+-- tests for the restrictions imposed by orphan, resoltion consistency
+-- are in resolved_dropped_modified_3
+--
-- other resolve_conflicts_dropped_modified_* tests validate resolving
-- in extended use cases.
+-- Parent nodes can be in several states: dropped, modified,
+-- recreated. Modified nodes can also be renamed, but that is
+-- orthogonal to resolutions; the parent name is used to detect
+-- recreate or duplicate name, and to name the result node if no
+-- rename resolution is specified. Dropped files can also be orphaned,
+-- but that just restricts the allowed resolutions (no keep).
+--
+-- We need to test all combinations of left/right, parent node state,
+-- and resolution:
+--
+-- state resolution left file right file
+-- dropped drop file_3 etc file_2 etc
+-- keep (not supported)
+-- rename (not supported)
+-- user (not supported)
+-- user_rename (not supported)
+--
+-- modified drop file_2 file_3 etc
+-- keep file_4 file_5
+-- rename file_14 file_9
+-- user file_6 file_7
+-- user_rename file_15 file_10
+--
+-- recreated drop file_16 file_12
+-- keep file_12 file_14
+-- rename file_17 file_15
+-- user file_13 file_16
+-- user_rename file_18 file_13
+--
+
mtn_setup()
--- Create conflicts; modify and rename file in one head, drop in
--- other.
+-- Create conflicts with single resolutions; modify and/or rename file in
+-- one parent, drop in the other.
--
--- 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.
+-- Six conflicts to test three possible resolutions, with drop on
+-- both left and right.
-addfile("file_2", "file_2 base") -- modify/rename left, drop right; drop
-addfile("file_3", "file_3 base") -- drop left, modify/rename right; drop
-addfile("file_4", "file_4 base") -- modify left; modify, rename, and drop right; keep
-addfile("file_5", "file_5 base") -- modify, rename, and drop left; modify right; keep
-addfile("file_6", "file_6 base") -- modify/rename left, drop right; user
-addfile("file_7", "file_7 base") -- drop left, modify/rename right; user
+addfile("file_2", "file_2 base") -- modify/rename left: drop right: drop left, drop right
+addfile("file_3", "file_3 base") -- drop left; modify/rename right: drop left, drop right
+addfile("file_4", "file_4 base") -- modify left; modify, rename, and drop right; keep left, drop right
+addfile("file_5", "file_5 base") -- modify, rename, and drop left; modify right; drop left, keep right
+addfile("file_6", "file_6 base") -- modify/rename left, drop right; user left, drop right
+addfile("file_7", "file_7 base") -- drop left, modify/rename right; drop left, user right
commit("testbranch", "base")
base = base_revision()
@@ -92,6 +122,8 @@ check(samelines("stderr",
"mtn: dropped 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\"",
"mtn: resolve_first keep",
"mtn: resolve_first user \"name\""}))
@@ -100,7 +132,7 @@ check(mtn("explicit_merge", "--resolve-c
-- check for nice error message if not all dropped_modified conflicts are resolved
-- we have to use explicit_merge to get left/right to match 'conflicts store'
check(mtn("explicit_merge", "--resolve-conflicts", left_1, right_1, "testbranch"), 1, nil, true)
-check(qgrep("no resolution provided for", "stderr"))
+check(qgrep("no resolution provided for dropped_modified 'file_3_renamed'", "stderr"))
check(mtn("conflicts", "show_first"), 0, nil, true)
check(samelines("stderr",
@@ -109,6 +141,8 @@ check(samelines("stderr",
"mtn: modified 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\"",
"mtn: resolve_first keep",
"mtn: resolve_first user \"name\""}))
@@ -121,6 +155,8 @@ check(samelines("stderr",
"mtn: dropped 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\"",
"mtn: resolve_first keep",
"mtn: resolve_first user \"name\""}))
@@ -133,6 +169,8 @@ check(samelines("stderr",
"mtn: modified 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\"",
"mtn: resolve_first keep",
"mtn: resolve_first user \"name\""}))
@@ -145,6 +183,8 @@ check(samelines("stderr",
"mtn: dropped 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\"",
"mtn: resolve_first keep",
"mtn: resolve_first user \"name\""}))
@@ -159,10 +199,11 @@ check(samelines("stderr",
"mtn: modified 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\"",
"mtn: resolve_first keep",
"mtn: resolve_first user \"name\""}))
-mkdir("_MTN/resolutions")
writefile("_MTN/resolutions/file_7_resolved", "file_7 resolved")
check(mtn("conflicts", "resolve_first", "user", "_MTN/resolutions/file_7_resolved"), 0, nil, true)
@@ -171,16 +212,23 @@ check(mtn("explicit_merge", "--resolve-c
-- we have to use explicit_merge to get left/right to match 'conflicts store'
check(mtn("explicit_merge", "--resolve-conflicts", left_1, right_1, "testbranch"), 0, nil, true)
-check(qgrep("dropping 'file_2_renamed'", "stderr"))
-check(qgrep("dropping 'file_3_renamed'", "stderr"))
-check(qgrep("keeping 'file_4'", "stderr"))
-check(qgrep("keeping 'file_5'", "stderr"))
-check(qgrep("replacing content of 'file_6_renamed' with '_MTN/resolutions/file_6_resolved", "stderr"))
-check(qgrep("replacing content of 'file_7_renamed' with '_MTN/resolutions/file_7_resolved", "stderr"))
-check(not qgrep("warning", "stderr"))
+check(samelines("stderr",
+{"mtn: [left] 7b2ef4343b0717bcd122498a1a0b7ff7acffb64c",
+ "mtn: [right] ca7922b510f9daf5c4b28c6788315ee82eb9a7f0",
+ "mtn: dropping 'file_2_renamed' from left",
+ "mtn: dropping 'file_3_renamed' from right",
+ "mtn: keeping 'file_4' from left",
+ "mtn: history for 'file_4' from left will be lost; see user manual Merge Conflicts section",
+ "mtn: keeping 'file_5' from right",
+ "mtn: history for 'file_5' from right will be lost; see user manual Merge Conflicts section",
+ "mtn: replacing content of 'file_6_renamed' from left with '_MTN/resolutions/file_6_resolved'",
+ "mtn: history for 'file_6_renamed' from left will be lost; see user manual Merge Conflicts section",
+ "mtn: replacing content of 'file_7_renamed' from right with '_MTN/resolutions/file_7_resolved'",
+ "mtn: history for 'file_7_renamed' from right will be lost; see user manual Merge Conflicts section",
+ "mtn: [merged] 57bf835ef0434411189dc3eca1650a6bba513c14"}))
-- If a file is renamed (without other change) and dropped,
--- the change is ignored:
+-- the rename is ignored:
addfile("file_8", "file_8 base") -- rename left, drop right
commit("testbranch", "base 2")
@@ -208,13 +256,13 @@ check(qgrep("0 conflicts", "stderr"))
-- 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:
+-- We create four 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
+adddir("dir1") -- empty - drop left; rename right (not a conflict; just dropped)
+mkdir("dir2") -- not empty - modified left; drop right
+addfile("dir2/file_9", "file_9 base") -- resolution: rename left, drop right
+addfile("dir2/file_10", "file_10 base") -- resolution: user_rename left, drop right
+addfile("dir2/file_11", "file_11 base") -- resolution: drop left, drop right
commit("testbranch", "base 3")
base_3 = base_revision()
@@ -260,6 +308,15 @@ check(mtn("conflicts", "resolve_first",
writefile("_MTN/resolutions/file_10", "file_10 user")
check(mtn("conflicts", "resolve_first", "user_rename", "_MTN/resolutions/file_10", "file_10"), 0, nil, true)
+-- Test error message from invalid resolution
+check(mtn("conflicts", "resolve_first", "keep"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: orphaned files must be renamed"}))
+
+check(mtn("conflicts", "resolve_first", "user", "foo"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: orphaned files must be renamed"}))
+
check(mtn("conflicts", "resolve_first", "drop"), 0, nil, nil)
check(mtn("conflicts", "resolve_first", "rename", "file_9"), 0, nil, nil)
@@ -270,97 +327,188 @@ check(samelines("stderr",
check(samelines("stderr",
{"mtn: [left] 4228fbd8003cdd89e7eea51fcef10c3f91d78f69",
"mtn: [right] 6cb6438a490a1ad4c69ff6cac23c75a903cd9cfd",
- "mtn: replacing content of 'dir2/file_10' (renamed to 'file_10') with '_MTN/resolutions/file_10'",
- "mtn: history for 'dir2/file_10' will be lost; see user manual Merge Conflicts section",
- "mtn: dropping 'dir2/file_11'",
- "mtn: renaming 'dir2/file_9' to 'file_9'",
- "mtn: history for 'dir2/file_9' will be lost; see user manual Merge Conflicts section",
+ "mtn: replacing content of 'dir2/file_10' from left with '_MTN/resolutions/file_10'",
+ "mtn: history for 'dir2/file_10' from left will be lost; see user manual Merge Conflicts section",
+ "mtn: renaming 'dir2/file_10' from left to 'file_10'",
+ "mtn: dropping 'dir2/file_11' from left",
+ "mtn: renaming 'dir2/file_9' from left to 'file_9'",
+ "mtn: history for 'dir2/file_9' from left will be lost; see user manual Merge Conflicts section",
"mtn: [merged] 5cafe5405ed31c81f9061be62e38f25aeaaea9c5"}))
-
--- A special case; drop then re-add vs modify. This used to be the test
+
+check(mtn("update"), 0, nil, true)
+
+-- Test recreated; 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") -- modify in left; drop, add in right
-addfile("file_11", "file_11 base") -- drop, add in left; modify in right
+addfile("file_12", "file_12 base") -- modify in left; drop, add in right: keep left, drop right
+addfile("file_13", "file_13 base") -- drop, add in left; modify in right: user left, user_rename right
+
+-- Other cases not covered above
+addfile("file_14", "file_14 base") -- modify in left; recreated in right: rename left, keep right
+addfile("file_15", "file_15 base") -- modify in left; recreated in right: user_rename left, rename right
+addfile("file_16", "file_16 base") -- recreated in left; modify in right: drop left, rename right
+addfile("file_17", "file_17 base") -- recreated in left; modify in right: rename left, drop right
+addfile("file_18", "file_18 base") -- recreated in left; modify in right: user_rename left, drop right
commit("testbranch", "base 4")
base_4 = base_revision()
-writefile("file_10", "file_10 left")
+writefile("file_12", "file_12 left")
+check(mtn("drop", "file_13"), 0, false, false)
-check(mtn("drop", "file_11"), 0, false, false)
+writefile("file_14", "file_14 left")
+writefile("file_15", "file_15 left")
+
+check(mtn("drop", "file_16"), 0, false, false)
+check(mtn("drop", "file_17"), 0, false, false)
+check(mtn("drop", "file_18"), 0, false, false)
commit("testbranch", "left 4a")
-addfile("file_11", "file_11 left re-add")
+addfile("file_13", "file_13 left re-add")
+addfile("file_16", "file_16 left re-add")
+addfile("file_17", "file_17 left re-add")
+addfile("file_18", "file_18 left re-add")
commit("testbranch", "left 4b")
left_4 = base_revision()
revert_to(base_4)
-check(mtn("drop", "file_10"), 0, false, false)
-writefile("file_11", "file_11 right")
+check(mtn("drop", "file_12"), 0, false, false)
+writefile("file_13", "file_13 right")
+check(mtn("drop", "file_14"), 0, false, false)
+check(mtn("drop", "file_15"), 0, false, false)
+writefile("file_16", "file_16 right")
+writefile("file_17", "file_17 right")
+writefile("file_18", "file_18 right")
commit("testbranch", "right 4a")
-addfile("file_10", "file_10 right re-add")
+addfile("file_12", "file_12 right re-add")
+addfile("file_14", "file_14 right re-add")
+addfile("file_15", "file_15 right re-add")
commit("testbranch", "right 4b")
right_4 = base_revision()
check(mtn("show_conflicts", left_4, right_4), 0, nil, true)
check(samelines("stderr",
-{"mtn: [left] 9485fe891d5e23d6dc30140228cd02840ee719e9",
- "mtn: [right] 9a8192d3bf263cbd5782791e823b837d42af6902",
- "mtn: [ancestor] 209e4118bda3960b2f83e48b2368e981ab748ee5",
- "mtn: conflict: file 'file_10' from revision 209e4118bda3960b2f83e48b2368e981ab748ee5",
- "mtn: modified on the left, named file_10",
+{"mtn: [left] " .. left_4,
+ "mtn: [right] " .. right_4,
+ "mtn: [ancestor] " .. base_4,
+ "mtn: conflict: file 'file_12'",
+ "mtn: modified on the left, named file_12",
"mtn: dropped and recreated on the right",
- "mtn: conflict: file 'file_11' from revision 209e4118bda3960b2f83e48b2368e981ab748ee5",
+ "mtn: conflict: file 'file_13'",
"mtn: dropped and recreated on the left",
- "mtn: modified on the right, named file_11",
- "mtn: 2 conflicts with supported resolutions."}))
+ "mtn: modified on the right, named file_13",
+ "mtn: conflict: file 'file_14'",
+ "mtn: modified on the left, named file_14",
+ "mtn: dropped and recreated on the right",
+ "mtn: conflict: file 'file_15'",
+ "mtn: modified on the left, named file_15",
+ "mtn: dropped and recreated on the right",
+ "mtn: conflict: file 'file_16'",
+ "mtn: dropped and recreated on the left",
+ "mtn: modified on the right, named file_16",
+ "mtn: conflict: file 'file_17'",
+ "mtn: dropped and recreated on the left",
+ "mtn: modified on the right, named file_17",
+ "mtn: conflict: file 'file_18'",
+ "mtn: dropped and recreated on the left",
+ "mtn: modified on the right, named file_18",
+ "mtn: 7 conflicts with supported resolutions."}))
check(mtn("conflicts", "store", left_4, right_4), 0, nil, true)
check(samefilestd("conflicts-recreated", "_MTN/conflicts"))
--- drop is not a valid resolution in this case
check(mtn("conflicts", "show_first"), 0, nil, true)
check(samelines("stderr",
-{"mtn: conflict: file 'file_10'",
+{"mtn: conflict: file 'file_12'",
"mtn: modified on the left",
"mtn: dropped and recreated on the right",
"mtn: possible resolutions:",
- "mtn: resolve_first keep",
- "mtn: resolve_first user \"name\""}))
+ "mtn: resolve_first_left drop",
+ "mtn: resolve_first_left rename",
+ "mtn: resolve_first_left user_rename \"new_content_name\" \"new_file_name\"",
+ "mtn: resolve_first_left keep",
+ "mtn: resolve_first_left user \"name\"",
+ "mtn: resolve_first_right drop",
+ "mtn: resolve_first_right rename",
+ "mtn: resolve_first_right user_rename \"new_content_name\" \"new_file_name\"",
+ "mtn: resolve_first_right keep",
+ "mtn: resolve_first_right user \"name\""}))
+-- need to specify both left and right resolutions
check(mtn("conflicts", "resolve_first", "drop"), 1, nil, true)
-check(samelines("stderr", {"mtn: misuse: recreated files may not be dropped"}))
+check(samelines("stderr",
+{"mtn: misuse: must specify 'resolve_first_left' or 'resolve_first_right' (not just 'resolve_first')"}))
-check(mtn("conflicts", "resolve_first", "keep"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_left", "keep"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
check(mtn("conflicts", "show_first"), 0, nil, true)
-check(samelines("stderr",
-{"mtn: conflict: file 'file_11'",
- "mtn: dropped and recreated on the left",
- "mtn: modified on the right",
- "mtn: possible resolutions:",
- "mtn: resolve_first keep",
- "mtn: resolve_first user \"name\""}))
+qgrep("mtn: conflict: file 'file_13'", "stderr")
+qgrep("mtn: dropped and recreated on the left", "stderr")
+qgrep("mtn: modified on the right", "stderr")
mkdir("_MTN")
mkdir("_MTN/resolutions")
-writefile("_MTN/resolutions/file_11", "file_11 user")
-check(mtn("conflicts", "resolve_first", "user", "_MTN/resolutions/file_11"), 0, nil, nil)
+writefile("_MTN/resolutions/file_13", "file_13 user")
+check(mtn("conflicts", "resolve_first_left", "user", "_MTN/resolutions/file_13"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_left", "rename", "file_14_renamed"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "keep"), 0, nil, nil)
+
+writefile("_MTN/resolutions/file_15_left", "file_15 user left")
+check(mtn("conflicts", "resolve_first_left", "user_rename", "_MTN/resolutions/file_15_left", "file_15_renamed_left"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "rename", "file_15_renamed_right"), 0, nil, nil)
+
+check(mtn("conflicts", "resolve_first_left", "drop"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "rename", "file_16_renamed"), 0, nil, nil)
+
+check(mtn("conflicts", "resolve_first_left", "rename", "file_17_renamed"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
+
+mkdir("_MTN")
+mkdir("_MTN/resolutions")
+writefile("_MTN/resolutions/file_18", "file_18 user")
+check(mtn("conflicts", "resolve_first_left", "user_rename", "_MTN/resolutions/file_18", "file_18_renamed"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
+
check(samefilestd("conflicts-recreated-resolved", "_MTN/conflicts"))
check(mtn("explicit_merge", "--resolve-conflicts", left_4, right_4, "testbranch"), 0, nil, true)
check(samelines("stderr",
-{"mtn: [left] 9485fe891d5e23d6dc30140228cd02840ee719e9",
- "mtn: [right] 9a8192d3bf263cbd5782791e823b837d42af6902",
- "mtn: keeping 'file_10' from left",
- "mtn: history for 'file_10' will be lost; see user manual Merge Conflicts section",
- "mtn: replacing content of 'file_11' with '_MTN/resolutions/file_11'",
- "mtn: history for 'file_11' will be lost; see user manual Merge Conflicts section",
- "mtn: [merged] 306eb31064512a8a2f4d316ff7a7ec32a1f64f4c"}))
+{"mtn: [left] " .. left_4,
+ "mtn: [right] " .. right_4,
+ "mtn: keeping 'file_12' from left",
+ "mtn: history for 'file_12' from left will be lost; see user manual Merge Conflicts section",
+ "mtn: dropping 'file_12' from right",
+ "mtn: replacing content of 'file_13' from left with '_MTN/resolutions/file_13'",
+ "mtn: dropping 'file_13' from right",
+ "mtn: renaming 'file_14' from left to 'file_14_renamed'",
+ "mtn: history for 'file_14' from left will be lost; see user manual Merge Conflicts section",
+ "mtn: keeping 'file_14' from right",
+ "mtn: replacing content of 'file_15' from left with '_MTN/resolutions/file_15_left'",
+ "mtn: history for 'file_15' from left will be lost; see user manual Merge Conflicts section",
+ "mtn: renaming 'file_15' from left to 'file_15_renamed_left'",
+ "mtn: renaming 'file_15' from right to 'file_15_renamed_right'",
+ "mtn: dropping 'file_16' from left",
+ "mtn: renaming 'file_16' from right to 'file_16_renamed'",
+ "mtn: history for 'file_16' from right will be lost; see user manual Merge Conflicts section",
+ "mtn: renaming 'file_17' from left to 'file_17_renamed'",
+ "mtn: dropping 'file_17' from right",
+ "mtn: replacing content of 'file_18' from left with '_MTN/resolutions/file_18'",
+ "mtn: renaming 'file_18' from left to 'file_18_renamed'",
+ "mtn: dropping 'file_18' from right",
+ "mtn: [merged] c6d6dba528110b6aa32572f6939982a1d56b17e0"}))
check(mtn("update"), 0, nil, true)
-check(samelines("file_10", {"file_10 left"}))
+check(samelines("file_12", {"file_12 left"}))
+check(samelines("file_13", {"file_13 user"}))
+check(samelines("file_14_renamed", {"file_14 left"}))
+check(samelines("file_14", {"file_14 right re-add"}))
+check(samelines("file_15_renamed_left", {"file_15 user left"}))
+check(samelines("file_15_renamed_right", {"file_15 right re-add"}))
+check(samelines("file_16_renamed", {"file_16 right"}))
+check(samelines("file_17_renamed", {"file_17 left re-add"}))
+check(samelines("file_18_renamed", {"file_18 user"}))
-- end of file
============================================================
--- test/func/resolve_conflicts_dropped_modified/conflicts-recreated 26f633aeeee82440eea41f8e1747f2c4262ce9bb
+++ test/func/resolve_conflicts_dropped_modified_1/conflicts-recreated 3f43d9d13d0149e3be0fa3a7a8695182dbc871ea
@@ -1,23 +1,73 @@
- left [9485fe891d5e23d6dc30140228cd02840ee719e9]
- right [9a8192d3bf263cbd5782791e823b837d42af6902]
-ancestor [209e4118bda3960b2f83e48b2368e981ab748ee5]
+ left [3721cc38b4f98b571d92bd38b2e269f438ed0af8]
+ right [ad9ca7cb1f77fe829269d4ac18763bfb9683a4b0]
+ancestor [a2b0bdd41b1b94e6e580c81c9901af128d299a7f]
conflict dropped_modified
- ancestor_name "file_10"
-ancestor_file_id [7368a4340573dca149c05db6f49638fafee766d0]
+ ancestor_name "file_12"
+ancestor_file_id [ec21b6df4e9613a1de985ab44f073a78b1f0b0c1]
left_type "modified file"
- left_name "file_10"
- left_file_id [080c590e6e671b1b9ca0e752e1bc468c5167e2a9]
+ left_name "file_12"
+ left_file_id [831efe7eb30ab2dfecc3b3d9e5b68f4d8d8978ca]
right_type "recreated file"
- right_name "file_10"
- right_file_id [59db7ed2afabb782b5a0215d825a86271eb96b8d]
+ right_name "file_12"
+ right_file_id [33f2071587733c13912824370e1ae0e3aa2a296c]
conflict dropped_modified
- ancestor_name "file_11"
-ancestor_file_id [498b49fddbd0418f62eb19d2096de816f3e34116]
+ ancestor_name "file_13"
+ancestor_file_id [833044cd7f5458fe436ddb0058dd9cde0e715715]
left_type "recreated file"
- left_name "file_11"
- left_file_id [bbf158a696465c2feb9ea22fac35ff7088f07ba0]
+ left_name "file_13"
+ left_file_id [c43d02936229a95d852d699ffb14ee8f02ad5311]
right_type "modified file"
- right_name "file_11"
- right_file_id [935f9a7af1da88e7fe541690076c48bac2108052]
+ right_name "file_13"
+ right_file_id [6aaa91015c6fc3b0dc8eeccf2aa22c52fe8dba2a]
+
+ conflict dropped_modified
+ ancestor_name "file_14"
+ancestor_file_id [0e462cd7a936807265ce7c01ce040b79aa2fa4d1]
+ left_type "modified file"
+ left_name "file_14"
+ left_file_id [442ddb4cae7d5cde84983dd60597c966e87645ea]
+ right_type "recreated file"
+ right_name "file_14"
+ right_file_id [963b47ce0f243cbd38b1ae288e6c6d559006ba6b]
+
+ conflict dropped_modified
+ ancestor_name "file_15"
+ancestor_file_id [13afe431eae6774a3b14ce8a2a6c2583ba375383]
+ left_type "modified file"
+ left_name "file_15"
+ left_file_id [8c1962f213226e85231b7b91b1a368f8e2ad8bf4]
+ right_type "recreated file"
+ right_name "file_15"
+ right_file_id [4d28d9df37261e18c1c23108c2ab531b8e535193]
+
+ conflict dropped_modified
+ ancestor_name "file_16"
+ancestor_file_id [b7de9cb0feb57657abcc6a991fdc7d034bfe2e66]
+ left_type "recreated file"
+ left_name "file_16"
+ left_file_id [7a8bca4a66301d480279b187927dcacba4da9f39]
+ right_type "modified file"
+ right_name "file_16"
+ right_file_id [e9d80dfb12b60107455fdf42fcc6beecb33fa7bd]
+
+ conflict dropped_modified
+ ancestor_name "file_17"
+ancestor_file_id [36158b32ea4ca5cbeba77374c9f407adeee91930]
+ left_type "recreated file"
+ left_name "file_17"
+ left_file_id [b5143f8996e5383113d406f263896a75f211e208]
+ right_type "modified file"
+ right_name "file_17"
+ right_file_id [5b5069994101a5bd4f35c9a9eaaf78abdf8e52ee]
+
+ conflict dropped_modified
+ ancestor_name "file_18"
+ancestor_file_id [4d70c0b068124556ad0e2d4f17b2d5994eaf01f5]
+ left_type "recreated file"
+ left_name "file_18"
+ left_file_id [3c2034c53b1882fd16fd943c80a93074932fc220]
+ right_type "modified file"
+ right_name "file_18"
+ right_file_id [c7ef23c4c1ad7b8c977a1caeb9a5830fd1fa1ae7]
============================================================
--- test/func/resolve_conflicts_dropped_modified/conflicts-recreated-resolved 5082532e55e68bc93610d1e8936fe790bb048d3d
+++ test/func/resolve_conflicts_dropped_modified_1/conflicts-recreated-resolved 7937832db9408aeadbbeed472d86f29ef3394a06
@@ -1,25 +1,89 @@
- left [9485fe891d5e23d6dc30140228cd02840ee719e9]
- right [9a8192d3bf263cbd5782791e823b837d42af6902]
-ancestor [209e4118bda3960b2f83e48b2368e981ab748ee5]
+ left [3721cc38b4f98b571d92bd38b2e269f438ed0af8]
+ right [ad9ca7cb1f77fe829269d4ac18763bfb9683a4b0]
+ancestor [a2b0bdd41b1b94e6e580c81c9901af128d299a7f]
- conflict dropped_modified
- ancestor_name "file_10"
- ancestor_file_id [7368a4340573dca149c05db6f49638fafee766d0]
- left_type "modified file"
- left_name "file_10"
- left_file_id [080c590e6e671b1b9ca0e752e1bc468c5167e2a9]
- right_type "recreated file"
- right_name "file_10"
- right_file_id [59db7ed2afabb782b5a0215d825a86271eb96b8d]
-resolved_keep_left
+ conflict dropped_modified
+ ancestor_name "file_12"
+ ancestor_file_id [ec21b6df4e9613a1de985ab44f073a78b1f0b0c1]
+ left_type "modified file"
+ left_name "file_12"
+ left_file_id [831efe7eb30ab2dfecc3b3d9e5b68f4d8d8978ca]
+ right_type "recreated file"
+ right_name "file_12"
+ right_file_id [33f2071587733c13912824370e1ae0e3aa2a296c]
+ resolved_keep_left
+resolved_drop_right
- conflict dropped_modified
- ancestor_name "file_11"
- ancestor_file_id [498b49fddbd0418f62eb19d2096de816f3e34116]
- left_type "recreated file"
- left_name "file_11"
- left_file_id [bbf158a696465c2feb9ea22fac35ff7088f07ba0]
- right_type "modified file"
- right_name "file_11"
- right_file_id [935f9a7af1da88e7fe541690076c48bac2108052]
-resolved_user_left "_MTN/resolutions/file_11"
+ conflict dropped_modified
+ ancestor_name "file_13"
+ ancestor_file_id [833044cd7f5458fe436ddb0058dd9cde0e715715]
+ left_type "recreated file"
+ left_name "file_13"
+ left_file_id [c43d02936229a95d852d699ffb14ee8f02ad5311]
+ right_type "modified file"
+ right_name "file_13"
+ right_file_id [6aaa91015c6fc3b0dc8eeccf2aa22c52fe8dba2a]
+ resolved_user_left "_MTN/resolutions/file_13"
+resolved_drop_right
+
+ conflict dropped_modified
+ ancestor_name "file_14"
+ ancestor_file_id [0e462cd7a936807265ce7c01ce040b79aa2fa4d1]
+ left_type "modified file"
+ left_name "file_14"
+ left_file_id [442ddb4cae7d5cde84983dd60597c966e87645ea]
+ right_type "recreated file"
+ right_name "file_14"
+ right_file_id [963b47ce0f243cbd38b1ae288e6c6d559006ba6b]
+resolved_rename_left "file_14_renamed"
+ resolved_keep_right
+
+ conflict dropped_modified
+ ancestor_name "file_15"
+ ancestor_file_id [13afe431eae6774a3b14ce8a2a6c2583ba375383]
+ left_type "modified file"
+ left_name "file_15"
+ left_file_id [8c1962f213226e85231b7b91b1a368f8e2ad8bf4]
+ right_type "recreated file"
+ right_name "file_15"
+ right_file_id [4d28d9df37261e18c1c23108c2ab531b8e535193]
+ resolved_user_left "_MTN/resolutions/file_15_left"
+ resolved_rename_left "file_15_renamed_left"
+resolved_rename_right "file_15_renamed_right"
+
+ conflict dropped_modified
+ ancestor_name "file_16"
+ ancestor_file_id [b7de9cb0feb57657abcc6a991fdc7d034bfe2e66]
+ left_type "recreated file"
+ left_name "file_16"
+ left_file_id [7a8bca4a66301d480279b187927dcacba4da9f39]
+ right_type "modified file"
+ right_name "file_16"
+ right_file_id [e9d80dfb12b60107455fdf42fcc6beecb33fa7bd]
+ resolved_drop_left
+resolved_rename_right "file_16_renamed"
+
+ conflict dropped_modified
+ ancestor_name "file_17"
+ ancestor_file_id [36158b32ea4ca5cbeba77374c9f407adeee91930]
+ left_type "recreated file"
+ left_name "file_17"
+ left_file_id [b5143f8996e5383113d406f263896a75f211e208]
+ right_type "modified file"
+ right_name "file_17"
+ right_file_id [5b5069994101a5bd4f35c9a9eaaf78abdf8e52ee]
+resolved_rename_left "file_17_renamed"
+ resolved_drop_right
+
+ conflict dropped_modified
+ ancestor_name "file_18"
+ ancestor_file_id [4d70c0b068124556ad0e2d4f17b2d5994eaf01f5]
+ left_type "recreated file"
+ left_name "file_18"
+ left_file_id [3c2034c53b1882fd16fd943c80a93074932fc220]
+ right_type "modified file"
+ right_name "file_18"
+ right_file_id [c7ef23c4c1ad7b8c977a1caeb9a5830fd1fa1ae7]
+ resolved_user_left "_MTN/resolutions/file_18"
+resolved_rename_left "file_18_renamed"
+ resolved_drop_right
============================================================
--- test/func/resolve_conflicts_dropped_modified/conflicts-resolved dd892da237ef4f3a0ee30fa3989374a65d092d68
+++ test/func/resolve_conflicts_dropped_modified_1/conflicts-resolved b2fe24f2d19a8d539c0c89c305a7b58a36ead63e
@@ -14,17 +14,17 @@ resolved_drop_left
right_file_id [4fd0fa24812427ee6c13a839d2a90bc0c6fc0091]
resolved_drop_left
- conflict dropped_modified
- ancestor_name "file_3"
- ancestor_file_id [311aac8e6f1fb6fca84da5153aa6d5a1c6faff79]
- left_type "dropped file"
- left_rev [c2fe3623ce72d248154425dc7db2ddcc397c9aca]
- left_name "file_3"
- left_file_id [311aac8e6f1fb6fca84da5153aa6d5a1c6faff79]
- right_type "modified file"
- right_name "file_3_renamed"
- right_file_id [da7ea65160c9c92f4ed120568229342fe7daa924]
-resolved_drop_left
+ conflict dropped_modified
+ ancestor_name "file_3"
+ ancestor_file_id [311aac8e6f1fb6fca84da5153aa6d5a1c6faff79]
+ left_type "dropped file"
+ left_rev [c2fe3623ce72d248154425dc7db2ddcc397c9aca]
+ left_name "file_3"
+ left_file_id [311aac8e6f1fb6fca84da5153aa6d5a1c6faff79]
+ right_type "modified file"
+ right_name "file_3_renamed"
+ right_file_id [da7ea65160c9c92f4ed120568229342fe7daa924]
+resolved_drop_right
conflict dropped_modified
ancestor_name "file_4"
@@ -38,17 +38,17 @@ resolved_keep_left
right_file_id [259dbd8291bd18ba3fdb9adb3776eb26f94b1230]
resolved_keep_left
- conflict dropped_modified
- ancestor_name "file_5"
- ancestor_file_id [d141bda733292622ebce4c231cbb0da44ac59f40]
- left_type "dropped file"
- left_rev [b0d6953684d49dd6bd345c312d6a0c8fed3078ce]
- left_name "file_5_renamed"
- left_file_id [420cde699a422f7c3d2c8951c46ddfd546db66c0]
- right_type "modified file"
- right_name "file_5"
- right_file_id [e7eb31ab48c2e42126f44ef78ffdb27f388333b0]
-resolved_keep_left
+ conflict dropped_modified
+ ancestor_name "file_5"
+ ancestor_file_id [d141bda733292622ebce4c231cbb0da44ac59f40]
+ left_type "dropped file"
+ left_rev [b0d6953684d49dd6bd345c312d6a0c8fed3078ce]
+ left_name "file_5_renamed"
+ left_file_id [420cde699a422f7c3d2c8951c46ddfd546db66c0]
+ right_type "modified file"
+ right_name "file_5"
+ right_file_id [e7eb31ab48c2e42126f44ef78ffdb27f388333b0]
+resolved_keep_right
conflict dropped_modified
ancestor_name "file_6"
@@ -62,14 +62,14 @@ resolved_user_left "_MTN/resolutions/fil
right_file_id [d5531643d3b5aee3e10eceabbdfecf167148a2d9]
resolved_user_left "_MTN/resolutions/file_6_resolved"
- conflict dropped_modified
- ancestor_name "file_7"
- ancestor_file_id [1a9d3059360fd5f04d0cec05875c8e376da0eaef]
- left_type "dropped file"
- left_rev [c2fe3623ce72d248154425dc7db2ddcc397c9aca]
- left_name "file_7"
- left_file_id [1a9d3059360fd5f04d0cec05875c8e376da0eaef]
- right_type "modified file"
- right_name "file_7_renamed"
- right_file_id [9b362e2754ea1f943497d5a31de3899271ee5a8b]
-resolved_user_left "_MTN/resolutions/file_7_resolved"
+ conflict dropped_modified
+ ancestor_name "file_7"
+ ancestor_file_id [1a9d3059360fd5f04d0cec05875c8e376da0eaef]
+ left_type "dropped file"
+ left_rev [c2fe3623ce72d248154425dc7db2ddcc397c9aca]
+ left_name "file_7"
+ left_file_id [1a9d3059360fd5f04d0cec05875c8e376da0eaef]
+ right_type "modified file"
+ right_name "file_7_renamed"
+ right_file_id [9b362e2754ea1f943497d5a31de3899271ee5a8b]
+resolved_user_right "_MTN/resolutions/file_7_resolved"
============================================================
--- test/func/resolve_conflicts_dropped_modified/show_conflicts 74f0f311dee5ce970396bed354b6ab0fd97077f0
+++ test/func/resolve_conflicts_dropped_modified_1/show_conflicts cce385ec522c8e4885cac7d3375896aaa507f0e0
@@ -1,22 +1,22 @@ mtn: [ancestor] c2fe3623ce72d248154425dc
mtn: [left] 7b2ef4343b0717bcd122498a1a0b7ff7acffb64c
mtn: [right] ca7922b510f9daf5c4b28c6788315ee82eb9a7f0
mtn: [ancestor] c2fe3623ce72d248154425dc7db2ddcc397c9aca
-mtn: conflict: file 'file_2' from revision c2fe3623ce72d248154425dc7db2ddcc397c9aca
+mtn: conflict: file 'file_2'
mtn: modified on the left, named file_2_renamed
mtn: dropped on the right
-mtn: conflict: file 'file_3' from revision c2fe3623ce72d248154425dc7db2ddcc397c9aca
+mtn: conflict: file 'file_3'
mtn: dropped on the left
mtn: modified on the right, named file_3_renamed
-mtn: conflict: file 'file_4' from revision c2fe3623ce72d248154425dc7db2ddcc397c9aca
+mtn: conflict: file 'file_4'
mtn: modified on the left, named file_4
mtn: dropped on the right
-mtn: conflict: file 'file_5' from revision c2fe3623ce72d248154425dc7db2ddcc397c9aca
+mtn: conflict: file 'file_5'
mtn: dropped on the left
mtn: modified on the right, named file_5
-mtn: conflict: file 'file_6' from revision c2fe3623ce72d248154425dc7db2ddcc397c9aca
+mtn: conflict: file 'file_6'
mtn: modified on the left, named file_6_renamed
mtn: dropped on the right
-mtn: conflict: file 'file_7' from revision c2fe3623ce72d248154425dc7db2ddcc397c9aca
+mtn: conflict: file 'file_7'
mtn: dropped on the left
mtn: modified on the right, named file_7_renamed
mtn: 6 conflicts with supported resolutions.
============================================================
--- test/func/resolve_conflicts_dropped_modified/show_conflicts-orphaned fbe2c5cc2c59c6fec1121e3be9469d370b9ed5cb
+++ test/func/resolve_conflicts_dropped_modified_1/show_conflicts-orphaned e343653ac3989164acb2dbb54f3f97b035d28de6
@@ -1,13 +1,13 @@ mtn: [ancestor] 44c4d408ecf65b6b45fa2c6f
mtn: [left] 4228fbd8003cdd89e7eea51fcef10c3f91d78f69
mtn: [right] 6cb6438a490a1ad4c69ff6cac23c75a903cd9cfd
mtn: [ancestor] 44c4d408ecf65b6b45fa2c6fa2a51e5b7485d8e1
-mtn: conflict: file 'dir2/file_10' from revision 44c4d408ecf65b6b45fa2c6fa2a51e5b7485d8e1
+mtn: conflict: file 'dir2/file_10'
mtn: modified on the left, named dir2/file_10
mtn: orphaned on the right
-mtn: conflict: file 'dir2/file_11' from revision 44c4d408ecf65b6b45fa2c6fa2a51e5b7485d8e1
+mtn: conflict: file 'dir2/file_11'
mtn: modified on the left, named dir2/file_11
mtn: orphaned on the right
-mtn: conflict: file 'dir2/file_9' from revision 44c4d408ecf65b6b45fa2c6fa2a51e5b7485d8e1
+mtn: conflict: file 'dir2/file_9'
mtn: modified on the left, named dir2/file_9
mtn: orphaned on the right
mtn: 3 conflicts with supported resolutions.
============================================================
--- test/func/resolve_conflicts_dropped_modified_2/__driver__.lua e1bd2fed5032ea4cb911ffc1289b1830e2195e1c
+++ test/func/resolve_conflicts_dropped_modified_2/__driver__.lua 81b11d9ab24ad470156b95e8be8efd9dc1645156
@@ -34,7 +34,7 @@ check(samelines("stderr",
{"mtn: [left] 506d8ed51b06c0080e8bb307155a88637045b532",
"mtn: [right] a2889488ed1801a904d0219ec9939dfc2e9be033",
"mtn: [ancestor] f80ff103551d0313647d6c84990bc9db6b158dac",
- "mtn: conflict: file 'file_2' from revision f80ff103551d0313647d6c84990bc9db6b158dac",
+ "mtn: conflict: file 'file_2'",
"mtn: modified on the left, named file_2",
"mtn: dropped on the right",
"mtn: 1 conflict with supported resolutions."}))
@@ -47,8 +47,8 @@ check(samelines("stderr",
check(samelines("stderr",
{"mtn: [left] 506d8ed51b06c0080e8bb307155a88637045b532",
"mtn: [right] a2889488ed1801a904d0219ec9939dfc2e9be033",
- "mtn: keeping 'file_2'",
- "mtn: history for 'file_2' will be lost; see user manual Merge Conflicts section",
+ "mtn: keeping 'file_2' from left",
+ "mtn: history for 'file_2' from left will be lost; see user manual Merge Conflicts section",
"mtn: [merged] 3df3126220588440def7b08f488ca35eaa94f1b6"}))
check(mtn("update"), 0, nil, true)
@@ -69,17 +69,19 @@ check(samelines("stderr",
{"mtn: [left] 5a144a43f03692e389f3ddd4c510a4d9754061d5",
"mtn: [right] 3df3126220588440def7b08f488ca35eaa94f1b6",
"mtn: [ancestor] 506d8ed51b06c0080e8bb307155a88637045b532",
- "mtn: conflict: file 'file_2' from revision 506d8ed51b06c0080e8bb307155a88637045b532",
+ "mtn: conflict: file 'file_2'",
"mtn: modified on the left, named file_2",
"mtn: dropped and recreated on the right",
"mtn: 1 conflict with supported resolutions."}))
check(mtn("conflicts", "store", left_2, right_2), 0, nil, true)
-check(mtn("conflicts", "resolve_first", "keep"), 0, nil, true)
+check(mtn("conflicts", "resolve_first_left", "keep"), 0, nil, true)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, true)
check(mtn("explicit_merge", "--resolve-conflicts", left_2, right_2, "testbranch"), 0, nil, true)
check(qgrep("mtn: keeping 'file_2' from left", "stderr"))
+check(qgrep("mtn: dropping 'file_2' from right", "stderr"))
check(mtn("update"), 0, nil, true)
check(samelines("file_2", {"file_2 left 2"}))
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_3/__driver__.lua fd2a4dd0c38dff10bd3ff2f20e983f3f548b3d18
@@ -0,0 +1,276 @@
+-- Test enforcement of consistent resolutions for drop/modified conflicts.
+--
+-- Only invalid combinations are tested here (we verify a good error
+-- message); valid combinations are tested in
+-- resolve_conflicts_dropped_modified_1.
+--
+-- The left and right conflicts chosen by the user must be consistent;
+-- they must give different names for the two sides.
+--
+-- When one file is in the dropped state, only one resolution can be
+-- specified; that of the modified file.
+--
+-- Rename on both sides is valid, unless the user specifies the same
+-- new name for both; that is tested only once here.
+--
+-- The only inconsistent cases are between modified and recreated
+-- files. A recreated file is detected by having the same name as the
+-- modified file; if the modified file has also been renamed, the
+-- recreated file must have the same name as the renamed file. Thus we
+-- do not need to consider a renamed modified file as a separate case.
+--
+-- Orphaned file resolution cannot be keep or user; those error
+-- messages are tested in resolve_conflicts_dropped_modified_1.
+--
+-- We need to test all invalid combinations of left/right resolution:
+--
+-- left right
+-- state resolution state resolution file case
+-----------------------------------------------------------
+-- dropped - dropped - (not a conflict)
+-- - modified keep (valid)
+-- - modified rename (valid)
+-- - modified user (valid)
+-- - modified user_rename (valid)
+-- - recreated - (not a conflict)
+--
+-- modified drop dropped - (valid)
+-- keep dropped - (valid)
+-- rename dropped - (valid)
+-- user dropped - (valid)
+-- user_rename dropped - (valid)
+--
+-- modified - modified - (file content conflict)
+-- drop recreated drop (valid)
+-- drop recreated keep (valid)
+-- drop recreated rename (valid)
+-- drop recreated user (valid)
+-- drop recreated user_rename (valid)
+-- keep recreated drop (valid)
+-- keep recreated keep file_2 1
+-- keep recreated rename (valid)
+-- keep recreated user file_2 2
+-- keep recreated user_rename (valid)
+-- rename recreated drop (valid)
+-- rename recreated keep (valid)
+-- rename recreated rename (valid)
+-- rename recreated user (valid)
+-- rename recreated user_rename (valid)
+-- user recreated drop (valid)
+-- user recreated keep file_4 3
+-- user recreated rename (valid)
+-- user recreated user file_4 4
+-- user recreated user_rename (valid)
+-- user_rename recreated drop (valid)
+-- user_rename recreated keep (valid)
+-- user_rename recreated rename (valid)
+-- user_rename recreated user (valid)
+-- user_rename recreated user_rename (valid)
+--
+-- recreated drop dropped - (valid)
+-- keep dropped - (valid)
+-- rename dropped - (valid)
+-- user dropped - (valid)
+-- user_rename dropped - (valid)
+-- drop modified drop (valid)
+-- drop modified keep (valid)
+-- drop modified rename (valid)
+-- drop modified user (valid)
+-- drop modified user_rename (valid)
+-- keep modified drop (valid)
+-- keep modified keep file_3 5
+-- keep modified rename (valid)
+-- keep modified user file_3 6
+-- keep modified user_rename (valid)
+-- rename modified drop (valid)
+-- rename modified keep (valid)
+-- rename modified rename (valid)
+-- rename modified user (valid)
+-- rename modified user_rename (valid)
+-- user modified drop (valid)
+-- user modified keep file_3 7
+-- user modified rename (valid)
+-- user modified user file_3 8
+-- user modified user_rename (valid)
+-- user_rename modified drop (valid)
+-- user_rename modified keep (valid)
+-- user_rename modified rename (valid)
+-- user_rename modified user (valid)
+-- user_rename modified user_rename (valid)
+
+mtn_setup()
+
+-- Create the test files
+
+addfile("file_2", "file_2 base") -- modified left, recreated right
+addfile("file_3", "file_3 base") -- recreated left, modified right
+commit("testbranch", "base")
+base = base_revision()
+
+writefile("file_2", "file_2 left")
+check(mtn("drop", "file_3"), 0, false, false)
+commit("testbranch", "left 1a")
+
+addfile("file_3", "file_3 left recreated")
+commit("testbranch", "left 1b")
+left_1 = base_revision()
+
+revert_to(base)
+
+check(mtn("drop", "file_2"), 0, false, false)
+writefile("file_3", "file_3 right")
+commit("testbranch", "right 1a")
+
+addfile("file_2", "file_2 right recreated")
+commit("testbranch", "right 1b")
+right_1 = base_revision()
+
+-- Store and show inconsistency error messages
+check(mtn("conflicts", "store", left_1, right_1), 0, nil, true)
+check(samelines("stderr",
+{"mtn: 2 conflicts with supported resolutions.",
+ "mtn: stored in '_MTN/conflicts'"}))
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_2'",
+ "mtn: modified on the left",
+ "mtn: dropped and recreated on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_left drop",
+ "mtn: resolve_first_left rename",
+ "mtn: resolve_first_left user_rename \"new_content_name\" \"new_file_name\"",
+ "mtn: resolve_first_left keep",
+ "mtn: resolve_first_left user \"name\"",
+ "mtn: resolve_first_right drop",
+ "mtn: resolve_first_right rename",
+ "mtn: resolve_first_right user_rename \"new_content_name\" \"new_file_name\"",
+ "mtn: resolve_first_right keep",
+ "mtn: resolve_first_right user \"name\""}))
+
+-- case 1, 2; keep *
+check(mtn("conflicts", "resolve_first_left", "keep"), 0, nil, false)
+
+-- check that inconsistent resolutions for right are not displayed
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_2'",
+ "mtn: modified on the left",
+ "mtn: dropped and recreated on the right",
+ "mtn: left_resolution: keep",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_right drop",
+ "mtn: resolve_first_right rename",
+ "mtn: resolve_first_right user_rename \"new_content_name\" \"new_file_name\""}))
+
+-- check for errors from inconsistent resolutions
+
+-- case 1: keep, keep
+check(mtn("conflicts", "resolve_first_right", "keep"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is keep; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- case 2: keep, user
+check(mtn("conflicts", "resolve_first_right", "user", "_MTN/resolutions/file_2"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is keep; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- case 1, 2, but specify right resolution first
+check(mtn("conflicts", "store", left_1, right_1), 0, nil, true)
+check(mtn("conflicts", "resolve_first_right", "keep"), 0, nil, false)
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_2'",
+ "mtn: modified on the left",
+ "mtn: dropped and recreated on the right",
+ "mtn: right_resolution: keep",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_left drop",
+ "mtn: resolve_first_left rename",
+ "mtn: resolve_first_left user_rename \"new_content_name\" \"new_file_name\""}))
+check(mtn("conflicts", "resolve_first_left", "keep"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is keep; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- No error if specify right again, but it actually sets file_3 right resolution. so we have to reset
+check(mtn("conflicts", "store", left_1, right_1), 0, nil, true)
+check(mtn("conflicts", "resolve_first_right", "user", "_MTN/resolutions/file_2"), 0, nil, false)
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(qgrep("right_resolution: content_user, content: '_MTN/resolutions/file_2'", "stderr"))
+
+check(mtn("conflicts", "resolve_first_left", "keep"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is content_user; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- provide a valid resolution for file_2 so file_3 is first
+check(mtn("conflicts", "resolve_first_left", "drop"), 0, nil, nil)
+
+-- case 3, 4; user *
+check(mtn("conflicts", "resolve_first_left", "user", "_MTN/resolutions/file_3"), 0, nil, false)
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_3'",
+ "mtn: dropped and recreated on the left",
+ "mtn: modified on the right",
+ "mtn: left_resolution: content_user, content: '_MTN/resolutions/file_3'",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_right drop",
+ "mtn: resolve_first_right rename",
+ "mtn: resolve_first_right user_rename \"new_content_name\" \"new_file_name\""}))
+
+-- case 3: user, keep
+check(mtn("conflicts", "resolve_first_right", "keep"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is content_user; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- case 4: user, user
+check(mtn("conflicts", "resolve_first_right", "user", "_MTN/resolutions/file_3"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is content_user; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- specify right first
+check(mtn("conflicts", "store", left_1, right_1), 0, nil, true)
+-- resolve file_2
+check(mtn("conflicts", "resolve_first_left", "keep"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
+
+-- file_3
+check(mtn("conflicts", "resolve_first_right", "keep"), 0, nil, true)
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+{"mtn: conflict: file 'file_3'",
+ "mtn: dropped and recreated on the left",
+ "mtn: modified on the right",
+ "mtn: right_resolution: keep",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_left drop",
+ "mtn: resolve_first_left rename",
+ "mtn: resolve_first_left user_rename \"new_content_name\" \"new_file_name\""}))
+check(mtn("conflicts", "resolve_first_left", "user", "_MTN/resolutions/file_3"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is keep; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- reset for case 4 reversed
+check(mtn("conflicts", "store", left_1, right_1), 0, nil, true)
+-- resolve file_2
+check(mtn("conflicts", "resolve_first_left", "keep"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
+
+check(mtn("conflicts", "resolve_first_right", "user", "_MTN/resolutions/file_3"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_left", "user", "_MTN/resolutions/file_3"), 1, nil, true)
+check(samelines("stderr",
+{"mtn: misuse: other resolution is content_user; specify 'drop', 'rename', or 'user_rename'"}))
+
+-- Test error from user rename both sides to same new name. The error is at merge time.
+check(mtn("conflicts", "store", left_1, right_1), 0, nil, true)
+check(mtn("conflicts", "resolve_first_left", "rename", "file_2_renamed"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "rename", "file_2_renamed"), 0, nil, nil)
+-- file_3
+check(mtn("conflicts", "resolve_first_left", "drop"), 0, nil, nil)
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, nil)
+check(mtn("explicit_merge", "--resolve-conflicts", left_1, right_1, "testbranch"), 1, nil, true)
+check(qgrep("'file_2_renamed' already exists", "stderr"))
+
+-- end of file
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/__driver__.lua 80f056dd3773dab5d5019d78cbb0f7393d66bde3
@@ -0,0 +1,170 @@
+-- Show a problematic use case involving a dropped_modified conflict,
+-- and how it can be resolved with the 'mtn:resolve_conflict'
+-- attribute.
+--
+-- There is an upstream branch, and a local branch. The local branch
+-- adds a file that the upstream branch adopts. The next merge from
+-- upstream to local encounters a duplicate_name conflict; if we
+-- resolve that the wrong way (keep local instead of upstream), on the
+-- next merge we get a dropped_modified conflict.
+--
+-- In the meantime, we've edited the file locally, illustrating that
+-- the dropped_modified conflict code needs to search thru history for
+-- the rev last containing the dropped node id (this was a bug in an
+-- earlier implementation).
+
+mtn_setup()
+
+addfile("file_1", "file_1 base")
+commit("testbranch", "base")
+base = base_revision()
+
+writefile("file_1", "file_1 upstream 1")
+
+commit("testbranch", "upstream 1")
+upstream_1 = base_revision()
+
+revert_to(base)
+
+addfile("file_2", "file_2 local")
+
+commit("testbranch", "local 1")
+local_1 = base_revision()
+
+revert_to(upstream_1)
+
+addfile("file_2", "file_2 upstream 1")
+
+commit("testbranch", "upstream 2")
+upstream_2 = base_revision()
+
+check(mtn("show_conflicts", upstream_2, local_1), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: [left] 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: [right] 3cae692a68fa6710b1db5e73e3e876994c175925",
+ "mtn: [ancestor] 736498437fa91538540dc5fbad750cbc1472d793",
+ "mtn: conflict: duplicate name 'file_2' for the directory ''",
+ "mtn: added as a new file on the left",
+ "mtn: added as a new file on the right",
+ "mtn: 1 conflict with supported resolutions."}))
+
+check(mtn("conflicts", "store", upstream_2, local_1), 0, nil, true)
+
+-- We should keep upstream, and drop local, but we get it backwards
+check(mtn("conflicts", "resolve_first_left", "drop"), 0, nil, true)
+check(mtn("conflicts", "resolve_first_right", "keep"), 0, nil, true)
+
+check(mtn("explicit_merge", "--resolve-conflicts", upstream_2, local_1, "testbranch"), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: [left] 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: [right] 3cae692a68fa6710b1db5e73e3e876994c175925",
+ "mtn: dropping 'file_2'",
+ "mtn: keeping 'file_2'",
+ "mtn: [merged] fce2fe3c327a294209ad695e0658275f104fe12a"}))
+
+check(mtn("update"), 0, nil, true)
+
+-- One more local mod
+writefile("file_2", "file_2 local 2")
+commit("testbranch", "local 2")
+local_2 = base_revision()
+
+-- round 2; upstream modifies the file again, and we try to merge
+revert_to(upstream_2)
+
+writefile("file_2", "file_2 upstream 2")
+
+commit("testbranch", "upstream 3")
+upstream_3 = base_revision()
+
+check(mtn("show_conflicts", upstream_3, local_2), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: [left] 48b18ebc7b70733133539384e49a2eedb82e32b2",
+ "mtn: [right] 650057e8a81bd41991dc5ff10b2d60343f1032ae",
+ "mtn: [ancestor] 27d41ae9f2b3cb73b130d9845d77574a11021b17",
+ "mtn: conflict: file 'file_2'",
+ "mtn: modified on the left, named file_2",
+ "mtn: dropped and recreated on the right",
+ "mtn: 1 conflict with supported resolutions."}))
+
+-- There are two nodes with filename 'file_2'; node 4 in upstream,
+-- node 3 in local. At this point, node 4 is modified in upstream and
+-- dropped in local; node 3 is unborn in upstream and modified in
+-- local. Therefore this is a combination of dropped_modified and
+-- duplicate_name conflicts, which we handle as a dropped_modified
+-- conflict.
+check(mtn("conflicts", "store", upstream_3, local_2), 0, nil, true)
+check(samefilestd("conflicts_3_2", "_MTN/conflicts"))
+
+-- since we have a duplicate name conflict, we need to specify both
+-- right and left resolutions, so 'resolve_first' is wrong here
+check(mtn("conflicts", "resolve_first", "keep"), 1, nil, true)
+check(qgrep("must specify 'resolve_first_left' or 'resolve_first_right'", "stderr"))
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: conflict: file 'file_2'",
+ "mtn: modified on the left",
+ "mtn: dropped and recreated on the right",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_left drop",
+ "mtn: resolve_first_left rename",
+ "mtn: resolve_first_left user_rename \"new_content_name\" \"new_file_name\"",
+ "mtn: resolve_first_left keep",
+ "mtn: resolve_first_left user \"name\"",
+ "mtn: resolve_first_right drop",
+ "mtn: resolve_first_right rename",
+ "mtn: resolve_first_right user_rename \"new_content_name\" \"new_file_name\"",
+ "mtn: resolve_first_right keep",
+ "mtn: resolve_first_right user \"name\""}))
+
+-- We want to keep the upstream node to avoid future conflicts
+check(mtn("conflicts", "resolve_first_left", "keep"), 0, nil, true)
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: conflict: file 'file_2'",
+ "mtn: modified on the left",
+ "mtn: dropped and recreated on the right",
+ "mtn: left_resolution: keep",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_right drop",
+ "mtn: resolve_first_right rename",
+ "mtn: resolve_first_right user_rename \"new_content_name\" \"new_file_name\""}))
+
+check(mtn("conflicts", "resolve_first_right", "drop"), 0, nil, true)
+check(samefilestd("conflicts_3_2_resolved", "_MTN/conflicts"))
+
+check(mtn("explicit_merge", "--resolve-conflicts", upstream_3, local_2, "testbranch"), 0, nil, true)
+check(qgrep("mtn: dropping 'file_2'", "stderr"))
+check(qgrep("mtn: \\[merged\\] 864bfab34bcd301828a985f000c6f8ada712b0ca", "stderr")) -- for comparing with below
+
+check(mtn("update"), 0, nil, true)
+check(samelines("file_2", {"file_2 upstream 2"}))
+
+-- Repeat merge with left, right swapped, to test symmetry in code.
+check(mtn("conflicts", "store", local_2, upstream_3), 0, nil, true)
+check(samefilestd("conflicts_2_3", "_MTN/conflicts"))
+
+check(mtn("conflicts", "resolve_first_right", "keep"), 0, nil, true)
+
+check(mtn("conflicts", "show_first"), 0, nil, true)
+check(samelines("stderr",
+ {"mtn: conflict: file 'file_2'",
+ "mtn: dropped and recreated on the left",
+ "mtn: modified on the right",
+ "mtn: right_resolution: keep",
+ "mtn: possible resolutions:",
+ "mtn: resolve_first_left drop",
+ "mtn: resolve_first_left rename",
+ "mtn: resolve_first_left user_rename \"new_content_name\" \"new_file_name\""}))
+
+check(mtn("conflicts", "resolve_first_left", "drop"), 0, nil, true)
+check(samefilestd("conflicts_2_3_resolved", "_MTN/conflicts"))
+
+check(mtn("explicit_merge", "--resolve-conflicts", local_2, upstream_3, "testbranch"), 0, nil, true)
+check(qgrep("mtn: dropping 'file_2'", "stderr"))
+check(qgrep("mtn: \\[merged\\] 864bfab34bcd301828a985f000c6f8ada712b0ca", "stderr"))
+-- same revision as merge in other order
+
+-- end of file
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_2_3 1f257fa6e99abf93229af189109b9efe3cfae88f
@@ -0,0 +1,13 @@
+ left [650057e8a81bd41991dc5ff10b2d60343f1032ae]
+ right [48b18ebc7b70733133539384e49a2eedb82e32b2]
+ancestor [27d41ae9f2b3cb73b130d9845d77574a11021b17]
+
+ conflict dropped_modified
+ ancestor_name "file_2"
+ancestor_file_id [7fc990de4797bd6534a5c1deb344e11964f6b353]
+ left_type "recreated file"
+ left_name "file_2"
+ left_file_id [6e49d17f382dc2f03d495181490e7653f1a14ad9]
+ right_type "modified file"
+ right_name "file_2"
+ right_file_id [b7e3240a78dc6afce4507f5a18ab516963e72022]
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_2_3_resolved d8b9a96fdaf210a4d1bc495c62c3dcf40114d39e
@@ -0,0 +1,15 @@
+ left [650057e8a81bd41991dc5ff10b2d60343f1032ae]
+ right [48b18ebc7b70733133539384e49a2eedb82e32b2]
+ancestor [27d41ae9f2b3cb73b130d9845d77574a11021b17]
+
+ conflict dropped_modified
+ ancestor_name "file_2"
+ ancestor_file_id [7fc990de4797bd6534a5c1deb344e11964f6b353]
+ left_type "recreated file"
+ left_name "file_2"
+ left_file_id [6e49d17f382dc2f03d495181490e7653f1a14ad9]
+ right_type "modified file"
+ right_name "file_2"
+ right_file_id [b7e3240a78dc6afce4507f5a18ab516963e72022]
+ resolved_drop_left
+resolved_keep_right
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2 bb23f1fbf87e4f1dcb8aa7c4c3fcb90e1fc84fed
@@ -0,0 +1,13 @@
+ left [48b18ebc7b70733133539384e49a2eedb82e32b2]
+ right [650057e8a81bd41991dc5ff10b2d60343f1032ae]
+ancestor [27d41ae9f2b3cb73b130d9845d77574a11021b17]
+
+ conflict dropped_modified
+ ancestor_name "file_2"
+ancestor_file_id [7fc990de4797bd6534a5c1deb344e11964f6b353]
+ left_type "modified file"
+ left_name "file_2"
+ left_file_id [b7e3240a78dc6afce4507f5a18ab516963e72022]
+ right_type "recreated file"
+ right_name "file_2"
+ right_file_id [6e49d17f382dc2f03d495181490e7653f1a14ad9]
============================================================
--- /dev/null
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_2/conflicts_3_2_resolved 4482ad2e755308ce8a546191348cc648ad13d782
@@ -0,0 +1,15 @@
+ left [48b18ebc7b70733133539384e49a2eedb82e32b2]
+ right [650057e8a81bd41991dc5ff10b2d60343f1032ae]
+ancestor [27d41ae9f2b3cb73b130d9845d77574a11021b17]
+
+ conflict dropped_modified
+ ancestor_name "file_2"
+ ancestor_file_id [7fc990de4797bd6534a5c1deb344e11964f6b353]
+ left_type "modified file"
+ left_name "file_2"
+ left_file_id [b7e3240a78dc6afce4507f5a18ab516963e72022]
+ right_type "recreated file"
+ right_name "file_2"
+ right_file_id [6e49d17f382dc2f03d495181490e7653f1a14ad9]
+ resolved_keep_left
+resolved_drop_right
============================================================
--- test/func/resolve_conflicts_dropped_modified_upstream_vs_local/__driver__.lua e7f37ed8b1a65325390ad4f1ade33904e7535381
+++ test/func/resolve_conflicts_dropped_modified_upstream_vs_local_attr/__driver__.lua abe2836cc2dfbae368820e3b5515ad587911c71b
@@ -34,7 +34,7 @@ check(samelines("stderr",
{"mtn: [left] 1e700864de7a2cbb1cf85c26f5e1e4ca335d2bc2",
"mtn: [right] a2889488ed1801a904d0219ec9939dfc2e9be033",
"mtn: [ancestor] f80ff103551d0313647d6c84990bc9db6b158dac",
- "mtn: conflict: file 'file_2' from revision f80ff103551d0313647d6c84990bc9db6b158dac",
+ "mtn: conflict: file 'file_2'",
"mtn: modified on the left, named file_2",
"mtn: dropped on the right",
"mtn: 1 conflict with supported resolutions."}))
@@ -47,7 +47,7 @@ check(samelines("stderr",
check(samelines("stderr",
{"mtn: [left] 1e700864de7a2cbb1cf85c26f5e1e4ca335d2bc2",
"mtn: [right] a2889488ed1801a904d0219ec9939dfc2e9be033",
- "mtn: dropping 'file_2'",
+ "mtn: dropping 'file_2' from left",
"mtn: [merged] dd1ba606b52fddb4431da3760ff65b65f6509a48"}))
check(mtn("update"), 0, nil, true)
@@ -75,7 +75,7 @@ check(mtn("merge", "--resolve-conflicts"
check(qgrep("mtn: misuse: merge failed due to unresolved conflicts", "stderr"))
check(mtn("merge", "--resolve-conflicts"), 0, nil, true)
-check(qgrep("mtn: dropping 'file_2'", "stderr"))
+check(qgrep("mtn: dropping 'file_2' from left", "stderr"))
check(mtn("update"), 0, nil, true)
check(not exists("file_2"))
@@ -86,10 +86,10 @@ check(samelines("stderr",
{"mtn: [left] c0ed8c29ffad149af1c948969e8e80d270999b13",
"mtn: [right] dd1ba606b52fddb4431da3760ff65b65f6509a48",
"mtn: [ancestor] 1e700864de7a2cbb1cf85c26f5e1e4ca335d2bc2",
- "mtn: conflict: file 'file_2' from revision 1e700864de7a2cbb1cf85c26f5e1e4ca335d2bc2",
+ "mtn: conflict: file 'file_2'",
"mtn: modified on the left, named file_2",
"mtn: dropped on the right",
- "mtn: resolution: drop",
+ "mtn: left_resolution: drop",
"mtn: 1 conflict with supported resolutions."}))
-- 'conflicts store' is not needed unless there are other conflicts,
@@ -98,4 +98,11 @@ check(samefilestd("conflicts", "_MTN/con
check(mtn("conflicts", "store", upstream_2, local_2), 0, nil, true)
check(samefilestd("conflicts", "_MTN/conflicts"))
+-- repeat merge with left, right swapped to verify symmetry in code
+remove("_MTN/conflicts")
+check(mtn("explicit_merge", "--resolve-conflicts", local_2, upstream_2, "testbranch"), 0, nil, true)
+check(qgrep("mtn: dropping 'file_2' from right", "stderr"))
+check(mtn("update"), 0, nil, true)
+check(not exists("file_2"))
+
-- end of file
============================================================
--- test/func/resolve_conflicts_errors/__driver__.lua 9a130c83d4a7e3545f18d089542603c8d0bb72fa
+++ test/func/resolve_conflicts_errors/__driver__.lua 0819ba223855d9814a7420c7412166b1109ed20f
@@ -107,7 +107,8 @@ canonicalize("stdout")
check(mtn("conflicts", "resolve_first_right", "user", "checkout.sh"), 1, nil, true)
check(grep("-v", "detected at", "stderr"), 0, true)
canonicalize("stdout")
-check("mtn: misuse: other resolution must be 'drop' or 'rename'\n" == readfile("stdout"))
+check(samelines("stdout",
+{"mtn: misuse: other resolution is content_user; specify 'drop', 'rename', or 'user_rename'"}))
-- not in workspace; report nice error; conflicts file must be under
-- _MTN, so need workspace. Fixes bug 30473
============================================================
--- test/func/resolve_conflicts_orphaned_file/__driver__.lua fe6a4618be2793d18ee2f97adf94cd564763164f
+++ test/func/resolve_conflicts_orphaned_file/__driver__.lua beb41b901c1e08bbef25e87fe0b2ef36e74a2a8b
@@ -1,5 +1,4 @@
-- Test resolving orphaned_file and orphaned_directory conflicts
-
mtn_setup()
addfile("foo", "foo base")
============================================================
--- innosetup/README.txt 6f92ce9f01c75b83994b690bb8b00c549c368965
+++ innosetup/README.txt d306d15f4bba8011dd1fa01dd9522b93c8ce8920
@@ -19,6 +19,10 @@
Check out the release version of monotone:
mtn -d /path/to/monotone.db checkout -r t:monotone-<version> --branch net.venge.monotone.monotone-<version> monotone-<version>
+Do not use the source tarball; if you do, the resulting monotone
+executable will not know the base revision, which is needed for good
+bug reports.
+
Build the release. See the last instruction in ../INSTALL_windows_native.txt
Then build the installer:
============================================================
--- src/automate.cc 919e3df52514d0877aeafc67791aae6a3faa33b4
+++ src/automate.cc 30e9bb3567e320f83ce5c1b4817dc9ad90fe8423
@@ -1352,15 +1352,15 @@ CMD_AUTOMATE(get_base_revision_id, "",
E(args.size() == 0, origin::user,
F("no arguments needed"));
- database db(app);
workspace work(app);
+ revision_t rev;
- parent_map parents;
- work.get_parent_rosters(db, parents);
- E(parents.size() == 1, origin::user,
+ work.get_work_rev(rev);
+
+ E(rev.edges.size() == 1, origin::user,
F("this command can only be used in a single-parent workspace"));
- output << parent_id(parents.begin()) << '\n';
+ output << rev.edges.begin()->first << '\n';
}
// Name: get_current_revision_id
[Prev in Thread] |
Current Thread |
[Next in Thread] |
- [Monotone-commits-diffs] net.venge.monotone: 806715c5ce888b7dbbce7752a7ff35868ee3bcfa,
code <=