comparison mercurial/merge.py @ 3112:5cc62d99b785

merge: move apply and dirstate code into separate functions
author Matt Mackall <mpm@selenic.com>
date Sun, 17 Sep 2006 17:39:19 -0500
parents 40e777bda455
children f96c8e219865
comparison
equal deleted inserted replaced
3111:40e777bda455 3112:5cc62d99b785
197 else: 197 else:
198 ui.debug(_("local deleted %s\n") % f) 198 ui.debug(_("local deleted %s\n") % f)
199 199
200 return action 200 return action
201 201
202 def update(repo, node, branchmerge=False, force=False, partial=None, 202 def applyupdates(repo, action, xp1, xp2):
203 wlock=None, show_stats=True, remind=True):
204
205 overwrite = force and not branchmerge
206 forcemerge = force and branchmerge
207
208 if not wlock:
209 wlock = repo.wlock()
210
211 ### check phase
212
213 pl = repo.dirstate.parents()
214 if not overwrite and pl[1] != nullid:
215 raise util.Abort(_("outstanding uncommitted merges"))
216
217 p1, p2 = pl[0], node
218 pa = repo.changelog.ancestor(p1, p2)
219
220 # are we going backwards?
221 backwards = (pa == p2)
222
223 # is there a linear path from p1 to p2?
224 if pa == p1 or pa == p2:
225 if branchmerge:
226 raise util.Abort(_("there is nothing to merge, just use "
227 "'hg update' or look at 'hg heads'"))
228 elif not (overwrite or branchmerge):
229 raise util.Abort(_("update spans branches, use 'hg merge' "
230 "or 'hg update -C' to lose changes"))
231
232 status = repo.status()
233 modified, added, removed, deleted, unknown = status[:5]
234 if branchmerge and not forcemerge:
235 if modified or added or removed:
236 raise util.Abort(_("outstanding uncommitted changes"))
237
238 m1 = repo.changectx(p1).manifest().copy()
239 m2 = repo.changectx(p2).manifest().copy()
240 ma = repo.changectx(pa).manifest()
241
242 # resolve the manifest to determine which files
243 # we care about merging
244 repo.ui.note(_("resolving manifests\n"))
245 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") %
246 (overwrite, branchmerge, bool(partial)))
247 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
248 (short(p1), short(p2), short(pa)))
249
250 action = []
251 m1 = workingmanifest(repo, m1, status)
252
253 if not force:
254 checkunknown(repo, m2, status)
255 if not branchmerge:
256 action += forgetremoved(m2, status)
257 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
258 del m1, m2, ma
259
260 ### apply phase
261
262 if not branchmerge:
263 # we don't need to do any magic, just jump to the new rev
264 p1, p2 = p2, nullid
265
266 xp1, xp2 = hex(p1), hex(p2)
267 if p2 == nullid: xp2 = ''
268
269 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
270
271 # update files
272 updated, merged, removed, unresolved = 0, 0, 0, 0 203 updated, merged, removed, unresolved = 0, 0, 0, 0
273 action.sort() 204 action.sort()
274 for a in action: 205 for a in action:
275 f, m = a[:2] 206 f, m = a[:2]
276 if f[0] == "/": 207 if f[0] == "/":
301 updated += 1 232 updated += 1
302 elif m == "e": # exec 233 elif m == "e": # exec
303 flag = a[2:] 234 flag = a[2:]
304 util.set_exec(repo.wjoin(f), flag) 235 util.set_exec(repo.wjoin(f), flag)
305 236
237 return updated, merged, removed, unresolved
238
239 def recordupdates(repo, action, branchmerge):
240 for a in action:
241 f, m = a[:2]
242 if m == "r": # remove
243 if branchmerge:
244 repo.dirstate.update([f], 'r')
245 else:
246 repo.dirstate.forget([f])
247 elif m == "f": # forget
248 repo.dirstate.forget([f])
249 elif m == "g": # get
250 if branchmerge:
251 repo.dirstate.update([f], 'n', st_mtime=-1)
252 else:
253 repo.dirstate.update([f], 'n')
254 elif m == "m": # merge
255 flag, my, other = a[2:]
256 if branchmerge:
257 # We've done a branch merge, mark this file as merged
258 # so that we properly record the merger later
259 repo.dirstate.update([f], 'm')
260 else:
261 # We've update-merged a locally modified file, so
262 # we set the dirstate to emulate a normal checkout
263 # of that file some time in the past. Thus our
264 # merge will appear as a normal local file
265 # modification.
266 fl = repo.file(f)
267 f_len = fl.size(fl.rev(other))
268 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
269
270 def update(repo, node, branchmerge=False, force=False, partial=None,
271 wlock=None, show_stats=True, remind=True):
272
273 overwrite = force and not branchmerge
274 forcemerge = force and branchmerge
275
276 if not wlock:
277 wlock = repo.wlock()
278
279 ### check phase
280
281 pl = repo.dirstate.parents()
282 if not overwrite and pl[1] != nullid:
283 raise util.Abort(_("outstanding uncommitted merges"))
284
285 p1, p2 = pl[0], node
286 pa = repo.changelog.ancestor(p1, p2)
287
288 # are we going backwards?
289 backwards = (pa == p2)
290
291 # is there a linear path from p1 to p2?
292 if pa == p1 or pa == p2:
293 if branchmerge:
294 raise util.Abort(_("there is nothing to merge, just use "
295 "'hg update' or look at 'hg heads'"))
296 elif not (overwrite or branchmerge):
297 raise util.Abort(_("update spans branches, use 'hg merge' "
298 "or 'hg update -C' to lose changes"))
299
300 status = repo.status()
301 modified, added, removed, deleted, unknown = status[:5]
302 if branchmerge and not forcemerge:
303 if modified or added or removed:
304 raise util.Abort(_("outstanding uncommitted changes"))
305
306 m1 = repo.changectx(p1).manifest().copy()
307 m2 = repo.changectx(p2).manifest().copy()
308 ma = repo.changectx(pa).manifest()
309
310 # resolve the manifest to determine which files
311 # we care about merging
312 repo.ui.note(_("resolving manifests\n"))
313 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") %
314 (overwrite, branchmerge, bool(partial)))
315 repo.ui.debug(_(" ancestor %s local %s remote %s\n") %
316 (short(p1), short(p2), short(pa)))
317
318 action = []
319 m1 = workingmanifest(repo, m1, status)
320
321 if not force:
322 checkunknown(repo, m2, status)
323 if not branchmerge:
324 action += forgetremoved(m2, status)
325 action += manifestmerge(repo.ui, m1, m2, ma, overwrite, backwards, partial)
326 del m1, m2, ma
327
328 ### apply phase
329
330 if not branchmerge:
331 # we don't need to do any magic, just jump to the new rev
332 p1, p2 = p2, nullid
333
334 xp1, xp2 = hex(p1), hex(p2)
335 if p2 == nullid: xp2 = ''
336
337 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
338
339 updated, merged, removed, unresolved = applyupdates(repo, action, xp1, xp2)
340
306 # update dirstate 341 # update dirstate
307 if not partial: 342 if not partial:
308 repo.dirstate.setparents(p1, p2) 343 repo.dirstate.setparents(p1, p2)
309 for a in action: 344 recordupdates(repo, action, branchmerge)
310 f, m = a[:2]
311 if m == "r": # remove
312 if branchmerge:
313 repo.dirstate.update([f], 'r')
314 else:
315 repo.dirstate.forget([f])
316 elif m == "f": # forget
317 repo.dirstate.forget([f])
318 elif m == "g": # get
319 if branchmerge:
320 repo.dirstate.update([f], 'n', st_mtime=-1)
321 else:
322 repo.dirstate.update([f], 'n')
323 elif m == "m": # merge
324 flag, my, other = a[2:]
325 if branchmerge:
326 # We've done a branch merge, mark this file as merged
327 # so that we properly record the merger later
328 repo.dirstate.update([f], 'm')
329 else:
330 # We've update-merged a locally modified file, so
331 # we set the dirstate to emulate a normal checkout
332 # of that file some time in the past. Thus our
333 # merge will appear as a normal local file
334 # modification.
335 fl = repo.file(f)
336 f_len = fl.size(fl.rev(other))
337 repo.dirstate.update([f], 'n', st_size=f_len, st_mtime=-1)
338 345
339 if show_stats: 346 if show_stats:
340 stats = ((updated, _("updated")), 347 stats = ((updated, _("updated")),
341 (merged - unresolved, _("merged")), 348 (merged - unresolved, _("merged")),
342 (removed, _("removed")), 349 (removed, _("removed")),