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