diff --git a/hgext/convert/hg.py b/hgext/convert/hg.py --- a/hgext/convert/hg.py +++ b/hgext/convert/hg.py @@ -217,7 +217,7 @@ """ anc = [p1ctx.ancestor(p2ctx)] # Calculate what files are coming from p2 - actions, diverge, rename = mergemod.calculateupdates( + mresult = mergemod.calculateupdates( self.repo, p1ctx, p2ctx, @@ -228,7 +228,7 @@ followcopies=False, ) - for file, (action, info, msg) in pycompat.iteritems(actions): + for file, (action, info, msg) in pycompat.iteritems(mresult.actions): if source.targetfilebelongstosource(file): # If the file belongs to the source repo, ignore the p2 # since it will be covered by the existing fileset. diff --git a/hgext/largefiles/overrides.py b/hgext/largefiles/overrides.py --- a/hgext/largefiles/overrides.py +++ b/hgext/largefiles/overrides.py @@ -543,16 +543,16 @@ origfn, repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs ): overwrite = force and not branchmerge - actions, diverge, renamedelete = origfn( + mresult = origfn( repo, p1, p2, pas, branchmerge, force, acceptremote, *args, **kwargs ) if overwrite: - return actions, diverge, renamedelete + return mresult # Convert to dictionary with filename as key and action as value. lfiles = set() - for f in actions: + for f in mresult.actions: splitstandin = lfutil.splitstandin(f) if splitstandin is not None and splitstandin in p1: lfiles.add(splitstandin) @@ -561,8 +561,8 @@ for lfile in sorted(lfiles): standin = lfutil.standin(lfile) - (lm, largs, lmsg) = actions.get(lfile, (None, None, None)) - (sm, sargs, smsg) = actions.get(standin, (None, None, None)) + (lm, largs, lmsg) = mresult.actions.get(lfile, (None, None, None)) + (sm, sargs, smsg) = mresult.actions.get(standin, (None, None, None)) if sm in (b'g', b'dc') and lm != b'r': if sm == b'dc': f1, f2, fa, move, anc = sargs @@ -578,14 +578,22 @@ % lfile ) if repo.ui.promptchoice(usermsg, 0) == 0: # pick remote largefile - actions[lfile] = (b'r', None, b'replaced by standin') - actions[standin] = (b'g', sargs, b'replaces standin') + mresult.actions[lfile] = (b'r', None, b'replaced by standin') + mresult.actions[standin] = (b'g', sargs, b'replaces standin') else: # keep local normal file - actions[lfile] = (b'k', None, b'replaces standin') + mresult.actions[lfile] = (b'k', None, b'replaces standin') if branchmerge: - actions[standin] = (b'k', None, b'replaced by non-standin') + mresult.actions[standin] = ( + b'k', + None, + b'replaced by non-standin', + ) else: - actions[standin] = (b'r', None, b'replaced by non-standin') + mresult.actions[standin] = ( + b'r', + None, + b'replaced by non-standin', + ) elif lm in (b'g', b'dc') and sm != b'r': if lm == b'dc': f1, f2, fa, move, anc = largs @@ -603,24 +611,32 @@ if repo.ui.promptchoice(usermsg, 0) == 0: # keep local largefile if branchmerge: # largefile can be restored from standin safely - actions[lfile] = (b'k', None, b'replaced by standin') - actions[standin] = (b'k', None, b'replaces standin') + mresult.actions[lfile] = ( + b'k', + None, + b'replaced by standin', + ) + mresult.actions[standin] = (b'k', None, b'replaces standin') else: # "lfile" should be marked as "removed" without # removal of itself - actions[lfile] = ( + mresult.actions[lfile] = ( b'lfmr', None, b'forget non-standin largefile', ) # linear-merge should treat this largefile as 're-added' - actions[standin] = (b'a', None, b'keep standin') + mresult.actions[standin] = (b'a', None, b'keep standin') else: # pick remote normal file - actions[lfile] = (b'g', largs, b'replaces standin') - actions[standin] = (b'r', None, b'replaced by non-standin') + mresult.actions[lfile] = (b'g', largs, b'replaces standin') + mresult.actions[standin] = ( + b'r', + None, + b'replaced by non-standin', + ) - return actions, diverge, renamedelete + return mresult @eh.wrapfunction(mergestatemod, b'recordupdates') diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -540,6 +540,40 @@ ) +class mergeresult(object): + ''''An object representing result of merging manifests. + + It has information about what actions need to be performed on dirstate + mapping of divergent renames and other such cases. ''' + + def __init__(self, actions, diverge, renamedelete): + """ + actions: dict of filename as keys and action related info as values + diverge: mapping of source name -> list of dest name for divergent renames + renamedelete: mapping of source name -> list of destinations for files + deleted on one side and renamed on other. + """ + + self._actions = actions + self._diverge = diverge + self._renamedelete = renamedelete + + @property + def actions(self): + return self._actions + + @property + def diverge(self): + return self._diverge + + @property + def renamedelete(self): + return self._renamedelete + + def setactions(self, actions): + self._actions = actions + + def manifestmerge( repo, wctx, @@ -559,12 +593,7 @@ matcher = matcher to filter file lists acceptremote = accept the incoming changes without prompting - Returns: - - actions: dict of filename as keys and action related info as values - diverge: mapping of source name -> list of dest name for divergent renames - renamedelete: mapping of source name -> list of destinations for files - deleted on one side and renamed on other. + Returns an object of mergeresult class """ if matcher is not None and matcher.always(): matcher = None @@ -845,7 +874,7 @@ renamedelete = branch_copies1.renamedelete renamedelete.update(branch_copies2.renamedelete) - return actions, diverge, renamedelete + return mergeresult(actions, diverge, renamedelete) def _resolvetrivial(repo, wctx, mctx, ancestor, actions): @@ -891,13 +920,13 @@ Also filters out actions which are unrequired if repository is sparse. - Returns same 3 element tuple as manifestmerge(). + Returns mergeresult object same as manifestmerge(). """ # Avoid cycle. from . import sparse if len(ancestors) == 1: # default - actions, diverge, renamedelete = manifestmerge( + mresult = manifestmerge( repo, wctx, mctx, @@ -908,7 +937,7 @@ acceptremote, followcopies, ) - _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce) + _checkunknownfiles(repo, wctx, mctx, force, mresult.actions, mergeforce) else: # only when merge.preferancestor=* - the default repo.ui.note( @@ -927,7 +956,7 @@ diverge, renamedelete = None, None for ancestor in ancestors: repo.ui.note(_(b'\ncalculating bids for ancestor %s\n') % ancestor) - actions, diverge1, renamedelete1 = manifestmerge( + mresult1 = manifestmerge( repo, wctx, mctx, @@ -939,16 +968,20 @@ followcopies, forcefulldiff=True, ) - _checkunknownfiles(repo, wctx, mctx, force, actions, mergeforce) + _checkunknownfiles( + repo, wctx, mctx, force, mresult1.actions, mergeforce + ) # Track the shortest set of warning on the theory that bid # merge will correctly incorporate more information - if diverge is None or len(diverge1) < len(diverge): - diverge = diverge1 - if renamedelete is None or len(renamedelete) < len(renamedelete1): - renamedelete = renamedelete1 + if diverge is None or len(mresult1.diverge) < len(diverge): + diverge = mresult1.diverge + if renamedelete is None or len(renamedelete) < len( + mresult1.renamedelete + ): + renamedelete = mresult1.renamedelete - for f, a in sorted(pycompat.iteritems(actions)): + for f, a in sorted(pycompat.iteritems(mresult1.actions)): m, args, msg = a if m == mergestatemod.ACTION_GET_OTHER_AND_STORE: m = mergestatemod.ACTION_GET @@ -1000,17 +1033,19 @@ actions[f] = l[0] continue repo.ui.note(_(b'end of auction\n\n')) + mresult = mergeresult(actions, diverge, renamedelete) if wctx.rev() is None: fractions = _forgetremoved(wctx, mctx, branchmerge) - actions.update(fractions) + mresult.actions.update(fractions) prunedactions = sparse.filterupdatesactions( - repo, wctx, mctx, branchmerge, actions + repo, wctx, mctx, branchmerge, mresult.actions ) - _resolvetrivial(repo, wctx, mctx, ancestors[0], actions) + _resolvetrivial(repo, wctx, mctx, ancestors[0], mresult.actions) - return prunedactions, diverge, renamedelete + mresult.setactions(prunedactions) + return mresult def _getcwd(): @@ -1734,7 +1769,7 @@ followcopies = False ### calculate phase - actionbyfile, diverge, renamedelete = calculateupdates( + mresult = calculateupdates( repo, wc, p2, @@ -1747,6 +1782,8 @@ mergeforce=mergeforce, ) + actionbyfile = mresult.actions + if updatecheck == UPDATECHECK_NO_CONFLICT: for f, (m, args, msg) in pycompat.iteritems(actionbyfile): if m not in ( @@ -1840,7 +1877,7 @@ _checkcollision(repo, wc.manifest(), actions) # divergent renames - for f, fl in sorted(pycompat.iteritems(diverge)): + for f, fl in sorted(pycompat.iteritems(mresult.diverge)): repo.ui.warn( _( b"note: possible conflict - %s was renamed " @@ -1852,7 +1889,7 @@ repo.ui.warn(b" %s\n" % nf) # rename and delete - for f, fl in sorted(pycompat.iteritems(renamedelete)): + for f, fl in sorted(pycompat.iteritems(mresult.renamedelete)): repo.ui.warn( _( b"note: possible conflict - %s was deleted "