monotone

monotone Mtn Source Tree

Root/merge.cc

1// Copyright (C) 2005 Nathaniel Smith <njs@pobox.com>
2//
3// This program is made available under the GNU GPL version 2.0 or
4// greater. See the accompanying file COPYING for details.
5//
6// This program is distributed WITHOUT ANY WARRANTY; without even the
7// implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR
8// PURPOSE.
9
10#include <set>
11
12#include <boost/shared_ptr.hpp>
13
14#include "diff_patch.hh"
15#include "merge.hh"
16#include "packet.hh"
17#include "revision.hh"
18#include "roster_merge.hh"
19#include "safe_map.hh"
20#include "transforms.hh"
21
22using std::make_pair;
23using std::map;
24using std::set;
25using std::vector;
26
27using boost::shared_ptr;
28
29static void
30get_file_details(roster_t const & ros, node_id nid,
31 file_id & fid,
32 file_path & pth)
33{
34 I(ros.has_node(nid));
35 file_t f = downcast_to_file_t(ros.get_node(nid));
36 fid = f->content;
37 split_path sp;
38 ros.get_name(nid, sp);
39 pth = file_path(sp);
40}
41
42void
43resolve_merge_conflicts(roster_t const & left_roster,
44 roster_t const & right_roster,
45 roster_merge_result & result,
46 content_merge_adaptor & adaptor,
47 app_state & app)
48{
49 // FIXME_ROSTERS: we only have code (below) to invoke the
50 // line-merger on content conflicts. Other classes of conflict will
51 // cause an invariant to trip below. Probably just a bunch of lua
52 // hooks for remaining conflict types will be ok.
53
54 if (!result.is_clean())
55 result.log_conflicts();
56
57 if (!result.is_clean_except_for_content())
58 {
59 result.warn_non_content_conflicts();
60 W(F("resolve non-content conflicts and then try again."));
61 }
62 else
63 {
64 // Attempt to auto-resolve any content conflicts using the line-merger.
65 // To do this requires finding a merge ancestor.
66 if (!result.file_content_conflicts.empty())
67 {
68
69 L(FL("examining content conflicts"));
70
71 size_t cnt;
72 size_t total_conflicts = result.file_content_conflicts.size();
73 std::vector<file_content_conflict>::iterator it;
74
75 for (cnt = 1, it = result.file_content_conflicts.begin();
76 it != result.file_content_conflicts.end(); ++cnt)
77 {
78 file_content_conflict const & conflict = *it;
79
80 shared_ptr<roster_t const> roster_for_file_lca;
81 adaptor.get_ancestral_roster(conflict.nid, roster_for_file_lca);
82
83 // Now we should certainly have a roster, which has the node.
84 I(roster_for_file_lca);
85 I(roster_for_file_lca->has_node(conflict.nid));
86
87 file_id anc_id, left_id, right_id;
88 file_path anc_path, left_path, right_path;
89 get_file_details (*roster_for_file_lca, conflict.nid, anc_id, anc_path);
90 get_file_details (left_roster, conflict.nid, left_id, left_path);
91 get_file_details (right_roster, conflict.nid, right_id, right_path);
92
93 file_id merged_id;
94
95 content_merger cm(app, *roster_for_file_lca,
96 left_roster, right_roster,
97 adaptor);
98
99 if (cm.try_to_merge_files(anc_path, left_path, right_path, right_path,
100 anc_id, left_id, right_id, merged_id))
101 {
102 L(FL("resolved content conflict %d / %d")
103 % cnt % total_conflicts);
104 file_t f = downcast_to_file_t(result.roster.get_node(conflict.nid));
105 f->content = merged_id;
106
107 it = result.file_content_conflicts.erase(it);
108 }
109 else
110 {
111 ++it;
112
113 // If the content_merger has failed, there's no point
114 // trying to continue--we'll only frustrate users by
115 // encouraging them to continue working with their merge
116 // tool on a merge that is now destined to fail.
117 break;
118 }
119 }
120 }
121 }
122
123 E(result.is_clean(),
124 F("merge failed due to unresolved conflicts"));
125}
126
127void
128interactive_merge_and_store(revision_id const & left_rid,
129 revision_id const & right_rid,
130 revision_id & merged_rid,
131 app_state & app)
132{
133 roster_t left_roster, right_roster;
134 marking_map left_marking_map, right_marking_map;
135 set<revision_id> left_uncommon_ancestors, right_uncommon_ancestors;
136
137 app.db.get_roster(left_rid, left_roster, left_marking_map);
138 app.db.get_roster(right_rid, right_roster, right_marking_map);
139 app.db.get_uncommon_ancestors(left_rid, right_rid,
140 left_uncommon_ancestors, right_uncommon_ancestors);
141
142 roster_merge_result result;
143
144// {
145// data tmp;
146// write_roster_and_marking(left_roster, left_marking_map, tmp);
147// P(F("merge left roster: [[[\n%s\n]]]") % tmp);
148// write_roster_and_marking(right_roster, right_marking_map, tmp);
149// P(F("merge right roster: [[[\n%s\n]]]") % tmp);
150// }
151
152 roster_merge(left_roster, left_marking_map, left_uncommon_ancestors,
153 right_roster, right_marking_map, right_uncommon_ancestors,
154 result);
155
156 content_merge_database_adaptor dba(app, left_rid, right_rid, left_marking_map);
157 resolve_merge_conflicts (left_roster, right_roster,
158 result, dba, app);
159
160 // write new files into the db
161 store_roster_merge_result(left_roster, right_roster, result,
162 left_rid, right_rid, merged_rid,
163 app);
164}
165
166void
167store_roster_merge_result(roster_t const & left_roster,
168 roster_t const & right_roster,
169 roster_merge_result & result,
170 revision_id const & left_rid,
171 revision_id const & right_rid,
172 revision_id & merged_rid,
173 app_state & app)
174{
175 I(result.is_clean());
176 roster_t & merged_roster = result.roster;
177 merged_roster.check_sane();
178
179 revision_t merged_rev;
180 merged_rev.made_for = made_for_database;
181
182 calculate_ident(merged_roster, merged_rev.new_manifest);
183
184 shared_ptr<cset> left_to_merged(new cset);
185 make_cset(left_roster, merged_roster, *left_to_merged);
186 safe_insert(merged_rev.edges, make_pair(left_rid, left_to_merged));
187
188 shared_ptr<cset> right_to_merged(new cset);
189 make_cset(right_roster, merged_roster, *right_to_merged);
190 safe_insert(merged_rev.edges, make_pair(right_rid, right_to_merged));
191
192 revision_data merged_data;
193 write_revision(merged_rev, merged_data);
194 calculate_ident(merged_data, merged_rid);
195 {
196 transaction_guard guard(app.db);
197
198 app.db.put_revision(merged_rid, merged_rev);
199
200 guard.commit();
201 }
202}
203
204// Local Variables:
205// mode: C++
206// fill-column: 76
207// c-file-style: "gnu"
208// indent-tabs-mode: nil
209// End:
210// vim: et:sw=2:sts=2:ts=2:cino=>2s,{s,\:s,+s,t0,g0,^-2,e-2,n-2,p2s,(0,=s:

Archive Download this file

Branches

Tags

Quick Links:     www.monotone.ca    -     Downloads    -     Documentation    -     Wiki    -     Code Forge    -     Build Status