atom feed7 messages in com.selenic.mercurial-develRe: Bookmarks: don't push local bookm...
FromSent OnAttachments
Matt MackallJun 2, 2012 2:16 pm 
Levi BardJun 3, 2012 3:30 am 
Matt MackallJun 3, 2012 5:37 pm 
Augie FacklerJun 4, 2012 6:46 am 
Bryan O'SullivanJun 4, 2012 10:10 am 
Pierre-Yves DavidJun 8, 2012 8:05 am 
Kevin BullockJun 8, 2012 9:15 am 
Subject:Re: Bookmarks: don't push local bookmark heads by default?
From:Pierre-Yves David (
Date:Jun 8, 2012 8:05:38 am

On Sat, Jun 02, 2012 at 04:16:21PM -0500, Matt Mackall wrote:

One possibility is that when an outgoing head has a bookmark that's local-only, we treat the commits as local-only as well and refrain from pushing it. This lets Alice make a private bookmark branch without needing to worry about it getting pushed by accident.

TL;DR: don't do that! Instead we should abort//warn when pushing a head without it's bookmark. (And migrate to local/global bookmark, see table at the

*Yes* the fact that you push bookmarked changeset without the bookmark is confusing, annoying and one of the major issue with bookmark.

*No* I do not like this proposal: =====================================================================

- You already sumup the downside and I feel they are pretty strong.

I "regularly" use bookmark to add "local label" to commit. This label -may- something ends on head and I will be confused and annoyed it if magically -stop- pushing change because I **finally moved** the 'test-on-sulfur' on a

Another example of strange behavior:

The very same command will push different head when used on two differents repo. Just the two remote does not have the same bookmark (and you have not easy way to know which bookmark are available on remote)

- I'm not convinced by the way this try to fix: "it's not making it very easy for Alice to make a "local branch".

The answer here is: "enforce the branch is not pushed".

And we -already- have a concept for "ensure this changeset are not pushed"
(secret phase).

The real point we should seek is "ensure the branch is not pushed without it's bookmark.". See my counter-proposal below.

- This goes down the "Let's do the exact same thing than git branch". This is very bad. This ultimately lead the need to have the exact same behavior than git branches, requesting everything to be bookmarked to have a descent user experience.

One of the strength of mercurial is to *not* have mandatory label on everything! Let's preserve it.

I believe we can find our own way for bookmark.

This is why I do have another simple proposal: =====================================================================

Abort when pushing bookmarked heads without they bookmark:

$ hg push abort: pushing heads b4b49c313571 without it bookmark "elephants" unknown
remotely (do you want to use -B to push bookmark of to turn you branch secret ?)

The user will have three options to be able to push:

A) pushing it's bookmark remotely

$ hg push -B elephants

B) making its local only changeset secret: (non-contractual revset)

$ hg phase --force --secret "draft() and ::elephant"

C) Add yet another option to push: (non-contractual option name)

$ hg push --yes-push-please-this-bookmark-is-local-only

A lower version of this is to just warn when this happen

$ hg push warning: pushed heads b4b49c313571 without it bookmark "elephants" unknown
remotely (use "hg push -B elephant" to push it)

Going even further: =====================================================================

(This part is not directly linked to the discussion but related to "how we can make bookmark usable")

I fell like the "ideal" alternative will be to always push all bookmark by default the same way we always pull and clone them. However:

Another alternative, pushing "local" bookmarks always, is probably off the table as it means anyone who is depending on having a private namespace today gets a nasty surprise on upgrade.

But it is clear that they are two usages for bookmarks:

- pointer for lightweight branches that we want to share

- local marker for local only purpose (yes, we had local tag for that)

And I think we should make this distinction explicit:

Bases rules:

1) Bookmark are either *local* or *global*.

2) *Global bookmark* are (almost) always pushed, pull and cloned.

3) *Local bookmark* are never pushed, pulled or cloned. (they don't appear in pushkey)

4) bookmark are created global unless "--local" flag is given

5) you can switch bookmark from *global* to *local* manually

Backward compat rules:

1) Bookmark created with older version of mercurial are *old*

2) *Old bookmark* seen on remote repo are promoted to *global*

$ hg push bookmark "elephants" promoted to global

3) *Old bookmark* on a *pushed head* warn if bookmark is not known remotely

$ hg push pushed head b4b49c313571 without it's old bookmark "elephants" (do you want it global ? see "hg help bookmark")

4) *Old bookmark* behave as local bookmark otherwise

5) *Old bookmark* can be switched to *global* or *local* manually

Interaction with secret changeset:

1) If they are unknown remotely, global bookmark on secret changeset are not pushed.

2) If they are known remotely, global bookmark on secret changeset are

pushed as if they where on the tip most draft ancestors of their current location. (if they are multiple heads to (public() and ::bookmarked) we create divergent bookmark and/or warn)

This point should be done even for the current implementation.

Summary table:



:secret: are the bookmark on a secret changeset :head: are the bookmark on a head :remote: are the bookmark know by remote ? :local: are the bookmark known locally

vertical :

:current: how bookmark currently behave in the current code. :old: bookmark created with older mercurial version :local: new local only bookmark :global: new global bookmark (new default)


:ignore: we do not try to push the bookmark :warn: bookmark is not pushed but warning is printed (can be
abort) :push: we try to push the bookmark (doing secret related magic if
necessary) :promote: old bookmark is promoted to global and pushed//pulled :pull: we update get the bookmark locally

Push behavior:

secret | | yes | remote | | yes | | yes | head | | yes | | | | ========+============================================= current | ignore | push | ignore | push* | old | ignore | warn | promote | ignore | promote | local | ignore | ignore | ignore | ignore | global | push | push | ignore | push |

* In 2.2 We don't apply secret magic and fail

Pull behavior:

secret | | yes | local | | yes | | yes | ========+====================================== current | pull | pull | ignore | pull* | old | pull | promote | ignore | promote | local | ignore | ignore | ignore | ignore | global | pull | pull | ignore | pull |

* In 2.2 We don't apply secret magic and fail

clone behavior:

secret | | yes | ========+===================| current | pull | ignore | old | promote | ignore | local | ignore | ignore | global | pull | ignore | (or pull ?)

* In 2.2 We don't apply secret magic and fail