sharing secret changesets with friends

Dov Feldstern dovdevel at
Tue Feb 18 18:40:14 CST 2014

Thanks, all, for your comments!

A few random thoughts, I don't think I have a coherent direction in
which to take this, yet:

What is the use case for "secret", as it currently stands? I can't
really think of any situation in which I would want to have something
that *can't* be cloned to my *personal* clones. The way I see it, I
want to always be able to clone my repo in order to branch out in some
new experimental direction without affecting the original repo and its
working directory -- and I want that clone to be, well, a *clone* --
an exact copy -- of the original repo, including all of the
experimental work or "pbranches" that it contained. Essentially,
"secret" in its current form means keeping secrets from *myself* -- I
don't see how that's useful...

And again, just to explain the background: Now that I'm switching from
mq to evolve, I have many csets in the repo that are not yet ready to
be published -- what used to be *unapplied* patches in mq, or, in
essence, "pbranches". (This is the expected state to be in with
evolve, right?) Now, when I want to push one piece of work, I want to
be able to guard against all the other "pbranches" from being
accidentally pushed. With mq, as long as they were still patches they
would not get accidentally pushed; and when I *did* intend to push, I
would "qfinish" those patches I intended to push, and thus make them
"pushable". So now I am looking for an equivalent way to differentiate
between the work that I intend to push, and all the other work that I
don't intend to push. Marking them as "secret" seems like the perfect
solution -- except that, as explained above, then I can't even share
them with myself -- and *that's* what I am hoping to solve.

The solutions suggested here of making the default-push point to a
non-public repo, or of somehow allowing for a "non-publishing" push
command, or of specifying certain peers as "no auto-publish" are all
addressing a problem which is subtly different than the problem I am
trying to solve: my problem is not so much that of pushing to the
wrong repo when I don't intend to, but rather that when I *do* intend
to publish, I accidentally publish *more* than I intended to. In other
words, the focus is not on how to mark *who* I am or am not willing to
share with, but rather on *what* I want to or don't want to share.

One way to think of this is as "tagging" the various draft csets --
some of them being tagged as "don't push yet" and others as "ok, this
is ready for pushing". But it's not exactly *tags* -- I want them to
be shared, and movable, kind of like bookmarks. But it's not
bookmarks, either; it's kind of *reverse* bookmarks: it's a movable
pointer to the *base* of a branch rather than to its head. Those are
exactly the semantics of phases...!

Perhaps a solution like that suggested by Kaz, of having a
'non-publishing' option to push, could work: I would personally set
that option to always be on, and that would provide the protection I
am used to from mq; and the equivalent to "qfinish" would be to change
the phase of the work that I'm ready to publish to be public. And
"secret" is not part of the scheme at all...

The idea of specifying filters for paths is interesting; it sounds
very powerful, and a little complicated ;) ... But for the specific
problem I am raising here, I don't see how exactly it would help...

On Wed, Feb 19, 2014 at 12:42 AM, Angel Ezquerra
<angel.ezquerra at> wrote:
> On Tue, Feb 18, 2014 at 10:56 PM, Pierre-Yves David
> <pierre-yves.david at> wrote:
>> On 02/16/2014 05:02 PM, Dov Feldstern wrote:
>>> I like to keep changesets that are still in-development secret --
>>> keeping them just as draft is risky, since I find that I am wont to
>>> "push" without limiting what branch I'm pushing, with the result that
>>> I push work that is not really ready to be published (this was not so
>>> much of a problem with mq, since patches did not get pushed by
>>> default, but now that I'm switching to evolve -- which I am generally
>>> very happy with :) -- this is more of an issue).
>> My usual solution to this is to have a different `default` and
>> `default-push` path.
>> eg:
>>   default =
>>   default-push =
>> So any push to a publishing server are explicit.
>>> OTOH, keeping the changesets secret means I can't share them with
>>> *any* repositories, though often I would like to be able to share
>>> among my different non-publishing repositories (this is one of the
>>> main drivers for switching from mq to evolve -- that with evolve it
>>> should be easier to share in-progress, still-mutating, work). This is
>>> also similar to the questions asked at [1,2], the answers to which I
>>> find not very satisfying (no offense, Martin!).
>> The phase dedicated to -in-progress- changeset I want to
>> -share-with-other-people- are -draft-.
>> You issue here seems to be accidentaly publication of such draft changeset.
>> So, maybe we should improve this aspect of the problem. This could includes:
>> - hook warning you when you are pushing draft to secret changeset.
>> - special configuration on the path to mark it as "no auto publish"
>>   (more on that below)
>> - `--no-publish` flag on push
>> (I'll talk about valid case for secret exchange later)
>>> But even this simple implementation has already raised some issues:
>>> 1. The pushed secret changesets get promoted to "draft" in both the
>>> local and remote repos. What's actually happening, I think, is that
>>> the csets get pushed to the remote as "draft", and then the comparison
>>> of the local with the remote finds that they are draft in the remote,
>>> and so promotes them to draft locally as well. (It was easy enough to
>>> prevent the promotion of the local csets, but I couldn't find where
>>> the promotion of the remote ones was happening; and if they get
>>> promoted, then preventing the promotion of the local ones is
>>> meaningless or downright wrong.) So, any tips on where the promotion
>>> of the remote changesets to "draft" is happening?
>> This is expected. New changeset added to a repo are added as draft (or
>> public if publishing). There is no concept of "new changeset pushed as
>> secret" as the fact someone was able to push them imply there were
>> non-secret.
>> And they try draft locally because they have been seen as draft remotely so
>> their phase is moved to the lowest known one (draft < secret).
>>> 2. If the secret changesets in the remote are manually forced back to
>>> secret, then subsequent 'outgoing -F' shows them again as outgoing!
>> Yes, because secret mean "no advertised by server".
>> (rest of the paragraph made my head hurt, ignoring it for now)
>>> 3. Just a general observation after having looked at the code a bit:
>>> it seems that the *current* semantics of secrets are pretty widely
>>> assumed, so I'm a *little* worried about being able to cover all
>>> edge-cases with a change like this...
>> You are right, the secret semantic is well established and well enforced.
>> A simplistic view of your current plan can be "attempt to make secret phase
>> a sightly altered draft phase". And this way is not going to fly. Once you
>> start thinking about various level of draft changeset you end up with:
>> - really secret changeset
>> - changeset you want to share with repo on you machine
>> - changeset you want to share with you various machine
>> - changeset you want to share with continuous integration
>> - changeset you want to share with your close coworker
>> - changeset you want to share with your team
>> - changeset you want to share with your review system
>> - changeset you want to share with all the company
>> - changeset you want to share with the alpha version repo
>> - changeset you want to share with the beta version repo
>> - changeset you want to share with the production version repo
>> - changeset you want to share with the old stable version repo
>> - changeset you want to share with the open source product repo
>> - etc...
>> This is why we stick to very simple public / draft / secret model in the
>> end. We can't build a sane model generic enough for all use case. We need
>> another tools for that.
> Very interesting discussion.
> I agree with your point of view that specifying levels of secretness
> with greater granularity does not make sense. However there is one
> thing that I really miss when using phases which is that there is no
> way to differentiate between unshared draft revisions and shared draft
> revisions.
> The way things currently are you can either work with a publishing
> repo, in which case you know that draft revisions are unshared because
> you cannot share them, or you can work with a non publishing repo in
> which case you can share draft revisions but you can't tell whether
> you have shared them or not. You cannot have both (i.e. you cannot
> share draft revisions and still be able to tell which ones you shared
> and which ones you did not share yet).
> I always thought that I'd be nice to have a "shared" phase between
> draft and public, which meant that the revision has been shared to a
> non publishing repo. These revisions would behave exactly the same as
> draft revisions. The only difference would be that you would be able
> to tell that they had been shared (and thus that they are in the
> wild).
> That being said, even though I still think that having a shared phase
> would be nice, it would be even nicer to have some sort of "sharelog"
> that could tell you which revisions you shared with which repositories
> (and also which revisions you got from where).
>>> Does this idea sound interesting/useful to anyone else? And if so, any
>>> pointers on how to move ahead with this?
>> Even if I do not believe in your current approach as is, You are definitely
>> pointing interesting issue that need proper solution. I would advertise a
>> different approach:
>> 1) make it harder to publish//exchange thing by mistake with some repo.
>> 2) build a small dedicated solution to allow secret changeset in bundle and
>> `backup push`
>> For (1) I think the MacHg developer wrote some interresting proposal on this
>> list about one year ago.
>> I think we need to introduce a "path attribute" concept somehow. Maybe
>> something like this
>>   [paths]
>>   toto =
>> = true
>>   toto.filter = branch("default") and ::tagged()
>> (not doable this way for backward compatibility reason but you get the idea)
> I think this would be very cool and useful. An empty "filter"
> attribute could mean that the repo is readonly and that you never want
> to push to it. The filter attribute could split into a push-filter and
> a pull-filter so that you could also specify what you want to pull
> from where.
> Going further, this would be specially useful if it could also apply
> to subrepos. Having a way to make a subrepo "readonly" is something
> that I've been asked more than a few times.
> Cheers,
> Angel

More information about the Mercurial-devel mailing list