Differences between revisions 2 and 3
Revision 2 as of 2011-05-07 20:05:02
Size: 8375
Editor: mpm
Comment:
Revision 3 as of 2011-05-09 14:00:00
Size: 8110
Editor: mpm
Comment:
Deletions are marked like this. Additions are marked like this.
Line 2: Line 2:
Line 4: Line 3:
Line 12: Line 10:
This page aims to define features connected with the 'liquid hg' discussion in enough detail that they can be fine-tuned and implemented.
Line 13: Line 12:
This page aims to define features connected with the 'liquid hg'
discussion in enough detail that they can be fine-tuned and
implemented.

They are intentionally presented in a proposed order of
implementation.
They are intentionally presented in a proposed order of implementation.
Line 21: Line 15:

Various features will require changesets to be hidden by default. So
it makes sense to implement a centralized method of dealing with this
property.
Various features will require changesets to be hidden by default. So it makes sense to implement a centralized method of dealing with this property.
Line 28: Line 19:
Hidden changesets can be shown with the --hidden flag, eg 'hg
log --hidden' will show all changesets.
Hidden changesets can be shown with the --hidden flag, eg 'hg log --hidden' will show all changesets.
Line 31: Line 21:
Implementation:  Implementation:
Line 33: Line 23:
The changelog object contains a _hidden set (using
revision numbers) that log and other commands consult. To hide a
changeset, add it to the set at startup. Contexts are given a
.hidden() predicate that consults the set.
The changelog object contains a _hidden set (using revision numbers) that log and other commands consult. To hide a changeset, add it to the set at startup. Contexts are given a .hidden() predicate that consults the set.
Line 39: Line 26:
A 'changeset state' is an indicator that tells us how a changeset is manipulated and communicated. The details of each state is described below, here we describe their shared properties.
Line 40: Line 28:
A 'changeset state' is an indicator that tells us how a changeset is
manipulated and communicated. The details of each state is described
below, here we describe their shared properties.
Like bookmarks, states are not stored in history and thus are not permanent and leave no audit trail.
Line 44: Line 30:
Like bookmarks, states are not stored in history and thus are not
permanent and leave no audit trail.

First, no changeset can be in two states at once. States are also
ordered, so they can be considered from lowest to highest. The
default, lowest state is 'frozen' - this is the normal state of
existing changesets. No child changeset can be in a lower state than
its parents.
First, no changeset can be in two states at once. States are also ordered, so they can be considered from lowest to highest. The default, lowest state is 'frozen' - this is the normal state of existing changesets. No child changeset can be in a lower state than its parents.
Line 58: Line 37:
|| ||mutable ||unshared ||hidden ||GC-able ||
||frozen || || || || ||
||liquid ||x || || || ||
||local ||x ||x || || ||
||dead ||x ||x ||x ||x ||
Line 59: Line 43:
|| || mutable || unshared || hidden || GC-able||
||frozen|| || || || ||
||liquid|| x || || || ||
||local || x || x || || ||
||dead || x || x || x || x ||
Line 65: Line 44:
These names are subject to change. Some of them have initials that
collide with each other and with options like force and they don't
have an obvious progression.


These names are subject to change. Some of them have initials that collide with each other and with options like force and they don't have an obvious progression.
Line 70: Line 49:

States are manipulated via the 'hg state' command, ie 'hg state -f x'
to mark x as frozen. Each state puts its own constraints on how it can
be manipulated. The current state of changesets is displayed in the
log with a 'state:' header. The frozen state is not displayed at all.
States are manipulated via the 'hg state' command, ie 'hg state -f x' to mark x as frozen. Each state puts its own constraints on how it can be manipulated. The current state of changesets is displayed in the log with a 'state:' header. The frozen state is not displayed at all.
Line 79: Line 54:

Contexts provide a state() method that returns the current state as a
string. It may be useful to represent the frozen state with the empty
string.
Contexts provide a state() method that returns the current state as a string. It may be useful to represent the frozen state with the empty string.
Line 85: Line 57:

Frozen changesets are changesets that are considered permanently
immutable. This matches the history model presented by legacy Mercurial:
changesets cannot be changed or removed without using history editing
features from extensions. This state can be thought of as 'published':
once a changeset is published, it becomes very difficult to remove it
from distributed history.
Frozen changesets are changesets that are considered permanently immutable. This matches the history model presented by legacy Mercurial: changesets cannot be changed or removed without using history editing features from extensions. This state can be thought of as 'published': once a changeset is published, it becomes very difficult to remove it from distributed history.
Line 94: Line 60:
Line 98: Line 63:
Line 102: Line 66:
Line 106: Line 69:
Liquid changesets are changesets that the user is permitted to use history-modifying operations like rebase or mq on. They may not be tagged. They may also be thought of as 'unpublished'.
Line 107: Line 71:
Liquid changesets are changesets that the user is permitted to use
history-modifying operations like rebase or mq on. They may
not be tagged. They may also be thought of as 'unpublished'.
Various operations such as pushing to certain public servers will move changesets into the frozen state. Changesets cannot be moved from frozen to liquid without a forcing operation.
Line 111: Line 73:
Various operations such as pushing to certain public servers will move
changesets into the frozen state. Changesets cannot be moved from
frozen to liquid without a forcing operation.
The liquidity of changesets can be communicated between compatible servers and clients. This allows people to collaborate on work in progress before it becomes finalized.
Line 115: Line 75:
The liquidity of changesets can be communicated between compatible
servers and clients. This allows people to collaborate on work in
progress before it becomes finalized.

This should generally be engineered such that users don't have to give
any additional thought to liquid vs frozen in their day-to-day usage.
This should generally be engineered such that users don't have to give any additional thought to liquid vs frozen in their day-to-day usage.
Line 123: Line 78:

Changesets must be in a liquid state when they are created. So new
commits will start in a liquid state by default.
Changesets must be in a liquid state when they are created. So new commits will start in a liquid state by default.
Line 128: Line 81:
The set of liquid changesets is stored as a list of liquid roots. All descendants of these roots are liquid (or in a higher state). This set is known as the 'liquid barrier' and defines the 'liquid set'. This barrier is intended only to advance.
Line 129: Line 83:
The set of liquid changesets is stored as a list of liquid roots. All
descendants of these roots are liquid (or in a higher state). This set
is known as the 'liquid barrier' and defines the 'liquid set'. This
barrier is intended only to advance.
The liquid barrier is communicated via the pushkey protocol to servers that support it. The client is responsible for advancing the barrier on both the client and server sides. On each operation, the client reduces the liquid set on both sides to the intersection of the sets on the client and server. That is, if a changeset is frozen on either side, it becomes frozen on both sides.
Line 134: Line 85:
The liquid barrier is communicated via the pushkey protocol to servers
that support it. The client is responsible for advancing the barrier
on both the client and server sides. On each operation, the client
reduces the liquid set on both sides to the intersection of the sets
on the client and server. That is, if a changeset is frozen on either
side, it becomes frozen on both sides.

Some servers are configured as 'publishing servers'. Legacy servers
are publishing servers by default. These are recognized by not having
the 'liquid' pushkey namespace. When pushing to a publishing server,
all pushed changesets are moved into the frozen state on the client.
Similarly, all changesets pulled from a publishing server are treated
as frozen.
Some servers are configured as 'publishing servers'. Legacy servers are publishing servers by default. These are recognized by not having the 'liquid' pushkey namespace. When pushing to a publishing server, all pushed changesets are moved into the frozen state on the client. Similarly, all changesets pulled from a publishing server are treated as frozen.
Line 149: Line 88:

See above for pushing to legacy clients. Legacy clients are allowed to
pull liquid changesets, though a round trip will make them frozen.
See above for pushing to legacy clients. Legacy clients are allowed to pull liquid changesets, though a round trip will make them frozen.
Line 154: Line 91:

Local changesets are changesets that are not visible to remote
clients. This is useful to mark work private and to avoid
inadvertently publishing changesets.
Local changesets are changesets that are not visible to remote clients. This is useful to mark work private and to avoid inadvertently publishing changesets.
Line 160: Line 94:
Line 164: Line 97:

Like liquid changesets, local changesets are implemented via a local
barrier set. This set is used to filter changesets from remote clients
for push/pull/hgweb. This is probably best implemented via a _local
set on changelog.
Like liquid changesets, local changesets are implemented via a local barrier set. This set is used to filter changesets from remote clients for push/pull/hgweb. This is probably best implemented via a _local set on changelog.
Line 171: Line 100:

Legacy clients cannot see local changesets so will not pull them. New
clients will not push local changesets by default
Legacy clients cannot see local changesets so will not pull them. New clients will not push local changesets by default
Line 176: Line 103:
Dead changesets are changesets that are hidden and are eligible for garbage collection.
Line 177: Line 105:
Dead changesets are changesets that are hidden and are eligible for
garbage collection.
Dead changesets themselves are never pushed or pulled between clients (they are a subset of local) but deadness of changesets can be communicated between clients.
Line 180: Line 107:
Dead changesets themselves are never pushed or pulled between clients
(they are a subset of local) but deadness of changesets can be
communicated between clients.
If a client has a dead changeset X and happens to pull a remote changeset Y that is a descendant of it, changeset X becomes liquid or frozen as appropriate.
Line 184: Line 109:
If a client has a dead changeset and happens to pull a remote
changeset that is an ancestor of it, the changeset is becomes liquid
or frozen as appropriate.

Garbage collection consists of stripping all dead changesets. When
garbage collection occurs is currently undefined.
Garbage collection consists of stripping all dead changesets. When garbage collection occurs is currently undefined.
Line 192: Line 112:

Commits (and their descendents) can be manually marked dead with 'hg
state --dead'. Some operations like strip, qpop, and rebase may choose
to mark changesets dead rather than actually stripping them.
Commits (and their descendents) can be manually marked dead with 'hg state --dead'. Some operations like strip, qpop, and rebase may choose to mark changesets dead rather than actually stripping them.
Line 198: Line 115:

The dead set is stored as a complete list of all revisions. This
allows dead status to be propagated after garbage collection occurs.
Dead status is communicated via pushkey.
The dead set is stored as a complete list of all revisions. This allows dead status to be propagated after garbage collection occurs. Dead status is communicated via pushkey.
Line 204: Line 118:
Line 208: Line 121:
Abandoned changesets are changesets that have been marked as 'no longer relevant'. Like dead changesets, they are hidden, but abandoned changesets are implemented via markers in history so they are not part of the states concept.
Line 209: Line 123:
Abandoned changesets are changesets that have been marked as 'no
longer relevant'. Like dead changesets, they are hidden, but abandoned
changesets are implemented via markers in history so they are not part
of the states concept.

Abandoned changesets are not pushed or pulled (see the implementation
of local) but are not subject to garbage collection. 
Abandoned changesets are not pushed or pulled (see the implementation of local) but are not subject to garbage collection.
Line 220: Line 128:

To mark a branch as abandoned, use 'hg commit --abandon' to abandon
the working directory and its descendants.
To mark a branch as abandoned, use 'hg commit --abandon' to abandon the working directory and its descendants.
Line 225: Line 131:
Line 229: Line 134:

Old clients see abandoned changesets and their marker commits as
normal changesets.
Old clients see abandoned changesets and their marker commits as normal changesets.
Line 234: Line 137:

Obsolete changesets are part of an advanced concept ('changeset
evolution') used to automatically resolve and combine refactoring
operations between collaborators using liquid changesets. Like dead
changessets, these are also hidden, but obsolete markers are
implemented as pointers from X' (new changeset) to X (obsolete
changeset) so are again not part of the state concept.
Obsolete changesets are part of an advanced concept ('changeset evolution') used to automatically resolve and combine refactoring operations between collaborators using liquid changesets. Like dead changessets, these are also hidden, but obsolete markers are implemented as pointers from X' (new changeset) to X (obsolete changeset) so are again not part of the state concept.

States Plan

/!\ This page is intended for developers

A set of proposed Mercurial features to cleanly and safely handle mutable history.

1. Introduction

This page aims to define features connected with the 'liquid hg' discussion in enough detail that they can be fine-tuned and implemented.

They are intentionally presented in a proposed order of implementation.

2. Hidden changesets

Various features will require changesets to be hidden by default. So it makes sense to implement a centralized method of dealing with this property.

Usage:

Hidden changesets can be shown with the --hidden flag, eg 'hg log --hidden' will show all changesets.

Implementation:

The changelog object contains a _hidden set (using revision numbers) that log and other commands consult. To hide a changeset, add it to the set at startup. Contexts are given a .hidden() predicate that consults the set.

3. Changeset states

A 'changeset state' is an indicator that tells us how a changeset is manipulated and communicated. The details of each state is described below, here we describe their shared properties.

Like bookmarks, states are not stored in history and thus are not permanent and leave no audit trail.

First, no changeset can be in two states at once. States are also ordered, so they can be considered from lowest to highest. The default, lowest state is 'frozen' - this is the normal state of existing changesets. No child changeset can be in a lower state than its parents.

The proposed states are:

frozen < liquid < local < dead

These states share a hierarchy of traits:

mutable

unshared

hidden

GC-able

frozen

liquid

x

local

x

x

dead

x

x

x

x

These names are subject to change. Some of them have initials that collide with each other and with options like force and they don't have an obvious progression.

3.1. Usage

States are manipulated via the 'hg state' command, ie 'hg state -f x' to mark x as frozen. Each state puts its own constraints on how it can be manipulated. The current state of changesets is displayed in the log with a 'state:' header. The frozen state is not displayed at all.

There are corresponding revset predicates for each state as well.

3.2. Implementation

Contexts provide a state() method that returns the current state as a string. It may be useful to represent the frozen state with the empty string.

4. Frozen changesets

Frozen changesets are changesets that are considered permanently immutable. This matches the history model presented by legacy Mercurial: changesets cannot be changed or removed without using history editing features from extensions. This state can be thought of as 'published': once a changeset is published, it becomes very difficult to remove it from distributed history.

4.1. Usage

Changeset are moved to the frozen state via 'hg state --frozen X'.

4.2. Implementation

N/A

4.3. Legacy clients

N/A

5. Liquid changesets

Liquid changesets are changesets that the user is permitted to use history-modifying operations like rebase or mq on. They may not be tagged. They may also be thought of as 'unpublished'.

Various operations such as pushing to certain public servers will move changesets into the frozen state. Changesets cannot be moved from frozen to liquid without a forcing operation.

The liquidity of changesets can be communicated between compatible servers and clients. This allows people to collaborate on work in progress before it becomes finalized.

This should generally be engineered such that users don't have to give any additional thought to liquid vs frozen in their day-to-day usage.

5.1. Usage

Changesets must be in a liquid state when they are created. So new commits will start in a liquid state by default.

5.2. Implementation

The set of liquid changesets is stored as a list of liquid roots. All descendants of these roots are liquid (or in a higher state). This set is known as the 'liquid barrier' and defines the 'liquid set'. This barrier is intended only to advance.

The liquid barrier is communicated via the pushkey protocol to servers that support it. The client is responsible for advancing the barrier on both the client and server sides. On each operation, the client reduces the liquid set on both sides to the intersection of the sets on the client and server. That is, if a changeset is frozen on either side, it becomes frozen on both sides.

Some servers are configured as 'publishing servers'. Legacy servers are publishing servers by default. These are recognized by not having the 'liquid' pushkey namespace. When pushing to a publishing server, all pushed changesets are moved into the frozen state on the client. Similarly, all changesets pulled from a publishing server are treated as frozen.

5.3. Legacy clients

See above for pushing to legacy clients. Legacy clients are allowed to pull liquid changesets, though a round trip will make them frozen.

6. Local changesets

Local changesets are changesets that are not visible to remote clients. This is useful to mark work private and to avoid inadvertently publishing changesets.

6.1. Usage

Local changesets (and their descendents) can be marked with 'hg state --local'.

6.2. Implementation

Like liquid changesets, local changesets are implemented via a local barrier set. This set is used to filter changesets from remote clients for push/pull/hgweb. This is probably best implemented via a _local set on changelog.

6.3. Legacy clients

Legacy clients cannot see local changesets so will not pull them. New clients will not push local changesets by default

7. Dead changesets

Dead changesets are changesets that are hidden and are eligible for garbage collection.

Dead changesets themselves are never pushed or pulled between clients (they are a subset of local) but deadness of changesets can be communicated between clients.

If a client has a dead changeset X and happens to pull a remote changeset Y that is a descendant of it, changeset X becomes liquid or frozen as appropriate.

Garbage collection consists of stripping all dead changesets. When garbage collection occurs is currently undefined.

7.1. Usage

Commits (and their descendents) can be manually marked dead with 'hg state --dead'. Some operations like strip, qpop, and rebase may choose to mark changesets dead rather than actually stripping them.

7.2. Implementation

The dead set is stored as a complete list of all revisions. This allows dead status to be propagated after garbage collection occurs. Dead status is communicated via pushkey.

7.3. Legacy clients

Like local changesets, old clients cannot see dead changesets.

8. Abandoned changesets

Abandoned changesets are changesets that have been marked as 'no longer relevant'. Like dead changesets, they are hidden, but abandoned changesets are implemented via markers in history so they are not part of the states concept.

Abandoned changesets are not pushed or pulled (see the implementation of local) but are not subject to garbage collection.

Abandoned changesets can be unabandoned by committing new descendants.

8.1. Usage

To mark a branch as abandoned, use 'hg commit --abandon' to abandon the working directory and its descendants.

8.2. Implementation

The abandon commit contains an explicit list of abandoned changesets.

8.3. Legacy clients

Old clients see abandoned changesets and their marker commits as normal changesets.

9. Obsolete changesets

Obsolete changesets are part of an advanced concept ('changeset evolution') used to automatically resolve and combine refactoring operations between collaborators using liquid changesets. Like dead changessets, these are also hidden, but obsolete markers are implemented as pointers from X' (new changeset) to X (obsolete changeset) so are again not part of the state concept.


CategoryDeveloper

StatesPlan (last edited 2012-01-12 00:40:09 by Pierre-YvesDavid)