##// END OF EJS Templates
parsers: inline fields of dirstate values in C version...
parsers: inline fields of dirstate values in C version Previously, while unpacking the dirstate we'd create 3-4 new CPython objects for most dirstate values: - the state is a single character string, which is pooled by CPython - the mode is a new object if it isn't 0 due to being in the lookup set - the size is a new object if it is greater than 255 - the mtime is a new object if it isn't -1 due to being in the lookup set - the tuple to contain them all In some cases such as regular hg status, we actually look at all the objects. In other cases like hg add, hg status for a subdirectory, or hg status with the third-party hgwatchman enabled, we look at almost none of the objects. This patch eliminates most object creation in these cases by defining a custom C struct that is exposed to Python with an interface similar to a tuple. Only when tuple elements are actually requested are the respective objects created. The gains, where they're expected, are significant. The following tests are run against a working copy with over 270,000 files. parse_dirstate becomes significantly faster: $ hg perfdirstate before: wall 0.186437 comb 0.180000 user 0.160000 sys 0.020000 (best of 35) after: wall 0.093158 comb 0.100000 user 0.090000 sys 0.010000 (best of 95) and as a result, several commands benefit: $ time hg status # with hgwatchman enabled before: 0.42s user 0.14s system 99% cpu 0.563 total after: 0.34s user 0.12s system 99% cpu 0.471 total $ time hg add new-file before: 0.85s user 0.18s system 99% cpu 1.033 total after: 0.76s user 0.17s system 99% cpu 0.931 total There is a slight regression in regular status performance, but this is fixed in an upcoming patch.

File last commit:

r21551:bde505f4 default
r21809:e250b830 default
Show More
merge.py
1149 lines | 42.1 KiB | text/x-python | PythonLexer
Matt Mackall
Move merge code to its own module...
r2775 # merge.py - directory-level update/merge handling for Mercurial
#
Thomas Arendsen Hein
Updated copyright notices and add "and others" to "hg version"
r4635 # Copyright 2006, 2007 Matt Mackall <mpm@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
Pierre-Yves David
merge: introduce new format for the state file...
r20590 import struct
Matt Mackall
resolve: new command...
r6518 from node import nullid, nullrev, hex, bin
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 from mercurial import obsolete
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 import error, util, filemerge, copies, subrepo, worker, dicthelpers
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import errno, os, shutil
Matt Mackall
merge: introduce mergestate
r6512
Pierre-Yves David
merge: introduce new format for the state file...
r20590 _pack = struct.pack
_unpack = struct.unpack
Pierre-Yves David
merge: add "other" file node in the merge state file...
r20593 def _droponode(data):
# used for compatibility for v1
bits = data.split("\0")
bits = bits[:-2] + bits[-1:]
return "\0".join(bits)
Matt Mackall
merge: introduce mergestate
r6512 class mergestate(object):
Pierre-Yves David
merge: introduce new format for the state file...
r20590 '''track 3-way merge state of individual files
it is stored on disk when needed. Two file are used, one with an old
format, one with a new format. Both contains similar data, but the new
format can store new kind of field.
Current new format is a list of arbitrary record of the form:
[type][length][content]
Type is a single character, length is a 4 bytes integer, content is an
Olle Lundberg
merge: fix spelling of length
r20607 arbitrary suites of bytes of length `length`.
Pierre-Yves David
merge: introduce new format for the state file...
r20590
Type should be a letter. Capital letter are mandatory record, Mercurial
should abort if they are unknown. lower case record can be safely ignored.
Currently known record:
L: the node of the "local" part of the merge (hexified version)
Pierre-Yves David
merge: record the "other" node in merge state...
r20591 O: the node of the "other" part of the merge (hexified version)
Pierre-Yves David
merge: introduce new format for the state file...
r20590 F: a file to be merged entry
'''
statepathv1 = "merge/state"
statepathv2 = "merge/state2"
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Matt Mackall
merge: introduce mergestate
r6512 def __init__(self, repo):
self._repo = repo
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = False
Matt Mackall
resolve: new command...
r6518 self._read()
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: record the "other" node in merge state...
r20591 def reset(self, node=None, other=None):
Matt Mackall
merge: introduce mergestate
r6512 self._state = {}
Gregory Szorc
mergestate: consistently set variables to None...
r21261 self._local = None
self._other = None
Matt Mackall
resolve: move reset to localrepo.commit...
r7848 if node:
self._local = node
Pierre-Yves David
merge: record the "other" node in merge state...
r20591 self._other = other
Matt Mackall
merge: introduce mergestate
r6512 shutil.rmtree(self._repo.join("merge"), True)
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = False
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Matt Mackall
resolve: new command...
r6518 def _read(self):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """Analyse each record content to restore a serialized state from disk
This function process "record" entry produced by the de-serialization
of on disk file.
"""
Matt Mackall
resolve: new command...
r6518 self._state = {}
Gregory Szorc
mergestate: consistently set variables to None...
r21261 self._local = None
self._other = None
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 records = self._readrecords()
for rtype, record in records:
if rtype == 'L':
self._local = bin(record)
Pierre-Yves David
merge: record the "other" node in merge state...
r20591 elif rtype == 'O':
self._other = bin(record)
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 elif rtype == "F":
bits = record.split("\0")
self._state[bits[0]] = bits[1:]
elif not rtype.islower():
FUJIWARA Katsunori
i18n: fix "% inside _()" problems...
r20868 raise util.Abort(_('unsupported merge state record: %s')
% rtype)
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 self._dirty = False
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 def _readrecords(self):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """Read merge state from disk and return a list of record (TYPE, data)
Mads Kiilerich
spelling: fixes from spell checker
r21024 We read data from both v1 and v2 files and decide which one to use.
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652
Mads Kiilerich
spelling: fixes from spell checker
r21024 V1 has been used by version prior to 2.9.1 and contains less data than
v2. We read both versions and check if no data in v2 contradicts
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 v1. If there is not contradiction we can safely assume that both v1
and v2 were written at the same time and use the extract data in v2. If
there is contradiction we ignore v2 content as we assume an old version
Mads Kiilerich
spelling: fixes from spell checker
r21024 of Mercurial has overwritten the mergestate file and left an old v2
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 file around.
returns list of record [(TYPE, data), ...]"""
Pierre-Yves David
merge: introduce new format for the state file...
r20590 v1records = self._readrecordsv1()
v2records = self._readrecordsv2()
Pierre-Yves David
merge: add "other" file node in the merge state file...
r20593 oldv2 = set() # old format version of v2 record
for rec in v2records:
if rec[0] == 'L':
oldv2.add(rec)
elif rec[0] == 'F':
# drop the onode data (not contained in v1)
oldv2.add(('F', _droponode(rec[1])))
for rec in v1records:
if rec not in oldv2:
Pierre-Yves David
merge: introduce new format for the state file...
r20590 # v1 file is newer than v2 file, use it
Pierre-Yves David
merge: infer the "other" changeset when falling back to v1 format...
r20592 # we have to infer the "other" changeset of the merge
# we cannot do better than that with v1 of the format
mctx = self._repo[None].parents()[-1]
v1records.append(('O', mctx.hex()))
Pierre-Yves David
merge: add "other" file node in the merge state file...
r20593 # add place holder "other" file node information
# nobody is using it yet so we do no need to fetch the data
# if mctx was wrong `mctx[bits[-2]]` may fails.
for idx, r in enumerate(v1records):
if r[0] == 'F':
bits = r[1].split("\0")
bits.insert(-2, '')
v1records[idx] = (r[0], "\0".join(bits))
Pierre-Yves David
merge: introduce new format for the state file...
r20590 return v1records
else:
return v2records
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: introduce new format for the state file...
r20590 def _readrecordsv1(self):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """read on disk merge state for version 1 file
returns list of record [(TYPE, data), ...]
Note: the "F" data from this file are one entry short
(no "other file node" entry)
"""
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 records = []
Matt Mackall
resolve: new command...
r6518 try:
Pierre-Yves David
merge: introduce new format for the state file...
r20590 f = self._repo.opener(self.statepathv1)
Patrick Mezard
merge: replace readline() call, missing from posixfile_nt
r6530 for i, l in enumerate(f):
if i == 0:
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 records.append(('L', l[:-1]))
Patrick Mezard
merge: replace readline() call, missing from posixfile_nt
r6530 else:
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 records.append(('F', l[:-1]))
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Matt Mackall
resolve: new command...
r6518 except IOError, err:
if err.errno != errno.ENOENT:
raise
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 return records
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: introduce new format for the state file...
r20590 def _readrecordsv2(self):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """read on disk merge state for version 2 file
returns list of record [(TYPE, data), ...]
"""
Pierre-Yves David
merge: introduce new format for the state file...
r20590 records = []
try:
f = self._repo.opener(self.statepathv2)
data = f.read()
off = 0
end = len(data)
while off < end:
rtype = data[off]
off += 1
Olle Lundberg
merge: fix spelling of length
r20607 length = _unpack('>I', data[off:(off + 4)])[0]
Pierre-Yves David
merge: introduce new format for the state file...
r20590 off += 4
Olle Lundberg
merge: fix spelling of length
r20607 record = data[off:(off + length)]
off += length
Pierre-Yves David
merge: introduce new format for the state file...
r20590 records.append((rtype, record))
f.close()
except IOError, err:
if err.errno != errno.ENOENT:
raise
return records
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Gregory Szorc
resolve: abort when not applicable (BC)...
r21264 def active(self):
"""Whether mergestate is active.
Returns True if there appears to be mergestate. This is a rough proxy
for "is a merge in progress."
"""
# Check local variables before looking at filesystem for performance
# reasons.
return bool(self._local) or bool(self._state) or \
self._repo.opener.exists(self.statepathv1) or \
self._repo.opener.exists(self.statepathv2)
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 def commit(self):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """Write current state on disk (if necessary)"""
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 if self._dirty:
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 records = []
records.append(("L", hex(self._local)))
Pierre-Yves David
merge: record the "other" node in merge state...
r20591 records.append(("O", hex(self._other)))
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 for d, v in self._state.iteritems():
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 records.append(("F", "\0".join([d] + v)))
self._writerecords(records)
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = False
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 def _writerecords(self, records):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """Write current state on disk (both v1 and v2)"""
Pierre-Yves David
merge: introduce new format for the state file...
r20590 self._writerecordsv1(records)
self._writerecordsv2(records)
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: introduce new format for the state file...
r20590 def _writerecordsv1(self, records):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """Write current state on disk in a version 1 file"""
Pierre-Yves David
merge: introduce new format for the state file...
r20590 f = self._repo.opener(self.statepathv1, "w")
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 irecords = iter(records)
lrecords = irecords.next()
assert lrecords[0] == 'L'
f.write(hex(self._local) + "\n")
for rtype, data in irecords:
if rtype == "F":
Pierre-Yves David
merge: add "other" file node in the merge state file...
r20593 f.write("%s\n" % _droponode(data))
Pierre-Yves David
merge: change the merge state serialisation to use a record based logic...
r20589 f.close()
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Pierre-Yves David
merge: introduce new format for the state file...
r20590 def _writerecordsv2(self, records):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """Write current state on disk in a version 2 file"""
Pierre-Yves David
merge: introduce new format for the state file...
r20590 f = self._repo.opener(self.statepathv2, "w")
for key, data in records:
assert len(key) == 1
format = ">sI%is" % len(data)
f.write(_pack(format, key, len(data), data))
f.close()
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Mads Kiilerich
merge: merge file flags together with file content...
r18338 def add(self, fcl, fco, fca, fd):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """add a new (potentially?) conflicting file the merge state
fcl: file context for local,
fco: file context for remote,
fca: file context for ancestors,
fd: file path of the resulting merge.
note: also write the local version to the `.hg/merge` directory.
"""
Dirkjan Ochtman
python-2.6: use sha wrapper from util for new merge code
r6517 hash = util.sha1(fcl.path()).hexdigest()
Dan Villiom Podlaski Christiansen
prevent transient leaks of file handle by using new helper functions...
r14168 self._repo.opener.write("merge/" + hash, fcl.data())
Pierre-Yves David
merge: add "other" file node in the merge state file...
r20593 self._state[fd] = ['u', hash, fcl.path(),
fca.path(), hex(fca.filenode()),
fco.path(), hex(fco.filenode()),
fcl.flags()]
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = True
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Matt Mackall
merge: introduce mergestate
r6512 def __contains__(self, dfile):
return dfile in self._state
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Matt Mackall
merge: introduce mergestate
r6512 def __getitem__(self, dfile):
Matt Mackall
resolve: new command...
r6518 return self._state[dfile][0]
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Matt Mackall
resolve: new command...
r6518 def __iter__(self):
Mads Kiilerich
merge: simplify mergestate iter
r21268 return iter(sorted(self._state))
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Bryan O'Sullivan
merge: add a files method to the mergestate class...
r19285 def files(self):
return self._state.keys()
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Matt Mackall
merge: introduce mergestate
r6512 def mark(self, dfile, state):
Matt Mackall
resolve: new command...
r6518 self._state[dfile][0] = state
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = True
Pierre-Yves David
merge: add blank line between mergestate's method...
r20651
Gregory Szorc
resolve: print message when no unresolved files remain (issue4214)...
r21266 def unresolved(self):
"""Obtain the paths of unresolved files."""
for f, entry in self._state.items():
if entry[0] == 'u':
yield f
Durham Goode
merge: add labels parameter from merge.update to filemerge...
r21524 def resolve(self, dfile, wctx, labels=None):
Pierre-Yves David
merge: adds documentation to the mergestate class...
r20652 """rerun merge process for file path `dfile`"""
Matt Mackall
merge: introduce mergestate
r6512 if self[dfile] == 'r':
return 0
Pierre-Yves David
merge: add "other" file node in the merge state file...
r20593 stateentry = self._state[dfile]
state, hash, lfile, afile, anode, ofile, onode, flags = stateentry
Pierre-Yves David
resolve: use "other" changeset from merge state (issue4163)...
r20594 octx = self._repo[self._other]
Mads Kiilerich
merge: merge file flags together with file content...
r18338 fcd = wctx[dfile]
fco = octx[ofile]
fca = self._repo.filectx(afile, fileid=anode)
# "premerge" x flags
flo = fco.flags()
fla = fca.flags()
if 'x' in flags + flo + fla and 'l' not in flags + flo + fla:
if fca.node() == nullid:
self._repo.ui.warn(_('warning: cannot merge flags for %s\n') %
afile)
elif flags == fla:
flags = flo
# restore local
Matt Mackall
merge: introduce mergestate
r6512 f = self._repo.opener("merge/" + hash)
self._repo.wwrite(dfile, f.read(), flags)
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Durham Goode
merge: add labels parameter from merge.update to filemerge...
r21524 r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca,
labels=labels)
Matt Mackall
merge: drop resolve state for mergers with identical contents (issue2680)
r13536 if r is None:
# no real conflict
del self._state[dfile]
Mads Kiilerich
merge: mark mergestate as dirty when resolve changes _state...
r20792 self._dirty = True
Matt Mackall
merge: drop resolve state for mergers with identical contents (issue2680)
r13536 elif not r:
Matt Mackall
merge: introduce mergestate
r6512 self.mark(dfile, 'r')
return r
Matt Mackall
Move merge code to its own module...
r2775
Matt Mackall
merge: refactor unknown file conflict checking...
r16093 def _checkunknownfile(repo, wctx, mctx, f):
return (not repo.dirstate._ignore(f)
Matt Mackall
merge: check for untracked files more precisely (issue3400)...
r16534 and os.path.isfile(repo.wjoin(f))
Siddharth Agarwal
manifestmerge: local unknown, remote created: don't traverse symlinks...
r19157 and repo.wopener.audit.check(f)
Matt Mackall
merge: fix unknown file merge detection for case-folding systems...
r16284 and repo.dirstate.normalize(f) not in repo.dirstate
Matt Mackall
merge: refactor unknown file conflict checking...
r16093 and mctx[f].cmp(wctx[f]))
def _checkunknown(repo, wctx, mctx):
Matt Mackall
merge: update some docstrings
r3315 "check for collisions between unknown files and files in mctx"
Jordi Gutiérrez Hermoso
merge: report all files in _checkunknown...
r15894
error = False
Matt Mackall
merge: refactor unknown file conflict checking...
r16093 for f in mctx:
if f not in wctx and _checkunknownfile(repo, wctx, mctx, f):
Jordi Gutiérrez Hermoso
merge: report all files in _checkunknown...
r15894 error = True
Matt Mackall
merge: refactor unknown file conflict checking...
r16093 wctx._repo.ui.warn(_("%s: untracked file differs\n") % f)
Jordi Gutiérrez Hermoso
merge: report all files in _checkunknown...
r15894 if error:
raise util.Abort(_("untracked files in working directory differ "
"from files in requested revision"))
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107
Matt Mackall
merge: privatize some functions, unnest some others
r6269 def _forgetremoved(wctx, mctx, branchmerge):
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 """
Mads Kiilerich
merge: use separate lists for each action type...
r21545 ractions = []
factions = xactions = []
if branchmerge:
xactions = ractions
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:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 xactions.append((f, None, "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:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 factions.append((f, None, "forget removed"))
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107
Mads Kiilerich
merge: use separate lists for each action type...
r21545 return ractions, factions
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640 def _checkcollision(repo, wmf, actions):
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105 # build provisional merged manifest up
pmmf = set(wmf)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 if actions:
# k, dr, e and rd are no-op
for m in 'a', 'f', 'g', 'cd', 'dc':
for f, args, msg in actions[m]:
pmmf.add(f)
for f, args, msg in actions['r']:
pmmf.discard(f)
for f, args, msg in actions['dm']:
f2, flags = args
pmmf.discard(f2)
pmmf.add(f)
for f, args, msg in actions['dg']:
f2, flags = args
pmmf.add(f)
for f, args, msg in actions['m']:
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 = {}
for f in sorted(pmmf):
fold = util.normcase(f)
if fold in foldmap:
raise util.Abort(_("case-folding collision between %s and %s")
% (f, foldmap[fold]))
foldmap[fold] = f
Durham Goode
rebase: fix --collapse when a file was added then removed...
r18778 def manifestmerge(repo, wctx, p2, pa, branchmerge, force, partial,
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 acceptremote, followcopies):
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 """
Alecs King
merge: fix typo in docstring
r11817 Merge p1 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
Matt Mackall
merge: update some docstrings
r3315 partial = function to filter file lists
Durham Goode
rebase: fix --collapse when a file was added then removed...
r18778 acceptremote = accept the incoming changes without prompting
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 """
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions = dict((m, []) for m in 'a f g cd dc r dm dg m dr e rd k'.split())
copy, movewithdir = {}, {}
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753
Siddharth Agarwal
manifestmerge: fix order in which manifests are fetched...
r18651 # manifests fetched in order are going to be faster, so prime the caches
[x.manifest() for x in
sorted(wctx.parents() + [p2, pa], key=lambda x: x.rev())]
if followcopies:
Bryan O'Sullivan
merge: rename p1 to wctx in manifestmerge...
r18611 ret = copies.mergecopies(repo, wctx, p2, pa)
Siddharth Agarwal
copies: separate moves via directory renames from explicit copies...
r18134 copy, movewithdir, diverge, renamedelete = ret
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753 for of, fl in diverge.iteritems():
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['dr'].append((of, (fl,), "divergent renames"))
Thomas Arendsen Hein
merge: warn about file deleted in one branch and renamed in other (issue3074)...
r16794 for of, fl in renamedelete.iteritems():
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['rd'].append((of, (fl,), "rename and delete"))
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753
repo.ui.note(_("resolving manifests\n"))
Siddharth Agarwal
manifestmerge: pass in branchmerge and force separately...
r18605 repo.ui.debug(" branchmerge: %s, force: %s, partial: %s\n"
% (bool(branchmerge), bool(force), bool(partial)))
Bryan O'Sullivan
merge: rename p1 to wctx in manifestmerge...
r18611 repo.ui.debug(" 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()
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753 copied = set(copy.values())
Siddharth Agarwal
copies: separate moves via directory renames from explicit copies...
r18134 copied.update(movewithdir.values())
Matt Mackall
merge: use contexts for manifestmerge...
r3295
Matt Mackall
subrepo: correctly handle update -C with modified subrepos (issue2022)...
r11470 if '.hgsubstate' in m1:
Matt Mackall
submerge: properly deal with overwrites...
r9783 # check whether sub state is modified
Bryan O'Sullivan
merge: rename p1 to wctx in manifestmerge...
r18611 for s in sorted(wctx.substate):
if wctx.sub(s).dirty():
Matt Mackall
submerge: properly deal with overwrites...
r9783 m1['.hgsubstate'] += "+"
break
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640 aborts = []
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 # Compare manifests
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 fdiff = dicthelpers.diff(m1, m2)
flagsdiff = m1.flagsdiff(m2)
diff12 = dicthelpers.join(fdiff, flagsdiff)
for f, (n12, fl12) in diff12.iteritems():
if n12:
n1, n2 = n12
else: # file contents didn't change, but flags did
Siddharth Agarwal
manifestmerge: handle workdir removed, remote removed with flags...
r18895 n1 = n2 = m1.get(f, None)
if n1 is None:
# Since n1 == n2, the file isn't present in m2 either. This
# means that the file was removed or deleted locally and
# removed remotely, but that residual entries remain in flags.
# This can happen in manifests generated by workingctx.
continue
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 if fl12:
fl1, fl2 = fl12
else: # flags didn't change, file contents did
fl1 = fl2 = m1.flags(f)
Matt Mackall
merge: reduce manifest copying
r3248 if partial and not partial(f):
continue
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 if n1 and n2:
Mads Kiilerich
merge: use the right ancestor when both sides copied the same file...
r20642 fa = f
a = ma.get(f, nullid)
if a == nullid:
fa = copy.get(f, f)
# Note: f as default is wrong - we can't really make a 3-way
# merge without an ancestor file.
fla = ma.flags(fa)
Mads Kiilerich
merge: merge file flags together with file content...
r18338 nol = 'l' not in fl1 + fl2 + fla
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 if n2 == a and fl2 == fla:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['k'].append((f, (), "keep")) # remote unchanged
Siddharth Agarwal
manifestmerge: rename n to n1 and n2...
r18818 elif n1 == a and fl1 == fla: # local unchanged - use remote
if n1 == n2: # optimization: keep local content
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['e'].append((f, (fl2,), "update permissions"))
Mads Kiilerich
merge: merge file flags together with file content...
r18338 else:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['g'].append((f, (fl2,), "remote is newer"))
Mads Kiilerich
merge: merge file flags together with file content...
r18338 elif nol and n2 == a: # remote only changed 'x'
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['e'].append((f, (fl2,), "update permissions"))
Siddharth Agarwal
manifestmerge: rename n to n1 and n2...
r18818 elif nol and n1 == a: # local only changed 'x'
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['g'].append((f, (fl1,), "remote is newer"))
Mads Kiilerich
merge: merge file flags together with file content...
r18338 else: # both changed something
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['m'].append((f, (f, f, fa, False, pa.node()),
Mads Kiilerich
merge: include ancestor node in merge actions
r20943 "versions differ"))
Matt Mackall
merge: simplify file revision comparison logic
r8752 elif f in copied: # files we'll deal with on m2 side
pass
Mads Kiilerich
merge: keep destination filename as key in actions for merge with dir rename...
r20944 elif n1 and f in movewithdir: # directory rename, move local
Siddharth Agarwal
copies: separate moves via directory renames from explicit copies...
r18134 f2 = movewithdir[f]
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['dm'].append((f2, (f, fl1),
Mads Kiilerich
merge: keep destination filename as key in actions for merge with dir rename...
r20944 "remote directory rename - move from " + f))
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 elif n1 and f in copy:
Matt Mackall
merge: add rename following...
r3249 f2 = copy[f]
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['m'].append((f, (f, f2, f2, False, pa.node()),
Mads Kiilerich
merge: keep destination filename as key in filemerge actions...
r20945 "local copied/moved from " + f2))
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 elif n1 and f in ma: # clean, a different, no remote
Siddharth Agarwal
manifestmerge: rename n to n1 and n2...
r18818 if n1 != ma[f]:
Mads Kiilerich
merge: handle acceptremove of create+delete early in manifest merge
r20639 if acceptremote:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['r'].append((f, None, "remote delete"))
Mads Kiilerich
merge: handle acceptremove of create+delete early in manifest merge
r20639 else:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['cd'].append((f, None, "prompt changed/deleted"))
Siddharth Agarwal
manifestmerge: rename n to n1 and n2...
r18818 elif n1[20:] == "a": # added, no remote
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['f'].append((f, None, "remote deleted"))
Matt Mackall
merge: don't use unknown()...
r16094 else:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['r'].append((f, None, "other deleted"))
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 elif n2 and f in movewithdir:
Siddharth Agarwal
copies: separate moves via directory renames from explicit copies...
r18134 f2 = movewithdir[f]
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['dg'].append((f2, (f, fl2),
Mads Kiilerich
merge: keep destination filename as key in actions for merge with dir rename...
r20944 "local directory rename - get from " + f))
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 elif n2 and f in copy:
Matt Mackall
merge: add rename following...
r3249 f2 = copy[f]
Mads Kiilerich
merge: remove "case" comments...
r18339 if f2 in m2:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['m'].append((f, (f2, f, f2, False, pa.node()),
Mads Kiilerich
merge: keep destination filename as key in filemerge actions...
r20945 "remote copied from " + f2))
Mads Kiilerich
merge: remove "case" comments...
r18339 else:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['m'].append((f, (f2, f, f2, True, pa.node()),
Mads Kiilerich
merge: keep destination filename as key in filemerge actions...
r20945 "remote moved from " + f2))
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 elif n2 and f not in ma:
Siddharth Agarwal
manifestmerge: handle abort on local unknown, remote created files...
r18606 # local unknown, remote created: the logic is described by the
# following table:
#
# force branchmerge different | action
# n * n | get
# n * y | abort
# y n * | get
# y y n | get
# y y y | merge
#
# Checking whether the files are different is expensive, so we
# don't do that when we can avoid it.
if force and not branchmerge:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['g'].append((f, (fl2,), "remote created"))
Mads Kiilerich
merge: remove "case" comments...
r18339 else:
Bryan O'Sullivan
merge: rename p1 to wctx in manifestmerge...
r18611 different = _checkunknownfile(repo, wctx, p2, f)
Siddharth Agarwal
manifestmerge: handle abort on local unknown, remote created files...
r18606 if force and branchmerge and different:
Mads Kiilerich
merge: use ancestor filename from planning phase instead of filectx ancestor...
r20897 # FIXME: This is wrong - f is not in ma ...
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['m'].append((f, (f, f, f, False, pa.node()),
Siddharth Agarwal
manifestmerge: handle abort on local unknown, remote created files...
r18606 "remote differs from untracked local"))
elif not force and different:
aborts.append((f, "ud"))
else:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['g'].append((f, (fl2,), "remote created"))
Siddharth Agarwal
manifestmerge: use dicthelpers.diff and join...
r18822 elif n2 and n2 != ma[f]:
Mads Kiilerich
merge: don't overwrite file untracked after remove, abort with 'untracked files'...
r20415 different = _checkunknownfile(repo, wctx, p2, f)
if not force and different:
aborts.append((f, "ud"))
else:
# if different: old untracked f may be overwritten and lost
Mads Kiilerich
merge: handle acceptremove of create+delete early in manifest merge
r20639 if acceptremote:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['g'].append((f, (m2.flags(f),),
Mads Kiilerich
merge: handle acceptremove of create+delete early in manifest merge
r20639 "remote recreating"))
else:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['dc'].append((f, (m2.flags(f),),
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640 "prompt deleted/changed"))
Mads Kiilerich
merge: delay prompts a bit and show them in (extra) sorted order...
r18539
Siddharth Agarwal
manifestmerge: handle abort on local unknown, remote created files...
r18606 for f, m in sorted(aborts):
if m == "ud":
repo.ui.warn(_("%s: untracked file differs\n") % f)
else: assert False, m
if aborts:
raise util.Abort(_("untracked files in working directory differ "
"from files in requested revision"))
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105 if not util.checkcase(repo.path):
# check collision between files only in p2 for clean update
if (not branchmerge and
(force or not wctx.dirty(missing=True, branch=False))):
Mads Kiilerich
merge: use separate lists for each action type...
r21545 _checkcollision(repo, m2, None)
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105 else:
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640 _checkcollision(repo, m1, actions)
FUJIWARA Katsunori
icasefs: rewrite case-folding collision detection (issue3452)...
r19105
Mads Kiilerich
merge: rename list of actions from action to actions
r18330 return actions
Matt Mackall
merge: pull manifest comparison out into separate function
r3105
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 def batchremove(repo, actions):
"""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
unlink = util.unlinkpath
wjoin = repo.wjoin
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630 audit = repo.wopener.audit
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:
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 repo.ui.debug(" %s: %s -> r\n" % (f, msg))
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 if verbose:
repo.ui.note(_("removing %s\n") % f)
audit(f)
try:
unlink(wjoin(f), ignoremissing=True)
except OSError, inst:
repo.ui.warn(_("update failed to remove %s: %s!\n") %
(f, inst.strerror))
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
def batchget(repo, mctx, actions):
"""apply gets to the working directory
mctx is the context to get from
yields tuples for progress updates
"""
verbose = repo.ui.verbose
fctx = mctx.filectx
wwrite = repo.wwrite
i = 0
Mads Kiilerich
merge: use separate lists for each action type...
r21545 for f, args, msg in actions:
Mads Kiilerich
merge: separate worker functions for batch remove and batch get...
r21392 repo.ui.debug(" %s: %s -> g\n" % (f, msg))
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 if verbose:
repo.ui.note(_("getting %s\n") % f)
wwrite(f, fctx(f).data(), args[0])
Bryan O'Sullivan
merge: report non-interactive progress in chunks...
r18633 if i == 100:
yield i, f
i = 0
i += 1
if i > 0:
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630 yield i, f
Durham Goode
merge: add labels parameter from merge.update to filemerge...
r21524 def applyupdates(repo, actions, wctx, mctx, overwrite, labels=None):
Peter Arrenbrecht
merge: pass constant cset ancestor to fctx.ancestor
r11454 """apply the merge action list to the working directory
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
Return a tuple of counts (updated, merged, removed, unresolved) that
describes how many files were affected by the update.
Peter Arrenbrecht
merge: pass constant cset ancestor to fctx.ancestor
r11454 """
Matt Mackall
merge: update some docstrings
r3315
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 updated, merged, removed, unresolved = 0, 0, 0, 0
Matt Mackall
merge: introduce mergestate
r6512 ms = mergestate(repo)
Pierre-Yves David
merge: record the "other" node in merge state...
r20591 ms.reset(wctx.p1().node(), mctx.node())
Matt Mackall
merge: introduce mergestate
r6512 moves = []
Mads Kiilerich
merge: use separate lists for each action type...
r21545 for m, l in actions.items():
l.sort()
Matt Mackall
merge: introduce mergestate
r6512
# prescan for merges
Mads Kiilerich
merge: use separate lists for each action type...
r21545 for f, args, msg in actions['m']:
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 f1, f2, fa, move, anc = args
if f == '.hgsubstate': # merged internally
continue
repo.ui.debug(" preserving %s for resolve of %s\n" % (f1, f))
fcl = wctx[f1]
fco = mctx[f2]
actx = repo[anc]
if fa in actx:
fca = actx[fa]
else:
fca = repo.filectx(f1, fileid=nullrev)
ms.add(fcl, fco, fca, f)
if f1 != f and move:
moves.append(f1)
Matt Mackall
merge: introduce mergestate
r6512
Mads Kiilerich
merge: consistently use repo.wopener.audit instead of creating a new auditor
r18328 audit = repo.wopener.audit
Mads Kiilerich
merge: move constant assignments a bit and use them more
r21390 _updating = _('updating')
_files = _('files')
progress = repo.ui.progress
Adrian Buehlmann
applyupdates: audit unlinking of renamed files and directories
r14398
Matt Mackall
merge: introduce mergestate
r6512 # remove renamed files after safely stored
for f in moves:
Martin Geisler
util: remove lexists, Python 2.4 introduced os.path.lexists
r12032 if os.path.lexists(repo.wjoin(f)):
Martin Geisler
do not attempt to translate ui.debug output
r9467 repo.ui.debug("removing %s\n" % f)
Adrian Buehlmann
applyupdates: audit unlinking of renamed files and directories
r14398 audit(f)
Mads Kiilerich
merge: use util.unlinkpath for removing moved files...
r18333 util.unlinkpath(repo.wjoin(f))
Matt Mackall
merge: do early copy to deal with issue636...
r5042
Mads Kiilerich
merge: use separate lists for each action type...
r21545 numupdates = sum(len(l) for m, l in actions.items() if m != 'k')
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630
Mads Kiilerich
merge: use separate lists for each action type...
r21545 if [a for a in actions['r'] if a[0] == '.hgsubstate']:
Bryan O'Sullivan
merge: handle subrepo merges and .hgsubstate specially...
r18632 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
Mads Kiilerich
merge: move constant assignments a bit and use them more
r21390 # remove in parallel (must come first)
Bryan O'Sullivan
merge: report non-interactive progress in chunks...
r18633 z = 0
Mads Kiilerich
merge: use separate lists for each action type...
r21545 prog = worker.worker(repo.ui, 0.001, batchremove, (repo,), actions['r'])
FUJIWARA Katsunori
merge: increase safety of parallel updating/removing on icasefs...
r19095 for i, item in prog:
z += i
Mads Kiilerich
merge: move constant assignments a bit and use them more
r21390 progress(_updating, z, item=item, total=numupdates, unit=_files)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 removed = len(actions['r'])
Mads Kiilerich
merge: move constant assignments a bit and use them more
r21390
# get in parallel
Mads Kiilerich
merge: use separate lists for each action type...
r21545 prog = worker.worker(repo.ui, 0.001, batchget, (repo, mctx), actions['g'])
Bryan O'Sullivan
merge: apply non-interactive working dir updates in parallel...
r18639 for i, item in prog:
Bryan O'Sullivan
merge: report non-interactive progress in chunks...
r18633 z += i
Mads Kiilerich
merge: move constant assignments a bit and use them more
r21390 progress(_updating, z, item=item, total=numupdates, unit=_files)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 updated = len(actions['g'])
Bryan O'Sullivan
merge: split out mostly-non-interactive working dir updates...
r18630
Mads Kiilerich
merge: use separate lists for each action type...
r21545 if [a for a in actions['g'] if a[0] == '.hgsubstate']:
Bryan O'Sullivan
merge: handle subrepo merges and .hgsubstate specially...
r18632 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # forget (manifest only, just log it) (must come first)
for f, args, msg in actions['f']:
repo.ui.debug(" %s: %s -> f\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
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)
for f, args, msg in actions['a']:
repo.ui.debug(" %s: %s -> a\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
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 # keep (noop, just log it)
for f, args, msg in actions['k']:
repo.ui.debug(" %s: %s -> k\n" % (f, msg))
# 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 # merge
for f, args, msg in actions['m']:
repo.ui.debug(" %s: %s -> m\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
f1, f2, fa, move, anc = args
if f == '.hgsubstate': # subrepo states need updating
subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
overwrite)
continue
audit(f)
r = ms.resolve(f, wctx, labels=labels)
if r is not None and r > 0:
unresolved += 1
else:
if r is None:
updated += 1
Matt Mackall
merge: pull file copy/move out of filemerge
r3309 else:
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 merged += 1
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
for f, args, msg in actions['dm']:
repo.ui.debug(" %s: %s -> dm\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
f0, flags = args
repo.ui.note(_("moving %s to %s\n") % (f0, f))
audit(f)
repo.wwrite(f, wctx.filectx(f0).data(), flags)
util.unlinkpath(repo.wjoin(f0))
updated += 1
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
for f, args, msg in actions['dg']:
repo.ui.debug(" %s: %s -> dg\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
f0, flags = args
repo.ui.note(_("getting %s to %s\n") % (f0, f))
repo.wwrite(f, mctx.filectx(f0).data(), flags)
updated += 1
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 # divergent renames
for f, args, msg in actions['dr']:
repo.ui.debug(" %s: %s -> dr\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
fl, = args
repo.ui.warn(_("note: possible conflict - %s was renamed "
"multiple times to:\n") % f)
for nf in fl:
repo.ui.warn(" %s\n" % nf)
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 # rename and delete
for f, args, msg in actions['rd']:
repo.ui.debug(" %s: %s -> rd\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
fl, = args
repo.ui.warn(_("note: possible conflict - %s was deleted "
"and renamed to:\n") % f)
for nf in fl:
repo.ui.warn(" %s\n" % nf)
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
for f, args, msg in actions['e']:
repo.ui.debug(" %s: %s -> e\n" % (f, msg))
z += 1
progress(_updating, z, item=f, total=numupdates, unit=_files)
flags, = args
audit(f)
util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
updated += 1
Mads Kiilerich
merge: change debug logging - test output changes but no real changes...
r21391
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 ms.commit()
Bryan O'Sullivan
merge: don't fiddle with name lookups or i18n in hot loops...
r18640 progress(_updating, None, total=numupdates, unit=_files)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111
return updated, merged, removed, unresolved
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 def calculateupdates(repo, wctx, mctx, ancestors, branchmerge, force, partial,
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 acceptremote, followcopies):
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 "Calculate the actions needed to merge mctx into wctx using ancestors"
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 if len(ancestors) == 1: # default
actions = manifestmerge(repo, wctx, mctx, ancestors[0],
branchmerge, force,
partial, acceptremote, followcopies)
else: # only when merge.preferancestor=* - experimentalish code
Mads Kiilerich
merge: tell the user when we are using bid merge...
r21171 repo.ui.status(
_("note: merging %s and %s using bids from ancestors %s\n") %
(wctx, mctx, _(' and ').join(str(anc) for anc in ancestors)))
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 # Call for bids
Mads Kiilerich
merge: use separate lists for each action type...
r21545 fbids = {} # mapping filename to bids (action method to list af actions)
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 for ancestor in ancestors:
repo.ui.note(_('\ncalculating bids for ancestor %s\n') % ancestor)
actions = manifestmerge(repo, wctx, mctx, ancestor,
branchmerge, force,
partial, acceptremote, followcopies)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 for m, l in sorted(actions.items()):
for a in l:
f, args, msg = a
repo.ui.debug(' %s: %s -> %s\n' % (f, msg, m))
if f in fbids:
d = fbids[f]
if m in d:
d[m].append(a)
else:
d[m] = [a]
else:
fbids[f] = {m: [a]}
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 # Pick the best bid for each file
repo.ui.note(_('\nauction for merging merge bids\n'))
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions = dict((m, []) for m in actions.keys())
for f, bids in sorted(fbids.items()):
# bids is a mapping from action method to list af actions
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 # Consensus?
Mads Kiilerich
merge: use separate lists for each action type...
r21545 if len(bids) == 1: # all bids are the same kind of method
m, l = bids.items()[0]
if util.all(a == l[0] for a in l[1:]): # len(bids) is > 1
repo.ui.note(" %s: consensus for %s\n" % (f, m))
actions[m].append(l[0])
continue
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 # If keep is an option, just do it.
if "k" in bids:
repo.ui.note(" %s: picking 'keep' action\n" % f)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['k'].append(bids["k"][0])
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 continue
Mads Kiilerich
merge: use separate lists for each action type...
r21545 # If there are gets and they all agree [how could they not?], do it.
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 if "g" in bids:
ga0 = bids["g"][0]
if util.all(a == ga0 for a in bids["g"][1:]):
repo.ui.note(" %s: picking 'get' action\n" % f)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 actions['g'].append(ga0)
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 continue
# TODO: Consider other simple actions such as mode changes
# Handle inefficient democrazy.
Mads Kiilerich
merge: improve notes for listing the bids for ambiguous merges
r21172 repo.ui.note(_(' %s: multiple bids for merge action:\n') % f)
Mads Kiilerich
merge: use separate lists for each action type...
r21545 for m, l in sorted(bids.items()):
for _f, args, msg in l:
repo.ui.note(' %s -> %s\n' % (msg, m))
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 # Pick random action. TODO: Instead, prompt user when resolving
Mads Kiilerich
merge: use separate lists for each action type...
r21545 m, l = bids.items()[0]
Mads Kiilerich
merge: fix stray character in bid merge message
r21170 repo.ui.warn(_(' %s: ambiguous merge - picked %s action\n') %
Mads Kiilerich
merge: use separate lists for each action type...
r21545 (f, m))
actions[m].append(l[0])
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 continue
repo.ui.note(_('end of auction\n\n'))
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640
# Prompt and create actions. TODO: Move this towards resolve phase.
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 for f, args, msg in actions['cd']:
if repo.ui.promptchoice(
_("local changed %s which remote deleted\n"
"use (c)hanged version or (d)elete?"
"$$ &Changed $$ &Delete") % f, 0):
actions['r'].append((f, None, "prompt delete"))
else:
actions['a'].append((f, None, "prompt keep"))
del actions['cd'][:]
Mads Kiilerich
merge: use separate lists for each action type...
r21545
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 for f, args, msg in actions['dc']:
flags, = args
if repo.ui.promptchoice(
_("remote changed %s which local deleted\n"
"use (c)hanged version or leave (d)eleted?"
"$$ &Changed $$ &Deleted") % f, 0) == 0:
actions['g'].append((f, (flags,), "prompt recreating"))
del actions['dc'][:]
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 if wctx.rev() is None:
Mads Kiilerich
merge: use separate lists for each action type...
r21545 ractions, factions = _forgetremoved(wctx, mctx, branchmerge)
actions['r'].extend(ractions)
actions['f'].extend(factions)
Mads Kiilerich
merge: handle create+delete prompts in calculateupdates...
r20640
Mads Kiilerich
merge: use separate lists for each action type...
r21545 return actions
David Schleimer
merge: refactor action calculation into function...
r18035
Mads Kiilerich
merge: rename list of actions from action to actions
r18330 def recordupdates(repo, actions, branchmerge):
Matt Mackall
merge: update some docstrings
r3315 "record merge actions to the dirstate"
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 # remove (must come first)
for f, args, msg in actions['r']:
if branchmerge:
repo.dirstate.remove(f)
else:
Mads Kiilerich
merge: change priority / ordering of merge actions...
r21389 repo.dirstate.drop(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 # forget (must come first)
for f, args, msg in actions['f']:
repo.dirstate.drop(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
for f, args, msg in actions['a']:
if not branchmerge:
repo.dirstate.add(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 # exec change
for f, args, msg in actions['e']:
repo.dirstate.normallookup(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 # keep
for f, args, msg in actions['k']:
pass
# get
for f, args, msg in actions['g']:
if branchmerge:
repo.dirstate.otherparent(f)
else:
repo.dirstate.normal(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 # merge
for f, args, msg in actions['m']:
f1, f2, fa, move, anc = args
if branchmerge:
# We've done a branch merge, mark this file as merged
# so that we properly record the merger later
repo.dirstate.merge(f)
if f1 != f2: # copy/rename
Matt Mackall
merge: unify merge and copy actions
r3308 if move:
Mads Kiilerich
merge: fix stupid indentation left over from previous refactorings
r21551 repo.dirstate.remove(f1)
if f1 != f:
repo.dirstate.copy(f1, f)
else:
repo.dirstate.copy(f2, f)
else:
# We've update-merged a locally modified file, so
# we set the dirstate to emulate a normal checkout
# of that file some time in the past. Thus our
# merge will appear as a normal local file
# modification.
if f2 == f: # file not locally copied/moved
repo.dirstate.normallookup(f)
if move:
repo.dirstate.drop(f1)
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
for f, args, msg in actions['dm']:
f0, flag = args
if f0 not in repo.dirstate:
# untracked file moved
continue
if branchmerge:
repo.dirstate.add(f)
repo.dirstate.remove(f0)
repo.dirstate.copy(f0, f)
else:
repo.dirstate.normal(f)
repo.dirstate.drop(f0)
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, get
for f, args, msg in actions['dg']:
f0, flag = args
if branchmerge:
repo.dirstate.add(f)
repo.dirstate.copy(f0, f)
else:
repo.dirstate.normal(f)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111
Patrick Mezard
rebase: allow collapsing branches in place (issue3111)...
r16696 def update(repo, node, branchmerge, force, partial, ancestor=None,
Durham Goode
merge: add labels parameter from merge.update to filemerge...
r21524 mergeancestor=False, labels=None):
Matt Mackall
merge: update some docstrings
r3315 """
Perform a merge between the working directory and the given node
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716 node = the node to update to, or None if unspecified
Matt Mackall
merge: update some docstrings
r3315 branchmerge = whether to merge between branches
force = whether to force branch merging or file overwriting
partial = a function 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.
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
The table below shows all the behaviors of the update command
given the -c and -C 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, on the same named
branch, or on another named branch).
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
-c -C dirty rev | linear same cross
n n n n | ok (1) x
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 n n n y | ok ok ok
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 n n y n | merge (2) (2)
n n y y | merge (3) (3)
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716 n y * * | --- discard ---
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 y n y * | --- (4) ---
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716 y n n * | --- ok ---
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 y y * * | --- (5) ---
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
x = can't happen
* = don't-care
Siddharth Agarwal
update: improve error message for clean non-linear update
r19798 1 = abort: not a linear update (merge or update --check to force update)
Siddharth Agarwal
update: improve error message for dirty non-linear update with rev
r19800 2 = abort: uncommitted changes (commit and merge, or update --clean to
discard changes)
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 3 = abort: uncommitted changes (commit or update --clean to discard changes)
Siddharth Agarwal
update: standardize error message for dirty update --check...
r19801 4 = abort: uncommitted changes (checked in commands.py)
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 5 = incompatible options (checked in commands.py)
Greg Ward
merge: document some internal return values.
r13162
Return the same tuple as applyupdates().
Matt Mackall
merge: update some docstrings
r3315 """
Matt Mackall
Merge: combine force and forcemerge arguments
r2815
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 onode = node
Matt Mackall
Make repo locks recursive, eliminate all passing of lock/wlock
r4917 wlock = repo.wlock()
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
Matt Mackall
use repo[changeid] to get a changectx
r6747 wc = repo[None]
Sean Farley
merge: refactor initialization of variables in update...
r20279 pl = wc.parents()
p1 = pl[0]
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [None]
Sean Farley
merge: refactor initialization of variables in update...
r20279 if ancestor:
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [repo[ancestor]]
Sean Farley
merge: refactor initialization of variables in update...
r20279
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if node is None:
Sean Farley
merge: update comment for future devs
r20278 # Here is where we should consider bookmarks, divergent bookmarks,
# foreground changesets (successors), and tip of current branch;
# but currently we are only checking the branch tips.
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 try:
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 node = repo.branchtip(wc.branch())
except error.RepoLookupError:
Matt Mackall
update: default to tipmost branch if default branch doesn't exist
r5570 if wc.branch() == "default": # no default branch!
node = repo.lookup("tip") # update to tip
else:
raise util.Abort(_("branch %s not found") % wc.branch())
Sean Farley
merge: consider successor changesets for a bare update...
r20280
if p1.obsolete() and not p1.children():
# allow updating to successors
successors = obsolete.successorssets(repo, p1.node())
# behavior of certain cases is as follows,
#
# divergent changesets: update to highest rev, similar to what
# is currently done when there are more than one head
# (i.e. 'tip')
#
# replaced changesets: same as divergent except we know there
# is no conflict
#
# pruned changeset: no update is done; though, we could
# consider updating to the first non-obsolete parent,
# similar to what is current done for 'hg prune'
if successors:
# flatten the list here handles both divergent (len > 1)
# and the usual case (len = 1)
successors = [n for sub in successors for n in sub]
# get the max revision for the given successors set,
# i.e. the 'tip' of a set
node = repo.revs("max(%ln)", successors)[0]
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [p1]
Sean Farley
merge: consider successor changesets for a bare update...
r20280
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 overwrite = force and not branchmerge
Sean Farley
merge: refactor initialization of variables in update...
r20279
p2 = repo[node]
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 if pas[0] is None:
Mads Kiilerich
merge: with merge.preferancestor=*, run an auction with bids from ancestors...
r21128 if repo.ui.config("merge", "preferancestor") == '*':
cahs = repo.changelog.commonancestorsheads(p1.node(), p2.node())
pas = [repo[anc] for anc in (sorted(cahs) or [nullid])]
else:
Matt Mackall
ancestor: silence multiple ancestor warning outside of merge (issue4234)...
r21203 pas = [p1.ancestor(p2, warn=True)]
Matt Mackall
merge: add ancestor to the update function...
r13874
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 fp1, fp2, xp1, xp2 = p1.node(), p2.node(), str(p1), str(p2)
Matt Mackall
merge: various tidying...
r3314
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 ### check phase
if not overwrite and len(pl) > 1:
raise util.Abort(_("outstanding uncommitted merges"))
Matt Mackall
update: better logic and messages for updates...
r6375 if branchmerge:
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 if pas == [p2]:
Matt Mackall
merge: improve merge with ancestor message
r11417 raise util.Abort(_("merging with a working directory ancestor"
" has no effect"))
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 elif pas == [p1]:
Patrick Mezard
rebase: allow collapsing branches in place (issue3111)...
r16696 if not mergeancestor and p1.branch() == p2.branch():
Kevin Bullock
merge: make 'nothing to merge' aborts consistent...
r15619 raise util.Abort(_("nothing to merge"),
hint=_("use 'hg update' "
"or check 'hg heads'"))
Matt Mackall
update: better logic and messages for updates...
r6375 if not force and (wc.files() or wc.deleted()):
Siddharth Agarwal
merge: standardize error message for dirty working dir
r19802 raise util.Abort(_("uncommitted changes"),
Kevin Bullock
merge: make 'nothing to merge' aborts consistent...
r15619 hint=_("use 'hg status' to list changes"))
Mads Kiilerich
subrepos: process subrepos in sorted order...
r18364 for s in sorted(wc.substate):
Oleg Stepanov
Do not allow merging with uncommitted changes in a subrepo
r13437 if wc.sub(s).dirty():
Siddharth Agarwal
merge: standardize error message for dirty subrepo
r19803 raise util.Abort(_("uncommitted changes in "
Oleg Stepanov
Do not allow merging with uncommitted changes in a subrepo
r13437 "subrepository '%s'") % s)
Matt Mackall
update: better logic and messages for updates...
r6375 elif not overwrite:
Siddharth Agarwal
merge: exit early during a no-op update (BC)...
r19929 if p1 == p2: # no-op update
# call the hooks and exit early
repo.hook('preupdate', throw=True, parent1=xp2, parent2='')
repo.hook('update', parent1=xp2, parent2='', error=0)
return 0, 0, 0, 0
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 if pas not in ([p1], [p2]): # nonlinear
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 dirty = wc.dirty(missing=True)
if dirty or onode is None:
# Branching is a bit strange to ensure we do the minimal
# amount of call to obsolete.background.
foreground = obsolete.foreground(repo, [p1.node()])
# note: the <node> variable contains a random identifier
if repo[node].node() in foreground:
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [p1] # allow updating to successors
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 elif dirty:
msg = _("uncommitted changes")
Siddharth Agarwal
update: improve error message for dirty non-linear update with rev
r19800 if onode is None:
hint = _("commit and merge, or update --clean to"
" discard changes")
else:
hint = _("commit or update --clean to discard"
" changes")
Siddharth Agarwal
update: add error message for dirty non-linear update with no rev...
r19799 raise util.Abort(msg, hint=hint)
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 else: # node is none
Siddharth Agarwal
update: improve error message for clean non-linear update
r19798 msg = _("not a linear update")
hint = _("merge or update --check to force update")
raise util.Abort(msg, hint=hint)
Pierre-Yves David
update: allow dirty update to foreground (successors)...
r18985 else:
# Allow jumping branches if clean and specific rev given
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [p1]
Matt Mackall
Merge: move most tests to the beginning
r2814
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 followcopies = False
if overwrite:
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 pas = [wc]
elif pas == [p2]: # backwards
pas = [wc.p1()]
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 elif not branchmerge and not wc.dirty(missing=True):
pass
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 elif pas[0] and repo.ui.configbool("merge", "followcopies", True):
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 followcopies = True
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 ### calculate phase
Mads Kiilerich
merge: pass merge ancestor to calculateupdates as a list...
r21081 actions = calculateupdates(repo, wc, p2, pas, branchmerge, force,
Mads Kiilerich
merge: move ancestor selection tweaking from manifestmerge to update function...
r21080 partial, mergeancestor, followcopies)
Matt Mackall
Move merge code to its own module...
r2775
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 ### apply phase
Matt Mackall
merge: back out single-parent fast-forward merge...
r13550 if not branchmerge: # just jump to the new rev
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 fp1, fp2, xp1, xp2 = fp2, nullid, xp2, ''
if not partial:
repo.hook('preupdate', throw=True, parent1=xp1, parent2=xp2)
Matt Mackall
update: add tracking of interrupted updates (issue3113)...
r19482 # note that we're in the middle of an update
repo.vfs.write('updatestate', p2.hex())
Matt Mackall
Move merge code to its own module...
r2775
Durham Goode
merge: add labels parameter from merge.update to filemerge...
r21524 stats = applyupdates(repo, actions, wc, p2, overwrite, labels=labels)
Matt Mackall
merge: consolidate dirstate updates
r2899
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if not partial:
Patrick Mezard
localrepo: add setparents() to adjust dirstate copies (issue3407)...
r16551 repo.setparents(fp1, fp2)
Mads Kiilerich
merge: rename list of actions from action to actions
r18330 recordupdates(repo, actions, branchmerge)
Matt Mackall
update: add tracking of interrupted updates (issue3113)...
r19482 # update completed, clear state
util.unlink(repo.join('updatestate'))
Mads Kiilerich
merge: remove last traces of fastforward merging...
r13561 if not branchmerge:
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 repo.dirstate.setbranch(p2.branch())
finally:
Ronny Pfannschmidt
switch lock releasing in the core from gc to explicit
r8109 wlock.release()
Sune Foldager
run commit and update hooks after command completion (issue1827)...
r10492
if not partial:
repo.hook('update', parent1=xp1, parent2=xp2, error=stats[3])
return stats