Fossil

Check-in [862b77b6]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Assorted improvements to the new material in www/branching.wiki, mainly in the way of clarifications and moderation of tone.
Downloads: Tarball | ZIP archive | SQL archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA3-256: 862b77b69aae9e0b1c7eb49135342a982b51e9840b84bf759894c6a981dd8b89
User & Date: wyoung 2019-06-27 23:12:23
Context
2019-06-27
23:37
Small fixes to branching.wiki check-in: cdd5e576 user: wyoung tags: trunk
23:12
Assorted improvements to the new material in www/branching.wiki, mainly in the way of clarifications and moderation of tone. check-in: 862b77b6 user: wyoung tags: trunk
14:39
Upgrade to openssl 1.1.1c. Use single-argument "expr" in auto.def. Update custom mingw makefile. check-in: 50501328 user: jan.nijtmans tags: trunk
Changes
Hide Diffs Unified Diffs Ignore Whitespace Patch

Changes to www/branching.wiki.

232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250







251
252


253
254
255
256
257
258

259
260
261









262
263


264
265
266
267
268
269
270
271
272
...
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389



390
391








392
393
394


395
396
397
398

399

400


401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
...
421
422
423
424
425
426
427
428

429
430


431
432
433
434
435
436
437
438
439


440
441
442
443
444
445
446
447
448
449
450
451
452
453



454
455
456
457
458
459
460
461
...
479
480
481
482
483
484
485
486
487

488
489
490

491
492
493
494
495
496
497
498
499
500
501
502

<h2 id="forking">Justifications For Forking</h2>

The primary cases where forking is justified over branching are all when
it is done purely in software in order to avoid losing information:

<ol>
    <li><p>By Fossil itself when two users check in children to the same
    leaf of a branch, as in Figure 2.  If the fork occurs because
    autosync is disabled on one or both of the repositories or because
    the user doing the check-in has no network connection at the moment
    of the commit, Fossil has no way of knowing that it is creating a
    fork until the two repositories are later sync'd.</p></li>

    <li><p>By Fossil when the cloning hierarchy is more than 2 levels
    deep. If your master repository is cloned by user A and then user B
    clones from user A's repository, a check-in by user B will cause
    that repo to attempt an autosync with user A's repo before allowing
    the checkin, but it will <i>not</i> check with the master repo as







    well. It isn't until user A syncs her repo with the
    master repo that an inadvertent fork can be detected.


    <br><br>
    Because of this, we recommend that if you're using Fossil in a
    distributed way like this, that check-ins be made only to the master
    or its immediate child repos, and that those further down the chain
    be read-only clones. This is not to say that we repudiate Fossil's
    use as a

    [https://en.wikipedia.org/wiki/Distributed_version_control|Distributed Version Control System],
    just that such use is
    prone to creating inadvertent forks by the very nature of distributed development.









    We make a more complete argument that [#bad-fork|forks on long-lived
    shared working branches are a problem] below.</p></li>



    <li><p>You've automated Fossil (e.g. with a shell script) and
    forking is a possibility, so you write <b>fossil commit
    --allow-fork</b> commands to prevent Fossil from refusing the
    check-in because it would create a fork.  It's better to write such
    a script to detect this condition and cope with it (e.g. <b>fossil
    update</b>) but if the alternative is losing information, you may
    feel justified in creating forks that an interactive user must later
    clean up with <b>fossil merge</b> commands.</p></li>
................................................................................
The <b>sym-release-1.0</b> tag means that check-in 9 can be referred to
using the more meaningful name "release-1.0."  The <b>closed</b> tag means
that check-in 9 is a "closed leaf."  A closed leaf is a leaf that should
never have direct children.

<h2 id="bad-fork">How Can Forks Divide Development Effort?</h2>

[#forking|Above], we stated that forks carry a risk that development
effort on a branch can be divided among the forks. It might not be
immediately obvious why this is so. To see it, consider this swim lane
diagram:

<table border=1 cellpadding=10 hspace=10 vspace=10 align="center">
<tr><td align="center">
<img src="branch06.svg"><br>
Figure 6
</td></tr></table>

All users in this diagram start off with the same two checkins at the
tip of the working branch, 1 and 2, they're all cloned directly from the
same master repository, and they're all working towards some indefinite,
unified future. This is a happy, cooperating team, with no malice or



selfishness in sight. This is all happening on some long-lived, shared
working branch, such as trunk, though it could be anything else that








matches those same qualifiers. Each user makes only one check-in, shaded
light gray.



<a name="bf-alan"></a>Alan sets the stage for this problem by creating a
fork from check-in 1 as check-in 3. This has consequences which will
occur regardless of how or why that fork occurred, so we can ignore both
questions for now.  We'll come back to these questions later in

[#post-mortem|the <i>post mortem</i> below].




<a name="bf-betty"></a>Because Betty's local clone is autosyncing with
the same upstream repository as Alan's clone, there are a number of ways
she can end up seeing Alan's check-in 3 as the latest on that branch:

<ol>
    <li><p>The working check-out directory she's using at the moment was
    on a different branch at the time Alan made check-in 3, so Fossil
    sees that as the tip at the time she switches her working directory
    to that branch with a <b>fossil update</b> command. (There is an
    implicit autosync before <b>update</b> if that option is enabled at
    the time.)</p></li>

    <li><p>The same thing, only in a fresh checkout directory with a
    <b>fossil open $REPO $BRANCH</b> command.</p></li>

    <li><p>Alan makes his check-in 3 while Betty has check-in 1 or 2 as
    the tip in her local clone, but because she's working with an
    autosync'd connection to the same upstream repository as Alan, on
................................................................................
    and tries again, moving her work to be a child of the new tip,
    check-in 3. (If she doesn't update, she creates a <i>second</i>
    fork, which simply complicates matters beyond what we need here for
    our illustration.)</p></li>
</ol>

For our purposes here, it doesn't really matter which one happened. All
that matters is that this new branch tip becomes the parent of Betty's

check-in 4.



<a name="bf-charlie"></a>Meanwhile, Charlie went offline after syncing
his repo with check-in 2 as the latest on that branch. When he checks
his changes in, it is as a child of 2, not of 4, because Charlie doesn't
know about check-ins 3 & 4 yet.  He does this at an absolute wall clock
time <i>after</i> Alan and Betty made their check-ins, so when Charlie
comes back online and pushes his check-in 5 to the master repository and
learns about check-ins 3 and 4 during Fossil sync, Charlie inadvertently
revives the other side of the fork.



<a name="bf-darlene"></a>Darlene sees all of this, because she joins in
on the work on this branch after Alan, Betty, and Charlie made their
check-ins and pushed them to the master repository. She's taking one of
the same three steps as we [#bf-betty|outlined for Betty above].
Regardless of her path to this view, it happens after Charlie pushed his
check-in 5 to the master repo, so Darlene sees that as the latest on the
branch, causing her work to be saved as a child of check-in 5, not of
check-in 4, as it would if Charlie didn't come back online and sync
before Darlene started work on that branch up.

<h3 id="post-mortem">Post Mortem</h3>

The end result of all of this is that everyone makes only one check-in,
but half of the check-ins are on one side of the fork, and half are on



the other. A future user — his mother calls him Edward, but please call him Eddie —
can then join in on the work on this branch and end up on <i>either</i> side of
the fork. If Eddie joins in with the state of the repository as drawn
above, he'll end up on the top side of the fork, because check-in 6 is
the latest, but if Alan or Betty makes a seventh check-in to that branch
first, it will be as a child of check-in 4 since that's the version in
their local check-out directories. Since that check-in 7 will then be the latest,
Eddie will end up on the bottom side of the fork instead.
................................................................................
thing given their imperfect view of the state of the global situation.

The same is true of Betty, Charlie, and Darlene. None of them tried to
create a fork, and none of them chose a side in this fork to participate
in. They just took Fossil's default and assumed it was correct.

The only blame I can assign here is on any of these users who believed
forks couldn't happen before this did occur, and that's for their
ignorance. (Which isn't you, dear reader, now.) Any time someone can

work without getting full coordination from every other clone of the
repo, forks are possible.  Given enough time, they're all but
inevitable.


This sort of consequence is why forks on shared working branches are
bad, which is why Fossil tries so hard to avoid them, why it warns you
about it when they do occur, and why it makes it relatively quick and
painless to fix them when they do occur.


<h2>Review Of Terminology</h2>

<blockquote><dl>
<dt><b>Branch</b></dt>
<dd><p>A branch is a set of check-ins with the same value for their







|






|
|
|
|
|
>
>
>
>
>
>
>
|
<
>
>

<
<
<
<
<
>
|
<
<
>
>
>
>
>
>
>
>
>
|
|
>
>

|







 







|










<
<
<
|
>
>
>
|
|
>
>
>
>
>
>
>
>
|
<

>
>
|
|
<
<
>
|
>

>
>
|







|
|
|







 







|
>
|

>
>
|








>
>
|











|
|
>
>
>
|







 







|
|
>
|
|
<
>


|
|
|







232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258

259
260
261





262
263


264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
...
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398



399
400
401
402
403
404
405
406
407
408
409
410
411
412
413

414
415
416
417
418


419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
...
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
...
511
512
513
514
515
516
517
518
519
520
521
522

523
524
525
526
527
528
529
530
531
532
533
534
535

<h2 id="forking">Justifications For Forking</h2>

The primary cases where forking is justified over branching are all when
it is done purely in software in order to avoid losing information:

<ol>
    <li><p id="offline">By Fossil itself when two users check in children to the same
    leaf of a branch, as in Figure 2.  If the fork occurs because
    autosync is disabled on one or both of the repositories or because
    the user doing the check-in has no network connection at the moment
    of the commit, Fossil has no way of knowing that it is creating a
    fork until the two repositories are later sync'd.</p></li>

    <li><p id="dist-clone">By Fossil when the cloning hierarchy is more
    than 2 levels deep.
    <br><br>
    [./sync.wiki|Fossil's synchronication protocol] is a two-party
    negotiation; syncs don't automatically propagate up the clone tree
    beyond that. Because of that, if you have a master repository and
    Alice clones it, then Bobby clones from Alice's repository, a
    check-in by Bobby that autosyncs with Alice's repo will <i>not</i>
    also autosync with the master repo. The master doesn't get a copy of
    Bobby's checkin until Alice <i>separately</i> syncs with the master.
    If Carol cloned from the master repo and checks something in that
    creates a fork relative to Bobby's check-in, the master repo won't
    know about that fork until Alice syncs her repo with the master.

    Even then, realize that Carol still won't know about the fork until
    she subsequently syncs with the master repo.
    <br><br>





    One way to deal with this is to just accept it as a fact of using a
    [https://en.wikipedia.org/wiki/Distributed_version_control|Distributed


    Version Control System] like Fossil.
    <br><br>
    Another option, which we recommend you consider carefully, is to
    make it a local policy that checkins be made only against the master
    repo or one of its immediate child clones so that the autosync
    algorithm can do its job most effectively; any clones deeper than
    that should be treated as read-only and thus get a copy of the new
    state of the world only once these central repos have negotiated
    that new state. This policy avoids a class of inadvertent fork you
    might not need to tolerate.  Since [#bad-fork|forks on long-lived
    shared working branches can end up dividing a team's development
    effort], a team may easily justify this restriction on distributed
    cloning.</p></li>

    <li><p id="automation">You've automated Fossil (e.g. with a shell script) and
    forking is a possibility, so you write <b>fossil commit
    --allow-fork</b> commands to prevent Fossil from refusing the
    check-in because it would create a fork.  It's better to write such
    a script to detect this condition and cope with it (e.g. <b>fossil
    update</b>) but if the alternative is losing information, you may
    feel justified in creating forks that an interactive user must later
    clean up with <b>fossil merge</b> commands.</p></li>
................................................................................
The <b>sym-release-1.0</b> tag means that check-in 9 can be referred to
using the more meaningful name "release-1.0."  The <b>closed</b> tag means
that check-in 9 is a "closed leaf."  A closed leaf is a leaf that should
never have direct children.

<h2 id="bad-fork">How Can Forks Divide Development Effort?</h2>

[#dist-clone|Above], we stated that forks carry a risk that development
effort on a branch can be divided among the forks. It might not be
immediately obvious why this is so. To see it, consider this swim lane
diagram:

<table border=1 cellpadding=10 hspace=10 vspace=10 align="center">
<tr><td align="center">
<img src="branch06.svg"><br>
Figure 6
</td></tr></table>




This is a happy, cooperating team. That is an important restriction on
our example, because you must understand that this sort of problem can
arise without any malice, selfishness, or willful ignorance in sight.
All users on this diagram start out with the same view of the
repository, cloned from the same master repo, and all of them are
working toward their shared vision of a unified future.

All users, except possibly Alan, start out with the same two initial
checkins in their local working clones, 1 & 2. It might be that Alan
starts out with only check-in 1 in his local clone, but we'll deal with
that detail later.

It doesn't matter which branch this happy team is working on, only that
it be a long-lived shared working branch like trunk. Each user makes
only one check-in, shaded light gray in the diagram.


<h3 id="bf-alan">Step 1: Alan</h3>

Alan sets the stage for this problem by creating a
fork from check-in 1 as check-in 3. How and why Alan did this doesn't


affect what happens next, though we will walk through the possible cases
and attempt to assign blame [#post-mortem|in the <i>post mortem</i>].
For now, you can assume that Alan did this out of unavoidable ignorance.

<h3 id="bf-betty">Step 2: Betty</h3>

Because Betty's local clone is autosyncing with
the same upstream repository as Alan's clone, there are a number of ways
she can end up seeing Alan's check-in 3 as the latest on that branch:

<ol>
    <li><p>The working check-out directory she's using at the moment was
    on a different branch at the time Alan made check-in 3, so Fossil
    sees that as the tip at the time she switches her working directory
    to that branch with a <b>fossil update $BRANCH</b> command. (There is an
    implicit autosync in that command, if the option was enabled at the
    time of the update.)</p></li>

    <li><p>The same thing, only in a fresh checkout directory with a
    <b>fossil open $REPO $BRANCH</b> command.</p></li>

    <li><p>Alan makes his check-in 3 while Betty has check-in 1 or 2 as
    the tip in her local clone, but because she's working with an
    autosync'd connection to the same upstream repository as Alan, on
................................................................................
    and tries again, moving her work to be a child of the new tip,
    check-in 3. (If she doesn't update, she creates a <i>second</i>
    fork, which simply complicates matters beyond what we need here for
    our illustration.)</p></li>
</ol>

For our purposes here, it doesn't really matter which one happened. All
that matters is that Alan's check-in 3 becomes the parent of Betty's
check-in 4 because it was the newest tip of the working branch at the
time Betty does her check-in.

<h3 id="bf-charlie">Step 3: Charlie</h3>

Meanwhile, Charlie went offline after syncing
his repo with check-in 2 as the latest on that branch. When he checks
his changes in, it is as a child of 2, not of 4, because Charlie doesn't
know about check-ins 3 & 4 yet.  He does this at an absolute wall clock
time <i>after</i> Alan and Betty made their check-ins, so when Charlie
comes back online and pushes his check-in 5 to the master repository and
learns about check-ins 3 and 4 during Fossil sync, Charlie inadvertently
revives the other side of the fork.

<h3 id="bf-darlene">Step 4: Darlene</h3>

Darlene sees all of this, because she joins in
on the work on this branch after Alan, Betty, and Charlie made their
check-ins and pushed them to the master repository. She's taking one of
the same three steps as we [#bf-betty|outlined for Betty above].
Regardless of her path to this view, it happens after Charlie pushed his
check-in 5 to the master repo, so Darlene sees that as the latest on the
branch, causing her work to be saved as a child of check-in 5, not of
check-in 4, as it would if Charlie didn't come back online and sync
before Darlene started work on that branch up.

<h3 id="post-mortem">Post Mortem</h3>

The end result of all of this is that even though everyone makes only one check-in
and no one disables autosync without genuine need,
half of the check-ins end up on one side of the fork and half on
the other.

A future user — his mother calls him Edward, but please call him Eddie —
can then join in on the work on this branch and end up on <i>either</i> side of
the fork. If Eddie joins in with the state of the repository as drawn
above, he'll end up on the top side of the fork, because check-in 6 is
the latest, but if Alan or Betty makes a seventh check-in to that branch
first, it will be as a child of check-in 4 since that's the version in
their local check-out directories. Since that check-in 7 will then be the latest,
Eddie will end up on the bottom side of the fork instead.
................................................................................
thing given their imperfect view of the state of the global situation.

The same is true of Betty, Charlie, and Darlene. None of them tried to
create a fork, and none of them chose a side in this fork to participate
in. They just took Fossil's default and assumed it was correct.

The only blame I can assign here is on any of these users who believed
forks couldn't happen before this did occur, and I blame them only for
their avoidable ignorance. (You, dear reader, have been ejected from
that category by reading this very document.) Any time someone can work
without getting full coordination from every other clone of the repo,
forks are possible.  Given enough time, they're all but inevitable. This

is a general property of DVCSes, not just of Fossil.

This sort of consequence is why forks on shared working branches are
bad, which is why [./concepts.wiki#workflow|Fossil tries so hard to avoid them], why it warns you
about it when they do occur, and why it makes it relatively [#fix|quick and
painless to fix them] when they do occur.


<h2>Review Of Terminology</h2>

<blockquote><dl>
<dt><b>Branch</b></dt>
<dd><p>A branch is a set of check-ins with the same value for their