mercurial/merge.py
changeset 5344 cc34be74eeec
parent 5210 90d9ec0dc69d
child 5371 17ed9b9a0d03
equal deleted inserted replaced
5343:26692d08c2f9 5344:cc34be74eeec
   446             f2, fd, flags, move = a[2:]
   446             f2, fd, flags, move = a[2:]
   447             if f != fd:
   447             if f != fd:
   448                 repo.ui.debug(_("copying %s to %s\n") % (f, fd))
   448                 repo.ui.debug(_("copying %s to %s\n") % (f, fd))
   449                 repo.wwrite(fd, repo.wread(f), flags)
   449                 repo.wwrite(fd, repo.wread(f), flags)
   450 
   450 
       
   451     audit_path = util.path_auditor(repo.root)
       
   452 
   451     for a in action:
   453     for a in action:
   452         f, m = a[:2]
   454         f, m = a[:2]
   453         if f and f[0] == "/":
   455         if f and f[0] == "/":
   454             continue
   456             continue
   455         if m == "r": # remove
   457         if m == "r": # remove
   456             repo.ui.note(_("removing %s\n") % f)
   458             repo.ui.note(_("removing %s\n") % f)
   457             util.audit_path(f)
   459             audit_path(f)
   458             try:
   460             try:
   459                 util.unlink(repo.wjoin(f))
   461                 util.unlink(repo.wjoin(f))
   460             except OSError, inst:
   462             except OSError, inst:
   461                 if inst.errno != errno.ENOENT:
   463                 if inst.errno != errno.ENOENT:
   462                     repo.ui.warn(_("update failed to remove %s: %s!\n") %
   464                     repo.ui.warn(_("update failed to remove %s: %s!\n") %
   510 
   512 
   511     for a in action:
   513     for a in action:
   512         f, m = a[:2]
   514         f, m = a[:2]
   513         if m == "r": # remove
   515         if m == "r": # remove
   514             if branchmerge:
   516             if branchmerge:
   515                 repo.dirstate.update([f], 'r')
   517                 repo.dirstate.remove(f)
   516             else:
   518             else:
   517                 repo.dirstate.forget([f])
   519                 repo.dirstate.forget(f)
   518         elif m == "f": # forget
   520         elif m == "f": # forget
   519             repo.dirstate.forget([f])
   521             repo.dirstate.forget(f)
   520         elif m in "ge": # get or exec change
   522         elif m in "ge": # get or exec change
   521             if branchmerge:
   523             if branchmerge:
   522                 repo.dirstate.update([f], 'n', st_mtime=-1)
   524                 repo.dirstate.normaldirty(f)
   523             else:
   525             else:
   524                 repo.dirstate.update([f], 'n')
   526                 repo.dirstate.normal(f)
   525         elif m == "m": # merge
   527         elif m == "m": # merge
   526             f2, fd, flag, move = a[2:]
   528             f2, fd, flag, move = a[2:]
   527             if branchmerge:
   529             if branchmerge:
   528                 # We've done a branch merge, mark this file as merged
   530                 # We've done a branch merge, mark this file as merged
   529                 # so that we properly record the merger later
   531                 # so that we properly record the merger later
   530                 repo.dirstate.update([fd], 'm')
   532                 repo.dirstate.merge(fd)
   531                 if f != f2: # copy/rename
   533                 if f != f2: # copy/rename
   532                     if move:
   534                     if move:
   533                         repo.dirstate.update([f], 'r')
   535                         repo.dirstate.remove(f)
   534                     if f != fd:
   536                     if f != fd:
   535                         repo.dirstate.copy(f, fd)
   537                         repo.dirstate.copy(f, fd)
   536                     else:
   538                     else:
   537                         repo.dirstate.copy(f2, fd)
   539                         repo.dirstate.copy(f2, fd)
   538             else:
   540             else:
   539                 # We've update-merged a locally modified file, so
   541                 # We've update-merged a locally modified file, so
   540                 # we set the dirstate to emulate a normal checkout
   542                 # we set the dirstate to emulate a normal checkout
   541                 # of that file some time in the past. Thus our
   543                 # of that file some time in the past. Thus our
   542                 # merge will appear as a normal local file
   544                 # merge will appear as a normal local file
   543                 # modification.
   545                 # modification.
   544                 repo.dirstate.update([fd], 'n', st_size=-1, st_mtime=-1)
   546                 repo.dirstate.normallookup(fd)
   545                 if move:
   547                 if move:
   546                     repo.dirstate.forget([f])
   548                     repo.dirstate.forget(f)
   547         elif m == "d": # directory rename
   549         elif m == "d": # directory rename
   548             f2, fd, flag = a[2:]
   550             f2, fd, flag = a[2:]
   549             if not f2 and f not in repo.dirstate:
   551             if not f2 and f not in repo.dirstate:
   550                 # untracked file moved
   552                 # untracked file moved
   551                 continue
   553                 continue
   552             if branchmerge:
   554             if branchmerge:
   553                 repo.dirstate.update([fd], 'a')
   555                 repo.dirstate.add(fd)
   554                 if f:
   556                 if f:
   555                     repo.dirstate.update([f], 'r')
   557                     repo.dirstate.remove(f)
   556                     repo.dirstate.copy(f, fd)
   558                     repo.dirstate.copy(f, fd)
   557                 if f2:
   559                 if f2:
   558                     repo.dirstate.copy(f2, fd)
   560                     repo.dirstate.copy(f2, fd)
   559             else:
   561             else:
   560                 repo.dirstate.update([fd], 'n')
   562                 repo.dirstate.normal(fd)
   561                 if f:
   563                 if f:
   562                     repo.dirstate.forget([f])
   564                     repo.dirstate.forget(f)
   563 
   565 
   564 def update(repo, node, branchmerge, force, partial, wlock):
   566 def update(repo, node, branchmerge, force, partial):
   565     """
   567     """
   566     Perform a merge between the working directory and the given node
   568     Perform a merge between the working directory and the given node
   567 
   569 
   568     branchmerge = whether to merge between branches
   570     branchmerge = whether to merge between branches
   569     force = whether to force branch merging or file overwriting
   571     force = whether to force branch merging or file overwriting
   570     partial = a function to filter file lists (dirstate not updated)
   572     partial = a function to filter file lists (dirstate not updated)
   571     wlock = working dir lock, if already held
   573     """
   572     """
   574 
   573 
   575     wlock = repo.wlock()
   574     if not wlock:
   576     try:
   575         wlock = repo.wlock()
   577         wc = repo.workingctx()
   576 
   578         if node is None:
   577     wc = repo.workingctx()
   579             # tip of current branch
   578     if node is None:
   580             try:
   579         # tip of current branch
   581                 node = repo.branchtags()[wc.branch()]
   580         try:
   582             except KeyError:
   581             node = repo.branchtags()[wc.branch()]
   583                 raise util.Abort(_("branch %s not found") % wc.branch())
   582         except KeyError:
   584         overwrite = force and not branchmerge
   583             raise util.Abort(_("branch %s not found") % wc.branch())
   585         forcemerge = force and branchmerge
   584     overwrite = force and not branchmerge
   586         pl = wc.parents()
   585     forcemerge = force and branchmerge
   587         p1, p2 = pl[0], repo.changectx(node)
   586     pl = wc.parents()
   588         pa = p1.ancestor(p2)
   587     p1, p2 = pl[0], repo.changectx(node)
   589         fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
   588     pa = p1.ancestor(p2)
   590         fastforward = False
   589     fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
   591 
   590     fastforward = False
   592         ### check phase
   591 
   593         if not overwrite and len(pl) > 1:
   592     ### check phase
   594             raise util.Abort(_("outstanding uncommitted merges"))
   593     if not overwrite and len(pl) > 1:
   595         if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
   594         raise util.Abort(_("outstanding uncommitted merges"))
   596             if branchmerge:
   595     if pa == p1 or pa == p2: # is there a linear path from p1 to p2?
   597                 if p1.branch() != p2.branch() and pa != p2:
   596         if branchmerge:
   598                     fastforward = True
   597             if p1.branch() != p2.branch() and pa != p2:
   599                 else:
   598                 fastforward = True
   600                     raise util.Abort(_("there is nothing to merge, just use "
   599             else:
   601                                        "'hg update' or look at 'hg heads'"))
   600                 raise util.Abort(_("there is nothing to merge, just use "
   602         elif not (overwrite or branchmerge):
   601                                    "'hg update' or look at 'hg heads'"))
   603             raise util.Abort(_("update spans branches, use 'hg merge' "
   602     elif not (overwrite or branchmerge):
   604                                "or 'hg update -C' to lose changes"))
   603         raise util.Abort(_("update spans branches, use 'hg merge' "
   605         if branchmerge and not forcemerge:
   604                            "or 'hg update -C' to lose changes"))
   606             if wc.files():
   605     if branchmerge and not forcemerge:
   607                 raise util.Abort(_("outstanding uncommitted changes"))
   606         if wc.files():
   608 
   607             raise util.Abort(_("outstanding uncommitted changes"))
   609         ### calculate phase
   608 
   610         action = []
   609     ### calculate phase
   611         if not force:
   610     action = []
   612             checkunknown(wc, p2)
   611     if not force:
   613         if not util.checkfolding(repo.path):
   612         checkunknown(wc, p2)
   614             checkcollision(p2)
   613     if not util.checkfolding(repo.path):
   615         if not branchmerge:
   614         checkcollision(p2)
   616             action += forgetremoved(wc, p2)
   615     if not branchmerge:
   617         action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
   616         action += forgetremoved(wc, p2)
   618 
   617     action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
   619         ### apply phase
   618 
   620         if not branchmerge: # just jump to the new rev
   619     ### apply phase
   621             fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
   620     if not branchmerge: # just jump to the new rev
   622         if not partial:
   621         fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
   623             repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
   622     if not partial:
   624 
   623         repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
   625         stats = applyupdates(repo, action, wc, p2)
   624 
   626 
   625     stats = applyupdates(repo, action, wc, p2)
   627         if not partial:
   626 
   628             recordupdates(repo, action, branchmerge)
   627     if not partial:
   629             repo.dirstate.setparents(fp1, fp2)
   628         recordupdates(repo, action, branchmerge)
   630             if not branchmerge and not fastforward:
   629         repo.dirstate.setparents(fp1, fp2)
   631                 repo.dirstate.setbranch(p2.branch())
   630         if not branchmerge and not fastforward:
   632             repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
   631             repo.dirstate.setbranch(p2.branch())
   633 
   632         repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
   634         return stats
   633 
   635     finally:
   634     return stats
   636         del wlock
   635