|
169a10d…
|
drh
|
1 |
<title>Branching, Forking, Merging, and Tagging</title> |
|
169a10d…
|
drh
|
2 |
<h2>Background</h2> |
|
2e275c1…
|
drh
|
3 |
|
|
2e275c1…
|
drh
|
4 |
In a simple and perfect world, the development of a project would proceed |
|
b882c62…
|
wyoung
|
5 |
linearly, as shown in Figure 1. |
|
2e275c1…
|
drh
|
6 |
|
|
01f6ed9…
|
wyoung
|
7 |
<verbatim type="pikchr center toggle"> |
|
239fb5b…
|
wyoung
|
8 |
ALL: [circle rad 0.1in thickness 1.5px "1" |
|
0b2f838…
|
drh
|
9 |
arrow right 40% |
|
0b2f838…
|
drh
|
10 |
circle same "2" |
|
0b2f838…
|
drh
|
11 |
arrow same |
|
0b2f838…
|
drh
|
12 |
circle same "3" |
|
0b2f838…
|
drh
|
13 |
arrow same |
|
299e064…
|
drh
|
14 |
circle same "4"] |
|
299e064…
|
drh
|
15 |
box invis "Figure 1" big fit with .n at .3cm below ALL.s |
|
0b2f838…
|
drh
|
16 |
</verbatim> |
|
2e275c1…
|
drh
|
17 |
|
|
2e275c1…
|
drh
|
18 |
Each circle represents a check-in. For the sake of clarity, the check-ins |
|
2e275c1…
|
drh
|
19 |
are given small consecutive numbers. In a real system, of course, the |
|
796db89…
|
drh
|
20 |
check-in numbers would be long hexadecimal hashes since it is not possible |
|
d06396d…
|
drh
|
21 |
to allocate collision-free sequential numbers in a distributed system. |
|
d06396d…
|
drh
|
22 |
But as sequential numbers are easier to read, we will substitute them for |
|
796db89…
|
drh
|
23 |
the long hashes in this document. |
|
2e275c1…
|
drh
|
24 |
|
|
b882c62…
|
wyoung
|
25 |
The arrows in Figure 1 show the evolution of a project. The initial |
|
2e275c1…
|
drh
|
26 |
check-in is 1. Check-in 2 is derived from 1. In other words, check-in 2 |
|
2e275c1…
|
drh
|
27 |
was created by making edits to check-in 1 and then committing those edits. |
|
2e275c1…
|
drh
|
28 |
We say that 2 is a <i>child</i> of 1 |
|
aafcf6c…
|
jan.nijtmans
|
29 |
and that 1 is a <i>parent</i> of 2. |
|
2e275c1…
|
drh
|
30 |
Check-in 3 is derived from check-in 2, making |
|
2e275c1…
|
drh
|
31 |
3 a child of 2. We say that 3 is a <i>descendant</i> of both 1 and 2 and that 1 |
|
aafcf6c…
|
jan.nijtmans
|
32 |
and 2 are both <i>ancestors</i> of 3. |
|
d06396d…
|
drh
|
33 |
|
|
b882c62…
|
wyoung
|
34 |
<h2 id="dag">DAGs</h2> |
|
d06396d…
|
drh
|
35 |
|
|
aafcf6c…
|
jan.nijtmans
|
36 |
The graph of check-ins is a |
|
f8d210a…
|
wyoung
|
37 |
[http://en.wikipedia.org/wiki/Directed_acyclic_graph | directed acyclic graph], |
|
d06396d…
|
drh
|
38 |
commonly shortened to <i>DAG</i>. Check-in 1 is the <i>root</i> of the DAG |
|
c1c18b7…
|
drh
|
39 |
since it has no ancestors. Check-in 4 is a <i>leaf</i> of the DAG since |
|
d06396d…
|
drh
|
40 |
it has no descendants. (We will give a more precise definition later of |
|
d06396d…
|
drh
|
41 |
"leaf.") |
|
2e275c1…
|
drh
|
42 |
|
|
2e275c1…
|
drh
|
43 |
Alas, reality often interferes with the simple linear development of a |
|
2e275c1…
|
drh
|
44 |
project. Suppose two programmers make independent modifications to check-in 2. |
|
b882c62…
|
wyoung
|
45 |
After both changes are committed, the check-in graph looks like Figure 2: |
|
b882c62…
|
wyoung
|
46 |
|
|
01f6ed9…
|
wyoung
|
47 |
<verbatim type="pikchr center toggle"> |
|
239fb5b…
|
wyoung
|
48 |
ALL: [circle rad 0.1in thickness 1.5px "1" |
|
0b2f838…
|
drh
|
49 |
arrow right 40% |
|
0b2f838…
|
drh
|
50 |
circle same "2" |
|
0b2f838…
|
drh
|
51 |
circle same "3" at 2nd circle+(.4,.3) |
|
0b2f838…
|
drh
|
52 |
arrow from 2nd circle to 3rd circle chop |
|
0b2f838…
|
drh
|
53 |
circle same "4" at 2nd circle+(.4,-.3) |
|
299e064…
|
drh
|
54 |
arrow from 2nd circle to 4th circle chop] |
|
299e064…
|
drh
|
55 |
box invis "Figure 2" big fit with .n at .3cm below ALL.s |
|
0b2f838…
|
drh
|
56 |
</verbatim> |
|
b882c62…
|
wyoung
|
57 |
|
|
b882c62…
|
wyoung
|
58 |
The graph in Figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has |
|
d06396d…
|
drh
|
59 |
two children, check-ins 3 and 4. We call this state a <i>fork</i>. |
|
d06396d…
|
drh
|
60 |
|
|
f8d210a…
|
wyoung
|
61 |
Fossil tries to prevent forks, primarily through its |
|
f8d210a…
|
wyoung
|
62 |
"[./concepts.wiki#workflow | autosync]" mechanism. |
|
f8d210a…
|
wyoung
|
63 |
|
|
f8d210a…
|
wyoung
|
64 |
Suppose two programmers named Alice and |
|
aafcf6c…
|
jan.nijtmans
|
65 |
Bob are each editing check-in 2 separately. Alice finishes her edits |
|
f8d210a…
|
wyoung
|
66 |
and commits her changes first, resulting in check-in 3. When Bob later |
|
b882c62…
|
wyoung
|
67 |
attempts to commit his changes, Fossil verifies that check-in 2 is still |
|
aafcf6c…
|
jan.nijtmans
|
68 |
a leaf. Fossil sees that check-in 3 has occurred and aborts Bob's commit |
|
aafcf6c…
|
jan.nijtmans
|
69 |
attempt with a message "would fork." This allows Bob to do a "fossil |
|
f8d210a…
|
wyoung
|
70 |
update" to pull in Alice's changes, merging them into his own |
|
aafcf6c…
|
jan.nijtmans
|
71 |
changes. After merging, Bob commits check-in 4 as a child of check-in 3. |
|
b882c62…
|
wyoung
|
72 |
The result is a linear graph as shown in Figure 1. This is how CVS |
|
f8d210a…
|
wyoung
|
73 |
works. This is also how Fossil works in autosync mode. |
|
f8d210a…
|
wyoung
|
74 |
|
|
f8d210a…
|
wyoung
|
75 |
But perhaps Bob is off-network when he does his commit, so he has no way |
|
f8d210a…
|
wyoung
|
76 |
of knowing that Alice has already committed her changes. Or, it could |
|
f8d210a…
|
wyoung
|
77 |
be that Bob has turned off "autosync" mode in Fossil. Or, maybe Bob |
|
f8d210a…
|
wyoung
|
78 |
just doesn't want to merge in Alice's changes before he has saved his |
|
f8d210a…
|
wyoung
|
79 |
own, so he forces the commit to occur using the "--allow-fork" option to |
|
c64f28d…
|
drh
|
80 |
the <b>[/help/commit | fossil commit]</b> command. For any of these |
|
f8d210a…
|
wyoung
|
81 |
reasons, two commits against check-in 2 have occurred, so the DAG now |
|
f8d210a…
|
wyoung
|
82 |
has two leaves. |
|
f8d210a…
|
wyoung
|
83 |
|
|
f8d210a…
|
wyoung
|
84 |
In such a condition, a person working with this repository has a |
|
f8d210a…
|
wyoung
|
85 |
dilemma: which version of the project is the "latest" in the sense of |
|
f8d210a…
|
wyoung
|
86 |
having the most features and the most bug fixes? When there is more |
|
f8d210a…
|
wyoung
|
87 |
than one leaf in the graph, you don't really know, which is why we |
|
f8d210a…
|
wyoung
|
88 |
would ideally prefer to have linear check-in graphs. |
|
b882c62…
|
wyoung
|
89 |
|
|
b882c62…
|
wyoung
|
90 |
Fossil resolves such problems using the check-in time on the leaves to |
|
b882c62…
|
wyoung
|
91 |
decide which leaf to use as the parent of new leaves. When a branch is |
|
b882c62…
|
wyoung
|
92 |
forked as in Figure 2, Fossil will choose check-in 4 as the parent for a |
|
b882c62…
|
wyoung
|
93 |
later check-in 5, but <i>only</i> if it has sync'd that check-in down |
|
b882c62…
|
wyoung
|
94 |
into the local repository. If autosync is disabled or the user is |
|
f8d210a…
|
wyoung
|
95 |
off-network when that fifth check-in occurs so that check-in 3 is the |
|
b882c62…
|
wyoung
|
96 |
latest on that branch at the time within that clone of the repository, |
|
f8d210a…
|
wyoung
|
97 |
Fossil will make check-in 3 the parent of check-in 5! We show practical |
|
f8d210a…
|
wyoung
|
98 |
consequences of this [#bad-fork | later in this article]. |
|
b882c62…
|
wyoung
|
99 |
|
|
b882c62…
|
wyoung
|
100 |
Fossil also uses a forked branch's leaf check-in timestamps when |
|
b882c62…
|
wyoung
|
101 |
checking out that branch: it gives you the fork with the latest |
|
b882c62…
|
wyoung
|
102 |
check-in, which in turn selects which parent your next check-in will be |
|
b882c62…
|
wyoung
|
103 |
a child of. This situation means development on that branch can fork |
|
b882c62…
|
wyoung
|
104 |
into two independent lines of development, based solely on which branch |
|
f8d210a…
|
wyoung
|
105 |
tip is newer at the time the next user starts his work on it. |
|
f8d210a…
|
wyoung
|
106 |
|
|
f8d210a…
|
wyoung
|
107 |
Because of these potential problems, we strongly recommend that you do |
|
f8d210a…
|
wyoung
|
108 |
not intentionally create forks on long-lived shared working branches |
|
f8d210a…
|
wyoung
|
109 |
with "--allow-fork". (Prime example: trunk.) The inverse case — |
|
f8d210a…
|
wyoung
|
110 |
intentional forks on short-lived single-developer branches — is far |
|
f8d210a…
|
wyoung
|
111 |
easier to justify, since presumably the lone developer is never confused |
|
f8d210a…
|
wyoung
|
112 |
about why there are two or more leaves on that branch. Further |
|
f8d210a…
|
wyoung
|
113 |
justifications for intentional forking are [#forking | given below]. |
|
b882c62…
|
wyoung
|
114 |
|
|
b882c62…
|
wyoung
|
115 |
Let us return to Figure 2. To resolve such situations before they can |
|
c64f28d…
|
drh
|
116 |
become a real problem, Alice can use the <b>[/help/merge | fossil |
|
f8d210a…
|
wyoung
|
117 |
merge]</b> command to merge Bob's changes into her local copy of |
|
f8d210a…
|
wyoung
|
118 |
check-in 3. Without arguments, that command merges all leaves on the |
|
f8d210a…
|
wyoung
|
119 |
current branch. Alice can then verify that the merge is sensible and if |
|
f8d210a…
|
wyoung
|
120 |
so, commit the results as check-in 5. This results in a DAG as shown in |
|
b882c62…
|
wyoung
|
121 |
Figure 3. |
|
b882c62…
|
wyoung
|
122 |
|
|
01f6ed9…
|
wyoung
|
123 |
<verbatim type="pikchr center toggle"> |
|
239fb5b…
|
wyoung
|
124 |
ALL: [circle rad 0.1in thickness 1.5px "1" |
|
0b2f838…
|
drh
|
125 |
arrow right 40% |
|
0b2f838…
|
drh
|
126 |
circle same "2" |
|
0b2f838…
|
drh
|
127 |
circle same "3" at 2nd circle+(.4,.3) |
|
0b2f838…
|
drh
|
128 |
arrow from 2nd circle to 3rd circle chop |
|
0b2f838…
|
drh
|
129 |
circle same "4" at 2nd circle+(.4,-.3) |
|
0b2f838…
|
drh
|
130 |
arrow from 2nd circle to 4th circle chop |
|
0b2f838…
|
drh
|
131 |
circle same "5" at 3rd circle+(.4,-.3) |
|
0b2f838…
|
drh
|
132 |
arrow from 3rd circle to 5th circle chop |
|
299e064…
|
drh
|
133 |
arrow dashed .03 from 4th circle to 5th circle chop] |
|
299e064…
|
drh
|
134 |
box invis "Figure 3" big fit with .n at .2cm below ALL.s |
|
0b2f838…
|
drh
|
135 |
</verbatim> |
|
766bec0…
|
drh
|
136 |
|
|
766bec0…
|
drh
|
137 |
Check-in 5 is a child of check-in 3 because it was created by editing |
|
f8d210a…
|
wyoung
|
138 |
check-in 3, but since check-in 5 also inherits the changes from check-in 4 by |
|
f8d210a…
|
wyoung
|
139 |
virtue of the merge, we say that check-in 5 is a <i>merge child</i> |
|
aafcf6c…
|
jan.nijtmans
|
140 |
of check-in 4 and that it is a <i>direct child</i> of check-in 3. |
|
b882c62…
|
wyoung
|
141 |
The graph is now back to a single leaf, check-in 5. |
|
766bec0…
|
drh
|
142 |
|
|
b882c62…
|
wyoung
|
143 |
We have already seen that if Fossil is in autosync mode then Bob would |
|
2e275c1…
|
drh
|
144 |
have been warned about the potential fork the first time he tried to |
|
2e275c1…
|
drh
|
145 |
commit check-in 4. If Bob had updated his local check-out to merge in |
|
f8d210a…
|
wyoung
|
146 |
Alice's check-in 3 changes, then committed, the fork would have |
|
2e275c1…
|
drh
|
147 |
never occurred. The resulting graph would have been linear, as shown |
|
b882c62…
|
wyoung
|
148 |
in Figure 1. |
|
b882c62…
|
wyoung
|
149 |
|
|
f8d210a…
|
wyoung
|
150 |
Realize that the graph of Figure 1 is a subset of Figure 3. If you hold your |
|
f8d210a…
|
wyoung
|
151 |
hand over the ④ in Figure 3, it looks |
|
f8d210a…
|
wyoung
|
152 |
exactly like Figure 1 except that the leaf has a different check-in |
|
f8d210a…
|
wyoung
|
153 |
number. That is just a notational difference: the two check-ins |
|
f8d210a…
|
wyoung
|
154 |
have exactly the same content. |
|
f8d210a…
|
wyoung
|
155 |
|
|
f8d210a…
|
wyoung
|
156 |
Inversely, Figure 3 is a |
|
b882c62…
|
wyoung
|
157 |
superset of Figure 1. The check-in 4 of Figure 3 captures additional |
|
b882c62…
|
wyoung
|
158 |
state which is omitted from Figure 1. Check-in 4 of Figure 3 holds a |
|
b882c62…
|
wyoung
|
159 |
copy of Bob's local checkout before he merged in Alice's changes. That |
|
b882c62…
|
wyoung
|
160 |
snapshot of Bob's changes, which is independent of Alice's changes, is |
|
f8d210a…
|
wyoung
|
161 |
omitted from Figure 1. |
|
f8d210a…
|
wyoung
|
162 |
|
|
f8d210a…
|
wyoung
|
163 |
Some people say that the development approach taken in |
|
b882c62…
|
wyoung
|
164 |
Figure 3 is better because it preserves this extra intermediate state. |
|
b882c62…
|
wyoung
|
165 |
Others say that the approach taken in Figure 1 is better because it is |
|
f8d210a…
|
wyoung
|
166 |
much easier to visualize linear development and because the |
|
b882c62…
|
wyoung
|
167 |
merging happens automatically instead of as a separate manual step. We |
|
b882c62…
|
wyoung
|
168 |
will not take sides in that debate. We will simply point out that |
|
b882c62…
|
wyoung
|
169 |
Fossil enables you to do it either way. |
|
b882c62…
|
wyoung
|
170 |
|
|
b882c62…
|
wyoung
|
171 |
<h2 id="branching">The Alternative to Forking: Branching</h2> |
|
aafcf6c…
|
jan.nijtmans
|
172 |
|
|
aafcf6c…
|
jan.nijtmans
|
173 |
Having more than one leaf in the check-in DAG is called a "fork." This |
|
d06396d…
|
drh
|
174 |
is usually undesirable and either avoided entirely, |
|
b882c62…
|
wyoung
|
175 |
as in Figure 1, or else quickly resolved as shown in Figure 3. |
|
2e275c1…
|
drh
|
176 |
But sometimes, one does want to have multiple leaves. For example, a project |
|
2e275c1…
|
drh
|
177 |
might have one leaf that is the latest version of the project under |
|
2e275c1…
|
drh
|
178 |
development and another leaf that is the latest version that has been |
|
2e275c1…
|
drh
|
179 |
tested. |
|
d06396d…
|
drh
|
180 |
When multiple leaves are desirable, we call this <i>branching</i> |
|
1e0cf46…
|
wyoung
|
181 |
instead of <i>forking</i>: |
|
1e0cf46…
|
wyoung
|
182 |
|
|
2e275c1…
|
drh
|
183 |
Figure 4 shows an example of a project where there are two branches, one |
|
2e275c1…
|
drh
|
184 |
for development work and another for testing. |
|
2e275c1…
|
drh
|
185 |
|
|
01f6ed9…
|
wyoung
|
186 |
<verbatim type="pikchr center toggle"> |
|
239fb5b…
|
wyoung
|
187 |
ALL: [circle rad 0.1in thickness 1.5px fill white "1" |
|
0b2f838…
|
drh
|
188 |
arrow 40% |
|
0b2f838…
|
drh
|
189 |
C2: circle same "2" |
|
0b2f838…
|
drh
|
190 |
arrow same |
|
0b2f838…
|
drh
|
191 |
circle same "3" |
|
0b2f838…
|
drh
|
192 |
arrow same |
|
0b2f838…
|
drh
|
193 |
C5: circle same "5" |
|
0b2f838…
|
drh
|
194 |
arrow same |
|
0b2f838…
|
drh
|
195 |
C7: circle same "7" |
|
0b2f838…
|
drh
|
196 |
arrow same |
|
0b2f838…
|
drh
|
197 |
C8: circle same "8" |
|
0b2f838…
|
drh
|
198 |
arrow same |
|
0b2f838…
|
drh
|
199 |
C10: circle same "10" |
|
0b2f838…
|
drh
|
200 |
C4: circle same at 3rd circle-(0,.35) "4" |
|
0b2f838…
|
drh
|
201 |
C6: circle same at (1/2 way between C5 and C7,C4) "6" |
|
0b2f838…
|
drh
|
202 |
C9: circle same at (1/2 way between C8 and C10,C4) "9" |
|
0b2f838…
|
drh
|
203 |
arrow from C2 to C4 chop |
|
0b2f838…
|
drh
|
204 |
arrow from C4 to C6 chop |
|
0b2f838…
|
drh
|
205 |
arrow from C6 to C9 chop |
|
0b2f838…
|
drh
|
206 |
arrow dashed 0.03 from C6 to C7 chop |
|
0b2f838…
|
drh
|
207 |
arrow same from C9 to C10 |
|
0b2f838…
|
drh
|
208 |
layer = 0 |
|
0b2f838…
|
drh
|
209 |
box fill 0x9bcdfc color 0x9bcdfc wid (C10.e.x - C2.w.x) ht C6.height*1.5 at C6.c |
|
299e064…
|
drh
|
210 |
box invis "test" fit with .sw at last box.sw] |
|
299e064…
|
drh
|
211 |
box invis "Figure 4" big with .n at 0 below ALL.s |
|
0b2f838…
|
drh
|
212 |
</verbatim> |
|
aafcf6c…
|
jan.nijtmans
|
213 |
|
|
f8d210a…
|
wyoung
|
214 |
Figure 4 diagrams the following scenario: the project starts and |
|
aafcf6c…
|
jan.nijtmans
|
215 |
progresses to a point where (at check-in 2) |
|
2e275c1…
|
drh
|
216 |
it is ready to enter testing for its first release. |
|
2e275c1…
|
drh
|
217 |
In a real project, of course, there might be hundreds or thousands of |
|
2e275c1…
|
drh
|
218 |
check-ins before a project reaches this point, but for simplicity of |
|
2e275c1…
|
drh
|
219 |
presentation we will say that the project is ready after check-in 2. |
|
2e275c1…
|
drh
|
220 |
The project then splits into two branches that are used by separate |
|
2e275c1…
|
drh
|
221 |
teams. The testing team, using the blue branch, finds and fixes a few |
|
f8d210a…
|
wyoung
|
222 |
bugs with check-ins 6 and 9. Meanwhile, the development |
|
aafcf6c…
|
jan.nijtmans
|
223 |
team, working on the top uncolored branch, |
|
dc1a5cf…
|
drh
|
224 |
is busy adding features for the second |
|
2e275c1…
|
drh
|
225 |
release. Of course, the development team would like to take advantage of |
|
f8d210a…
|
wyoung
|
226 |
the bug fixes implemented by the testing team, so periodically the |
|
2e275c1…
|
drh
|
227 |
changes in the test branch are merged into the dev branch. This is |
|
2e275c1…
|
drh
|
228 |
shown by the dashed merge arrows between check-ins 6 and 7 and between |
|
2e275c1…
|
drh
|
229 |
check-ins 9 and 10. |
|
2e275c1…
|
drh
|
230 |
|
|
b882c62…
|
wyoung
|
231 |
In both Figures 2 and 4, check-in 2 has two children. In Figure 2, |
|
d06396d…
|
drh
|
232 |
we call this a "fork." In diagram 4, we call it a "branch." What is |
|
b882c62…
|
wyoung
|
233 |
the difference? As far as the internal Fossil data structures are |
|
2e275c1…
|
drh
|
234 |
concerned, there is no difference. The distinction is in the intent. |
|
b882c62…
|
wyoung
|
235 |
In Figure 2, the fact that check-in 2 has multiple children is an |
|
b882c62…
|
wyoung
|
236 |
accident that stems from concurrent development. In Figure 4, giving |
|
f8d210a…
|
wyoung
|
237 |
check-in 2 multiple children is a deliberate act. To a good |
|
dc1a5cf…
|
drh
|
238 |
approximation, we define forking to be by accident and branching to |
|
2e275c1…
|
drh
|
239 |
be by intent. Apart from that, they are the same. |
|
f8d210a…
|
wyoung
|
240 |
|
|
f8d210a…
|
wyoung
|
241 |
When the fork is intentional, it helps humans to understand what is |
|
f8d210a…
|
wyoung
|
242 |
going on if we <i>name</i> the forks. This is not essential to Fossil's |
|
f8d210a…
|
wyoung
|
243 |
internal data model, but humans have trouble working with long-lived |
|
f8d210a…
|
wyoung
|
244 |
branches identified only by the commit ID currently at its tip, being a |
|
f8d210a…
|
wyoung
|
245 |
long string of hex digits. Therefore, Fossil conflates two concepts: |
|
f8d210a…
|
wyoung
|
246 |
branching as intentional forking and the naming of forks as branches. |
|
f8d210a…
|
wyoung
|
247 |
They are in fact separate concepts, but since Fossil is intended to be |
|
f8d210a…
|
wyoung
|
248 |
used primarily by humans, we combine them in Fossil's human user |
|
f8d210a…
|
wyoung
|
249 |
interfaces. |
|
f8d210a…
|
wyoung
|
250 |
|
|
8a1ba49…
|
wyoung
|
251 |
<p class="blockquote"> |
|
f8d210a…
|
wyoung
|
252 |
<b>Key Distinction:</b> A branch is a <i>named, intentional</i> fork. |
|
8a1ba49…
|
wyoung
|
253 |
</p> |
|
f8d210a…
|
wyoung
|
254 |
|
|
f8d210a…
|
wyoung
|
255 |
Unnamed forks <i>may</i> be intentional, but most of the time, they're |
|
f8d210a…
|
wyoung
|
256 |
accidental and left unnamed. |
|
2da1099…
|
wyoung
|
257 |
|
|
2da1099…
|
wyoung
|
258 |
Fossil offers two primary ways to create named, intentional forks, |
|
7391166…
|
wyoung
|
259 |
a.k.a. branches. First: |
|
7391166…
|
wyoung
|
260 |
|
|
7391166…
|
wyoung
|
261 |
<pre> |
|
ccd880e…
|
wyoung
|
262 |
$ fossil commit --branch my-new-branch-name |
|
7391166…
|
wyoung
|
263 |
</pre> |
|
7391166…
|
wyoung
|
264 |
|
|
7391166…
|
wyoung
|
265 |
This is the method we recommend for most cases: it creates a branch as |
|
f8d210a…
|
wyoung
|
266 |
part of a check-in using the version in the current checkout directory |
|
2da1099…
|
wyoung
|
267 |
as its basis. (This is normally the tip of the current branch, though |
|
f8d210a…
|
wyoung
|
268 |
it doesn't have to be. You can create a branch from an ancestor check-in |
|
2da1099…
|
wyoung
|
269 |
on a branch as well.) After making this branch-creating |
|
f8d210a…
|
wyoung
|
270 |
check-in, your local working directory is switched to that branch, so |
|
f8d210a…
|
wyoung
|
271 |
that further check-ins occur on that branch as well, as children of the |
|
f8d210a…
|
wyoung
|
272 |
tip check-in on that branch. |
|
7391166…
|
wyoung
|
273 |
|
|
7391166…
|
wyoung
|
274 |
The second, more complicated option is: |
|
1e0cf46…
|
wyoung
|
275 |
|
|
1e0cf46…
|
wyoung
|
276 |
<pre> |
|
ccd880e…
|
wyoung
|
277 |
$ fossil branch new my-new-branch-name trunk |
|
ccd880e…
|
wyoung
|
278 |
$ fossil update my-new-branch-name |
|
ccd880e…
|
wyoung
|
279 |
$ fossil commit |
|
1e0cf46…
|
wyoung
|
280 |
</pre> |
|
1e0cf46…
|
wyoung
|
281 |
|
|
2da1099…
|
wyoung
|
282 |
Not only is this three commands instead of one, the first of which is |
|
2da1099…
|
wyoung
|
283 |
longer than the entire simpler command above, you must give the second command |
|
f8d210a…
|
wyoung
|
284 |
before creating any check-ins, because until you do, your local working |
|
7391166…
|
wyoung
|
285 |
directory remains on the same branch it was on at the time you issued |
|
2da1099…
|
wyoung
|
286 |
the command, so that the commit would otherwise put the new material on |
|
2da1099…
|
wyoung
|
287 |
the original branch instead of the new one. |
|
7391166…
|
wyoung
|
288 |
|
|
7391166…
|
wyoung
|
289 |
In addition to those problems, the second method is a violation of the |
|
1e0cf46…
|
wyoung
|
290 |
[https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it|YAGNI |
|
1e0cf46…
|
wyoung
|
291 |
Principle]. We recommend that you wait until you actually need the |
|
f8d210a…
|
wyoung
|
292 |
branch before you create it using the first command above. |
|
7391166…
|
wyoung
|
293 |
|
|
f8d210a…
|
wyoung
|
294 |
The "trunk" is just another named branch in Fossil. It is simply |
|
f8d210a…
|
wyoung
|
295 |
the default branch name for the first check-in and every check-in made as |
|
7391166…
|
wyoung
|
296 |
one of its direct descendants. It is special only in that it is Fossil's |
|
f8d210a…
|
wyoung
|
297 |
default when it has no better idea of which branch you mean. |
|
1e0cf46…
|
wyoung
|
298 |
|
|
1e0cf46…
|
wyoung
|
299 |
|
|
b882c62…
|
wyoung
|
300 |
<h2 id="forking">Justifications For Forking</h2> |
|
b882c62…
|
wyoung
|
301 |
|
|
bf048cd…
|
wyoung
|
302 |
The primary cases where forking is justified over branching are all when |
|
bf048cd…
|
wyoung
|
303 |
it is done purely in software in order to avoid losing information: |
|
b882c62…
|
wyoung
|
304 |
|
|
b882c62…
|
wyoung
|
305 |
<ol> |
|
862b77b…
|
wyoung
|
306 |
<li><p id="offline">By Fossil itself when two users check in children to the same |
|
f8d210a…
|
wyoung
|
307 |
leaf of a branch, as in Figure 2. |
|
f8d210a…
|
wyoung
|
308 |
<br><br> |
|
f8d210a…
|
wyoung
|
309 |
If the fork occurs because |
|
bf048cd…
|
wyoung
|
310 |
autosync is disabled on one or both of the repositories or because |
|
bf048cd…
|
wyoung
|
311 |
the user doing the check-in has no network connection at the moment |
|
bf048cd…
|
wyoung
|
312 |
of the commit, Fossil has no way of knowing that it is creating a |
|
0996347…
|
wyoung
|
313 |
fork until the two repositories are later synchronized.</p></li> |
|
862b77b…
|
wyoung
|
314 |
|
|
862b77b…
|
wyoung
|
315 |
<li><p id="dist-clone">By Fossil when the cloning hierarchy is more |
|
862b77b…
|
wyoung
|
316 |
than 2 levels deep. |
|
862b77b…
|
wyoung
|
317 |
<br><br> |
|
79c2cb0…
|
wyoung
|
318 |
[./sync.wiki|Fossil's synchronization protocol] is a two-party |
|
862b77b…
|
wyoung
|
319 |
negotiation; syncs don't automatically propagate up the clone tree |
|
862b77b…
|
wyoung
|
320 |
beyond that. Because of that, if you have a master repository and |
|
862b77b…
|
wyoung
|
321 |
Alice clones it, then Bobby clones from Alice's repository, a |
|
862b77b…
|
wyoung
|
322 |
check-in by Bobby that autosyncs with Alice's repo will <i>not</i> |
|
862b77b…
|
wyoung
|
323 |
also autosync with the master repo. The master doesn't get a copy of |
|
f8d210a…
|
wyoung
|
324 |
Bobby's check-in until Alice <i>separately</i> syncs with the master. |
|
862b77b…
|
wyoung
|
325 |
If Carol cloned from the master repo and checks something in that |
|
862b77b…
|
wyoung
|
326 |
creates a fork relative to Bobby's check-in, the master repo won't |
|
862b77b…
|
wyoung
|
327 |
know about that fork until Alice syncs her repo with the master. |
|
862b77b…
|
wyoung
|
328 |
Even then, realize that Carol still won't know about the fork until |
|
862b77b…
|
wyoung
|
329 |
she subsequently syncs with the master repo. |
|
862b77b…
|
wyoung
|
330 |
<br><br> |
|
862b77b…
|
wyoung
|
331 |
One way to deal with this is to just accept it as a fact of using a |
|
862b77b…
|
wyoung
|
332 |
[https://en.wikipedia.org/wiki/Distributed_version_control|Distributed |
|
862b77b…
|
wyoung
|
333 |
Version Control System] like Fossil. |
|
862b77b…
|
wyoung
|
334 |
<br><br> |
|
862b77b…
|
wyoung
|
335 |
Another option, which we recommend you consider carefully, is to |
|
f8d210a…
|
wyoung
|
336 |
make it a local policy that check-ins be made only directly against the master |
|
862b77b…
|
wyoung
|
337 |
repo or one of its immediate child clones so that the autosync |
|
f8d210a…
|
wyoung
|
338 |
algorithm can do its job most effectively. Any clones deeper than |
|
862b77b…
|
wyoung
|
339 |
that should be treated as read-only and thus get a copy of the new |
|
862b77b…
|
wyoung
|
340 |
state of the world only once these central repos have negotiated |
|
862b77b…
|
wyoung
|
341 |
that new state. This policy avoids a class of inadvertent fork you |
|
862b77b…
|
wyoung
|
342 |
might not need to tolerate. Since [#bad-fork|forks on long-lived |
|
862b77b…
|
wyoung
|
343 |
shared working branches can end up dividing a team's development |
|
862b77b…
|
wyoung
|
344 |
effort], a team may easily justify this restriction on distributed |
|
862b77b…
|
wyoung
|
345 |
cloning.</p></li> |
|
862b77b…
|
wyoung
|
346 |
|
|
f8d210a…
|
wyoung
|
347 |
<li><p id="automation">You've automated Fossil, so you use |
|
f8d210a…
|
wyoung
|
348 |
<b>fossil commit --allow-fork</b> commands to prevent Fossil from |
|
f8d210a…
|
wyoung
|
349 |
refusing the check-in simply because it would create a fork. |
|
f8d210a…
|
wyoung
|
350 |
<br><br> |
|
f8d210a…
|
wyoung
|
351 |
If you are writing such a tool — e.g. a shell script to make |
|
f8d210a…
|
wyoung
|
352 |
multiple manipulations on a Fossil repo — it's better to make it |
|
f8d210a…
|
wyoung
|
353 |
smart enough to detect this condition and cope with it, such as |
|
c64f28d…
|
drh
|
354 |
by making a call to <b>[/help/update | fossil update]</b> |
|
f8d210a…
|
wyoung
|
355 |
and checking for a merge conflict. That said, if the alternative is |
|
f8d210a…
|
wyoung
|
356 |
losing information, you may feel justified in creating forks that an |
|
f8d210a…
|
wyoung
|
357 |
interactive user must later manually clean up with <b>fossil merge</b> |
|
f8d210a…
|
wyoung
|
358 |
commands.</p></li> |
|
b882c62…
|
wyoung
|
359 |
</ol> |
|
b882c62…
|
wyoung
|
360 |
|
|
b882c62…
|
wyoung
|
361 |
That leaves only one case where we can recommend use of "--allow-fork" |
|
f8d210a…
|
wyoung
|
362 |
by interactive users: when you're working on a personal branch so that |
|
f8d210a…
|
wyoung
|
363 |
creating a dual-tipped branch isn't going to cause any other user an |
|
f8d210a…
|
wyoung
|
364 |
inconvenience or risk [#bad-fork | inadvertently forking the development |
|
f8d210a…
|
wyoung
|
365 |
effort]. In such a case, the lone developer working on that branch is |
|
f8d210a…
|
wyoung
|
366 |
not confused, since the fork in development is intentional. Sometimes it |
|
f8d210a…
|
wyoung
|
367 |
simply makes no sense to bother creating a name, cluttering the global |
|
f8d210a…
|
wyoung
|
368 |
branch namespace, simply to convert an intentional fork into a "branch." |
|
f8d210a…
|
wyoung
|
369 |
This is especially the case when the fork is short-lived. |
|
3cc437a…
|
wyoung
|
370 |
|
|
3cc437a…
|
wyoung
|
371 |
There's a common generalization of that case: you're a solo developer, |
|
184cf20…
|
wyoung
|
372 |
so that the problems with branching vs forking simply don't matter. In |
|
3cc437a…
|
wyoung
|
373 |
that case, feel free to use "--allow-fork" as much as you like. |
|
2686bad…
|
wyoung
|
374 |
|
|
2686bad…
|
wyoung
|
375 |
|
|
2686bad…
|
wyoung
|
376 |
<h2 id="fix">Fixing Forks</h2> |
|
2686bad…
|
wyoung
|
377 |
|
|
2686bad…
|
wyoung
|
378 |
If your local checkout is on a forked branch, you can usually fix a fork |
|
2686bad…
|
wyoung
|
379 |
automatically with: |
|
2686bad…
|
wyoung
|
380 |
|
|
2686bad…
|
wyoung
|
381 |
<pre> |
|
ccd880e…
|
wyoung
|
382 |
$ fossil merge |
|
2686bad…
|
wyoung
|
383 |
</pre> |
|
2686bad…
|
wyoung
|
384 |
|
|
2686bad…
|
wyoung
|
385 |
Normally you need to pass arguments to <b>fossil merge</b> to tell it |
|
2686bad…
|
wyoung
|
386 |
what you want to merge into the current basis view of the repository, |
|
2686bad…
|
wyoung
|
387 |
but without arguments, the command seeks out and fixes forks. |
|
b882c62…
|
wyoung
|
388 |
|
|
b882c62…
|
wyoung
|
389 |
|
|
b882c62…
|
wyoung
|
390 |
<h2 id="tags">Tags And Properties</h2> |
|
2e275c1…
|
drh
|
391 |
|
|
b882c62…
|
wyoung
|
392 |
Tags and properties are used in Fossil to help express the intent, and |
|
2e275c1…
|
drh
|
393 |
thus to distinguish between forks and branches. Figure 5 shows the |
|
b882c62…
|
wyoung
|
394 |
same scenario as Figure 4 but with tags and properties added: |
|
2e275c1…
|
drh
|
395 |
|
|
01f6ed9…
|
wyoung
|
396 |
<verbatim type="pikchr center toggle"> |
|
299e064…
|
drh
|
397 |
ALL: [arrowht = 0.07 |
|
239fb5b…
|
wyoung
|
398 |
C1: circle rad 0.1in thickness 1.5px fill white "1" |
|
9ec0cce…
|
drh
|
399 |
arrow 40% |
|
9ec0cce…
|
drh
|
400 |
C2: circle same "2" |
|
9ec0cce…
|
drh
|
401 |
arrow same |
|
9ec0cce…
|
drh
|
402 |
circle same "3" |
|
9ec0cce…
|
drh
|
403 |
arrow same |
|
9ec0cce…
|
drh
|
404 |
C5: circle same "5" |
|
9ec0cce…
|
drh
|
405 |
arrow same |
|
9ec0cce…
|
drh
|
406 |
C7: circle same "7" |
|
9ec0cce…
|
drh
|
407 |
arrow same |
|
9ec0cce…
|
drh
|
408 |
C8: circle same "8" |
|
9ec0cce…
|
drh
|
409 |
arrow same |
|
9ec0cce…
|
drh
|
410 |
C10: circle same "10" |
|
9ec0cce…
|
drh
|
411 |
C4: circle same at 3rd circle-(0,.35) "4" |
|
9ec0cce…
|
drh
|
412 |
C6: circle same at (1/2 way between C5 and C7,C4) "6" |
|
9ec0cce…
|
drh
|
413 |
C9: circle same at (1/2 way between C8 and C10,C4) "9" |
|
9ec0cce…
|
drh
|
414 |
arrow from C2 to C4 chop |
|
9ec0cce…
|
drh
|
415 |
arrow from C4 to C6 chop |
|
9ec0cce…
|
drh
|
416 |
arrow from C6 to C9 chop |
|
9ec0cce…
|
drh
|
417 |
arrow dashed 0.03 from C6 to C7 chop |
|
9ec0cce…
|
drh
|
418 |
arrow same from C9 to C10 |
|
9ec0cce…
|
drh
|
419 |
layer = 0 |
|
9ec0cce…
|
drh
|
420 |
box fill 0x9bcdfc color 0x9bcdfc wid (C10.e.x - C2.w.x) ht C6.height*1.5 at C6.c |
|
9ec0cce…
|
drh
|
421 |
text " test" above ljust at last box.sw |
|
9ec0cce…
|
drh
|
422 |
box fill lightgray "branch=trunk" "sym-trunk" fit with .ne at C1-(0.05,0.3); |
|
9ec0cce…
|
drh
|
423 |
line color gray from last box.ne to C1 chop |
|
9ec0cce…
|
drh
|
424 |
box same "branch=test" "sym-test" "bgcolor=blue" "cancel=sym-trunk" fit \ |
|
9ec0cce…
|
drh
|
425 |
with .n at C4-(0,0.3) |
|
9ec0cce…
|
drh
|
426 |
line color gray from last box.n to C4 chop |
|
9ec0cce…
|
drh
|
427 |
box same "sym-release-1.0" "closed" fit with .n at C9-(0,0.3) |
|
299e064…
|
drh
|
428 |
line color gray from last box.n to C9 chop] |
|
239fb5b…
|
wyoung
|
429 |
box invis "Figure 5" big fit with .n at 0.2cm below ALL.s |
|
9ec0cce…
|
drh
|
430 |
</verbatim> |
|
2e275c1…
|
drh
|
431 |
|
|
2e275c1…
|
drh
|
432 |
A <i>tag</i> is a name that is attached to a check-in. A |
|
b882c62…
|
wyoung
|
433 |
<i>property</i> is a name/value pair. Internally, Fossil implements |
|
2e275c1…
|
drh
|
434 |
tags as properties with a NULL value. So, tags and properties really |
|
2e275c1…
|
drh
|
435 |
are much the same thing, and henceforth we will use the word "tag" |
|
aafcf6c…
|
jan.nijtmans
|
436 |
to mean either a tag or a property. |
|
2e275c1…
|
drh
|
437 |
|
|
aafcf6c…
|
jan.nijtmans
|
438 |
A tag can be a one-time tag, a propagating tag or a cancellation tag. |
|
dc1a5cf…
|
drh
|
439 |
A one-time tag only applies to the check-in to which it is attached. A |
|
2e275c1…
|
drh
|
440 |
propagating tag applies to the check-in to which it is attached and also |
|
2e275c1…
|
drh
|
441 |
to all direct descendants of that check-in. A <i>direct descendant</i> |
|
bdc892f…
|
drh
|
442 |
is a descendant through direct children. Tag propagation does not |
|
2e275c1…
|
drh
|
443 |
cross merges. Tag propagation also stops as soon |
|
2e275c1…
|
drh
|
444 |
as it encounters another check-in with the same tag. A cancellation tag |
|
2e275c1…
|
drh
|
445 |
is attached to a single check-in in order to either override a one-time |
|
766bec0…
|
drh
|
446 |
tag that was previously placed on that same check-in, or to block |
|
766bec0…
|
drh
|
447 |
tag propagation from an ancestor. |
|
2e275c1…
|
drh
|
448 |
|
|
fe38a76…
|
drh
|
449 |
The initial check-in of every repository has two propagating tags. In |
|
b882c62…
|
wyoung
|
450 |
Figure 5, that initial check-in is check-in 1. The <b>branch</b> tag |
|
aafcf6c…
|
jan.nijtmans
|
451 |
tells (by its value) what branch the check-in is a member of. |
|
d06396d…
|
drh
|
452 |
The default branch is called "trunk." All tags that begin with "<b>sym-</b>" |
|
2e275c1…
|
drh
|
453 |
are symbolic name tags. When a symbolic name tag is attached to a |
|
2e275c1…
|
drh
|
454 |
check-in, that allows you to refer to that check-in by its symbolic |
|
796db89…
|
drh
|
455 |
name rather than by its hexadecimal hash name. When a symbolic name |
|
2e275c1…
|
drh
|
456 |
tag propagates (as does the <b>sym-trunk</b> tag) then referring to that |
|
2e275c1…
|
drh
|
457 |
name is the same as referring to the most recent check-in with that name. |
|
d06396d…
|
drh
|
458 |
Thus the two tags on check-in 1 cause all descendants to be in the |
|
d06396d…
|
drh
|
459 |
"trunk" branch and to have the symbolic name "trunk." |
|
2e275c1…
|
drh
|
460 |
|
|
2e275c1…
|
drh
|
461 |
Check-in 4 has a <b>branch</b> tag which changes the name of the branch |
|
d06396d…
|
drh
|
462 |
to "test." The branch tag on check-in 4 propagates to check-ins 6 and 9. |
|
2e275c1…
|
drh
|
463 |
But because tag propagation does not follow merge links, the <b>branch=test</b> |
|
5e4b163…
|
eric
|
464 |
tag does not propagate to check-ins 7, 8, or 10. Note also that the |
|
2e275c1…
|
drh
|
465 |
<b>branch</b> tag on check-in 4 blocks the propagation of <b>branch=trunk</b> |
|
2e275c1…
|
drh
|
466 |
so that it cannot reach check-ins 6 or 9. This causes check-ins 4, 6, and |
|
2e275c1…
|
drh
|
467 |
9 to be in the "test" branch and all others to be in the "trunk" branch. |
|
2e275c1…
|
drh
|
468 |
|
|
2e275c1…
|
drh
|
469 |
Check-in 4 also has a <b>sym-test</b> tag, which gives the symbolic name |
|
2e275c1…
|
drh
|
470 |
"test" to check-ins 4, 6, and 9. Because tags do not propagate across |
|
5e4b163…
|
eric
|
471 |
merges, check-ins 7, 8, and 10 do not inherit the <b>sym-test</b> tag and |
|
d06396d…
|
drh
|
472 |
are hence not known by the name "test." |
|
aafcf6c…
|
jan.nijtmans
|
473 |
To prevent the <b>sym-trunk</b> tag from propagating from check-in 1 |
|
aafcf6c…
|
jan.nijtmans
|
474 |
into check-ins 4, 6, and 9, there is a cancellation tag for |
|
d06396d…
|
drh
|
475 |
<b>sym-trunk</b> on check-in 4. The net effect is that |
|
2e275c1…
|
drh
|
476 |
check-ins on the trunk go by the symbolic name of "trunk" and check-ins |
|
d06396d…
|
drh
|
477 |
on the test branch go by the symbolic name "test." |
|
2e275c1…
|
drh
|
478 |
|
|
2e275c1…
|
drh
|
479 |
The <b>bgcolor=blue</b> tag on check-in 4 causes the background color |
|
766bec0…
|
drh
|
480 |
of timelines to be blue for check-in 4 and its direct descendants. |
|
2e275c1…
|
drh
|
481 |
|
|
2e275c1…
|
drh
|
482 |
Figure 5 also shows two one-time tags on check-in 9. (The diagram does |
|
2e275c1…
|
drh
|
483 |
not make a graphical distinction between one-time and propagating tags.) |
|
2e275c1…
|
drh
|
484 |
The <b>sym-release-1.0</b> tag means that check-in 9 can be referred to |
|
d06396d…
|
drh
|
485 |
using the more meaningful name "release-1.0." The <b>closed</b> tag means |
|
aafcf6c…
|
jan.nijtmans
|
486 |
that check-in 9 is a "closed leaf." A closed leaf is a leaf that should |
|
d06396d…
|
drh
|
487 |
never have direct children. |
|
aafcf6c…
|
jan.nijtmans
|
488 |
|
|
efb104b…
|
wyoung
|
489 |
<h2 id="bad-fork">How Can Forks Divide Development Effort?</h2> |
|
efb104b…
|
wyoung
|
490 |
|
|
862b77b…
|
wyoung
|
491 |
[#dist-clone|Above], we stated that forks carry a risk that development |
|
efb104b…
|
wyoung
|
492 |
effort on a branch can be divided among the forks. It might not be |
|
efb104b…
|
wyoung
|
493 |
immediately obvious why this is so. To see it, consider this swim lane |
|
efb104b…
|
wyoung
|
494 |
diagram: |
|
efb104b…
|
wyoung
|
495 |
|
|
b3d99d9…
|
wyoung
|
496 |
<verbatim type="pikchr center toggle"> |
|
0b2f838…
|
drh
|
497 |
$laneh = 0.75 |
|
0b2f838…
|
drh
|
498 |
|
|
299e064…
|
drh
|
499 |
ALL: [ |
|
0b2f838…
|
drh
|
500 |
# Draw the lanes |
|
0b2f838…
|
drh
|
501 |
down |
|
0b2f838…
|
drh
|
502 |
box width 3.5in height $laneh fill 0xacc9e3 |
|
0b2f838…
|
drh
|
503 |
box same fill 0xc5d8ef |
|
0b2f838…
|
drh
|
504 |
box same as first box |
|
0b2f838…
|
drh
|
505 |
box same as 2nd box |
|
0b2f838…
|
drh
|
506 |
line from 1st box.sw+(0.2,0) up until even with 1st box.n \ |
|
0b2f838…
|
drh
|
507 |
"Alan" above aligned |
|
0b2f838…
|
drh
|
508 |
line from 2nd box.sw+(0.2,0) up until even with 2nd box.n \ |
|
0b2f838…
|
drh
|
509 |
"Betty" above aligned |
|
0b2f838…
|
drh
|
510 |
line from 3rd box.sw+(0.2,0) up until even with 3rd box.n \ |
|
0b2f838…
|
drh
|
511 |
"Charlie" above aligned |
|
0b2f838…
|
drh
|
512 |
line from 4th box.sw+(0.2,0) up until even with 4th box.n \ |
|
0b2f838…
|
drh
|
513 |
"Darlene" above aligned |
|
0b2f838…
|
drh
|
514 |
|
|
0b2f838…
|
drh
|
515 |
# fill in content for the Alice lane |
|
0b2f838…
|
drh
|
516 |
right |
|
0b2f838…
|
drh
|
517 |
A1: circle rad 0.1in at end of first line + (0.2,-0.2) \ |
|
0b2f838…
|
drh
|
518 |
fill white thickness 1.5px "1" |
|
0b2f838…
|
drh
|
519 |
arrow right 50% |
|
0b2f838…
|
drh
|
520 |
circle same "2" |
|
0b2f838…
|
drh
|
521 |
arrow right until even with first box.e - (0.65,0.0) |
|
0b2f838…
|
drh
|
522 |
ellipse "future" fit fill white height 0.2 width 0.5 thickness 1.5px |
|
0b2f838…
|
drh
|
523 |
A3: circle same at A1+(0.8,-0.3) "3" fill 0xc0c0c0 |
|
0b2f838…
|
drh
|
524 |
arrow from A1 to last circle chop "fork!" below aligned |
|
0b2f838…
|
drh
|
525 |
|
|
0b2f838…
|
drh
|
526 |
# content for the Betty lane |
|
0b2f838…
|
drh
|
527 |
B1: circle same as A1 at A1-(0,$laneh) "1" |
|
0b2f838…
|
drh
|
528 |
arrow right 50% |
|
0b2f838…
|
drh
|
529 |
circle same "2" |
|
0b2f838…
|
drh
|
530 |
arrow right until even with first ellipse.w |
|
0b2f838…
|
drh
|
531 |
ellipse same "future" |
|
0b2f838…
|
drh
|
532 |
B3: circle same at A3-(0,$laneh) "3" |
|
0b2f838…
|
drh
|
533 |
arrow right 50% |
|
0b2f838…
|
drh
|
534 |
circle same as A3 "4" |
|
0b2f838…
|
drh
|
535 |
arrow from B1 to 2nd last circle chop |
|
0b2f838…
|
drh
|
536 |
|
|
0b2f838…
|
drh
|
537 |
# content for the Charlie lane |
|
0b2f838…
|
drh
|
538 |
C1: circle same as A1 at B1-(0,$laneh) "1" |
|
0b2f838…
|
drh
|
539 |
arrow 50% |
|
0b2f838…
|
drh
|
540 |
circle same "2" |
|
0b2f838…
|
drh
|
541 |
arrow right 0.8in "goes" "offline" |
|
0b2f838…
|
drh
|
542 |
C5: circle same as A3 "5" |
|
c3bb7cd…
|
drh
|
543 |
arrow right until even with first ellipse.w \ |
|
c3bb7cd…
|
drh
|
544 |
"back online" above "pushes 5" below "pulls 3 & 4" below |
|
0b2f838…
|
drh
|
545 |
ellipse same "future" |
|
0b2f838…
|
drh
|
546 |
|
|
0b2f838…
|
drh
|
547 |
# content for the Darlene lane |
|
0b2f838…
|
drh
|
548 |
D1: circle same as A1 at C1-(0,$laneh) "1" |
|
0b2f838…
|
drh
|
549 |
arrow 50% |
|
0b2f838…
|
drh
|
550 |
circle same "2" |
|
0b2f838…
|
drh
|
551 |
arrow right until even with C5.w |
|
0b2f838…
|
drh
|
552 |
circle same "5" |
|
0b2f838…
|
drh
|
553 |
arrow 50% |
|
0b2f838…
|
drh
|
554 |
circle same as A3 "6" |
|
0b2f838…
|
drh
|
555 |
arrow right until even with first ellipse.w |
|
0b2f838…
|
drh
|
556 |
ellipse same "future" |
|
0b2f838…
|
drh
|
557 |
D3: circle same as B3 at B3-(0,2*$laneh) "3" |
|
0b2f838…
|
drh
|
558 |
arrow 50% |
|
0b2f838…
|
drh
|
559 |
circle same "4" |
|
0b2f838…
|
drh
|
560 |
arrow from D1 to D3 chop |
|
299e064…
|
drh
|
561 |
] |
|
299e064…
|
drh
|
562 |
box invis "Figure 6" big fit with .n at 0.2cm below ALL.s |
|
0b2f838…
|
drh
|
563 |
</verbatim> |
|
862b77b…
|
wyoung
|
564 |
|
|
862b77b…
|
wyoung
|
565 |
This is a happy, cooperating team. That is an important restriction on |
|
862b77b…
|
wyoung
|
566 |
our example, because you must understand that this sort of problem can |
|
862b77b…
|
wyoung
|
567 |
arise without any malice, selfishness, or willful ignorance in sight. |
|
862b77b…
|
wyoung
|
568 |
All users on this diagram start out with the same view of the |
|
862b77b…
|
wyoung
|
569 |
repository, cloned from the same master repo, and all of them are |
|
862b77b…
|
wyoung
|
570 |
working toward their shared vision of a unified future. |
|
862b77b…
|
wyoung
|
571 |
|
|
862b77b…
|
wyoung
|
572 |
All users, except possibly Alan, start out with the same two initial |
|
f8d210a…
|
wyoung
|
573 |
check-ins in their local working clones, 1 & 2. It might be that Alan |
|
862b77b…
|
wyoung
|
574 |
starts out with only check-in 1 in his local clone, but we'll deal with |
|
862b77b…
|
wyoung
|
575 |
that detail later. |
|
862b77b…
|
wyoung
|
576 |
|
|
862b77b…
|
wyoung
|
577 |
It doesn't matter which branch this happy team is working on, only that |
|
cdd5e57…
|
wyoung
|
578 |
our example makes the most sense if you think of it as a long-lived shared |
|
cdd5e57…
|
wyoung
|
579 |
working branch like trunk. Each user makes |
|
862b77b…
|
wyoung
|
580 |
only one check-in, shaded light gray in the diagram. |
|
862b77b…
|
wyoung
|
581 |
|
|
862b77b…
|
wyoung
|
582 |
<h3 id="bf-alan">Step 1: Alan</h3> |
|
862b77b…
|
wyoung
|
583 |
|
|
862b77b…
|
wyoung
|
584 |
Alan sets the stage for this problem by creating a |
|
862b77b…
|
wyoung
|
585 |
fork from check-in 1 as check-in 3. How and why Alan did this doesn't |
|
862b77b…
|
wyoung
|
586 |
affect what happens next, though we will walk through the possible cases |
|
862b77b…
|
wyoung
|
587 |
and attempt to assign blame [#post-mortem|in the <i>post mortem</i>]. |
|
862b77b…
|
wyoung
|
588 |
For now, you can assume that Alan did this out of unavoidable ignorance. |
|
862b77b…
|
wyoung
|
589 |
|
|
862b77b…
|
wyoung
|
590 |
<h3 id="bf-betty">Step 2: Betty</h3> |
|
862b77b…
|
wyoung
|
591 |
|
|
862b77b…
|
wyoung
|
592 |
Because Betty's local clone is autosyncing with |
|
70a7db8…
|
wyoung
|
593 |
the same upstream repository as Alan's clone, there are a number of ways |
|
70a7db8…
|
wyoung
|
594 |
she can end up seeing Alan's check-in 3 as the latest on that branch: |
|
70a7db8…
|
wyoung
|
595 |
|
|
70a7db8…
|
wyoung
|
596 |
<ol> |
|
70a7db8…
|
wyoung
|
597 |
<li><p>The working check-out directory she's using at the moment was |
|
70a7db8…
|
wyoung
|
598 |
on a different branch at the time Alan made check-in 3, so Fossil |
|
70a7db8…
|
wyoung
|
599 |
sees that as the tip at the time she switches her working directory |
|
862b77b…
|
wyoung
|
600 |
to that branch with a <b>fossil update $BRANCH</b> command. (There is an |
|
862b77b…
|
wyoung
|
601 |
implicit autosync in that command, if the option was enabled at the |
|
862b77b…
|
wyoung
|
602 |
time of the update.)</p></li> |
|
70a7db8…
|
wyoung
|
603 |
|
|
70a7db8…
|
wyoung
|
604 |
<li><p>The same thing, only in a fresh checkout directory with a |
|
c64f28d…
|
drh
|
605 |
<b>[/help/open | fossil open $REPO $BRANCH]</b> command.</p></li> |
|
70a7db8…
|
wyoung
|
606 |
|
|
70a7db8…
|
wyoung
|
607 |
<li><p>Alan makes his check-in 3 while Betty has check-in 1 or 2 as |
|
70a7db8…
|
wyoung
|
608 |
the tip in her local clone, but because she's working with an |
|
70a7db8…
|
wyoung
|
609 |
autosync'd connection to the same upstream repository as Alan, on |
|
70a7db8…
|
wyoung
|
610 |
attempting what will become check-in 4, she gets the "would fork" |
|
f8d210a…
|
wyoung
|
611 |
message from <b>fossil commit</b>, so she dutifully updates her clone |
|
70a7db8…
|
wyoung
|
612 |
and tries again, moving her work to be a child of the new tip, |
|
70a7db8…
|
wyoung
|
613 |
check-in 3. (If she doesn't update, she creates a <i>second</i> |
|
70a7db8…
|
wyoung
|
614 |
fork, which simply complicates matters beyond what we need here for |
|
70a7db8…
|
wyoung
|
615 |
our illustration.)</p></li> |
|
70a7db8…
|
wyoung
|
616 |
</ol> |
|
70a7db8…
|
wyoung
|
617 |
|
|
70a7db8…
|
wyoung
|
618 |
For our purposes here, it doesn't really matter which one happened. All |
|
862b77b…
|
wyoung
|
619 |
that matters is that Alan's check-in 3 becomes the parent of Betty's |
|
862b77b…
|
wyoung
|
620 |
check-in 4 because it was the newest tip of the working branch at the |
|
862b77b…
|
wyoung
|
621 |
time Betty does her check-in. |
|
862b77b…
|
wyoung
|
622 |
|
|
862b77b…
|
wyoung
|
623 |
<h3 id="bf-charlie">Step 3: Charlie</h3> |
|
70a7db8…
|
wyoung
|
624 |
|
|
862b77b…
|
wyoung
|
625 |
Meanwhile, Charlie went offline after syncing |
|
70a7db8…
|
wyoung
|
626 |
his repo with check-in 2 as the latest on that branch. When he checks |
|
70a7db8…
|
wyoung
|
627 |
his changes in, it is as a child of 2, not of 4, because Charlie doesn't |
|
70a7db8…
|
wyoung
|
628 |
know about check-ins 3 & 4 yet. He does this at an absolute wall clock |
|
70a7db8…
|
wyoung
|
629 |
time <i>after</i> Alan and Betty made their check-ins, so when Charlie |
|
70a7db8…
|
wyoung
|
630 |
comes back online and pushes his check-in 5 to the master repository and |
|
70a7db8…
|
wyoung
|
631 |
learns about check-ins 3 and 4 during Fossil sync, Charlie inadvertently |
|
70a7db8…
|
wyoung
|
632 |
revives the other side of the fork. |
|
70a7db8…
|
wyoung
|
633 |
|
|
862b77b…
|
wyoung
|
634 |
<h3 id="bf-darlene">Step 4: Darlene</h3> |
|
862b77b…
|
wyoung
|
635 |
|
|
862b77b…
|
wyoung
|
636 |
Darlene sees all of this, because she joins in |
|
70a7db8…
|
wyoung
|
637 |
on the work on this branch after Alan, Betty, and Charlie made their |
|
70a7db8…
|
wyoung
|
638 |
check-ins and pushed them to the master repository. She's taking one of |
|
70a7db8…
|
wyoung
|
639 |
the same three steps as we [#bf-betty|outlined for Betty above]. |
|
70a7db8…
|
wyoung
|
640 |
Regardless of her path to this view, it happens after Charlie pushed his |
|
70a7db8…
|
wyoung
|
641 |
check-in 5 to the master repo, so Darlene sees that as the latest on the |
|
70a7db8…
|
wyoung
|
642 |
branch, causing her work to be saved as a child of check-in 5, not of |
|
70a7db8…
|
wyoung
|
643 |
check-in 4, as it would if Charlie didn't come back online and sync |
|
cdd5e57…
|
wyoung
|
644 |
before Darlene started work on that branch. |
|
2ac5bc3…
|
wyoung
|
645 |
|
|
2ac5bc3…
|
wyoung
|
646 |
<h3 id="post-mortem">Post Mortem</h3> |
|
2ac5bc3…
|
wyoung
|
647 |
|
|
862b77b…
|
wyoung
|
648 |
The end result of all of this is that even though everyone makes only one check-in |
|
862b77b…
|
wyoung
|
649 |
and no one disables autosync without genuine need, |
|
862b77b…
|
wyoung
|
650 |
half of the check-ins end up on one side of the fork and half on |
|
862b77b…
|
wyoung
|
651 |
the other. |
|
862b77b…
|
wyoung
|
652 |
|
|
862b77b…
|
wyoung
|
653 |
A future user — his mother calls him Edward, but please call him Eddie — |
|
70a7db8…
|
wyoung
|
654 |
can then join in on the work on this branch and end up on <i>either</i> side of |
|
70a7db8…
|
wyoung
|
655 |
the fork. If Eddie joins in with the state of the repository as drawn |
|
2ac5bc3…
|
wyoung
|
656 |
above, he'll end up on the top side of the fork, because check-in 6 is |
|
2ac5bc3…
|
wyoung
|
657 |
the latest, but if Alan or Betty makes a seventh check-in to that branch |
|
2ac5bc3…
|
wyoung
|
658 |
first, it will be as a child of check-in 4 since that's the version in |
|
2ac5bc3…
|
wyoung
|
659 |
their local check-out directories. Since that check-in 7 will then be the latest, |
|
2ac5bc3…
|
wyoung
|
660 |
Eddie will end up on the bottom side of the fork instead. |
|
c16f7cb…
|
wyoung
|
661 |
|
|
c16f7cb…
|
wyoung
|
662 |
In all of this, realize that neither side of the fork is obviously |
|
efb104b…
|
wyoung
|
663 |
"correct." Every participant was doing the right thing by their own |
|
70a7db8…
|
wyoung
|
664 |
lights at the time they made their lone check-in. |
|
70a7db8…
|
wyoung
|
665 |
|
|
70a7db8…
|
wyoung
|
666 |
Who, then, is to blame? |
|
70a7db8…
|
wyoung
|
667 |
|
|
70a7db8…
|
wyoung
|
668 |
We can only blame the consequences of creating the fork on Alan if he |
|
70a7db8…
|
wyoung
|
669 |
did so on purpose, as by passing "--allow-fork" when creating a check-in |
|
70a7db8…
|
wyoung
|
670 |
on a shared working branch. Alan might have created it inadvertently by |
|
70a7db8…
|
wyoung
|
671 |
going offline while check-in 1 was the tip of the branch in his local |
|
70a7db8…
|
wyoung
|
672 |
clone, so that by the time he made his check-in 3, check-in 2 had |
|
70a7db8…
|
wyoung
|
673 |
arrived at the shared parent repository from someone else. (Francine?) |
|
70a7db8…
|
wyoung
|
674 |
When Alan rejoins the network and does an autosync, he learns about |
|
70a7db8…
|
wyoung
|
675 |
check-in 2. Since his #3 is already checked into his local clone because |
|
70a7db8…
|
wyoung
|
676 |
autosync was off or blocked, the sync creates an unavoidable fork. We |
|
70a7db8…
|
wyoung
|
677 |
can't blame either Alan or Francine here: they were both doing the right |
|
70a7db8…
|
wyoung
|
678 |
thing given their imperfect view of the state of the global situation. |
|
70a7db8…
|
wyoung
|
679 |
|
|
70a7db8…
|
wyoung
|
680 |
The same is true of Betty, Charlie, and Darlene. None of them tried to |
|
70a7db8…
|
wyoung
|
681 |
create a fork, and none of them chose a side in this fork to participate |
|
70a7db8…
|
wyoung
|
682 |
in. They just took Fossil's default and assumed it was correct. |
|
70a7db8…
|
wyoung
|
683 |
|
|
70a7db8…
|
wyoung
|
684 |
The only blame I can assign here is on any of these users who believed |
|
862b77b…
|
wyoung
|
685 |
forks couldn't happen before this did occur, and I blame them only for |
|
862b77b…
|
wyoung
|
686 |
their avoidable ignorance. (You, dear reader, have been ejected from |
|
862b77b…
|
wyoung
|
687 |
that category by reading this very document.) Any time someone can work |
|
862b77b…
|
wyoung
|
688 |
without getting full coordination from every other clone of the repo, |
|
862b77b…
|
wyoung
|
689 |
forks are possible. Given enough time, they're all but inevitable. This |
|
862b77b…
|
wyoung
|
690 |
is a general property of DVCSes, not just of Fossil. |
|
70a7db8…
|
wyoung
|
691 |
|
|
70a7db8…
|
wyoung
|
692 |
This sort of consequence is why forks on shared working branches are |
|
862b77b…
|
wyoung
|
693 |
bad, which is why [./concepts.wiki#workflow|Fossil tries so hard to avoid them], why it warns you |
|
862b77b…
|
wyoung
|
694 |
about it when they do occur, and why it makes it relatively [#fix|quick and |
|
862b77b…
|
wyoung
|
695 |
painless to fix them] when they do occur. |
|
efb104b…
|
wyoung
|
696 |
|
|
efb104b…
|
wyoung
|
697 |
|
|
2e275c1…
|
drh
|
698 |
<h2>Review Of Terminology</h2> |
|
2e275c1…
|
drh
|
699 |
|
|
8a1ba49…
|
wyoung
|
700 |
<dl> |
|
2e275c1…
|
drh
|
701 |
<dt><b>Branch</b></dt> |
|
d06396d…
|
drh
|
702 |
<dd><p>A branch is a set of check-ins with the same value for their |
|
c1c18b7…
|
drh
|
703 |
"branch" property.</p></dd> |
|
2e275c1…
|
drh
|
704 |
<dt><b>Leaf</b></dt> |
|
d06396d…
|
drh
|
705 |
<dd><p>A leaf is a check-in with no children in the same branch.</p></dd> |
|
2e275c1…
|
drh
|
706 |
<dt><b>Closed Leaf</b></dt> |
|
d06396d…
|
drh
|
707 |
<dd><p>A closed leaf is any leaf with the <b>closed</b> tag. These leaves |
|
d06396d…
|
drh
|
708 |
are intended to never be extended with descendants and hence are omitted |
|
2e275c1…
|
drh
|
709 |
from lists of leaves in the command-line and web interface.</p></dd> |
|
2e275c1…
|
drh
|
710 |
<dt><b>Open Leaf</b></dt> |
|
2e275c1…
|
drh
|
711 |
<dd><p>A open leaf is a leaf that is not closed.</p></dd> |
|
2e275c1…
|
drh
|
712 |
<dt><b>Fork</b></dt> |
|
d06396d…
|
drh
|
713 |
<dd><p>A fork is when a check-in has two or more direct (non-merge) |
|
2e275c1…
|
drh
|
714 |
children in the same branch.</p></dd> |
|
2e275c1…
|
drh
|
715 |
<dt><b>Branch Point</b></dt> |
|
2e275c1…
|
drh
|
716 |
<dd><p>A branch point occurs when a check-in has two or more direct (non-merge) |
|
d06396d…
|
drh
|
717 |
children in different branches. A branch point is similar to a fork, |
|
2e275c1…
|
drh
|
718 |
except that the children are in different branches.</p></dd> |
|
8a1ba49…
|
wyoung
|
719 |
</dl> |
|
2e275c1…
|
drh
|
720 |
|
|
b882c62…
|
wyoung
|
721 |
Check-in 4 of Figure 3 is not a leaf because it has a child (check-in 5) |
|
b882c62…
|
wyoung
|
722 |
in the same branch. Check-in 9 of Figure 5 also has a child (check-in 10) |
|
2e275c1…
|
drh
|
723 |
but that child is in a different branch, so check-in 9 is a leaf. Because |
|
d06396d…
|
drh
|
724 |
of the <b>closed</b> tag on check-in 9, it is a closed leaf. |
|
2e275c1…
|
drh
|
725 |
|
|
b882c62…
|
wyoung
|
726 |
Check-in 2 of Figure 3 is considered a "fork" |
|
b882c62…
|
wyoung
|
727 |
because it has two children in the same branch. Check-in 2 of Figure 5 |
|
2e275c1…
|
drh
|
728 |
also has two children, but each child is in a different branch, hence in |
|
b882c62…
|
wyoung
|
729 |
Figure 5, check-in 2 is considered a "branch point." |
|
c1c18b7…
|
drh
|
730 |
|
|
c1c18b7…
|
drh
|
731 |
<h2>Differences With Other DVCSes</h2> |
|
b882c62…
|
wyoung
|
732 |
|
|
42bfe93…
|
wyoung
|
733 |
<h3 id="single">Single DAG</h3> |
|
42bfe93…
|
wyoung
|
734 |
|
|
c1c18b7…
|
drh
|
735 |
Fossil keeps all check-ins on a single DAG. Branches are identified with |
|
c1c18b7…
|
drh
|
736 |
tags. This means that check-ins can be freely moved between branches |
|
d06396d…
|
drh
|
737 |
simply by altering their tags. |
|
c1c18b7…
|
drh
|
738 |
|
|
c1c18b7…
|
drh
|
739 |
Most other DVCSes maintain a separate DAG for each branch. |
|
42bfe93…
|
wyoung
|
740 |
|
|
42bfe93…
|
wyoung
|
741 |
<h3 id="unique">Branch Names Need Not Be Unique</h3> |
|
42bfe93…
|
wyoung
|
742 |
|
|
42bfe93…
|
wyoung
|
743 |
Fossil does not require that branch names be unique, as in some VCSes, |
|
42bfe93…
|
wyoung
|
744 |
most notably Git. Just as with unnamed branches (which we call forks) |
|
42bfe93…
|
wyoung
|
745 |
Fossil resolves such ambiguities using the timestamps on the latest |
|
f8d210a…
|
wyoung
|
746 |
check-in in each branch. If you have two branches named "foo" and you say |
|
f8d210a…
|
wyoung
|
747 |
<b>fossil update foo</b>, you get the tip of the "foo" branch with the most |
|
f8d210a…
|
wyoung
|
748 |
recent check-in. |
|
42bfe93…
|
wyoung
|
749 |
|
|
42bfe93…
|
wyoung
|
750 |
This fact is helpful because it means you can reuse branch names, which |
|
42bfe93…
|
wyoung
|
751 |
is especially useful with utility branches. There are several of these |
|
42bfe93…
|
wyoung
|
752 |
in the SQLite and Fossil repositories: "broken-build," "declined," |
|
42bfe93…
|
wyoung
|
753 |
"mistake," etc. As you might guess from these names, such branch names |
|
42bfe93…
|
wyoung
|
754 |
are used in renaming the tip of one branch to shunt it off away from the |
|
f8d210a…
|
wyoung
|
755 |
mainline of that branch due to some human error. (See |
|
c64f28d…
|
drh
|
756 |
<b>[/help/amend | fossil |
|
f8d210a…
|
wyoung
|
757 |
amend]</b> and the Fossil UI check-in amendment features.) This is a |
|
42bfe93…
|
wyoung
|
758 |
workaround for Fossil's [./shunning.wiki|normal inability to forget |
|
42bfe93…
|
wyoung
|
759 |
history]: we usually don't want to actually <i>remove</i> history, but |
|
42bfe93…
|
wyoung
|
760 |
would like to sometimes set some of it aside under a new label. |
|
42bfe93…
|
wyoung
|
761 |
|
|
42bfe93…
|
wyoung
|
762 |
Because some VCSes can't cope with duplicate branch names, Fossil |
|
0996347…
|
wyoung
|
763 |
collapses such names down on export using the same time stamp based |
|
f8d210a…
|
wyoung
|
764 |
arbitration logic, so that only the branch with the newest check-in gets |
|
42bfe93…
|
wyoung
|
765 |
the branch name in the export. |
|
42bfe93…
|
wyoung
|
766 |
|
|
42bfe93…
|
wyoung
|
767 |
All of the above is true of tags in general, not just branches. |