##// END OF EJS Templates
interfaces: mark a few dirstate methods abstract...
interfaces: mark a few dirstate methods abstract I'm not sure what's going on here, but when enabling pytype checking on this package, it spits out the following errors: File "/mnt/c/Users/Matt/hg/mercurial/interfaces/dirstate.py", line 136, in changing_parents: bad return type [bad-return-type] Expected: Iterator Actually returned: None Attributes of protocol Iterator are not implemented on None: __next__ File "/mnt/c/Users/Matt/hg/mercurial/interfaces/dirstate.py", line 145, in changing_files: bad return type [bad-return-type] Expected: Iterator Actually returned: None Attributes of protocol Iterator are not implemented on None: __next__ I guess technically that's true, because these methods only have a doc comment, and don't explicitly return something or unconditionally raise an error. The strange thing is that both before and after this change, the *.pyi file that is generated is unchanged, and contains: def changing_files(self, repo) -> contextlib._GeneratorContextManager: ... def changing_parents(self, repo) -> contextlib._GeneratorContextManager: ... I'm not sure if the `@abstractmethod` should be the most inner or most outer decoration. We'll roll the dice with being the innermost, because that's how `@abstractproperty` says it should be used in conjunction with `@property`. We should probably make all of the methods without an actual body abstract, like was done for some `mercurial.wireprototypes` classes in fd200f5bcaea. But let's hold off for now and do that enmass later.

File last commit:

r53083:e6a44bc9 stable
r53328:2c8c46c3 default
Show More
merge.py
2655 lines | 95.9 KiB | text/x-python | PythonLexer
Matt Mackall
Move merge code to its own module...
r2775 # merge.py - directory-level update/merge handling for Mercurial
#
Raphaël Gomès
contributor: change mentions of mpm to olivia...
r47575 # Copyright 2006, 2007 Olivia Mackall <olivia@selenic.com>
Matt Mackall
Move merge code to its own module...
r2775 #
Martin Geisler
updated license to be explicit about GPL version 2
r8225 # This software may be used and distributed according to the terms of the
Matt Mackall
Update license to GPLv2+
r10263 # GNU General Public License version 2 or any later version.
Matt Mackall
Move merge code to its own module...
r2775
Matt Harbison
typing: add `from __future__ import annotations` to most files...
r52756 from __future__ import annotations
Gregory Szorc
merge: use absolute_import
r25959
Pulkit Goyal
mergeresult: introduce action -> (filename, data, msg) mapping and related API...
r45849 import collections
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 import os
Pierre-Yves David
merge: introduce new format for the state file...
r20590 import struct
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622 import typing
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951 from typing import Dict, Optional, Tuple
Pierre-Yves David
merge: introduce new format for the state file...
r20590
Gregory Szorc
merge: use absolute_import
r25959 from .i18n import _
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 from .node import nullrev
Augie Fackler
formatting: blacken the codebase...
r43346 from .thirdparty import attr
Matt Harbison
typing: induce pytype to use the standard `attr` instead of the vendored copy...
r52622
# Force pytype to use the non-vendored package
if typing.TYPE_CHECKING:
# noinspection PyPackageRequirements
import attr
Matt Harbison
merge: force an exception message to bytes before printing as a warning...
r47519 from .utils import stringutil
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 from .dirstateutils import timestamp
Gregory Szorc
merge: use absolute_import
r25959 from . import (
copies,
Matt Harbison
py3: rename pycompat.getcwd() to encoding.getcwd() (API)...
r39843 encoding,
Pierre-Yves David
error: get Abort from 'error' instead of 'util'...
r26587 error,
Gregory Szorc
merge: use absolute_import
r25959 filemerge,
Durham Goode
merge: remove uses of manifest.matches...
r31257 match as matchmod,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestate as mergestatemod,
obsutil: move 'foreground' to the new modules...
r33147 obsutil,
Martin von Zweigbergk
utils: move finddirs() to pathutil...
r44032 pathutil,
Raphaël Gomès
merge: remove direct rustmod reference...
r49660 policy,
Pulkit Goyal
py3: use pycompat.getcwd() instead of os.getcwd()...
r30519 pycompat,
Siddharth Agarwal
batchget: add support for backing up files...
r27656 scmutil,
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 subrepoutil,
Gregory Szorc
merge: use absolute_import
r25959 util,
worker,
)
Matt Mackall
merge: introduce mergestate
r6512
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 rust_update_mod = policy.importrust("update")
Pierre-Yves David
merge: introduce new format for the state file...
r20590 _pack = struct.pack
_unpack = struct.unpack
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
merge: factor out code to get checkunknown config...
r27740 def _getcheckunknownconfig(repo, section, name):
Boris Feld
configitems: register 'merge.checkunknown' and 'merge.checkignored'...
r34523 config = repo.ui.config(section, name)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 valid = [b'abort', b'ignore', b'warn']
Siddharth Agarwal
merge: factor out code to get checkunknown config...
r27740 if config not in valid:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 validstr = b', '.join([b"'" + v + b"'" for v in valid])
merge: break up a not-so-one-liner for readability...
r49547 msg = _(b"%s.%s not valid ('%s' is none of %s)")
msg %= (section, name, config, validstr)
raise error.ConfigError(msg)
Siddharth Agarwal
merge: factor out code to get checkunknown config...
r27740 return config
Augie Fackler
formatting: blacken the codebase...
r43346
Arseniy Alekseyev
merge: avoid dereferencing repo fields repeatedly
r50805 def _checkunknownfile(dirstate, wvfs, dircache, wctx, mctx, f, f2=None):
Phil Cohen
merge: don't check for unknown files in IMM...
r35289 if wctx.isinmemory():
# Nothing to do in IMM because nothing in the "working copy" can be an
# unknown file.
#
# Note that we should bail out here, not in ``_checkunknownfiles()``,
# because that function does other useful work.
return False
Martin von Zweigbergk
merge: don't overwrite untracked file at directory rename target...
r23653 if f2 is None:
f2 = f
Augie Fackler
formatting: blacken the codebase...
r43346 return (
Arseniy Alekseyev
merge: avoid dereferencing repo fields repeatedly
r50805 wvfs.isfileorlink_checkdir(dircache, f)
and dirstate.normalize(f) not in dirstate
Augie Fackler
formatting: blacken the codebase...
r43346 and mctx[f2].cmp(wctx[f])
)
Matt Mackall
merge: refactor unknown file conflict checking...
r16093
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class _unknowndirschecker:
Mark Thomas
merge: add _checkunknowndirs function for detecting path conflicts...
r34551 """
Look for any unknown files or directories that may have a path conflict
with a file. If any path prefix of the file exists as a file or link,
then it conflicts. If the file itself is a directory that contains any
file that is not tracked, then it conflicts.
Returns the shortest path at which a conflict occurs, or None if there is
no conflict.
"""
Augie Fackler
formatting: blacken the codebase...
r43346
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 def __init__(self):
# A set of paths known to be good. This prevents repeated checking of
# dirs. It will be updated with any new dirs that are checked and found
# to be safe.
self._unknowndircache = set()
Mark Thomas
merge: add _checkunknowndirs function for detecting path conflicts...
r34551
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 # A set of paths that are known to be absent. This prevents repeated
# checking of subdirectories that are known not to exist. It will be
# updated with any new dirs that are checked and found to be absent.
self._missingdircache = set()
Mark Thomas
merge: add _checkunknowndirs function for detecting path conflicts...
r34551
Phil Cohen
merge: don't check for unknown files in IMM...
r35289 def __call__(self, repo, wctx, f):
if wctx.isinmemory():
# Nothing to do in IMM for the same reason as ``_checkunknownfile``.
return False
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 # Check for path prefixes that exist as unknown files.
Martin von Zweigbergk
utils: move finddirs() to pathutil...
r44032 for p in reversed(list(pathutil.finddirs(f))):
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 if p in self._missingdircache:
return
if p in self._unknowndircache:
continue
if repo.wvfs.audit.check(p):
Augie Fackler
formatting: blacken the codebase...
r43346 if (
repo.wvfs.isfileorlink(p)
and repo.dirstate.normalize(p) not in repo.dirstate
):
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 return p
if not repo.wvfs.lexists(p):
self._missingdircache.add(p)
return
self._unknowndircache.add(p)
# Check if the file conflicts with a directory containing unknown files.
if repo.wvfs.audit.check(f) and repo.wvfs.isdir(f):
# Does the directory contain any files that are not in the dirstate?
for p, dirs, files in repo.wvfs.walk(f):
for fn in files:
Matt Harbison
merge: pconvert paths in _unknowndirschecker before dirstate-normalizing...
r37104 relf = util.pconvert(repo.wvfs.reljoin(p, fn))
Matt Harbison
merge: add 'isknown=True' to a dirstate.normalize() in _unknowndirschecker...
r37105 relf = repo.dirstate.normalize(relf, isknown=True)
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 if relf not in repo.dirstate:
return f
return None
Mark Thomas
merge: add _checkunknowndirs function for detecting path conflicts...
r34551
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult instead of actions in _checkunknownfiles() (API)...
r45844 def _checkunknownfiles(repo, wctx, mctx, force, mresult, mergeforce):
Martin von Zweigbergk
merge: extract method for checking for conflicting untracked file...
r23655 """
Considers any actions that care about the presence of conflicting unknown
files. For some actions, the result is to abort; for others, it is to
choose a different action.
"""
Mark Thomas
merge: rename conflicts to fileconflicts in _checkunknownfiles...
r34552 fileconflicts = set()
Mark Thomas
merge: check for path conflicts when updating (issue5628)...
r34553 pathconflicts = set()
Siddharth Agarwal
merge: move abort/warn checks up to the top level of _checkunknownfiles...
r28018 warnconflicts = set()
abortconflicts = set()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 unknownconfig = _getcheckunknownconfig(repo, b'merge', b'checkunknown')
ignoredconfig = _getcheckunknownconfig(repo, b'merge', b'checkignored')
pathconfig = repo.ui.configbool(
b'experimental', b'merge.checkpathconflicts'
)
Arseniy Alekseyev
merge: skip syntactic path checks in [_checkunknownfile]...
r50804 dircache = dict()
Arseniy Alekseyev
merge: avoid dereferencing repo fields repeatedly
r50805 dirstate = repo.dirstate
wvfs = repo.wvfs
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 # wouldn't it be easier to loop over unknown files (and dirs)?
Martin von Zweigbergk
merge: extract method for checking for conflicting untracked file...
r23655 if not force:
Augie Fackler
formatting: blacken the codebase...
r43346
Siddharth Agarwal
merge: determine what untracked conflicts cause warns and aborts separately...
r27741 def collectconflicts(conflicts, config):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if config == b'abort':
Siddharth Agarwal
merge: determine what untracked conflicts cause warns and aborts separately...
r27741 abortconflicts.update(conflicts)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 elif config == b'warn':
Siddharth Agarwal
merge: determine what untracked conflicts cause warns and aborts separately...
r27741 warnconflicts.update(conflicts)
Mark Thomas
merge: cache unknown dir checks (issue5716)...
r35181 checkunknowndirs = _unknowndirschecker()
Arseniy Alekseyev
merge: skip syntactic path checks in [_checkunknownfile]...
r50804 for f in mresult.files(
(
mergestatemod.ACTION_CREATED,
mergestatemod.ACTION_DELETED_CHANGED,
)
):
Arseniy Alekseyev
merge: avoid dereferencing repo fields repeatedly
r50805 if _checkunknownfile(dirstate, wvfs, dircache, wctx, mctx, f):
Arseniy Alekseyev
merge: skip syntactic path checks in [_checkunknownfile]...
r50804 fileconflicts.add(f)
elif pathconfig and f not in wctx:
path = checkunknowndirs(repo, wctx, f)
if path is not None:
pathconflicts.add(path)
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 for f, args, msg in mresult.getactions(
[mergestatemod.ACTION_LOCAL_DIR_RENAME_GET]
):
Arseniy Alekseyev
merge: avoid dereferencing repo fields repeatedly
r50805 if _checkunknownfile(
dirstate, wvfs, dircache, wctx, mctx, f, args[0]
):
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 fileconflicts.add(f)
Martin von Zweigbergk
merge: extract method for checking for conflicting untracked file...
r23655
Mark Thomas
merge: check for path conflicts when updating (issue5628)...
r34553 allconflicts = fileconflicts | pathconflicts
Augie Fackler
formatting: blacken the codebase...
r43346 ignoredconflicts = {c for c in allconflicts if repo.dirstate._ignore(c)}
Mark Thomas
merge: rename conflicts to fileconflicts in _checkunknownfiles...
r34552 unknownconflicts = allconflicts - ignoredconflicts
Siddharth Agarwal
merge: split up checks for unknown and ignored files that differ...
r27742 collectconflicts(ignoredconflicts, ignoredconfig)
collectconflicts(unknownconflicts, unknownconfig)
Siddharth Agarwal
rebase: respect checkunknown and checkignored in more cases...
r28022 else:
Pulkit Goyal
mergeresult: yield from getactions() instead of buidling a list and returning...
r45900 for f, args, msg in list(
mresult.getactions([mergestatemod.ACTION_CREATED_MERGE])
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 ):
fl2, anc = args
Arseniy Alekseyev
merge: avoid dereferencing repo fields repeatedly
r50805 different = _checkunknownfile(
dirstate, wvfs, dircache, wctx, mctx, f
)
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 if repo.dirstate._ignore(f):
config = ignoredconfig
else:
config = unknownconfig
Siddharth Agarwal
rebase: respect checkunknown and checkignored in more cases...
r28022
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 # The behavior when force is True is described by this table:
# config different mergeforce | action backup
# * n * | get n
# * y y | merge -
# abort y n | merge - (1)
# warn y n | warn + get y
# ignore y n | get y
#
# (1) this is probably the wrong behavior here -- we should
# probably abort, but some actions like rebases currently
# don't like an abort happening in the middle of
# merge.update.
if not different:
mresult.addfile(
f,
mergestatemod.ACTION_GET,
(fl2, False),
b'remote created',
)
elif mergeforce or config == b'abort':
mresult.addfile(
f,
mergestatemod.ACTION_MERGE,
(f, f, None, False, anc),
b'remote differs from untracked local',
)
elif config == b'abort':
abortconflicts.add(f)
else:
if config == b'warn':
warnconflicts.add(f)
mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_GET,
(fl2, True),
b'remote created',
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 )
Siddharth Agarwal
merge: determine what untracked conflicts cause warns and aborts separately...
r27741
Siddharth Agarwal
merge: move abort/warn checks up to the top level of _checkunknownfiles...
r28018 for f in sorted(abortconflicts):
Mark Thomas
merge: improve error messages for path conflicts during update...
r34554 warn = repo.ui.warn
if f in pathconflicts:
if repo.wvfs.isfileorlink(f):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 warn(_(b"%s: untracked file conflicts with directory\n") % f)
Mark Thomas
merge: improve error messages for path conflicts during update...
r34554 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 warn(_(b"%s: untracked directory conflicts with file\n") % f)
Mark Thomas
merge: improve error messages for path conflicts during update...
r34554 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 warn(_(b"%s: untracked file differs\n") % f)
Siddharth Agarwal
merge: move abort/warn checks up to the top level of _checkunknownfiles...
r28018 if abortconflicts:
Martin von Zweigbergk
errors: use StateError more in merge module...
r47146 raise error.StateError(
Augie Fackler
formatting: blacken the codebase...
r43346 _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"untracked files in working directory "
b"differ from files in requested revision"
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Siddharth Agarwal
merge: move abort/warn checks up to the top level of _checkunknownfiles...
r28018
for f in sorted(warnconflicts):
Mark Thomas
merge: improve error messages for path conflicts during update...
r34554 if repo.wvfs.isfileorlink(f):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b"%s: replacing untracked file\n") % f)
Mark Thomas
merge: improve error messages for path conflicts during update...
r34554 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b"%s: replacing untracked files in directory\n") % f)
Martin von Zweigbergk
merge: extract method for checking for conflicting untracked file...
r23655
Arseniy Alekseyev
merge: add mergeresult.mapaction to improve speed...
r50806 def transformargs(f, args):
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 backup = (
f in fileconflicts
Arseniy Alekseyev
merge: don't pay for pathconflicts if there are none
r50781 or pathconflicts
and (
f in pathconflicts
or any(p in pathconflicts for p in pathutil.finddirs(f))
)
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 )
(flags,) = args
Arseniy Alekseyev
merge: add mergeresult.mapaction to improve speed...
r50806 return (flags, backup)
mresult.mapaction(
mergestatemod.ACTION_CREATED, mergestatemod.ACTION_GET, transformargs
)
Martin von Zweigbergk
merge: extract method for checking for conflicting untracked file...
r23655
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult obj in _forgetremoved() (API)...
r45907 def _forgetremoved(wctx, mctx, branchmerge, mresult):
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107 """
Forget removed files
If we're jumping between revisions (as opposed to merging), and if
neither the working directory nor the target rev has the file,
then we need to remove it from the dirstate, to prevent the
dirstate from listing the file when it is no longer in the
manifest.
Alexis S. L. Carvalho
merge: fix handling of deleted files
r6242
If we're merging, and the other revision has removed a file
that is not present in the working directory, we need to mark it
as removed.
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107 """
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 m = mergestatemod.ACTION_FORGET
Mads Kiilerich
merge: use separate lists for each action type...
r21545 if branchmerge:
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 m = mergestatemod.ACTION_REMOVE
Alexis S. L. Carvalho
merge: fix handling of deleted files
r6242 for f in wctx.deleted():
Matt Mackall
merge: simplify some helpers
r6272 if f not in mctx:
Pulkit Goyal
merge: pass mergeresult obj in _forgetremoved() (API)...
r45907 mresult.addfile(f, m, None, b"forget deleted")
Alexis S. L. Carvalho
merge: fix handling of deleted files
r6242
if not branchmerge:
for f in wctx.removed():
Matt Mackall
merge: simplify some helpers
r6272 if f not in mctx:
Pulkit Goyal
merge: pass mergeresult obj in _forgetremoved() (API)...
r45907 mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_FORGET,
None,
b"forget removed",
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 def _checkcollision(repo, wmf, mresult):
Martin von Zweigbergk
narrow: filter set of files to check for case-folding to core...
r38056 """
Check for case-folding collisions.
"""
# If the repo is narrowed, filter out files outside the narrowspec.
narrowmatch = repo.narrowmatch()
if not narrowmatch.always():
Augie Fackler
merge: use manifestdict.walk() instead of manifestdict.matches()...
r44769 pmmf = set(wmf.walk(narrowmatch))
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 if mresult:
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in list(mresult.files()):
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 if not narrowmatch(f):
mresult.removefile(f)
Augie Fackler
merge: use manifestdict.walk() instead of manifestdict.matches()...
r44769 else:
# build provisional merged manifest up
pmmf = set(wmf)
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 if mresult:
Gregory Szorc
merge: use constants for actions...
r37130 # KEEP and EXEC are no-op
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in mresult.files(
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 (
mergestatemod.ACTION_ADD,
mergestatemod.ACTION_ADD_MODIFIED,
mergestatemod.ACTION_FORGET,
mergestatemod.ACTION_GET,
mergestatemod.ACTION_CHANGED_DELETED,
mergestatemod.ACTION_DELETED_CHANGED,
)
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 pmmf.add(f)
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in mresult.files((mergestatemod.ACTION_REMOVE,)):
Mads Kiilerich
merge: use separate lists for each action type...
r21545 pmmf.discard(f)
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 for f, args, msg in mresult.getactions(
[mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL]
):
Mads Kiilerich
merge: use separate lists for each action type...
r21545 f2, flags = args
pmmf.discard(f2)
pmmf.add(f)
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in mresult.files((mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,)):
Mads Kiilerich
merge: use separate lists for each action type...
r21545 pmmf.add(f)
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 for f, args, msg in mresult.getactions([mergestatemod.ACTION_MERGE]):
Mads Kiilerich
merge: use separate lists for each action type...
r21545 f1, f2, fa, move, anc = args
if move:
pmmf.discard(f1)
pmmf.add(f)
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105
# check case-folding collision in provisional merged manifest
foldmap = {}
Alex Gaynor
merge: removed sorting in casefolding detection, for a slight performance win...
r33807 for f in pmmf:
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105 fold = util.normcase(f)
if fold in foldmap:
merge: break up a not-so-one-liner for readability...
r49548 msg = _(b"case-folding collision between %s and %s")
msg %= (f, foldmap[fold])
raise error.StateError(msg)
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105 foldmap[fold] = f
Mads Kiilerich
merge: abort on file/directory case folding collisions (issue4892)...
r26661 # check case-folding of directories
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 foldprefix = unfoldprefix = lastfull = b''
Mads Kiilerich
merge: abort on file/directory case folding collisions (issue4892)...
r26661 for fold, f in sorted(foldmap.items()):
if fold.startswith(foldprefix) and not f.startswith(unfoldprefix):
# the folded prefix matches but actual casing is different
merge: break up a not-so-one-liner for readability...
r49549 msg = _(b"case-folding collision between %s and directory of %s")
msg %= (lastfull, f)
raise error.StateError(msg)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 foldprefix = fold + b'/'
unfoldprefix = f + b'/'
Mads Kiilerich
merge: abort on file/directory case folding collisions (issue4892)...
r26661 lastfull = f
Augie Fackler
formatting: blacken the codebase...
r43346
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 def _filesindirs(repo, manifest, dirs):
"""
Generator that yields pairs of all the files in the manifest that are found
inside the directories listed in dirs, and which directory they are found
in.
"""
for f in manifest:
Martin von Zweigbergk
utils: move finddirs() to pathutil...
r44032 for p in pathutil.finddirs(f):
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 if p in dirs:
yield f, p
break
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 def checkpathconflicts(repo, wctx, mctx, mresult):
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 """
Check if any actions introduce path conflicts in the repository, updating
actions to record or handle the path conflict accordingly.
"""
mf = wctx.manifest()
# The set of local files that conflict with a remote directory.
localconflicts = set()
# The set of directories that conflict with a remote file, and so may cause
# conflicts if they still contain any files after the merge.
remoteconflicts = set()
# The set of directories that appear as both a file and a directory in the
# remote manifest. These indicate an invalid remote manifest, which
# can't be updated to cleanly.
invalidconflicts = set()
Mark Thomas
merge: check created file dirs for path conflicts only once (issue5716)...
r35182 # The set of directories that contain files that are being created.
createdfiledirs = set()
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 # The set of files deleted by all the actions.
deletedfiles = set()
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in mresult.files(
Pulkit Goyal
merge: rework iteration over mergeresult object in checkpathconflicts()...
r45902 (
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CREATED,
mergestatemod.ACTION_DELETED_CHANGED,
mergestatemod.ACTION_MERGE,
mergestatemod.ACTION_CREATED_MERGE,
Pulkit Goyal
merge: rework iteration over mergeresult object in checkpathconflicts()...
r45902 )
):
# This action may create a new local file.
createdfiledirs.update(pathutil.finddirs(f))
if mf.hasdir(f):
# The file aliases a local directory. This might be ok if all
# the files in the local directory are being deleted. This
# will be checked once we know what all the deleted files are.
remoteconflicts.add(f)
# Track the names of all deleted files.
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in mresult.files((mergestatemod.ACTION_REMOVE,)):
Pulkit Goyal
merge: rework iteration over mergeresult object in checkpathconflicts()...
r45902 deletedfiles.add(f)
Raphaël Gomès
black: format the codebase with 23.3.0...
r52596 for f, args, msg in mresult.getactions((mergestatemod.ACTION_MERGE,)):
Pulkit Goyal
merge: rework iteration over mergeresult object in checkpathconflicts()...
r45902 f1, f2, fa, move, anc = args
if move:
deletedfiles.add(f1)
Raphaël Gomès
black: format the codebase with 23.3.0...
r52596 for f, args, msg in mresult.getactions(
Pulkit Goyal
merge: rework iteration over mergeresult object in checkpathconflicts()...
r45902 (mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,)
):
f2, flags = args
deletedfiles.add(f2)
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556
Mark Thomas
merge: check created file dirs for path conflicts only once (issue5716)...
r35182 # Check all directories that contain created files for path conflicts.
for p in createdfiledirs:
if p in mf:
if p in mctx:
# A file is in a directory which aliases both a local
# and a remote file. This is an internal inconsistency
# within the remote manifest.
invalidconflicts.add(p)
else:
# A file is in a directory which aliases a local file.
# We will need to rename the local file.
localconflicts.add(p)
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904 pd = mresult.getfile(p)
if pd and pd[0] in (
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CREATED,
mergestatemod.ACTION_DELETED_CHANGED,
mergestatemod.ACTION_MERGE,
mergestatemod.ACTION_CREATED_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Mark Thomas
merge: check created file dirs for path conflicts only once (issue5716)...
r35182 # The file is in a directory which aliases a remote file.
# This is an internal inconsistency within the remote
# manifest.
invalidconflicts.add(p)
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 # Rename all local conflicting files that have not been deleted.
for p in localconflicts:
if p not in deletedfiles:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ctxname = bytes(wctx).rstrip(b'+')
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 pnew = util.safename(p, ctxname, wctx, set(mresult.files()))
Martin von Zweigbergk
merge: move an inspection of the dirstate from record to calculate phase...
r45465 porig = wctx[p].copysource() or p
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 mresult.addfile(
pnew,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
Martin von Zweigbergk
merge: move an inspection of the dirstate from record to calculate phase...
r45465 (p, porig),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'local path conflict',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 mresult.addfile(
p,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_PATH_CONFLICT,
(pnew, b'l'),
b'path conflict',
)
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556
if remoteconflicts:
# Check if all files in the conflicting directories have been removed.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 ctxname = bytes(mctx).rstrip(b'+')
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 for f, p in _filesindirs(repo, mf, remoteconflicts):
if f not in deletedfiles:
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904 m, args, msg = mresult.getfile(p)
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 pnew = util.safename(p, ctxname, wctx, set(mresult.files()))
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 if m in (
mergestatemod.ACTION_DELETED_CHANGED,
mergestatemod.ACTION_MERGE,
):
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 # Action was merge, just update target.
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 mresult.addfile(pnew, m, args, msg)
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 else:
# Action was create, change to renamed get action.
fl = args[0]
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 mresult.addfile(
pnew,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
Augie Fackler
formatting: blacken the codebase...
r43346 (p, fl),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'remote path conflict',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 mresult.addfile(
p,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_PATH_CONFLICT,
merge: stop using merge action for pathconflict option...
r49557 (pnew, b'r'),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'path conflict',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556 remoteconflicts.remove(p)
break
if invalidconflicts:
for p in invalidconflicts:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b"%s: is both a file and a directory\n") % p)
Martin von Zweigbergk
errors: use StateError more in merge module...
r47146 raise error.StateError(
_(b"destination manifest contains path conflicts")
)
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _filternarrowactions()...
r45842 def _filternarrowactions(narrowmatch, branchmerge, mresult):
Martin von Zweigbergk
narrow: filter merge actions in core...
r38055 """
Filters out actions that can ignored because the repo is narrowed.
Raise an exception if the merge cannot be completed because the repo is
narrowed.
"""
# We mutate the items in the dict during iteration, so iterate
# over a copy.
Manuel Jacob
merge: sort filemap only if requested by the caller...
r52711 for f, action in list(mresult.filemap()):
Martin von Zweigbergk
narrow: filter merge actions in core...
r38055 if narrowmatch(f):
pass
elif not branchmerge:
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _filternarrowactions()...
r45842 mresult.removefile(f) # just updating, ignore changes outside clone
merge-actions: add an explicite "no_op" attribute...
r49562 elif action[0].no_op:
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _filternarrowactions()...
r45842 mresult.removefile(f) # merge does not affect file
narrow: allow merging non-conflicting change outside of the narrow spec...
r49565 elif action[0].narrow_safe:
narrow: add support for merging add and remove outside of the tracked set...
r49592 if not f.endswith(b'/'):
narrow: allow merging non-conflicting change outside of the narrow spec...
r49565 mresult.removefile(f) # merge won't affect on-disk files
mresult.addcommitinfo(
f, b'outside-narrow-merge-action', action[0].changes
)
else: # TODO: handle the tree case
msg = _(
b'merge affects file \'%s\' outside narrow, '
b'which is not yet supported'
)
hint = _(b'merging in the other direction may work')
raise error.Abort(msg % f, hint=hint)
Martin von Zweigbergk
narrow: filter merge actions in core...
r38055 else:
merge: break up a not-so-one-liner for readability...
r49551 msg = _(b'conflict in file \'%s\' is outside narrow clone')
raise error.StateError(msg % f)
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
narrow: filter merge actions in core...
r38055
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class mergeresult:
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """An object representing result of merging manifests.
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831
It has information about what actions need to be performed on dirstate
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 mapping of divergent renames and other such cases."""
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831
Pulkit Goyal
merge: make mergeresult constructor initialize empty object...
r45838 def __init__(self):
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 """
Pulkit Goyal
mergeresult: rename _actions to _filemapping...
r45848 filemapping: dict of filename as keys and action related info as values
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 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.
Pulkit Goyal
merge: introduce 'commitinfo' in mergeresult...
r45832 commitinfo: dict containing data which should be used on commit
contains a filename -> info mapping
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 actionmapping: dict of action names as keys and values are dict of
filename as key and related data as values
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 """
Pulkit Goyal
mergeresult: rename _actions to _filemapping...
r45848 self._filemapping = {}
Pulkit Goyal
merge: make mergeresult constructor initialize empty object...
r45838 self._diverge = {}
self._renamedelete = {}
Pulkit Goyal
merge: use collections.defaultdict() for mergeresult.commitinfo...
r45943 self._commitinfo = collections.defaultdict(dict)
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 self._actionmapping = collections.defaultdict(dict)
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 def updatevalues(self, diverge, renamedelete):
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 self._diverge = diverge
self._renamedelete = renamedelete
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 def addfile(self, filename, action, data, message):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """adds a new file to the mergeresult object
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839
filename: file which we are adding
action: one of mergestatemod.ACTION_*
data: a tuple of information like fctx and ctx related to this merge
message: a message about the merge
"""
Pulkit Goyal
mergeresult: introduce action -> (filename, data, msg) mapping and related API...
r45849 # if the file already existed, we need to delete it's old
# entry form _actionmapping too
if filename in self._filemapping:
a, d, m = self._filemapping[filename]
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 del self._actionmapping[a][filename]
Pulkit Goyal
mergeresult: introduce action -> (filename, data, msg) mapping and related API...
r45849
Pulkit Goyal
mergeresult: rename _actions to _filemapping...
r45848 self._filemapping[filename] = (action, data, message)
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 self._actionmapping[action][filename] = (data, message)
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839
Arseniy Alekseyev
merge: add mergeresult.mapaction to improve speed...
r50806 def mapaction(self, actionfrom, actionto, transform):
"""changes all occurrences of action `actionfrom` into `actionto`,
transforming its args with the function `transform`.
"""
orig = self._actionmapping[actionfrom]
del self._actionmapping[actionfrom]
dest = self._actionmapping[actionto]
for f, (data, msg) in orig.items():
data = transform(f, data)
self._filemapping[f] = (actionto, data, msg)
dest[f] = (data, msg)
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904 def getfile(self, filename, default_return=None):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """returns (action, args, msg) about this file
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 returns default_return if the file is not present"""
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904 if filename in self._filemapping:
return self._filemapping[filename]
return default_return
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 def files(self, actions=None):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """returns files on which provided action needs to perfromed
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905
If actions is None, all files are returned
"""
# TODO: think whether we should return renamedelete and
# diverge filenames also
if actions is None:
for f in self._filemapping:
yield f
else:
for a in actions:
for f in self._actionmapping[a]:
yield f
Pulkit Goyal
merge: add removefile() to mergeresult object...
r45840 def removefile(self, filename):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """removes a file from the mergeresult object as the file might
not merging anymore"""
Pulkit Goyal
mergeresult: introduce action -> (filename, data, msg) mapping and related API...
r45849 action, data, message = self._filemapping[filename]
Pulkit Goyal
mergeresult: rename _actions to _filemapping...
r45848 del self._filemapping[filename]
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 del self._actionmapping[action][filename]
Pulkit Goyal
mergeresult: introduce action -> (filename, data, msg) mapping and related API...
r45849
Pulkit Goyal
mergeresult: add sort argument to getactions() method...
r45896 def getactions(self, actions, sort=False):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """get list of files which are marked with these actions
Pulkit Goyal
mergeresult: add sort argument to getactions() method...
r45896 if sort is true, files for each action is sorted and then added
Pulkit Goyal
mergeresult: introduce action -> (filename, data, msg) mapping and related API...
r45849
Returns a list of tuple of form (filename, data, message)
"""
for a in actions:
Pulkit Goyal
mergeresult: add sort argument to getactions() method...
r45896 if sort:
for f in sorted(self._actionmapping[a]):
args, msg = self._actionmapping[a][f]
Pulkit Goyal
mergeresult: yield from getactions() instead of buidling a list and returning...
r45900 yield f, args, msg
Pulkit Goyal
mergeresult: add sort argument to getactions() method...
r45896 else:
Gregory Szorc
merge: remove pycompat.iteritems()...
r49782 for f, (args, msg) in self._actionmapping[a].items():
Pulkit Goyal
mergeresult: yield from getactions() instead of buidling a list and returning...
r45900 yield f, args, msg
Pulkit Goyal
merge: add removefile() to mergeresult object...
r45840
Pulkit Goyal
mergeresult: implement a len() function and use it...
r45898 def len(self, actions=None):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """returns number of files which needs actions
Pulkit Goyal
mergeresult: implement a len() function and use it...
r45898
if actions is passed, total of number of files in that action
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 only is returned"""
Pulkit Goyal
mergeresult: implement a len() function and use it...
r45898
if actions is None:
return len(self._filemapping)
return sum(len(self._actionmapping[a]) for a in actions)
Pulkit Goyal
mergeresult: introduce filemap() which yields filename based mapping...
r45906 def filemap(self, sort=False):
Manuel Jacob
merge: sort filemap only if requested by the caller...
r52711 if sort:
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for key, val in sorted(self._filemapping.items()):
Pulkit Goyal
mergeresult: introduce filemap() which yields filename based mapping...
r45906 yield key, val
else:
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for key, val in self._filemapping.items():
Pulkit Goyal
mergeresult: introduce filemap() which yields filename based mapping...
r45906 yield key, val
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 def addcommitinfo(self, filename, key, value):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """adds key-value information about filename which will be required
while committing this merge"""
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 self._commitinfo[filename][key] = value
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 @property
def diverge(self):
return self._diverge
@property
def renamedelete(self):
return self._renamedelete
Pulkit Goyal
merge: introduce 'commitinfo' in mergeresult...
r45832 @property
def commitinfo(self):
return self._commitinfo
Pulkit Goyal
merge: move conversion of file-key dict to action-key dict in mergeresult...
r45836 @property
def actionsdict(self):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """returns a dictionary of actions to be perfomed with action as key
and a list of files and related arguments as values"""
Pulkit Goyal
merge: remove emptyactions() and use collections.defaultdict(list) instead...
r45908 res = collections.defaultdict(list)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for a, d in self._actionmapping.items():
for f, (args, msg) in d.items():
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 res[a].append((f, args, msg))
return res
Pulkit Goyal
merge: move conversion of file-key dict to action-key dict in mergeresult...
r45836
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 def setactions(self, actions):
Pulkit Goyal
mergeresult: rename _actions to _filemapping...
r45848 self._filemapping = actions
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 self._actionmapping = collections.defaultdict(dict)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for f, (act, data, msg) in self._filemapping.items():
Pulkit Goyal
mergeresult: make actionmapping a dict of dict instead of dict of lists...
r45856 self._actionmapping[act][f] = data, msg
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831
Pulkit Goyal
merge: introduce hasconflicts() on mergeresult object...
r45835 def hasconflicts(self):
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 """tells whether this merge resulted in some actions which can
result in conflicts or not"""
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 for a in self._actionmapping.keys():
if (
a
not in (
mergestatemod.ACTION_GET,
mergestatemod.ACTION_EXEC,
mergestatemod.ACTION_REMOVE,
mergestatemod.ACTION_PATH_CONFLICT_RESOLVE,
)
and self._actionmapping[a]
merge-actions: add an explicite "no_op" attribute...
r49562 and not a.no_op
Pulkit Goyal
merge: introduce hasconflicts() on mergeresult object...
r45835 ):
return True
return False
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831
Augie Fackler
formatting: blacken the codebase...
r43346 def manifestmerge(
repo,
wctx,
p2,
pa,
branchmerge,
force,
matcher,
acceptremote,
followcopies,
forcefulldiff=False,
):
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 """
Yuya Nishihara
merge: update doc of manifestmerge() per 18c2184c27dc...
r30096 Merge wctx and p2 with ancestor pa and generate merge action list
Matt Mackall
merge: update some docstrings
r3315
Siddharth Agarwal
manifestmerge: pass in branchmerge and force separately...
r18605 branchmerge and force are as passed in to update
Augie Fackler
merge: rework manifestmerge to use a matcher...
r27346 matcher = matcher to filter file lists
Durham Goode
rebase: fix --collapse when a file was added then removed...
r18778 acceptremote = accept the incoming changes without prompting
Pulkit Goyal
merge: document return values of manifestmerge() and calculateupdates()...
r45728
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 Returns an object of mergeresult class
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 """
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult = mergeresult()
Augie Fackler
merge: rework manifestmerge to use a matcher...
r27346 if matcher is not None and matcher.always():
matcher = None
Matt Mackall
merge: pull manifest comparison out into separate function
r3105
Siddharth Agarwal
manifestmerge: fix order in which manifests are fetched...
r18651 # manifests fetched in order are going to be faster, so prime the caches
Augie Fackler
formatting: blacken the codebase...
r43346 [
x.manifest()
for x in sorted(wctx.parents() + [p2, pa], key=scmutil.intrev)
]
Siddharth Agarwal
manifestmerge: fix order in which manifests are fetched...
r18651
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 branch_copies1 = copies.branch_copies()
branch_copies2 = copies.branch_copies()
diverge = {}
Pulkit Goyal
merge: introduce 'commitinfo' in mergeresult...
r45832 # information from merge which is needed at commit time
# for example choosing filelog of which parent to commit
# TODO: use specific constants in future for this mapping
Siddharth Agarwal
manifestmerge: fix order in which manifests are fetched...
r18651 if followcopies:
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 branch_copies1, branch_copies2, diverge = copies.mergecopies(
repo, wctx, p2, pa
)
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753
Pulkit Goyal
py3: convert bool variables to bytes before passing into ui.debug()...
r32641 boolbm = pycompat.bytestr(bool(branchmerge))
boolf = pycompat.bytestr(bool(force))
boolm = pycompat.bytestr(bool(matcher))
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"resolving manifests\n"))
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.debug(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b" branchmerge: %s, force: %s, partial: %s\n" % (boolbm, boolf, boolm)
Augie Fackler
formatting: blacken the codebase...
r43346 )
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" ancestor: %s, local: %s, remote: %s\n" % (pa, wctx, p2))
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753
Bryan O'Sullivan
merge: rename p1 to wctx in manifestmerge...
r18611 m1, m2, ma = wctx.manifest(), p2.manifest(), pa.manifest()
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 copied1 = set(branch_copies1.copy.values())
copied1.update(branch_copies1.movewithdir.values())
copied2 = set(branch_copies2.copy.values())
copied2.update(branch_copies2.movewithdir.values())
Matt Mackall
merge: use contexts for manifestmerge...
r3295
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if b'.hgsubstate' in m1 and wctx.rev() is None:
Yuya Nishihara
merge: do not fill manifest of committed revision with pseudo node (issue5526)...
r38444 # Check whether sub state is modified, and overwrite the manifest
# to flag the change. If wctx is a committed revision, we shouldn't
# care for the dirty state of the working directory.
Martin von Zweigbergk
merge: use any() instead of for loop when checking for dirty subrepos...
r28226 if any(wctx.sub(s).dirty() for s in wctx.substate):
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 m1[b'.hgsubstate'] = repo.nodeconstants.modifiednodeid
Matt Mackall
submerge: properly deal with overwrites...
r9783
Durham Goode
rebase: use matcher to optimize manifestmerge...
r32151 # Don't use m2-vs-ma optimization if:
# - ma is the same as m1 or m2, which we're just going to diff again later
# - The caller specifically asks for a full diff, which is useful during bid
# merge.
Pulkit Goyal
merge: disable `m2-vs-ma` optimization if new filenode config is true...
r46154 # - we are tracking salvaged files specifically hence should process all
# files
if (
pa not in ([wctx, p2] + wctx.parents())
and not forcefulldiff
salvaged: track removal-candidates in more cases...
r46253 and not (
repo.ui.configbool(b'experimental', b'merge-track-salvaged')
or repo.filecopiesmode == b'changeset-sidedata'
)
Pulkit Goyal
merge: disable `m2-vs-ma` optimization if new filenode config is true...
r46154 ):
Durham Goode
rebase: use matcher to optimize manifestmerge...
r32151 # Identify which files are relevant to the merge, so we can limit the
# total m1-vs-m2 diff to just those files. This has significant
# performance benefits in large repositories.
relevantfiles = set(ma.diff(m2).keys())
# For copied and moved files, we need to add the source file too.
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for copykey, copyvalue in branch_copies1.copy.items():
Durham Goode
rebase: use matcher to optimize manifestmerge...
r32151 if copyvalue in relevantfiles:
relevantfiles.add(copykey)
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 for movedirkey in branch_copies1.movewithdir:
Durham Goode
rebase: use matcher to optimize manifestmerge...
r32151 relevantfiles.add(movedirkey)
Martin von Zweigbergk
merge: use intersectmatchers() in "m2-vs-ma optimization"...
r32498 filesmatcher = scmutil.matchfiles(repo, relevantfiles)
matcher = matchmod.intersectmatchers(matcher, filesmatcher)
Durham Goode
rebase: use matcher to optimize manifestmerge...
r32151
Durham Goode
merge: remove uses of manifest.matches...
r31257 diff = m1.diff(m2, match=matcher)
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for f, ((n1, fl1), (n2, fl2)) in diff.items():
Augie Fackler
formatting: blacken the codebase...
r43346 if n1 and n2: # file exists on both local and remote side
Martin von Zweigbergk
merge: separate out "both created" cases...
r23396 if f not in ma:
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 # TODO: what if they're renamed from different sources?
fa = branch_copies1.copy.get(
f, None
) or branch_copies2.copy.get(f, None)
Pulkit Goyal
merge: unify logic of couple of if-else's in manifestmerge()...
r45853 args, msg = None, None
Martin von Zweigbergk
merge: break out "both renamed a -> b" case...
r23397 if fa is not None:
Pulkit Goyal
merge: unify logic of couple of if-else's in manifestmerge()...
r45853 args = (f, f, fa, False, pa.node())
msg = b'both renamed from %s' % fa
Mads Kiilerich
merge: merge file flags together with file content...
r18338 else:
Pulkit Goyal
merge: unify logic of couple of if-else's in manifestmerge()...
r45853 args = (f, f, None, False, pa.node())
msg = b'both created'
mresult.addfile(f, mergestatemod.ACTION_MERGE, args, msg)
Martin von Zweigbergk
copies: handle more cases where a file got replaced by a copy...
r46421 elif f in branch_copies1.copy:
fa = branch_copies1.copy[f]
mresult.addfile(
f,
mergestatemod.ACTION_MERGE,
(f, fa, fa, False, pa.node()),
b'local replaced from %s' % fa,
)
elif f in branch_copies2.copy:
fa = branch_copies2.copy[f]
mresult.addfile(
f,
mergestatemod.ACTION_MERGE,
(fa, f, fa, False, pa.node()),
b'other replaced from %s' % fa,
)
Matt Mackall
merge: don't use unknown()...
r16094 else:
Martin von Zweigbergk
merge: separate out "both created" cases...
r23396 a = ma[f]
fla = ma.flags(f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 nol = b'l' not in fl1 + fl2 + fla
Martin von Zweigbergk
merge: indent to prepare for next patch
r23395 if n2 == a and fl2 == fla:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_KEEP,
(),
b'remote unchanged',
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Augie Fackler
formatting: blacken the codebase...
r43346 elif n1 == a and fl1 == fla: # local unchanged - use remote
if n1 == n2: # optimization: keep local content
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_EXEC,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 (fl2,),
b'update permissions',
)
Martin von Zweigbergk
merge: indent to prepare for next patch
r23395 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Pulkit Goyal
merge: remove no longer required ACTION_GET_OTHER_AND_STORE...
r45834 mergestatemod.ACTION_GET,
Augie Fackler
formatting: blacken the codebase...
r43346 (fl2, False),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'remote is newer',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pulkit Goyal
merge: introduce 'commitinfo' in mergeresult...
r45832 if branchmerge:
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 mresult.addcommitinfo(
f, b'filenode-source', b'other'
)
Augie Fackler
formatting: blacken the codebase...
r43346 elif nol and n2 == a: # remote only changed 'x'
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_EXEC,
(fl2,),
b'update permissions',
)
Augie Fackler
formatting: blacken the codebase...
r43346 elif nol and n1 == a: # local only changed 'x'
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Pulkit Goyal
merge: remove no longer required ACTION_GET_OTHER_AND_STORE...
r45834 mergestatemod.ACTION_GET,
Pulkit Goyal
mergestate: store about files resolved in favour of other...
r45178 (fl1, False),
b'remote is newer',
)
Pulkit Goyal
merge: introduce 'commitinfo' in mergeresult...
r45832 if branchmerge:
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 mresult.addcommitinfo(f, b'filenode-source', b'other')
Augie Fackler
formatting: blacken the codebase...
r43346 else: # both changed something
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 (f, f, f, False, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'versions differ',
Augie Fackler
formatting: blacken the codebase...
r43346 )
elif n1: # file exists only on local side
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 if f in copied2:
Augie Fackler
formatting: blacken the codebase...
r43346 pass # we'll deal with it on m2 side
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 elif (
f in branch_copies1.movewithdir
): # directory rename, move local
f2 = branch_copies1.movewithdir[f]
Durham Goode
merge: remove unnecessary matcher checks...
r31515 if f2 in m2:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f2,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 (f, f2, None, True, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'remote directory rename, both created',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
merge: don't ignore conflicting file in remote renamed directory...
r23475 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f2,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
Augie Fackler
formatting: blacken the codebase...
r43346 (f, fl1),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'remote directory rename - move from %s' % f,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 elif f in branch_copies1.copy:
f2 = branch_copies1.copy[f]
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 (f, f2, f2, False, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'local copied/moved from %s' % f2,
Augie Fackler
formatting: blacken the codebase...
r43346 )
elif f in ma: # clean, a different, no remote
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 if n1 != ma[f]:
if acceptremote:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_REMOVE,
None,
b'remote delete',
)
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CHANGED_DELETED,
Augie Fackler
formatting: blacken the codebase...
r43346 (f, None, f, False, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'prompt changed/deleted',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pulkit Goyal
merge: store commitinfo if these is a dc or cd conflict...
r46158 if branchmerge:
mresult.addcommitinfo(
f, b'merge-removal-candidate', b'yes'
)
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 elif n1 == repo.nodeconstants.addednodeid:
Joerg Sonnenberger
manifest: tigher manifest parsing and flag use...
r45678 # This file was locally added. We should forget it instead of
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 # deleting it.
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_FORGET,
None,
b'remote deleted',
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Mads Kiilerich
merge: handle acceptremove of create+delete early in manifest merge
r20639 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_REMOVE,
None,
b'other deleted',
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Pulkit Goyal
merge: store cases when a file is absent post merge in commitinfo...
r46161 if branchmerge:
# the file must be absent after merging,
# howeber the user might make
# the file reappear using revert and if they does,
# we force create a new node
mresult.addcommitinfo(
f, b'merge-removal-candidate', b'yes'
)
Pulkit Goyal
merge: add missing ACTION_KEEP when both remote and ancestor are not present...
r46041 else: # file not in ancestor, not in remote
mresult.addfile(
f,
Pulkit Goyal
mergestate: introduce a new ACTION_KEEP_NEW...
r46095 mergestatemod.ACTION_KEEP_NEW,
Pulkit Goyal
merge: add missing ACTION_KEEP when both remote and ancestor are not present...
r46041 None,
b'ancestor missing, remote missing',
)
Augie Fackler
formatting: blacken the codebase...
r43346 elif n2: # file exists only on remote side
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 if f in copied1:
Augie Fackler
formatting: blacken the codebase...
r43346 pass # we'll deal with it on m1 side
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 elif f in branch_copies2.movewithdir:
f2 = branch_copies2.movewithdir[f]
Durham Goode
merge: remove unnecessary matcher checks...
r31515 if f2 in m1:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f2,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 (f2, f, None, False, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'local directory rename, both created',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
merge: don't overwrite conflicting file in locally renamed directory...
r23476 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f2,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
Augie Fackler
formatting: blacken the codebase...
r43346 (f, fl2),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'local directory rename - get from %s' % f,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 elif f in branch_copies2.copy:
f2 = branch_copies2.copy[f]
Pulkit Goyal
merge: unify logic of couple of if-else's in manifestmerge()...
r45853 msg, args = None, None
Durham Goode
merge: remove unnecessary matcher checks...
r31515 if f2 in m2:
Pulkit Goyal
merge: unify logic of couple of if-else's in manifestmerge()...
r45853 args = (f2, f, f2, False, pa.node())
msg = b'remote copied from %s' % f2
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 else:
Pulkit Goyal
merge: unify logic of couple of if-else's in manifestmerge()...
r45853 args = (f2, f, f2, True, pa.node())
msg = b'remote moved from %s' % f2
mresult.addfile(f, mergestatemod.ACTION_MERGE, args, msg)
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 elif f not in ma:
# local unknown, remote created: the logic is described by the
# following table:
#
# force branchmerge different | action
Martin von Zweigbergk
merge: collect checking for unknown files at end of manifestmerge()...
r23651 # n * * | create
Martin von Zweigbergk
merge: introduce 'c' action like 'g', but with additional safety...
r23650 # y n * | create
# y y n | create
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 # y y y | merge
#
# Checking whether the files are different is expensive, so we
# don't do that when we can avoid it.
Martin von Zweigbergk
merge: structure 'remote created' code to match table...
r23649 if not force:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CREATED,
(fl2,),
b'remote created',
)
Martin von Zweigbergk
merge: structure 'remote created' code to match table...
r23649 elif not branchmerge:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CREATED,
(fl2,),
b'remote created',
)
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CREATED_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 (fl2, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'remote created, get or merge',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
merge: branch code into {n1 and n2, n1, n2} top-level cases...
r23473 elif n2 != ma[f]:
Gábor Stefanik
graft: support grafting changes to new file in renamed directory (issue5436)
r30581 df = None
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 for d in branch_copies1.dirmove:
Gábor Stefanik
graft: support grafting changes to new file in renamed directory (issue5436)
r30581 if f.startswith(d):
# new file added in a directory that was moved
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 df = branch_copies1.dirmove[d] + f[len(d) :]
Gábor Stefanik
graft: support grafting changes to new file in renamed directory (issue5436)
r30581 break
Durham Goode
merge: remove unnecessary matcher checks...
r31515 if df is not None and df in m1:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
df,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_MERGE,
Augie Fackler
formatting: blacken the codebase...
r43346 (df, f, f, False, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'local directory rename - respect move '
b'from %s' % f,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gábor Stefanik
graft: support grafting changes to new file in renamed directory (issue5436)
r30581 elif acceptremote:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_CREATED,
(fl2,),
b'remote recreating',
)
Siddharth Agarwal
manifestmerge: handle abort on local unknown, remote created files...
r18606 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_DELETED_CHANGED,
Augie Fackler
formatting: blacken the codebase...
r43346 (None, f, f, False, pa.node()),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'prompt deleted/changed',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pulkit Goyal
merge: store commitinfo if these is a dc or cd conflict...
r46158 if branchmerge:
mresult.addcommitinfo(
f, b'merge-removal-candidate', b'yes'
)
Pulkit Goyal
merge: store ACTION_KEEP_ABSENT when we are keeping the file absent locally...
r46040 else:
mresult.addfile(
f,
mergestatemod.ACTION_KEEP_ABSENT,
None,
b'local not present, remote unchanged',
)
Pulkit Goyal
merge: store cases when a file is absent post merge in commitinfo...
r46161 if branchmerge:
# the file must be absent after merging
# however the user might make
# the file reappear using revert and if they does,
# we force create a new node
mresult.addcommitinfo(f, b'merge-removal-candidate', b'yes')
Martin von Zweigbergk
merge: collect checking for unknown files at end of manifestmerge()...
r23651
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.ui.configbool(b'experimental', b'merge.checkpathconflicts'):
Siddharth Agarwal
merge: add a config option to disable path conflict checking...
r34942 # If we are merging, look for path conflicts.
Pulkit Goyal
merge: pass mergeresult in checkpassconflicts() instead of actions (API)...
r45841 checkpathconflicts(repo, wctx, p2, mresult)
Mark Thomas
merge: check for path conflicts when merging (issue5628)...
r34556
Martin von Zweigbergk
narrow: filter merge actions in core...
r38055 narrowmatch = repo.narrowmatch()
if not narrowmatch.always():
# Updates "actions" in place
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _filternarrowactions()...
r45842 _filternarrowactions(narrowmatch, branchmerge, mresult)
Martin von Zweigbergk
narrow: filter merge actions in core...
r38055
Martin von Zweigbergk
merge: start using the per-side copy dicts...
r44682 renamedelete = branch_copies1.renamedelete
renamedelete.update(branch_copies2.renamedelete)
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 mresult.updatevalues(diverge, renamedelete)
Pulkit Goyal
merge: make mergeresult constructor initialize empty object...
r45838 return mresult
Matt Mackall
merge: pull manifest comparison out into separate function
r3105
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult obj instead of actions dict in _resolvetrivial()...
r45843 def _resolvetrivial(repo, wctx, mctx, ancestor, mresult):
Martin von Zweigbergk
merge: extract _resolvetrivial() function...
r23531 """Resolves false conflicts where the nodeid changed but the content
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 remained the same."""
Augie Fackler
merge: make a copy of dict.items() before mutating the dict during iteration...
r36334 # We force a copy of actions.items() because we're going to mutate
# actions as we resolve trivial conflicts.
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in list(mresult.files((mergestatemod.ACTION_CHANGED_DELETED,))):
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 if f in ancestor and not wctx[f].cmp(ancestor[f]):
Martin von Zweigbergk
merge: extract _resolvetrivial() function...
r23531 # local did change but ended up with same content
Pulkit Goyal
merge: pass mergeresult obj instead of actions dict in _resolvetrivial()...
r45843 mresult.addfile(
f, mergestatemod.ACTION_REMOVE, None, b'prompt same'
)
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 for f in list(mresult.files((mergestatemod.ACTION_DELETED_CHANGED,))):
Pulkit Goyal
merge: use the new action based mapping introduced in mergeresult obj...
r45850 if f in ancestor and not mctx[f].cmp(ancestor[f]):
Martin von Zweigbergk
merge: extract _resolvetrivial() function...
r23531 # remote did change but ended up with same content
Pulkit Goyal
merge: pass mergeresult obj instead of actions dict in _resolvetrivial()...
r45843 mresult.removefile(f) # don't get = keep local deleted
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
merge: extract _resolvetrivial() function...
r23531
Augie Fackler
formatting: blacken the codebase...
r43346 def calculateupdates(
repo,
wctx,
mctx,
ancestors,
branchmerge,
force,
acceptremote,
followcopies,
matcher=None,
mergeforce=False,
):
Pulkit Goyal
merge: document return values of manifestmerge() and calculateupdates()...
r45728 """
Calculate the actions needed to merge mctx into wctx using ancestors
Uses manifestmerge() to merge manifest and get list of actions required to
perform for merging two manifests. If there are multiple ancestors, uses bid
merge if enabled.
Also filters out actions which are unrequired if repository is sparse.
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 Returns mergeresult object same as manifestmerge().
Pulkit Goyal
merge: document return values of manifestmerge() and calculateupdates()...
r45728 """
Gregory Szorc
sparse: refactor update actions filtering and call from core...
r33323 # Avoid cycle.
from . import sparse
Pulkit Goyal
merge: make mergeresult constructor initialize empty object...
r45838 mresult = None
Augie Fackler
formatting: blacken the codebase...
r43346 if len(ancestors) == 1: # default
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 mresult = manifestmerge(
Augie Fackler
formatting: blacken the codebase...
r43346 repo,
wctx,
mctx,
ancestors[0],
branchmerge,
force,
matcher,
acceptremote,
followcopies,
)
Pulkit Goyal
merge: pass mergeresult instead of actions in _checkunknownfiles() (API)...
r45844 _checkunknownfiles(repo, wctx, mctx, force, mresult, mergeforce)
Arseniy Alekseyev
debug: add a config to abort update early...
r50778 if repo.ui.configbool(b'devel', b'debug.abort-update'):
exit(1)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385
Augie Fackler
formatting: blacken the codebase...
r43346 else: # only when merge.preferancestor=* - the default
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 repo.ui.note(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b"note: merging %s and %s using bids from ancestors %s\n")
Augie Fackler
formatting: blacken the codebase...
r43346 % (
wctx,
mctx,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b' and ').join(pycompat.bytestr(anc) for anc in ancestors),
Augie Fackler
formatting: blacken the codebase...
r43346 )
)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385
Pulkit Goyal
merge: improve documentation of fbid dict used for merge bid...
r45837 # mapping filename to bids (action method to list af actions)
# {FILENAME1 : BID1, FILENAME2 : BID2}
# BID is another dictionary which contains
# mapping of following form:
# {ACTION_X : [info, ..], ACTION_Y : [info, ..]}
fbids = {}
Pulkit Goyal
merge: update commitinfo from all mergeresults during bid merge...
r46042 mresult = mergeresult()
Martin von Zweigbergk
merge: don't treat 'diverge' and 'renamedelete' like actions...
r23526 diverge, renamedelete = None, None
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 for ancestor in ancestors:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b'\ncalculating bids for ancestor %s\n') % ancestor)
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 mresult1 = manifestmerge(
Augie Fackler
formatting: blacken the codebase...
r43346 repo,
wctx,
mctx,
ancestor,
branchmerge,
force,
matcher,
acceptremote,
followcopies,
forcefulldiff=True,
)
Pulkit Goyal
merge: pass mergeresult instead of actions in _checkunknownfiles() (API)...
r45844 _checkunknownfiles(repo, wctx, mctx, force, mresult1, mergeforce)
Matt Mackall
bidmerge: choose shortest list of diverge and rename/delete warnings...
r26318
# Track the shortest set of warning on the theory that bid
# merge will correctly incorporate more information
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 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
Matt Mackall
bidmerge: choose shortest list of diverge and rename/delete warnings...
r26318
Pulkit Goyal
merge: update commitinfo from all mergeresults during bid merge...
r46042 # blindly update final mergeresult commitinfo with what we get
# from mergeresult object for each ancestor
# TODO: some commitinfo depends on what bid merge choose and hence
# we will need to make commitinfo also depend on bid merge logic
mresult._commitinfo.update(mresult1._commitinfo)
Pulkit Goyal
mergeresult: introduce filemap() which yields filename based mapping...
r45906 for f, a in mresult1.filemap(sort=True):
Martin von Zweigbergk
merge: let bid merge work on the file->action dict...
r23638 m, args, msg = a
merge-actions: make merge action a full featured object...
r49560 repo.ui.debug(b' %s: %s -> %s\n' % (f, msg, m.__bytes__()))
Martin von Zweigbergk
merge: let bid merge work on the file->action dict...
r23638 if f in fbids:
d = fbids[f]
if m in d:
d[m].append(a)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 else:
Martin von Zweigbergk
merge: let bid merge work on the file->action dict...
r23638 d[m] = [a]
else:
fbids[f] = {m: [a]}
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385
Pulkit Goyal
merge: improve documentation of fbid dict used for merge bid...
r45837 # Call for bids
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 # Pick the best bid for each file
Pulkit Goyal
merge: show number of ancestors in bid merge debug notes...
r46018 repo.ui.note(
_(b'\nauction for merging merge bids (%d ancestors)\n')
% len(ancestors)
)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 for f, bids in sorted(fbids.items()):
Pulkit Goyal
merge: show list of bids for each file in bid-merge in ui.debug()...
r46031 if repo.ui.debugflag:
repo.ui.debug(b" list of bids for %s:\n" % f)
for m, l in sorted(bids.items()):
for _f, args, msg in l:
merge-actions: make merge action a full featured object...
r49560 repo.ui.debug(b' %s -> %s\n' % (msg, m.__bytes__()))
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 # bids is a mapping from action method to list af actions
# Consensus?
Augie Fackler
formatting: blacken the codebase...
r43346 if len(bids) == 1: # all bids are the same kind of method
Pulkit Goyal
py3: explicitly convert dict.keys() and dict.items() into a list...
r34350 m, l = list(bids.items())[0]
Augie Fackler
formatting: blacken the codebase...
r43346 if all(a == l[0] for a in l[1:]): # len(bids) is > 1
merge-actions: make merge action a full featured object...
r49560 repo.ui.note(
_(b" %s: consensus for %s\n") % (f, m.__bytes__())
)
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(f, *l[0])
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 continue
# If keep is an option, just do it.
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 if mergestatemod.ACTION_KEEP in bids:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b" %s: picking 'keep' action\n") % f)
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(f, *bids[mergestatemod.ACTION_KEEP][0])
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 continue
Pulkit Goyal
merge: add `ACTION_KEEP_ABSENT` to represent files we want to keep absent...
r46039 # If keep absent is an option, just do that
if mergestatemod.ACTION_KEEP_ABSENT in bids:
repo.ui.note(_(b" %s: picking 'keep absent' action\n") % f)
mresult.addfile(f, *bids[mergestatemod.ACTION_KEEP_ABSENT][0])
continue
Pulkit Goyal
merge: if CHANGED_DELETED and KEEP_NEW are actions, choose CHANGED_DELETED...
r46194 # ACTION_KEEP_NEW and ACTION_CHANGED_DELETED are conflicting actions
# as one say that file is new while other says that file was present
# earlier too and has a change delete conflict
# Let's fall back to conflicting ACTION_CHANGED_DELETED and let user
# do the right thing
if (
mergestatemod.ACTION_CHANGED_DELETED in bids
and mergestatemod.ACTION_KEEP_NEW in bids
):
repo.ui.note(_(b" %s: picking 'changed/deleted' action\n") % f)
mresult.addfile(
f, *bids[mergestatemod.ACTION_CHANGED_DELETED][0]
)
continue
Pulkit Goyal
mergestate: introduce a new ACTION_KEEP_NEW...
r46095 # If keep new is an option, let's just do that
if mergestatemod.ACTION_KEEP_NEW in bids:
repo.ui.note(_(b" %s: picking 'keep new' action\n") % f)
mresult.addfile(f, *bids[mergestatemod.ACTION_KEEP_NEW][0])
continue
Pulkit Goyal
merge: if DELETED_CHANGED and GET are in actions, choose DELETED_CHANGED...
r46192 # ACTION_GET and ACTION_DELETE_CHANGED are conflicting actions as
# one action states the file is newer/created on remote side and
# other states that file is deleted locally and changed on remote
# side. Let's fallback and rely on a conflicting action to let user
# do the right thing
if (
mergestatemod.ACTION_DELETED_CHANGED in bids
and mergestatemod.ACTION_GET in bids
):
repo.ui.note(_(b" %s: picking 'delete/changed' action\n") % f)
mresult.addfile(
f, *bids[mergestatemod.ACTION_DELETED_CHANGED][0]
)
continue
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 # If there are gets and they all agree [how could they not?], do it.
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 if mergestatemod.ACTION_GET in bids:
ga0 = bids[mergestatemod.ACTION_GET][0]
if all(a == ga0 for a in bids[mergestatemod.ACTION_GET][1:]):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b" %s: picking 'get' action\n") % f)
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(f, *ga0)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 continue
# TODO: Consider other simple actions such as mode changes
# Handle inefficient democrazy.
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b' %s: multiple bids for merge action:\n') % f)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 for m, l in sorted(bids.items()):
for _f, args, msg in l:
merge-actions: make merge action a full featured object...
r49560 repo.ui.note(b' %s -> %s\n' % (msg, m.__bytes__()))
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 # Pick random action. TODO: Instead, prompt user when resolving
Pulkit Goyal
py3: explicitly convert dict.keys() and dict.items() into a list...
r34350 m, l = list(bids.items())[0]
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
merge-actions: make merge action a full featured object...
r49560 _(b' %s: ambiguous merge - picked %s action\n')
% (f, m.__bytes__())
Augie Fackler
formatting: blacken the codebase...
r43346 )
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(f, *l[0])
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385 continue
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b'end of auction\n\n'))
Pulkit Goyal
merge: introduce `addcommitinfo()` on mergeresult object...
r45944 mresult.updatevalues(diverge, renamedelete)
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385
Martin von Zweigbergk
merge: let _forgetremoved() work on the file->action dict...
r23640 if wctx.rev() is None:
Pulkit Goyal
merge: pass mergeresult obj in _forgetremoved() (API)...
r45907 _forgetremoved(wctx, mctx, branchmerge, mresult)
Martin von Zweigbergk
merge: let _forgetremoved() work on the file->action dict...
r23640
Pulkit Goyal
sparse: pass mergeresult obj in sparse.filterupdatesactions() (API)...
r45847 sparse.filterupdatesactions(repo, wctx, mctx, branchmerge, mresult)
Pulkit Goyal
merge: pass mergeresult obj instead of actions dict in _resolvetrivial()...
r45843 _resolvetrivial(repo, wctx, mctx, ancestors[0], mresult)
Gregory Szorc
sparse: refactor update actions filtering and call from core...
r33323
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 return mresult
Martin von Zweigbergk
merge: move calculateupdates() before applyupdated()...
r23385
Augie Fackler
formatting: blacken the codebase...
r43346
Phil Cohen
merge: move cwd-missing detection to helper functions...
r34144 def _getcwd():
try:
Matt Harbison
py3: rename pycompat.getcwd() to encoding.getcwd() (API)...
r39843 return encoding.getcwd()
Manuel Jacob
py3: catch FileNotFoundError instead of checking errno == ENOENT
r50201 except FileNotFoundError:
return None
Phil Cohen
merge: move cwd-missing detection to helper functions...
r34144
Augie Fackler
formatting: blacken the codebase...
r43346
Phil Cohen
merge: pass wctx to batchremove and batchget...
r33081 def batchremove(repo, wctx, actions):
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 """apply removes to the working directory
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630
yields tuples for progress updates
"""
Bryan O'Sullivan
merge: don't fiddle with name lookups or i18n in hot loops...
r18640 verbose = repo.ui.verbose
Phil Cohen
merge: move cwd-missing detection to helper functions...
r34144 cwd = _getcwd()
Bryan O'Sullivan
merge: report non-interactive progress in chunks...
r18633 i = 0
Mads Kiilerich
merge: use separate lists for each action type...
r21545 for f, args, msg in actions:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> r\n" % (f, msg))
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 if verbose:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"removing %s\n") % f)
Phil Cohen
workingfilectx: add audit() as a wrapper for wvfs.audit()
r33086 wctx[f].audit()
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 try:
Phil Cohen
merge: replace repo.wvfs.unlinkpath() with calls to wctx[f].remove()...
r33082 wctx[f].remove(ignoremissing=True)
Gregory Szorc
global: mass rewrite to use modern exception syntax...
r25660 except OSError as inst:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
Martin von Zweigbergk
py3: convert an exception message to bytes...
r46280 _(b"update failed to remove %s: %s!\n")
Matt Harbison
merge: force an exception message to bytes before printing as a warning...
r47519 % (f, stringutil.forcebytestr(inst.strerror))
Augie Fackler
formatting: blacken the codebase...
r43346 )
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 if i == 100:
yield i, f
i = 0
i += 1
if i > 0:
yield i, f
Phil Cohen
merge: move cwd-missing detection to helper functions...
r34144
if cwd and not _getcwd():
# cwd was removed in the course of removing files; print a helpful
# warning.
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"current directory was removed\n"
b"(consider changing to repo root: %s)\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% repo.root
)
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 def batchget(repo, mctx, wctx, wantfiledata, actions):
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 """apply gets to the working directory
mctx is the context to get from
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 Yields arbitrarily many (False, tuple) for progress updates, followed by
exactly one (True, filedata). When wantfiledata is false, filedata is an
Valentin Gatien-Baron
update: fix spurious unclean status bug shown by previous commit...
r42722 empty dict. When wantfiledata is true, filedata[f] is a triple (mode, size,
mtime) of the file f written for each action.
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 """
Valentin Gatien-Baron
update: fix spurious unclean status bug shown by previous commit...
r42722 filedata = {}
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 verbose = repo.ui.verbose
fctx = mctx.filectx
Siddharth Agarwal
batchget: add support for backing up files...
r27656 ui = repo.ui
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 i = 0
Gregory Szorc
merge: perform background file closing in batchget...
r28200 with repo.wvfs.backgroundclosing(ui, expectedcount=len(actions)):
Gregory Szorc
merge: indent code in batchget()...
r28199 for f, (flags, backup), msg in actions:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> g\n" % (f, msg))
Gregory Szorc
merge: indent code in batchget()...
r28199 if verbose:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"getting %s\n") % f)
Siddharth Agarwal
batchget: add support for backing up files...
r27656
Gregory Szorc
merge: indent code in batchget()...
r28199 if backup:
Mark Thomas
merge: backup conflicting directories when getting files...
r34550 # If a file or directory exists with the same name, back that
# up. Otherwise, look to see if there is a file that conflicts
# with a directory this file is in, and if so, back that up.
Martin von Zweigbergk
merge: don't unnecessarily calculate absolute path...
r41711 conflicting = f
Mark Thomas
merge: backup conflicting directories when getting files...
r34550 if not repo.wvfs.lexists(f):
Martin von Zweigbergk
utils: move finddirs() to pathutil...
r44032 for p in pathutil.finddirs(f):
Mark Thomas
merge: backup conflicting directories when getting files...
r34550 if repo.wvfs.isfileorlink(p):
Martin von Zweigbergk
merge: don't unnecessarily calculate absolute path...
r41711 conflicting = p
Mark Thomas
merge: backup conflicting directories when getting files...
r34550 break
Martin von Zweigbergk
merge: don't unnecessarily calculate absolute path...
r41711 if repo.wvfs.lexists(conflicting):
Martin von Zweigbergk
merge: migrate to scmutil.backuppath()...
r41750 orig = scmutil.backuppath(ui, repo, conflicting)
util.rename(repo.wjoin(conflicting), orig)
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 wfctx = wctx[f]
wfctx.clearunknown()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 atomictemp = ui.configbool(b"experimental", b"update.atomic-file")
Augie Fackler
formatting: blacken the codebase...
r43346 size = wfctx.write(
fctx(f).data(),
flags,
backgroundclose=True,
atomictemp=atomictemp,
)
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 if wantfiledata:
dirstate: add a comment about a racy piece of code during updates...
r49200 # XXX note that there is a race window between the time we
# write the clean data into the file and we stats it. So another
# writing process meddling with the file content right after we
# wrote it could cause bad stat data to be gathered.
#
# They are 2 data we gather here
# - the mode:
# That we actually just wrote, we should not need to read
# it from disk, (except not all mode might have survived
# the disk round-trip, which is another issue: we should
# not depends on this)
# - the mtime,
# On system that support nanosecond precision, the mtime
# could be accurate enough to tell the two writes appart.
# However gathering it in a racy way make the mtime we
# gather "unreliable".
#
# (note: we get the size from the data we write, which is sane)
#
# So in theory the data returned here are fully racy, but in
# practice "it works mostly fine".
#
# Do not be surprised if you end up reading this while looking
# for the causes of some buggy status. Feel free to improve
# this in the future, but we cannot simply stop gathering
# information. Otherwise `hg status` call made after a large `hg
# update` runs would have to redo a similar amount of work to
# restore and compare all files content.
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 s = wfctx.lstat()
mode = s.st_mode
Simon Sapin
dirstate: store mtimes with nanosecond precision in memory...
r49079 mtime = timestamp.mtime_of(s)
# for dirstate.update_file's parentfiledata argument:
filedata[f] = (mode, size, mtime)
Gregory Szorc
merge: indent code in batchget()...
r28199 if i == 100:
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 yield False, (i, f)
Gregory Szorc
merge: indent code in batchget()...
r28199 i = 0
i += 1
Bryan O'Sullivan
merge: report non-interactive progress in chunks...
r18633 if i > 0:
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 yield False, (i, f)
yield True, filedata
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: pass mergeresult obj in merge._prefetchfiles()...
r45895 def _prefetchfiles(repo, ctx, mresult):
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 """Invoke ``scmutil.prefetchfiles()`` for the files relevant to the dict
Matt Harbison
merge: invoke scmutil.fileprefetchhooks() prior to applying updates...
r36159 of merge actions. ``ctx`` is the context being merged in."""
# Skipping 'a', 'am', 'f', 'r', 'dm', 'e', 'k', 'p' and 'pr', because they
# don't touch the context to be merged in. 'cd' is skipped, because
# changed/deleted never resolves to something from the remote side.
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 files = mresult.files(
Pulkit Goyal
merge: pass mergeresult obj in merge._prefetchfiles()...
r45895 [
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_GET,
mergestatemod.ACTION_DELETED_CHANGED,
mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
mergestatemod.ACTION_MERGE,
Pulkit Goyal
merge: pass mergeresult obj in merge._prefetchfiles()...
r45895 ]
Pulkit Goyal
mergeresult: add `files()` and use it...
r45905 )
Pulkit Goyal
merge: pass mergeresult obj in merge._prefetchfiles()...
r45895
Matt Harbison
scmutil: teach the file prefetch hook to handle multiple commits...
r37780 prefetch = scmutil.prefetchfiles
matchfiles = scmutil.matchfiles
Augie Fackler
formatting: blacken the codebase...
r43346 prefetch(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 repo,
[
(
ctx.rev(),
matchfiles(repo, files),
)
],
Augie Fackler
formatting: blacken the codebase...
r43346 )
Phil Cohen
merge: flush any deferred writes before, and after, running any workers...
r34126
Gregory Szorc
merge: return an attrs class from update() and applyupdates()...
r37125 @attr.s(frozen=True)
Gregory Szorc
py3: use class X: instead of class X(object):...
r49801 class updateresult:
Gregory Szorc
merge: return an attrs class from update() and applyupdates()...
r37125 updatedcount = attr.ib()
mergedcount = attr.ib()
removedcount = attr.ib()
unresolvedcount = attr.ib()
Gregory Szorc
merge: deprecate accessing update results by index...
r37143 def isempty(self):
Augie Fackler
formatting: blacken the codebase...
r43346 return not (
self.updatedcount
or self.mergedcount
or self.removedcount
or self.unresolvedcount
)
Gregory Szorc
merge: deprecate accessing update results by index...
r37143
Augie Fackler
formatting: blacken the codebase...
r43346 def applyupdates(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 repo,
mresult,
wctx,
mctx,
overwrite,
wantfiledata,
labels=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Peter Arrenbrecht
merge: pass constant cset ancestor to fctx.ancestor
r11454 """apply the merge action list to the working directory
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 mresult is a mergeresult object representing result of the merge
Peter Arrenbrecht
merge: pass constant cset ancestor to fctx.ancestor
r11454 wctx is the working copy context
mctx is the context to be merged into the working copy
Greg Ward
merge: document some internal return values.
r13162
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 Return a tuple of (counts, filedata), where counts is a tuple
(updated, merged, removed, unresolved) that describes how many
files were affected by the update, and filedata is as described in
batchget.
Peter Arrenbrecht
merge: pass constant cset ancestor to fctx.ancestor
r11454 """
Matt Mackall
merge: update some docstrings
r3315
Pulkit Goyal
merge: pass mergeresult obj in merge._prefetchfiles()...
r45895 _prefetchfiles(repo, mctx, mresult)
Matt Harbison
merge: invoke scmutil.fileprefetchhooks() prior to applying updates...
r36159
Siddharth Agarwal
merge.applyupdates: use counters from mergestate...
r27078 updated, merged, removed = 0, 0, 0
Martin von Zweigbergk
merge: use in-memory mergestate when using in-memory context...
r46071 ms = wctx.mergestate(clean=True)
Martin von Zweigbergk
mergestate: make clean() only be about creating a clean mergestate...
r46065 ms.start(wctx.p1().node(), mctx.node(), labels)
Pulkit Goyal
mergestate: store about files resolved in favour of other...
r45178
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for f, op in mresult.commitinfo.items():
Pulkit Goyal
merge: pass commitinfo to applyupdates() and get it stored in mergestate...
r45833 # the other side of filenode was choosen while merging, store this in
# mergestate so that it can be reused on commit
Pulkit Goyal
mergestate: replace `addmergedother()` with generic `addcommitinfo()` (API)...
r45945 ms.addcommitinfo(f, op)
Pulkit Goyal
merge: pass commitinfo to applyupdates() and get it stored in mergestate...
r45833
merge-actions: add an explicite "no_op" attribute...
r49562 num_no_op = mresult.len(mergestatemod.MergeAction.NO_OP_ACTIONS)
numupdates = mresult.len() - num_no_op
Augie Fackler
formatting: blacken the codebase...
r43346 progress = repo.ui.makeprogress(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 _(b'updating'), unit=_(b'files'), total=numupdates
Augie Fackler
formatting: blacken the codebase...
r43346 )
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 if b'.hgsubstate' in mresult._actionmapping[mergestatemod.ACTION_REMOVE]:
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
Bryan O'Sullivan
merge: handle subrepo merges and .hgsubstate specially...
r18632
Mark Thomas
merge: add merge action 'p' to record path conflicts during update...
r34548 # record path conflicts
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
[mergestatemod.ACTION_PATH_CONFLICT], sort=True
):
Mark Thomas
merge: add merge action 'p' to record path conflicts during update...
r34548 f1, fo = args
s = repo.ui.status
Augie Fackler
formatting: blacken the codebase...
r43346 s(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"%s: path conflict - a file or link has the same name as a "
b"directory\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% f
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if fo == b'l':
s(_(b"the local file has been renamed to %s\n") % f1)
Mark Thomas
merge: add merge action 'p' to record path conflicts during update...
r34548 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 s(_(b"the remote file has been renamed to %s\n") % f1)
s(_(b"resolve manually then use 'hg resolve --mark %s'\n") % f)
Pulkit Goyal
mergestate: rename addpath() -> addpathonflict() to prevent confusion...
r45719 ms.addpathconflict(f, f1, fo)
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Mark Thomas
merge: add merge action 'p' to record path conflicts during update...
r34548
Phil Cohen
merge: don't use workers in in-memory mode...
r34787 # When merging in-memory, we can't support worker processes, so set the
# per-item cost at 0 in that case.
cost = 0 if wctx.isinmemory() else 0.001
Mark Thomas
merge: add merge action 'pr' to rename files during update...
r34549 # remove in parallel (must come before resolving path conflicts and getting)
Augie Fackler
formatting: blacken the codebase...
r43346 prog = worker.worker(
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 repo.ui,
cost,
batchremove,
(repo, wctx),
Pulkit Goyal
mergeresult: yield from getactions() instead of buidling a list and returning...
r45900 list(mresult.getactions([mergestatemod.ACTION_REMOVE], sort=True)),
Augie Fackler
formatting: blacken the codebase...
r43346 )
FUJIWARA Katsunori
merge: increase safety of parallel updating/removing on icasefs...
r19095 for i, item in prog:
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(step=i, item=item)
Pulkit Goyal
mergeresult: implement a len() function and use it...
r45898 removed = mresult.len((mergestatemod.ACTION_REMOVE,))
Mads Kiilerich
merge: move constant assignments a bit and use them more
r21390
Mark Thomas
merge: add merge action 'pr' to rename files during update...
r34549 # resolve path conflicts (must come before getting)
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
[mergestatemod.ACTION_PATH_CONFLICT_RESOLVE], sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> pr\n" % (f, msg))
Martin von Zweigbergk
merge: move an inspection of the dirstate from record to calculate phase...
r45465 (f0, origf0) = args
Mark Thomas
merge: add merge action 'pr' to rename files during update...
r34549 if wctx[f0].lexists():
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"moving %s to %s\n") % (f0, f))
Mark Thomas
merge: add merge action 'pr' to rename files during update...
r34549 wctx[f].audit()
wctx[f].write(wctx.filectx(f0).data(), wctx.filectx(f0).flags())
wctx[f0].remove()
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Mark Thomas
merge: add merge action 'pr' to rename files during update...
r34549
Gregory Szorc
merge: mark file gets as not thread safe (issue5933)...
r38755 # get in parallel.
Augie Fackler
formatting: blacken the codebase...
r43346 threadsafe = repo.ui.configbool(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'experimental', b'worker.wdir-get-thread-safe'
Augie Fackler
formatting: blacken the codebase...
r43346 )
prog = worker.worker(
repo.ui,
cost,
batchget,
(repo, mctx, wctx, wantfiledata),
Pulkit Goyal
mergeresult: yield from getactions() instead of buidling a list and returning...
r45900 list(mresult.getactions([mergestatemod.ACTION_GET], sort=True)),
Augie Fackler
formatting: blacken the codebase...
r43346 threadsafe=threadsafe,
hasretval=True,
)
Valentin Gatien-Baron
update: fix spurious unclean status bug shown by previous commit...
r42722 getfiledata = {}
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 for final, res in prog:
if final:
getfiledata = res
else:
i, item = res
progress.increment(step=i, item=item)
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 if b'.hgsubstate' in mresult._actionmapping[mergestatemod.ACTION_GET]:
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 subrepoutil.submerge(repo, wctx, mctx, wctx, overwrite, labels)
Bryan O'Sullivan
merge: handle subrepo merges and .hgsubstate specially...
r18632
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # forget (manifest only, just log it) (must come first)
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
(mergestatemod.ACTION_FORGET,), sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> f\n" % (f, msg))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # re-add (manifest only, just log it)
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
(mergestatemod.ACTION_ADD,), sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> a\n" % (f, msg))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Siddharth Agarwal
merge: add a new action type representing files to add/mark as modified...
r27131 # re-add/mark as modified (manifest only, just log it)
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
(mergestatemod.ACTION_ADD_MODIFIED,), sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> am\n" % (f, msg))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Siddharth Agarwal
merge: add a new action type representing files to add/mark as modified...
r27131
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # keep (noop, just log it)
merge-actions: add an explicite "no_op" attribute...
r49562 for a in mergestatemod.MergeAction.NO_OP_ACTIONS:
Pulkit Goyal
mergestate: introduce a new ACTION_KEEP_NEW...
r46095 for f, args, msg in mresult.getactions((a,), sort=True):
merge-actions: make merge action a full featured object...
r49560 repo.ui.debug(b" %s: %s -> %s\n" % (f, msg, a.__bytes__()))
Pulkit Goyal
mergestate: introduce a new ACTION_KEEP_NEW...
r46095 # no progress
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # directory rename, move local
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
(mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,), sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> dm\n" % (f, msg))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 f0, flags = args
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"moving %s to %s\n") % (f0, f))
Phil Cohen
workingfilectx: add audit() as a wrapper for wvfs.audit()
r33086 wctx[f].audit()
Phil Cohen
merge: convert repo.wwrite() calls to wctx[f].write()...
r33083 wctx[f].write(wctx.filectx(f0).data(), flags)
Phil Cohen
merge: replace repo.wvfs.unlinkpath() with calls to wctx[f].remove()...
r33082 wctx[f0].remove()
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # local directory rename, get
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
(mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,), sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> dg\n" % (f, msg))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 f0, flags = args
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b"getting %s to %s\n") % (f0, f))
Phil Cohen
merge: convert repo.wwrite() calls to wctx[f].write()...
r33083 wctx[f].write(mctx.filectx(f0).data(), flags)
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # exec
Pulkit Goyal
merge: replace use of actions dict with mergeresult object...
r45897 for f, args, msg in mresult.getactions(
(mergestatemod.ACTION_EXEC,), sort=True
):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.debug(b" %s: %s -> e\n" % (f, msg))
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Augie Fackler
formatting: blacken the codebase...
r43346 (flags,) = args
Phil Cohen
workingfilectx: add audit() as a wrapper for wvfs.audit()
r33086 wctx[f].audit()
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 wctx[f].setflags(b'l' in flags, b'x' in flags)
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Pulkit Goyal
merge: move initial handling of mergeactions near to later one...
r46060 moves = []
# 'cd' and 'dc' actions are treated like other merge conflicts
mergeactions = list(
mresult.getactions(
[
mergestatemod.ACTION_CHANGED_DELETED,
mergestatemod.ACTION_DELETED_CHANGED,
mergestatemod.ACTION_MERGE,
],
sort=True,
)
)
for f, args, msg in mergeactions:
f1, f2, fa, move, anc = args
if f == b'.hgsubstate': # merged internally
continue
if f1 is None:
fcl = filemerge.absentfilectx(wctx, fa)
else:
repo.ui.debug(b" preserving %s for resolve of %s\n" % (f1, f))
fcl = wctx[f1]
if f2 is None:
fco = filemerge.absentfilectx(mctx, fa)
else:
fco = mctx[f2]
actx = repo[anc]
if fa in actx:
fca = actx[fa]
else:
# TODO: move to absentfilectx
fca = repo.filectx(f1, fileid=nullrev)
ms.add(fcl, fco, fca, f)
if f1 != f and move:
moves.append(f1)
# remove renamed files after safely stored
for f in moves:
if wctx[f].lexists():
repo.ui.debug(b"removing %s\n" % f)
wctx[f].audit()
wctx[f].remove()
Pulkit Goyal
applyupdates: simplfy calculation of number of updated files...
r45901 # these actions updates the file
updated = mresult.len(
(
mergestatemod.ACTION_GET,
mergestatemod.ACTION_EXEC,
mergestatemod.ACTION_LOCAL_DIR_RENAME_GET,
mergestatemod.ACTION_DIR_RENAME_MOVE_LOCAL,
)
)
Siddharth Agarwal
merge.applyupdates: call driverpreprocess before starting merge actions...
r26786
Ryan McElroy
merge: ensure that we always commit the mergestate...
r34681 try:
for f, args, msg in mergeactions:
Martin von Zweigbergk
mergestate: merge `preresolve()` into `resolve()`...
r49256 repo.ui.debug(b" %s: %s -> m\n" % (f, msg))
Pulkit Goyal
commit: get info from mergestate whether a file was merged or not...
r47567 ms.addcommitinfo(f, {b'merged': b'yes'})
Martin von Zweigbergk
progress: create helper class for incrementing progress...
r38364 progress.increment(item=f)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if f == b'.hgsubstate': # subrepo states need updating
Augie Fackler
formatting: blacken the codebase...
r43346 subrepoutil.submerge(
repo, wctx, mctx, wctx.ancestor(mctx), overwrite, labels
)
Ryan McElroy
merge: ensure that we always commit the mergestate...
r34681 continue
wctx[f].audit()
ms.resolve(f, wctx)
Siddharth Agarwal
merge: move merge step to the end...
r26292
Kyle Lippincott
merge-halt: fix issue with merge.on-failure=halt breaking unshelve...
r49092 except error.InterventionRequired:
# If the user has merge.on-failure=halt, catch the error and close the
# merge state "properly".
pass
Ryan McElroy
merge: ensure that we always commit the mergestate...
r34681 finally:
ms.commit()
Siddharth Agarwal
merge.applyupdates: call driverconclude after performing merge actions...
r26787
Siddharth Agarwal
merge.applyupdates: use counters from mergestate...
r27078 unresolved = ms.unresolvedcount()
msupdated, msmerged, msremoved = ms.counts()
updated += msupdated
merged += msmerged
removed += msremoved
Siddharth Agarwal
merge.applyupdates: extend action queues with ones returned from mergestate...
r27080
extraactions = ms.actions()
Martin von Zweigbergk
progress: hide update(None) in a new complete() method...
r38392 progress.complete()
Martin von Zweigbergk
merge: make applyupdates() not mutate mresult argument...
r48163 return (
updateresult(updated, merged, removed, unresolved),
getfiledata,
extraactions,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111
Augie Fackler
formatting: blacken the codebase...
r43346
Pulkit Goyal
merge: refactor code to advise fsmonitor in separate function...
r45727 def _advertisefsmonitor(repo, num_gets, p1node):
# Advertise fsmonitor when its presence could be useful.
#
# We only advertise when performing an update from an empty working
# directory. This typically only occurs during initial clone.
#
# We give users a mechanism to disable the warning in case it is
# annoying.
#
# We only allow on Linux and MacOS because that's where fsmonitor is
# considered stable.
fsmonitorwarning = repo.ui.configbool(b'fsmonitor', b'warn_when_unused')
fsmonitorthreshold = repo.ui.configint(
b'fsmonitor', b'warn_update_file_count'
)
Valentin Gatien-Baron
fsmonitor: increase the threshold before we recommend it, when using rust...
r46034 # avoid cycle dirstate -> sparse -> merge -> dirstate
Raphaël Gomès
merge: remove direct rustmod reference...
r49660 dirstate_rustmod = policy.importrust("dirstate")
Valentin Gatien-Baron
fsmonitor: increase the threshold before we recommend it, when using rust...
r46034
Raphaël Gomès
merge: remove direct rustmod reference...
r49660 if dirstate_rustmod is not None:
Valentin Gatien-Baron
fsmonitor: increase the threshold before we recommend it, when using rust...
r46034 # When using rust status, fsmonitor becomes necessary at higher sizes
fsmonitorthreshold = repo.ui.configint(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 b'fsmonitor',
b'warn_update_file_count_rust',
Valentin Gatien-Baron
fsmonitor: increase the threshold before we recommend it, when using rust...
r46034 )
Pulkit Goyal
merge: refactor code to advise fsmonitor in separate function...
r45727 try:
# avoid cycle: extensions -> cmdutil -> merge
from . import extensions
extensions.find(b'fsmonitor')
fsmonitorenabled = repo.ui.config(b'fsmonitor', b'mode') != b'off'
# We intentionally don't look at whether fsmonitor has disabled
# itself because a) fsmonitor may have already printed a warning
# b) we only care about the config state here.
except KeyError:
fsmonitorenabled = False
if (
fsmonitorwarning
and not fsmonitorenabled
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 and p1node == repo.nullid
Pulkit Goyal
merge: refactor code to advise fsmonitor in separate function...
r45727 and num_gets >= fsmonitorthreshold
and pycompat.sysplatform.startswith((b'linux', b'darwin'))
):
repo.ui.warn(
_(
b'(warning: large working directory being used without '
b'fsmonitor enabled; enable fsmonitor to improve performance; '
b'see "hg help -e fsmonitor")\n'
)
)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 UPDATECHECK_ABORT = b'abort' # handled at higher layers
UPDATECHECK_NONE = b'none'
UPDATECHECK_LINEAR = b'linear'
UPDATECHECK_NO_CONFLICT = b'noconflict'
Augie Fackler
merge: replace magic strings with NAMED_CONSTANTS (API)...
r43240
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 # Let extensions turn off any Rust code in the update code if that interferes
# will their patching.
# This being `True` does not mean that you have Rust extensions installed or
# that the Rust path will be taken for any given invocation.
MAYBE_USE_RUST_UPDATE = True
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
merge: make low-level update() private (API)...
r46134 def _update(
Augie Fackler
formatting: blacken the codebase...
r43346 repo,
node,
branchmerge,
force,
ancestor=None,
mergeancestor=False,
labels=None,
matcher=None,
mergeforce=False,
Martin von Zweigbergk
merge: introduce a revert_to() for that use-case...
r44744 updatedirstate=True,
Augie Fackler
formatting: blacken the codebase...
r43346 updatecheck=None,
wc=None,
):
Matt Mackall
merge: update some docstrings
r3315 """
Perform a merge between the working directory and the given node
Martin von Zweigbergk
merge: remove unused handling of default destination in merge.update()...
r30902 node = the node to update to
Matt Mackall
merge: update some docstrings
r3315 branchmerge = whether to merge between branches
force = whether to force branch merging or file overwriting
Augie Fackler
merge: have merge.update use a matcher instead of partial fn...
r27344 matcher = a matcher to filter file lists (dirstate not updated)
Durham Goode
rebase: fix --collapse when a file was added then removed...
r18778 mergeancestor = whether it is merging with an ancestor. If true,
we should accept the incoming changes for any prompts that occur.
If false, merging with an ancestor (fast-forward) is only allowed
between different named branches. This flag is used by rebase extension
as a temporary fix and should be avoided in general.
Martin von Zweigbergk
merge: fix documented order of `labels` argument...
r49601 labels = labels to use for local, other, and base
Siddharth Agarwal
merge: tell _checkunknownfiles about whether this was merge --force...
r28020 mergeforce = whether the merge was run with 'merge --force' (deprecated): if
this is True, then 'force' should be True as well.
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
muxator
update: mention long options explicitly in description of merge.update()...
r34920 The table below shows all the behaviors of the update command given the
-c/--check and -C/--clean or no options, whether the working directory is
dirty, whether a revision is specified, and the relationship of the parent
rev to the target rev (linear or not). Match from top first. The -n
option doesn't exist on the command line, but represents the
Martin von Zweigbergk
update: allow setting default update check to "noconflict"...
r31168 experimental.updatecheck=noconflict option.
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
Adrian Buehlmann
combine tests
r12279 This logic is tested by test-update-branches.t.
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
Martin von Zweigbergk
update: allow setting default update check to "noconflict"...
r31168 -c -C -n -m dirty rev linear | result
y y * * * * * | (1)
y * y * * * * | (1)
y * * y * * * | (1)
* y y * * * * | (1)
* y * y * * * | (1)
* * y y * * * | (1)
* * * * * n n | x
* * * * n * * | ok
n n n n y * y | merge
n n n n y y n | (2)
n n n y y * * | merge
n n y n y * * | merge if no conflict
n y n n y * * | discard
y n n n y * * | (3)
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
x = can't happen
* = don't-care
Martin von Zweigbergk
merge: move "incompatible options" case first in docstring table
r31161 1 = incompatible options (checked in commands.py)
2 = abort: uncommitted changes (commit or update --clean to discard changes)
3 = abort: uncommitted changes (checked in commands.py)
Greg Ward
merge: document some internal return values.
r13162
Phil Cohen
merge: allow a custom working context to be passed to update...
r34303 The merge is performed inside ``wc``, a workingctx-like objects. It defaults
to repo[None] if None is passed.
Greg Ward
merge: document some internal return values.
r13162 Return the same tuple as applyupdates().
Matt Mackall
merge: update some docstrings
r3315 """
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321 # Avoid cycle.
from . import sparse
Matt Mackall
Merge: combine force and forcemerge arguments
r2815
Martin von Zweigbergk
update: accept --merge to allow merging across topo branches (issue5125)
r31166 # This function used to find the default destination if node was None, but
Martin von Zweigbergk
merge: remove unused handling of default destination in merge.update()...
r30902 # that's now in destutil.py.
assert node is not None
Martin von Zweigbergk
update: accept --merge to allow merging across topo branches (issue5125)
r31166 if not branchmerge and not force:
# TODO: remove the default once all callers that pass branchmerge=False
# and force=False pass a value for updatecheck. We may want to allow
# updatecheck='abort' to better suppport some of these callers.
if updatecheck is None:
Augie Fackler
merge: replace magic strings with NAMED_CONSTANTS (API)...
r43240 updatecheck = UPDATECHECK_LINEAR
merge: break up two not-so-one-liner for extra readability...
r49552 okay = (UPDATECHECK_NONE, UPDATECHECK_LINEAR, UPDATECHECK_NO_CONFLICT)
if updatecheck not in okay:
msg = r'Invalid updatecheck %r (can accept %r)'
msg %= (updatecheck, okay)
raise ValueError(msg)
Martin von Zweigbergk
merge: don't grab wlock when merging in memory...
r45536 if wc is not None and wc.isinmemory():
maybe_wlock = util.nullcontextmanager()
else:
maybe_wlock = repo.wlock()
with maybe_wlock:
Phil Cohen
merge: allow a custom working context to be passed to update...
r34303 if wc is None:
wc = repo[None]
Sean Farley
merge: refactor initialization of variables in update...
r20279 pl = wc.parents()
p1 = pl[0]
Martin von Zweigbergk
merge: reorder some initialization to make more sense...
r42601 p2 = repo[node]
Mads Kiilerich
merge: 0 is a valid ancestor different from None...
r23405 if ancestor is not None:
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [repo[ancestor]]
Martin von Zweigbergk
merge: simplify initialization of "pas"...
r42602 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 if repo.ui.configlist(b'merge', b'preferancestor') == [b'*']:
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 pas = [repo[anc] for anc in (sorted(cahs) or [repo.nullid])]
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 else:
Mads Kiilerich
merge: show the scary multiple ancestor hint for merges only, not for updates...
r22179 pas = [p1.ancestor(p2, warn=branchmerge)]
Matt Mackall
merge: add ancestor to the update function...
r13874
Augie Fackler
merge: coerce nodes to bytes, not str...
r36195 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), bytes(p1), bytes(p2)
Matt Mackall
merge: various tidying...
r3314
Martin von Zweigbergk
merge: reorder some initialization to make more sense...
r42601 overwrite = force and not branchmerge
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 ### check phase
Martin von Zweigbergk
merge: refuse update/merge if there are unresolved conflicts (BC)...
r27316 if not overwrite:
if len(pl) > 1:
Martin von Zweigbergk
errors: use StateError more in merge module...
r47146 raise error.StateError(_(b"outstanding uncommitted merge"))
Martin von Zweigbergk
merge: use in-memory mergestate when using in-memory context...
r46071 ms = wc.mergestate()
Augie Fackler
cleanup: use mergestate.unresolvedcount() instead of bool(list(unresolved()))...
r47070 if ms.unresolvedcount():
merge: break up two not-so-one-liner for extra readability...
r49552 msg = _(b"outstanding merge conflicts")
hint = _(b"use 'hg resolve' to resolve")
raise error.StateError(msg, hint=hint)
Matt Mackall
update: better logic and messages for updates...
r6375 if branchmerge:
merge: break up a not-so-one-liner for readability...
r49553 m_a = _(b"merging with a working directory ancestor has no effect")
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 if pas == [p2]:
merge: break up a not-so-one-liner for readability...
r49553 raise error.Abort(m_a)
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 elif pas == [p1]:
Mads Kiilerich
merge: check current wc branch for 'nothing to merge', not its p1...
r31379 if not mergeancestor and wc.branch() == p2.branch():
merge: break up a not-so-one-liner for readability...
r49554 msg = _(b"nothing to merge")
hint = _(b"use 'hg update' or check 'hg heads'")
raise error.Abort(msg, hint=hint)
Matt Mackall
update: better logic and messages for updates...
r6375 if not force and (wc.files() or wc.deleted()):
merge: break up a not-so-one-liner for readability...
r49555 msg = _(b"uncommitted changes")
hint = _(b"use 'hg status' to list changes")
raise error.StateError(msg, hint=hint)
Phil Cohen
merge: skip subrepo state, update hooks, and updating the dirstate in IMM...
r35285 if not wc.isinmemory():
for s in sorted(wc.substate):
wc.sub(s).bailifchanged()
Oleg Stepanov
Do not allow merging with uncommitted changes in a subrepo
r13437
Matt Mackall
update: better logic and messages for updates...
r6375 elif not overwrite:
Augie Fackler
formatting: blacken the codebase...
r43346 if p1 == p2: # no-op update
Siddharth Agarwal
merge: exit early during a no-op update (BC)...
r19929 # call the hooks and exit early
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.hook(b'preupdate', throw=True, parent1=xp2, parent2=b'')
repo.hook(b'update', parent1=xp2, parent2=b'', error=0)
Gregory Szorc
merge: return an attrs class from update() and applyupdates()...
r37125 return updateresult(0, 0, 0, 0)
Siddharth Agarwal
merge: exit early during a no-op update (BC)...
r19929
Augie Fackler
formatting: blacken the codebase...
r43346 if updatecheck == UPDATECHECK_LINEAR and pas not in (
[p1],
[p2],
): # nonlinear
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 dirty = wc.dirty(missing=True)
Martin von Zweigbergk
merge: remove unused handling of default destination in merge.update()...
r30902 if dirty:
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 # Branching is a bit strange to ensure we do the minimal
obsutil: move 'foreground' to the new modules...
r33147 # amount of call to obsutil.foreground.
foreground = obsutil.foreground(repo, [p1.node()])
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 # note: the <node> variable contains a random identifier
if repo[node].node() in foreground:
Augie Fackler
formatting: blacken the codebase...
r43346 pass # allow updating to successors
Martin von Zweigbergk
merge: remove unused handling of default destination in merge.update()...
r30902 else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 msg = _(b"uncommitted changes")
hint = _(b"commit or update --clean to discard changes")
Martin von Zweigbergk
destutil: remove duplicate check and leave it to merge.update()...
r30961 raise error.UpdateAbort(msg, hint=hint)
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 else:
# Allow jumping branches if clean and specific rev given
Martin von Zweigbergk
update: localize logic around which ancestor to use...
r30901 pass
if overwrite:
pas = [wc]
elif not branchmerge:
pas = [p1]
Matt Mackall
Merge: move most tests to the beginning
r2814
Matt Mackall
merge: mark ancient debugging option
r25843 # deprecated config: merge.followcopies
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 followcopies = repo.ui.configbool(b'merge', b'followcopies')
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 if overwrite:
Gábor Stefanik
update: enable copy tracing for backwards and non-linear updates...
r30200 followcopies = False
elif not pas[0]:
followcopies = False
if not branchmerge and not wc.dirty(missing=True):
followcopies = False
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 update_from_null = False
update_from_null_fallback = False
if (
MAYBE_USE_RUST_UPDATE
Raphaël Gomès
rust-update: add a config item to disable the Rust update fastpath...
r52954 and repo.ui.configbool(b"rust", b"update-from-null")
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 and rust_update_mod is not None
and p1.rev() == nullrev
and not branchmerge
# TODO it's probably not too hard to pass down the transaction and
# respect the write patterns from Rust. But since it doesn't affect
# a simple update from null, then it doesn't matter yet.
and repo.currenttransaction() is None
and matcher is None
and not wc.mergestate().active()
and b'.hgsubstate' not in p2
):
working_dir_iter = os.scandir(repo.root)
maybe_hg_folder = next(working_dir_iter)
assert maybe_hg_folder is not None
if maybe_hg_folder.name == b".hg":
try:
next(working_dir_iter)
except StopIteration:
update_from_null = True
if update_from_null:
# Check the narrowspec and sparsespec here to display warnings
# more easily.
# TODO figure out of a way of bubbling up warnings to Python
# while not polluting the Rust code (probably a channel)
repo.narrowmatch()
sparse.matcher(repo, [nullrev, p2.rev()])
repo.hook(b'preupdate', throw=True, parent1=xp1, parent2=xp2)
# note that we're in the middle of an update
repo.vfs.write(b'updatestate', p2.hex())
Raphaël Gomès
rust-update: make `update_from_null` respect `worker.numcpu` config option...
r53083 num_cpus = (
repo.ui.configint(b"worker", b"numcpus", None)
if repo.ui.configbool(b"worker", b"enabled")
else 1
)
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 try:
updated_count = rust_update_mod.update_from_null(
Raphaël Gomès
rust-update: make `update_from_null` respect `worker.numcpu` config option...
r53083 repo.root, p2.rev(), num_cpus
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 )
except rust_update_mod.FallbackError:
update_from_null_fallback = True
else:
# We've changed the dirstate from Rust, we need to tell Python
repo.dirstate.invalidate()
# This includes setting the parents, since they are not read
# again on invalidation
with repo.dirstate.changing_parents(repo):
repo.dirstate.setparents(fp2)
repo.dirstate.setbranch(p2.branch(), repo.currenttransaction())
sparse.prunetemporaryincludes(repo)
repo.hook(b'update', parent1=xp1, parent2=xp2, error=0)
# update completed, clear state
util.unlink(repo.vfs.join(b'updatestate'))
return updateresult(updated_count, 0, 0, 0)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 ### calculate phase
Pulkit Goyal
merge: return a mergeresult obj from manifestmerge(), calculateupdates() (API)...
r45831 mresult = calculateupdates(
Augie Fackler
formatting: blacken the codebase...
r43346 repo,
wc,
p2,
pas,
branchmerge,
force,
mergeancestor,
followcopies,
matcher=matcher,
mergeforce=mergeforce,
)
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951
Augie Fackler
merge: replace magic strings with NAMED_CONSTANTS (API)...
r43240 if updatecheck == UPDATECHECK_NO_CONFLICT:
Pulkit Goyal
merge: introduce hasconflicts() on mergeresult object...
r45835 if mresult.hasconflicts():
msg = _(b"conflicting changes")
hint = _(b"commit or update --clean to discard changes")
Martin von Zweigbergk
errors: use StateError more in merge module...
r47146 raise error.StateError(msg, hint=hint)
Martin von Zweigbergk
update: allow setting default update check to "noconflict"...
r31168
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951 # Prompt and create actions. Most of this is in the resolve phase
# already, but we can't handle .hgsubstate in filemerge or
Yuya Nishihara
subrepo: split non-core functions to new module...
r36026 # subrepoutil.submerge yet so we have to keep prompting for it.
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904 vals = mresult.getfile(b'.hgsubstate')
if vals:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 f = b'.hgsubstate'
Pulkit Goyal
mergeresult: introduce getfile() and use it where required...
r45904 m, args, msg = vals
Simon Farnsworth
merge: use labels in prompts to the user...
r29774 prompts = filemerge.partextras(labels)
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 prompts[b'f'] = f
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 if m == mergestatemod.ACTION_CHANGED_DELETED:
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951 if repo.ui.promptchoice(
Augie Fackler
formatting: blacken the codebase...
r43346 _(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"local%(l)s changed %(f)s which other%(o)s deleted\n"
b"use (c)hanged version or (d)elete?"
b"$$ &Changed $$ &Delete"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% prompts,
0,
):
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_REMOVE,
None,
b'prompt delete',
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951 elif f in p1:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_ADD_MODIFIED,
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 None,
b'prompt keep',
)
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951 else:
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 f,
mergestatemod.ACTION_ADD,
None,
b'prompt keep',
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
elif m == mergestatemod.ACTION_DELETED_CHANGED:
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951 f1, f2, fa, move, anc = args
flags = p2[f2].flags()
Augie Fackler
formatting: blacken the codebase...
r43346 if (
repo.ui.promptchoice(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"other%(o)s changed %(f)s which local%(l)s deleted\n"
b"use (c)hanged version or leave (d)eleted?"
b"$$ &Changed $$ &Deleted"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% prompts,
0,
)
== 0
):
Pulkit Goyal
merge: introduce mergeresult.addfile() and use it...
r45839 mresult.addfile(
f,
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.ACTION_GET,
Augie Fackler
formatting: blacken the codebase...
r43346 (flags, False),
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'prompt recreating',
Augie Fackler
formatting: blacken the codebase...
r43346 )
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951 else:
Pulkit Goyal
merge: add removefile() to mergeresult object...
r45840 mresult.removefile(f)
Siddharth Agarwal
merge: don't try to merge subrepos twice (issue4988)...
r27951
Martin von Zweigbergk
util: rename checkcase() to fscasesensitive() (API)...
r29889 if not util.fscasesensitive(repo.path):
Martin von Zweigbergk
merge: perform case-collision checking on final set of actions...
r23544 # check collision between files only in p2 for clean update
Augie Fackler
formatting: blacken the codebase...
r43346 if not branchmerge and (
force or not wc.dirty(missing=True, branch=False)
):
Martin von Zweigbergk
merge: perform case-collision checking on final set of actions...
r23544 _checkcollision(repo, p2.manifest(), None)
else:
Pulkit Goyal
merge: pass mergeresult obj instead of actions in _checkcollision() (API)...
r45893 _checkcollision(repo, wc.manifest(), mresult)
Martin von Zweigbergk
merge: perform case-collision checking on final set of actions...
r23544
Martin von Zweigbergk
merge: move dr/rd warning messages out of applyupdates()...
r23525 # divergent renames
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for f, fl in sorted(mresult.diverge.items()):
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"note: possible conflict - %s was renamed "
b"multiple times to:\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% f
)
Martin von Zweigbergk
copies: print list of divergent renames in sorted order...
r42279 for nf in sorted(fl):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(b" %s\n" % nf)
Martin von Zweigbergk
merge: move dr/rd warning messages out of applyupdates()...
r23525
# rename and delete
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for f, fl in sorted(mresult.renamedelete.items()):
Augie Fackler
formatting: blacken the codebase...
r43346 repo.ui.warn(
_(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b"note: possible conflict - %s was deleted "
b"and renamed to:\n"
Augie Fackler
formatting: blacken the codebase...
r43346 )
% f
)
Martin von Zweigbergk
copies: print list of divergent renames in sorted order...
r42279 for nf in sorted(fl):
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(b" %s\n" % nf)
Martin von Zweigbergk
merge: move dr/rd warning messages out of applyupdates()...
r23525
Martin von Zweigbergk
merge: move messages about possible conflicts a litte earlier...
r26957 ### apply phase
Augie Fackler
formatting: blacken the codebase...
r43346 if not branchmerge: # just jump to the new rev
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 fp1, fp2, xp1, xp2 = fp2, repo.nullid, xp2, b''
Martin von Zweigbergk
merge: move definition of `partial` closer to where it's used...
r44625 # If we're doing a partial update, we need to skip updating
Martin von Zweigbergk
merge: avoid a negation in the definition of updatedirstate...
r44626 # the dirstate.
always = matcher is None or matcher.always()
Martin von Zweigbergk
merge: introduce a revert_to() for that use-case...
r44744 updatedirstate = updatedirstate and always and not wc.isinmemory()
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 # If we're in the fallback case, we've already done this
if updatedirstate and not update_from_null_fallback:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.hook(b'preupdate', throw=True, parent1=xp1, parent2=xp2)
Martin von Zweigbergk
merge: move messages about possible conflicts a litte earlier...
r26957 # note that we're in the middle of an update
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.vfs.write(b'updatestate', p2.hex())
Martin von Zweigbergk
merge: move messages about possible conflicts a litte earlier...
r26957
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 # TODO don't run if Rust is available
Pulkit Goyal
merge: refactor code to advise fsmonitor in separate function...
r45727 _advertisefsmonitor(
Pulkit Goyal
mergeresult: implement a len() function and use it...
r45898 repo, mresult.len((mergestatemod.ACTION_GET,)), p1.node()
Augie Fackler
formatting: blacken the codebase...
r43346 )
Gregory Szorc
fsmonitor: warn when fsmonitor could be used...
r34886
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 wantfiledata = updatedirstate and not branchmerge
Martin von Zweigbergk
merge: make applyupdates() not mutate mresult argument...
r48163 stats, getfiledata, extraactions = applyupdates(
Augie Fackler
formating: upgrade to black 20.8b1...
r46554 repo,
mresult,
wc,
p2,
overwrite,
wantfiledata,
labels=labels,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Martin von Zweigbergk
merge: move messages about possible conflicts a litte earlier...
r26957
Valentin Gatien-Baron
merge: fix race that could cause wrong size in dirstate...
r42656 if updatedirstate:
Martin von Zweigbergk
merge: make applyupdates() not mutate mresult argument...
r48163 if extraactions:
Gregory Szorc
global: bulk replace simple pycompat.iteritems(x) with x.items()...
r49768 for k, acts in extraactions.items():
Martin von Zweigbergk
merge: make applyupdates() not mutate mresult argument...
r48163 for a in acts:
mresult.addfile(a[0], k, *a[1:])
if k == mergestatemod.ACTION_GET and wantfiledata:
# no filedata until mergestate is updated to provide it
for a in acts:
getfiledata[a[0]] = None
assert len(getfiledata) == (
mresult.len((mergestatemod.ACTION_GET,)) if wantfiledata else 0
)
dirstate: rename parentchange to changing_parents...
r50855 with repo.dirstate.changing_parents(repo):
update: filter the ambiguous mtime in update directly...
r49203 if getfiledata:
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951 getfiledata = filter_ambiguous_files(repo, getfiledata)
update: filter the ambiguous mtime in update directly...
r49203
Augie Fackler
merge: migrate to context manager for changing dirstate parents
r32351 repo.setparents(fp1, fp2)
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 mergestatemod.recordupdates(
Pulkit Goyal
merge: pass mergeresult obj instead of actions in applyupdates() (API)...
r45894 repo, mresult.actionsdict, branchmerge, getfiledata
Augie Fackler
mergestate: split out merge state handling code from main merge module...
r45383 )
Augie Fackler
merge: migrate to context manager for changing dirstate parents
r32351 if not branchmerge:
branch: pass current transaction when writing branch in merge
r51155 repo.dirstate.setbranch(
p2.branch(), repo.currenttransaction()
)
Sune Foldager
run commit and update hooks after command completion (issue1827)...
r10492
Raphaël Gomès
update: add a Rust fast-path when updating from null (and clean)...
r52953 # update completed, clear state
util.unlink(repo.vfs.join(b'updatestate'))
sparse: adjust the temporary includes within a `parentchange` context...
r48409 # If we're updating to a location, clean up any stale temporary includes
# (ex: this happens during hg rebase --abort).
if not branchmerge:
sparse.prunetemporaryincludes(repo)
Gregory Szorc
sparse: move pruning of temporary includes into core...
r33321
Martin von Zweigbergk
merge: don't call update hook when using in-memory context...
r44611 if updatedirstate:
Augie Fackler
formatting: blacken the codebase...
r43346 repo.hook(
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 b'update', parent1=xp1, parent2=xp2, error=stats.unresolvedcount
Augie Fackler
formatting: blacken the codebase...
r43346 )
Sune Foldager
run commit and update hooks after command completion (issue1827)...
r10492 return stats
Matt Mackall
merge: add merge.graft helper...
r22902
Augie Fackler
formatting: blacken the codebase...
r43346
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951 # filename -> (mode, size, timestamp)
FileData = Dict[bytes, Optional[Tuple[int, int, Optional[timestamp.timestamp]]]]
def filter_ambiguous_files(repo, file_data: FileData) -> Optional[FileData]:
"""We've gathered "cache" information for the clean files while updating
them: their mtime, size and mode.
At the time this comment is written, there are various issues with how we
gather the `mode` and `mtime` information (see the comment in `batchget`).
We are going to smooth one of these issues here: mtime ambiguity.
i.e. even if the mtime gathered during `batchget` was correct[1] a change
happening right after it could change the content while keeping
the same mtime[2].
When we reach the current code, the "on disk" part of the update operation
is finished. We still assume that no other process raced that "on disk"
part, but we want to at least prevent later file changes to alter the
contents of the file right after the update operation so quickly that the
same mtime is recorded for the operation.
Raphaël Gomès
merge: improve working-copy mtime race handling...
r52952
To prevent such ambiguities from happenning, we will do (up to) two things:
- wait until the filesystem clock has ticked
- only keep the "file data" for files with mtimes that are strictly in
the past, i.e. whose mtime is strictly lower than the current time.
We only wait for the system clock to tick if using dirstate-v2, since v1
only has second-level granularity and waiting for a whole second is
too much of a penalty in the general case.
Although we're assuming that people running dirstate-v2 on Linux
don't have a second-granularity FS (with the exclusion of NFS), users
can be surprising, and at some point in the future, dirstate-v2 will become
the default. To that end, we limit the wait time to 100ms and fall back
to the filtering method in case of a timeout.
+------------+------+--------------+
| version | wait | filter level |
+------------+------+--------------+
| V1 | No | Second |
| V2 | Yes | Nanosecond |
| V2-slow-fs | No | Second |
+------------+------+--------------+
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951
This protects us from race conditions from operations that could run right
after this one, especially other Mercurial operations that could be waiting
for the wlock to touch files contents and the dirstate.
In an ideal world, we could only get reliable information in `getfiledata`
Raphaël Gomès
merge: improve working-copy mtime race handling...
r52952 (from `getbatch`), however this filtering approach has been a successful
compromise for many years. A patch series of the linux kernel might change
this in 6.12³.
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951
At the time this comment is written, not using any "cache" file data at all
here would not be viable, as it would result is a very large amount of work
(equivalent to the previous `hg update` during the next status after an
update).
[1] the current code cannot grantee that the `mtime` and `mode`
are correct, but the result is "okay in practice".
(see the comment in `batchget`)
[2] using nano-second precision can greatly help here because it makes the
"different write with same mtime" issue virtually vanish. However,
dirstate v1 cannot store such precision and a bunch of python-runtime,
operating-system and filesystem parts do not provide us with such
Raphaël Gomès
merge: improve working-copy mtime race handling...
r52952 precision, so we have to operate as if it wasn't available.
[3] https://lore.kernel.org/all/20241002-mgtime-v10-8-d1c4717f5284@kernel.org
"""
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951 ambiguous_mtime: FileData = {}
Raphaël Gomès
merge: improve working-copy mtime race handling...
r52952 dirstate_v2 = repo.dirstate._use_dirstate_v2
fs_now_result = None
fast_enough_fs = True
if dirstate_v2:
fstype = util.getfstype(repo.vfs.base)
# Exclude NFS right off the bat
fast_enough_fs = fstype != b'nfs'
if fstype is not None and fast_enough_fs:
fs_now_result = timestamp.wait_until_fs_tick(repo.vfs)
if fs_now_result is None:
try:
now = timestamp.get_fs_now(repo.vfs)
fs_now_result = (now, False)
except OSError:
pass
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951 if fs_now_result is None:
# we can't write to the FS, so we won't actually update
# the dirstate content anyway, no need to put cache
# information.
return None
else:
now, timed_out = fs_now_result
if timed_out:
fast_enough_fs = False
for f, m in file_data.items():
Raphaël Gomès
merge: improve working-copy mtime race handling...
r52952 if m is not None:
reliable = timestamp.make_mtime_reliable(m[2], now)
if reliable is None or (
reliable[2] and (not dirstate_v2 or not fast_enough_fs)
):
# Either it's not reliable, or it's second ambiguous
# and we're in dirstate-v1 or in a slow fs, so discard
# the mtime.
ambiguous_mtime[f] = (m[0], m[1], None)
elif reliable[2]:
# We need to remember that this time is "second ambiguous"
# otherwise the next status might miss a subsecond change
# if its "stat" doesn't provide nanoseconds.
#
# TODO make osutil.c understand nanoseconds when possible
# (see timestamp.py for the same note)
ambiguous_mtime[f] = (m[0], m[1], reliable)
Raphaël Gomès
merge: move the filtering of ambiguous files to a dedicated function...
r52951 for f, m in ambiguous_mtime.items():
file_data[f] = m
return file_data
Martin von Zweigbergk
merge: introduce a merge() for that use-case...
r44883 def merge(ctx, labels=None, force=False, wc=None):
"""Merge another topological branch into the working copy.
force = whether the merge was run with 'merge --force' (deprecated)
"""
Martin von Zweigbergk
merge: make low-level update() private (API)...
r46134 return _update(
Martin von Zweigbergk
merge: introduce a merge() for that use-case...
r44883 ctx.repo(),
ctx.rev(),
labels=labels,
branchmerge=True,
force=force,
mergeforce=force,
wc=wc,
)
Martin von Zweigbergk
merge: add a higher-level update() for the common `hg update` use case...
r46150 def update(ctx, updatecheck=None, wc=None):
"""Do a regular update to the given commit, aborting if there are conflicts.
The 'updatecheck' argument can be used to control what to do in case of
conflicts.
Note: This is a new, higher-level update() than the one that used to exist
in this module. That function is now called _update(). You can hopefully
replace your callers to use this new update(), or clean_update(), merge(),
revert_to(), or graft().
"""
return _update(
ctx.repo(),
ctx.rev(),
branchmerge=False,
force=False,
Martin von Zweigbergk
update: set custom conflict label for base commit...
r49436 labels=[b'working copy', b'destination', b'working copy parent'],
Martin von Zweigbergk
merge: add a higher-level update() for the common `hg update` use case...
r46150 updatecheck=updatecheck,
wc=wc,
)
Martin von Zweigbergk
merge: introduce a clean_update() for that use-case...
r44743 def clean_update(ctx, wc=None):
"""Do a clean update to the given commit.
This involves updating to the commit and discarding any changes in the
working copy.
"""
Martin von Zweigbergk
merge: make low-level update() private (API)...
r46134 return _update(ctx.repo(), ctx.rev(), branchmerge=False, force=True, wc=wc)
Martin von Zweigbergk
merge: introduce a clean_update() for that use-case...
r44743
Martin von Zweigbergk
merge: introduce a revert_to() for that use-case...
r44744 def revert_to(ctx, matcher=None, wc=None):
"""Revert the working copy to the given commit.
The working copy will keep its current parent(s) but its content will
be the same as in the given commit.
"""
Martin von Zweigbergk
merge: make low-level update() private (API)...
r46134 return _update(
Martin von Zweigbergk
merge: introduce a revert_to() for that use-case...
r44744 ctx.repo(),
ctx.rev(),
branchmerge=False,
force=True,
updatedirstate=False,
matcher=matcher,
wc=wc,
)
Augie Fackler
formatting: blacken the codebase...
r43346 def graft(
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 repo,
ctx,
Martin von Zweigbergk
graft: default `base` argument to common case of `ctx.p1()`...
r44693 base=None,
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 labels=None,
keepparent=False,
keepconflictparent=False,
wctx=None,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Matt Mackall
merge: add merge.graft helper...
r22902 """Do a graft-like merge.
This is a merge where the merge ancestor is chosen such that one
or more changesets are grafted onto the current changeset. In
addition to the merge, this fixes up the dirstate to include only
Andrew Halberstadt
merge.graft: add option to keep second parent...
r27267 a single parent (if keepparent is False) and tries to duplicate any
renames/copies appropriately.
Matt Mackall
merge: add merge.graft helper...
r22902
ctx - changeset to rebase
Martin von Zweigbergk
graft: default `base` argument to common case of `ctx.p1()`...
r44693 base - merge base, or ctx.p1() if not specified
Matt Mackall
merge: add merge.graft helper...
r22902 labels - merge labels eg ['local', 'graft']
Andrew Halberstadt
merge.graft: add option to keep second parent...
r27267 keepparent - keep second parent if any
av6
merge: correct argument name in docstring...
r42604 keepconflictparent - if unresolved, keep parent used for the merge
Matt Mackall
merge: add merge.graft helper...
r22902
"""
Durham Goode
graft: allow creating sibling grafts...
r24643 # If we're grafting a descendant onto an ancestor, be sure to pass
# mergeancestor=True to update. This does two things: 1) allows the merge if
# the destination is the same as the parent of the ctx (so we can use graft
# to copy commits), and 2) informs update that the incoming changes are
# newer than the destination so it doesn't prompt about "remote changed foo
# which local deleted".
Valentin Gatien-Baron
graft: always allow hg graft --base . (issue6248)...
r44867 # We also pass mergeancestor=True when base is the same revision as p1. 2)
# doesn't matter as there can't possibly be conflicts, but 1) is necessary.
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 wctx = wctx or repo[None]
Martin von Zweigbergk
graft: extract repo[None] to a variable...
r44548 pctx = wctx.p1()
Martin von Zweigbergk
graft: default `base` argument to common case of `ctx.p1()`...
r44693 base = base or ctx.p1()
Valentin Gatien-Baron
graft: always allow hg graft --base . (issue6248)...
r44867 mergeancestor = (
repo.changelog.isancestor(pctx.node(), ctx.node())
or pctx.rev() == base.rev()
)
Matt Mackall
merge: add merge.graft helper...
r22902
Martin von Zweigbergk
merge: make low-level update() private (API)...
r46134 stats = _update(
Augie Fackler
formatting: blacken the codebase...
r43346 repo,
ctx.node(),
True,
True,
Martin von Zweigbergk
graft: rename `pctx` argument to `base` since that's what it is...
r44235 base.node(),
Augie Fackler
formatting: blacken the codebase...
r43346 mergeancestor=mergeancestor,
labels=labels,
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 wc=wctx,
Augie Fackler
formatting: blacken the codebase...
r43346 )
Boris Feld
merge: add a 'keepconflictparent' argument to graft...
r38513
if keepconflictparent and stats.unresolvedcount:
pother = ctx.node()
else:
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 pother = repo.nullid
Boris Feld
merge: add a 'keepconflictparent' argument to graft...
r38513 parents = ctx.parents()
Martin von Zweigbergk
graft: rename `pctx` argument to `base` since that's what it is...
r44235 if keepparent and len(parents) == 2 and base in parents:
parents.remove(base)
Boris Feld
merge: add a 'keepconflictparent' argument to graft...
r38513 pother = parents[0].node()
Martin von Zweigbergk
graft: never set both parents equal in the dirstate (issue6098)...
r44237 # Never set both parents equal to each other
if pother == pctx.node():
Joerg Sonnenberger
node: replace nullid and friends with nodeconstants class...
r47771 pother = repo.nullid
Andrew Halberstadt
merge.graft: add option to keep second parent...
r27267
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 if wctx.isinmemory():
wctx.setparents(pctx.node(), pother)
Augie Fackler
merge: migrate to context manager for changing dirstate parents
r32351 # fix up dirstate for copies and renames
Martin von Zweigbergk
graftcopies: remove `skip` and `repo` arguments...
r44551 copies.graftcopies(wctx, ctx, base)
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 else:
dirstate: rename parentchange to changing_parents...
r50855 with repo.dirstate.changing_parents(repo):
Martin von Zweigbergk
graft: let caller pass in overlayworkingctx to merge.graft()...
r44692 repo.setparents(pctx.node(), pother)
repo.dirstate.write(repo.currenttransaction())
# fix up dirstate for copies and renames
copies.graftcopies(wctx, ctx, base)
Matt Mackall
merge: add merge.graft helper...
r22902 return stats
Gregory Szorc
merge: move purge logic from extension...
r39499
Augie Fackler
formatting: blacken the codebase...
r43346
Martin von Zweigbergk
merge: add a back_out() function to encapsulate update()...
r46117 def back_out(ctx, parent=None, wc=None):
if parent is None:
if ctx.p2() is not None:
merge: break up a not-so-one-liner for readability...
r49556 msg = b"must specify parent of merge commit to back out"
raise error.ProgrammingError(msg)
Martin von Zweigbergk
merge: add a back_out() function to encapsulate update()...
r46117 parent = ctx.p1()
Martin von Zweigbergk
merge: make low-level update() private (API)...
r46134 return _update(
Martin von Zweigbergk
merge: add a back_out() function to encapsulate update()...
r46117 ctx.repo(),
parent,
branchmerge=True,
force=True,
ancestor=ctx.node(),
mergeancestor=False,
)
Augie Fackler
formatting: blacken the codebase...
r43346 def purge(
repo,
matcher,
Valentin Gatien-Baron
purge: add -i flag to delete ignored files instead of untracked files...
r44771 unknown=True,
Augie Fackler
formatting: blacken the codebase...
r43346 ignored=False,
removeemptydirs=True,
removefiles=True,
abortonerror=False,
noop=False,
purge: add a --confirm option...
r47078 confirm=False,
Augie Fackler
formatting: blacken the codebase...
r43346 ):
Gregory Szorc
merge: move purge logic from extension...
r39499 """Purge the working directory of untracked files.
``matcher`` is a matcher configured to scan the working directory -
potentially a subset.
Valentin Gatien-Baron
purge: add -i flag to delete ignored files instead of untracked files...
r44771 ``unknown`` controls whether unknown files should be purged.
``ignored`` controls whether ignored files should be purged.
Gregory Szorc
merge: move purge logic from extension...
r39499
``removeemptydirs`` controls whether empty directories should be removed.
``removefiles`` controls whether files are removed.
``abortonerror`` causes an exception to be raised if an error occurs
deleting a file or directory.
``noop`` controls whether to actually remove files. If not defined, actions
will be taken.
purge: add a --confirm option...
r47078 ``confirm`` ask confirmation before actually removing anything.
Gregory Szorc
merge: move purge logic from extension...
r39499 Returns an iterable of relative paths in the working directory that were
or would be removed.
"""
def remove(removefn, path):
try:
Gregory Szorc
merge: use vfs methods for I/O...
r39500 removefn(path)
Gregory Szorc
merge: move purge logic from extension...
r39499 except OSError:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 m = _(b'%s cannot be removed') % path
Gregory Szorc
merge: move purge logic from extension...
r39499 if abortonerror:
raise error.Abort(m)
else:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.warn(_(b'warning: %s\n') % m)
Gregory Szorc
merge: move purge logic from extension...
r39499
# There's no API to copy a matcher. So mutate the passed matcher and
# restore it when we're done.
oldtraversedir = matcher.traversedir
res = []
try:
if removeemptydirs:
directories = []
Martin von Zweigbergk
dirstate: include explicit matches in match.traversedir calls...
r44112 matcher.traversedir = directories.append
Gregory Szorc
merge: move purge logic from extension...
r39499
Valentin Gatien-Baron
purge: add -i flag to delete ignored files instead of untracked files...
r44771 status = repo.status(match=matcher, ignored=ignored, unknown=unknown)
Gregory Szorc
merge: move purge logic from extension...
r39499
purge: add a --confirm option...
r47078 if confirm:
purge: prevent a silly crash with --confirm --files...
r50239 msg = None
purge: add a --confirm option...
r47078 nb_ignored = len(status.ignored)
Raphaël Gomès
typo: s/unkown/unknown across the codebase...
r49252 nb_unknown = len(status.unknown)
if nb_unknown and nb_ignored:
msg = _(b"permanently delete %d unknown and %d ignored files?")
msg %= (nb_unknown, nb_ignored)
elif nb_unknown:
msg = _(b"permanently delete %d unknown files?")
msg %= nb_unknown
purge: add a --confirm option...
r47078 elif nb_ignored:
msg = _(b"permanently delete %d ignored files?")
msg %= nb_ignored
purge: also deal with directory with --confirm...
r47079 elif removeemptydirs:
dir_count = 0
for f in directories:
if matcher(f) and not repo.wvfs.listdir(f):
dir_count += 1
if dir_count:
msg = _(
b"permanently delete at least %d empty directories?"
)
msg %= dir_count
purge: prevent a silly crash with --confirm --files...
r50239 if msg is None:
return res
else:
msg += b" (yN)$$ &Yes $$ &No"
if repo.ui.promptchoice(msg, default=1) == 1:
raise error.CanceledError(_(b'removal cancelled'))
purge: add a --confirm option...
r47078
Gregory Szorc
merge: move purge logic from extension...
r39499 if removefiles:
for f in sorted(status.unknown + status.ignored):
if not noop:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b'removing file %s\n') % f)
Gregory Szorc
merge: use vfs methods for I/O...
r39500 remove(repo.wvfs.unlink, f)
Gregory Szorc
merge: move purge logic from extension...
r39499 res.append(f)
if removeemptydirs:
for f in sorted(directories, reverse=True):
Gregory Szorc
merge: use vfs methods for I/O...
r39500 if matcher(f) and not repo.wvfs.listdir(f):
Gregory Szorc
merge: move purge logic from extension...
r39499 if not noop:
Augie Fackler
formatting: byteify all mercurial/ and hgext/ string literals...
r43347 repo.ui.note(_(b'removing directory %s\n') % f)
Gregory Szorc
merge: use vfs methods for I/O...
r39500 remove(repo.wvfs.rmdir, f)
Gregory Szorc
merge: move purge logic from extension...
r39499 res.append(f)
return res
finally:
matcher.traversedir = oldtraversedir