[PATCH 5 of 6] update: learn --merge to allow merging across topological branches (issue5125)
Martin von Zweigbergk
martinvonz at google.com
Mon Feb 13 20:07:22 EST 2017
# HG changeset patch
# User Martin von Zweigbergk <martinvonz at google.com>
# Date 1487019517 28800
# Mon Feb 13 12:58:37 2017 -0800
# Node ID 75e5a492d7f69420a554fe498ae24060c755b09f
# Parent 59e2d3da607cc09ebe133ab199fc4f343d74e1e6
update: learn --merge to allow merging across topological branches (issue5125)
diff -r 59e2d3da607c -r 75e5a492d7f6 mercurial/commands.py
--- a/mercurial/commands.py Mon Feb 13 15:04:46 2017 -0800
+++ b/mercurial/commands.py Mon Feb 13 12:58:37 2017 -0800
@@ -6471,12 +6471,13 @@
@command('^update|up|checkout|co',
[('C', 'clean', None, _('discard uncommitted changes (no backup)')),
('c', 'check', None, _('require clean working directory')),
+ ('m', 'merge', None, _('merge local changes')),
('d', 'date', '', _('tipmost revision matching date'), _('DATE')),
('r', 'rev', '', _('revision'), _('REV'))
] + mergetoolopts,
- _('[-C|-c] [-d DATE] [[-r] REV]'))
+ _('[-C|-c|-m] [-d DATE] [[-r] REV]'))
def update(ui, repo, node=None, rev=None, clean=False, date=None, check=False,
- tool=None):
+ merge=None, tool=None):
"""update working directory (or switch revisions)
Update the repository's working directory to the specified
@@ -6498,7 +6499,7 @@
The following rules apply when the working directory contains
uncommitted changes:
- 1. If neither -c/--check nor -C/--clean is specified, and if
+ 1. If none of -c/--check, -C/--clean, or -m/--merge is specified, and if
the requested changeset is an ancestor or descendant of
the working directory's parent, the uncommitted changes
are merged into the requested changeset and the merged
@@ -6507,10 +6508,14 @@
branch), the update is aborted and the uncommitted changes
are preserved.
- 2. With the -c/--check option, the update is aborted and the
+ 2. With the -m/--merge option, the update is allowed even if the
+ requested changeset is not an ancestor or descendant of
+ the working directory's parent.
+
+ 3. With the -c/--check option, the update is aborted and the
uncommitted changes are preserved.
- 3. With the -C/--clean option, uncommitted changes are discarded and
+ 4. With the -C/--clean option, uncommitted changes are discarded and
the working directory is updated to the requested changeset.
To cancel an uncommitted merge (and lose your changes), use
@@ -6535,8 +6540,15 @@
if date and rev is not None:
raise error.Abort(_("you can't specify a revision and a date"))
- if check and clean:
- raise error.Abort(_("cannot specify both -c/--check and -C/--clean"))
+ if len([x for x in (check, clean , merge) if x]) > 1:
+ raise error.Abort(_("can only specify one of -c/--check, -C/--clean, "
+ "and -m/merge"))
+
+ updatecheck = 'linear'
+ if check:
+ updatecheck = 'abort'
+ elif merge:
+ updatecheck = None
with repo.wlock():
cmdutil.clearunfinished(repo)
@@ -6550,7 +6562,8 @@
repo.ui.setconfig('ui', 'forcemerge', tool, 'update')
- return hg.updatetotally(ui, repo, rev, brev, clean=clean, check=check)
+ return hg.updatetotally(ui, repo, rev, brev, clean=clean,
+ updatecheck=updatecheck)
@command('verify', [])
def verify(ui, repo):
diff -r 59e2d3da607c -r 75e5a492d7f6 mercurial/hg.py
--- a/mercurial/hg.py Mon Feb 13 15:04:46 2017 -0800
+++ b/mercurial/hg.py Mon Feb 13 12:58:37 2017 -0800
@@ -681,18 +681,19 @@
repo.ui.status(_("%d files updated, %d files merged, "
"%d files removed, %d files unresolved\n") % stats)
-def updaterepo(repo, node, overwrite):
+def updaterepo(repo, node, overwrite, updatecheck=None):
"""Update the working directory to node.
When overwrite is set, changes are clobbered, merged else
returns stats (see pydoc mercurial.merge.applyupdates)"""
return mergemod.update(repo, node, False, overwrite,
- labels=['working copy', 'destination'])
+ labels=['working copy', 'destination'],
+ updatecheck=updatecheck)
-def update(repo, node, quietempty=False):
- """update the working directory to node, merging linear changes"""
- stats = updaterepo(repo, node, False)
+def update(repo, node, quietempty=False, updatecheck=None):
+ """update the working directory to node"""
+ stats = updaterepo(repo, node, False, updatecheck=updatecheck)
_showstats(repo, stats, quietempty)
if stats[3]:
repo.ui.status(_("use 'hg resolve' to retry unresolved file merges\n"))
@@ -712,7 +713,8 @@
# naming conflict in updatetotally()
_clean = clean
-def updatetotally(ui, repo, checkout, brev, clean=False, check=False):
+def updatetotally(ui, repo, checkout, brev, clean=False,
+ updatecheck='linear'):
"""Update the working directory with extra care for non-file components
This takes care of non-file components below:
@@ -724,7 +726,14 @@
:checkout: to which revision the working directory is updated
:brev: a name, which might be a bookmark to be activated after updating
:clean: whether changes in the working directory can be discarded
- :check: whether changes in the working directory should be checked
+ :updatecheck: how to deal with a dirty working directory
+
+ Valid values for updatecheck are:
+
+ * abort: abort if the working directory is dirty
+ * None: don't check (merge working directory changes into destination)
+ * linear: check that update is linear before merging working directory
+ changes into destination
This returns whether conflict is detected at updating or not.
"""
@@ -739,9 +748,10 @@
if clean:
ret = _clean(repo, checkout)
else:
- if check:
+ if updatecheck == 'abort':
cmdutil.bailifchanged(repo, merge=False)
- ret = _update(repo, checkout)
+ updatecheck = None
+ ret = _update(repo, checkout, updatecheck=updatecheck)
if not ret and movemarkfrom:
if movemarkfrom == repo['.'].node():
diff -r 59e2d3da607c -r 75e5a492d7f6 mercurial/merge.py
--- a/mercurial/merge.py Mon Feb 13 15:04:46 2017 -0800
+++ b/mercurial/merge.py Mon Feb 13 12:58:37 2017 -0800
@@ -1444,7 +1444,8 @@
repo.dirstate.normal(f)
def update(repo, node, branchmerge, force, ancestor=None,
- mergeancestor=False, labels=None, matcher=None, mergeforce=False):
+ mergeancestor=False, labels=None, matcher=None, mergeforce=False,
+ updatecheck='linear'):
"""
Perform a merge between the working directory and the given node
@@ -1494,6 +1495,7 @@
# This functon used to find the default destination if node was None, but
# that's now in destutil.py.
assert node is not None
+ assert updatecheck in (None, 'linear')
# If we're doing a partial update, we need to skip updating
# the dirstate, so make a note of any partial-ness to the
# update here.
@@ -1550,7 +1552,8 @@
repo.hook('update', parent1=xp2, parent2='', error=0)
return 0, 0, 0, 0
- if pas not in ([p1], [p2]): # nonlinear
+ if (updatecheck == 'linear' and
+ pas not in ([p1], [p2])): # nonlinear
dirty = wc.dirty(missing=True)
if dirty:
# Branching is a bit strange to ensure we do the minimal
diff -r 59e2d3da607c -r 75e5a492d7f6 tests/test-completion.t
--- a/tests/test-completion.t Mon Feb 13 15:04:46 2017 -0800
+++ b/tests/test-completion.t Mon Feb 13 12:58:37 2017 -0800
@@ -223,7 +223,7 @@
serve: accesslog, daemon, daemon-postexec, errorlog, port, address, prefix, name, web-conf, webdir-conf, pid-file, stdio, cmdserver, templates, style, ipv6, certificate
status: all, modified, added, removed, deleted, clean, unknown, ignored, no-status, copies, print0, rev, change, include, exclude, subrepos, template
summary: remote
- update: clean, check, date, rev, tool
+ update: clean, check, merge, date, rev, tool
addremove: similarity, subrepos, include, exclude, dry-run
archive: no-decode, prefix, rev, type, subrepos, include, exclude
backout: merge, commit, no-commit, parent, rev, edit, tool, include, exclude, message, logfile, date, user
diff -r 59e2d3da607c -r 75e5a492d7f6 tests/test-update-branches.t
--- a/tests/test-update-branches.t Mon Feb 13 15:04:46 2017 -0800
+++ b/tests/test-update-branches.t Mon Feb 13 12:58:37 2017 -0800
@@ -160,6 +160,16 @@
parent=1
M foo
+ $ revtest '-m dirty linear' dirty 1 2 -m
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=2
+ M foo
+
+ $ revtest '-m dirty cross' dirty 3 4 -m
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+ parent=4
+ M foo
+
$ revtest '-c dirtysub linear' dirtysub 1 2 -c
abort: uncommitted changes in subrepository 'sub'
parent=1
@@ -171,7 +181,17 @@
parent=2
$ revtest '-cC dirty linear' dirty 1 2 -cC
- abort: cannot specify both -c/--check and -C/--clean
+ abort: can only specify one of -c/--check, -C/--clean, and -m/merge
+ parent=1
+ M foo
+
+ $ revtest '-mc dirty linear' dirty 1 2 -mc
+ abort: can only specify one of -c/--check, -C/--clean, and -m/merge
+ parent=1
+ M foo
+
+ $ revtest '-mC dirty linear' dirty 1 2 -mC
+ abort: can only specify one of -c/--check, -C/--clean, and -m/merge
parent=1
M foo
More information about the Mercurial-devel
mailing list