Fossil SCM

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

Keyboard Shortcuts

Open search /
Next entry (timeline) j
Previous entry (timeline) k
Open focused entry Enter
Show this help ?
Toggle theme Top nav button