##// END OF EJS Templates
convert: keep branch switching merges with ancestors (issue3340)...
convert: keep branch switching merges with ancestors (issue3340) When running convert with a filemap, merge parents which are ancestors of other parents are ignored. This is hardly a problem when parents belong to the same branch, but the result could be confusing when named branches are involved. With: -o-a1-a2-a3... <- A \ \ b1-b2-b3...-m- <- B If all b* revisions are discarded, it is useful to preserve 'm' even if it is empty after filtering to record the branch switch. This patch makes filemap preserve "ancestor parents" if there is no "non-ancestor parent" on the same branch than the merge revision. Remarks: - I am not completely convinced by the reasons given above and those detailed by Matt in this thread: http://selenic.com/pipermail/mercurial-devel/2012-May/040627.html The properties we try to preserve are not clearly defined. That said, I know this patch already helped someone on IRC and the tests output look reasonable. - This is a new version of the original "convert: filemap must preserve fast-forward merges" patch. It has exactly the same output for 2 parents merges, the additional complexity is here to handle more than two parents.

File last commit:

r16794:98687cdd default
r17103:5146de7b default
Show More
merge.py
622 lines | 22.7 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
Matt Mackall
resolve: new command...
r6518 from node import nullid, nullrev, hex, bin
Matt Mackall
Simplify i18n imports
r3891 from i18n import _
Brodie Rao
localrepo: add branchtip() method for faster single-branch lookups...
r16719 import error, scmutil, util, filemerge, copies, subrepo
Simon Heimberg
separate import lines from mercurial and general python modules
r8312 import errno, os, shutil
Matt Mackall
merge: introduce mergestate
r6512
class mergestate(object):
'''track 3-way merge state of individual files'''
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()
Matt Mackall
resolve: move reset to localrepo.commit...
r7848 def reset(self, node=None):
Matt Mackall
merge: introduce mergestate
r6512 self._state = {}
Matt Mackall
resolve: move reset to localrepo.commit...
r7848 if node:
self._local = node
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
Matt Mackall
resolve: new command...
r6518 def _read(self):
self._state = {}
try:
f = self._repo.opener("merge/state")
Patrick Mezard
merge: replace readline() call, missing from posixfile_nt
r6530 for i, l in enumerate(f):
if i == 0:
Martin Geisler
resolve: do not crash on empty mergestate...
r11451 self._local = bin(l[:-1])
Patrick Mezard
merge: replace readline() call, missing from posixfile_nt
r6530 else:
bits = l[:-1].split("\0")
self._state[bits[0]] = bits[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
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = False
def commit(self):
if self._dirty:
f = self._repo.opener("merge/state", "w")
f.write(hex(self._local) + "\n")
for d, v in self._state.iteritems():
f.write("\0".join([d] + v) + "\n")
Dan Villiom Podlaski Christiansen
explicitly close files...
r13400 f.close()
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = False
Matt Mackall
merge: introduce mergestate
r6512 def add(self, fcl, fco, fca, fd, flags):
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())
Matt Mackall
resolve: new command...
r6518 self._state[fd] = ['u', hash, fcl.path(), fca.path(),
hex(fca.filenode()), fco.path(), flags]
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 self._dirty = True
Matt Mackall
merge: introduce mergestate
r6512 def __contains__(self, dfile):
return dfile in self._state
def __getitem__(self, dfile):
Matt Mackall
resolve: new command...
r6518 return self._state[dfile][0]
def __iter__(self):
l = self._state.keys()
l.sort()
for f in l:
yield f
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
Matt Mackall
merge: introduce mergestate
r6512 def resolve(self, dfile, wctx, octx):
if self[dfile] == 'r':
return 0
Matt Mackall
resolve: new command...
r6518 state, hash, lfile, afile, anode, ofile, flags = self._state[dfile]
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()
Matt Mackall
merge: introduce mergestate
r6512 fcd = wctx[dfile]
fco = octx[ofile]
fca = self._repo.filectx(afile, fileid=anode)
r = filemerge.filemerge(self._repo, self._local, lfile, fcd, fco, fca)
Matt Mackall
merge: drop resolve state for mergers with identical contents (issue2680)
r13536 if r is None:
# no real conflict
del self._state[dfile]
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))
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
FUJIWARA Katsunori
merge: check filename case collision between changesets for branch merging...
r15673 def _checkcollision(mctx, wctx):
Matt Mackall
imported patch collision
r3785 "check for case folding collisions in the destination context"
folded = {}
Matt Mackall
merge: simplify some helpers
r6272 for fn in mctx:
FUJIWARA Katsunori
icasefs: use util.normcase() instead of str.lower() or os.path.normpath()
r15637 fold = util.normcase(fn)
Matt Mackall
imported patch collision
r3785 if fold in folded:
raise util.Abort(_("case-folding collision between %s and %s")
% (fn, folded[fold]))
folded[fold] = fn
FUJIWARA Katsunori
merge: check filename case collision between changesets for branch merging...
r15673 if wctx:
FUJIWARA Katsunori
icasefs: make case-folding collision detection as rename aware (issue3370)...
r16478 # class to delay looking up copy mapping
class pathcopies(object):
@util.propertycache
def map(self):
# {dst@mctx: src@wctx} copy mapping
return copies.pathcopies(wctx, mctx)
pc = pathcopies()
FUJIWARA Katsunori
merge: check filename case collision between changesets for branch merging...
r15673 for fn in wctx:
fold = util.normcase(fn)
mfn = folded.get(fold, None)
FUJIWARA Katsunori
icasefs: make case-folding collision detection as rename aware (issue3370)...
r16478 if mfn and mfn != fn and pc.map.get(mfn) != fn:
FUJIWARA Katsunori
merge: check filename case collision between changesets for branch merging...
r15673 raise util.Abort(_("case-folding collision between %s and %s")
% (mfn, fn))
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 """
action = []
Alexis S. L. Carvalho
merge: fix handling of deleted files
r6242 state = branchmerge and 'r' or 'f'
for f in wctx.deleted():
Matt Mackall
merge: simplify some helpers
r6272 if f not in mctx:
Alexis S. L. Carvalho
merge: fix handling of deleted files
r6242 action.append((f, state))
if not branchmerge:
for f in wctx.removed():
Matt Mackall
merge: simplify some helpers
r6272 if f not in mctx:
Alexis S. L. Carvalho
merge: fix handling of deleted files
r6242 action.append((f, "f"))
Matt Mackall
merge: pull manifest checks and updates into separate functions
r3107
return action
Matt Mackall
merge: use contexts for manifestmerge...
r3295 def manifestmerge(repo, p1, p2, pa, overwrite, partial):
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
overwrite = whether we clobber working files
partial = function to filter file lists
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 """
Matt Mackall
merge: simplify flag merging code slightly
r8733 def fmerge(f, f2, fa):
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 """merge flags"""
Matt Mackall
merge: add flag merging intelligence...
r5708 a, m, n = ma.flags(fa), m1.flags(f), m2.flags(f2)
if m == n: # flags agree
return m # unchanged
Matt Mackall
merge: simplify flag merging code slightly
r8733 if m and n and not a: # flags set, don't agree, differ from parent
Simon Heimberg
ui: extract choice from prompt...
r9048 r = repo.ui.promptchoice(
Matt Mackall
merge: simplify flag merging code slightly
r8733 _(" conflicting flags for %s\n"
"(n)one, e(x)ec or sym(l)ink?") % f,
Simon Heimberg
ui: extract choice from prompt...
r9048 (_("&None"), _("E&xec"), _("Sym&link")), 0)
Matt Mackall
many, many trivial check-code fixups
r10282 if r == 1:
return "x" # Exec
if r == 2:
return "l" # Symlink
Simon Heimberg
ui: extract choice from prompt...
r9048 return ""
Matt Mackall
merge: add flag merging intelligence...
r5708 if m and m != a: # changed from a to m
return m
if n and n != a: # changed from a to n
Matt Mackall
merge: accept missing revisions in symlink flag merge (issue3316)
r16257 if (n == 'l' or a == 'l') and m1.get(f) != ma.get(f):
Matt Mackall
merge: handle linear update to symlink correctly (issue3316)...
r16255 # can't automatically merge symlink flag when there
# are file-level conflicts here, let filemerge take
# care of it
Matt Mackall
merge: defer symlink flag merging to filemerge (issue3200)...
r16001 return m
Matt Mackall
merge: add flag merging intelligence...
r5708 return n
return '' # flag was cleared
Matt Mackall
merge: simplify exec flag handling
r3118
Matt Mackall
merge: swap file and mode args for act()
r3307 def act(msg, m, f, *args):
Matt Mackall
merge: use contexts for manifestmerge...
r3295 repo.ui.debug(" %s: %s -> %s\n" % (f, msg, m))
Matt Mackall
merge: simplify actions with helper function
r3121 action.append((f, m) + args)
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753 action, copy = [], {}
Matt Mackall
merge: refactor some initialization, drop backwards var
r8749 if overwrite:
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753 pa = p1
elif pa == p2: # backwards
pa = p1.p1()
elif pa and repo.ui.configbool("merge", "followcopies", True):
Thomas Arendsen Hein
merge: warn about file deleted in one branch and renamed in other (issue3074)...
r16794 copy, diverge, renamedelete = copies.mergecopies(repo, p1, p2, pa)
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753 for of, fl in diverge.iteritems():
act("divergent renames", "dr", of, fl)
Thomas Arendsen Hein
merge: warn about file deleted in one branch and renamed in other (issue3074)...
r16794 for of, fl in renamedelete.iteritems():
act("rename and delete", "rd", of, fl)
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753
repo.ui.note(_("resolving manifests\n"))
Martin Geisler
merge: make debug output easier to read...
r15625 repo.ui.debug(" overwrite: %s, partial: %s\n"
% (bool(overwrite), bool(partial)))
repo.ui.debug(" ancestor: %s, local: %s, remote: %s\n" % (pa, p1, p2))
Matt Mackall
merge: refactor manifestmerge init to better report effective ancestor
r8753
m1, m2, ma = p1.manifest(), p2.manifest(), pa.manifest()
copied = set(copy.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
for s in p1.substate:
if p1.sub(s).dirty():
m1['.hgsubstate'] += "+"
break
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 # Compare manifests
for f, n in m1.iteritems():
Matt Mackall
merge: reduce manifest copying
r3248 if partial and not partial(f):
continue
Matt Mackall
merge: pull manifest comparison out into separate function
r3105 if f in m2:
Matt Mackall
merge: remove a flags case
r8735 rflags = fmerge(f, f, f)
Matt Mackall
merge: simplify file revision comparison logic
r8752 a = ma.get(f, nullid)
if n == m2[f] or m2[f] == a: # same or local newer
Matt Mackall
update: synchronize permissions in the dirstate (issue1473)...
r11466 # is file locally modified or flags need changing?
# dirstate flags may need to be made current
if m1.flags(f) != rflags or n[20:]:
Matt Mackall
merge: simplify file revision comparison logic
r8752 act("update permissions", "e", f, rflags)
elif n == a: # remote newer
act("remote is newer", "g", f, rflags)
else: # both changed
act("versions differ", "m", f, f, f, rflags, False)
elif f in copied: # files we'll deal with on m2 side
pass
Matt Mackall
merge: add rename following...
r3249 elif f in copy:
f2 = copy[f]
Matt Mackall
merge: handle directory renames...
r3733 if f2 not in m2: # directory rename
act("remote renamed directory to " + f2, "d",
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 f, None, f2, m1.flags(f))
Matt Mackall
merge: combine a copy and move case
r8748 else: # case 2 A,B/B/B or case 4,21 A/B/B
act("local copied/moved to " + f2, "m",
Matt Mackall
merge: only store one direction of copies in the copy map...
r3730 f, f2, f, fmerge(f, f2, f2), False)
Matt Mackall
merge: simplify 'other deleted' case
r8744 elif f in ma: # clean, a different, no remote
Matt Mackall
merge: drop an overwrite test
r8739 if n != ma[f]:
Simon Heimberg
ui: extract choice from prompt...
r9048 if repo.ui.promptchoice(
Thomas Arendsen Hein
Fix misleading error and prompts during update/merge (issue556)
r5670 _(" local changed %s which remote deleted\n"
"use (c)hanged version or (d)elete?") % f,
Simon Heimberg
ui: extract choice from prompt...
r9048 (_("&Changed"), _("&Delete")), 0):
Matt Mackall
merge: swap file and mode args for act()
r3307 act("prompt delete", "r", f)
Matt Mackall
merge: fix prompt keep
r8736 else:
act("prompt keep", "a", f)
Matt Mackall
merge: make locally-added file test more correct
r8751 elif n[20:] == "a": # added, no remote
act("remote deleted", "f", f)
Matt Mackall
merge: don't use unknown()...
r16094 else:
Matt Mackall
merge: swap file and mode args for act()
r3307 act("other deleted", "r", f)
Matt Mackall
merge: pull manifest comparison out into separate function
r3105
for f, n in m2.iteritems():
Matt Mackall
merge: reduce manifest copying
r3248 if partial and not partial(f):
continue
Matt Mackall
merge: simplify file revision comparison logic
r8752 if f in m1 or f in copied: # files already visited
Matt Mackall
merge: add copied hash to simplify copy logic
r3729 continue
Matt Mackall
merge: add rename following...
r3249 if f in copy:
f2 = copy[f]
Matt Mackall
merge: handle directory renames...
r3733 if f2 not in m1: # directory rename
act("local renamed directory to " + f2, "d",
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 None, f, f2, m2.flags(f))
Matt Mackall
merge: handle directory renames...
r3733 elif f2 in m2: # rename case 1, A/A,B/A
Matt Mackall
merge: only store one direction of copies in the copy map...
r3730 act("remote copied to " + f, "m",
f2, f, f, fmerge(f2, f, f2), False)
else: # case 3,20 A/B/A
act("remote moved to " + f, "m",
f2, f, f, fmerge(f2, f, f2), True)
Matt Mackall
merge: reorder remote creation tests
r8741 elif f not in ma:
Matt Mackall
merge: don't use unknown()...
r16094 if (not overwrite
and _checkunknownfile(repo, p1, p2, f)):
rflags = fmerge(f, f, f)
act("remote differs from untracked local",
"m", f, f, f, rflags, False)
else:
act("remote created", "g", f, m2.flags(f))
Matt Mackall
merge: reorder remote creation tests
r8741 elif n != ma[f]:
Simon Heimberg
ui: extract choice from prompt...
r9048 if repo.ui.promptchoice(
Matt Mackall
merge: reorder remote creation tests
r8741 _("remote changed %s which local deleted\n"
"use (c)hanged version or leave (d)eleted?") % f,
Simon Heimberg
ui: extract choice from prompt...
r9048 (_("&Changed"), _("&Deleted")), 0) == 0:
Matt Mackall
merge: reorder remote creation tests
r8741 act("prompt recreating", "g", f, m2.flags(f))
Matt Mackall
merge: pull manifest comparison out into separate function
r3105
return action
Dirkjan Ochtman
some modernization cleanups, forward compatibility
r8366 def actionkey(a):
return a[1] == 'r' and -1 or 0, a
Paul Moore
Sort removes first when applying updates (fixes issues 750 and 912)...
r6805
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 def applyupdates(repo, action, wctx, mctx, actx, overwrite):
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
actx is the context of the common ancestor
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)
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 ms.reset(wctx.p1().node())
Matt Mackall
merge: introduce mergestate
r6512 moves = []
Dirkjan Ochtman
some modernization cleanups, forward compatibility
r8366 action.sort(key=actionkey)
Matt Mackall
merge: introduce mergestate
r6512
# prescan for merges
Matt Mackall
merge: do early copy to deal with issue636...
r5042 for a in action:
f, m = a[:2]
if m == 'm': # merge
f2, fd, flags, move = a[2:]
Matt Mackall
subrepo: add update/merge logic
r8814 if f == '.hgsubstate': # merged internally
continue
Martin Geisler
do not attempt to translate ui.debug output
r9467 repo.ui.debug("preserving %s for resolve of %s\n" % (f, fd))
Matt Mackall
merge: introduce mergestate
r6512 fcl = wctx[f]
fco = mctx[f2]
Matt Mackall
merge: move reverse-merge logic out of filemerge (issue2342)
r12008 if mctx == actx: # backwards, use working dir parent as ancestor
Matt Mackall
merge: handle no file parent in backwards merge (issue2364)
r12664 if fcl.parents():
Matt Mackall
misc: replace .parents()[0] with p1()
r13878 fca = fcl.p1()
Matt Mackall
merge: handle no file parent in backwards merge (issue2364)
r12664 else:
fca = repo.filectx(f, fileid=nullrev)
Matt Mackall
merge: move reverse-merge logic out of filemerge (issue2342)
r12008 else:
fca = fcl.ancestor(fco, actx)
if not fca:
fca = repo.filectx(f, fileid=nullrev)
Matt Mackall
merge: introduce mergestate
r6512 ms.add(fcl, fco, fca, fd, flags)
if f != fd and move:
moves.append(f)
Adrian Buehlmann
applyupdates: audit unlinking of renamed files and directories
r14398 audit = scmutil.pathauditor(repo.root)
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)
Matt Mackall
merge: introduce mergestate
r6512 os.unlink(repo.wjoin(f))
Matt Mackall
merge: do early copy to deal with issue636...
r5042
Augie Fackler
update: make calls to ui.progress()
r10431 numupdates = len(action)
for i, a in enumerate(action):
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 f, m = a[:2]
Martin Geisler
merge: use repo.ui directly instead local variable...
r15041 repo.ui.progress(_('updating'), i + 1, item=f, total=numupdates,
unit=_('files'))
Matt Mackall
merge: handle directory renames...
r3733 if f and f[0] == "/":
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 continue
if m == "r": # remove
repo.ui.note(_("removing %s\n") % f)
Adrian Buehlmann
applyupdates: audit unlinking of renamed files and directories
r14398 audit(f)
Matt Mackall
subrepo: add update/merge logic
r8814 if f == '.hgsubstate': # subrepo states need updating
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 try:
Adrian Buehlmann
rename util.unlink to unlinkpath
r13235 util.unlinkpath(repo.wjoin(f))
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 except OSError, inst:
if inst.errno != errno.ENOENT:
repo.ui.warn(_("update failed to remove %s: %s!\n") %
(f, inst.strerror))
Thomas Arendsen Hein
white space and line break cleanups
r3673 removed += 1
Matt Mackall
merge: unify merge and copy actions
r3308 elif m == "m": # merge
Matt Mackall
subrepo: add update/merge logic
r8814 if f == '.hgsubstate': # subrepo states need updating
Brodie Rao
cleanup: eradicate long lines
r16683 subrepo.submerge(repo, wctx, mctx, wctx.ancestor(mctx),
overwrite)
Matt Mackall
subrepo: add update/merge logic
r8814 continue
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 f2, fd, flags, move = a[2:]
Adrian Buehlmann
applyupdates: audit merged files...
r14406 repo.wopener.audit(fd)
Matt Mackall
merge: introduce mergestate
r6512 r = ms.resolve(fd, wctx, mctx)
Alejandro Santos
compat: can't compare two values of unequal datatypes
r9030 if r is not None and r > 0:
Matt Mackall
merge: add rename following...
r3249 unresolved += 1
Matt Mackall
merge: pull file copy/move out of filemerge
r3309 else:
Matt Mackall
merge: if filemerge skips merge, report as updated
r3400 if r is None:
updated += 1
else:
merged += 1
Matt Mackall
merge: avoid unlinking destination of merge when case changes (issue2715)
r13718 if (move and repo.dirstate.normalize(fd) != f
and 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)
Matt Mackall
merge: do early copy to deal with issue636...
r5042 os.unlink(repo.wjoin(f))
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 elif m == "g": # get
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 flags = a[2]
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 repo.ui.note(_("getting %s\n") % f)
Matt Mackall
merge: eliminate nodes from action list...
r3303 t = mctx.filectx(f).data()
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 repo.wwrite(f, t, flags)
Matt Mackall
merge: drop reference to file contents after write...
r11755 t = None
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 updated += 1
Matt Mackall
subrepo: add update/merge logic
r8814 if f == '.hgsubstate': # subrepo states need updating
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 subrepo.submerge(repo, wctx, mctx, wctx, overwrite)
Matt Mackall
merge: handle directory renames...
r3733 elif m == "d": # directory rename
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 f2, fd, flags = a[2:]
Matt Mackall
merge: handle directory renames...
r3733 if f:
repo.ui.note(_("moving %s to %s\n") % (f, fd))
Adrian Buehlmann
applyupdates: audit unlinking of renamed files and directories
r14398 audit(f)
Matt Mackall
merge: handle directory renames...
r3733 t = wctx.filectx(f).data()
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 repo.wwrite(fd, t, flags)
Adrian Buehlmann
rename util.unlink to unlinkpath
r13235 util.unlinkpath(repo.wjoin(f))
Matt Mackall
merge: handle directory renames...
r3733 if f2:
repo.ui.note(_("getting %s to %s\n") % (f2, fd))
t = mctx.filectx(f2).data()
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 repo.wwrite(fd, t, flags)
Matt Mackall
merge: handle directory renames...
r3733 updated += 1
Matt Mackall
merge: warn user about divergent renames
r4674 elif m == "dr": # divergent renames
fl = a[2]
Dan Villiom Podlaski Christiansen
merge: make 'diverging renames' diagnostic a more helpful note....
r12757 repo.ui.warn(_("note: possible conflict - %s was renamed "
"multiple times to:\n") % f)
Matt Mackall
merge: warn user about divergent renames
r4674 for nf in fl:
repo.ui.warn(" %s\n" % nf)
Thomas Arendsen Hein
merge: warn about file deleted in one branch and renamed in other (issue3074)...
r16794 elif m == "rd": # rename and delete
fl = a[2]
repo.ui.warn(_("note: possible conflict - %s was deleted "
"and renamed to:\n") % f)
for nf in fl:
repo.ui.warn(" %s\n" % nf)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 elif m == "e": # exec
Matt Mackall
symlinks: minimal support for symlinks in merge/update...
r4007 flags = a[2]
Adrian Buehlmann
applyupdates: audit path on flag changes...
r14405 repo.wopener.audit(f)
Adrian Buehlmann
rename util.set_flags to setflags
r14232 util.setflags(repo.wjoin(f), 'l' in flags, 'x' in flags)
Peter Arrenbrecht
merge: delay writing the mergestate during until commit is called...
r12369 ms.commit()
Martin Geisler
merge: use repo.ui directly instead local variable...
r15041 repo.ui.progress(_('updating'), None, total=numupdates, unit=_('files'))
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111
return updated, merged, removed, unresolved
Matt Mackall
merge: update dirstate correctly for non-branchmerge updates...
r3372 def recordupdates(repo, action, branchmerge):
Matt Mackall
merge: update some docstrings
r3315 "record merge actions to the dirstate"
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 for a in action:
f, m = a[:2]
if m == "r": # remove
if branchmerge:
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.remove(f)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 else:
Matt Mackall
dirstate: rename forget to drop...
r14434 repo.dirstate.drop(f)
Matt Mackall
merge: mark kept local files as readded on linear update (issue539)
r7768 elif m == "a": # re-add
if not branchmerge:
repo.dirstate.add(f)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 elif m == "f": # forget
Matt Mackall
dirstate: rename forget to drop...
r14434 repo.dirstate.drop(f)
Benoit Boissinot
correctly update dirstate after update+mode change (issue1456)
r7569 elif m == "e": # exec change
Patrick Mezard
merge: fix execute bit update issue introduced by 89207edf3973
r7630 repo.dirstate.normallookup(f)
Benoit Boissinot
correctly update dirstate after update+mode change (issue1456)
r7569 elif m == "g": # get
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 if branchmerge:
Benoit Boissinot
dirstate: more explicit name, rename normaldirty() to otherparent()
r10968 repo.dirstate.otherparent(f)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 else:
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.normal(f)
Matt Mackall
merge: move apply and dirstate code into separate functions
r3111 elif m == "m": # merge
Matt Mackall
merge: eliminate nodes from action list...
r3303 f2, fd, flag, move = a[2:]
Matt Mackall
merge: fixes for merge+rename...
r3251 if branchmerge:
# We've done a branch merge, mark this file as merged
# so that we properly record the merger later
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.merge(fd)
Matt Mackall
merge: update dirstate correctly for non-branchmerge updates...
r3372 if f != f2: # copy/rename
if move:
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.remove(f)
Matt Mackall
merge: update dirstate correctly for non-branchmerge updates...
r3372 if f != fd:
repo.dirstate.copy(f, fd)
else:
repo.dirstate.copy(f2, fd)
Matt Mackall
merge: fixes for merge+rename...
r3251 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.
Gilles Moris
merge: avoid to break the dirstate copy status on moved files...
r11178 if f2 == fd: # file not locally copied/moved
repo.dirstate.normallookup(fd)
Matt Mackall
merge: unify merge and copy actions
r3308 if move:
Matt Mackall
dirstate: rename forget to drop...
r14434 repo.dirstate.drop(f)
Matt Mackall
merge: handle directory renames...
r3733 elif m == "d": # directory rename
f2, fd, flag = a[2:]
Matt Mackall
merge: fix adding untracked files on directory rename (issue612)...
r4819 if not f2 and f not in repo.dirstate:
# untracked file moved
continue
Matt Mackall
merge: handle directory renames...
r3733 if branchmerge:
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.add(fd)
Matt Mackall
merge: handle directory renames...
r3733 if f:
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.remove(f)
Matt Mackall
merge: handle directory renames...
r3733 repo.dirstate.copy(f, fd)
if f2:
repo.dirstate.copy(f2, fd)
else:
Matt Mackall
dirstate: break update into separate functions
r4904 repo.dirstate.normal(fd)
Matt Mackall
merge: handle directory renames...
r3733 if f:
Matt Mackall
dirstate: rename forget to drop...
r14434 repo.dirstate.drop(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,
mergeancestor=False):
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)
Patrick Mezard
rebase: allow collapsing branches in place (issue3111)...
r16696 mergeancestor = 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
n n y * | merge (2) (2)
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716 n y * * | --- discard ---
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 y n y * | --- (3) ---
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716 y n n * | --- ok ---
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 y y * * | --- (4) ---
Stuart W Marks
update: add comments and test cases for updating across branches...
r9716
x = can't happen
* = don't-care
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 1 = abort: crosses branches (use 'hg merge' or 'hg update -c')
2 = abort: crosses branches (use 'hg merge' to merge or
use 'hg update -C' to discard changes)
3 = abort: uncommitted local changes
4 = 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]
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 if node is None:
# tip of current branch
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())
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 overwrite = force and not branchmerge
pl = wc.parents()
Matt Mackall
use repo[changeid] to get a changectx
r6747 p1, p2 = pl[0], repo[node]
Matt Mackall
merge: add ancestor to the update function...
r13874 if ancestor:
pa = repo[ancestor]
else:
pa = p1.ancestor(p2)
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:
if pa == p2:
Matt Mackall
merge: improve merge with ancestor message
r11417 raise util.Abort(_("merging with a working directory ancestor"
" has no effect"))
Matt Mackall
update: better logic and messages for updates...
r6375 elif pa == 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()):
Kevin Bullock
merge: make 'nothing to merge' aborts consistent...
r15619 raise util.Abort(_("outstanding uncommitted changes"),
hint=_("use 'hg status' to list changes"))
Oleg Stepanov
Do not allow merging with uncommitted changes in a subrepo
r13437 for s in wc.substate:
if wc.sub(s).dirty():
raise util.Abort(_("outstanding uncommitted changes in "
"subrepository '%s'") % s)
Matt Mackall
update: better logic and messages for updates...
r6375 elif not overwrite:
Matt Mackall
backout most of 4f8067c94729
r12401 if pa == p1 or pa == p2: # linear
Matt Mackall
update: better logic and messages for updates...
r6375 pass # all good
Augie Fackler
update: check wc.dirty() before setting overwrite=True...
r14663 elif wc.dirty(missing=True):
Brodie Rao
update: use higher level wording for "crosses branches" error...
r12681 raise util.Abort(_("crosses branches (merge branches or use"
" --clean to discard changes)"))
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 elif onode is None:
Brendan Cully
Make pull -u behave like pull && update...
r14485 raise util.Abort(_("crosses branches (merge branches or update"
Brodie Rao
update: use higher level wording for "crosses branches" error...
r12681 " --check to force update)"))
Matt Mackall
update: better logic and messages for updates...
r6375 else:
Stuart W Marks
update: allow branch crossing without -c or -C, with no uncommitted changes...
r9717 # Allow jumping branches if clean and specific rev given
Matt Mackall
update: use normal update path with --check (issue2450)...
r16092 pa = p1
Matt Mackall
Merge: move most tests to the beginning
r2814
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 ### calculate phase
action = []
Mads Kiilerich
update: don't clobber untracked files with wrong casing
r15538 folding = not util.checkcase(repo.path)
if folding:
FUJIWARA Katsunori
icasefs: make case-folding collision detection as rename aware (issue3370)...
r16478 # collision check is not needed for clean update
Patrick Mezard
update: fix case-collision with a clean wd and no --clean...
r16492 if (not branchmerge and
(force or not wc.dirty(missing=True, branch=False))):
FUJIWARA Katsunori
icasefs: make case-folding collision detection as rename aware (issue3370)...
r16478 _checkcollision(p2, None)
else:
_checkcollision(p2, wc)
Matt Mackall
merge: fix unknown file merge detection for case-folding systems...
r16284 if not force:
_checkunknown(repo, wc, p2)
Matt Mackall
merge: privatize some functions, unnest some others
r6269 action += _forgetremoved(wc, p2, branchmerge)
Matt Mackall
Use try/finally pattern to cleanup locks and transactions
r4915 action += manifestmerge(repo, wc, p2, pa, overwrite, partial)
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
Move merge code to its own module...
r2775
Erik Zielke
subrepo: make update -C clean the working directory for svn subrepos...
r13322 stats = applyupdates(repo, action, wc, p2, pa, overwrite)
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)
Matt Mackall
merge: back out single-parent fast-forward merge...
r13550 recordupdates(repo, action, branchmerge)
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