Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
| Comment: | First draft of the "branching" document. |
|---|---|
| Downloads: | Tarball | ZIP archive |
| Timelines: | family | ancestors | descendants | both | trunk |
| Files: | files | file ages | folders |
| SHA1: |
2e275c14202446fca2bb8a48a8d15ed8 |
| User & Date: | drh 2009-01-23 21:24:00.000 |
Context
|
2009-01-29
| ||
| 19:11 | Add link to branching page. check-in: f8f8baf945 user: kejoki tags: trunk | |
|
2009-01-23
| ||
| 22:05 | Updates to the branching document. check-in: dc1a5cf739 user: drh tags: trunk | |
| 21:24 | First draft of the "branching" document. check-in: 2e275c1420 user: drh tags: trunk | |
| 01:01 | Nomenclature chanage: "bug report" becomes "ticket" check-in: cf9ee7d67e user: drh tags: trunk | |
Changes
Added art/branching.odp.
cannot compute difference between binary files
Added www/branch01.gif.
cannot compute difference between binary files
Added www/branch02.gif.
cannot compute difference between binary files
Added www/branch03.gif.
cannot compute difference between binary files
Added www/branch04.gif.
cannot compute difference between binary files
Added www/branch05.gif.
cannot compute difference between binary files
Added www/branching.wiki.
> > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 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 | <h1 align="center"> Branching, Forking, Merging, and Tagging </h1> In a simple and perfect world, the development of a project would proceed linearly, as shown in figure 1. <center><table border=1 cellpadding=10 hspace=10 vspace=10> <tr><td align="center"> <img src="branch01.gif"><br> Figure 1 </td></tr></table></center> 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 40-character SHA1 hashes since it is not possible to allocate collision-free sequential numbers is a distributed system. But sequential numbers are easier to read, so we will substitute them for the 40-character SHA1 hashes in this document. The arrows in figure 1 show evolution of the 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. We call the graph of check-ins a <i>tree</i>. Check-in 1 is the <i>root</i> since it has no ancestors. Check-in 4 is a <i>leaf</i> of the tree since it has no descendants. 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 checked in, we have a check-in graph that looks like figure 2: <center><table border=1 cellpadding=10 hspace=10 vspace=10> <tr><td align="center"> <img src="branch02.gif"><br> Figure 2 </td></tr></table></center> 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 stituation a <i>fork</i>. Fossil tries to prevent forks. Suppose the two programmers who were editing check-in 2 are named Alice and Bob. Suppose Alice finished her edits first and did a commit, resulting in check-in 3. Later, when Bob tried to commit his changes, fossil would try to verify that check-in 2 was still a leaf. Fossil would see that check-in 3 had occurred and would abort Bob's commit attempt with a message "would fork". This allows Bob to do a "fossil update" which would pull in Alices changes and merge them together with his own changes. After merging, Bob could then commit check-in 4 as a child of check-in 3 and the result would be a linear graph as shown in figure 1. This is how CVS works. This is also how fossil works in "autosync" mode. But it might be that 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 of "autosync" mode in SQLite. Or, maybe Bob just doesn't want to merge in Alices changes before he has saved his own, so he forces the commit to occur using the "--force" option to the fossil <b>commit</b> command. For whatever reason, two commits against check-in 2 have occurred and now the tree has two leaves. So 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. So we like to have graphs with a single leaf. To resolve this situation, Alice can use the fossil <b>merge</b> command to me merge in Bob's changes in here local copy of check-in 3. Then she can commit the results as check-in 5. This results in a tree as shown in figure 3. <center><table border=1 cellpadding=10 hspace=10 vspace=10> <tr><td align="center"> <img src="branch03.gif"><br> Figure 3 </td></tr></table></center> Check-in 5 is a direct child of check-in 3 because it was created by editing check-in 3. But check-in 5 also inherits the changes from check-in 4 by virtual of the merge. So 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, then the fork would have never occurred. The resulting graph would have been linear, as shown in figure 1. Really the graph of figure 1 is a subset of figure 3. Hold your hand over the check-in 4 circle of figure 3 and then figure 3 looks exactly like figure 1 (except that the leaf has a different check-in number, but that is just a notational difference - the two check-ins have exactly the same content). In other words, figure 3 is really a superset of figure 1. The check-in 4 of figure 3 captures addition state which is omitted from figure 1. In check-in 4 of figure 3 is a copy of Bob's local checkout before he merged in Alices changes. That snapshot of Bob's changes independent of Alice's changes is omitted from figure 1. Some people say that the 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 a linear line of development and because the the merging happens automatically instead of as a separate manual step. We will not take sides in this debate. We will simply point out that fossil enables you to do it either way. <h2>Forking Versus Branching</h2> Forking and having more than one leaf in the check-in tree is usually considered undesirable, and so forks are usually quickly resolved as shown in figure 3 above. 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 the phenomenon <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. <center><table border=1 cellpadding=10 hspace=10 vspace=10> <tr><td align="center"> <img src="branch04.gif"><br> Figure 4 </td></tr></table></center> The hypothetical scenario of figure 4 is this: 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. This is shown by check-ins 6 and 9. Meanwhile the development team, working on the red 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 called this a "fork". In diagram 4, we call it a "branch". What is the difference? As far as the internal fossil data structure 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. So, to a good approximating, we define forking to be by accident and branching to be by intent. Apart from that, they are the same. <h2>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: <center><table border=1 cellpadding=10 hspace=10 vspace=10> <tr><td align="center"> <img src="branch05.gif"><br> Figure 5 </td></tr></table></center> 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 either a one-time tag or an propagating tag or a cancellation. A one-time tag only applies to the check-in to which it is attached. An 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. Tags 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 placed on that same check-in, or to block tag propagation. Every repository is created with a single empty check-in that has two propagating tags. In figure 5, that initial empty 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 40-character SHA1 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 once cause all decendents 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 9. 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 9 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 of all of this is that check-ins on the trunk go by the symbolic name of "trunk" and check-ins that are 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 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 intended to never have any childred. <h2>Review Of Terminology</h2> Here is a list of definitions of key terms: <blockquote><dl> <dt><b>Branch</b></dt> <dd><p>A branch is a set of check-ins that have the same value for their <dt><b>Leaf</b></dt> <dd><p>A leaf is a check-in that has no children in the same branch.</p></dd> <dt><b>Closed Leaf</b></dt> <dd><p>A closed leaf is leaf that has the <b>closed</b> tag. Such leaves are intented to never be extended with descendents 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 occurs 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 the different branches. A branch point is similar to a fork, except that the children are in different branches.</p></dd> </dl></blockquote> 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 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". |
Changes to www/concepts.wiki.
| ︙ | ︙ | |||
210 211 212 213 214 215 216 | <h2>4.0 Workflow</h2> <img src="concept2.gif" align="right" hspace="10"> <p>Fossil has two modes of operation: "autosync" and "non-autosync". Autosync mode works something like CVS or SVN in that it automatically keeps your work in sync with the central server. Non-autosync is | | | | 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 | <h2>4.0 Workflow</h2> <img src="concept2.gif" align="right" hspace="10"> <p>Fossil has two modes of operation: "autosync" and "non-autosync". Autosync mode works something like CVS or SVN in that it automatically keeps your work in sync with the central server. Non-autosync is more like GIT or Bitkeeper in that your local repository develops independently of your coworkers and you share your changes manually. An interesting feature of fossil is that it supports both autosync and non-autosync work flows.</p> <p>The default setting for fossil is to be in autosync mode. You can change the autosync setting or check the current autosync setting using commands like:</p> <blockquote> |
| ︙ | ︙ | |||
380 381 382 383 384 385 386 387 388 389 390 391 392 393 | option to specify the repository file.</p> <p>A stand-alone server is a great way to set of transient connections between coworkers for doing quick pushes or pulls. But you can also set up a permanent stand-alone server if you prefer. Just make arrangements for fossil to be launched with appropriate arguments after every reboot.</p> </li> <li><p><b>Setting up a CGI server</b></p> <p>If you have a webserver running on your machine already, you can set up fossil to be run from CGI. Simply create an executable script that looks something like this:</p> | > > > > > > | 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 | option to specify the repository file.</p> <p>A stand-alone server is a great way to set of transient connections between coworkers for doing quick pushes or pulls. But you can also set up a permanent stand-alone server if you prefer. Just make arrangements for fossil to be launched with appropriate arguments after every reboot.</p> <p>If you just want a server to browse the built-in fossil website locally, use the <b>ui</b> command in place of <b>server</b>. The <b>ui</b> command starts up a local server too, but it also takes the additional step of automatically launching your webbrowser and pointing at the new server.</p> </li> <li><p><b>Setting up a CGI server</b></p> <p>If you have a webserver running on your machine already, you can set up fossil to be run from CGI. Simply create an executable script that looks something like this:</p> |
| ︙ | ︙ |
Changes to www/index.wiki.
| ︙ | ︙ | |||
56 57 58 59 60 61 62 63 64 65 66 67 68 69 |
User Links:
* The [./concepts.wiki | concepts] behind fossil
* [./build.wiki | Building And Installing]
* [./quickstart.wiki | Quick Start] guide to using fossil
* Fossil supports [./embeddeddoc.wiki | embedded documentation]
that is versioned along with project source code.
* The [./selfcheck.wiki | automatic self-check] mechanism
helps insure project integrity.
* Fossil contains a [./wikitheory.wiki | built-in wiki].
* There is a
[http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list]
available for discussing fossil issues.
* [./qandc.wiki | Questions & Criticisms] directed at fossil.
| > > | 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 |
User Links:
* The [./concepts.wiki | concepts] behind fossil
* [./build.wiki | Building And Installing]
* [./quickstart.wiki | Quick Start] guide to using fossil
* Fossil supports [./embeddeddoc.wiki | embedded documentation]
that is versioned along with project source code.
* A tutorial on [./branching.wiki | branching], what it means and how
to do it using fossil.
* The [./selfcheck.wiki | automatic self-check] mechanism
helps insure project integrity.
* Fossil contains a [./wikitheory.wiki | built-in wiki].
* There is a
[http://lists.fossil-scm.org:8080/cgi-bin/mailman/listinfo/fossil-users | mailing list]
available for discussing fossil issues.
* [./qandc.wiki | Questions & Criticisms] directed at fossil.
|
| ︙ | ︙ |