summaryrefslogtreecommitdiff
path: root/www/branching.wiki
diff options
context:
space:
mode:
Diffstat (limited to 'www/branching.wiki')
-rw-r--r--www/branching.wiki767
1 files changed, 767 insertions, 0 deletions
diff --git a/www/branching.wiki b/www/branching.wiki
new file mode 100644
index 0000000..90eb265
--- /dev/null
+++ b/www/branching.wiki
@@ -0,0 +1,767 @@
+<title>Branching, Forking, Merging, and Tagging</title>
+<h2>Background</h2>
+
+In a simple and perfect world, the development of a project would proceed
+linearly, as shown in Figure 1.
+
+<verbatim type="pikchr center toggle">
+ALL: [circle rad 0.1in thickness 1.5px "1"
+arrow right 40%
+circle same "2"
+arrow same
+circle same "3"
+arrow same
+circle same "4"]
+box invis "Figure 1" big fit with .n at .3cm below ALL.s
+</verbatim>
+
+Each circle represents a check-in. For the sake of clarity, the check-ins
+are given small consecutive numbers. In a real system, of course, the
+check-in numbers would be long hexadecimal hashes since it is not possible
+to allocate collision-free sequential numbers in a distributed system.
+But as sequential numbers are easier to read, we will substitute them for
+the long hashes in this document.
+
+The arrows in Figure 1 show the evolution of a project. The initial
+check-in is 1. Check-in 2 is derived from 1. In other words, check-in 2
+was created by making edits to check-in 1 and then committing those edits.
+We say that 2 is a <i>child</i> of 1
+and that 1 is a <i>parent</i> of 2.
+Check-in 3 is derived from check-in 2, making
+3 a child of 2. We say that 3 is a <i>descendant</i> of both 1 and 2 and that 1
+and 2 are both <i>ancestors</i> of 3.
+
+<h2 id="dag">DAGs</h2>
+
+The graph of check-ins is a
+[http://en.wikipedia.org/wiki/Directed_acyclic_graph | directed acyclic graph],
+commonly shortened to <i>DAG</i>. Check-in 1 is the <i>root</i> of the DAG
+since it has no ancestors. Check-in 4 is a <i>leaf</i> of the DAG since
+it has no descendants. (We will give a more precise definition later of
+"leaf.")
+
+Alas, reality often interferes with the simple linear development of a
+project. Suppose two programmers make independent modifications to check-in 2.
+After both changes are committed, the check-in graph looks like Figure 2:
+
+<verbatim type="pikchr center toggle">
+ALL: [circle rad 0.1in thickness 1.5px "1"
+arrow right 40%
+circle same "2"
+circle same "3" at 2nd circle+(.4,.3)
+arrow from 2nd circle to 3rd circle chop
+circle same "4" at 2nd circle+(.4,-.3)
+arrow from 2nd circle to 4th circle chop]
+box invis "Figure 2" big fit with .n at .3cm below ALL.s
+</verbatim>
+
+The graph in Figure 2 has two leaves: check-ins 3 and 4. Check-in 2 has
+two children, check-ins 3 and 4. We call this state a <i>fork</i>.
+
+Fossil tries to prevent forks, primarily through its
+"[./concepts.wiki#workflow | autosync]" mechanism.
+
+Suppose two programmers named Alice and
+Bob are each editing check-in 2 separately. Alice finishes her edits
+and commits her changes first, resulting in check-in 3. When Bob later
+attempts to commit his changes, Fossil verifies that check-in 2 is still
+a leaf. Fossil sees that check-in 3 has occurred and aborts Bob's commit
+attempt with a message "would fork." This allows Bob to do a "fossil
+update" to pull in Alice's changes, merging them into his own
+changes. After merging, Bob commits check-in 4 as a child of check-in 3.
+The result is a linear graph as shown in Figure 1. This is how CVS
+works. This is also how Fossil works in autosync mode.
+
+But perhaps Bob is off-network when he does his commit, so he has no way
+of knowing that Alice has already committed her changes. Or, it could
+be that Bob has turned off "autosync" mode in Fossil. Or, maybe Bob
+just doesn't want to merge in Alice's changes before he has saved his
+own, so he forces the commit to occur using the "--allow-fork" option to
+the <b>[/help/commit | fossil commit]</b> command. For any of these
+reasons, two commits against check-in 2 have occurred, so the DAG now
+has two leaves.
+
+In such a condition, a person working with this repository has a
+dilemma: which version of the project is the "latest" in the sense of
+having the most features and the most bug fixes? When there is more
+than one leaf in the graph, you don't really know, which is why we
+would ideally prefer to have linear check-in graphs.
+
+Fossil resolves such problems using the check-in time on the leaves to
+decide which leaf to use as the parent of new leaves. When a branch is
+forked as in Figure 2, Fossil will choose check-in 4 as the parent for a
+later check-in 5, but <i>only</i> if it has sync'd that check-in down
+into the local repository. If autosync is disabled or the user is
+off-network when that fifth check-in occurs so that check-in 3 is the
+latest on that branch at the time within that clone of the repository,
+Fossil will make check-in 3 the parent of check-in 5! We show practical
+consequences of this [#bad-fork | later in this article].
+
+Fossil also uses a forked branch's leaf check-in timestamps when
+checking out that branch: it gives you the fork with the latest
+check-in, which in turn selects which parent your next check-in will be
+a child of. This situation means development on that branch can fork
+into two independent lines of development, based solely on which branch
+tip is newer at the time the next user starts his work on it.
+
+Because of these potential problems, we strongly recommend that you do
+not intentionally create forks on long-lived shared working branches
+with "--allow-fork". (Prime example: trunk.) The inverse case —
+intentional forks on short-lived single-developer branches — is far
+easier to justify, since presumably the lone developer is never confused
+about why there are two or more leaves on that branch. Further
+justifications for intentional forking are [#forking | given below].
+
+Let us return to Figure 2. To resolve such situations before they can
+become a real problem, Alice can use the <b>[/help/merge | fossil
+merge]</b> command to merge Bob's changes into her local copy of
+check-in 3. Without arguments, that command merges all leaves on the
+current branch. Alice can then verify that the merge is sensible and if
+so, commit the results as check-in 5. This results in a DAG as shown in
+Figure 3.
+
+<verbatim type="pikchr center toggle">
+ALL: [circle rad 0.1in thickness 1.5px "1"
+arrow right 40%
+circle same "2"
+circle same "3" at 2nd circle+(.4,.3)
+arrow from 2nd circle to 3rd circle chop
+circle same "4" at 2nd circle+(.4,-.3)
+arrow from 2nd circle to 4th circle chop
+circle same "5" at 3rd circle+(.4,-.3)
+arrow from 3rd circle to 5th circle chop
+arrow dashed .03 from 4th circle to 5th circle chop]
+box invis "Figure 3" big fit with .n at .2cm below ALL.s
+</verbatim>
+
+Check-in 5 is a child of check-in 3 because it was created by editing
+check-in 3, but since check-in 5 also inherits the changes from check-in 4 by
+virtue of the merge, we say that check-in 5 is a <i>merge child</i>
+of check-in 4 and that it is a <i>direct child</i> of check-in 3.
+The graph is now back to a single leaf, check-in 5.
+
+We have already seen that if Fossil is in autosync mode then Bob would
+have been warned about the potential fork the first time he tried to
+commit check-in 4. If Bob had updated his local check-out to merge in
+Alice's check-in 3 changes, then committed, the fork would have
+never occurred. The resulting graph would have been linear, as shown
+in Figure 1.
+
+Realize that the graph of Figure 1 is a subset of Figure 3. If you hold your
+hand over the ④ in Figure 3, it looks
+exactly like Figure 1 except that the leaf has a different check-in
+number. That is just a notational difference: the two check-ins
+have exactly the same content.
+
+Inversely, Figure 3 is a
+superset of Figure 1. The check-in 4 of Figure 3 captures additional
+state which is omitted from Figure 1. Check-in 4 of Figure 3 holds a
+copy of Bob's local checkout before he merged in Alice's changes. That
+snapshot of Bob's changes, which is independent of Alice's changes, is
+omitted from Figure 1.
+
+Some people say that the development approach taken in
+Figure 3 is better because it preserves this extra intermediate state.
+Others say that the approach taken in Figure 1 is better because it is
+much easier to visualize linear development and because the
+merging happens automatically instead of as a separate manual step. We
+will not take sides in that debate. We will simply point out that
+Fossil enables you to do it either way.
+
+<h2 id="branching">The Alternative to Forking: Branching</h2>
+
+Having more than one leaf in the check-in DAG is called a "fork." This
+is usually undesirable and either avoided entirely,
+as in Figure 1, or else quickly resolved as shown in Figure 3.
+But sometimes, one does want to have multiple leaves. For example, a project
+might have one leaf that is the latest version of the project under
+development and another leaf that is the latest version that has been
+tested.
+When multiple leaves are desirable, we call this <i>branching</i>
+instead of <i>forking</i>:
+
+Figure 4 shows an example of a project where there are two branches, one
+for development work and another for testing.
+
+<verbatim type="pikchr center toggle">
+ALL: [circle rad 0.1in thickness 1.5px fill white "1"
+arrow 40%
+C2: circle same "2"
+arrow same
+circle same "3"
+arrow same
+C5: circle same "5"
+arrow same
+C7: circle same "7"
+arrow same
+C8: circle same "8"
+arrow same
+C10: circle same "10"
+C4: circle same at 3rd circle-(0,.35) "4"
+C6: circle same at (1/2 way between C5 and C7,C4) "6"
+C9: circle same at (1/2 way between C8 and C10,C4) "9"
+arrow from C2 to C4 chop
+arrow from C4 to C6 chop
+arrow from C6 to C9 chop
+arrow dashed 0.03 from C6 to C7 chop
+arrow same from C9 to C10
+layer = 0
+box fill 0x9bcdfc color 0x9bcdfc wid (C10.e.x - C2.w.x) ht C6.height*1.5 at C6.c
+box invis "test" fit with .sw at last box.sw]
+box invis "Figure 4" big with .n at 0 below ALL.s
+</verbatim>
+
+Figure 4 diagrams the following scenario: the project starts and
+progresses to a point where (at check-in 2)
+it is ready to enter testing for its first release.
+In a real project, of course, there might be hundreds or thousands of
+check-ins before a project reaches this point, but for simplicity of
+presentation we will say that the project is ready after check-in 2.
+The project then splits into two branches that are used by separate
+teams. The testing team, using the blue branch, finds and fixes a few
+bugs with check-ins 6 and 9. Meanwhile, the development
+team, working on the top uncolored branch,
+is busy adding features for the second
+release. Of course, the development team would like to take advantage of
+the bug fixes implemented by the testing team, so periodically the
+changes in the test branch are merged into the dev branch. This is
+shown by the dashed merge arrows between check-ins 6 and 7 and between
+check-ins 9 and 10.
+
+In both Figures 2 and 4, check-in 2 has two children. In Figure 2,
+we call this a "fork." In diagram 4, we call it a "branch." What is
+the difference? As far as the internal Fossil data structures are
+concerned, there is no difference. The distinction is in the intent.
+In Figure 2, the fact that check-in 2 has multiple children is an
+accident that stems from concurrent development. In Figure 4, giving
+check-in 2 multiple children is a deliberate act. To a good
+approximation, we define forking to be by accident and branching to
+be by intent. Apart from that, they are the same.
+
+When the fork is intentional, it helps humans to understand what is
+going on if we <i>name</i> the forks. This is not essential to Fossil's
+internal data model, but humans have trouble working with long-lived
+branches identified only by the commit ID currently at its tip, being a
+long string of hex digits. Therefore, Fossil conflates two concepts:
+branching as intentional forking and the naming of forks as branches.
+They are in fact separate concepts, but since Fossil is intended to be
+used primarily by humans, we combine them in Fossil's human user
+interfaces.
+
+<p class="blockquote">
+<b>Key Distinction:</b> A branch is a <i>named, intentional</i> fork.
+</p>
+
+Unnamed forks <i>may</i> be intentional, but most of the time, they're
+accidental and left unnamed.
+
+Fossil offers two primary ways to create named, intentional forks,
+a.k.a. branches. First:
+
+<pre>
+$ fossil commit --branch my-new-branch-name
+</pre>
+
+This is the method we recommend for most cases: it creates a branch as
+part of a check-in using the version in the current checkout directory
+as its basis. (This is normally the tip of the current branch, though
+it doesn't have to be. You can create a branch from an ancestor check-in
+on a branch as well.) After making this branch-creating
+check-in, your local working directory is switched to that branch, so
+that further check-ins occur on that branch as well, as children of the
+tip check-in on that branch.
+
+The second, more complicated option is:
+
+<pre>
+$ fossil branch new my-new-branch-name trunk
+$ fossil update my-new-branch-name
+$ fossil commit
+</pre>
+
+Not only is this three commands instead of one, the first of which is
+longer than the entire simpler command above, you must give the second command
+before creating any check-ins, because until you do, your local working
+directory remains on the same branch it was on at the time you issued
+the command, so that the commit would otherwise put the new material on
+the original branch instead of the new one.
+
+In addition to those problems, the second method is a violation of the
+[https://en.wikipedia.org/wiki/You_aren%27t_gonna_need_it|YAGNI
+Principle]. We recommend that you wait until you actually need the
+branch before you create it using the first command above.
+
+The "trunk" is just another named branch in Fossil. It is simply
+the default branch name for the first check-in and every check-in made as
+one of its direct descendants. It is special only in that it is Fossil's
+default when it has no better idea of which branch you mean.
+
+
+<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.
+ <br><br>
+ 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 synchronized.</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 synchronization 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 check-in 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 check-ins be made only directly 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, so you use
+ <b>fossil commit --allow-fork</b> commands to prevent Fossil from
+ refusing the check-in simply because it would create a fork.
+ <br><br>
+ If you are writing such a tool — e.g. a shell script to make
+ multiple manipulations on a Fossil repo — it's better to make it
+ smart enough to detect this condition and cope with it, such as
+ by making a call to <b>[/help/update | fossil update]</b>
+ and checking for a merge conflict. That said, if the alternative is
+ losing information, you may feel justified in creating forks that an
+ interactive user must later manually clean up with <b>fossil merge</b>
+ commands.</p></li>
+</ol>
+
+That leaves only one case where we can recommend use of "--allow-fork"
+by interactive users: when you're working on a personal branch so that
+creating a dual-tipped branch isn't going to cause any other user an
+inconvenience or risk [#bad-fork | inadvertently forking the development
+effort]. In such a case, the lone developer working on that branch is
+not confused, since the fork in development is intentional. Sometimes it
+simply makes no sense to bother creating a name, cluttering the global
+branch namespace, simply to convert an intentional fork into a "branch."
+This is especially the case when the fork is short-lived.
+
+There's a common generalization of that case: you're a solo developer,
+so that the problems with branching vs forking simply don't matter. In
+that case, feel free to use "--allow-fork" as much as you like.
+
+
+<h2 id="fix">Fixing Forks</h2>
+
+If your local checkout is on a forked branch, you can usually fix a fork
+automatically with:
+
+<pre>
+$ fossil merge
+</pre>
+
+Normally you need to pass arguments to <b>fossil merge</b> to tell it
+what you want to merge into the current basis view of the repository,
+but without arguments, the command seeks out and fixes forks.
+
+
+<h2 id="tags">Tags And Properties</h2>
+
+Tags and properties are used in Fossil to help express the intent, and
+thus to distinguish between forks and branches. Figure 5 shows the
+same scenario as Figure 4 but with tags and properties added:
+
+<verbatim type="pikchr center toggle">
+ALL: [arrowht = 0.07
+C1: circle rad 0.1in thickness 1.5px fill white "1"
+arrow 40%
+C2: circle same "2"
+arrow same
+circle same "3"
+arrow same
+C5: circle same "5"
+arrow same
+C7: circle same "7"
+arrow same
+C8: circle same "8"
+arrow same
+C10: circle same "10"
+C4: circle same at 3rd circle-(0,.35) "4"
+C6: circle same at (1/2 way between C5 and C7,C4) "6"
+C9: circle same at (1/2 way between C8 and C10,C4) "9"
+arrow from C2 to C4 chop
+arrow from C4 to C6 chop
+arrow from C6 to C9 chop
+arrow dashed 0.03 from C6 to C7 chop
+arrow same from C9 to C10
+layer = 0
+box fill 0x9bcdfc color 0x9bcdfc wid (C10.e.x - C2.w.x) ht C6.height*1.5 at C6.c
+text " test" above ljust at last box.sw
+box fill lightgray "branch=trunk" "sym-trunk" fit with .ne at C1-(0.05,0.3);
+line color gray from last box.ne to C1 chop
+box same "branch=test" "sym-test" "bgcolor=blue" "cancel=sym-trunk" fit \
+ with .n at C4-(0,0.3)
+line color gray from last box.n to C4 chop
+box same "sym-release-1.0" "closed" fit with .n at C9-(0,0.3)
+line color gray from last box.n to C9 chop]
+box invis "Figure 5" big fit with .n at 0.2cm below ALL.s
+</verbatim>
+
+A <i>tag</i> is a name that is attached to a check-in. A
+<i>property</i> is a name/value pair. Internally, Fossil implements
+tags as properties with a NULL value. So, tags and properties really
+are much the same thing, and henceforth we will use the word "tag"
+to mean either a tag or a property.
+
+A tag can be a one-time tag, a propagating tag or a cancellation tag.
+A one-time tag only applies to the check-in to which it is attached. A
+propagating tag applies to the check-in to which it is attached and also
+to all direct descendants of that check-in. A <i>direct descendant</i>
+is a descendant through direct children. Tag propagation does not
+cross merges. Tag propagation also stops as soon
+as it encounters another check-in with the same tag. A cancellation tag
+is attached to a single check-in in order to either override a one-time
+tag that was previously placed on that same check-in, or to block
+tag propagation from an ancestor.
+
+The initial check-in of every repository has two propagating tags. In
+Figure 5, that initial check-in is check-in 1. The <b>branch</b> tag
+tells (by its value) what branch the check-in is a member of.
+The default branch is called "trunk." All tags that begin with "<b>sym-</b>"
+are symbolic name tags. When a symbolic name tag is attached to a
+check-in, that allows you to refer to that check-in by its symbolic
+name rather than by its hexadecimal hash name. When a symbolic name
+tag propagates (as does the <b>sym-trunk</b> tag) then referring to that
+name is the same as referring to the most recent check-in with that name.
+Thus the two tags on check-in 1 cause all descendants to be in the
+"trunk" branch and to have the symbolic name "trunk."
+
+Check-in 4 has a <b>branch</b> tag which changes the name of the branch
+to "test." The branch tag on check-in 4 propagates to check-ins 6 and 9.
+But because tag propagation does not follow merge links, the <b>branch=test</b>
+tag does not propagate to check-ins 7, 8, or 10. Note also that the
+<b>branch</b> tag on check-in 4 blocks the propagation of <b>branch=trunk</b>
+so that it cannot reach check-ins 6 or 9. This causes check-ins 4, 6, and
+9 to be in the "test" branch and all others to be in the "trunk" branch.
+
+Check-in 4 also has a <b>sym-test</b> tag, which gives the symbolic name
+"test" to check-ins 4, 6, and 9. Because tags do not propagate across
+merges, check-ins 7, 8, and 10 do not inherit the <b>sym-test</b> tag and
+are hence not known by the name "test."
+To prevent the <b>sym-trunk</b> tag from propagating from check-in 1
+into check-ins 4, 6, and 9, there is a cancellation tag for
+<b>sym-trunk</b> on check-in 4. The net effect is that
+check-ins on the trunk go by the symbolic name of "trunk" and check-ins
+on the test branch go by the symbolic name "test."
+
+The <b>bgcolor=blue</b> tag on check-in 4 causes the background color
+of timelines to be blue for check-in 4 and its direct descendants.
+
+Figure 5 also shows two one-time tags on check-in 9. (The diagram does
+not make a graphical distinction between one-time and propagating tags.)
+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:
+
+<verbatim type="pikchr center toggle">
+ $laneh = 0.75
+
+ALL: [
+ # Draw the lanes
+ down
+ box width 3.5in height $laneh fill 0xacc9e3
+ box same fill 0xc5d8ef
+ box same as first box
+ box same as 2nd box
+ line from 1st box.sw+(0.2,0) up until even with 1st box.n \
+ "Alan" above aligned
+ line from 2nd box.sw+(0.2,0) up until even with 2nd box.n \
+ "Betty" above aligned
+ line from 3rd box.sw+(0.2,0) up until even with 3rd box.n \
+ "Charlie" above aligned
+ line from 4th box.sw+(0.2,0) up until even with 4th box.n \
+ "Darlene" above aligned
+
+ # fill in content for the Alice lane
+ right
+A1: circle rad 0.1in at end of first line + (0.2,-0.2) \
+ fill white thickness 1.5px "1"
+ arrow right 50%
+ circle same "2"
+ arrow right until even with first box.e - (0.65,0.0)
+ ellipse "future" fit fill white height 0.2 width 0.5 thickness 1.5px
+A3: circle same at A1+(0.8,-0.3) "3" fill 0xc0c0c0
+ arrow from A1 to last circle chop "fork!" below aligned
+
+ # content for the Betty lane
+B1: circle same as A1 at A1-(0,$laneh) "1"
+ arrow right 50%
+ circle same "2"
+ arrow right until even with first ellipse.w
+ ellipse same "future"
+B3: circle same at A3-(0,$laneh) "3"
+ arrow right 50%
+ circle same as A3 "4"
+ arrow from B1 to 2nd last circle chop
+
+ # content for the Charlie lane
+C1: circle same as A1 at B1-(0,$laneh) "1"
+ arrow 50%
+ circle same "2"
+ arrow right 0.8in "goes" "offline"
+C5: circle same as A3 "5"
+ arrow right until even with first ellipse.w \
+ "back online" above "pushes 5" below "pulls 3 &amp; 4" below
+ ellipse same "future"
+
+ # content for the Darlene lane
+D1: circle same as A1 at C1-(0,$laneh) "1"
+ arrow 50%
+ circle same "2"
+ arrow right until even with C5.w
+ circle same "5"
+ arrow 50%
+ circle same as A3 "6"
+ arrow right until even with first ellipse.w
+ ellipse same "future"
+D3: circle same as B3 at B3-(0,2*$laneh) "3"
+ arrow 50%
+ circle same "4"
+ arrow from D1 to D3 chop
+]
+box invis "Figure 6" big fit with .n at 0.2cm below ALL.s
+</verbatim>
+
+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
+check-ins 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
+our example makes the most sense if you think of it as 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>[/help/open | 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
+ attempting what will become check-in 4, she gets the "would fork"
+ message from <b>fossil commit</b>, so she dutifully updates her clone
+ 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.
+
+<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.
+
+In all of this, realize that neither side of the fork is obviously
+"correct." Every participant was doing the right thing by their own
+lights at the time they made their lone check-in.
+
+Who, then, is to blame?
+
+We can only blame the consequences of creating the fork on Alan if he
+did so on purpose, as by passing "--allow-fork" when creating a check-in
+on a shared working branch. Alan might have created it inadvertently by
+going offline while check-in 1 was the tip of the branch in his local
+clone, so that by the time he made his check-in 3, check-in 2 had
+arrived at the shared parent repository from someone else. (Francine?)
+When Alan rejoins the network and does an autosync, he learns about
+check-in 2. Since his #3 is already checked into his local clone because
+autosync was off or blocked, the sync creates an unavoidable fork. We
+can't blame either Alan or Francine here: they were both doing the right
+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>
+
+<dl>
+<dt><b>Branch</b></dt>
+<dd><p>A branch is a set of check-ins with the same value for their
+"branch" property.</p></dd>
+<dt><b>Leaf</b></dt>
+<dd><p>A leaf is a check-in with no children in the same branch.</p></dd>
+<dt><b>Closed Leaf</b></dt>
+<dd><p>A closed leaf is any leaf with the <b>closed</b> tag. These leaves
+are intended to never be extended with descendants and hence are omitted
+from lists of leaves in the command-line and web interface.</p></dd>
+<dt><b>Open Leaf</b></dt>
+<dd><p>A open leaf is a leaf that is not closed.</p></dd>
+<dt><b>Fork</b></dt>
+<dd><p>A fork is when a check-in has two or more direct (non-merge)
+children in the same branch.</p></dd>
+<dt><b>Branch Point</b></dt>
+<dd><p>A branch point occurs when a check-in has two or more direct (non-merge)
+children in different branches. A branch point is similar to a fork,
+except that the children are in different branches.</p></dd>
+</dl>
+
+Check-in 4 of Figure 3 is not a leaf because it has a child (check-in 5)
+in the same branch. Check-in 9 of Figure 5 also has a child (check-in 10)
+but that child is in a different branch, so check-in 9 is a leaf. Because
+of the <b>closed</b> tag on check-in 9, it is a closed leaf.
+
+Check-in 2 of Figure 3 is considered a "fork"
+because it has two children in the same branch. Check-in 2 of Figure 5
+also has two children, but each child is in a different branch, hence in
+Figure 5, check-in 2 is considered a "branch point."
+
+<h2>Differences With Other DVCSes</h2>
+
+<h3 id="single">Single DAG</h3>
+
+Fossil keeps all check-ins on a single DAG. Branches are identified with
+tags. This means that check-ins can be freely moved between branches
+simply by altering their tags.
+
+Most other DVCSes maintain a separate DAG for each branch.
+
+<h3 id="unique">Branch Names Need Not Be Unique</h3>
+
+Fossil does not require that branch names be unique, as in some VCSes,
+most notably Git. Just as with unnamed branches (which we call forks)
+Fossil resolves such ambiguities using the timestamps on the latest
+check-in in each branch. If you have two branches named "foo" and you say
+<b>fossil update foo</b>, you get the tip of the "foo" branch with the most
+recent check-in.
+
+This fact is helpful because it means you can reuse branch names, which
+is especially useful with utility branches. There are several of these
+in the SQLite and Fossil repositories: "broken-build," "declined,"
+"mistake," etc. As you might guess from these names, such branch names
+are used in renaming the tip of one branch to shunt it off away from the
+mainline of that branch due to some human error. (See
+<b>[/help/amend | fossil
+amend]</b> and the Fossil UI check-in amendment features.) This is a
+workaround for Fossil's [./shunning.wiki|normal inability to forget
+history]: we usually don't want to actually <i>remove</i> history, but
+would like to sometimes set some of it aside under a new label.
+
+Because some VCSes can't cope with duplicate branch names, Fossil
+collapses such names down on export using the same time stamp based
+arbitration logic, so that only the branch with the newest check-in gets
+the branch name in the export.
+
+All of the above is true of tags in general, not just branches.