Differences between revisions 20 and 52 (spanning 32 versions)
Revision 20 as of 2016-02-19 14:35:37
Size: 8407
Comment: changed stage name (because "fuzzy") before deeper rewrite and added link to related concept.
Revision 52 as of 2020-05-29 08:03:48
Size: 16015
Editor: aayjaychan
Comment: Fixed link
Deletions are marked like this. Additions are marked like this.
Line 3: Line 3:
Line 5: Line 6:
{i} For a user perspective see ChangesetEvolution.
Line 7: Line 10:
For a user perspective have a look at the ChangesetEvolution page.
Line 10: Line 11:
The simplest way to help is to grab one of: [[http://bz.selenic.com/buglist.cgi?keywords=easy,%20&keywords_type=anywords&order=Bug%20Number&resolution=---&query_format=advanced&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE&bug_status=IN_PROGRESS&component=evolution&list_id=5014|list of easy bug]] The simplest way to help is to grab one of: [[https://bz.mercurial-scm.org/buglist.cgi?keywords=easy,%20&keywords_type=anywords&order=Bug%20Number&resolution=---&query_format=advanced&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE&bug_status=IN_PROGRESS&component=evolution&list_id=5014|list of easy bug]]
Line 18: Line 19:
 * [[ObsolescenceMarkersExchange|Obsolescence markers exchange]] (no really we have idea waiting to be implemented)  * [[CEDObsmarkersExchange|Obsolescence markers exchange]] (no really we have idea waiting to be implemented)
Line 41: Line 42:
Current status:

 * (./) Alpha Stage,
 * {X} Beta Stage,
 * {X} Release Stage,

=== Stage A ===
Changeset Evolution is currently at Alpha Stage. If won't eat people data, but only handful of people knowns how to get out some situation..

=== Stage B ===
At beta state, the UI and experience will not be easy/pleasant enough for normal user, but advance user of Mercurial should find their mark. We may consider shipping it with Core Mercurial with an experimental flag.

Blocker to beta release:

 * Obsmarkers exchange should be good enough to define a final storage format for markers.

 * On disk format should be stable in the foreseeable future and fit performance//exchange need.

 * Evolve should be able to solve (or provide a way to) all troubles that a user may encounter, especially divergence,

 * Evolve should have predictable result (--rev options and co),

 * Evolve should be abortable (wide transaction),

 * Performance impact should be ''reasonable'',

=== Release Stage ===
A which point we can merge changesets evolution into core.

 * UI offering a Solution to the N² markers creation when editing history (TopicPlan),

 * Commands set defined enough to be freezed for backward compatibility

 * No race condition when exchanging with server ''(bundle2 + repo layout allowing atomic transaction)'',

 * No impactful Performance Regression (including efficient exchange),

 * Concrete plan to handle high volume of markers (archiving or something),

=== Related Concept ===

See [[CEDRoadMap]]

== Overall concept ==

See [[CEDConcept]]

== Related Concept ==
Line 92: Line 61:
 * PlanHistoryRewritePlan: Factorise and empower all the common history rewriting operation,
Line 95: Line 65:
== In progress Features == == In progress Features and discussion ==
Line 116: Line 87:
== Archived Topic ==
=== Obsstore Format ===
Markers are stored in an append-only file stored in '.hg/store/obsstore'.

==== V1 (current) Format ====
(see in line document for latest data)

===== quick summary =====
 * <number-of-successors(=N)><metadata-lenght(=M)><bits-field><precursor>(<successor>*N)<metadata>

 * B, I, B, 20s, (20s*N), s*M

===== longer explanation =====
The file starts with a version header:

 * 1 unsigned byte: version number, starting at zero.

The header is followed by the markers. Each marker is made of:

 * 1 unsigned byte: number of new changesets "N", can be zero.

 * 1 unsigned 32-bits integer: metadata size "M" in bytes.

 * 1 byte: a bit field. It is reserved for flags used in common
  . obsolete marker operations, to avoid repeated decoding of metadata entries.

 * 20 bytes: obsoleted changeset identifier.

 * N*20 bytes: new changesets identifiers.

 * M bytes: metadata as a sequence of nul-terminated strings. Each
  . string contains a key and a value, separated by a colon ':', without additional encoding. Keys cannot contain '\0' or ':' and values cannot contain '\0'.

==== V2 (current) Format ====
===== motivation =====
There is two extra information we would like to see in a second version of the format:

 * date: There is currently *always* a date in the meta data. So storing it explicitly would be more space efficient. It would also open the way to quickly access the date for sorting purpose (no use case yet but not crazy to think about it)

 * parents: When a changesets is pruned (obsoleted, no successors) we needs to records its parents. This is necessary to link the markers chain to the push/pull operation it is relevant to.

 * We may want to extend the bit field to 2 bytes. We currently use 1 and can see use case for 3-5 others (tracking the type of changes introduce by the rewriting (desc, patches, content, etc) so we are running short

 * We may also want to explicitly store the username of the marker's creator are they will always be ones. however there is no need for quick access of such information so it could stay in the metadata field.

===== possible change =====
'''Date''':

 * The date will be a 64bits float (for seconds since epoch) followed by a 16 bits integer (time zone)

 * It will make sense to put the date in front of the markers. that would give markers sorting some semantic.

'''Parents''':

We have multiple option for storing parents:

 1. Having an explicite field similar to successors (one byte to know how many parents, then parents)

 1. Having an explicite field but store the number of parent in the bit fields (since we never have more than 2 parents)

 1. Using the successors field. Having negative number of successors mean it is a prune.

Option (3) is the most space saving but prevent use to store parent information for more changesets if needed in the future (We do not have a final exchange plan yet).

Option (1) and (2) takes 2 to 8 bits more than (3) but are more flexible.

'''bit field'''

If we extend the bit field to 2 Bytes, it makes sense to use option (2) for storing parent.

===== Proposed Format =====
 * <date><timezone><number-of-successors(=N)><metadata-lenght(=M)><bits-field+nb-parents(=P)><precursor>(<successor>*N)(<parents>*P)<metadata>

 * d, h, B, I, H, 20s, (20s*N), (20s*P), s*M

The P number would be hidden in the bit field. We need to store 4 possible values here: 0 parents, 1 parent, 2 parents, ø parents information stored. Possible assignement is 00, 01, 10, 11. this let both 0 parent and ø parent info to be 0 module 3.
=== `hg evolve --list` ===

This is also tracked in [[https://bz.mercurial-scm.org/show_bug.cgi?id=4845|https://bz.mercurial-scm.org/show_bug.cgi?id=4845]]

Evolution can compute a lot of information out of the obsolescence graph. It
already use it to compute troubles and automatically solve them. Yet this
information is not easily accessible to the user.

We would like to gain a basic version of `hg evolve --list` that would provide
all available information on current troubles.

==== Output Proposal ====

  CHANGESET
   - TROUBLE: REASON
   - TROUBLE: REASON
  CHANGESET
   - TROUBLE: REASON

More concrete example:

5633576f2df1: unbundle: cleanly abort on unknown ...
  unstable: parent 485eb2a02a2b is obsolete
  bumped: precursors ec2662b9629d is public
  divergent: precursors 4a8e21578e14 have another succcessor 84dcc37b1272
  divergent: precursors 4a8e21578e14 have another succcessor 2a3010ba6f52

We want to ensure this is implemented through the 'formatter' API so we gain
structured output easily "eg -Tjson"

==== Command Line API ====

We probably want

 * `--rev` to allow select revision to display
 * `--unstable`/`--bumped`/`divergent` to restrict the trouble we display.

==== Details on Each Trouble Cases ====

Here is some idea for data we could provide in each cases. This provide an handy
list of case in the process.

===== Unstable from Obsolete Parent =====

 * reason: unstability comes from parent being obsolete
 * Source: What is this obsolete parent,
 * Evolution target: What the evolution will turn the parent into (beware of pruned changeset)
 * We should mention problematic split,

===== Unstable from Unstable Parent =====

 * reason: unstability comes from parent being unstable
 * Source: What is this unstable parent,
 * parent needs to be evolved before that one.

===== Unstable Merge =====

 * If both parent have obsolescence/troubles, we must issue two entries

===== Bumped Changeset =====

 * Point at the public changeset
 * Mention if we need a rebase or not
 * ADVANCE: Is there a commit message change

===== Divergent Changeset =====

 * Point at the other divergent changeset
 * Point at the "greater common evolution ancestors" of divergence
 * Says if this GCEA is known locally
 * Point "greater locally known common evolution ancestors" in addition
   otherwise.
 * mention if we need a rebase or not,
 * The "divergent with a split" case…

===== Divergent with the other side public =====

This is actually one of the most common divergence scenario. '''We probably need
a dedicated name for this'''.

 * We should mention that the other side is public/immutable.

===== Visible Obsolete Changeset =====

Should list them with a mention of why they are still visible?

=== obsmarker support in `hg strip` ===

We would like to be able to strip obsolescence marker related to a changeset
when stripping it.

We want:

 * (some) way to disable it ("nice way" can come later),
 * the obsmarker to be in the backup bundle,
 * A mode where we strip all markers between the stripped one and first known
   precursors (default?)
 * A mode where we strip all precursors too (and associated markers) (beware of
   untargeted descendant of precursors, cf drophack).

The "obsmarker in the backup bundle" will requires some work because there is no
other place storing obsmarkers in an on disk bundle. However, all infra should
be in place as we already exchange obsmarker over the wire through a bundle.

In the same go, you can consider adding obsmarker support to `hg bundle` through
the "variants" part of the type.

=== `hg evolve --continue/--abort/--drop` ===

Currently evolve implement a super basic state format that does not allow a
proper "multi step" behavior.

==== About `--continue` ====

Current issues

 * does not remember the currently evolved set (just finish the current one)
 * does not work for `--bumped` or `--divergent`

We need to update the format on disk to allow these.

==== About `--abort` ====

This does not exists but it would be useful.

 * We need to know the evolved set,
 * We must also record and remove obsmarker we created in the process.

==== About `--drop` ====

Currently, user can "abandon" his evolve at any time. leaving half of the thing
evolved and the other one still unstable. That is a pretty cool feature we want
a way to keep. Adding a flag could be a way. openning the way to similar feature
in other multi step command.

Name is not frozen, this is the first time we mention it.

Maybe we just want `hg up -C` to be that, but it seems a bit too easy to run by
mistake.

=== Tagging draft changeset ===

Currently tagging draft a changeset may lead to issues when the tagged changeset is rewritten and its hash change, making the tag invalid.

Here is a small (draftish) list of ideas to handle the question, the first one "rewriting the tag file when we evolve/rewrite the tagging changeset" is probably the way to go.

Mailing list discussion about this: https://www.mercurial-scm.org/pipermail/evolve-testers/2016-May/000178.html

==== rewriting the tag file when we evolve/rewrite the tagging changeset ====

When the tagging changeset is evolved (changed from a descendant of the old tagged, to the new version), we could rewrite the content of the tag file.

Pro:

 * Does "the right thing"™
 * Works even if the tagged changeset is pulled -after- the rewrite.

Cons:

 * Only work when the tagging changeset is a descendant of the tagged,
 * Does not handle the local case.

==== Warn when pushing a draft tag ====

The idea is that pushing a tagged changeset as draft increase the risk of rewrite, so warning could help having user think about turning them public.

Pro:

 * easy to do,
 * can be reverted when we need something better,
 * prevent the error to pass silently,

Cons:

 * Does not actually solve the problem,
 * Does not handle the local case.

==== Warn when rewriting a draft tag ====

Pro:

 * easy to do,
 * can be reverted when we need something better,
 * prevent the error to pass silently,

Cons:

 * Does not actually solve the problem,

==== Turning the changeset public on tagging ====

Pro:

 * Prevent any tag rewrite issue,
 * easy to do,
 * handle both local and remote case,

Cons:

 * loose the ability to fix tagging error before publishing,
 * break backward compatibility,
 * hard to revert if we get something better,

==== Turn the tagged changesets public on push ====

Pro:

 * Turn changeset public at the time it become more complicated,

Cons:

 * loose the ability to fix tagging error before publishing,
 * break backward compatibility for non-publishing repo,
 * hard to revert if we get something better,
 * do not handle the local case.

==== refuse to tag draft ====

Pro:

 * Get rid of the issue (almost) entirely,
 * handle local and remote case,

Cons:

 * massive backward compatibility breakage, sensible user script will break,
 * hard to revert if we get something better

=== Obsolescence Marker Discovery ===

 * See dedicated page: ObsolescenceMarkersExchange

=== amend/uncommit/recommit/etc ===

A recurring discussion is "What should be 'base' for the 'amend' operation" (or other related command).

The complexity of the situation comes from the fact we have 3 states of interest

 1. `wc()`: The working copy content (on disk file)
 2. `p1()`: The working copy parent content (commit content, affected by commands)
 3. `p1()~1`: The working copy parent (commit content).

Various core command already allow to interact with these layers.

* The `commit` command move content from `wc()` to `p1()` (creating a new `p1()`) in the process),
* The `commit --amend` is just a variation of that moving content from `wc()` to `p1()` (reusing the existing one).
* The `revert` command move content from `p1()` to `wc()`
* The `revert --rev` command move content from any commit content to `wc()`

Evolve have various commands in this area too.

* The `amend` command mimic `commit --amend`, moving content from `wc()` to `p1()`
* The `uncommit` command move content from `p1()~1` to `p1()`.

A common question is to change the default of `amend` to use `p1()~1` as base. Picking change from `wc()` when selected and resetting to `p1()~1` for excluded content. "Just changing the default" is not a solution here. We have multiple possibilities (because we have 3 states to select from) and if we change from one to the other, some people will just start asking for the other one instead.CategoryNewFeatures

However, having an easy way to select the mode would be nice, gather all usecase into a single command would be preferable. Building a good UI for that might allow us to remove the dedicated `uncommit` command and provide a `recommit` capabilities that people have been asking for.

=== Record types of operation ===

Storing more information about what the type of rewrite in obsolescence markers would be useful. The idea is to leverage the bitfield in the markers to record various kind of actions.

==== Recorded actions ====

 * did the "diff" changed, (eg: amend)
 * did the parent changed, (eg: rebase, but not plain evolve)
 * did the commit message got edited,
 * did the changeset metadata got rewritten.

And probably these extra data too:

 * is the changeset purely identical to another (rewind),
 * is the rewrite part of a fold.

The various edition command will be responsible for adding useful information:

 * a `hg amend` that update the diff will create a markers recording the "content changes",

 * a `hg amend -e` that only update he commit message will record the "message change",

 * a `hg rebase` will record the "parent change",

 * a `hg amend` that update the message, the content and user will record these three things (content, message and meta changes).

 * `hg histedit` would record the right operation according the the action.

==== Advantages ====

 * '''Compact''': Since we use the (existing) bitfield, the storage cost is free (or minimal if we need to adds an extra Byte of bitfield). Accessing the data is also very cheap:


 * '''Compoundable''': We'll often needs to combine multiple markers to reports changesets between two revisions (eg: we do not have the intermediate revision locally). the bit approach makes it trivial to compound the information. We can display display the same final information when the same result if obtained from different path (eg: from two markers `[content change; message change]` or from one markers `[content change | message change]`).


 * '''UI Abstraction''': since we record the "effect" information, we abstract the command names. This makes use more agile about the actual UI. User can use their own "hg myownrewritetool" command and still record information useful for the other users.

==== Usage ====

Having that data will help providing information about the obsolescence history. Example:

{{{

     @ ac28e3 durham
    / First commit
   |
   | o d4afe7 durham
   | | Second commit
   | |
   | x 8e9a5d (Amended as ac28e3) durham
   |/ First commit
   |
}}}


== See Also ==

 * entry points: [[http://bz.mercurial-scm.org/buglist.cgi?keywords=easy,%20&keywords_type=anywords&order=Bug%20Number&resolution=---&query_format=advanced&bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE&bug_status=IN_PROGRESS&component=evolution&list_id=5014|list of easy bug]]
 * contributing: [[https://bz.mercurial-scm.org/buglist.cgi?bug_status=UNCONFIRMED&bug_status=CONFIRMED&bug_status=NEED_EXAMPLE&bug_status=IN_PROGRESS&component=evolution&keywords_type=anywords&list_id=9370&order=Bug%20Number&query_format=advanced&resolution=---|list of all issues]]
 * User: ChangesetEvolution
 * Planning: [[CEDRoadMap|Road Map]]
 * Core Concept: [[CEDConcept|Concept and important sub-issue]]
 * Interface: [[ChangesetEvolutionDevelUI|Generic user interface discussion]]
 * Vabulary: [[CEDVocabulary|How should we name things]]
 * Exchange: [[CEDObsmarkersExchange|Information about obsolescence markers exchange and discovery]]
 * Rebase: [[CEDRebase|Behavior with "hg rebase"]]
 * Cycles: [[CEDCycles|Handling of cycle in the obsolescence markers]]
 * Format: [[CEDObsstoreFormat|Archived page about the "obsstore" format]]


----
CategoryNewFeatures CategoryDeveloper CategoryEvolution

Changesets Evolution - development page.

/!\ This page is intended for developer

{i} For a user perspective see ChangesetEvolution.

1. Contributing

The simplest way to help is to grab one of: list of easy bug

There is also a multiple well defined topic that where idea exist but needs an implementation

  • Rebase could make more use of obsolescence marker:
    • detection that part of the rebase set is already in the destination
    • warning about divergence creation.
  • Obsolescence markers exchange (no really we have idea waiting to be implemented)

  • Prototype for a command bringing changeset back to life.

There is more complicated part that requires attention too.

  • Better storage//loading//cache for markers (depends on marker exchange)

  • Solving the problem of Topic Branch

  • Handling moving changesets around with the "plan" concept,
  • in memory merge (helps a lot of troubles resolution throught evolve)

  • Wide transaction capability
    • Continue/stop/abort for all command including evolve
    • In transaction content non exchangeable.
  • Making evolve capable of solving all troubles that user can encounter
  • Computing UI message about troubles from event who happened during the transaction.

2. Roadmap

See CEDRoadMap

3. Overall concept

See CEDConcept

Other concept not directly involved in Changeset Evolution and closely related for technical or user experience reason.

5. In progress Features and discussion

5.1. Using Obsolescence Marker during Rebase

There is two big issues with rebasing a set containing obsolescence changeset:

  • It is easy to create divergence
  • You get a lot of conflict when rebasing an obsolete stack on it's successors version.

To enable the current implementation set the config experimental.rebaseskipobsolete to true.

Current progress:

  • (./) rebase can skip obsolete changeset when rebased on successors,

  • (./) same logic as above, handling prune,

  • (./) same logic as above, handling split,

  • (./) ability to detect divergence creation and bail out,

  • {X} ability to rebase set with obsolescence inside the set (rebasing both precursors and successors) without creating divergence,

  • {X} official config to control these two behavior (either in one or two config)

  • {X} config on by default.

5.2. `hg evolve --list`

This is also tracked in https://bz.mercurial-scm.org/show_bug.cgi?id=4845

Evolution can compute a lot of information out of the obsolescence graph. It already use it to compute troubles and automatically solve them. Yet this information is not easily accessible to the user.

We would like to gain a basic version of hg evolve --list that would provide all available information on current troubles.

5.2.1. Output Proposal

  • CHANGESET
    • - TROUBLE: REASON - TROUBLE: REASON
    CHANGESET
    • - TROUBLE: REASON

More concrete example:

5633576f2df1: unbundle: cleanly abort on unknown ...

  • unstable: parent 485eb2a02a2b is obsolete bumped: precursors ec2662b9629d is public divergent: precursors 4a8e21578e14 have another succcessor 84dcc37b1272 divergent: precursors 4a8e21578e14 have another succcessor 2a3010ba6f52

We want to ensure this is implemented through the 'formatter' API so we gain structured output easily "eg -Tjson"

5.2.2. Command Line API

We probably want

  • --rev to allow select revision to display

  • --unstable/--bumped/divergent to restrict the trouble we display.

5.2.3. Details on Each Trouble Cases

Here is some idea for data we could provide in each cases. This provide an handy list of case in the process.

5.2.3.1. Unstable from Obsolete Parent
  • reason: unstability comes from parent being obsolete
  • Source: What is this obsolete parent,
  • Evolution target: What the evolution will turn the parent into (beware of pruned changeset)
  • We should mention problematic split,

5.2.3.2. Unstable from Unstable Parent
  • reason: unstability comes from parent being unstable
  • Source: What is this unstable parent,
  • parent needs to be evolved before that one.

5.2.3.3. Unstable Merge
  • If both parent have obsolescence/troubles, we must issue two entries

5.2.3.4. Bumped Changeset
  • Point at the public changeset
  • Mention if we need a rebase or not
  • ADVANCE: Is there a commit message change

5.2.3.5. Divergent Changeset
  • Point at the other divergent changeset
  • Point at the "greater common evolution ancestors" of divergence
  • Says if this GCEA is known locally
  • Point "greater locally known common evolution ancestors" in addition
    • otherwise.
  • mention if we need a rebase or not,
  • The "divergent with a split" case…

5.2.3.6. Divergent with the other side public

This is actually one of the most common divergence scenario. We probably need a dedicated name for this.

  • We should mention that the other side is public/immutable.

5.2.3.7. Visible Obsolete Changeset

Should list them with a mention of why they are still visible?

5.3. obsmarker support in `hg strip`

We would like to be able to strip obsolescence marker related to a changeset when stripping it.

We want:

  • (some) way to disable it ("nice way" can come later),
  • the obsmarker to be in the backup bundle,
  • A mode where we strip all markers between the stripped one and first known
    • precursors (default?)
  • A mode where we strip all precursors too (and associated markers) (beware of
    • untargeted descendant of precursors, cf drophack).

The "obsmarker in the backup bundle" will requires some work because there is no other place storing obsmarkers in an on disk bundle. However, all infra should be in place as we already exchange obsmarker over the wire through a bundle.

In the same go, you can consider adding obsmarker support to hg bundle through the "variants" part of the type.

5.4. `hg evolve --continue/--abort/--drop`

Currently evolve implement a super basic state format that does not allow a proper "multi step" behavior.

5.4.1. About `--continue`

Current issues

  • does not remember the currently evolved set (just finish the current one)
  • does not work for --bumped or --divergent

We need to update the format on disk to allow these.

5.4.2. About `--abort`

This does not exists but it would be useful.

  • We need to know the evolved set,
  • We must also record and remove obsmarker we created in the process.

5.4.3. About `--drop`

Currently, user can "abandon" his evolve at any time. leaving half of the thing evolved and the other one still unstable. That is a pretty cool feature we want a way to keep. Adding a flag could be a way. openning the way to similar feature in other multi step command.

Name is not frozen, this is the first time we mention it.

Maybe we just want hg up -C to be that, but it seems a bit too easy to run by mistake.

5.5. Tagging draft changeset

Currently tagging draft a changeset may lead to issues when the tagged changeset is rewritten and its hash change, making the tag invalid.

Here is a small (draftish) list of ideas to handle the question, the first one "rewriting the tag file when we evolve/rewrite the tagging changeset" is probably the way to go.

Mailing list discussion about this: https://www.mercurial-scm.org/pipermail/evolve-testers/2016-May/000178.html

5.5.1. rewriting the tag file when we evolve/rewrite the tagging changeset

When the tagging changeset is evolved (changed from a descendant of the old tagged, to the new version), we could rewrite the content of the tag file.

Pro:

  • Does "the right thing"™
  • Works even if the tagged changeset is pulled -after- the rewrite.

Cons:

  • Only work when the tagging changeset is a descendant of the tagged,
  • Does not handle the local case.

5.5.2. Warn when pushing a draft tag

The idea is that pushing a tagged changeset as draft increase the risk of rewrite, so warning could help having user think about turning them public.

Pro:

  • easy to do,
  • can be reverted when we need something better,
  • prevent the error to pass silently,

Cons:

  • Does not actually solve the problem,
  • Does not handle the local case.

5.5.3. Warn when rewriting a draft tag

Pro:

  • easy to do,
  • can be reverted when we need something better,
  • prevent the error to pass silently,

Cons:

  • Does not actually solve the problem,

5.5.4. Turning the changeset public on tagging

Pro:

  • Prevent any tag rewrite issue,
  • easy to do,
  • handle both local and remote case,

Cons:

  • loose the ability to fix tagging error before publishing,
  • break backward compatibility,
  • hard to revert if we get something better,

5.5.5. Turn the tagged changesets public on push

Pro:

  • Turn changeset public at the time it become more complicated,

Cons:

  • loose the ability to fix tagging error before publishing,
  • break backward compatibility for non-publishing repo,
  • hard to revert if we get something better,
  • do not handle the local case.

5.5.6. refuse to tag draft

Pro:

  • Get rid of the issue (almost) entirely,
  • handle local and remote case,

Cons:

  • massive backward compatibility breakage, sensible user script will break,
  • hard to revert if we get something better

5.6. Obsolescence Marker Discovery

5.7. amend/uncommit/recommit/etc

A recurring discussion is "What should be 'base' for the 'amend' operation" (or other related command).

The complexity of the situation comes from the fact we have 3 states of interest

  1. wc(): The working copy content (on disk file)

  2. p1(): The working copy parent content (commit content, affected by commands)

  3. p1()~1: The working copy parent (commit content).

Various core command already allow to interact with these layers.

* The commit command move content from wc() to p1() (creating a new p1()) in the process), * The commit --amend is just a variation of that moving content from wc() to p1() (reusing the existing one). * The revert command move content from p1() to wc() * The revert --rev command move content from any commit content to wc()

Evolve have various commands in this area too.

* The amend command mimic commit --amend, moving content from wc() to p1() * The uncommit command move content from p1()~1 to p1().

A common question is to change the default of amend to use p1()~1 as base. Picking change from wc() when selected and resetting to p1()~1 for excluded content. "Just changing the default" is not a solution here. We have multiple possibilities (because we have 3 states to select from) and if we change from one to the other, some people will just start asking for the other one instead.CategoryNewFeatures

However, having an easy way to select the mode would be nice, gather all usecase into a single command would be preferable. Building a good UI for that might allow us to remove the dedicated uncommit command and provide a recommit capabilities that people have been asking for.

5.8. Record types of operation

Storing more information about what the type of rewrite in obsolescence markers would be useful. The idea is to leverage the bitfield in the markers to record various kind of actions.

5.8.1. Recorded actions

  • did the "diff" changed, (eg: amend)
  • did the parent changed, (eg: rebase, but not plain evolve)
  • did the commit message got edited,
  • did the changeset metadata got rewritten.

And probably these extra data too:

  • is the changeset purely identical to another (rewind),
  • is the rewrite part of a fold.

The various edition command will be responsible for adding useful information:

  • a hg amend that update the diff will create a markers recording the "content changes",

  • a hg amend -e that only update he commit message will record the "message change",

  • a hg rebase will record the "parent change",

  • a hg amend that update the message, the content and user will record these three things (content, message and meta changes).

  • hg histedit would record the right operation according the the action.

5.8.2. Advantages

  • Compact: Since we use the (existing) bitfield, the storage cost is free (or minimal if we need to adds an extra Byte of bitfield). Accessing the data is also very cheap:

  • Compoundable: We'll often needs to combine multiple markers to reports changesets between two revisions (eg: we do not have the intermediate revision locally). the bit approach makes it trivial to compound the information. We can display display the same final information when the same result if obtained from different path (eg: from two markers [content change; message change] or from one markers [content change | message change]).

  • UI Abstraction: since we record the "effect" information, we abstract the command names. This makes use more agile about the actual UI. User can use their own "hg myownrewritetool" command and still record information useful for the other users.

5.8.3. Usage

Having that data will help providing information about the obsolescence history. Example:

     @  ac28e3  durham
    /   First commit
   |
   | o  d4afe7 durham
   | |  Second commit
   | |
   | x  8e9a5d (Amended as ac28e3)  durham
   |/   First commit
   |

6. See Also


CategoryNewFeatures CategoryDeveloper CategoryEvolution

ChangesetEvolutionDevel (last edited 2020-05-29 08:03:48 by aayjaychan)