Fossil SCM

Add initial infrastructure for being able to resolve 'ckout' uniformly in certain contexts, per /chat discussion.

stephan 2023-01-24 19:01 trunk
Commit 4d8c30265b3dc76d9fe559cb1c91aea018f0e520f07037fce09a101583611b6f
2 files changed +1 -1 +49 -12
+1 -1
--- src/db.c
+++ src/db.c
@@ -2204,11 +2204,11 @@
22042204
while( n>0 && zPwd[n-1]=='/' ){
22052205
n--;
22062206
zPwd[n] = 0;
22072207
}
22082208
g.zLocalRoot = mprintf("%s/", zPwd);
2209
- g.localOpen = 1;
2209
+ g.localOpen = db_lget_int("checkout", -1);
22102210
db_open_repository(zDbName);
22112211
return 1;
22122212
}
22132213
}
22142214
if( bRootOnly ) break;
22152215
--- src/db.c
+++ src/db.c
@@ -2204,11 +2204,11 @@
2204 while( n>0 && zPwd[n-1]=='/' ){
2205 n--;
2206 zPwd[n] = 0;
2207 }
2208 g.zLocalRoot = mprintf("%s/", zPwd);
2209 g.localOpen = 1;
2210 db_open_repository(zDbName);
2211 return 1;
2212 }
2213 }
2214 if( bRootOnly ) break;
2215
--- src/db.c
+++ src/db.c
@@ -2204,11 +2204,11 @@
2204 while( n>0 && zPwd[n-1]=='/' ){
2205 n--;
2206 zPwd[n] = 0;
2207 }
2208 g.zLocalRoot = mprintf("%s/", zPwd);
2209 g.localOpen = db_lget_int("checkout", -1);
2210 db_open_repository(zDbName);
2211 return 1;
2212 }
2213 }
2214 if( bRootOnly ) break;
2215
+49 -12
--- src/name.c
+++ src/name.c
@@ -19,10 +19,23 @@
1919
*/
2020
#include "config.h"
2121
#include "name.h"
2222
#include <assert.h>
2323
24
+#if INTERFACE
25
+/*
26
+** An upper boundary on RIDs, provided in order to be able to
27
+** distinguish real RID values from RID_CKOUT and any future
28
+** RID_... values.
29
+*/
30
+#define RID_MAX 0x7ffffff0
31
+/*
32
+** A "magic" RID representing the current checkout in some contexts.
33
+*/
34
+#define RID_CKOUT (RID_MAX+1)
35
+#endif
36
+
2437
/*
2538
** Return TRUE if the string begins with something that looks roughly
2639
** like an ISO date/time string. The SQLite date/time functions will
2740
** have the final say-so about whether or not the date/time string is
2841
** well-formed.
@@ -165,11 +178,11 @@
165178
" WHERE tagid=%d AND tagtype>0"
166179
" AND value=%Q AND rid=plink.pid), 1"
167180
" FROM plink WHERE cid=%d AND isprim"
168181
" UNION ALL "
169182
" SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref "
170
- " WHERE tagid=%d AND tagtype>0"
183
+ " WHERE tagid=%d AND tagtype>0"
171184
" AND value=%Q AND rid=plink.pid),"
172185
" 1+par.cnt"
173186
" FROM plink, par"
174187
" WHERE cid=par.pid AND isprim AND par.ex "
175188
" LIMIT 100000 "
@@ -177,11 +190,11 @@
177190
" SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1",
178191
TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2
179192
);
180193
fossil_free(zBr);
181194
rc = db_step(&q);
182
- if( rc==SQLITE_ROW ){
195
+ if( rc==SQLITE_ROW ){
183196
ans = db_column_int(&q, 0);
184197
}
185198
db_finalize(&q);
186199
if( eType==2 && ans>0 ){
187200
zBr = branch_of_rid(ans);
@@ -195,11 +208,11 @@
195208
** Find the RID of the most recent object with symbolic tag zTag
196209
** and having a type that matches zType.
197210
**
198211
** Return 0 if there are no matches.
199212
**
200
-** This is a tricky query to do efficiently.
213
+** This is a tricky query to do efficiently.
201214
** If the tag is very common (ex: "trunk") then
202215
** we want to use the query identified below as Q1 - which searching
203216
** the most recent EVENT table entries for the most recent with the tag.
204217
** But if the tag is relatively scarce (anything other than "trunk", basically)
205218
** then we want to do the indexed search show below as Q2.
@@ -278,56 +291,73 @@
278291
** If zType is NULL or "" or "*" then any type of artifact will serve.
279292
** If zType is "br" then find the first check-in of the named branch
280293
** rather than the last.
281294
**
282295
** zType is "ci" in most use cases since we are usually searching for
283
-** a check-in.
296
+** a check-in. A value of "ci+" works like "ci" but adds these
297
+** semantics: if zTag is "ckout" and a checkout is open, "ci+" causes
298
+** RID_CKOUT to be returned, in which case g.localOpen will hold the
299
+** RID of the checkout. Conversely, passing in the hash, or another
300
+** symbolic name of the local checkout version, will always result in
301
+** its RID being returned.
284302
**
285303
** Note that the input zTag for types "t" and "e" is the artifact hash of
286304
** the ticket-change or technote-change artifact, not the randomly generated
287305
** hexadecimal identifier assigned to tickets and events. Those identifiers
288306
** live in a separate namespace.
289307
*/
290308
int symbolic_name_to_rid(const char *zTag, const char *zType){
291
- int vid;
292309
int rid = 0;
293310
int nTag;
294311
int i;
295312
int startOfBranch = 0;
296313
const char *zXTag; /* zTag with optional [...] removed */
297314
int nXTag; /* Size of zXTag */
298315
const char *zDate; /* Expanded date-time string */
316
+ int isCheckin = 0; /* zType==ci = 1, zType==ci+ = 2 */
299317
300318
if( zType==0 || zType[0]==0 ){
301319
zType = "*";
302320
}else if( zType[0]=='b' ){
303321
zType = "ci";
304322
startOfBranch = 1;
305323
}
306324
if( zTag==0 || zTag[0]==0 ) return 0;
325
+ else if( 'c'==zType[0] ){
326
+ if( fossil_strcmp(zType,"ci")==0 ){
327
+ isCheckin = 1;
328
+ }else if( fossil_strcmp(zType,"ci+")==0 ){
329
+ isCheckin = 2;
330
+ zType = "ci";
331
+ }
332
+ }
307333
308334
/* special keyword: "tip" */
309
- if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){
335
+ if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || isCheckin!=0) ){
310336
rid = db_int(0,
311337
"SELECT objid"
312338
" FROM event"
313339
" WHERE type='ci'"
314340
" ORDER BY event.mtime DESC"
315341
);
316342
if( rid ) return rid;
317343
}
318344
319
- /* special keywords: "prev", "previous", "current", and "next" */
320
- if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
345
+ /* special keywords: "prev", "previous", "current", "ckout", and
346
+ ** "next" */
347
+ if( g.localOpen>0 && (zType[0]=='*' || isCheckin!=0) ){
348
+ const int vid = g.localOpen;
321349
if( fossil_strcmp(zTag, "current")==0 ){
322350
rid = vid;
323351
}else if( fossil_strcmp(zTag, "prev")==0
324352
|| fossil_strcmp(zTag, "previous")==0 ){
325353
rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid);
326354
}else if( fossil_strcmp(zTag, "next")==0 ){
327355
rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
328356
" ORDER BY isprim DESC, mtime DESC", vid);
357
+ }else if( isCheckin>1 && fossil_strcmp(zTag, "ckout")==0 ){
358
+ rid = RID_CKOUT;
329359
}
330360
if( rid ) return rid;
331361
}
332362
333363
/* Date and times */
@@ -523,11 +553,11 @@
523553
&& !is_trailing_punct(zTag[nTag-2])
524554
){
525555
char *zNew = fossil_strndup(zTag, nTag-1);
526556
rid = symbolic_name_to_rid(zNew,zType);
527557
fossil_free(zNew);
528
- }else
558
+ }else
529559
if( nTag>5
530560
&& is_trailing_punct(zTag[nTag-1])
531561
&& is_trailing_punct(zTag[nTag-2])
532562
&& !is_trailing_punct(zTag[nTag-3])
533563
){
@@ -588,11 +618,13 @@
588618
** the full hash, which must eventually be free()d by the caller.
589619
*/
590620
int name_to_uuid2(const char *zName, const char *zType, char **pUuid){
591621
int rid = symbolic_name_to_rid(zName, zType);
592622
if((rid>0) && pUuid){
593
- *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid);
623
+ *pUuid = (rid<RID_MAX)
624
+ ? db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid)
625
+ : NULL;
594626
}
595627
return rid;
596628
}
597629
598630
@@ -623,30 +655,35 @@
623655
}
624656
625657
/*
626658
** COMMAND: test-name-to-id
627659
**
628
-** Usage: %fossil test-name-to-id [--count N] NAME
660
+** Usage: %fossil test-name-to-id [--count N] [--type ARTIFACT_TYPE] NAME
629661
**
630662
** Convert a NAME to a full artifact ID. Repeat the conversion N
631663
** times (for timing purposes) if the --count option is given.
632664
*/
633665
void test_name_to_id(void){
634666
int i;
635667
int n = 0;
636668
Blob name;
669
+ const char *zType;
670
+
637671
db_must_be_within_tree();
672
+ if( (zType = find_option("type","t",1))==0 ){
673
+ zType = "*";
674
+ }
638675
for(i=2; i<g.argc; i++){
639676
if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){
640677
i++;
641678
n = atoi(g.argv[i]);
642679
continue;
643680
}
644681
do{
645682
blob_init(&name, g.argv[i], -1);
646683
fossil_print("%s -> ", g.argv[i]);
647
- if( name_to_uuid(&name, 1, "*") ){
684
+ if( name_to_uuid(&name, 1, zType) ){
648685
fossil_print("ERROR: %s\n", g.zErrMsg);
649686
fossil_error_reset();
650687
}else{
651688
fossil_print("%s\n", blob_buffer(&name));
652689
}
653690
--- src/name.c
+++ src/name.c
@@ -19,10 +19,23 @@
19 */
20 #include "config.h"
21 #include "name.h"
22 #include <assert.h>
23
 
 
 
 
 
 
 
 
 
 
 
 
 
24 /*
25 ** Return TRUE if the string begins with something that looks roughly
26 ** like an ISO date/time string. The SQLite date/time functions will
27 ** have the final say-so about whether or not the date/time string is
28 ** well-formed.
@@ -165,11 +178,11 @@
165 " WHERE tagid=%d AND tagtype>0"
166 " AND value=%Q AND rid=plink.pid), 1"
167 " FROM plink WHERE cid=%d AND isprim"
168 " UNION ALL "
169 " SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref "
170 " WHERE tagid=%d AND tagtype>0"
171 " AND value=%Q AND rid=plink.pid),"
172 " 1+par.cnt"
173 " FROM plink, par"
174 " WHERE cid=par.pid AND isprim AND par.ex "
175 " LIMIT 100000 "
@@ -177,11 +190,11 @@
177 " SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1",
178 TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2
179 );
180 fossil_free(zBr);
181 rc = db_step(&q);
182 if( rc==SQLITE_ROW ){
183 ans = db_column_int(&q, 0);
184 }
185 db_finalize(&q);
186 if( eType==2 && ans>0 ){
187 zBr = branch_of_rid(ans);
@@ -195,11 +208,11 @@
195 ** Find the RID of the most recent object with symbolic tag zTag
196 ** and having a type that matches zType.
197 **
198 ** Return 0 if there are no matches.
199 **
200 ** This is a tricky query to do efficiently.
201 ** If the tag is very common (ex: "trunk") then
202 ** we want to use the query identified below as Q1 - which searching
203 ** the most recent EVENT table entries for the most recent with the tag.
204 ** But if the tag is relatively scarce (anything other than "trunk", basically)
205 ** then we want to do the indexed search show below as Q2.
@@ -278,56 +291,73 @@
278 ** If zType is NULL or "" or "*" then any type of artifact will serve.
279 ** If zType is "br" then find the first check-in of the named branch
280 ** rather than the last.
281 **
282 ** zType is "ci" in most use cases since we are usually searching for
283 ** a check-in.
 
 
 
 
 
284 **
285 ** Note that the input zTag for types "t" and "e" is the artifact hash of
286 ** the ticket-change or technote-change artifact, not the randomly generated
287 ** hexadecimal identifier assigned to tickets and events. Those identifiers
288 ** live in a separate namespace.
289 */
290 int symbolic_name_to_rid(const char *zTag, const char *zType){
291 int vid;
292 int rid = 0;
293 int nTag;
294 int i;
295 int startOfBranch = 0;
296 const char *zXTag; /* zTag with optional [...] removed */
297 int nXTag; /* Size of zXTag */
298 const char *zDate; /* Expanded date-time string */
 
299
300 if( zType==0 || zType[0]==0 ){
301 zType = "*";
302 }else if( zType[0]=='b' ){
303 zType = "ci";
304 startOfBranch = 1;
305 }
306 if( zTag==0 || zTag[0]==0 ) return 0;
 
 
 
 
 
 
 
 
307
308 /* special keyword: "tip" */
309 if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || zType[0]=='c') ){
310 rid = db_int(0,
311 "SELECT objid"
312 " FROM event"
313 " WHERE type='ci'"
314 " ORDER BY event.mtime DESC"
315 );
316 if( rid ) return rid;
317 }
318
319 /* special keywords: "prev", "previous", "current", and "next" */
320 if( g.localOpen && (vid=db_lget_int("checkout",0))!=0 ){
 
 
321 if( fossil_strcmp(zTag, "current")==0 ){
322 rid = vid;
323 }else if( fossil_strcmp(zTag, "prev")==0
324 || fossil_strcmp(zTag, "previous")==0 ){
325 rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid);
326 }else if( fossil_strcmp(zTag, "next")==0 ){
327 rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
328 " ORDER BY isprim DESC, mtime DESC", vid);
 
 
329 }
330 if( rid ) return rid;
331 }
332
333 /* Date and times */
@@ -523,11 +553,11 @@
523 && !is_trailing_punct(zTag[nTag-2])
524 ){
525 char *zNew = fossil_strndup(zTag, nTag-1);
526 rid = symbolic_name_to_rid(zNew,zType);
527 fossil_free(zNew);
528 }else
529 if( nTag>5
530 && is_trailing_punct(zTag[nTag-1])
531 && is_trailing_punct(zTag[nTag-2])
532 && !is_trailing_punct(zTag[nTag-3])
533 ){
@@ -588,11 +618,13 @@
588 ** the full hash, which must eventually be free()d by the caller.
589 */
590 int name_to_uuid2(const char *zName, const char *zType, char **pUuid){
591 int rid = symbolic_name_to_rid(zName, zType);
592 if((rid>0) && pUuid){
593 *pUuid = db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid);
 
 
594 }
595 return rid;
596 }
597
598
@@ -623,30 +655,35 @@
623 }
624
625 /*
626 ** COMMAND: test-name-to-id
627 **
628 ** Usage: %fossil test-name-to-id [--count N] NAME
629 **
630 ** Convert a NAME to a full artifact ID. Repeat the conversion N
631 ** times (for timing purposes) if the --count option is given.
632 */
633 void test_name_to_id(void){
634 int i;
635 int n = 0;
636 Blob name;
 
 
637 db_must_be_within_tree();
 
 
 
638 for(i=2; i<g.argc; i++){
639 if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){
640 i++;
641 n = atoi(g.argv[i]);
642 continue;
643 }
644 do{
645 blob_init(&name, g.argv[i], -1);
646 fossil_print("%s -> ", g.argv[i]);
647 if( name_to_uuid(&name, 1, "*") ){
648 fossil_print("ERROR: %s\n", g.zErrMsg);
649 fossil_error_reset();
650 }else{
651 fossil_print("%s\n", blob_buffer(&name));
652 }
653
--- src/name.c
+++ src/name.c
@@ -19,10 +19,23 @@
19 */
20 #include "config.h"
21 #include "name.h"
22 #include <assert.h>
23
24 #if INTERFACE
25 /*
26 ** An upper boundary on RIDs, provided in order to be able to
27 ** distinguish real RID values from RID_CKOUT and any future
28 ** RID_... values.
29 */
30 #define RID_MAX 0x7ffffff0
31 /*
32 ** A "magic" RID representing the current checkout in some contexts.
33 */
34 #define RID_CKOUT (RID_MAX+1)
35 #endif
36
37 /*
38 ** Return TRUE if the string begins with something that looks roughly
39 ** like an ISO date/time string. The SQLite date/time functions will
40 ** have the final say-so about whether or not the date/time string is
41 ** well-formed.
@@ -165,11 +178,11 @@
178 " WHERE tagid=%d AND tagtype>0"
179 " AND value=%Q AND rid=plink.pid), 1"
180 " FROM plink WHERE cid=%d AND isprim"
181 " UNION ALL "
182 " SELECT plink.pid, EXISTS(SELECT 1 FROM tagxref "
183 " WHERE tagid=%d AND tagtype>0"
184 " AND value=%Q AND rid=plink.pid),"
185 " 1+par.cnt"
186 " FROM plink, par"
187 " WHERE cid=par.pid AND isprim AND par.ex "
188 " LIMIT 100000 "
@@ -177,11 +190,11 @@
190 " SELECT pid FROM par WHERE ex>=%d ORDER BY cnt DESC LIMIT 1",
191 TAG_BRANCH, zBr, ans, TAG_BRANCH, zBr, eType%2
192 );
193 fossil_free(zBr);
194 rc = db_step(&q);
195 if( rc==SQLITE_ROW ){
196 ans = db_column_int(&q, 0);
197 }
198 db_finalize(&q);
199 if( eType==2 && ans>0 ){
200 zBr = branch_of_rid(ans);
@@ -195,11 +208,11 @@
208 ** Find the RID of the most recent object with symbolic tag zTag
209 ** and having a type that matches zType.
210 **
211 ** Return 0 if there are no matches.
212 **
213 ** This is a tricky query to do efficiently.
214 ** If the tag is very common (ex: "trunk") then
215 ** we want to use the query identified below as Q1 - which searching
216 ** the most recent EVENT table entries for the most recent with the tag.
217 ** But if the tag is relatively scarce (anything other than "trunk", basically)
218 ** then we want to do the indexed search show below as Q2.
@@ -278,56 +291,73 @@
291 ** If zType is NULL or "" or "*" then any type of artifact will serve.
292 ** If zType is "br" then find the first check-in of the named branch
293 ** rather than the last.
294 **
295 ** zType is "ci" in most use cases since we are usually searching for
296 ** a check-in. A value of "ci+" works like "ci" but adds these
297 ** semantics: if zTag is "ckout" and a checkout is open, "ci+" causes
298 ** RID_CKOUT to be returned, in which case g.localOpen will hold the
299 ** RID of the checkout. Conversely, passing in the hash, or another
300 ** symbolic name of the local checkout version, will always result in
301 ** its RID being returned.
302 **
303 ** Note that the input zTag for types "t" and "e" is the artifact hash of
304 ** the ticket-change or technote-change artifact, not the randomly generated
305 ** hexadecimal identifier assigned to tickets and events. Those identifiers
306 ** live in a separate namespace.
307 */
308 int symbolic_name_to_rid(const char *zTag, const char *zType){
 
309 int rid = 0;
310 int nTag;
311 int i;
312 int startOfBranch = 0;
313 const char *zXTag; /* zTag with optional [...] removed */
314 int nXTag; /* Size of zXTag */
315 const char *zDate; /* Expanded date-time string */
316 int isCheckin = 0; /* zType==ci = 1, zType==ci+ = 2 */
317
318 if( zType==0 || zType[0]==0 ){
319 zType = "*";
320 }else if( zType[0]=='b' ){
321 zType = "ci";
322 startOfBranch = 1;
323 }
324 if( zTag==0 || zTag[0]==0 ) return 0;
325 else if( 'c'==zType[0] ){
326 if( fossil_strcmp(zType,"ci")==0 ){
327 isCheckin = 1;
328 }else if( fossil_strcmp(zType,"ci+")==0 ){
329 isCheckin = 2;
330 zType = "ci";
331 }
332 }
333
334 /* special keyword: "tip" */
335 if( fossil_strcmp(zTag, "tip")==0 && (zType[0]=='*' || isCheckin!=0) ){
336 rid = db_int(0,
337 "SELECT objid"
338 " FROM event"
339 " WHERE type='ci'"
340 " ORDER BY event.mtime DESC"
341 );
342 if( rid ) return rid;
343 }
344
345 /* special keywords: "prev", "previous", "current", "ckout", and
346 ** "next" */
347 if( g.localOpen>0 && (zType[0]=='*' || isCheckin!=0) ){
348 const int vid = g.localOpen;
349 if( fossil_strcmp(zTag, "current")==0 ){
350 rid = vid;
351 }else if( fossil_strcmp(zTag, "prev")==0
352 || fossil_strcmp(zTag, "previous")==0 ){
353 rid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", vid);
354 }else if( fossil_strcmp(zTag, "next")==0 ){
355 rid = db_int(0, "SELECT cid FROM plink WHERE pid=%d"
356 " ORDER BY isprim DESC, mtime DESC", vid);
357 }else if( isCheckin>1 && fossil_strcmp(zTag, "ckout")==0 ){
358 rid = RID_CKOUT;
359 }
360 if( rid ) return rid;
361 }
362
363 /* Date and times */
@@ -523,11 +553,11 @@
553 && !is_trailing_punct(zTag[nTag-2])
554 ){
555 char *zNew = fossil_strndup(zTag, nTag-1);
556 rid = symbolic_name_to_rid(zNew,zType);
557 fossil_free(zNew);
558 }else
559 if( nTag>5
560 && is_trailing_punct(zTag[nTag-1])
561 && is_trailing_punct(zTag[nTag-2])
562 && !is_trailing_punct(zTag[nTag-3])
563 ){
@@ -588,11 +618,13 @@
618 ** the full hash, which must eventually be free()d by the caller.
619 */
620 int name_to_uuid2(const char *zName, const char *zType, char **pUuid){
621 int rid = symbolic_name_to_rid(zName, zType);
622 if((rid>0) && pUuid){
623 *pUuid = (rid<RID_MAX)
624 ? db_text(NULL, "SELECT uuid FROM blob WHERE rid=%d", rid)
625 : NULL;
626 }
627 return rid;
628 }
629
630
@@ -623,30 +655,35 @@
655 }
656
657 /*
658 ** COMMAND: test-name-to-id
659 **
660 ** Usage: %fossil test-name-to-id [--count N] [--type ARTIFACT_TYPE] NAME
661 **
662 ** Convert a NAME to a full artifact ID. Repeat the conversion N
663 ** times (for timing purposes) if the --count option is given.
664 */
665 void test_name_to_id(void){
666 int i;
667 int n = 0;
668 Blob name;
669 const char *zType;
670
671 db_must_be_within_tree();
672 if( (zType = find_option("type","t",1))==0 ){
673 zType = "*";
674 }
675 for(i=2; i<g.argc; i++){
676 if( strcmp(g.argv[i],"--count")==0 && i+1<g.argc ){
677 i++;
678 n = atoi(g.argv[i]);
679 continue;
680 }
681 do{
682 blob_init(&name, g.argv[i], -1);
683 fossil_print("%s -> ", g.argv[i]);
684 if( name_to_uuid(&name, 1, zType) ){
685 fossil_print("ERROR: %s\n", g.zErrMsg);
686 fossil_error_reset();
687 }else{
688 fossil_print("%s\n", blob_buffer(&name));
689 }
690

Keyboard Shortcuts

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