160 If we're merging, and the other revision has removed a file |
160 If we're merging, and the other revision has removed a file |
161 that is not present in the working directory, we need to mark it |
161 that is not present in the working directory, we need to mark it |
162 as removed. |
162 as removed. |
163 """ |
163 """ |
164 |
164 |
165 action = [] |
165 actions = [] |
166 state = branchmerge and 'r' or 'f' |
166 state = branchmerge and 'r' or 'f' |
167 for f in wctx.deleted(): |
167 for f in wctx.deleted(): |
168 if f not in mctx: |
168 if f not in mctx: |
169 action.append((f, state)) |
169 actions.append((f, state)) |
170 |
170 |
171 if not branchmerge: |
171 if not branchmerge: |
172 for f in wctx.removed(): |
172 for f in wctx.removed(): |
173 if f not in mctx: |
173 if f not in mctx: |
174 action.append((f, "f")) |
174 actions.append((f, "f")) |
175 |
175 |
176 return action |
176 return actions |
177 |
177 |
178 def manifestmerge(repo, p1, p2, pa, overwrite, partial): |
178 def manifestmerge(repo, p1, p2, pa, overwrite, partial): |
179 """ |
179 """ |
180 Merge p1 and p2 with ancestor pa and generate merge action list |
180 Merge p1 and p2 with ancestor pa and generate merge action list |
181 |
181 |
209 return n |
209 return n |
210 return '' # flag was cleared |
210 return '' # flag was cleared |
211 |
211 |
212 def act(msg, m, f, *args): |
212 def act(msg, m, f, *args): |
213 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) |
213 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) |
214 action.append((f, m) + args) |
214 actions.append((f, m) + args) |
215 |
215 |
216 action, copy, movewithdir = [], {}, {} |
216 actions, copy, movewithdir = [], {}, {} |
217 |
217 |
218 if overwrite: |
218 if overwrite: |
219 pa = p1 |
219 pa = p1 |
220 elif pa == p2: # backwards |
220 elif pa == p2: # backwards |
221 pa = p1.p1() |
221 pa = p1.p1() |
313 _("remote changed %s which local deleted\n" |
313 _("remote changed %s which local deleted\n" |
314 "use (c)hanged version or leave (d)eleted?") % f, |
314 "use (c)hanged version or leave (d)eleted?") % f, |
315 (_("&Changed"), _("&Deleted")), 0) == 0: |
315 (_("&Changed"), _("&Deleted")), 0) == 0: |
316 act("prompt recreating", "g", f, m2.flags(f)) |
316 act("prompt recreating", "g", f, m2.flags(f)) |
317 |
317 |
318 return action |
318 return actions |
319 |
319 |
320 def actionkey(a): |
320 def actionkey(a): |
321 return a[1] == "r" and -1 or 0, a |
321 return a[1] == "r" and -1 or 0, a |
322 |
322 |
323 def applyupdates(repo, action, wctx, mctx, actx, overwrite): |
323 def applyupdates(repo, actions, wctx, mctx, actx, overwrite): |
324 """apply the merge action list to the working directory |
324 """apply the merge action list to the working directory |
325 |
325 |
326 wctx is the working copy context |
326 wctx is the working copy context |
327 mctx is the context to be merged into the working copy |
327 mctx is the context to be merged into the working copy |
328 actx is the context of the common ancestor |
328 actx is the context of the common ancestor |
333 |
333 |
334 updated, merged, removed, unresolved = 0, 0, 0, 0 |
334 updated, merged, removed, unresolved = 0, 0, 0, 0 |
335 ms = mergestate(repo) |
335 ms = mergestate(repo) |
336 ms.reset(wctx.p1().node()) |
336 ms.reset(wctx.p1().node()) |
337 moves = [] |
337 moves = [] |
338 action.sort(key=actionkey) |
338 actions.sort(key=actionkey) |
339 |
339 |
340 # prescan for merges |
340 # prescan for merges |
341 for a in action: |
341 for a in actions: |
342 f, m = a[:2] |
342 f, m = a[:2] |
343 if m == "m": # merge |
343 if m == "m": # merge |
344 f2, fd, flags, move = a[2:] |
344 f2, fd, flags, move = a[2:] |
345 if f == '.hgsubstate': # merged internally |
345 if f == '.hgsubstate': # merged internally |
346 continue |
346 continue |
367 if os.path.lexists(repo.wjoin(f)): |
367 if os.path.lexists(repo.wjoin(f)): |
368 repo.ui.debug("removing %s\n" % f) |
368 repo.ui.debug("removing %s\n" % f) |
369 audit(f) |
369 audit(f) |
370 os.unlink(repo.wjoin(f)) |
370 os.unlink(repo.wjoin(f)) |
371 |
371 |
372 numupdates = len(action) |
372 numupdates = len(actions) |
373 for i, a in enumerate(action): |
373 for i, a in enumerate(actions): |
374 f, m = a[:2] |
374 f, m = a[:2] |
375 repo.ui.progress(_('updating'), i + 1, item=f, total=numupdates, |
375 repo.ui.progress(_('updating'), i + 1, item=f, total=numupdates, |
376 unit=_('files')) |
376 unit=_('files')) |
377 if f and f[0] == "/": |
377 if f and f[0] == "/": |
378 continue |
378 continue |
450 |
450 |
451 return updated, merged, removed, unresolved |
451 return updated, merged, removed, unresolved |
452 |
452 |
453 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial): |
453 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial): |
454 "Calculate the actions needed to merge mctx into tctx" |
454 "Calculate the actions needed to merge mctx into tctx" |
455 action = [] |
455 actions = [] |
456 folding = not util.checkcase(repo.path) |
456 folding = not util.checkcase(repo.path) |
457 if folding: |
457 if folding: |
458 # collision check is not needed for clean update |
458 # collision check is not needed for clean update |
459 if (not branchmerge and |
459 if (not branchmerge and |
460 (force or not tctx.dirty(missing=True, branch=False))): |
460 (force or not tctx.dirty(missing=True, branch=False))): |
462 else: |
462 else: |
463 _checkcollision(mctx, (tctx, ancestor)) |
463 _checkcollision(mctx, (tctx, ancestor)) |
464 if not force: |
464 if not force: |
465 _checkunknown(repo, tctx, mctx) |
465 _checkunknown(repo, tctx, mctx) |
466 if tctx.rev() is None: |
466 if tctx.rev() is None: |
467 action += _forgetremoved(tctx, mctx, branchmerge) |
467 actions += _forgetremoved(tctx, mctx, branchmerge) |
468 action += manifestmerge(repo, tctx, mctx, |
468 actions += manifestmerge(repo, tctx, mctx, |
469 ancestor, |
469 ancestor, |
470 force and not branchmerge, |
470 force and not branchmerge, |
471 partial) |
471 partial) |
472 return action |
472 return actions |
473 |
473 |
474 def recordupdates(repo, action, branchmerge): |
474 def recordupdates(repo, actions, branchmerge): |
475 "record merge actions to the dirstate" |
475 "record merge actions to the dirstate" |
476 |
476 |
477 for a in action: |
477 for a in actions: |
478 f, m = a[:2] |
478 f, m = a[:2] |
479 if m == "r": # remove |
479 if m == "r": # remove |
480 if branchmerge: |
480 if branchmerge: |
481 repo.dirstate.remove(f) |
481 repo.dirstate.remove(f) |
482 else: |
482 else: |
630 else: |
630 else: |
631 # Allow jumping branches if clean and specific rev given |
631 # Allow jumping branches if clean and specific rev given |
632 pa = p1 |
632 pa = p1 |
633 |
633 |
634 ### calculate phase |
634 ### calculate phase |
635 action = calculateupdates(repo, wc, p2, pa, branchmerge, force, partial) |
635 actions = calculateupdates(repo, wc, p2, pa, |
|
636 branchmerge, force, partial) |
636 |
637 |
637 ### apply phase |
638 ### apply phase |
638 if not branchmerge: # just jump to the new rev |
639 if not branchmerge: # just jump to the new rev |
639 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
640 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
640 if not partial: |
641 if not partial: |
641 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
642 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
642 |
643 |
643 stats = applyupdates(repo, action, wc, p2, pa, overwrite) |
644 stats = applyupdates(repo, actions, wc, p2, pa, overwrite) |
644 |
645 |
645 if not partial: |
646 if not partial: |
646 repo.setparents(fp1, fp2) |
647 repo.setparents(fp1, fp2) |
647 recordupdates(repo, action, branchmerge) |
648 recordupdates(repo, actions, branchmerge) |
648 if not branchmerge: |
649 if not branchmerge: |
649 repo.dirstate.setbranch(p2.branch()) |
650 repo.dirstate.setbranch(p2.branch()) |
650 finally: |
651 finally: |
651 wlock.release() |
652 wlock.release() |
652 |
653 |