mercurial/merge.py
branchstable
changeset 19105 c60a7f5a741f
parent 19095 5cc71484ee9c
child 19157 113681bbef9e
equal deleted inserted replaced
19104:370d9ea027b1 19105:c60a7f5a741f
   108             wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
   108             wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
   109     if error:
   109     if error:
   110         raise util.Abort(_("untracked files in working directory differ "
   110         raise util.Abort(_("untracked files in working directory differ "
   111                            "from files in requested revision"))
   111                            "from files in requested revision"))
   112 
   112 
   113 def _remains(f, m, ma, workingctx=False):
       
   114     """check whether specified file remains after merge.
       
   115 
       
   116     It is assumed that specified file is not contained in the manifest
       
   117     of the other context.
       
   118     """
       
   119     if f in ma:
       
   120         n = m[f]
       
   121         if n != ma[f]:
       
   122             return True # because it is changed locally
       
   123             # even though it doesn't remain, if "remote deleted" is
       
   124             # chosen in manifestmerge()
       
   125         elif workingctx and n[20:] == "a":
       
   126             return True # because it is added locally (linear merge specific)
       
   127         else:
       
   128             return False # because it is removed remotely
       
   129     else:
       
   130         return True # because it is added locally
       
   131 
       
   132 def _checkcollision(mctx, extractxs):
       
   133     "check for case folding collisions in the destination context"
       
   134     folded = {}
       
   135     for fn in mctx:
       
   136         fold = util.normcase(fn)
       
   137         if fold in folded:
       
   138             raise util.Abort(_("case-folding collision between %s and %s")
       
   139                              % (fn, folded[fold]))
       
   140         folded[fold] = fn
       
   141 
       
   142     if extractxs:
       
   143         wctx, actx = extractxs
       
   144         # class to delay looking up copy mapping
       
   145         class pathcopies(object):
       
   146             @util.propertycache
       
   147             def map(self):
       
   148                 # {dst@mctx: src@wctx} copy mapping
       
   149                 return copies.pathcopies(wctx, mctx)
       
   150         pc = pathcopies()
       
   151 
       
   152         for fn in wctx:
       
   153             fold = util.normcase(fn)
       
   154             mfn = folded.get(fold, None)
       
   155             if (mfn and mfn != fn and pc.map.get(mfn) != fn and
       
   156                 _remains(fn, wctx.manifest(), actx.manifest(), True) and
       
   157                 _remains(mfn, mctx.manifest(), actx.manifest())):
       
   158                 raise util.Abort(_("case-folding collision between %s and %s")
       
   159                                  % (mfn, fn))
       
   160 
       
   161 def _forgetremoved(wctx, mctx, branchmerge):
   113 def _forgetremoved(wctx, mctx, branchmerge):
   162     """
   114     """
   163     Forget removed files
   115     Forget removed files
   164 
   116 
   165     If we're jumping between revisions (as opposed to merging), and if
   117     If we're jumping between revisions (as opposed to merging), and if
   183         for f in wctx.removed():
   135         for f in wctx.removed():
   184             if f not in mctx:
   136             if f not in mctx:
   185                 actions.append((f, "f", None, "forget removed"))
   137                 actions.append((f, "f", None, "forget removed"))
   186 
   138 
   187     return actions
   139     return actions
       
   140 
       
   141 def _checkcollision(repo, wmf, actions, prompts):
       
   142     # build provisional merged manifest up
       
   143     pmmf = set(wmf)
       
   144 
       
   145     def addop(f, args):
       
   146         pmmf.add(f)
       
   147     def removeop(f, args):
       
   148         pmmf.discard(f)
       
   149     def nop(f, args):
       
   150         pass
       
   151 
       
   152     def renameop(f, args):
       
   153         f2, fd, flags = args
       
   154         if f:
       
   155             pmmf.discard(f)
       
   156         pmmf.add(fd)
       
   157     def mergeop(f, args):
       
   158         f2, fd, move = args
       
   159         if move:
       
   160             pmmf.discard(f)
       
   161         pmmf.add(fd)
       
   162 
       
   163     opmap = {
       
   164         "a": addop,
       
   165         "d": renameop,
       
   166         "dr": nop,
       
   167         "e": nop,
       
   168         "f": addop, # untracked file should be kept in working directory
       
   169         "g": addop,
       
   170         "m": mergeop,
       
   171         "r": removeop,
       
   172         "rd": nop,
       
   173     }
       
   174     for f, m, args, msg in actions:
       
   175         op = opmap.get(m)
       
   176         assert op, m
       
   177         op(f, args)
       
   178 
       
   179     opmap = {
       
   180         "cd": addop,
       
   181         "dc": addop,
       
   182     }
       
   183     for f, m in prompts:
       
   184         op = opmap.get(m)
       
   185         assert op, m
       
   186         op(f, None)
       
   187 
       
   188     # check case-folding collision in provisional merged manifest
       
   189     foldmap = {}
       
   190     for f in sorted(pmmf):
       
   191         fold = util.normcase(f)
       
   192         if fold in foldmap:
       
   193             raise util.Abort(_("case-folding collision between %s and %s")
       
   194                              % (f, foldmap[fold]))
       
   195         foldmap[fold] = f
   188 
   196 
   189 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
   197 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
   190                   acceptremote=False):
   198                   acceptremote=False):
   191     """
   199     """
   192     Merge p1 and p2 with ancestor pa and generate merge action list
   200     Merge p1 and p2 with ancestor pa and generate merge action list
   340         else: assert False, m
   348         else: assert False, m
   341     if aborts:
   349     if aborts:
   342         raise util.Abort(_("untracked files in working directory differ "
   350         raise util.Abort(_("untracked files in working directory differ "
   343                            "from files in requested revision"))
   351                            "from files in requested revision"))
   344 
   352 
       
   353     if not util.checkcase(repo.path):
       
   354         # check collision between files only in p2 for clean update
       
   355         if (not branchmerge and
       
   356             (force or not wctx.dirty(missing=True, branch=False))):
       
   357             _checkcollision(repo, m2, [], [])
       
   358         else:
       
   359             _checkcollision(repo, m1, actions, prompts)
       
   360 
   345     for f, m in sorted(prompts):
   361     for f, m in sorted(prompts):
   346         if m == "cd":
   362         if m == "cd":
   347             if acceptremote:
   363             if acceptremote:
   348                 actions.append((f, "r", None, "remote delete"))
   364                 actions.append((f, "r", None, "remote delete"))
   349             elif repo.ui.promptchoice(
   365             elif repo.ui.promptchoice(
   539 
   555 
   540 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial,
   556 def calculateupdates(repo, tctx, mctx, ancestor, branchmerge, force, partial,
   541                      acceptremote=False):
   557                      acceptremote=False):
   542     "Calculate the actions needed to merge mctx into tctx"
   558     "Calculate the actions needed to merge mctx into tctx"
   543     actions = []
   559     actions = []
   544     folding = not util.checkcase(repo.path)
       
   545     if folding:
       
   546         # collision check is not needed for clean update
       
   547         if (not branchmerge and
       
   548             (force or not tctx.dirty(missing=True, branch=False))):
       
   549             _checkcollision(mctx, None)
       
   550         else:
       
   551             _checkcollision(mctx, (tctx, ancestor))
       
   552     actions += manifestmerge(repo, tctx, mctx,
   560     actions += manifestmerge(repo, tctx, mctx,
   553                              ancestor,
   561                              ancestor,
   554                              branchmerge, force,
   562                              branchmerge, force,
   555                              partial, acceptremote)
   563                              partial, acceptremote)
   556     if tctx.rev() is None:
   564     if tctx.rev() is None: