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(revision_id const & left_rid,
44 revision_id const & right_rid,
45 roster_t const & left_roster,
46 roster_t const & right_roster,
47 marking_map const & left_marking_map,
48 marking_map const & right_marking_map,
49 roster_merge_result & result,
50 content_merge_adaptor & adaptor,
51 app_state & app)
52{
53 // FIXME_ROSTERS: we only have code (below) to invoke the
54 // line-merger on content conflicts. Other classes of conflict will
55 // cause an invariant to trip below. Probably just a bunch of lua
56 // hooks for remaining conflict types will be ok.
57
58 if (!result.is_clean())
59 result.log_conflicts();
60
61 if (!result.is_clean_except_for_content())
62 {
63 result.warn_non_content_conflicts();
64 W(F("resolve non-content conflicts and then try again."));
65 }
66 else
67 {
68 // Attempt to auto-resolve any content conflicts using the line-merger.
69 // To do this requires finding a merge ancestor.
70 if (!result.file_content_conflicts.empty())
71 {
72
73 L(FL("examining content conflicts"));
74 vector<file_content_conflict> residual_conflicts;
75
76 for (size_t i = 0; i < result.file_content_conflicts.size(); ++i)
77 {
78 file_content_conflict const & conflict = result.file_content_conflicts[i];
79
80 shared_ptr<roster_t> 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 % (i+1) % result.file_content_conflicts.size());
104 file_t f = downcast_to_file_t(result.roster.get_node(conflict.nid));
105 f->content = merged_id;
106 }
107 else
108 residual_conflicts.push_back(conflict);
109 }
110 result.file_content_conflicts = residual_conflicts;
111 }
112 }
113
114 E(result.is_clean(),
115 F("merge failed due to unresolved conflicts\n"));
116}
117
118void
119interactive_merge_and_store(revision_id const & left_rid,
120 revision_id const & right_rid,
121 revision_id & merged_rid,
122 app_state & app)
123{
124 roster_t left_roster, right_roster;
125 marking_map left_marking_map, right_marking_map;
126 set<revision_id> left_uncommon_ancestors, right_uncommon_ancestors;
127
128 app.db.get_roster(left_rid, left_roster, left_marking_map);
129 app.db.get_roster(right_rid, right_roster, right_marking_map);
130 app.db.get_uncommon_ancestors(left_rid, right_rid,
131 left_uncommon_ancestors, right_uncommon_ancestors);
132
133 roster_merge_result result;
134
135// {
136// data tmp;
137// write_roster_and_marking(left_roster, left_marking_map, tmp);
138// P(F("merge left roster: [[[\n%s\n]]]") % tmp);
139// write_roster_and_marking(right_roster, right_marking_map, tmp);
140// P(F("merge right roster: [[[\n%s\n]]]") % tmp);
141// }
142
143 roster_merge(left_roster, left_marking_map, left_uncommon_ancestors,
144 right_roster, right_marking_map, right_uncommon_ancestors,
145 result);
146
147 content_merge_database_adaptor dba(app, left_rid, right_rid, left_marking_map);
148 resolve_merge_conflicts (left_rid, right_rid,
149 left_roster, right_roster,
150 left_marking_map, right_marking_map,
151 result, dba, app);
152
153 // write new files into the db
154 store_roster_merge_result(left_roster, right_roster, result,
155 left_rid, right_rid, merged_rid,
156 app);
157}
158
159void
160store_roster_merge_result(roster_t const & left_roster,
161 roster_t const & right_roster,
162 roster_merge_result & result,
163 revision_id const & left_rid,
164 revision_id const & right_rid,
165 revision_id & merged_rid,
166 app_state & app)
167{
168 I(result.is_clean());
169 roster_t & merged_roster = result.roster;
170 merged_roster.check_sane();
171
172 revision_t merged_rev;
173
174 calculate_ident(merged_roster, merged_rev.new_manifest);
175
176 shared_ptr<cset> left_to_merged(new cset);
177 make_cset(left_roster, merged_roster, *left_to_merged);
178 safe_insert(merged_rev.edges, make_pair(left_rid, left_to_merged));
179
180 shared_ptr<cset> right_to_merged(new cset);
181 make_cset(right_roster, merged_roster, *right_to_merged);
182 safe_insert(merged_rev.edges, make_pair(right_rid, right_to_merged));
183
184 revision_data merged_data;
185 write_revision(merged_rev, merged_data);
186 calculate_ident(merged_data, merged_rid);
187 {
188 transaction_guard guard(app.db);
189
190 app.db.put_revision(merged_rid, merged_rev);
191 packet_db_writer dbw(app);
192 if (app.date_set)
193 cert_revision_date_time(merged_rid, app.date, app, dbw);
194 else
195 cert_revision_date_now(merged_rid, app, dbw);
196 if (app.author().length() > 0)
197 cert_revision_author(merged_rid, app.author(), app, dbw);
198 else
199 cert_revision_author_default(merged_rid, app, dbw);
200
201 guard.commit();
202 }
203}
204
205// Local Variables:
206// mode: C++
207// fill-column: 76
208// c-file-style: "gnu"
209// indent-tabs-mode: nil
210// End:
211// 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