mercurial/merge.py
changeset 3111 5cc62d99b785
parent 3110 40e777bda455
child 3112 f96c8e219865
equal deleted inserted replaced
3110:40e777bda455 3111: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")),