Mercurial > evolve
comparison docs/concepts.rst @ 2020:143c8e4dc22d
topic: merge the topic extension in the evolve repository
There is a lot of synergy between the two concepts. Topic is expected to be able
to smooth multiple of evolution sharp edge. Having them both in the same
repository will make this collaboration easier.
author | Pierre-Yves David <pierre-yves.david@ens-lyon.org> |
---|---|
date | Thu, 02 Mar 2017 18:07:46 +0100 |
parents | c3ecf6871872 |
children | 803d32f4e498 |
comparison
equal
deleted
inserted
replaced
2019:996a562b6c9f | 2020:143c8e4dc22d |
---|---|
1 .. Copyright 2014 Greg Ward <greg@gerg.ca> | |
2 | |
3 ---------------- | |
4 Evolve: Concepts | |
5 ---------------- | |
6 | |
7 Getting the most out of software requires an accurate understanding of | |
8 the concepts underlying it. For example, you cannot use Mercurial to | |
9 its full potential without understanding the DAG (directed acyclic | |
10 graph) of changesets and the meaning of parent/child relationships | |
11 between nodes in that graph. Mercurial with changeset evolution adds | |
12 some additional concepts to the graph of changesets. Understanding | |
13 those concepts will make you an informed and empowered user of | |
14 ``evolve``. | |
15 | |
16 .. note:: This document contains math! If you have a pathological fear | |
17 of set theory and the associated notation, you might be | |
18 better off just reading the `user guide`_. But if you | |
19 appreciate the theoretical rigour underlying core Mercurial, | |
20 you will be happy to know that it continues right into | |
21 changeset evolution. | |
22 | |
23 .. note:: This document is incomplete! (The formatting of the math | |
24 isn't quite right yet, and the diagrams are missing for | |
25 malformatted.) | |
26 | |
27 This document follows standard set theory notation:: | |
28 | |
29 x ∈ A: x is a member of A | |
30 | |
31 A ∪ B: union of A and B: { x | x ∈ A or x ∈ B } | |
32 | |
33 A ∖ B: set difference: { x | x ∈ A and x ∉ B } | |
34 | |
35 A ⊇ B: superset: if x ∈ B, then x ∈ A | |
36 | |
37 .. _`user guide`: user-guide.html | |
38 | |
39 Phases | |
40 ------ | |
41 | |
42 First, every changeset in a Mercurial repository (since 2.3) has a | |
43 *phase*. Phases are independent of ``evolve`` and they affect | |
44 Mercurial usage with or without changeset evolution. However, they | |
45 were implemented in order to support evolution, and are a critical | |
46 foundation of ``evolve``. | |
47 | |
48 Phases are strictly ordered: | |
49 | |
50 secret > draft > public | |
51 | |
52 Changesets generally only move from a higher phase to a lower phase. | |
53 Typically, changesets start life in *draft* phase, and move to | |
54 *public* phase when they are pushed to a public repository. (You can | |
55 set the default phase of new commits in Mercurial configuration.) | |
56 | |
57 The purpose of phases is to prevent modifying published history. | |
58 ``evolve`` will therefore only let you rewrite changesets in one of | |
59 the two *mutable* phases (secret or draft). | |
60 | |
61 Run ``hg help phases`` for more information on phases. | |
62 | |
63 Obsolete changesets | |
64 ------------------- | |
65 | |
66 *Obsolescence* is they key concept at the heart of changeset | |
67 evolution. Everything else in this document depends on understanding | |
68 obsolescence. So: what does it mean for a changeset to be obsolete? | |
69 | |
70 In implementation terms, there is an *obsolescence marker* associated | |
71 with changesets: every changeset is either obsolete or not. | |
72 | |
73 The simplest way that a changeset becomes obsolete is by *pruning* it. | |
74 The ``hg prune`` command simply marks the specified changesets | |
75 obsolete, as long as they are mutable. | |
76 | |
77 More commonly, a changeset *A* becomes obsolete by *amending* it. | |
78 Amendment creates a new changeset *A'* that replaces *A*, which is now | |
79 obsolete. *A'* is the successor of *A*, and *A* the predecessor of *A'*: | |
80 | |
81 [diagram: A and A' with pred/succ edge] | |
82 | |
83 The predecessor/successor relationship forms an additional | |
84 *obsolescence graph* overlaid on top of the traditional DAG formed by | |
85 changesets and their parent/child relationships. In fact, the | |
86 obsolescence graph is second-order version control. Where the | |
87 traditional parent/child DAG tracks changes to your source code, the | |
88 obsolescence graph tracks changes to your changesets. It tracks the | |
89 evolution of your changesets. | |
90 | |
91 (If you prefer a calculus metaphor to set theory, it might help to | |
92 think of the traditional parent/child DAG as the first derivative of | |
93 your source code, and the obsolescence DAG as the second derivative.) | |
94 | |
95 Troubled changesets (unstable, bumped, divergent) | |
96 ------------------------------------------------- | |
97 | |
98 Evolving history can introduce problems that need to be solved. For | |
99 example, if you prune a changeset *P* but not its descendants, those | |
100 descendants are now on thin ice. To push a changeset to another | |
101 repository *R*, all of its ancestors must be present in *R* or pushed | |
102 at the same time. But Mercurial does not push obsolete changesets like | |
103 *P*, so it cannot push the descendants of *P*. Any non-obsolete | |
104 changeset that is a descendant of an obsolete changeset is said to be | |
105 *unstable*. | |
106 | |
107 [diagram: obsolete cset with non-obsolete descendant] | |
108 | |
109 Another sort of trouble occurs when two developers, Alice and Bob, | |
110 collaborate via a shared non-publishing repository. (This is how | |
111 developers can safely `share mutable history`_.) Say Alice and Bob | |
112 both start the day with changeset *C* in *draft* phase. If Alice | |
113 pushes *C* to their public repository, then it is now published and | |
114 therefore immutable. But Bob is working from a desert island and | |
115 cannot pull this change in *C*'s phase. For Bob, *C* is still in draft | |
116 phase and therefore mutable. So Bob amends *C*, which marks it | |
117 obsolete and replaces it with *C'*. When he is back online and pulls | |
118 from the public repository, Mercurial learns that *C* is public, which | |
119 means it cannot be obsolete. We say that *C'* is *bumped*, since it is | |
120 the successor of a public changeset. | |
121 | |
122 .. _`share mutable history`: sharing.html | |
123 | |
124 (Incidentally, the terminology here comes from airline overbooking: if | |
125 two people have bought tickets for the same seat on a plane and they | |
126 both show up at the airport, only one of them gets on the plane. The | |
127 passenger who is left behind in the airport terminal has been | |
128 "bumped".) | |
129 | |
130 The third sort of trouble is when Alice and Bob both amend the same | |
131 changeset *C* to have different successors. When this happens, the | |
132 successors are both called *divergent* (unless one of them is in | |
133 public phase; only mutable changesets are divergent). | |
134 | |
135 The collective term for unstable, bumped, and divergent changeset is | |
136 *troubled*:: | |
137 | |
138 troubled = unstable ∪ bumped ∪ divergent | |
139 | |
140 It is possible for a changeset to be in any of the troubled categories | |
141 at the same time: it might be unstable and divergent, or bumped and | |
142 divergent, or whatever. | |
143 | |
144 [diagram: Venn diagram of troubled changesets, showing overlap] | |
145 | |
146 The presence of troubled changesets indicates the need to run ``hg | |
147 evolve``. | |
148 | |
149 Hidden (and visible) changesets | |
150 ------------------------------- | |
151 | |
152 Some obsolete changesets are *hidden*: deliberately suppressed by | |
153 Mercurial and usually not visible through the UI. (As of Mercurial | |
154 2.9, there are still some commands that inadvertently reveal hidden | |
155 changesets; these are bugs and will be fixed in due course.) | |
156 | |
157 All hidden changesets are obsolete, and all obsolete changesets are | |
158 part of your repository. Mathematically speaking:: | |
159 | |
160 repo ⊇ obsolete ⊇ hidden | |
161 | |
162 Or, putting it visually: | |
163 | |
164 [diagram: Venn diagram showing nested strict subsets] | |
165 | |
166 However, the presence of obsolete but not hidden changesets should be | |
167 temporary. The desired end state for any history mutation operation is | |
168 that all obsolete changesets are hidden, i.e.: | |
169 | |
170 repo ⊇ obsolete, obsolete = hidden | |
171 | |
172 Visually: | |
173 | |
174 [diagram: Venn diagram showing obsolete = hidden, subset of repo] | |
175 | |
176 | |
177 Why is this changeset visible? | |
178 ------------------------------ | |
179 | |
180 Any changeset which is not hidden is *visible*. That is, :: | |
181 | |
182 visible = repo ∖ hidden | |
183 | |
184 (Recall that ∖ means set difference: *visible* is the set of | |
185 changesets that are in *repo* but not in *hidden*.) | |
186 | |
187 After amending or pruning a changeset, you might expect it to be | |
188 hidden. It doesn't always work out that way. The precise rules are:: | |
189 | |
190 hideable = obsolete | |
191 blockers = bookmarks ∪ parents(workingcopy) ∪ localtags | |
192 hidden = hideable ∖ ancestors((repo ∖ hideable) ∪ blockers) | |
193 | |
194 This will probably be clearer with a worked example. First, here's a | |
195 repository with some obsolete changesets, some troubled changesets, | |
196 one bookmark, a working copy, and some hidden changesets:: | |
197 | |
198 x-x | |
199 / | |
200 -o-o-o-o | |
201 \ | |
202 x-x-o | |
203 | |
204 Here's the computation required to determine which changesets are | |
205 hidden:: | |
206 | |
207 repo = { 0, 1, 2, 3, 4, 5, 6, 7, 8 } | |
208 | |
209 hideable = obsolete = { 2, 4, 5, 8 } | |
210 | |
211 blockers = { 6 } ∪ { 4 } ∪ {} | |
212 | |
213 blockers = { 4, 6 } | |
214 | |
215 hidden = hideable ∖ ancestors((repo ∖ { 2, 4, 5, 8 }) ∪ { 4, 6 }) | |
216 | |
217 hidden = hideable ∖ ancestors({ 0, 1, 3, 6, 7 } ∪ { 4, 6 }) | |
218 | |
219 hidden = hideable ∖ ancestors({ 0, 1, 3, 4, 6, 7 }) | |
220 | |
221 hidden = { 2, 4, 5, 8 } ∖ { 0, 1, 2, 3, 4, 5, 6, 7 } | |
222 | |
223 hidden = { 8 } |