Mercurial > evolve
view docs/troubles-handling.rst @ 6910:038df334d51a mercurial-6.0
test-compat: merge mercurial-6.1 into mercurial-6.0
author | Anton Shestakov <av6@dwimlabs.net> |
---|---|
date | Fri, 25 Oct 2024 15:50:15 +0400 |
parents | 43a5371fa669 |
children |
line wrap: on
line source
########################################################### Possible troubles in rewriting history and their resolution ########################################################### .. Copyright 2020 Sushil Khanchi <sushilkhanchi97@gmail.com> .. Octobus SAS <contact@octobus.net> Rewriting history, and especially rewriting draft history that have been exchanged can lead to "unstable" situation. This document is intended for developer of the changeset evolution concept. It cover through the technical aspects of each "instability" a changeset can get into. It aims at building an exhaustive list of each cases and sub-cases and the status of automatic resolution for these cases. Public changeset are part of the permanent history and are never considered unstable. .. contents:: :depth: 4 ****** Orphan ****** Basics ====== A changeset is orphan when there is at least one obsolete ancestor. As a resolution, we need to find a new appropriate parents for the changeset and rebase the orphan there. If the parents of an orphan changeset are orphan themself, they will have to be "stabilised" fist. Cause of trouble ================ Orphan can appears because the user locally rewrite changeset with descendants. In this case the orphan are created when the command run. They are few real use case for such action and the user interface should focus on discouraging it. Orphan can also happens when the users created new changeset on draft that got rewritten in another repository. The orphan are then "discovered" when the obsolescence information of the ancestors is pulled in the local repository. This is the most common way to create phase divergences. Source of Complexity ==================== There can be different situations we need to take care of when dealing with resolution of an orphan changeset, like: * parents might not be obsolete (yet) and orphan themself. They will need to be resolved first. * obsolete parent has conflicting rewrites (content-divergence), so there might not be an obvious "good spot" to rebase the changeset too. * obsolete parent could have been prune, so it has not direct successors, * obsolete parent was split in multiple changesets. This comes with multiple variants: * successors could be linear of spread across multiple branches, * successors could have been reordered after the initial split, * Some of the successors could have been pruned. * the orphan changeset can be a merge and orphan may come any numbers of parents * rebasing might lead to conflict. Details of Sub cases ==================== .. contents:: :local: O-A: Linear changeset (one parent) ---------------------------------- O-A1: parent has a single successors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Stabilisation Strategy** Solution is Clear. Relocate the orphan changeset onto the single successor of obsolete parent. **Current Support Level** Good: current implementation is expected to perform the planned stabilisation. O-A2: parent is pruned (no successors) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Find nearest "not-pruned" ancestor and treat it (or its successor, if apply) as a resolution parent. (re-run Orphan resolution starting from these parent). In some cases, there can be multiple "not-pruned" ancestor and it could be ambiguous for us to decide which one to pick. O-A2.1: set of "not-pruned" ancestor has single head """""""""""""""""""""""""""""""""""""""""""""""""""" **Stabilisation Strategy** This comes under `O-A3` and `O-A4` cases (since we re-run orphan resolution assuming "not-pruned" ancestor as parent) **Current Support Level** Good: current implementation is expected to perform the planned stabilisation. O-A2.2: set of "not-pruned" ancestor has multiple heads """"""""""""""""""""""""""""""""""""""""""""""""""""""" If a merge is pruned, we have multiple "not-pruned" ancestor for its immediate child to stabilise. **Stabilisation Strategy** XXX: yet to decide resolution **Current Support Level** O-A3: parent has multiple successors sets (divergence case) ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Stabilisation Strategy** XXX: yet to decide resolution **Current Support Level** O-A4: parent is split into multiple successors ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ O-A4.1: successors of parent are all on the same topological branch """""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" **Stabilisation Strategy** Pick highest one as resolution parent. **Current Support Level** Good: current implementation is expected to perform the planned stabilisation. O-A4.2: parent is split into multiple topological branches (at least 2 heads) """"""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""""" In this case, the destination can be ambiguous. **Stabilisation Strategy** prompt user to choose one. (could we do better in some case?) **Current Support Level** Current implementation is expected to perform the planned stabilisation. O-M: Parent are Merge (multiple parent) --------------------------------------- O-M1: Only one parent is obsolete ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XXX Simple case are probably as good as any `O-A` case. However special case are probably ignored right now (e.g: successors of the obsolete parent is linear with the other parent). O-M2: both parent are obsolete ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XXX currently we evolve one after the other. **************** Phase-Divergence **************** Basics ====== It appears when a rewritten changeset got published. A phase-divergent changeset has a public predecessor. Solving phase divergence is done by extracting the changes made between the public predecessors and the latest evolution of the changesets into a new changesets, descendants of the public predecessors. Cause of trouble ================ It can appear if a user locally change the phase of an obsolete changeset (which has successors) to public. Phase-divergence can also happens when the users rewrite draft changeset that got published in another repository. The phase divergence then "discovered" when the publishing information of the predecessors is pulled in the local repository. Source of Complexity ==================== * public version is a merge * phase-divergent changeset is a merge * public version was split (linear, over multiple topo branches, etc…) * phase-divergent version was folded with others * rebasing might lead to conflict. Details of Sub cases ==================== .. contents:: :local: #TODO: yet to document ****************** Content-Divergence ****************** Basics ====== Independent rewrites of same changeset leads to content-divergence. So an obsolete changeset have multiple "sets" of successors. And the content-divergent changeset have some predecessors in common without the situation being the result of a split. To stabilise the situation, we need to "merge" the changes introduced in each side of the divergence and create a new changeset, that will supersede both of the unstable one. The merged information can be both about file content and metadata (author, parent, etc). In practice there are a lot of corner case where this is "not that simple". Cause of trouble ================ It can appear locally if a user independently rewrite the same changeset multiple times. Content-divergence can also happens when the users rewrite draft changesets that got rewritten in another repository as well. The content divergence then "revealed" when the rewriting information is shared (pulled/pushed) with another repository. Source of Complexity ==================== Before we perform a 3-way merge between the divergent changesets and common predecessor (which acts as the 3-way merge base), there are some situations we need to take care of, like: * if divergent changesets moved, check which side moved in which direction, and proceed accordingly * they moved on different unrelated branches * divergent changeset can be orphan as well * one side of divergence is in public phase * divergent changeset is part of a split or fold Details of resolution ===================== Resolution of content-divergence can be understand by dividing it in stages: Special case: If one of the divergent changeset is part of a split or fold, we don't handle it right now. But when we are going to support it, it will probably have its own logic and seperate from generic resolution. Generic resolution: The first stage of solving content-divergence is to find the changeset where the resolution changeset will be based on (which we call the resolution parent or the target parent) and relocate the divergent changesets on the resolution parent, if apply. In second stage, we deal with merging files of two divergent changesets using the 3-way merge. In third stage, we deal with merging the metadata changes and creating the resultant changeset. Details of Sub cases ==================== .. contents:: :local: D-S: One of the divergent changeset is part of a split or fold -------------------------------------------------------------- XXX: yet to decide resolution D-A: Finding the resolution parent ---------------------------------- This section is responsible to decide where the resultant changeset should live. If it's unable to find the resolution parent, we abort the content-divergence resolution. Following are the possible situations between the two divergent changesets and current support for each situation. D-A1: one of the divergent changeset is public ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Set the parent of public changeset as resolution parent. Note: After we resolve content-divergence in this case, the resultant changeset will be phase-divergent with the public side; so then we resolve phase-divergence to completely resolve the instability. D-A2: both are on the same parent ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ Set the parent (or its successor, if apply) as resolution parent. D-A3: both are on different parents ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ D-A3.1: one side moved """""""""""""""""""""" Set the parent of moved changeset as resolution parent. Special-case: When parent of moved one is obsolete with a successor ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' By default, evolution will set the successor of obsolete parent as resolution parent and will relocate both the divergent cset on it to perform 3-way merge. But if the following config is set to True, it will set the obsolete parent as resolution parent, so now resolved cset will be orphan, as it will be based on the obsolete parent. Some users might not like the evolve to automatically resovle this orphan instability as well (while they only wanted to resolve the divergence), which is why we are providing this config. `experimental.evolution.divergence-resolution-minimal=False(default)` (The default resolution that automatically evolve the orphan instability as well seems the best approach for now, but let's also gather user feedback, then we can decide accordingly) D-A3.2: both moved forward; same branch """"""""""""""""""""""""""""""""""""""" Set the parent of ahead one as resolution parent. As most obvious is that, ahead one has the latest changes. D-A3.3: both moved backward; same branch """""""""""""""""""""""""""""""""""""""" XXX: yet to decide resolution D-A3.4: both moved opposite; same branch """""""""""""""""""""""""""""""""""""""" XXX: yet to decide resolution D-A3.5: both moved; one moved on different unrelated branch """"""""""""""""""""""""""""""""""""""""""""""""""""""""""" XXX: yet to decide resolution D-A3.6: both moved on two different unrelated branch """""""""""""""""""""""""""""""""""""""""""""""""""" XXX: yet to decide resolution D-B: Merging files of divergent changesets ------------------------------------------ While merging the files, there are few sub-cases that could arise like file content conflict, rename information conflict, multiple newest predecessor. Let's see them in detail. D-B1: File content conflict ^^^^^^^^^^^^^^^^^^^^^^^^^^^ If there is a conflict in merging content of files we let the user to resolve the conflict. D-B2: Rename information conflict ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XXX: yet to explore D-B3: Multiple newest predecessor ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ XXX: yet to explore D-C: Merging metadata changes and create resultant changeset ------------------------------------------------------------ While merging the metadata, there are few sub-cases that could arise like branch name conflict, commit message conflict, commit author conflict. If everything goes fine, we create the resultant changeset as a resolution of content-divergence. D-C1: Branch name conflict ^^^^^^^^^^^^^^^^^^^^^^^^^^ **Stabilisation Strategy** Merge branch names using the 3-way merge. If unable to merge, we prompt the user to select a branch. Possible improvement: If we are solving a long streak of divergence, each side having the same branch, we can probably infer the correct resolution from previous resolution. **Current Support Level** Good: current implementation is expected to perform the planned stabilisation. D-C2: Commit description conflict ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Stabilisation Strategy** Merge commit description using text merge tool from user. Possible improvement: They are currently no way to "interrupt" and resume that conflict resolution. Having some way to do that would be nice. **Current Support Level** Good: current implementation is expected to perform the planned stabilisation. D-C3: Commit author conflict ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ **Stabilisation Strategy** Merge authors using 3-way merge. If unable to merge we concatenate the two, separated by comma. (for e.g. "John Doe, Malcolm X") **Current Support Level** Good: current implementation is expected to perform the planned stabilisation.