<?xml version="1.0" encoding="UTF-8"?>
<rdf:RDF xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" xmlns="http://purl.org/rss/1.0/" xmlns:taxo="http://purl.org/rss/1.0/modules/taxonomy/" xmlns:dc="http://purl.org/dc/elements/1.1/" xmlns:syn="http://purl.org/rss/1.0/modules/syndication/" xmlns:admin="http://webns.net/mvcb/">
  <channel rdf:about="http://blog.gmane.org/gmane.comp.version-control.mercurial.devel">
    <title>gmane.comp.version-control.mercurial.devel</title>
    <link>http://blog.gmane.org/gmane.comp.version-control.mercurial.devel</link>
    <description/>
    <syn:updatePeriod>hourly</syn:updatePeriod>
    <syn:updateFrequency>1</syn:updateFrequency>
    <syn:updateBase>1901-01-01T00:00+00:00</syn:updateBase>
    <items>
      <rdf:Seq>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50572"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50569"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50567"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50561"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50560"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50553"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50548"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50546"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50544"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50540"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50531"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50523"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50522"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50517"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50515"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50514"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50510"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50509"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50504"/>
        <rdf:li rdf:resource="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50494"/>
      </rdf:Seq>
    </items>
    <image rdf:resource="http://gmane.org/img/gmane-25t.png"/>
    <textinput rdf:resource=""/>
  </channel>
  <image rdf:about="http://gmane.org/img/gmane-25t.png">
    <title>Gmane</title>
    <url>http://gmane.org/img/gmane-25t.png</url>
    <link>http://gmane.org</link>
  </image>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50572">
    <title>[PATCH 0 of 7] help: format help text using RST</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50572</link>
    <description>&lt;pre&gt;This set of patches changes the help system so that all help text is formatted
using RST. The first patches contain some refactoring. Then a sequence of
patches follows which change the helper functions to use RST formatting
internally.

In the final step, the helper functions are changed to simply return the RST
text they produce, instead of printing it themselves. The main help function is
then changed to assemble the RST pieces and to format and print the entire help
text.

&lt;/pre&gt;</description>
    <dc:creator>Olav Reinert</dc:creator>
    <dc:date>2012-05-26T15:43:45</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50569">
    <title>mercurial/crew&lt; at &gt;16782: 4 outgoing changesets</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50569</link>
    <description>&lt;pre&gt;4 outgoing changesets in mercurial/crew:

http://hg.intevation.org/mercurial/crew/rev/e9ae770eff1c
changeset:   16782:e9ae770eff1c
tag:         tip
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 21:34:29 2012 +0200
summary:     merge: show renamed on one and deleted on the other side in debug output

http://hg.intevation.org/mercurial/crew/rev/98687cdddcb1
changeset:   16781:98687cdddcb1
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 20:50:16 2012 +0200
summary:     merge: warn about file deleted in one branch and renamed in other (issue3074)

http://hg.intevation.org/mercurial/crew/rev/9cbc44a6600e
changeset:   16780:9cbc44a6600e
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 17:33:19 2012 +0200
summary:     tests: do not create repos inside repos in test-rename-merge1.t

http://hg.intevation.org/mercurial/crew/rev/ad394c897b16
changeset:   16779:ad394c897b16
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 17:25:48 2012 +0200
summary:     merge: do not warn about copy and rename in the same transaction (issue2113)

&lt;/pre&gt;</description>
    <dc:creator>Mercurial Commits</dc:creator>
    <dc:date>2012-05-26T11:00:06</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50567">
    <title>[PATCH RFC] revset: add pattern matching to 'tag' revset expression</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50567</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Simon King &amp;lt;simon&amp;lt; at &amp;gt;simonking.org.uk&amp;gt;
# Date 1337980885 -3600
# Node ID acd9d3574a98a80e9db12b89a6f338d1541f3a1d
# Parent  2ac08d8b21aa7b6e0a062afed5a3f357ccef67f9
revset: add pattern matching to 'tag' revset expression

The 'tag' revset expression now takes an optional second parameter, which
is either 're' or 'glob'. When one of these is supplied, the tag name is
treated as a pattern, and any tags which match the pattern will be returned
from the expression.

Outstanding questions:

1. Is an optional parameter the right way to support this? Would it be better
   to have a separate expression, or use 're:' and 'glob:' prefixes on the
   tag name parameter instead?

2. Is it OK to use the python fnmatch module for glob patterns? Mercurial's
   match module seems much more geared towards filename matching; even the
   _globre function treats path separators specially.

3. Patterns must match from the start of the tag name. I think this would be
   the least surprising behaviour, but perhaps others may disagree.

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -6,6 +6,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 # GNU General Public License version 2 or any later version.
 
 import re
+import fnmatch
 import parser, util, error, discovery, hbisect, phases
 import node
 import bookmarks as bookmarksmod
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1120,19 +1121,42 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     return [e[-1] for e in l]
 
 def tag(repo, subset, x):
-    """``tag([name])``
+    """``tag([name[, patterntype]])``
     The specified tag by name, or all tagged revisions if no name is given.
+
+    If patterntype is passed, it may be one of 're' or 'glob'. Revisions
+    with tags matching the pattern will be returned.
     """
     # i18n: "tag" is a keyword
-    args = getargs(x, 0, 1, _("tag takes one or no arguments"))
+    args = getargs(x, 0, 2, _("tag takes at most 2 arguments"))
     cl = repo.changelog
     if args:
         tn = getstring(args[0],
                        # i18n: "tag" is a keyword
                        _('the argument to tag must be a string'))
-        if not repo.tags().get(tn, None):
-            raise util.Abort(_("tag '%s' does not exist") % tn)
-        s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
+        if len(args) == 1:
+            if not repo.tags().get(tn, None):
+                raise util.Abort(_("tag '%s' does not exist") % tn)
+            s = set([cl.rev(n) for t, n in repo.tagslist() if t == tn])
+        else:
+            # i18n: "tag" is a keyword
+            typemsg = _("the second argument to tag must be 're' or 'glob'")
+            patterntype = getstring(args[1], typemsg)
+            if patterntype == 're':
+                try:
+                    regexp = re.compile(tn)
+                except re.error, e:
+                    raise error.ParseError(_("invalid match pattern: %s") % e)
+            elif patterntype == 'glob':
+                regexp = re.compile(fnmatch.translate(tn))
+            else:
+                raise util.Abort(typemsg)
+            s = set()
+            for t, n in repo.tagslist():
+                if regexp.match(t):
+                    s.add(cl.rev(n))
+            if not s:
+                raise util.Abort(_('no tags match pattern "%s"') % tn)
     else:
         s = set([cl.rev(n) for t, n in repo.tagslist() if t != 'tip'])
     return [r for r in subset if r in s]
diff --git a/tests/test-revset.t b/tests/test-revset.t
--- a/tests/test-revset.t
+++ b/tests/test-revset.t
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -369,6 +369,16 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   6
   $ log 'tag(tip)'
   9
+  $ log 'tag("1.*", "glob")'
+  6
+  $ log 'tag("0.*", "glob")'
+  abort: no tags match pattern "0.*"
+  [255]
+  $ log 'tag("foo", "re")'
+  abort: no tags match pattern "foo"
+  [255]
+  $ log 'tag("[0-9].[0-9]", "re")'
+  6
   $ log 'tag(unknown)'
   abort: tag 'unknown' does not exist
   [255]
&lt;/pre&gt;</description>
    <dc:creator>Simon King</dc:creator>
    <dc:date>2012-05-25T21:23:02</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50561">
    <title>[Bug 3471] New: keyword extension: commit --amend not supported</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50561</link>
    <description>&lt;pre&gt;http://bz.selenic.com/show_bug.cgi?id=3471

          Priority: normal
            Bug ID: 3471
                CC: mercurial-devel&amp;lt; at &amp;gt;selenic.com
          Assignee: blacktrash&amp;lt; at &amp;gt;gmx.net
           Summary: keyword extension: commit --amend not supported
          Severity: bug
    Classification: Unclassified
                OS: All
          Reporter: blacktrash&amp;lt; at &amp;gt;gmx.net
          Hardware: All
            Status: UNCONFIRMED
           Version: 2.2.1
         Component: Mercurial
           Product: Mercurial

Currently commit --amend does not update the keywords.

Patch in preparation.

Aside: "Mercurial" core seems a too general component for this bug, but I could
not find a way to create a new component. Perhaps I'm not entitled to do so.

&lt;/pre&gt;</description>
    <dc:creator>bugzilla-daemon&lt; at &gt;bz.selenic.com</dc:creator>
    <dc:date>2012-05-25T11:42:40</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50560">
    <title>[Bug 3470] New: crash in dispatch.py when trying to report an error</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50560</link>
    <description>&lt;pre&gt;http://bz.selenic.com/show_bug.cgi?id=3470

          Priority: normal
            Bug ID: 3470
                CC: mercurial-devel&amp;lt; at &amp;gt;selenic.com
          Assignee: bugzilla&amp;lt; at &amp;gt;selenic.com
           Summary: crash in dispatch.py when trying to report an error
          Severity: bug
    Classification: Unclassified
                OS: All
          Reporter: bos&amp;lt; at &amp;gt;serpentine.com
          Hardware: All
            Status: UNCONFIRMED
           Version: 2.2.1
         Component: Mercurial
           Product: Mercurial

Augie's new "identify third-party extensions as sources of tracebacks" code
prevents Mercurial from printing a traceback.

http://selenic.com/repo/hg/rev/1c9f58a6c8f1

Here's what I get instead:

Traceback (most recent call last):
  File "/home/bryano/hg/hg/hg", line 38, in &amp;lt;module&amp;gt;
    mercurial.dispatch.run()
  File "/home/bryano/hg/hg/mercurial/dispatch.py", line 28, in run
    sys.exit((dispatch(request(sys.argv[1:])) or 0) &amp;amp; 255)
  File "/home/bryano/hg/hg/mercurial/dispatch.py", line 65, in dispatch
    return _runcatch(req)
  File "/home/bryano/hg/hg/mercurial/dispatch.py", line 217, in _runcatch
    ct = tuplever(compare)
  File "/home/bryano/hg/hg/mercurial/dispatch.py", line 255, in tuplever
    return tuple([int(i) for i in v.split('.')])
ValueError: invalid literal for int() with base 10: '8a8ccfeb07ea'

These are the contents of mercurial/__version__.py that I believe are causing
the problem:

# this file is autogenerated by setup.py
version = "8a8ccfeb07ea+20120524"

&lt;/pre&gt;</description>
    <dc:creator>bugzilla-daemon&lt; at &gt;bz.selenic.com</dc:creator>
    <dc:date>2012-05-24T22:24:37</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50553">
    <title>[PATCH 0 of 9 RFC] manage filename normalization policy per repository</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50553</link>
    <description>&lt;pre&gt;this patch series allows users to manage filename normalization policy
per repository

this is just for the base of discussion, and tested a little: clone,
bundle/unbundle, archive, diff, export/import.... simply.

basic concepts of this patch series are:

  (1) management of filename normalization are configured like as EOL
      extension:

      - tracked configuration file ".hgnormfn" chooses type of
        normalization (NFC/NFD/none) for data storing

      - filenames are checked at commit/update/merge and so on as like
        case-folding collision detection, according to the configured
        normalization type

        this can prevent users on Linux/Windows from adding files:

          - normalized in the type other than configured one, or
          - colliding against ones normalized in another type

        # this feature is not yet implemented in my patches

  (2) in storage layer and external representation, filenames are
      normalized in chosen style (= "global style"), for portability

      "storage layer" means:
        - manifest file
        - changelog file
        - path to each filelogs

      "external representation" means:
        - bundle file
        - archive file
        - diff (both "hg diff" and "hg export")


  (3) filenames in the on-memory-objects and the working directory are
      always normalized in appropriate style (= "local style"):

      for example, in NFD on MacOS (if this feature is enabled), and
      NFC(or 'none') on Linux/Windows.

      converting on the border between storage layer/external
      representation and on-memory-objects (manifest, context and so
      on) is done

      HFS+ can treat both NFC/NFD form as same file (and tools on
      MacOS, too), so user can write filenames in NFC for (many) tool
      chain configuration files, if they want to use it each on
      MacOS/Linux/Windows

steps to enable this feature are:

    1. enable "hgext.normfn" extension

    2. create ".hgnormfn" under root of the working directory.
       content of it is:

       [normalize]
       type = nfc

    3. add ".hgnormfn" as tracked file

    4. then, commited files are recorded into history with normalized
       name in NFC even on MacOS

the last patch (adding "debug-normfn.py") of this series helps you to
examine this patch series on other than MacOS environment: you can use
"llug"(lower for local, upper for global) as normalization type, if
you enable "hgext.debug-normfn" extension.
&lt;/pre&gt;</description>
    <dc:creator>FUJIWARA Katsunori</dc:creator>
    <dc:date>2012-05-25T15:00:49</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50548">
    <title>[PATCH RFC] update: skip bookmarked heads when running a bare "hgupdate"</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50548</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Angel Ezquerra &amp;lt;angel.ezquerra&amp;lt; at &amp;gt;gmail.com&amp;gt;
# Date 1337955724 -7200
# Node ID cb06046e10797e569bed05850318068f4a5d535c
# Parent  2ac08d8b21aa7b6e0a062afed5a3f357ccef67f9
update: skip bookmarked heads when running a bare "hg update"

When running a bare "hg update" without specifying a revision, we used to
update to the tip of the current branch, even if it were bookmarked. This is
inconvenient when using bookmarks for feature branches, since pulling new
bookmarks will make "hg update" update to those bookmarked "feature branches".

This patch changes this behavior. "hg update" will look for the tipmost head of
the current branch that is not bookmarked. If none is found the old behavior is
used (i.e. we will update to the tip of the current branch).

This is missing tests and possibly a comment on the update command help.

diff --git a/mercurial/merge.py b/mercurial/merge.py
--- a/mercurial/merge.py
+++ b/mercurial/merge.py
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -527,9 +527,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     try:
         wc = repo[None]
         if node is None:
-            # tip of current branch
+            # tipmost, non bookmarked head of current branch
+            # if all heads on the current branch are bookmarked,
+            # go to the tip of the current branch
             try:
-                node = repo.branchtip(wc.branch())
+                # brancheads returns the branch heads sorted from max to min rev
+                for head in repo.branchheads(wc.branch()):
+                    if repo[head].bookmarks() == []:
+                        node = head
+                        break
+                if node is None:
+                    # all heads are bookmarked, go to the tip of current branch
+                    node = repo.branchtip(wc.branch())                
             except error.RepoLookupError:
                 if wc.branch() == "default": # no default branch!
                     node = repo.lookup("tip") # update to tip
&lt;/pre&gt;</description>
    <dc:creator>Angel Ezquerra</dc:creator>
    <dc:date>2012-05-25T14:25:31</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50546">
    <title>[PATCH] dispatch: tolerate non-standard version strings in tuplever()</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50546</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Adrian Buehlmann &amp;lt;adrian&amp;lt; at &amp;gt;cadifra.com&amp;gt;
# Date 1337948647 -7200
# Node ID c516ea214b28d738e1c6b8010b8d4202c208b572
# Parent  5d64306f39bb1f7ceab8d482156cd071d75f4d17
dispatch: tolerate non-standard version strings in tuplever()

When developing, we may see non-standard version strings of the form

  5d64306f39bb+20120525

which caused tuplever() to raise

  ValueError: invalid literal for int() with base 10: '5d64306f39bb'

and shadowing the real traceback.

diff --git a/mercurial/dispatch.py b/mercurial/dispatch.py
--- a/mercurial/dispatch.py
+++ b/mercurial/dispatch.py
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -252,8 +252,10 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     return -1
 
 def tuplever(v):
-    return tuple([int(i) for i in v.split('.')])
-
+    try:
+        return tuple([int(i) for i in v.split('.')])
+    except ValueError:
+        return tuple()
 
 def aliasargs(fn, givenargs):
     args = getattr(fn, 'args', [])
&lt;/pre&gt;</description>
    <dc:creator>Adrian Buehlmann</dc:creator>
    <dc:date>2012-05-25T12:32:10</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50544">
    <title>mercurial/crew&lt; at &gt;16782: 4 outgoing changesets</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50544</link>
    <description>&lt;pre&gt;4 outgoing changesets in mercurial/crew:

http://hg.intevation.org/mercurial/crew/rev/e9ae770eff1c
changeset:   16782:e9ae770eff1c
tag:         tip
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 21:34:29 2012 +0200
summary:     merge: show renamed on one and deleted on the other side in debug output

http://hg.intevation.org/mercurial/crew/rev/98687cdddcb1
changeset:   16781:98687cdddcb1
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 20:50:16 2012 +0200
summary:     merge: warn about file deleted in one branch and renamed in other (issue3074)

http://hg.intevation.org/mercurial/crew/rev/9cbc44a6600e
changeset:   16780:9cbc44a6600e
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 17:33:19 2012 +0200
summary:     tests: do not create repos inside repos in test-rename-merge1.t

http://hg.intevation.org/mercurial/crew/rev/ad394c897b16
changeset:   16779:ad394c897b16
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 17:25:48 2012 +0200
summary:     merge: do not warn about copy and rename in the same transaction (issue2113)

&lt;/pre&gt;</description>
    <dc:creator>Mercurial Commits</dc:creator>
    <dc:date>2012-05-25T11:00:06</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50540">
    <title>Build &amp; Infrastructure Programmer with Mercurial Experience?</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50540</link>
    <description>&lt;pre&gt;Hello,

I would like to announce that Unity is searching for a Build &amp;amp;
Infrastructure Programer to work preferably out of our Copenhagen office
(though we might be willing to consider someone remotely).  Mercurial
experience, good Python skills, and experience working on open-source
projects is a big bonus.

Please see the job description below and ping me offline if you are
interested.

Thanks,
Na'Tosha

&lt;/pre&gt;</description>
    <dc:creator>Na'Tosha Bard</dc:creator>
    <dc:date>2012-05-25T08:35:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50531">
    <title>[PATCH 0 of 4 RFC] RFC: safe pattern matching for problematic encoding</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50531</link>
    <description>&lt;pre&gt;this patch series achieves safe pattern matching for problematic encoding.

this series is posted for just as the base of discussion: not well
tested yet.
&lt;/pre&gt;</description>
    <dc:creator>FUJIWARA Katsunori</dc:creator>
    <dc:date>2012-05-24T17:04:24</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50523">
    <title>[Bug 3469] New: Fix for bug 2653 broke ability to map svn trunk tobranch other than 'default'</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50523</link>
    <description>&lt;pre&gt;http://bz.selenic.com/show_bug.cgi?id=3469

          Priority: normal
            Bug ID: 3469
                CC: mercurial-devel&amp;lt; at &amp;gt;selenic.com
          Assignee: bugzilla&amp;lt; at &amp;gt;selenic.com
           Summary: Fix for bug 2653 broke ability to map svn trunk to
                    branch other than 'default'
          Severity: feature
    Classification: Unclassified
                OS: Other
          Reporter: lstewart&amp;lt; at &amp;gt;room52.net
          Hardware: PC
            Status: UNCONFIRMED
           Version: 2.2.1
         Component: convert
           Product: Mercurial

I use Mercurial to mirror the FreeBSD Subversion repository for local FreeBSD
development purposes. FreeBSD's trunk branch is named "head", and the convert
extension post bugfix 2653 now forces commits on the "head" branch to be mapped
to the "default" branch in the Mercurial repository. For my use case, the new
behaviour is a regression in functionality.

I realise it is more "Mercurial-y" to use "default" as the equivalent branch
name for trunk, but I would prefer to keep the branch names the same between
svn and hg in this instance.

I propose to leave the default behaviour of the convert extension as is post
bugfix 2653, but allow the branchmap file to be used to override the default
behaviour and map the svn trunk name to a hg branch name other than "default"
e.g. by placing the line "head head" in the branchmap file, the convert
extension should preserve the trunk branch name of "head" in the svn repo as
"head" in the converted hg repo.

&lt;/pre&gt;</description>
    <dc:creator>bugzilla-daemon&lt; at &gt;bz.selenic.com</dc:creator>
    <dc:date>2012-05-24T07:45:01</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50522">
    <title>[PATCH] localrepo: Add locking to _branchtags around _writebrancache</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50522</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Joshua Redstone &amp;lt;joshua.redstone&amp;lt; at &amp;gt;fb.com&amp;gt;
# Date 1336812429 25200
# Node ID b3bb1d7360c481b847431fc0d264111b1d93f993
# Parent  2ac08d8b21aa7b6e0a062afed5a3f357ccef67f9
localrepo:  Add locking to _branchtags around _writebrancache

Read code paths such as via localrepo.branchmap() may end up calling
_writebranchcache without having acquire a repo lock, potentially leading to
races with other repo mutations.  This fix acquires the repo lock if not yet
held before calling _writebranchcache.

diff -r 2ac08d8b21aa -r b3bb1d7360c4 mercurial/localrepo.py
--- a/mercurial/localrepo.pyTue May 22 14:37:20 2012 -0500
+++ b/mercurial/localrepo.pySat May 12 01:47:09 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -481,8 +481,18 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         if lrev != tiprev:
             ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
             self._updatebranchcache(partial, ctxgen)
-            self._writebranchcache(partial, self.changelog.tip(), tiprev)
-
+            # Read code paths (e.g., from branchmap()) do not have the lock
+            # yet.  Lock acquisition may fail if we do not have write-access
+            # to the directory.
+            try:
+                wlock = self.wlock(wait=False)
+                try:
+                    self._writebranchcache(partial, self.changelog.tip(),
+                                           tiprev)
+                finally:
+                    wlock.release()
+            except error.LockError:
+                pass
         return partial
 
     def updatebranchcache(self):
diff -r 2ac08d8b21aa -r b3bb1d7360c4 mercurial/statichttprepo.py
--- a/mercurial/statichttprepo.pyTue May 22 14:37:20 2012 -0500
+++ b/mercurial/statichttprepo.pySat May 12 01:47:09 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -133,6 +133,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     def lock(self, wait=True):
         raise util.Abort(_('cannot lock static-http repository'))
 
+    def wlock(self, wait=True):
+        raise error.LockError(0, "statichttprepository",
+                              "statichttprepository does not support locking",
+                              "statichttprepository")
+
 def instance(ui, path, create):
     if create:
         raise util.Abort(_('cannot create new static-http repository'))
diff -r 2ac08d8b21aa -r b3bb1d7360c4 tests/test-bheads.t
--- a/tests/test-bheads.tTue May 22 14:37:20 2012 -0500
+++ b/tests/test-bheads.tSat May 12 01:47:09 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -31,6 +31,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
 =======
 
+Not being able to update the branchheads cache should not make read ops fail
+  $ echo "junk" &amp;gt; $TESTTMP/a/.hg/cache/branchheads
+  $ chmod -R u-w $TESTTMP/a/.hg
+  $ heads
+  1: Adding a branch (a)
+  0: Adding root node ()
+  $ chmod -R u+w $TESTTMP/a/.hg
+
   $ hg update -C 0
   0 files updated, 0 files merged, 1 files removed, 0 files unresolved
   $ echo 'b' &amp;gt;b
&lt;/pre&gt;</description>
    <dc:creator>Joshua Redstone</dc:creator>
    <dc:date>2012-05-24T14:50:53</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50517">
    <title>[PATCH] revset: cache alias expansions</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50517</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Patrick Mezard &amp;lt;patrick&amp;lt; at &amp;gt;mezard.eu&amp;gt;
# Date 1337857506 -7200
# Node ID f5171e8248a20b23f0404a6f41c1c88390060e60
# Parent  2ac08d8b21aa7b6e0a062afed5a3f357ccef67f9
revset: cache alias expansions

Caching has no performance effect on the revset aliases which triggered
the recent recursive evaluation bug. I wrote it not to feel bad about
expanding several times the same complicated expression.

diff --git a/mercurial/revset.py b/mercurial/revset.py
--- a/mercurial/revset.py
+++ b/mercurial/revset.py
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1387,7 +1387,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         return args[arg]
     return tuple(_expandargs(t, args) for t in tree)
 
-def _expandaliases(aliases, tree, expanding):
+def _expandaliases(aliases, tree, expanding, cache):
     """Expand aliases in tree, recursively.
 
     'aliases' is a dictionary mapping user defined aliases to
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1402,17 +1402,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
             raise error.ParseError(_('infinite expansion of revset alias "%s" '
                                      'detected') % alias.name)
         expanding.append(alias)
-        result = _expandaliases(aliases, alias.replacement, expanding)
+        if alias.name not in cache:
+            cache[alias.name] = _expandaliases(aliases, alias.replacement,
+                                               expanding, cache)
+        result = cache[alias.name]
         expanding.pop()
         if alias.args is not None:
             l = getlist(tree[2])
             if len(l) != len(alias.args):
                 raise error.ParseError(
                     _('invalid number of arguments: %s') % len(l))
-            l = [_expandaliases(aliases, a, []) for a in l]
+            l = [_expandaliases(aliases, a, [], cache) for a in l]
             result = _expandargs(result, dict(zip(alias.args, l)))
     else:
-        result = tuple(_expandaliases(aliases, t, expanding)
+        result = tuple(_expandaliases(aliases, t, expanding, cache)
                        for t in tree)
     return result
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1422,7 +1425,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     for k, v in ui.configitems('revsetalias'):
         alias = revsetalias(k, v)
         aliases[alias.name] = alias
-    return _expandaliases(aliases, tree, [])
+    return _expandaliases(aliases, tree, [], {})
 
 parse = parser.parser(tokenize, elements).parse
 
&lt;/pre&gt;</description>
    <dc:creator>Patrick Mezard</dc:creator>
    <dc:date>2012-05-24T11:49:49</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50515">
    <title>mercurial/crew&lt; at &gt;16782: 4 outgoing changesets</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50515</link>
    <description>&lt;pre&gt;4 outgoing changesets in mercurial/crew:

http://hg.intevation.org/mercurial/crew/rev/e9ae770eff1c
changeset:   16782:e9ae770eff1c
tag:         tip
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 21:34:29 2012 +0200
summary:     merge: show renamed on one and deleted on the other side in debug output

http://hg.intevation.org/mercurial/crew/rev/98687cdddcb1
changeset:   16781:98687cdddcb1
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 20:50:16 2012 +0200
summary:     merge: warn about file deleted in one branch and renamed in other (issue3074)

http://hg.intevation.org/mercurial/crew/rev/9cbc44a6600e
changeset:   16780:9cbc44a6600e
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 17:33:19 2012 +0200
summary:     tests: do not create repos inside repos in test-rename-merge1.t

http://hg.intevation.org/mercurial/crew/rev/ad394c897b16
changeset:   16779:ad394c897b16
user:        Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;
date:        Wed May 23 17:25:48 2012 +0200
summary:     merge: do not warn about copy and rename in the same transaction (issue2113)

&lt;/pre&gt;</description>
    <dc:creator>Mercurial Commits</dc:creator>
    <dc:date>2012-05-24T11:00:05</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50514">
    <title>[PATCH] base85: use Py_ssize_t for string lengths</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50514</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Adrian Buehlmann &amp;lt;adrian&amp;lt; at &amp;gt;cadifra.com&amp;gt;
# Date 1337815812 -7200
# Node ID e7a3700ed766935900bda57eb9bfa8cc4ca36381
# Parent  2ac08d8b21aa7b6e0a062afed5a3f357ccef67f9
base85: use Py_ssize_t for string lengths

diff --git a/mercurial/base85.c b/mercurial/base85.c
--- a/mercurial/base85.c
+++ b/mercurial/base85.c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -9,6 +9,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
  Largely based on git's implementation
 */
 
+#define PY_SSIZE_T_CLEAN
 #include &amp;lt;Python.h&amp;gt;
 
 #include "util.h"
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -33,7 +34,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 const unsigned char *text;
 PyObject *out;
 char *dst;
-int len, olen, i;
+Py_ssize_t len, olen, i;
 unsigned int acc, val, ch;
 int pad = 0;
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -81,7 +82,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 PyObject *out;
 const char *text;
 char *dst;
-int len, i, j, olen, c, cap;
+Py_ssize_t len, i, j, olen, cap;
+int c;
 unsigned int acc;
 
 if (!PyArg_ParseTuple(args, "s#", &amp;amp;text, &amp;amp;len))
&lt;/pre&gt;</description>
    <dc:creator>Adrian Buehlmann</dc:creator>
    <dc:date>2012-05-24T10:04:21</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50510">
    <title>strip v4 patch</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50510</link>
    <description>&lt;pre&gt;Hi Matt,
I just updated the patch I sent yesterday - I thought of another corner 
case I wasn't handling - that if the set of branches that have nodes 
stripped and the set of branches of their parents are not the same, 
though both are of size 1.  I also added an additional test case to 
exercise that scenario.

&lt;/pre&gt;</description>
    <dc:creator>Joshua Redstone</dc:creator>
    <dc:date>2012-05-23T21:18:27</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50509">
    <title>[PATCH v4] strip: incrementally update the branchheads cache after astrip</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50509</link>
    <description>&lt;pre&gt;# HG changeset patch
# User Joshua Redstone &amp;lt;joshua.redstone&amp;lt; at &amp;gt;fb.com&amp;gt;
# Date 1337370347 25200
# Node ID cb504dab484a34f21656fc594f0a58f65a653a23
# Parent  d0b9ebba41e9a1733294d5fa1b497ada5eda93c8
strip: incrementally update the branchheads cache after a strip

This function augments strip to incrementally update the branchheads cache
rather than recompute it from scratch.  This speeds up the performance of strip
and rebase on repos with long history.  The performance optimization only
happens if the revisions stripped are all on the same branch and the parents of
the stripped revisions are also on that same branch.

This also fixes a small performance bug in localrepo._updatebranchcache.  That
function would iterate over new candidate heads in order from oldest to newest,
in contrast to the comment that observes that iterating from newest to oldest
results in fewer pases over the set of reachable nodes.

This adds a few test cases, particularly one that reproduces the extra heads
that mpm observed.

diff -r d0b9ebba41e9 -r cb504dab484a hgext/mq.py
--- a/hgext/mq.pySun May 20 14:40:36 2012 -0500
+++ b/hgext/mq.pyFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3449,7 +3449,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
             if start &amp;lt; qbase:
                 # update the cache (excluding the patches) and save it
                 ctxgen = (self[r] for r in xrange(lrev + 1, qbase))
-                self._updatebranchcache(partial, ctxgen)
+                self._updatebranchcache(partial, ctxgen, ctxisnew=True)
                 self._writebranchcache(partial, cl.node(qbase - 1), qbase - 1)
                 start = qbase
             # if start = qbase, the cache is as updated as it should be.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -3458,7 +3458,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
 
             # update the cache up to the tip
             ctxgen = (self[r] for r in xrange(start, len(cl)))
-            self._updatebranchcache(partial, ctxgen)
+            self._updatebranchcache(partial, ctxgen, ctxisnew=True)
 
             return partial
 
diff -r d0b9ebba41e9 -r cb504dab484a mercurial/discovery.py
--- a/mercurial/discovery.pySun May 20 14:40:36 2012 -0500
+++ b/mercurial/discovery.pyFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -201,7 +201,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         # 4. Update newmap with outgoing changes.
         # This will possibly add new heads and remove existing ones.
         ctxgen = (repo[n] for n in outgoing.missing)
-        repo._updatebranchcache(newmap, ctxgen)
+        repo._updatebranchcache(newmap, ctxgen, ctxisnew=True)
 
     else:
         # 1-4b. old servers: Check for new topological heads.
diff -r d0b9ebba41e9 -r cb504dab484a mercurial/localrepo.py
--- a/mercurial/localrepo.pySun May 20 14:40:36 2012 -0500
+++ b/mercurial/localrepo.pyFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -480,7 +480,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         tiprev = len(self) - 1
         if lrev != tiprev:
             ctxgen = (self[r] for r in xrange(lrev + 1, tiprev + 1))
-            self._updatebranchcache(partial, ctxgen)
+            self._updatebranchcache(partial, ctxgen, ctxisnew=True)
             self._writebranchcache(partial, self.changelog.tip(), tiprev)
 
         return partial
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -550,6 +550,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                     continue
                 node, label = l.split(" ", 1)
                 label = encoding.tolocal(label.strip())
+                if not node in self:
+                    raise ValueError('invalidating branch cache because node '+
+                                     '%s does not exist' % node)
                 partial.setdefault(label, []).append(bin(node))
         except KeyboardInterrupt:
             raise
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -570,7 +573,14 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         except (IOError, OSError):
             pass
 
-    def _updatebranchcache(self, partial, ctxgen):
+    def _updatebranchcache(self, partial, ctxgen, ctxisnew):
+        """Given a branchhead cache, partial, that may have extra nodes or be
+        missing heads, and a generator of nodes that are at least a superset of
+        heads missing, this function updates partial to be correct.
+
+        ctxisnew is a bool specifying whether the nodes produced by ctxgen are
+        guaranteed to not be ancestors of any existing heads.
+        """
         # collect new branch entries
         newbranches = {}
         for c in ctxgen:
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -581,21 +591,55 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
         for branch, newnodes in newbranches.iteritems():
             bheads = partial.setdefault(branch, [])
             bheads.extend(newnodes)
-            if len(bheads) &amp;lt;= 1:
-                continue
-            bheads = sorted(bheads, key=lambda x: self[x].rev())
-            # starting from tip means fewer passes over reachable
-            while newnodes:
-                latest = newnodes.pop()
-                if latest not in bheads:
-                    continue
-                minbhnode = self[bheads[0]].node()
-                reachable = self.changelog.reachable(latest, minbhnode)
-                reachable.remove(latest)
-                if reachable:
-                    bheads = [b for b in bheads if b not in reachable]
+            # Remove duplicates - nodes that are in newnodes and are already in
+            # bheads.  This can happen if you strip a node whose parent was
+            # already a head (because they're on different branches).
+            bheads = set(bheads)
+
+            # Remove candidate heads that no longer are in the repo (e.g., as
+            # the result of a strip that just happened).  Avoid using 'bhead in
+            # self' here because that dives down into branchcache code somewhat
+            # recrusively.
+            bheads = [bhead for bhead in bheads \
+                          if self.changelog.hasnode(bhead)]
+            if len(bheads) &amp;gt; 1:
+                bheads = sorted(bheads, key=lambda x: self[x].rev())
+                # starting from tip means fewer passes over reachable.
+                #
+                # If we know the new candidates are not ancestors of existing
+                # heads, we don't have to examine ancestors of existing heads
+                if ctxisnew:
+                    iternodes = sorted(newnodes, key=lambda x: self[x].rev(),
+                                       reverse=True)
+                else:
+                    iternodes = sorted(bheads, key=lambda x: self[x].rev(),
+                                       reverse=True)
+
+                # This loop prunes out two kinds of heads - heads that are
+                # superceded by a head in newnodes, and newnodes that are not
+                # heads because an existing head is their descendant.
+                while iternodes:
+                    latest = iternodes.pop()
+                    if latest not in bheads:
+                        continue
+                    minbhnode = self[bheads[0]].node()
+                    reachable = self.changelog.reachable(latest, minbhnode)
+                    reachable.remove(latest)
+                    if reachable:
+                        bheads = [b for b in bheads if b not in reachable]
             partial[branch] = bheads
 
+        # There may be branches that cease to exist when the last commit in the
+        # branch was stripped.  This code filters them out.  Note that the
+        # branch that ceased to exist may not be in newbranches because
+        # newbranches is the set of candidate heads, which when you strip the
+        # last commit in a branch will be the parent branch.
+        for branch in partial.keys():
+            nodes = [head for head in partial[branch] \
+                         if self.changelog.hasnode(head)]
+            if len(nodes) &amp;lt; 1:
+                del partial[branch]
+
     def lookup(self, key):
         return self[key].node()
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -858,6 +902,9 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
             else:
                 ui.status(_('working directory now based on '
                             'revision %d\n') % parents)
+        # TODO: if we know which new heads may result from this rollback, pass
+        # them to destroy(), which will prevent the branchhead cache from being
+        # invalidated.
         self.destroyed()
         return 0
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -1301,12 +1348,28 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                 tr.release()
             lock.release()
 
-    def destroyed(self):
+    def destroyed(self, newheadrevs=None):
         '''Inform the repository that nodes have been destroyed.
         Intended for use by strip and rollback, so there's a common
-        place for anything that has to be done after destroying history.'''
-        # XXX it might be nice if we could take the list of destroyed
-        # nodes, but I don't see an easy way for rollback() to do that
+        place for anything that has to be done after destroying history.
+
+        If you know the branchheadcache was uptodate before nodes were removed
+        and you also know the set of candidate new heads that may have resulted
+        from the destruction, you can set newheadrevs.  This will enable the
+        code to update the branchheads cache, rather than having future code
+        decide it's invalid and regenrating it from scratch.
+        '''
+        if newheadrevs:
+            tiprev = len(self) - 1
+            ctxgen = (self[rev] for rev in newheadrevs)
+            self._updatebranchcache(self._branchcache, ctxgen,
+                                    ctxisnew=False)
+            self._writebranchcache(self._branchcache, self.changelog.tip(),
+                                   tiprev)
+        else:
+            # No info to update the cache.  If nodes were destroyed, the cache
+            # is stale and this will be caught the next time it is read.
+            pass
 
         # Ensure the persistent tag cache is updated.  Doing it now
         # means that the tag cache only has to worry about destroyed
diff -r d0b9ebba41e9 -r cb504dab484a mercurial/repair.py
--- a/mercurial/repair.pySun May 20 14:40:36 2012 -0500
+++ b/mercurial/repair.pyFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -56,6 +56,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     return s
 
 def strip(ui, repo, nodelist, backup="all", topic='backup'):
+    # It simplifies the logic around updating the branchheads cache if we only
+    # have to consider the effect of the stripped revisions and not revisions
+    # missing because the cache is out-of-date.
+    repo.updatebranchcache()
+
     cl = repo.changelog
     # TODO handle undo of merge sets
     if isinstance(nodelist, str):
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -63,6 +68,20 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
     striplist = [cl.rev(node) for node in nodelist]
     striprev = min(striplist)
 
+    # Generate set of branches who will have nodes stripped.
+    stringstriplist = [str(rev) for rev in striplist]
+    striprevs = set(repo.revs("%lr::", stringstriplist,
+                                stringstriplist))
+    stripbranches = set([repo[rev].branch() for rev in striprevs])
+
+    # Set of potential new heads resulting from the strip.  The parents of any
+    # node removed could be a new head because the node to be removed could have
+    # been the only child of the parent.
+    # Save as a set to remove duplicates.
+    newheadrevs = set(repo.revs("parents(%lr::) - %lr::", stringstriplist,
+                                stringstriplist))
+    newheadbranches = set([repo[rev].branch() for rev in newheadrevs])
+
     keeppartialbundle = backup == 'strip'
 
     # Some revisions with rev &amp;gt; striprev may not be descendants of striprev.
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -169,4 +188,11 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
                     % chgrpfile)
         raise
 
-    repo.destroyed()
+    if len(stripbranches) == 1 and len(newheadbranches) == 1 \
+            and stripbranches == newheadbranches:
+        repo.destroyed(newheadrevs)
+    else:
+        # Multiple branches involved in strip. Will allow branchcache to become
+        # invalid and later on rebuilt from scratch
+        repo.destroyed()
+
diff -r d0b9ebba41e9 -r cb504dab484a tests/test-mq-caches.t
--- a/tests/test-mq-caches.tSun May 20 14:40:36 2012 -0500
+++ b/tests/test-mq-caches.tFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -36,7 +36,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   $ hg qrefresh -m 'patch 1'
   $ show_branch_cache
   tip: 0
-  No branch cache
+  d986d5caac23a7d44a46efc0ddaf5eb9665844cf 0
+  d986d5caac23a7d44a46efc0ddaf5eb9665844cf default
 
 some regular revisions
 
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -75,8 +76,8 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   $ hg qrefresh -m 'patch 2'
   $ show_branch_cache 1
   tip: 3
-  c229711f16da3d7591f89b1b8d963b79bda22714 1
-  c229711f16da3d7591f89b1b8d963b79bda22714 bar
+  982611f6955f9c48d3365decea203217c945ef0d 2
+  982611f6955f9c48d3365decea203217c945ef0d bar
   dc25e3827021582e979f600811852e36cbe57341 foo
   branch foo: 3
   branch bar: 2
diff -r d0b9ebba41e9 -r cb504dab484a tests/test-rebase-cache.t
--- a/tests/test-rebase-cache.tSun May 20 14:40:36 2012 -0500
+++ b/tests/test-rebase-cache.tFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,6 +2,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   &amp;gt; [extensions]
   &amp;gt; graphlog=
   &amp;gt; rebase=
+  &amp;gt; mq=
   &amp;gt; 
   &amp;gt; [phases]
   &amp;gt; publish=False
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -262,3 +263,75 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   
   $ hg verify -q
 
+Stripping multiple branches in one go bypasses the fast-case code to
+update the branch cache.
+
+  $ hg strip 2
+  0 files updated, 0 files merged, 4 files removed, 0 files unresolved
+  saved backup bundle to $TESTTMP/a3/.hg/strip-backup/*-backup.hg (glob)
+
+  $ hg tglog
+  o  3: 'C' branch2
+  |
+  o  2: 'branch2' branch2
+  |
+  | &amp;lt; at &amp;gt;  1: 'branch1' branch1
+  |/
+  o  0: 'A'
+  
+
+  $ hg branches
+  branch2                        3:e4fdb121d036
+  branch1                        1:63379ac49655
+  default                        0:1994f17a630e (inactive)
+
+  $ hg theads
+  3: 'C' branch2
+  1: 'branch1' branch1
+  0: 'A' 
+
+Fast path branchcache code should not be invoked if branches stripped is not 
+the same as branches remaining.
+
+  $ hg init b
+  $ cd b
+
+  $ hg branch branch1
+  marked working directory as branch branch1
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg ci -m 'branch1'
+
+  $ hg branch branch2
+  marked working directory as branch branch2
+  (branches are permanent and global, did you want a bookmark?)
+  $ hg ci -m 'branch2'
+
+  $ hg branch -f branch1
+  marked working directory as branch branch1
+  (branches are permanent and global, did you want a bookmark?)
+
+  $ echo a &amp;gt; A
+  $ hg ci -Am A
+  adding A
+  created new head
+
+  $ hg tglog
+  &amp;lt; at &amp;gt;  2: 'A' branch1
+  |
+  o  1: 'branch2' branch2
+  |
+  o  0: 'branch1' branch1
+  
+
+  $ hg theads
+  2: 'A' branch1
+  1: 'branch2' branch2
+
+  $ hg strip 2
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  saved backup bundle to $TESTTMP/a3/b/.hg/strip-backup/*-backup.hg (glob)
+
+  $ hg theads
+  1: 'branch2' branch2
+  0: 'branch1' branch1
+
diff -r d0b9ebba41e9 -r cb504dab484a tests/test-rebase-collapse.t
--- a/tests/test-rebase-collapse.tSun May 20 14:40:36 2012 -0500
+++ b/tests/test-rebase-collapse.tFri May 18 12:45:47 2012 -0700
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -2,6 +2,7 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   &amp;gt; [extensions]
   &amp;gt; graphlog=
   &amp;gt; rebase=
+  &amp;gt; mq=
   &amp;gt; 
   &amp;gt; [phases]
   &amp;gt; publish=False
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -260,6 +261,44 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   $ cd ..
 
 
+
+
+Test that branchheads cache is updated correctly when doing a strip in which
+the parent of the ancestor node to be stripped does not become a head and
+also, the parent of a node that is a child of the node stripped becomes a head
+(node 3).
+
+  $ hg clone -q -u . b b2
+  $ cd b2
+
+  $ hg heads --template="{rev}:{node} {branch}\n"
+  7:c65502d4178782309ce0574c5ae6ee9485a9bafa default
+  6:c772a8b2dc17629cec88a19d09c926c4814b12c7 default
+
+  $ cat $TESTTMP/b2/.hg/cache/branchheads
+  c65502d4178782309ce0574c5ae6ee9485a9bafa 7
+  c772a8b2dc17629cec88a19d09c926c4814b12c7 default
+  c65502d4178782309ce0574c5ae6ee9485a9bafa default
+
+  $ hg strip 4
+  saved backup bundle to $TESTTMP/b2/.hg/strip-backup/8a5212ebc852-backup.hg
+
+  $ cat $TESTTMP/b2/.hg/cache/branchheads
+  c65502d4178782309ce0574c5ae6ee9485a9bafa 4
+  2870ad076e541e714f3c2bc32826b5c6a6e5b040 default
+  c65502d4178782309ce0574c5ae6ee9485a9bafa default
+
+  $ hg heads --template="{rev}:{node} {branch}\n"
+  4:c65502d4178782309ce0574c5ae6ee9485a9bafa default
+  3:2870ad076e541e714f3c2bc32826b5c6a6e5b040 default
+
+  $ cd ..
+
+
+
+
+
+
 Create repo c:
 
   $ hg init c
&amp;lt; at &amp;gt;&amp;lt; at &amp;gt; -630,3 +669,56 &amp;lt; at &amp;gt;&amp;lt; at &amp;gt;
   b
   b
   $ cd ..
+
+
+Test stripping a revision with another child
+
+  $ hg init f
+  $ cd f
+
+  $ echo A &amp;gt; A
+  $ hg ci -Am A
+  adding A
+  $ echo B &amp;gt; B
+  $ hg ci -Am B
+  adding B
+
+  $ hg up -q 0
+
+  $ echo C &amp;gt; C
+  $ hg ci -Am C
+  adding C
+  created new head
+
+  $ hg tglog
+  &amp;lt; at &amp;gt;  2: 'C'
+  |
+  | o  1: 'B'
+  |/
+  o  0: 'A'
+  
+
+
+  $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
+  2:c5cefa58fd557f84b72b87f970135984337acbc5 default: C
+  1:27547f69f25460a52fff66ad004e58da7ad3fb56 default: B
+
+  $ hg strip 2
+  0 files updated, 0 files merged, 1 files removed, 0 files unresolved
+  saved backup bundle to $TESTTMP/f/.hg/strip-backup/*-backup.hg (glob)
+
+  $ hg tglog
+  o  1: 'B'
+  |
+  &amp;lt; at &amp;gt;  0: 'A'
+  
+
+
+  $ hg heads --template="{rev}:{node} {branch}: {desc}\n"
+  1:27547f69f25460a52fff66ad004e58da7ad3fb56 default: B
+
+  $ cd ..
+
+
+
+
&lt;/pre&gt;</description>
    <dc:creator>Joshua Redstone</dc:creator>
    <dc:date>2012-05-23T21:15:43</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50504">
    <title>buildbot failure in Mercurial on hg tests</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50504</link>
    <description>&lt;pre&gt;The Buildbot has detected a new failure on builder hg tests while building hg.
Full details are available at:
 http://hgbuildbot.kublai.com/builders/hg%20tests/builds/121

Buildbot URL: http://hgbuildbot.kublai.com/

Buildslave for this Build: l6

Build Reason: scheduler
Build Source Stamp: [branch default] e9ae770eff1c5728eb397e0bd413af6b93e78a5f
Blamelist: Thomas Arendsen Hein &amp;lt;thomas&amp;lt; at &amp;gt;intevation.de&amp;gt;

BUILD FAILED: failed run-tests.py (python2.6)

sincerely,
 -The Buildbot



&lt;/pre&gt;</description>
    <dc:creator>hgbuildbot&lt; at &gt;kublai.com</dc:creator>
    <dc:date>2012-05-23T20:58:16</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50494">
    <title>[Bug 3468] New: shell alias: not possible to honor -R</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50494</link>
    <description>&lt;pre&gt;http://bz.selenic.com/show_bug.cgi?id=3468

          Priority: normal
            Bug ID: 3468
                CC: mercurial-devel&amp;lt; at &amp;gt;selenic.com
          Assignee: bugzilla&amp;lt; at &amp;gt;selenic.com
           Summary: shell alias: not possible to honor -R
          Severity: bug
    Classification: Unclassified
                OS: Linux
          Reporter: patrickdepinguin+mercurial&amp;lt; at &amp;gt;gmail.com
          Hardware: PC
            Status: UNCONFIRMED
           Version: earlier
         Component: Mercurial
           Product: Mercurial

In shell aliases you can use $HG to refer to the hg binary, and $HG_ARGS to
refer to the options given to the alias command.

However, when you run an alias with -R, as in:
hg myalias -R somerepo
there is no way for the alias to know about 'somerepo', because it is neither
in $HG nor in $HG_ARGS.

This is troublesome for aliases that wrap around existing Mercurial commands,
like:

deliverylog = !args=`echo $HG_ARGS | cut -s -d' '  -f2-`; 
            cmd="$HG log --rev 'sort( user(\"Official delivery\") and branch(.)
, -date)' --limit 1 $args";
            echo "$cmd";
            eval $cmd

If you run this alias with '-R somerepo', the hg log will not be executed in
somerepo (although this is what I'd expect).

This is not exactly the same problem as in related bugs:
1599 hgext/alias: -R and --cwd options dont work with alias extension RESOLVED
WONTFIX
2306 -R/-cwd support in aliases CONF

&lt;/pre&gt;</description>
    <dc:creator>bugzilla-daemon&lt; at &gt;bz.selenic.com</dc:creator>
    <dc:date>2012-05-23T07:38:27</dc:date>
  </item>
  <item rdf:about="http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50484">
    <title>RFC: safe pattern matching for problematic encoding</title>
    <link>http://comments.gmane.org/gmane.comp.version-control.mercurial.devel/50484</link>
    <description>&lt;pre&gt;Hi, devels.

I'm working to achieve safe pattern matching/parsing for problematic
encodings (e.g.: cp932), in which strings may contain '\\' as a part
of multi-byte characters.

I finished to write draft version patch series to do it, but it
requires changes as below:

  (1) add hooks to replace '\' in mbcs by '\x5c' before:

      - re.compile() invocation from:
        - grep() in command.py
        - grep() in fileset.py
        - grep() in revset.py

      - re.escape() invocation from:
        -  _globre(), _regex() in match.py
        - remap() in subrepo.py

      - re.sub() invocation from remap() in subrepo.py

    re.compile()/escape()/sub() are invoked from many other places,
    so they can not be wrapped directly.


  (2) wrap tokenizer for parser._iter in parser.py to:

      - convert mbcs to unicode to avoid unexpected escaping by '\' in mbcs
      - convert token from unicode to local encoding, and
      - adjust parsed length in unicode to one in local encoding
        (mismatching of parsed length causes exception)


  (3) add hooks to execute 'string-escape' safely:

      - for "r'xxx'" style by tokenize() in fileset.py, revset.py,
      - for "r'xxx'" style by tokenizer() in templater.py

    'string-escape' can't be applied on unicode, but sometimes it is
    needed, because above wrapping/hooking convert target object to
    unicode object.

As you noticed, wrapping/hooking points are scattered in widely, so I
think that this implementation is not so good. But I don't have any
other ideas.

Are there any other ideas to solve this problem ? or should I post
this patches, even though it is not so good, as a first step ?


BTW, how is "using Unicode API on Windows" plan progressing ?

  http://www.selenic.com/pipermail/mercurial-devel/2011-December/036385.html

If this is implemented, people who uses problematic encoding can solve
this problem by using utf-8 encoding instead of local problematic
encoding.

# of course, encoding exchange between utf-8 and local encoding should
# be done on UI boundary for interaction with other programs (e.g.:
# dos prompt window), even though mercurial itself can use utf-8
# internally.

So, I will do whatever is in my power to progress this changes !

# checking sources, testing in problematic encoding env, and so on

----------------------------------------------------------------------
[FUJIWARA Katsunori]                             foozy&amp;lt; at &amp;gt;lares.dti.ne.jp
&lt;/pre&gt;</description>
    <dc:creator>FUJIWARA Katsunori</dc:creator>
    <dc:date>2012-05-23T12:38:52</dc:date>
  </item>
  <textinput rdf:about="http://search.gmane.org/?group=$group=gmane.comp.version-control.mercurial.devel">
    <title>Search Engine</title>
    <description>Search the mailing list at Gmane</description>
    <name>query</name>
    <link>http://search.gmane.org/?group=$group=gmane.comp.version-control.mercurial.devel</link>
  </textinput>
</rdf:RDF>

