[PATCH 4 of 4 RFC path options] ui: add a "pushnames" path option

Ryan McElroy rm at fb.com
Sat Mar 14 02:38:55 CDT 2015


On 3/3/2015 11:39 AM, Augie Fackler wrote:
> On Sun, Mar 01, 2015 at 03:23:48PM -0800, Gregory Szorc wrote:
>> # HG changeset patch
>> # User Gregory Szorc <gregory.szorc at gmail.com>
>> # Date 1423550715 28800
>> #      Mon Feb 09 22:45:15 2015 -0800
>> # Node ID 96836adc7bfd1a1b41befc2cbbcc135fc35b7948
>> # Parent  4da24a2a9e7b82e5cd0082e4d69255c0cd5b805b
>> ui: add a "pushnames" path option
> I think I'm +0 on this in principle, but we should probably coordinate
> between this and the workflow ideas smf and Ryan have around
> remotenames. I haven't done enough thinking to have strong convictions yet.

Gregory, have you played around with the latest remotenames extension? 
There's this interesting/controversial/etc "feature" called tracking, 
inspired by git, where a bookmark can "track" another name (usually a 
remote bookmark, but could also be local, or other names exposed via the 
namespace API), so that a few commands just "do the right thing" when 
called without parameters:

"hg rebase" rebases with an implicit "--dest <tracking name>"
"hg push" pushes with an implicit "dest" path and updates an implicit 
"--to" bookmark

Today, while chatting with smf, I realized we can go one step further 
and allow the push tracking to be different from the rebase tracking. 
This idea was inspired by the workflow Sean and I have adopted:

sean's laptop ---(push)---> smf.io ---(pull)--> ryan's devserver 
---(push)---> "nexus" (hg.silverfir.net) ---(pull)---> sean's laptop ...

In this world, on my devserver, I want to rebase onto the changes from 
smf.io's @ bookmark, but I want to push to nexus and the @ bookmark 
there. If we have two tracking targets, we can do this. I'm not 
convinced this is a good idea yet, since it seems too complicated, but 
we're in exploratory mode here so I might implement this at some point.

Anyway, back to this patch: I think it's useful -- it's essentially 
moving command-line options into config to avoid repeated typing and 
potential mistakes, which makes me think this is good, but it also isn't 
a fundamentally different workflow, like remotenames is attempting to 
unlock (eg the --to flag on push allows pushing to a remote bookmark 
without the same bookmark -- or any bookmark for that matter -- being 
present in the local repo for that rev).

I'd call it 'pushbookmark' and restrict to to the equivalent of passing 
-B <name> to hg push. The other stuff can come later when it becomes 
more clear what direction we want to go.

>
>> "pushrevset" will not push bookmarks because revsets expand to
>> revisions, even if bookmarks are queried for. So, we need an
>> additional mechanism to specify names to push.
>>
>> We introduce the "pushnames" path option for this purpose.
>>
>> The intent of this option is to resolve all names. This includes
>> bookmarks, branches, and any other namespaces that may be installed
>> through extensions. However, supporting all names is rather
>> difficult, so support hasn't yet been added for things that aren't
>> bookmarks. See "hg.addbranchrevs" for an example of the complexity
>> this involves.
>>
>> Given that bookmarks (and other names for that matter) are special,
>> it might be worth abandoning a generic API and going for name-specific
>> options. This would map to command line argument usage (-B, --branch).
>>
>> Another thought that came up when implementing this patch is that it
>> might be worth creating a unified "what to push" API that takes
>> a "path", a remote, and a set of options and returns a data structure
>> describing what to push. This is because the logic for figuring this
>> out is somewhat complicated and it might warrant living in a
>> more core API, such as exchange.push. But I'm hard pressed to name
>> any benefits besides the ability to make this code unit testable,
>> as I don't think there are other code paths that require knowledge
>> on how to resolve what to push. Then again, once this API exists,
>> perhaps extensions will invent a need for it.
>>
>> diff --git a/mercurial/commands.py b/mercurial/commands.py
>> --- a/mercurial/commands.py
>> +++ b/mercurial/commands.py
>> @@ -5071,8 +5071,20 @@ def push(ui, repo, dest=None, **opts):
>>       URLs. If DESTINATION is omitted, a default path will be used.
>>
>>       Returns 0 if push was successful, 1 if nothing to push.
>>       """
>> +    allowpathrevs = not opts.get('bookmark') and not opts.get('rev') \
>> +                    and not opts.get('branch')
>> +
>> +    path = ui.paths.getpath(dest, default='push', require=True)
>> +
>> +    if path.pushnames and allowpathrevs:
>> +        for name in path.pushnames:
>> +            if name in repo._bookmarks:
>> +                opts.setdefault('bookmark', []).append(name)
>> +            else:
>> +                raise util.Abort('non-bookmarks not currently supported '
>> +                                 'by pushnames path option')
>>
>>       if opts.get('bookmark'):
>>           ui.setconfig('bookmarks', 'pushing', opts['bookmark'], 'push')
>>           for b in opts['bookmark']:
>> @@ -5083,9 +5095,8 @@ def push(ui, repo, dest=None, **opts):
>>                   # if we try to push a deleted bookmark, translate it to null
>>                   # this lets simultaneous -r, -b options continue working
>>                   opts.setdefault('rev', []).append("null")
>>
>> -    path = ui.paths.getpath(dest, default='push', require=True)
>>       url = path.pushurl
>>       branches = [path.rev, opts.get('branch', [])]
>>       ui.status(_('pushing to %s\n') % util.hidepassword(url))
>>       revs, checkout = hg.addbranchrevs(repo, repo, branches, opts.get('rev'))
>> diff --git a/mercurial/help/config.txt b/mercurial/help/config.txt
>> --- a/mercurial/help/config.txt
>> +++ b/mercurial/help/config.txt
>> @@ -1115,9 +1115,23 @@ The following per-path options are recog
>>       working copy is based upon.
>>
>>       Note: Bookmarks will not be pushed if this option is set, even if the
>>       revset specifies bookmarks to push. This is because revsets evaluate
>> -    to changesets, not names.
>> +    to changesets, not names. To push a set of bookmarks by default, use
>> +    ``pushnames``.
>> +
>> +    This option is mutually exclusive with ``pushnames``.
>> +
>> +``pushnames``
>> +    A list of comma or space delimited names to push to this path by default.
>> +
>> +    This option is similar to ``pushrevset`` except it operates on names,
>> +    not revisions.
>> +
>> +    This option is mutually exclusive with ``pushrevset``.
>> +
>> +    Note: Bookmarks are names. Use this option to specify which bookmarks
>> +    to push by default.
>>
>>   ``phases``
>>   ----------
>>
>> diff --git a/mercurial/ui.py b/mercurial/ui.py
>> --- a/mercurial/ui.py
>> +++ b/mercurial/ui.py
>> @@ -960,9 +960,10 @@ class paths(object):
>>                   continue
>>
>>               yield path(name, url=loc,
>>                          pushurl=ui.config('paths', '%s.pushurl' % name),
>> -                       pushrevset=ui.config('paths', '%s.pushrevset' % name))
>> +                       pushrevset=ui.config('paths', '%s.pushrevset' % name),
>> +                       pushnames=ui.configlist('paths', '%s.pushnames' % name))
>>
>>       def __getitem__(self, key):
>>           for path in self:
>>               if path.name == key:
>> @@ -1024,9 +1025,9 @@ class paths(object):
>>   class path(object):
>>       """Represents an individual path and its configuration."""
>>
>>       def __init__(self, name, url=None, local=None, pushurl=None,
>> -                 pushrevset=None):
>> +                 pushrevset=None, pushnames=None):
>>           """Construct a path from its config options.
>>
>>           The primary URL for the path is defined as either a URL via ``url``
>>           (preferred) or from a local, relative filesystem path (``local``).
>> @@ -1048,5 +1049,11 @@ class path(object):
>>               raise util.Abort(_('pushurl may not have #revision fragment: %s') %
>>                                  pushurl)
>>
>>           self.pushurl = pushurl or url
>> +
>> +        if pushrevset and pushnames:
>> +            raise util.Abort(_('only 1 of pushrevset and pushnames may be '
>> +                               'defined on path: %s') % name)
>> +
>>           self.pushrevset = pushrevset
>> +        self.pushnames = pushnames
>> diff --git a/tests/test-push-path-config.t b/tests/test-push-path-config.t
>> --- a/tests/test-push-path-config.t
>> +++ b/tests/test-push-path-config.t
>> @@ -131,4 +131,60 @@ A pushrevset with multiple branches conf
>>     remote: adding changesets
>>     remote: adding manifests
>>     remote: adding file changes
>>     remote: added 2 changesets with 2 changes to 1 files
>> +
>> +pushrevset and pushnames are mutually exclusive
>> +
>> +  $ hg --config paths.pushrevset1.pushnames=foo push pushrevset1
>> +  abort: only 1 of pushrevset and pushnames may be defined on path: pushrevset1
>> +  [255]
>> +
>> +adding bookmarks to pushnames will push bookmarks
>> +
>> +  $ cat >> .hg/hgrc << EOF
>> +  > pushbookmark = ssh://user@dummy/$TESTTMP/server
>> +  > pushbookmark.pushnames = bookmark1
>> +  > EOF
>> +
>> +  $ hg -q up -r 0
>> +  $ echo bm1_1 > foo
>> +  $ hg commit -m 'bookmark 1 commit 1'
>> +  created new head
>> +  $ echo bm1_2 > foo
>> +  $ hg commit -m 'bookmark 1 commit 2'
>> +  $ hg bookmark -r ce2028409ac8 bookmark1
>> +  $ hg -q up -r 0
>> +  $ echo bm2 > foo
>> +  $ hg commit -m 'bookmark 2'
>> +  created new head
>> +  $ hg bookmark bookmark2
>> +
>> +  $ hg push pushbookmark
>> +  pushing to ssh://user@dummy/$TESTTMP/server
>> +  searching for changes
>> +  remote: adding changesets
>> +  remote: adding manifests
>> +  remote: adding file changes
>> +  remote: added 1 changesets with 1 changes to 1 files (+1 heads)
>> +  exporting bookmark bookmark1
>> +
>> +Specifying -B overrides pushnames
>> +
>> +  $ hg bookmark -r a41d7b167990 bookmark1
>> +  moving bookmark 'bookmark1' forward from ce2028409ac8
>> +
>> +  $ hg push -B bookmark2 pushbookmark
>> +  pushing to ssh://user@dummy/$TESTTMP/server
>> +  searching for changes
>> +  remote: adding changesets
>> +  remote: adding manifests
>> +  remote: adding file changes
>> +  remote: added 1 changesets with 1 changes to 1 files (+1 heads)
>> +  exporting bookmark bookmark2
>> +
>> +Specifying an unknown name is currently unsupported
>> +
>> +  $ hg --config paths.pushbookmark.pushnames=unknown push pushbookmark
>> +  abort: non-bookmarks not currently supported by pushnames path option
>> +  [255]
>> +
>> _______________________________________________
>> Mercurial-devel mailing list
>> Mercurial-devel at selenic.com
>> http://selenic.com/mailman/listinfo/mercurial-devel
> _______________________________________________
> Mercurial-devel mailing list
> Mercurial-devel at selenic.com
> http://selenic.com/mailman/listinfo/mercurial-devel



More information about the Mercurial-devel mailing list