Bookmarks with hg update question

Sean Farley sean at farley.io
Tue Jun 28 21:48:46 UTC 2016


Scott Palmer <swpalmer at gmail.com> writes:

>> On Jun 27, 2016, at 9:27 PM, Ethan Furman <ethan at stoneleaf.us> wrote:
>> 
>> On 06/27/2016 06:00 PM, Scott Palmer wrote:
>> 
>>> It's not that it can't be done, but existing scripts will break
>> > (silently perhaps) and that sort of thing.
>> 
>> Valid point.  So the behavior change should happen with a major version change, then.
>> 
>>> If I have an *active* bookmark and I execute an update without specifying
>> > a revision it means I want to advance the bookmark as far as I can.  If
>> > you don't want the bookmark to move, don't activate it, or specify a
>> > revision with your update.
>>> 
>>> This is consistent with the non-bookmark workflow. You do an update with
>> > no revision to move as far ahead as you can before committing new work.
>> > Same goes if I want to commit the work to the active bookmark.
>> 
>> That is not consistent nor the same thing at all.  If I'm at revision 71 and I issue `hg update` the tip does not suddenly become revision 71.
>
>
> I’m not sure why you mention that, as the current bookmark behaviour wouldn’t do anything like that either.
>
>> If I'm at branch 3.4 and issue `hg update` I'm not suddenly at the tip of 3.5, with the tip of branch 3.4 also being there. So why then if I'm at the bookmark 'gui_refresh' and I issue `hg update` and move forward 31 commits, should the 'gui_refresh' bookmark also be there?
>
> Because bookmarks and branches aren’t the same thing.
> 'hg update’ with no args does not hop from one branch to another, even with bookmarks.  So the idea of moving from 3.4 to 3.5 is bogus.  The current bookmark behaviour doesn’t do that. It doesn’t jump to another topological branch.
>
>> Particularly when there are explicit ways to move it there -- like reissuing the bookmark command.
>
> Which is more awkward because then you DO have to worry about the bookmark jumping branches.
>
>> 
>> I suspect this is the heart of the problem:  `hg update` is doing double duty, and it shouldn't be -- at least not implicitly.
>
> I don’t see it that way.  Bookmarks mark my current spot and they follow along automatically, that’s the point of them.  hg update *with no args* moves my current spot ahead in a natural way and only the active bookmark (naturally) moves with it… it is supposed to ‘follow along’ to keep track of my current spot.  Only when I specify moving to a specific spot by being explicit about the revision I’m updating to is the intent to move away from the bookmark implied (yes a flag to say ‘hey bookmark, deactivate and stay where you are’ might be a good idea as well, but you can accomplish that with an alias I think.).
>
>
>>  Particularly not when the general advice (and the specific advice from the program) is to use bookmarks instead of branches, yet the behavior of `hg update` is so vastly different between the two.
>> 
>>> I can just as well ask, "Would it be a major hardship to add 'tip' instead
>> > of breaking existing workflows?"
>> 
>> It would not -- but that doesn't solve the problem as eventually I would forget to add 'tip' and then my bookmark would move
>
> The key here is "Where would it move to?”  I believe moving the active bookmark is the right thing to do, so long as it moves to the right place.  More on that below.
>
>> and I would have to try and figure out where it came from, or, more likely, undo the damage from the commits that happened when I went back to my bookmark without realizing it wasn't where I thought it was.
>> 
>>> My current issue is that TortoiseHg doesn't have an easy way to do the
>> > equivalent of the current command line behaviour. It  moves me off the
>> > bookmark when I don't want it to. Explicitly moving the bookmark with
>> > TortoiseHg is dangerous because I can easily accidentally jump to a
>> > different head.
>> 
>> You wouldn't lose the ability to move your bookmark from the command line -- it would just cost you a few more characters.
>
> Here is a test case where the bookmark does not jump to some unrelated branch when I execute ‘hg update’
>
>> hg init testrepo
>> cd testrepo/
>> touch file.txt
>> hg address
>> hg ci -m "first rev”
>> hg bookmark @
>> hg st
>> hg sum
> parent: 0:ac94f1f98bd0 tip
>  first rev
> branch: default
> bookmarks: *@
> commit: (clean)
> update: (current)
> phases: 1 draft
>
>> echo hi > file.txt 
>> hg st
> M file.txt
>> hg ci -m "added content"
>> hg log -G
> @  changeset:   1:d8108c070a9f
> |  bookmark:    @
> |  tag:         tip
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
>> echo mom >> file.txt 
>> hg ci -m "addressed mother"
>> hg log -G
> @  changeset:   2:9e4af144d1b7
> |  bookmark:    @
> |  tag:         tip
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:58 2016 -0400
> |  summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
>> hg up 1
> 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> (leaving bookmark @)
>> hg bookmark feature_A
>> touch readme.txt
>> hg addrem
>> hg ci -m "added readme"
>> hg log -G
> @  changeset:   3:e336d7687ff2
> |  bookmark:    feature_A
> |  tag:         tip
> |  parent:      1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:00:58 2016 -0400
> |  summary:     added readme
> |
> | o  changeset:   2:9e4af144d1b7
> |/   bookmark:    @
> |    user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
>> hg up @
> 1 files updated, 0 files merged, 1 files removed, 0 files unresolved
> (activating bookmark @)
>> echo and >> file.txt 
>> hg ci -m "more work"
>> echo dad >> file.txt 
>> hg ci -m "don't leave out dad"
>> hg log -G
> @  changeset:   5:9eafbee1ebd0
> |  bookmark:    @
> |  tag:         tip
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:49 2016 -0400
> |  summary:     don't leave out dad
> |
> o  changeset:   4:b562fba2af67
> |  parent:      2:9e4af144d1b7
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:33 2016 -0400
> |  summary:     more work
> |
> | o  changeset:   3:e336d7687ff2
> | |  bookmark:    feature_A
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> o |  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
>> hg up feature_A
> 2 files updated, 0 files merged, 0 files removed, 0 files unresolved
> (activating bookmark feature_A)
>> hg up
> 0 files updated, 0 files merged, 0 files removed, 0 files unresolved
>
>> hg log -G
> o  changeset:   5:9eafbee1ebd0
> |  bookmark:    @
> |  tag:         tip
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:49 2016 -0400
> |  summary:     don't leave out dad
> |
> o  changeset:   4:b562fba2af67
> |  parent:      2:9e4af144d1b7
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:33 2016 -0400
> |  summary:     more work
> |
> | @  changeset:   3:e336d7687ff2
> | |  bookmark:    feature_A
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> o |  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
> As you can see the “hg up” did not move we to the “tip” revision because that would have moved off the line of development that my bookmark was on.
>
> Now if I had done the “hg up” immediately after I made the bookmark, in this case it does what I believe is the right thing…
>
>> hg up 1
> 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> (leaving bookmark feature_A)
>> hg bookmark new_feature
>> hg log -G
> o  changeset:   5:9eafbee1ebd0
> |  bookmark:    @
> |  tag:         tip
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:49 2016 -0400
> |  summary:     don't leave out dad
> |
> o  changeset:   4:b562fba2af67
> |  parent:      2:9e4af144d1b7
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:33 2016 -0400
> |  summary:     more work
> |
> | o  changeset:   3:e336d7687ff2
> | |  bookmark:    feature_A
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> o |  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> @  changeset:   1:d8108c070a9f
> |  bookmark:    new_feature
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
>> hg up
> 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> updating bookmark new_feature
>> hg log -G
> @  changeset:   5:9eafbee1ebd0
> |  bookmark:    @
> |  bookmark:    new_feature
> |  tag:         tip
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:49 2016 -0400
> |  summary:     don't leave out dad
> |
> o  changeset:   4:b562fba2af67
> |  parent:      2:9e4af144d1b7
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:01:33 2016 -0400
> |  summary:     more work
> |
> | o  changeset:   3:e336d7687ff2
> | |  bookmark:    feature_A
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> o |  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
> The bookmark was advanced to the tip.  Which is where I want it to be because that is my ‘@‘ bookmark, the default place where I would be from a fresh clone.  It’s where I would have started my bookmark anyway had I waited a bit.
>
> Now, here is where I think the real problem lies… In my example above ‘tip’ was on the main line with my ‘@‘ bookmark, not feature_A’s head.  If we flip that around we get the problem you describe. First we get feature_A to have the tip revision:
>
>> hg up feature_A
> 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> (activating bookmark feature_A)
>> echo Just a test >> readme.txt 
>> hg ci -m "added a message for Feature A”
>> hg log -G
> @  changeset:   6:06f298aadb96
> |  bookmark:    feature_A
> |  tag:         tip
> |  parent:      3:e336d7687ff2
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:17:17 2016 -0400
> |  summary:     added a message for Feature A
> |
> | o  changeset:   5:9eafbee1ebd0
> | |  bookmark:    @
> | |  bookmark:    new_feature
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:01:49 2016 -0400
> | |  summary:     don't leave out dad
> | |
> | o  changeset:   4:b562fba2af67
> | |  parent:      2:9e4af144d1b7
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:01:33 2016 -0400
> | |  summary:     more work
> | |
> o |  changeset:   3:e336d7687ff2
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> | o  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
> Then we start feature_B back at the common ancestor.
>
>> hg up 1
> 0 files updated, 0 files merged, 1 files removed, 0 files unresolved
> (leaving bookmark feature_A)
>> hg bookmark feature_B
>> hg log -G
> o  changeset:   6:06f298aadb96
> |  bookmark:    feature_A
> |  tag:         tip
> |  parent:      3:e336d7687ff2
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:17:17 2016 -0400
> |  summary:     added a message for Feature A
> |
> | o  changeset:   5:9eafbee1ebd0
> | |  bookmark:    @
> | |  bookmark:    new_feature
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:01:49 2016 -0400
> | |  summary:     don't leave out dad
> | |
> | o  changeset:   4:b562fba2af67
> | |  parent:      2:9e4af144d1b7
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:01:33 2016 -0400
> | |  summary:     more work
> | |
> o |  changeset:   3:e336d7687ff2
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> | o  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> @  changeset:   1:d8108c070a9f
> |  bookmark:    feature_B
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
> This time “hg up” takes us to the “wrong” place.
>
>> hg up
> 1 files updated, 0 files merged, 0 files removed, 0 files unresolved
> updating bookmark feature_B
>> hg log -G
> @  changeset:   6:06f298aadb96
> |  bookmark:    feature_A
> |  bookmark:    feature_B
> |  tag:         tip
> |  parent:      3:e336d7687ff2
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 23:17:17 2016 -0400
> |  summary:     added a message for Feature A
> |
> | o  changeset:   5:9eafbee1ebd0
> | |  bookmark:    @
> | |  bookmark:    new_feature
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:01:49 2016 -0400
> | |  summary:     don't leave out dad
> | |
> | o  changeset:   4:b562fba2af67
> | |  parent:      2:9e4af144d1b7
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:01:33 2016 -0400
> | |  summary:     more work
> | |
> o |  changeset:   3:e336d7687ff2
> | |  parent:      1:d8108c070a9f
> | |  user:        Scott Palmer <swpalmer at ....com>
> | |  date:        Mon Jun 27 23:00:58 2016 -0400
> | |  summary:     added readme
> | |
> | o  changeset:   2:9e4af144d1b7
> |/   user:        Scott Palmer <swpalmer at ....com>
> |    date:        Mon Jun 27 22:59:58 2016 -0400
> |    summary:     addressed mother
> |
> o  changeset:   1:d8108c070a9f
> |  user:        Scott Palmer <swpalmer at ....com>
> |  date:        Mon Jun 27 22:59:29 2016 -0400
> |  summary:     added content
> |
> o  changeset:   0:ac94f1f98bd0
>    user:        Scott Palmer <swpalmer at ....com>
>    date:        Mon Jun 27 22:58:05 2016 -0400
>    summary:     first rev
>
> There you go… the bookmark for feature_B is on feature_A’s head.  Bad, I agree.  However, my proposed solution is different.
>
> How about we move the active bookmark forward in a limited way, as far as we can without causing this sort of trouble.  But we DON’T deactivate the bookmark and move away from it if no explicit revision was given to ‘hg update’.

There is a metric ton of points to address here but that will take too
long so I'll just reply to a few of the more important ones.

The proposed solution is to treat bookmarks as more-or-less a head. 'hg
up' on an active bookmark will not move you anywhere nor deactivate the
bookmark. The reason for this is that it's the same behavior as named
branches. Having three stacked named branches is my usual example:

A1 <- A2 <- A3 <- B1 <- B2 <- C1 <- C2 <- C3

If I am at A3, then 'hg up' will not move me anywhere. Yet, if this was
a bookmark work, it would move me to C3 which is just bonkers.

Your statement "move the active bookmark forward ... as far as we can"
is non-deterministic and not possible. Imagine 'hg pull -r BOOKMARK^'.
You do not have the information you need "as far as possible". By making
bookmark movement explicit, we fix this insanely complicated behavior.

I've added a skeleton of an outline here:

https://www.mercurial-scm.org/wiki/BookmarkUpdatePlan

> We treat the ‘@‘ bookmark as the destination revision if we can get to it by moving ahead without jumping branches.

That's usually not enough state. For this, I implemented 'tracking' in
my remotebookmarks extension. I'll be slowly moving parts of that into
core soon (hopefully).

> So in the case above with ‘feature_B’ use the ‘@‘ bookmark as the destination revision.  We can say that the ‘@‘ bookmark tells us where the ‘neutral’ branch is, so we don’t take the wrong fork onto some other feature.
> If there is no ‘@‘ bookmark, or it its behind the current position (old rev), or it is only reachable by “jumping” to another branch (unreachable by moving forward on existing edges), then we move as far as we can before we come to a place that leads to different ‘heads’.
>
> If we started feature_B at rev 0 in the above case, and we DIDN’T have an @ bookmark, then we would advance to rev 1, because bringing the bookmark farther forward would require that we picked a branch and without a ‘@‘ bookmark to disambiguate that’s as far as we can safely take the bookmark.
>
> If feature_A is merged with the main branch so we are back to one topological head in the path forward, then we can go all the way, since it doesn’t matter which fork we take in the path, they both read to an unambiguous head revision.
>
> Of course, if a bookmark is NOT active, let “hg update” tries to go to ‘tip’ as before.

Point of correction: 'hg update' has always gone to the highest revision
of the current named branch.



More information about the Mercurial mailing list