view docs/troubles-handling.rst @ 5544:0bb75a6c29b1

rewind: add a --dry-run flag There are 3 cases handled separately in formatstatus(): - common-case rewind when we have X current successors rewinding to Y predecessors - rewinding with --as-divergence, when we don't obsolete current successors - rewinding pruned commits, when we don't have current successors to show In the common case, we might have sub-cases that change the output with --dry-run (but not the way the rewind operates): - more predecessors than successors (e.g. after a fold), in which case we simply use successorsmap, which maps successors to a set of predecessors - equal number of predecessors and successors, see the previous case - more successors than predecessors (e.g. after a split), in which case we use a reverse of successorsmap (rsm), which maps predecessors to a set of successors and exists only for the sake of --dry-run functionality These two dicts allow us to group rewind targets and output separate lines for separate predecessors<->successors relations.
author Anton Shestakov <av6@dwimlabs.net>
date Tue, 21 Jul 2020 01:04:43 +0800
parents c408a31d8883
children 72a4aa791d97
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)
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


**Stabilisation Strategy**

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).

XXX what about if they are multiple heads to that set of "not-pruned" ancestor?
Especially when they are more then 2 ?

**Current Support Level**

Good support if there is only one head to the set.

O-A3: parent has multiple successors sets
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^


**Stabilisation Strategy**

**Current Support Level**

O-A4: parent is split into multiple successors
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^

O-A4.1: successors of parent are all one 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 prédecessors.

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 as 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

Details of Sub cases
====================

.. contents::
   :local: