[PATCH] add support for marking changesets as dead

Martin Geisler mg at aragost.com
Tue Feb 1 04:21:01 CST 2011


Matt Mackall <mpm at selenic.com> writes:

> On Mon, 2011-01-31 at 22:41 +0100, Henrik Stuart wrote:
>> On 2011-01-31 22:15, Matt Mackall wrote:
>>> On Mon, 2011-01-31 at 11:10 +0100, Martin Geisler wrote:
>>>> # HG changeset patch
>>>> # User Henrik Stuart <hg at hstuart.dk>
>>>> # Date 1295774638 -3600
>>>> # Node ID 7bd977fdbca15da3c69ea7ef01df987b95475b11
>>>> # Parent  0d1dca7d2a041cb1cb6c6bd90608aa87068bde02
>>>> add support for marking changesets as dead
>>>
>>> I like this core concept. I think we need a scheme for marking
>>> branches with something like 'do not display or propagate'.
>>>
>>> However, as discussed at the 1.7 sprint, I still think we should use
>>> pushkey[1] to implement this. For starters, it meshes well
>>> conceptually with the liquid concept that's also going to be
>>> communicated via pushkey.
>>
>> I think that making it a core concept rather than pushkey-based
>
> Uh, what? Pushkey is a core concept. It's how we distribute data
> that's not an immutable part of history. Since your data is all about
> changing history, it should use pushkey.

Well, "changing" is a bit of a misnormer here, it is more about
appending more history, which will in turn hide some old part of the
history.

>> Liquid and dead are, in my opinion, completely orthogonal and solve
>> two different problems: tracking what's safe to modify, and telling
>> everyone else that something's gone amiss.
>
> I'm afraid this can only mean you haven't fully understood what
> 'liquid' is about. The primary distinction liquid makes is 'these are
> things that will never disappear' and 'these are things that might
> disappear'. Whereas dead heads is distinguishing between 'these are
> things we're keeping' and 'these are things you should drop'. To say
> these are unrelated is.. puzzling. My mental models of how to
> implement these two concepts are nearly identical.

I sort of see what you mean here... however, it was my impression that

>> (I told Martin to insist that pushkey wasn't the best choice at the
>> sprint, but he must've forgotten). :o)
>
> Nah, what he forgot was to tell you I thought you were crazy.

Ahem... :)

>>> Also, I think there are some problems with a cset-base
>>> implementation that are unaddressed here. Fundamentally, lines of
>>> development are not the thing we actually care about, not heads.
>>> Consider:
>>>
>>> 0-1-2-3-6
>>>    \   /
>>>     4-5
>>>
>>> If I want to mark 1 and all descendants dead, it does not appear to
>>> be enough to put a mark at 1:
>>>
>>>     M
>>>    /
>>> 0-1-2-3-6
>>>    \   /
>>>     4-5
>>>
>>> Looking at that last graph, it's not clear whether M was added
>>> before or after 2. Thus it's not clear whether M kills 2 (case A) or
>>> 2 invalidates M (case B).
>>
>> The concept is invalidating ancestors, so you would commit a --kill
>> changeset on top of 6 and a new child from 0 to make 0 alive. If you
>> wanted M killed you would also have to commit a --kill on top of
>> that, otherwise M keeps 1 alive.
>
> And that, I think, is conceptually broken. I can know that I want "1
> and descendants" dead long before I know what I want to replace it
> with. Having to commit an extra dummy cset (note that we actively
> reject empty csets!) to have a living head at this point "sucks" from
> a user POV.

Sort of -- see it this way: the dead changesets are no good if you want
to back up a linear track of development. They are good if you have
different (concurrent!) lines of development and you want to kill one of
them, in which case you already have a branch point in the past.

> Again, dead "heads" are a boring special case of dead "anonymous
> branches". If you're not talking about killing -whole lines of
> development- after the fact, it's a non-starter. And killing branches
> is logicially going to be about 'invalidating descendants' and not
> 'invalidating ancestors'.

That is because you want to kill the branch before you've started a new
branch. I imagined the dead heads to be used in cases where you do

  hg merge X
  hg commit
  hg push

Ups, bad merge!

  hg update revA
  hg merge X
  hg commit
  hg strip --kill old-merge-head
  hg push

or in situations where you pull in changes, rebase and let the old
changesets stay behind as a dead branch.

>>> So the pushkey version is effectively an extension of history where
>>> each cset has a deadness bit that's read/write.
>>>
>>> [1] "Pushkey implementation" here means "something that's stored
>>> with a mechanism outside of history and thus needs to be transmitted
>>> via pushkey", eg like bookmarks. Pushkey itself doesn't implement
>>> any sort of storage.
>>
>> We'll then need to extend pushkey with enough knowledge about whether
>> it kills heads here or there (push or pull) and compute much of what
>> is already computed in discovery.
>
> Extend pushkey? That's pretty much redundant. Pushkey is very
> abstract, everything that uses pushkey defines its own add/remove and
> list methods. I strongly suggest you actually look at how pushing
> bookmarks work.

Henrik knows how pushkey works. What he is saying is that you would need
to redo the computations done in the discovery protocol to figure out
which (live) changesets that need to be propagated and which should not
be sent anywhere.

Also, with pushkey, how will we solve the problem of cancelleing the
kill orders? If I pull from A and get meta data that says "kill X", and
if this is cancelled at A, then how do I know if I should push the kill
order back to A or if I should delete my own?

That has always confused me about the out of history meta data, and the
changeset based meta data avoids that.

-- 
Martin Geisler

aragost Trifork
Professional Mercurial support
http://aragost.com/en/services/mercurial/blog/


More information about the Mercurial-devel mailing list