50 |
50 |
51 os.unlink(b) |
51 os.unlink(b) |
52 os.unlink(c) |
52 os.unlink(c) |
53 return r |
53 return r |
54 |
54 |
55 def manifestmerge(ui, m1, m2, ma, overwrite, backwards): |
55 def checkunknown(repo, m2, status): |
|
56 """ |
|
57 check for collisions between unknown files and files in m2 |
|
58 """ |
|
59 modified, added, removed, deleted, unknown = status[:5] |
|
60 for f in unknown: |
|
61 if f in m2: |
|
62 if repo.file(f).cmp(m2[f], repo.wread(f)): |
|
63 raise util.Abort(_("'%s' already exists in the working" |
|
64 " dir and differs from remote") % f) |
|
65 |
|
66 def workingmanifest(repo, man, status): |
|
67 """ |
|
68 Update manifest to correspond to the working directory |
|
69 """ |
|
70 |
|
71 modified, added, removed, deleted, unknown = status[:5] |
|
72 for i,l in (("a", added), ("m", modified), ("u", unknown)): |
|
73 for f in l: |
|
74 man[f] = man.get(f, nullid) + i |
|
75 man.set(f, util.is_exec(repo.wjoin(f), man.execf(f))) |
|
76 |
|
77 for f in deleted + removed: |
|
78 del man[f] |
|
79 |
|
80 return man |
|
81 |
|
82 def forgetremoved(m2, status): |
|
83 """ |
|
84 Forget removed files |
|
85 |
|
86 If we're jumping between revisions (as opposed to merging), and if |
|
87 neither the working directory nor the target rev has the file, |
|
88 then we need to remove it from the dirstate, to prevent the |
|
89 dirstate from listing the file when it is no longer in the |
|
90 manifest. |
|
91 """ |
|
92 |
|
93 modified, added, removed, deleted, unknown = status[:5] |
|
94 action = [] |
|
95 |
|
96 for f in deleted + removed: |
|
97 if f not in m2: |
|
98 action.append((f, "f")) |
|
99 |
|
100 return action |
|
101 |
|
102 def manifestmerge(ui, m1, m2, ma, overwrite, backwards, partial): |
56 """ |
103 """ |
57 Merge manifest m1 with m2 using ancestor ma and generate merge action list |
104 Merge manifest m1 with m2 using ancestor ma and generate merge action list |
58 """ |
105 """ |
59 |
106 |
60 action = [] |
107 action = [] |
|
108 |
|
109 # Filter manifests |
|
110 if partial: |
|
111 for f in m1.keys(): |
|
112 if not partial(f): del m1[f] |
|
113 for f in m2.keys(): |
|
114 if not partial(f): del m2[f] |
61 |
115 |
62 # Compare manifests |
116 # Compare manifests |
63 for f, n in m1.iteritems(): |
117 for f, n in m1.iteritems(): |
64 if f in m2: |
118 if f in m2: |
65 queued = 0 |
119 queued = 0 |
174 |
228 |
175 if not linear_path and not (overwrite or branchmerge): |
229 if not linear_path and not (overwrite or branchmerge): |
176 raise util.Abort(_("update spans branches, use 'hg merge' " |
230 raise util.Abort(_("update spans branches, use 'hg merge' " |
177 "or 'hg update -C' to lose changes")) |
231 "or 'hg update -C' to lose changes")) |
178 |
232 |
179 modified, added, removed, deleted, unknown = repo.status()[:5] |
233 status = repo.status() |
|
234 modified, added, removed, deleted, unknown = status[:5] |
180 if branchmerge and not forcemerge: |
235 if branchmerge and not forcemerge: |
181 if modified or added or removed: |
236 if modified or added or removed: |
182 raise util.Abort(_("outstanding uncommitted changes")) |
237 raise util.Abort(_("outstanding uncommitted changes")) |
183 |
238 |
184 m1 = repo.changectx(p1).manifest().copy() |
239 m1 = repo.changectx(p1).manifest().copy() |
185 m2 = repo.changectx(p2).manifest().copy() |
240 m2 = repo.changectx(p2).manifest().copy() |
186 ma = repo.changectx(pa).manifest() |
241 ma = repo.changectx(pa).manifest() |
187 |
|
188 if not force: |
|
189 for f in unknown: |
|
190 if f in m2: |
|
191 if repo.file(f).cmp(m2[f], repo.wread(f)): |
|
192 raise util.Abort(_("'%s' already exists in the working" |
|
193 " dir and differs from remote") % f) |
|
194 |
242 |
195 # resolve the manifest to determine which files |
243 # resolve the manifest to determine which files |
196 # we care about merging |
244 # we care about merging |
197 repo.ui.note(_("resolving manifests\n")) |
245 repo.ui.note(_("resolving manifests\n")) |
198 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") % |
246 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s linear %s\n") % |
199 (overwrite, branchmerge, bool(partial), linear_path)) |
247 (overwrite, branchmerge, bool(partial), linear_path)) |
200 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % |
248 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % |
201 (short(p1), short(p2), short(pa))) |
249 (short(p1), short(p2), short(pa))) |
202 |
250 |
203 action = [] |
251 action = [] |
204 |
252 m1 = workingmanifest(repo, m1, status) |
205 # update m1 from working dir |
253 |
206 for i,l in (("a", added), ("m", modified), ("u", unknown)): |
254 if not force: |
207 for f in l: |
255 checkunknown(repo, m2, status) |
208 m1[f] = m1.get(f, nullid) + i |
256 if linear_path: |
209 m1.set(f, util.is_exec(repo.wjoin(f), m1.execf(f))) |
257 action += forgetremoved(m2, status) |
210 |
258 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial) |
211 for f in deleted + removed: |
|
212 del m1[f] |
|
213 |
|
214 # If we're jumping between revisions (as opposed to merging), |
|
215 # and if neither the working directory nor the target rev has |
|
216 # the file, then we need to remove it from the dirstate, to |
|
217 # prevent the dirstate from listing the file when it is no |
|
218 # longer in the manifest. |
|
219 if linear_path and f not in m2: |
|
220 action.append((f, "f")) |
|
221 |
|
222 if partial: |
|
223 for f in m1.keys(): |
|
224 if not partial(f): del m1[f] |
|
225 for f in m2.keys(): |
|
226 if not partial(f): del m2[f] |
|
227 |
|
228 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards) |
|
229 del m1, m2, ma |
259 del m1, m2, ma |
230 |
260 |
231 ### apply phase |
261 ### apply phase |
232 |
262 |
233 if linear_path or overwrite: |
263 if linear_path or overwrite: |