diff -r 370d9ea027b1 -r c60a7f5a741f mercurial/merge.py --- a/mercurial/merge.py Tue Apr 30 05:01:32 2013 +0900 +++ b/mercurial/merge.py Tue Apr 30 05:01:32 2013 +0900 @@ -110,54 +110,6 @@ raise util.Abort(_("untracked files in working directory differ " "from files in requested revision")) -def _remains(f, m, ma, workingctx=False): - """check whether specified file remains after merge. - - It is assumed that specified file is not contained in the manifest - of the other context. - """ - if f in ma: - n = m[f] - if n != ma[f]: - return True # because it is changed locally - # even though it doesn't remain, if "remote deleted" is - # chosen in manifestmerge() - elif workingctx and n[20:] == "a": - return True # because it is added locally (linear merge specific) - else: - return False # because it is removed remotely - else: - return True # because it is added locally - -def _checkcollision(mctx, extractxs): - "check for case folding collisions in the destination context" - folded = {} - for fn in mctx: - fold = util.normcase(fn) - if fold in folded: - raise util.Abort(_("case-folding collision between %s and %s") - % (fn, folded[fold])) - folded[fold] = fn - - if extractxs: - wctx, actx = extractxs - # class to delay looking up copy mapping - class pathcopies(object): - @util.propertycache - def map(self): - # {dst@mctx: src@wctx} copy mapping - return copies.pathcopies(wctx, mctx) - pc = pathcopies() - - for fn in wctx: - fold = util.normcase(fn) - mfn = folded.get(fold, None) - if (mfn and mfn != fn and pc.map.get(mfn) != fn and - _remains(fn, wctx.manifest(), actx.manifest(), True) and - _remains(mfn, mctx.manifest(), actx.manifest())): - raise util.Abort(_("case-folding collision between %s and %s") - % (mfn, fn)) - def _forgetremoved(wctx, mctx, branchmerge): """ Forget removed files @@ -186,6 +138,62 @@ return actions +def _checkcollision(repo, wmf, actions, prompts): + # build provisional merged manifest up + pmmf = set(wmf) + + def addop(f, args): + pmmf.add(f) + def removeop(f, args): + pmmf.discard(f) + def nop(f, args): + pass + + def renameop(f, args): + f2, fd, flags = args + if f: + pmmf.discard(f) + pmmf.add(fd) + def mergeop(f, args): + f2, fd, move = args + if move: + pmmf.discard(f) + pmmf.add(fd) + + opmap = { + "a": addop, + "d": renameop, + "dr": nop, + "e": nop, + "f": addop, # untracked file should be kept in working directory + "g": addop, + "m": mergeop, + "r": removeop, + "rd": nop, + } + for f, m, args, msg in actions: + op = opmap.get(m) + assert op, m + op(f, args) + + opmap = { + "cd": addop, + "dc": addop, + } + for f, m in prompts: + op = opmap.get(m) + assert op, m + op(f, None) + + # check case-folding collision in provisional merged manifest + foldmap = {} + for f in sorted(pmmf): + fold = util.normcase(f) + if fold in foldmap: + raise util.Abort(_("case-folding collision between %s and %s") + % (f, foldmap[fold])) + foldmap[fold] = f + def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial, acceptremote=False): """ @@ -342,6 +350,14 @@ raise util.Abort(_("untracked files in working directory differ " "from files in requested revision")) + if not util.checkcase(repo.path): + # check collision between files only in p2 for clean update + if (not branchmerge and + (force or not wctx.dirty(missing=True, branch=False))): + _checkcollision(repo, m2, [], []) + else: + _checkcollision(repo, m1, actions, prompts) + for f, m in sorted(prompts): if m == "cd": if acceptremote: @@ -541,14 +557,6 @@ acceptremote=False): "Calculate the actions needed to merge mctx into tctx" actions = [] - folding = not util.checkcase(repo.path) - if folding: - # collision check is not needed for clean update - if (not branchmerge and - (force or not tctx.dirty(missing=True, branch=False))): - _checkcollision(mctx, None) - else: - _checkcollision(mctx, (tctx, ancestor)) actions += manifestmerge(repo, tctx, mctx, ancestor, branchmerge, force,