Comments
Patch
@@ -5,10 +5,11 @@
# This software may be used and distributed according to the terms of the
# GNU General Public License version 2 or any later version.
from node import nullid, nullrev, hex, bin
from i18n import _
+from mercurial import obsolete
import error, util, filemerge, copies, subrepo, worker, dicthelpers
import errno, os, shutil
class mergestate(object):
'''track 3-way merge state of individual files'''
@@ -695,21 +696,30 @@ def update(repo, node, branchmerge, forc
if wc.sub(s).dirty():
raise util.Abort(_("outstanding uncommitted changes in "
"subrepository '%s'") % s)
elif not overwrite:
- if pa == p1 or pa == p2: # linear
- pass # all good
- elif wc.dirty(missing=True):
- raise util.Abort(_("crosses branches (merge branches or use"
- " --clean to discard changes)"))
- elif onode is None:
- raise util.Abort(_("crosses branches (merge branches or update"
- " --check to force update)"))
- else:
- # Allow jumping branches if clean and specific rev given
- pa = p1
+ if pa not in (p1, p2): # nolinear
+ 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:
+ pa = p1 # allow updating to successors
+ elif dirty:
+ msg = _("crosses branches (merge branches or use"
+ " --clean to discard changes)")
+ raise util.Abort(msg)
+ else: # node is none
+ msg = _("crosses branches (merge branches or update"
+ " --check to force update)")
+ raise util.Abort(msg)
+ else:
+ # Allow jumping branches if clean and specific rev given
+ pa = p1
### calculate phase
actions = calculateupdates(repo, wc, p2, pa,
branchmerge, force, partial, mergeancestor)
@@ -162,5 +162,65 @@ Cases are run as shown in that table, ro
$ revtest '-cC dirty linear' dirty 1 2 -cC
abort: cannot specify both -c/--check and -C/--clean
parent=1
M foo
+Test obsolescence behavior
+---------------------------------------------------------------------
+
+successors should be taken in account when checking head destination
+
+ $ cat << EOF >> $HGRCPATH
+ > [extensions]
+ > obs=$TESTTMP/obs.py
+ > [ui]
+ > logtemplate={rev}:{node|short} {desc|firstline}
+ > EOF
+ $ cat > $TESTTMP/obs.py << EOF
+ > import mercurial.obsolete
+ > mercurial.obsolete._enabled = True
+ > EOF
+
+Test no-argument update to a successor of an obsoleted changeset
+
+ $ hg log -G
+ o 5:ff252e8273df 5
+ |
+ o 4:d047485b3896 4
+ |
+ | o 3:6efa171f091b 3
+ | |
+ | | o 2:bd10386d478c 2
+ | |/
+ | @ 1:0786582aa4b1 1
+ |/
+ o 0:60829823a42a 0
+
+ $ hg status
+ M foo
+
+We add simple obsolescence marker between 3 and 4 (indirect successors)
+
+ $ hg id --debug -i -r 3
+ 6efa171f091b00a3c35edc15d48c52a498929953
+ $ hg id --debug -i -r 4
+ d047485b3896813b2a624e86201983520f003206
+ $ hg debugobsolete 6efa171f091b00a3c35edc15d48c52a498929953 aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa
+ $ hg debugobsolete aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa d047485b3896813b2a624e86201983520f003206
+
+Test that 5 is detected as a valid destination from 3
+ $ hg up --quiet --hidden 3
+ $ hg up 5
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Test that 5 is detected as a valid destination from 1
+ $ hg up --quiet 0 # we should be able to update to 3 directly
+ $ hg up --quiet --hidden 3 # but not implemented yet.
+ $ hg up 5
+ 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
+
+Test that 5 is not detected as a valid destination from 2
+ $ hg up --quiet 0
+ $ hg up --quiet 2
+ $ hg up 5
+ abort: crosses branches (merge branches or use --clean to discard changes)
+ [255]