175 def manifestmerge(repo, p1, p2, pa, overwrite, partial): |
175 def manifestmerge(repo, p1, p2, pa, overwrite, partial): |
176 """ |
176 """ |
177 Merge manifest m1 with m2 using ancestor ma and generate merge action list |
177 Merge manifest m1 with m2 using ancestor ma and generate merge action list |
178 """ |
178 """ |
179 |
179 |
|
180 repo.ui.note(_("resolving manifests\n")) |
|
181 repo.ui.debug(_(" overwrite %s partial %s\n") % (overwrite, bool(partial))) |
|
182 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (pa, p1, p2)) |
|
183 |
180 m1 = p1.manifest() |
184 m1 = p1.manifest() |
181 m2 = p2.manifest() |
185 m2 = p2.manifest() |
182 ma = pa.manifest() |
186 ma = pa.manifest() |
183 backwards = (pa == p2) |
187 backwards = (pa == p2) |
|
188 action = [] |
|
189 copy = {} |
184 |
190 |
185 def fmerge(f, f2=None, fa=None): |
191 def fmerge(f, f2=None, fa=None): |
186 """merge executable flags""" |
192 """merge executable flags""" |
187 if not f2: |
193 if not f2: |
188 f2 = f |
194 f2 = f |
189 fa = f |
195 fa = f |
190 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2) |
196 a, b, c = ma.execf(fa), m1.execf(f), m2.execf(f2) |
191 return ((a^b) | (a^c)) ^ a |
197 return ((a^b) | (a^c)) ^ a |
192 |
198 |
193 action = [] |
|
194 |
|
195 def act(msg, m, f, *args): |
199 def act(msg, m, f, *args): |
196 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) |
200 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m)) |
197 action.append((f, m) + args) |
201 action.append((f, m) + args) |
198 |
202 |
199 copy = {} |
|
200 if not (backwards or overwrite): |
203 if not (backwards or overwrite): |
201 copy = findcopies(repo, m1, m2, pa.rev()) |
204 copy = findcopies(repo, m1, m2, pa.rev()) |
202 |
205 |
203 # Compare manifests |
206 # Compare manifests |
204 for f, n in m1.iteritems(): |
207 for f, n in m1.iteritems(): |
353 repo.dirstate.copy(f2, fd) |
356 repo.dirstate.copy(f2, fd) |
354 |
357 |
355 def update(repo, node, branchmerge=False, force=False, partial=None, |
358 def update(repo, node, branchmerge=False, force=False, partial=None, |
356 wlock=None, show_stats=True, remind=True): |
359 wlock=None, show_stats=True, remind=True): |
357 |
360 |
|
361 if not wlock: |
|
362 wlock = repo.wlock() |
|
363 |
358 overwrite = force and not branchmerge |
364 overwrite = force and not branchmerge |
359 forcemerge = force and branchmerge |
365 forcemerge = force and branchmerge |
360 |
|
361 if not wlock: |
|
362 wlock = repo.wlock() |
|
363 |
|
364 ### check phase |
|
365 |
|
366 wc = repo.workingctx() |
366 wc = repo.workingctx() |
367 pl = wc.parents() |
367 pl = wc.parents() |
|
368 p1, p2 = pl[0], repo.changectx(node) |
|
369 pa = p1.ancestor(p2) |
|
370 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
|
371 |
|
372 ### check phase |
368 if not overwrite and len(pl) > 1: |
373 if not overwrite and len(pl) > 1: |
369 raise util.Abort(_("outstanding uncommitted merges")) |
374 raise util.Abort(_("outstanding uncommitted merges")) |
370 |
375 if pa == p1 or pa == p2: # is there a linear path from p1 to p2? |
371 p1, p2 = pl[0], repo.changectx(node) |
|
372 pa = p1.ancestor(p2) |
|
373 |
|
374 # is there a linear path from p1 to p2? |
|
375 if pa == p1 or pa == p2: |
|
376 if branchmerge: |
376 if branchmerge: |
377 raise util.Abort(_("there is nothing to merge, just use " |
377 raise util.Abort(_("there is nothing to merge, just use " |
378 "'hg update' or look at 'hg heads'")) |
378 "'hg update' or look at 'hg heads'")) |
379 elif not (overwrite or branchmerge): |
379 elif not (overwrite or branchmerge): |
380 raise util.Abort(_("update spans branches, use 'hg merge' " |
380 raise util.Abort(_("update spans branches, use 'hg merge' " |
381 "or 'hg update -C' to lose changes")) |
381 "or 'hg update -C' to lose changes")) |
382 |
|
383 if branchmerge and not forcemerge: |
382 if branchmerge and not forcemerge: |
384 if wc.modified() or wc.added() or wc.removed(): |
383 if wc.modified() or wc.added() or wc.removed(): |
385 raise util.Abort(_("outstanding uncommitted changes")) |
384 raise util.Abort(_("outstanding uncommitted changes")) |
386 |
385 |
387 # resolve the manifest to determine which files |
386 ### calculate phase |
388 # we care about merging |
|
389 repo.ui.note(_("resolving manifests\n")) |
|
390 repo.ui.debug(_(" overwrite %s branchmerge %s partial %s\n") % |
|
391 (overwrite, branchmerge, bool(partial))) |
|
392 repo.ui.debug(_(" ancestor %s local %s remote %s\n") % (p1, p2, pa)) |
|
393 |
|
394 action = [] |
387 action = [] |
395 |
|
396 if not force: |
388 if not force: |
397 checkunknown(wc, p2) |
389 checkunknown(wc, p2) |
398 if not branchmerge: |
390 if not branchmerge: |
399 action += forgetremoved(wc, p2) |
391 action += forgetremoved(wc, p2) |
400 |
|
401 action += manifestmerge(repo, wc, p2, pa, overwrite, partial) |
392 action += manifestmerge(repo, wc, p2, pa, overwrite, partial) |
402 |
393 |
403 ### apply phase |
394 ### apply phase |
404 |
395 if not branchmerge: # just jump to the new rev |
405 if not branchmerge: |
396 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, '' |
406 # just jump to the new rev |
|
407 fp1, fp2, xp1, xp2 = p2.node(), nullid, str(p2), '' |
|
408 else: |
|
409 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2) |
|
410 |
|
411 if not partial: |
397 if not partial: |
412 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
398 repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2) |
413 |
399 |
414 updated, merged, removed, unresolved = applyupdates(repo, action, wc, p2) |
400 updated, merged, removed, unresolved = applyupdates(repo, action, wc, p2) |
415 |
|
416 # update dirstate |
|
417 if not partial: |
|
418 recordupdates(repo, action, branchmerge, p2) |
|
419 repo.dirstate.setparents(fp1, fp2) |
|
420 repo.hook('update', parent1=xp1, parent2=xp2, error=unresolved) |
|
421 |
401 |
422 if show_stats: |
402 if show_stats: |
423 stats = ((updated, _("updated")), |
403 stats = ((updated, _("updated")), |
424 (merged - unresolved, _("merged")), |
404 (merged - unresolved, _("merged")), |
425 (removed, _("removed")), |
405 (removed, _("removed")), |
426 (unresolved, _("unresolved"))) |
406 (unresolved, _("unresolved"))) |
427 note = ", ".join([_("%d files %s") % s for s in stats]) |
407 note = ", ".join([_("%d files %s") % s for s in stats]) |
428 repo.ui.status("%s\n" % note) |
408 repo.ui.status("%s\n" % note) |
429 if not partial: |
409 if not partial: |
|
410 recordupdates(repo, action, branchmerge, p2) |
|
411 repo.dirstate.setparents(fp1, fp2) |
|
412 repo.hook('update', parent1=xp1, parent2=xp2, error=unresolved) |
|
413 |
430 if branchmerge: |
414 if branchmerge: |
431 if unresolved: |
415 if unresolved: |
432 repo.ui.status(_("There are unresolved merges," |
416 repo.ui.status(_("There are unresolved merges," |
433 " you can redo the full merge using:\n" |
417 " you can redo the full merge using:\n" |
434 " hg update -C %s\n" |
418 " hg update -C %s\n" |