diff --git a/mercurial/merge.py b/mercurial/merge.py --- a/mercurial/merge.py +++ b/mercurial/merge.py @@ -7,6 +7,7 @@ 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 @@ -697,17 +698,26 @@ def update(repo, node, branchmerge, forc "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 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, diff --git a/tests/test-update-branches.t b/tests/test-update-branches.t --- a/tests/test-update-branches.t +++ b/tests/test-update-branches.t @@ -164,3 +164,63 @@ Cases are run as shown in that table, ro 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]