Fossil

Check-in [766bec08ce]
Login

Check-in [766bec08ce]

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

Overview
Comment:Documentation tweaks. Change the "Setup" menu title to "Admin". Added pages under Admin to view the RCVFROM table of the database.
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: 766bec08cebeb858a874df71c4d6e3961e3a33e8
User & Date: drh 2009-01-25 19:18:09.000
Context
2009-01-25
19:47
Add explanatory text to the top of the rcvfromlist webpage. The info page for the root check-in now knows how to redirect to vinfo. ... (check-in: 9c89b0e0f1 user: drh tags: trunk)
19:18
Documentation tweaks. Change the "Setup" menu title to "Admin". Added pages under Admin to view the RCVFROM table of the database. ... (check-in: 766bec08ce user: drh tags: trunk)
16:00
Update the file format documentation. ... (check-in: c664695186 user: drh tags: trunk)
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/info.c.
388
389
390
391
392
393
394

















395
396
397
398
399
400
401
402
403
404
405
    if( zEComment ){
      @ <tr><th>Edited&nbsp;Comment:</th><td>%w(zEComment)</td></tr>
      @ <tr><th>Original&nbsp;Comment:</th><td>%w(zComment)</td></tr>
    }else{
      @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
    }
    @ </td></tr>

















    if( g.okHistory ){
      char *zShortUuid = mprintf("%.10s", zUuid);
      const char *zProjName = db_get("project-name", "unnamed");
      Stmt q;
      @ <tr><th>Timelines:</th><td>
      @    <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
      @    | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
      @    | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
      db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
                     " WHERE rid=%d AND tagtype>0 "
                     "   AND tag.tagid=tagxref.tagid "







>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>



<







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
    if( zEComment ){
      @ <tr><th>Edited&nbsp;Comment:</th><td>%w(zEComment)</td></tr>
      @ <tr><th>Original&nbsp;Comment:</th><td>%w(zComment)</td></tr>
    }else{
      @ <tr><th>Comment:</th><td>%w(zComment)</td></tr>
    }
    @ </td></tr>
    if( g.okAdmin ){
      db_prepare(&q, 
         "SELECT rcvfrom.ipaddr, user.login, datetime(rcvfrom.mtime)"
         "  FROM blob JOIN rcvfrom USING(rcvid) LEFT JOIN user USING(uid)"
         " WHERE blob.rid=%d",
         rid
      );
      if( db_step(&q)==SQLITE_ROW ){
        const char *zIpAddr = db_column_text(&q, 0);
        const char *zUser = db_column_text(&q, 1);
        const char *zDate = db_column_text(&q, 2);
        if( zUser==0 || zUser[0]==0 ) zUser = "unknown";
        @ <tr><th>Received&nbsp;From:</th>
        @ <td>%h(zUser) @ %h(zIpAddr) on %s(zDate)</td></tr>
      }
      db_finalize(&q);
    }
    if( g.okHistory ){
      char *zShortUuid = mprintf("%.10s", zUuid);
      const char *zProjName = db_get("project-name", "unnamed");

      @ <tr><th>Timelines:</th><td>
      @    <a href="%s(g.zBaseURL)/timeline?p=%d(rid)">ancestors</a>
      @    | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)">descendants</a>
      @    | <a href="%s(g.zBaseURL)/timeline?d=%d(rid)&p=%d(rid)">both</a>
      db_prepare(&q, "SELECT substr(tag.tagname,5) FROM tagxref, tag "
                     " WHERE rid=%d AND tagtype>0 "
                     "   AND tag.tagid=tagxref.tagid "
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
    @ <p>No such object: %h(zName)</p>
    style_footer();
    return;
  }
  if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
    vinfo_page();
  }else
  if( db_exists("SELECT 1 FROM mlink WHERE fid=%d", rid) ){
    finfo_page();
  }else
  if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){
    winfo_page();
  }else
  if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
    tinfo_page();







<
<
<







1142
1143
1144
1145
1146
1147
1148



1149
1150
1151
1152
1153
1154
1155
    @ <p>No such object: %h(zName)</p>
    style_footer();
    return;
  }
  if( db_exists("SELECT 1 FROM mlink WHERE mid=%d", rid) ){
    vinfo_page();
  }else



  if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                " WHERE rid=%d AND tagname LIKE 'wiki-%%'", rid) ){
    winfo_page();
  }else
  if( db_exists("SELECT 1 FROM tagxref JOIN tag USING(tagid)"
                " WHERE rid=%d AND tagname LIKE 'tkt-%%'", rid) ){
    tinfo_page();
Changes to src/setup.c.
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
*/
void setup_page(void){
  login_check_credentials();
  if( !g.okSetup ){
    login_needed();
  }

  style_header("Setup");
  @ <table border="0" cellspacing="20">
  setup_menu_entry("Users", "setup_ulist",
    "Grant privileges to individual users.");
  setup_menu_entry("Access", "setup_access",
    "Control access settings.");
  setup_menu_entry("Configuration", "setup_config",
    "Configure the WWW components of the repository");
  setup_menu_entry("Timeline", "setup_timeline",
    "Timeline display preferences");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");
  setup_menu_entry("CSS", "setup_editcss",
    "Edit the Cascading Style Sheet used by all pages of this repository");
  setup_menu_entry("Header", "setup_header",
    "Edit HTML text inserted at the top of every page");
  setup_menu_entry("Footer", "setup_footer",
    "Edit HTML text inserted at the bottom of every page");
  setup_menu_entry("Shunned", "shun",
    "Show artifacts that are shunned by this repository");


  setup_menu_entry("Stats", "stat",
    "Display repository statistics");
  @ </table>

  style_footer();
}








|



















>
>







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
*/
void setup_page(void){
  login_check_credentials();
  if( !g.okSetup ){
    login_needed();
  }

  style_header("Server Administration");
  @ <table border="0" cellspacing="20">
  setup_menu_entry("Users", "setup_ulist",
    "Grant privileges to individual users.");
  setup_menu_entry("Access", "setup_access",
    "Control access settings.");
  setup_menu_entry("Configuration", "setup_config",
    "Configure the WWW components of the repository");
  setup_menu_entry("Timeline", "setup_timeline",
    "Timeline display preferences");
  setup_menu_entry("Tickets", "tktsetup",
    "Configure the trouble-ticketing system for this repository");
  setup_menu_entry("CSS", "setup_editcss",
    "Edit the Cascading Style Sheet used by all pages of this repository");
  setup_menu_entry("Header", "setup_header",
    "Edit HTML text inserted at the top of every page");
  setup_menu_entry("Footer", "setup_footer",
    "Edit HTML text inserted at the bottom of every page");
  setup_menu_entry("Shunned", "shun",
    "Show artifacts that are shunned by this repository");
  setup_menu_entry("Log", "rcvfromlist",
    "A record of received artifacts and their sources");
  setup_menu_entry("Stats", "stat",
    "Display repository statistics");
  @ </table>

  style_footer();
}

Changes to src/shun.c.
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** This file contains code used to manage SHUN table of the repository
*/
#include "config.h"
#include "shun.h"
#include <assert.h>

/*
** Return true if the given UUID should be shunned.
*/
int uuid_is_shunned(const char *zUuid){
  static Stmt q;
  int rc;
  if( zUuid==0 || zUuid[0]==0 ) return 0;
  db_static_prepare(&q, "SELECT 1 FROM shun WHERE uuid=:uuid");
  db_bind_text(&q, ":uuid", zUuid);







|







24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
** This file contains code used to manage SHUN table of the repository
*/
#include "config.h"
#include "shun.h"
#include <assert.h>

/*
** Return true if the given artifact ID should be shunned.
*/
int uuid_is_shunned(const char *zUuid){
  static Stmt q;
  int rc;
  if( zUuid==0 || zUuid[0]==0 ) return 0;
  db_static_prepare(&q, "SELECT 1 FROM shun WHERE uuid=:uuid");
  db_bind_text(&q, ":uuid", zUuid);
117
118
119
120
121
122
123
124

125
126
127



128
129
130
131
132
133
134
  if( cnt==0 ){
    @ <i>no artifacts are shunned on this server</i>
  }
  db_finalize(&q);
  @ </blockquote>
  @ <hr>
  @ <a name="addshun"></a>
  @ <p>To shun an artifact, enter its UUID in the

  @ following box and press the "Shun" button.  This will cause the artifact
  @ to be removed from the repository and will prevent the artifact from being
  @ readded to the repository by subsequent sync operation.</p>



  @
  @ <p>Warning:  Shunning should only be used to remove inappropriate content
  @ from the repository.  Inappropriate content includes such things as
  @ spam added to Wiki, files that violate copyright or patent agreements,
  @ or artifacts that by design or accident interfere with the processing
  @ of the repository.  Do not shun artifacts merely to remove them from
  @ sight - set the "hidden" tag on such artifacts instead.</p>







|
>



>
>
>







117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
  if( cnt==0 ){
    @ <i>no artifacts are shunned on this server</i>
  }
  db_finalize(&q);
  @ </blockquote>
  @ <hr>
  @ <a name="addshun"></a>
  @ <p>To shun an artifact, enter its artifact ID (the 40-character SHA1
  @ hash of the artifact) in the
  @ following box and press the "Shun" button.  This will cause the artifact
  @ to be removed from the repository and will prevent the artifact from being
  @ readded to the repository by subsequent sync operation.</p>
  @
  @ <p>Note that you must enter the full 40-character artifact ID, not
  @ an abbreviation or a symbolic tag.</p>
  @
  @ <p>Warning:  Shunning should only be used to remove inappropriate content
  @ from the repository.  Inappropriate content includes such things as
  @ spam added to Wiki, files that violate copyright or patent agreements,
  @ or artifacts that by design or accident interfere with the processing
  @ of the repository.  Do not shun artifacts merely to remove them from
  @ sight - set the "hidden" tag on such artifacts instead.</p>
151
152
153
154
155
156
157

158
159
160
161
162
163
164
  @ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
  login_insert_csrf_secret();
  @ <input type="text" name="uuid" size="50">
  @ <input type="submit" name="sub" value="Accept">
  @ </form>
  @ </blockquote>
  @

  @ <p>Press the button below to rebuild the respository.  The rebuild
  @ may take several seconds, so be patient after pressing the button.</p>
  @
  @ <blockquote>
  @ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
  login_insert_csrf_secret();
  @ <input type="submit" name="rebuild" value="Rebuild">







>







155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
  @ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
  login_insert_csrf_secret();
  @ <input type="text" name="uuid" size="50">
  @ <input type="submit" name="sub" value="Accept">
  @ </form>
  @ </blockquote>
  @
  @ <hr>
  @ <p>Press the button below to rebuild the respository.  The rebuild
  @ may take several seconds, so be patient after pressing the button.</p>
  @
  @ <blockquote>
  @ <form method="POST" action="%s(g.zBaseURL)/%s(g.zPath)">
  login_insert_csrf_secret();
  @ <input type="submit" name="rebuild" value="Rebuild">
187
188
189
190
191
192
193








































































































  db_finalize(&q);
  db_multi_exec(
     "DELETE FROM delta WHERE rid IN toshun;"
     "DELETE FROM blob WHERE rid IN toshun;"
     "DROP TABLE toshun;"
  );
}















































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
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
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
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
  db_finalize(&q);
  db_multi_exec(
     "DELETE FROM delta WHERE rid IN toshun;"
     "DELETE FROM blob WHERE rid IN toshun;"
     "DROP TABLE toshun;"
  );
}

/*
** WEBPAGE: rcvfromlist
**
** Show a listing of RCVFROM table entries.
*/
void rcvfromlist_page(void){
  int ofst = atoi(PD("ofst","0"));
  int cnt;
  Stmt q;

  login_check_credentials();
  if( !g.okAdmin ){
    login_needed();
  }
  style_header("Content Sources");
  if( ofst>0 ){
    style_submenu_element("Later", "Later", "rcvfromlist?ofst=%d",
                           ofst>30 ? ofst-30 : 0);
  }
  db_prepare(&q, 
    "SELECT rcvid, login, datetime(rcvfrom.mtime), rcvfrom.ipaddr"
    "  FROM rcvfrom LEFT JOIN user USING(uid)"
    " ORDER BY rcvid DESC LIMIT 31 OFFSET %d",
    ofst
  );
  @ <table cellpadding=0 cellspacing=0 border=0>
  @ <tr><th>rcvid</th><th width=15>
  @     <th>Date</th><th width=15><th>User</th>
  @     <th width=15><th>IP&nbsp;Address</th></tr>
  cnt = 0;
  while( db_step(&q)==SQLITE_ROW ){
    int rcvid = db_column_int(&q, 0);
    const char *zUser = db_column_text(&q, 1);
    const char *zDate = db_column_text(&q, 2);
    const char *zIpAddr = db_column_text(&q, 3);
    if( cnt==30 ){
      style_submenu_element("Earlier", "Earlier",
         "rcvfromlist?ofst=%d", ofst+30);
    }else{
      cnt++;
      @ <tr>
      @ <td><a href="rcvfrom?rcvid=%d(rcvid)">%d(rcvid)</a></td><td>
      @ <td>%s(zDate)</td><td>
      @ <td>%h(zUser)</td><td>
      @ <td>&nbsp;%s(zIpAddr)&nbsp</td>
      @ </tr>
    }
  }
  db_finalize(&q);
  @ </table>
  style_footer();
}

/*
** WEBPAGE: rcvfrom
**
** Show a single RCVFROM table entry.
*/
void rcvfrom_page(void){
  int rcvid = atoi(PD("rcvid","0"));
  Stmt q;

  login_check_credentials();
  if( !g.okAdmin ){
    login_needed();
  }
  style_header("Content Source %d", rcvid);
  db_prepare(&q, 
    "SELECT login, datetime(rcvfrom.mtime), rcvfrom.ipaddr"
    "  FROM rcvfrom LEFT JOIN user USING(uid)"
    " WHERE rcvid=%d",
    rcvid
  );
  @ <table cellspacing=15 cellpadding=0 border=0>
  @ <tr><td valign="top" align="right">rcvid:</td>
  @ <td valign="top">%d(rcvid)</td></tr>
  if( db_step(&q)==SQLITE_ROW ){
    const char *zUser = db_column_text(&q, 0);
    const char *zDate = db_column_text(&q, 1);
    const char *zIpAddr = db_column_text(&q, 2);
    @ <tr><td valign="top" align="right">User:</td>
    @ <td valign="top">%s(zUser)</td></tr>
    @ <tr><td valign="top" align="right">Date:</td>
    @ <td valign="top">%s(zDate)</td></tr>
    @ <tr><td valign="top" align="right">IP&nbspAddress:</td>
    @ <td valign="top">%s(zIpAddr)</td></tr>
  }
  db_finalize(&q);
  db_prepare(&q,
    "SELECT rid, uuid, size FROM blob WHERE rcvid=%d", rcvid
  );
  @ <tr><td valign="top" align="right">Artifacts:</td>
  @ <td valign="top">
  while( db_step(&q)==SQLITE_ROW ){
    int rid = db_column_int(&q, 0);
    const char *zUuid = db_column_text(&q, 1);
    int size = db_column_int(&q, 2);
    @ <a href="%s(g.zBaseURL)/info/%s(zUuid)">%s(zUuid)</a>
    @ (rid: %d(rid), size: %d(size))<br>
  }
  @ </td></tr>
  @ </table>
}
Changes to src/style.c.
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
@ if {[hascap r]} {
@   html "<a href='$baseurl/reportlist'>Tickets</a>"
@ }
@ if {[hascap j]} {
@   html "<a href='$baseurl/wiki'>Wiki</a>"
@ }
@ if {[hascap s]} {
@   html "<a href='$baseurl/setup'>Setup</a>"
@ } elseif {[hascap a]} {
@   html "<a href='$baseurl/setup_ulist'>Users</a>"
@ }
@ if {[info exists login]} {
@   html "<a href='$baseurl/login'>Logout</a>"
@ } else {
@   html "<a href='$baseurl/login'>Login</a>"







|







219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
@ if {[hascap r]} {
@   html "<a href='$baseurl/reportlist'>Tickets</a>"
@ }
@ if {[hascap j]} {
@   html "<a href='$baseurl/wiki'>Wiki</a>"
@ }
@ if {[hascap s]} {
@   html "<a href='$baseurl/setup'>Admin</a>"
@ } elseif {[hascap a]} {
@   html "<a href='$baseurl/setup_ulist'>Users</a>"
@ }
@ if {[info exists login]} {
@   html "<a href='$baseurl/login'>Logout</a>"
@ } else {
@   html "<a href='$baseurl/login'>Login</a>"
Changes to www/branching.wiki.
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

<center><table border=1 cellpadding=10 hspace=10 vspace=10>
<tr><td align="center">
<img src="branch03.gif" width=282 height=152><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







|

|







78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94

<center><table border=1 cellpadding=10 hspace=10 vspace=10>
<tr><td align="center">
<img src="branch03.gif" width=282 height=152><br>
Figure 3
</td></tr></table></center>

Check-in 5 is a 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
virtue 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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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 that
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







|
|
|







107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
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 that
debate.  We will simply point out that fossil enables you to do it either way.

<h2>Forking Versus Branching</h2>

Having more than one leaf in the check-in tree is usually
considered undesirable, and so forks are usually 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 the phenomenon <i>branching</i>
instead of <i>forking</i>.
Figure 4 shows an example of a project where there are two branches, one
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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
approximation, we define forking to be by accident and branching to
be by intent.  Apart from that, they are the same.








|







144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
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 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.  So, to a good
approximation, we define forking to be by accident and branching to
be by intent.  Apart from that, they are the same.

170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185

186
187
188
189
190
191
192

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.  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.  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







|







|
>







170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193

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 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.  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 previously placed on that same check-in, or to block
tag propagation from an ancestor.

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
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
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 direct children.

<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>







|
















>







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
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 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 intended
to never have any direct children.

<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
branch property.</p></dd>
<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>
Changes to www/newrepo.wiki.
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<verbatim>
stephan@ludo:~/fossil$ fossil ui demo.fossil
</verbatim>

The <tt>ui</tt> command starts up a server (with an optional <tt>-port
NUMBER</tt> argument) and launches a web browser pointing at the
fossil server. From there it takes just a few moments to configure the
repo. Most importantly, go to the Setup menu, then the Users link, and
set your account name and password, and grant your account all access
priviledges. (I also like to grant Clone access to the anonymous user,
but that's personal preference.)

Once you are done, kill the fossil server (with Ctrl-C or equivalent)
and close the browser window.








|







28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
<verbatim>
stephan@ludo:~/fossil$ fossil ui demo.fossil
</verbatim>

The <tt>ui</tt> command starts up a server (with an optional <tt>-port
NUMBER</tt> argument) and launches a web browser pointing at the
fossil server. From there it takes just a few moments to configure the
repo. Most importantly, go to the Admin menu, then the Users link, and
set your account name and password, and grant your account all access
priviledges. (I also like to grant Clone access to the anonymous user,
but that's personal preference.)

Once you are done, kill the fossil server (with Ctrl-C or equivalent)
and close the browser window.

152
153
154
155
156
157
158
159
160
161
162
163
164
local repository, with one very important difference.  When you commit
changes to a cloned remote repository, they will be pushed back to the
remote repository. If you have <tt>autosync</tt> on then this sync
happens automatically, otherwise you will need to use the
<em>pull</em> command to get remote changes and the <em>push</em>
command to push your local commits to the remote repository. You must
of course have authorization to commit changes (access is configured
via the Setup/Users page mentioned above).

You may always use the <em>server</em> or <em>ui</em> commands to
browse a cloned repository. You can even edit create or wiki entries,
etc., and they will be pushed to the remote side the next time you
push data to the the remote.







|





152
153
154
155
156
157
158
159
160
161
162
163
164
local repository, with one very important difference.  When you commit
changes to a cloned remote repository, they will be pushed back to the
remote repository. If you have <tt>autosync</tt> on then this sync
happens automatically, otherwise you will need to use the
<em>pull</em> command to get remote changes and the <em>push</em>
command to push your local commits to the remote repository. You must
of course have authorization to commit changes (access is configured
via the Admin/Users page mentioned above).

You may always use the <em>server</em> or <em>ui</em> commands to
browse a cloned repository. You can even edit create or wiki entries,
etc., and they will be pushed to the remote side the next time you
push data to the the remote.
Changes to www/quickstart.wiki.
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    <p>This starts a webserver listening on port 8080.  You can
    specify a different port using the <b>-port</b> option on the command-line.
    After the server is running, fossil will then attempt to launch your
    web browser and make it point to this web server.  If your system
    has an unusual configuration, fossil might not be able to figure out
    how to start your web browser.  In that case, start the web browser
    yourself and point it at http://localhost:8080/.  Click on the
    "Setup" link on the menu bar to start configuring your repository.</p>
    
    <p>By default, fossil does not require a login for HTTP connections
    coming in from the IP loopback address 127.0.0.1.  You can, and perhaps
    should, change this after you create a few users.</p>
    
    <p>When you are finished configuring, just press Control-C or use
    the <b>kill</b> command to shut down the mini-server.</p>







|







71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
    <p>This starts a webserver listening on port 8080.  You can
    specify a different port using the <b>-port</b> option on the command-line.
    After the server is running, fossil will then attempt to launch your
    web browser and make it point to this web server.  If your system
    has an unusual configuration, fossil might not be able to figure out
    how to start your web browser.  In that case, start the web browser
    yourself and point it at http://localhost:8080/.  Click on the
    "Admin" link on the menu bar to start configuring your repository.</p>
    
    <p>By default, fossil does not require a login for HTTP connections
    coming in from the IP loopback address 127.0.0.1.  You can, and perhaps
    should, change this after you create a few users.</p>
    
    <p>When you are finished configuring, just press Control-C or use
    the <b>kill</b> command to shut down the mini-server.</p>