Mercurial > hg
changeset 18990:7373be706f02
merge with crew
author | Matt Mackall <mpm@selenic.com> |
---|---|
date | Tue, 16 Apr 2013 13:22:29 -0500 |
parents | a59e575c6ff8 (diff) 12a3474c1634 (current diff) |
children | c1af1fb314bc |
files | |
diffstat | 6 files changed, 228 insertions(+), 26 deletions(-) [+] |
line wrap: on
line diff
--- a/mercurial/bookmarks.py Tue Apr 16 10:08:20 2013 -0700 +++ b/mercurial/bookmarks.py Tue Apr 16 13:22:29 2013 -0500 @@ -292,19 +292,7 @@ # (new != nullrev has been excluded by the previous check) return True elif repo.obsstore: - # We only need this complicated logic if there is obsolescence - # XXX will probably deserve an optimised revset. - nm = repo.changelog.nodemap - validdests = set([old]) - plen = -1 - # compute the whole set of successors or descendants - while len(validdests) != plen: - plen = len(validdests) - succs = set(c.node() for c in validdests) - mutable = [c.node() for c in validdests if c.mutable()] - succs.update(obsolete.allsuccessors(repo.obsstore, mutable)) - known = (n for n in succs if n in nm) - validdests = set(repo.set('%ln::', known)) - return new in validdests + return new.node() in obsolete.foreground(repo, [old.node()]) else: + # still an independant clause as it is lazyer (and therefore faster) return old.descendant(new)
--- a/mercurial/merge.py Tue Apr 16 10:08:20 2013 -0700 +++ b/mercurial/merge.py Tue Apr 16 13:22:29 2013 -0500 @@ -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 @@ "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,
--- a/mercurial/obsolete.py Tue Apr 16 10:08:20 2013 -0700 +++ b/mercurial/obsolete.py Tue Apr 16 13:22:29 2013 -0500 @@ -405,6 +405,33 @@ seen.add(suc) remaining.add(suc) +def foreground(repo, nodes): + """return all nodes in the "foreground" of other node + + The foreground of a revision is anything reachable using parent -> children + or precursor -> sucessor relation. It is very similars to "descendant" but + augmented with obsolescence information. + + Beware that possible obsolescence cycle may result if complexe situation. + """ + repo = repo.unfiltered() + foreground = set(repo.set('%ln::', nodes)) + if repo.obsstore: + # We only need this complicated logic if there is obsolescence + # XXX will probably deserve an optimised revset. + nm = repo.changelog.nodemap + plen = -1 + # compute the whole set of successors or descendants + while len(foreground) != plen: + plen = len(foreground) + succs = set(c.node() for c in foreground) + mutable = [c.node() for c in foreground if c.mutable()] + succs.update(allsuccessors(repo.obsstore, mutable)) + known = (n for n in succs if n in nm) + foreground = set(repo.set('%ln::', known)) + return set(c.node() for c in foreground) + + def successorssets(repo, initialnode, cache=None): """Return all set of successors of initial nodes
--- a/mercurial/phases.py Tue Apr 16 10:08:20 2013 -0700 +++ b/mercurial/phases.py Tue Apr 16 13:22:29 2013 -0500 @@ -266,7 +266,15 @@ filtered = True if filtered: self.dirty = True - self._phaserevs = None + # filterunknown is called by repo.destroyed, we may have no changes in + # root but phaserevs contents is certainly invalide (or at least we + # have not proper way to check that. related to issue 3858. + # + # The other caller is __init__ that have no _phaserevs initialized + # anyway. If this change we should consider adding a dedicated + # "destroyed" function to phasecache or a proper cache key mechanisme + # (see branchmap one) + self._phaserevs = None def advanceboundary(repo, targetphase, nodes): """Add nodes to a phase changing other nodes phases if necessary.
--- a/tests/test-rebase-cache.t Tue Apr 16 10:08:20 2013 -0700 +++ b/tests/test-rebase-cache.t Tue Apr 16 13:22:29 2013 -0500 @@ -385,3 +385,112 @@ $ hg theads 0: 'A' + +Make sure rebase does not break for phase/filter related reason +---------------------------------------------------------------- +(issue3858) + + $ cd .. + + $ cat >> $HGRCPATH << EOF + > [ui] + > logtemplate={rev} {desc} {phase}\n + > EOF + $ cat $HGRCPATH + [ui] + slash = True + interactive = False + [defaults] + backout = -d "0 0" + commit = -d "0 0" + tag = -d "0 0" + [extensions] + graphlog= + rebase= + mq= + + [phases] + publish=False + + [alias] + tglog = log -G --template "{rev}: '{desc}' {branches}\n" + theads = heads --template "{rev}: '{desc}' {branches}\n" + [ui] + logtemplate={rev} {desc} {phase}\n + + + $ hg init c4 + $ cd c4 + + $ echo a > a + $ hg ci -Am A + adding a + $ echo b > b + $ hg ci -Am B + adding b + $ hg up 0 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo c > c + $ hg ci -Am C + adding c + created new head + $ hg up 1 + 1 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ hg merge + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ hg ci -m d + $ hg up 2 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo e > e + $ hg ci -Am E + adding e + created new head + $ hg merge 3 + 1 files updated, 0 files merged, 0 files removed, 0 files unresolved + (branch merge, don't forget to commit) + $ hg ci -m F + $ hg up 3 + 0 files updated, 0 files merged, 1 files removed, 0 files unresolved + $ echo g > g + $ hg ci -Am G + adding g + created new head + $ echo h > h + $ hg ci -Am H + adding h + $ hg up 5 + 1 files updated, 0 files merged, 2 files removed, 0 files unresolved + $ echo i > i + $ hg ci -Am I + adding i + +Turn most changeset public + + $ hg ph -p 7 + + $ hg heads + 8 I draft + 7 H public + $ hg log -G + @ 8 I draft + | + | o 7 H public + | | + | o 6 G public + | | + o | 5 F draft + |\| + o | 4 E draft + | | + | o 3 d public + |/| + o | 2 C public + | | + | o 1 B public + |/ + o 0 A public + + + $ hg rebase --dest 7 --source 5 + saved backup bundle to $TESTTMP/a3/c4/.hg/strip-backup/*-backup.hg (glob)
--- a/tests/test-update-branches.t Tue Apr 16 10:08:20 2013 -0700 +++ b/tests/test-update-branches.t Tue Apr 16 13:22:29 2013 -0500 @@ -164,3 +164,63 @@ 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]