Fossil SCM
Merge the latest trunk changes into the side-by-side diff branch.
Commit
23c3affad4c0a620e2f8e0b6d2f9183f65cdb84a
Parent
ff9de303e3bfb7d…
14 files changed
+3
-1
+1
-1
-2
+1
-3
+38
+3
-19
+1
-1
+3
+3
+20
-3
-2
+1
-3
+1
-4
+40
-29
+3
-1
| --- src/browse.c | ||
| +++ src/browse.c | ||
| @@ -249,11 +249,13 @@ | ||
| 249 | 249 | /* Generate a multi-column table listing the contents of zD[] |
| 250 | 250 | ** directory. |
| 251 | 251 | */ |
| 252 | 252 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 253 | 253 | cnt = db_int(0, "SELECT count(*) FROM localfiles /*scan*/"); |
| 254 | - nCol = 4; | |
| 254 | + nCol = 100/mxLen; | |
| 255 | + if( nCol<1 ) nCol = 1; | |
| 256 | + if( nCol>5 ) nCol = 5; | |
| 255 | 257 | nRow = (cnt+nCol-1)/nCol; |
| 256 | 258 | db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/"); |
| 257 | 259 | @ <table class="browser"><tr><td class="browser"><ul class="browser"> |
| 258 | 260 | i = 0; |
| 259 | 261 | while( db_step(&q)==SQLITE_ROW ){ |
| 260 | 262 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -249,11 +249,13 @@ | |
| 249 | /* Generate a multi-column table listing the contents of zD[] |
| 250 | ** directory. |
| 251 | */ |
| 252 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 253 | cnt = db_int(0, "SELECT count(*) FROM localfiles /*scan*/"); |
| 254 | nCol = 4; |
| 255 | nRow = (cnt+nCol-1)/nCol; |
| 256 | db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/"); |
| 257 | @ <table class="browser"><tr><td class="browser"><ul class="browser"> |
| 258 | i = 0; |
| 259 | while( db_step(&q)==SQLITE_ROW ){ |
| 260 |
| --- src/browse.c | |
| +++ src/browse.c | |
| @@ -249,11 +249,13 @@ | |
| 249 | /* Generate a multi-column table listing the contents of zD[] |
| 250 | ** directory. |
| 251 | */ |
| 252 | mxLen = db_int(12, "SELECT max(length(x)) FROM localfiles /*scan*/"); |
| 253 | cnt = db_int(0, "SELECT count(*) FROM localfiles /*scan*/"); |
| 254 | nCol = 100/mxLen; |
| 255 | if( nCol<1 ) nCol = 1; |
| 256 | if( nCol>5 ) nCol = 5; |
| 257 | nRow = (cnt+nCol-1)/nCol; |
| 258 | db_prepare(&q, "SELECT x, u FROM localfiles ORDER BY x /*scan*/"); |
| 259 | @ <table class="browser"><tr><td class="browser"><ul class="browser"> |
| 260 | i = 0; |
| 261 | while( db_step(&q)==SQLITE_ROW ){ |
| 262 |
+1
-1
| --- src/cgi.c | ||
| +++ src/cgi.c | ||
| @@ -135,11 +135,11 @@ | ||
| 135 | 135 | } |
| 136 | 136 | |
| 137 | 137 | /* |
| 138 | 138 | ** Return a pointer to the HTTP reply text. |
| 139 | 139 | */ |
| 140 | -char *cgi_extract_content(int *pnAmt){ | |
| 140 | +char *cgi_extract_content(void){ | |
| 141 | 141 | cgi_combine_header_and_body(); |
| 142 | 142 | return blob_buffer(&cgiContent[0]); |
| 143 | 143 | } |
| 144 | 144 | |
| 145 | 145 | /* |
| 146 | 146 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -135,11 +135,11 @@ | |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | ** Return a pointer to the HTTP reply text. |
| 139 | */ |
| 140 | char *cgi_extract_content(int *pnAmt){ |
| 141 | cgi_combine_header_and_body(); |
| 142 | return blob_buffer(&cgiContent[0]); |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 |
| --- src/cgi.c | |
| +++ src/cgi.c | |
| @@ -135,11 +135,11 @@ | |
| 135 | } |
| 136 | |
| 137 | /* |
| 138 | ** Return a pointer to the HTTP reply text. |
| 139 | */ |
| 140 | char *cgi_extract_content(void){ |
| 141 | cgi_combine_header_and_body(); |
| 142 | return blob_buffer(&cgiContent[0]); |
| 143 | } |
| 144 | |
| 145 | /* |
| 146 |
-2
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -282,18 +282,16 @@ | ||
| 282 | 282 | Stmt q; |
| 283 | 283 | int n; |
| 284 | 284 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 285 | 285 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 286 | 286 | int cwdRelative = 0; |
| 287 | - int outputManifest; | |
| 288 | 287 | Glob *pIgnore; |
| 289 | 288 | Blob rewrittenPathname; |
| 290 | 289 | const char *zPathname, *zDisplayName; |
| 291 | 290 | |
| 292 | 291 | db_must_be_within_tree(); |
| 293 | 292 | cwdRelative = determine_cwd_relative_option(); |
| 294 | - outputManifest = db_get_boolean("manifest",0); | |
| 295 | 293 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 296 | 294 | n = strlen(g.zLocalRoot); |
| 297 | 295 | blob_init(&path, g.zLocalRoot, n-1); |
| 298 | 296 | if( zIgnoreFlag==0 ){ |
| 299 | 297 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 300 | 298 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -282,18 +282,16 @@ | |
| 282 | Stmt q; |
| 283 | int n; |
| 284 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 285 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 286 | int cwdRelative = 0; |
| 287 | int outputManifest; |
| 288 | Glob *pIgnore; |
| 289 | Blob rewrittenPathname; |
| 290 | const char *zPathname, *zDisplayName; |
| 291 | |
| 292 | db_must_be_within_tree(); |
| 293 | cwdRelative = determine_cwd_relative_option(); |
| 294 | outputManifest = db_get_boolean("manifest",0); |
| 295 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 296 | n = strlen(g.zLocalRoot); |
| 297 | blob_init(&path, g.zLocalRoot, n-1); |
| 298 | if( zIgnoreFlag==0 ){ |
| 299 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 300 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -282,18 +282,16 @@ | |
| 282 | Stmt q; |
| 283 | int n; |
| 284 | const char *zIgnoreFlag = find_option("ignore",0,1); |
| 285 | int allFlag = find_option("dotfiles",0,0)!=0; |
| 286 | int cwdRelative = 0; |
| 287 | Glob *pIgnore; |
| 288 | Blob rewrittenPathname; |
| 289 | const char *zPathname, *zDisplayName; |
| 290 | |
| 291 | db_must_be_within_tree(); |
| 292 | cwdRelative = determine_cwd_relative_option(); |
| 293 | db_multi_exec("CREATE TEMP TABLE sfile(x TEXT PRIMARY KEY)"); |
| 294 | n = strlen(g.zLocalRoot); |
| 295 | blob_init(&path, g.zLocalRoot, n-1); |
| 296 | if( zIgnoreFlag==0 ){ |
| 297 | zIgnoreFlag = db_get("ignore-glob", 0); |
| 298 |
+1
-3
| --- src/http_transport.c | ||
| +++ src/http_transport.c | ||
| @@ -265,14 +265,12 @@ | ||
| 265 | 265 | void transport_send(Blob *toSend){ |
| 266 | 266 | char *z = blob_buffer(toSend); |
| 267 | 267 | int n = blob_size(toSend); |
| 268 | 268 | transport.nSent += n; |
| 269 | 269 | if( g.urlIsSsh ){ |
| 270 | - int sent; | |
| 271 | - sent = fwrite(z, 1, n, sshOut); | |
| 270 | + fwrite(z, 1, n, sshOut); | |
| 272 | 271 | fflush(sshOut); |
| 273 | - /* printf("sent %d of %d bytes\n", sent, n); fflush(stdout); */ | |
| 274 | 272 | }else if( g.urlIsHttps ){ |
| 275 | 273 | #ifdef FOSSIL_ENABLE_SSL |
| 276 | 274 | int sent; |
| 277 | 275 | while( n>0 ){ |
| 278 | 276 | sent = ssl_send(0, z, n); |
| 279 | 277 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -265,14 +265,12 @@ | |
| 265 | void transport_send(Blob *toSend){ |
| 266 | char *z = blob_buffer(toSend); |
| 267 | int n = blob_size(toSend); |
| 268 | transport.nSent += n; |
| 269 | if( g.urlIsSsh ){ |
| 270 | int sent; |
| 271 | sent = fwrite(z, 1, n, sshOut); |
| 272 | fflush(sshOut); |
| 273 | /* printf("sent %d of %d bytes\n", sent, n); fflush(stdout); */ |
| 274 | }else if( g.urlIsHttps ){ |
| 275 | #ifdef FOSSIL_ENABLE_SSL |
| 276 | int sent; |
| 277 | while( n>0 ){ |
| 278 | sent = ssl_send(0, z, n); |
| 279 |
| --- src/http_transport.c | |
| +++ src/http_transport.c | |
| @@ -265,14 +265,12 @@ | |
| 265 | void transport_send(Blob *toSend){ |
| 266 | char *z = blob_buffer(toSend); |
| 267 | int n = blob_size(toSend); |
| 268 | transport.nSent += n; |
| 269 | if( g.urlIsSsh ){ |
| 270 | fwrite(z, 1, n, sshOut); |
| 271 | fflush(sshOut); |
| 272 | }else if( g.urlIsHttps ){ |
| 273 | #ifdef FOSSIL_ENABLE_SSL |
| 274 | int sent; |
| 275 | while( n>0 ){ |
| 276 | sent = ssl_send(0, z, n); |
| 277 |
+38
| --- src/manifest.c | ||
| +++ src/manifest.c | ||
| @@ -1819,10 +1819,48 @@ | ||
| 1819 | 1819 | "VALUES('t',%.17g,%d,%Q,%Q)", |
| 1820 | 1820 | p->rDate, rid, p->zUser, zComment |
| 1821 | 1821 | ); |
| 1822 | 1822 | free(zComment); |
| 1823 | 1823 | } |
| 1824 | + } | |
| 1825 | + if( p->type==CFTYPE_CONTROL ){ | |
| 1826 | + Blob comment; | |
| 1827 | + int i; | |
| 1828 | + const char *zName; | |
| 1829 | + const char *zValue; | |
| 1830 | + const char *zUuid; | |
| 1831 | + blob_zero(&comment); | |
| 1832 | + for(i=0; i<p->nTag; i++){ | |
| 1833 | + zUuid = p->aTag[i].zUuid; | |
| 1834 | + if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){ | |
| 1835 | + if( i>0 ) blob_append(&comment, " ", 1); | |
| 1836 | + blob_appendf(&comment, "Tag changes on [/timeline?dp=%S&n=4 | %S]:", | |
| 1837 | + zUuid, zUuid); | |
| 1838 | + } | |
| 1839 | + zName = p->aTag[i].zName; | |
| 1840 | + zValue = p->aTag[i].zValue; | |
| 1841 | + if( zName[0]=='-' ){ | |
| 1842 | + blob_appendf(&comment, " Cancel"); | |
| 1843 | + }else if( zName[0]=='+' ){ | |
| 1844 | + blob_appendf(&comment, " Add"); | |
| 1845 | + }else{ | |
| 1846 | + blob_appendf(&comment, " Add propagating"); | |
| 1847 | + } | |
| 1848 | + if( memcmp(&zName[1], "sym-",4)==0 ){ | |
| 1849 | + blob_appendf(&comment, " symbolic tag \"%h\".", &zName[5]); | |
| 1850 | + }else if( fossil_strcmp(&zName[1], "comment")!=0 && zValue && zValue[0] ){ | |
| 1851 | + blob_appendf(&comment, " %h=%h.", &zName[1], zValue); | |
| 1852 | + }else{ | |
| 1853 | + blob_appendf(&comment, " %h.", &zName[1]); | |
| 1854 | + } | |
| 1855 | + } | |
| 1856 | + db_multi_exec( | |
| 1857 | + "REPLACE INTO event(type,mtime,objid,user,comment)" | |
| 1858 | + "VALUES('g',%.17g,%d,%Q,%Q)", | |
| 1859 | + p->rDate, rid, p->zUser, blob_str(&comment) | |
| 1860 | + ); | |
| 1861 | + blob_reset(&comment); | |
| 1824 | 1862 | } |
| 1825 | 1863 | db_end_transaction(0); |
| 1826 | 1864 | if( p->type==CFTYPE_MANIFEST ){ |
| 1827 | 1865 | manifest_cache_insert(p); |
| 1828 | 1866 | }else{ |
| 1829 | 1867 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1819,10 +1819,48 @@ | |
| 1819 | "VALUES('t',%.17g,%d,%Q,%Q)", |
| 1820 | p->rDate, rid, p->zUser, zComment |
| 1821 | ); |
| 1822 | free(zComment); |
| 1823 | } |
| 1824 | } |
| 1825 | db_end_transaction(0); |
| 1826 | if( p->type==CFTYPE_MANIFEST ){ |
| 1827 | manifest_cache_insert(p); |
| 1828 | }else{ |
| 1829 |
| --- src/manifest.c | |
| +++ src/manifest.c | |
| @@ -1819,10 +1819,48 @@ | |
| 1819 | "VALUES('t',%.17g,%d,%Q,%Q)", |
| 1820 | p->rDate, rid, p->zUser, zComment |
| 1821 | ); |
| 1822 | free(zComment); |
| 1823 | } |
| 1824 | } |
| 1825 | if( p->type==CFTYPE_CONTROL ){ |
| 1826 | Blob comment; |
| 1827 | int i; |
| 1828 | const char *zName; |
| 1829 | const char *zValue; |
| 1830 | const char *zUuid; |
| 1831 | blob_zero(&comment); |
| 1832 | for(i=0; i<p->nTag; i++){ |
| 1833 | zUuid = p->aTag[i].zUuid; |
| 1834 | if( i==0 || fossil_strcmp(zUuid, p->aTag[i-1].zUuid)!=0 ){ |
| 1835 | if( i>0 ) blob_append(&comment, " ", 1); |
| 1836 | blob_appendf(&comment, "Tag changes on [/timeline?dp=%S&n=4 | %S]:", |
| 1837 | zUuid, zUuid); |
| 1838 | } |
| 1839 | zName = p->aTag[i].zName; |
| 1840 | zValue = p->aTag[i].zValue; |
| 1841 | if( zName[0]=='-' ){ |
| 1842 | blob_appendf(&comment, " Cancel"); |
| 1843 | }else if( zName[0]=='+' ){ |
| 1844 | blob_appendf(&comment, " Add"); |
| 1845 | }else{ |
| 1846 | blob_appendf(&comment, " Add propagating"); |
| 1847 | } |
| 1848 | if( memcmp(&zName[1], "sym-",4)==0 ){ |
| 1849 | blob_appendf(&comment, " symbolic tag \"%h\".", &zName[5]); |
| 1850 | }else if( fossil_strcmp(&zName[1], "comment")!=0 && zValue && zValue[0] ){ |
| 1851 | blob_appendf(&comment, " %h=%h.", &zName[1], zValue); |
| 1852 | }else{ |
| 1853 | blob_appendf(&comment, " %h.", &zName[1]); |
| 1854 | } |
| 1855 | } |
| 1856 | db_multi_exec( |
| 1857 | "REPLACE INTO event(type,mtime,objid,user,comment)" |
| 1858 | "VALUES('g',%.17g,%d,%Q,%Q)", |
| 1859 | p->rDate, rid, p->zUser, blob_str(&comment) |
| 1860 | ); |
| 1861 | blob_reset(&comment); |
| 1862 | } |
| 1863 | db_end_transaction(0); |
| 1864 | if( p->type==CFTYPE_MANIFEST ){ |
| 1865 | manifest_cache_insert(p); |
| 1866 | }else{ |
| 1867 |
+3
-19
| --- src/report.c | ||
| +++ src/report.c | ||
| @@ -630,17 +630,11 @@ | ||
| 630 | 630 | char **azName /* Names of the columns */ |
| 631 | 631 | ){ |
| 632 | 632 | struct GenerateHTML *pState = (struct GenerateHTML*)pUser; |
| 633 | 633 | int i; |
| 634 | 634 | const char *zTid; /* Ticket UUID. (value of column named '#') */ |
| 635 | - int rn; /* Report number */ | |
| 636 | 635 | char *zBg = 0; /* Use this background color */ |
| 637 | - char zPage[30]; /* Text version of the ticket number */ | |
| 638 | - | |
| 639 | - /* Get the report number | |
| 640 | - */ | |
| 641 | - rn = pState->rn; | |
| 642 | 636 | |
| 643 | 637 | /* Do initialization |
| 644 | 638 | */ |
| 645 | 639 | if( pState->nCount==0 ){ |
| 646 | 640 | /* Turn off the authorizer. It is no longer doing anything since the |
| @@ -719,11 +713,10 @@ | ||
| 719 | 713 | */ |
| 720 | 714 | zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0; |
| 721 | 715 | if( zBg==0 ) zBg = "white"; |
| 722 | 716 | @ <tr style="background-color:%h(zBg)"> |
| 723 | 717 | zTid = 0; |
| 724 | - zPage[0] = 0; | |
| 725 | 718 | for(i=0; i<nArg; i++){ |
| 726 | 719 | char *zData; |
| 727 | 720 | if( i==pState->iBg ) continue; |
| 728 | 721 | zData = azArg[i]; |
| 729 | 722 | if( zData==0 ) zData = ""; |
| @@ -1108,41 +1101,32 @@ | ||
| 1108 | 1101 | const char *zFilter, |
| 1109 | 1102 | tTktShowEncoding enc |
| 1110 | 1103 | ){ |
| 1111 | 1104 | Stmt q; |
| 1112 | 1105 | char *zSql; |
| 1113 | - const char *zTitle; | |
| 1114 | - const char *zOwner; | |
| 1115 | - const char *zClrKey; | |
| 1116 | 1106 | char *zErr1 = 0; |
| 1117 | 1107 | char *zErr2 = 0; |
| 1118 | 1108 | int count = 0; |
| 1119 | 1109 | int rn; |
| 1120 | 1110 | |
| 1121 | 1111 | if (!zRep || !strcmp(zRep,zFullTicketRptRn) || !strcmp(zRep,zFullTicketRptTitle) ){ |
| 1122 | - zTitle = zFullTicketRptTitle; | |
| 1123 | 1112 | zSql = "SELECT * FROM ticket"; |
| 1124 | - zOwner = g.zLogin; | |
| 1125 | - zClrKey = ""; | |
| 1126 | 1113 | }else{ |
| 1127 | 1114 | rn = atoi(zRep); |
| 1128 | 1115 | if( rn ){ |
| 1129 | 1116 | db_prepare(&q, |
| 1130 | - "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn); | |
| 1117 | + "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn); | |
| 1131 | 1118 | }else{ |
| 1132 | 1119 | db_prepare(&q, |
| 1133 | - "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE title='%s'", zRep); | |
| 1120 | + "SELECT sqlcode FROM reportfmt WHERE title='%s'", zRep); | |
| 1134 | 1121 | } |
| 1135 | 1122 | if( db_step(&q)!=SQLITE_ROW ){ |
| 1136 | 1123 | db_finalize(&q); |
| 1137 | 1124 | rpt_list_reports(); |
| 1138 | 1125 | fossil_fatal("unknown report format(%s)!",zRep); |
| 1139 | 1126 | } |
| 1140 | - zTitle = db_column_malloc(&q, 0); | |
| 1141 | - zSql = db_column_malloc(&q, 1); | |
| 1142 | - zOwner = db_column_malloc(&q, 2); | |
| 1143 | - zClrKey = db_column_malloc(&q, 3); | |
| 1127 | + zSql = db_column_malloc(&q, 0); | |
| 1144 | 1128 | db_finalize(&q); |
| 1145 | 1129 | } |
| 1146 | 1130 | if( zFilter ){ |
| 1147 | 1131 | zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); |
| 1148 | 1132 | } |
| 1149 | 1133 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -630,17 +630,11 @@ | |
| 630 | char **azName /* Names of the columns */ |
| 631 | ){ |
| 632 | struct GenerateHTML *pState = (struct GenerateHTML*)pUser; |
| 633 | int i; |
| 634 | const char *zTid; /* Ticket UUID. (value of column named '#') */ |
| 635 | int rn; /* Report number */ |
| 636 | char *zBg = 0; /* Use this background color */ |
| 637 | char zPage[30]; /* Text version of the ticket number */ |
| 638 | |
| 639 | /* Get the report number |
| 640 | */ |
| 641 | rn = pState->rn; |
| 642 | |
| 643 | /* Do initialization |
| 644 | */ |
| 645 | if( pState->nCount==0 ){ |
| 646 | /* Turn off the authorizer. It is no longer doing anything since the |
| @@ -719,11 +713,10 @@ | |
| 719 | */ |
| 720 | zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0; |
| 721 | if( zBg==0 ) zBg = "white"; |
| 722 | @ <tr style="background-color:%h(zBg)"> |
| 723 | zTid = 0; |
| 724 | zPage[0] = 0; |
| 725 | for(i=0; i<nArg; i++){ |
| 726 | char *zData; |
| 727 | if( i==pState->iBg ) continue; |
| 728 | zData = azArg[i]; |
| 729 | if( zData==0 ) zData = ""; |
| @@ -1108,41 +1101,32 @@ | |
| 1108 | const char *zFilter, |
| 1109 | tTktShowEncoding enc |
| 1110 | ){ |
| 1111 | Stmt q; |
| 1112 | char *zSql; |
| 1113 | const char *zTitle; |
| 1114 | const char *zOwner; |
| 1115 | const char *zClrKey; |
| 1116 | char *zErr1 = 0; |
| 1117 | char *zErr2 = 0; |
| 1118 | int count = 0; |
| 1119 | int rn; |
| 1120 | |
| 1121 | if (!zRep || !strcmp(zRep,zFullTicketRptRn) || !strcmp(zRep,zFullTicketRptTitle) ){ |
| 1122 | zTitle = zFullTicketRptTitle; |
| 1123 | zSql = "SELECT * FROM ticket"; |
| 1124 | zOwner = g.zLogin; |
| 1125 | zClrKey = ""; |
| 1126 | }else{ |
| 1127 | rn = atoi(zRep); |
| 1128 | if( rn ){ |
| 1129 | db_prepare(&q, |
| 1130 | "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE rn=%d", rn); |
| 1131 | }else{ |
| 1132 | db_prepare(&q, |
| 1133 | "SELECT title, sqlcode, owner, cols FROM reportfmt WHERE title='%s'", zRep); |
| 1134 | } |
| 1135 | if( db_step(&q)!=SQLITE_ROW ){ |
| 1136 | db_finalize(&q); |
| 1137 | rpt_list_reports(); |
| 1138 | fossil_fatal("unknown report format(%s)!",zRep); |
| 1139 | } |
| 1140 | zTitle = db_column_malloc(&q, 0); |
| 1141 | zSql = db_column_malloc(&q, 1); |
| 1142 | zOwner = db_column_malloc(&q, 2); |
| 1143 | zClrKey = db_column_malloc(&q, 3); |
| 1144 | db_finalize(&q); |
| 1145 | } |
| 1146 | if( zFilter ){ |
| 1147 | zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); |
| 1148 | } |
| 1149 |
| --- src/report.c | |
| +++ src/report.c | |
| @@ -630,17 +630,11 @@ | |
| 630 | char **azName /* Names of the columns */ |
| 631 | ){ |
| 632 | struct GenerateHTML *pState = (struct GenerateHTML*)pUser; |
| 633 | int i; |
| 634 | const char *zTid; /* Ticket UUID. (value of column named '#') */ |
| 635 | char *zBg = 0; /* Use this background color */ |
| 636 | |
| 637 | /* Do initialization |
| 638 | */ |
| 639 | if( pState->nCount==0 ){ |
| 640 | /* Turn off the authorizer. It is no longer doing anything since the |
| @@ -719,11 +713,10 @@ | |
| 713 | */ |
| 714 | zBg = pState->iBg>=0 ? azArg[pState->iBg] : 0; |
| 715 | if( zBg==0 ) zBg = "white"; |
| 716 | @ <tr style="background-color:%h(zBg)"> |
| 717 | zTid = 0; |
| 718 | for(i=0; i<nArg; i++){ |
| 719 | char *zData; |
| 720 | if( i==pState->iBg ) continue; |
| 721 | zData = azArg[i]; |
| 722 | if( zData==0 ) zData = ""; |
| @@ -1108,41 +1101,32 @@ | |
| 1101 | const char *zFilter, |
| 1102 | tTktShowEncoding enc |
| 1103 | ){ |
| 1104 | Stmt q; |
| 1105 | char *zSql; |
| 1106 | char *zErr1 = 0; |
| 1107 | char *zErr2 = 0; |
| 1108 | int count = 0; |
| 1109 | int rn; |
| 1110 | |
| 1111 | if (!zRep || !strcmp(zRep,zFullTicketRptRn) || !strcmp(zRep,zFullTicketRptTitle) ){ |
| 1112 | zSql = "SELECT * FROM ticket"; |
| 1113 | }else{ |
| 1114 | rn = atoi(zRep); |
| 1115 | if( rn ){ |
| 1116 | db_prepare(&q, |
| 1117 | "SELECT sqlcode FROM reportfmt WHERE rn=%d", rn); |
| 1118 | }else{ |
| 1119 | db_prepare(&q, |
| 1120 | "SELECT sqlcode FROM reportfmt WHERE title='%s'", zRep); |
| 1121 | } |
| 1122 | if( db_step(&q)!=SQLITE_ROW ){ |
| 1123 | db_finalize(&q); |
| 1124 | rpt_list_reports(); |
| 1125 | fossil_fatal("unknown report format(%s)!",zRep); |
| 1126 | } |
| 1127 | zSql = db_column_malloc(&q, 0); |
| 1128 | db_finalize(&q); |
| 1129 | } |
| 1130 | if( zFilter ){ |
| 1131 | zSql = mprintf("SELECT * FROM (%s) WHERE %s",zSql,zFilter); |
| 1132 | } |
| 1133 |
+1
-1
| --- src/schema.c | ||
| +++ src/schema.c | ||
| @@ -251,11 +251,11 @@ | ||
| 251 | 251 | @ CREATE TABLE leaf(rid INTEGER PRIMARY KEY); |
| 252 | 252 | @ |
| 253 | 253 | @ -- Events used to generate a timeline |
| 254 | 254 | @ -- |
| 255 | 255 | @ CREATE TABLE event( |
| 256 | -@ type TEXT, -- Type of event: 'ci', 'w', 'e', 't' | |
| 256 | +@ type TEXT, -- Type of event: 'ci', 'w', 'e', 't', 'g' | |
| 257 | 257 | @ mtime DATETIME, -- Time of occurrence. Julian day. |
| 258 | 258 | @ objid INTEGER PRIMARY KEY, -- Associated record ID |
| 259 | 259 | @ tagid INTEGER, -- Associated ticket or wiki name tag |
| 260 | 260 | @ uid INTEGER REFERENCES user, -- User who caused the event |
| 261 | 261 | @ bgcolor TEXT, -- Color set by 'bgcolor' property |
| 262 | 262 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -251,11 +251,11 @@ | |
| 251 | @ CREATE TABLE leaf(rid INTEGER PRIMARY KEY); |
| 252 | @ |
| 253 | @ -- Events used to generate a timeline |
| 254 | @ -- |
| 255 | @ CREATE TABLE event( |
| 256 | @ type TEXT, -- Type of event: 'ci', 'w', 'e', 't' |
| 257 | @ mtime DATETIME, -- Time of occurrence. Julian day. |
| 258 | @ objid INTEGER PRIMARY KEY, -- Associated record ID |
| 259 | @ tagid INTEGER, -- Associated ticket or wiki name tag |
| 260 | @ uid INTEGER REFERENCES user, -- User who caused the event |
| 261 | @ bgcolor TEXT, -- Color set by 'bgcolor' property |
| 262 |
| --- src/schema.c | |
| +++ src/schema.c | |
| @@ -251,11 +251,11 @@ | |
| 251 | @ CREATE TABLE leaf(rid INTEGER PRIMARY KEY); |
| 252 | @ |
| 253 | @ -- Events used to generate a timeline |
| 254 | @ -- |
| 255 | @ CREATE TABLE event( |
| 256 | @ type TEXT, -- Type of event: 'ci', 'w', 'e', 't', 'g' |
| 257 | @ mtime DATETIME, -- Time of occurrence. Julian day. |
| 258 | @ objid INTEGER PRIMARY KEY, -- Associated record ID |
| 259 | @ tagid INTEGER, -- Associated ticket or wiki name tag |
| 260 | @ uid INTEGER REFERENCES user, -- User who caused the event |
| 261 | @ bgcolor TEXT, -- Color set by 'bgcolor' property |
| 262 |
+3
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -1301,10 +1301,13 @@ | ||
| 1301 | 1301 | db_multi_exec("%s", zCurrent); |
| 1302 | 1302 | } |
| 1303 | 1303 | } |
| 1304 | 1304 | |
| 1305 | 1305 | style_header("Skins"); |
| 1306 | + if( zErr ){ | |
| 1307 | + @ <p><font color="red">%h(zErr)</font></p> | |
| 1308 | + } | |
| 1306 | 1309 | @ <p>A "skin" is a combination of |
| 1307 | 1310 | @ <a href="setup_editcss">CSS</a>, |
| 1308 | 1311 | @ <a href="setup_header">Header</a>, |
| 1309 | 1312 | @ <a href="setup_footer">Footer</a>, and |
| 1310 | 1313 | @ <a href="setup_logo">Logo</a> that determines the look and feel |
| 1311 | 1314 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -1301,10 +1301,13 @@ | |
| 1301 | db_multi_exec("%s", zCurrent); |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | style_header("Skins"); |
| 1306 | @ <p>A "skin" is a combination of |
| 1307 | @ <a href="setup_editcss">CSS</a>, |
| 1308 | @ <a href="setup_header">Header</a>, |
| 1309 | @ <a href="setup_footer">Footer</a>, and |
| 1310 | @ <a href="setup_logo">Logo</a> that determines the look and feel |
| 1311 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -1301,10 +1301,13 @@ | |
| 1301 | db_multi_exec("%s", zCurrent); |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | style_header("Skins"); |
| 1306 | if( zErr ){ |
| 1307 | @ <p><font color="red">%h(zErr)</font></p> |
| 1308 | } |
| 1309 | @ <p>A "skin" is a combination of |
| 1310 | @ <a href="setup_editcss">CSS</a>, |
| 1311 | @ <a href="setup_header">Header</a>, |
| 1312 | @ <a href="setup_footer">Footer</a>, and |
| 1313 | @ <a href="setup_logo">Logo</a> that determines the look and feel |
| 1314 |
+3
| --- src/skins.c | ||
| +++ src/skins.c | ||
| @@ -1301,10 +1301,13 @@ | ||
| 1301 | 1301 | db_multi_exec("%s", zCurrent); |
| 1302 | 1302 | } |
| 1303 | 1303 | } |
| 1304 | 1304 | |
| 1305 | 1305 | style_header("Skins"); |
| 1306 | + if( zErr ){ | |
| 1307 | + @ <p><font color="red">%h(zErr)</font></p> | |
| 1308 | + } | |
| 1306 | 1309 | @ <p>A "skin" is a combination of |
| 1307 | 1310 | @ <a href="setup_editcss">CSS</a>, |
| 1308 | 1311 | @ <a href="setup_header">Header</a>, |
| 1309 | 1312 | @ <a href="setup_footer">Footer</a>, and |
| 1310 | 1313 | @ <a href="setup_logo">Logo</a> that determines the look and feel |
| 1311 | 1314 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -1301,10 +1301,13 @@ | |
| 1301 | db_multi_exec("%s", zCurrent); |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | style_header("Skins"); |
| 1306 | @ <p>A "skin" is a combination of |
| 1307 | @ <a href="setup_editcss">CSS</a>, |
| 1308 | @ <a href="setup_header">Header</a>, |
| 1309 | @ <a href="setup_footer">Footer</a>, and |
| 1310 | @ <a href="setup_logo">Logo</a> that determines the look and feel |
| 1311 |
| --- src/skins.c | |
| +++ src/skins.c | |
| @@ -1301,10 +1301,13 @@ | |
| 1301 | db_multi_exec("%s", zCurrent); |
| 1302 | } |
| 1303 | } |
| 1304 | |
| 1305 | style_header("Skins"); |
| 1306 | if( zErr ){ |
| 1307 | @ <p><font color="red">%h(zErr)</font></p> |
| 1308 | } |
| 1309 | @ <p>A "skin" is a combination of |
| 1310 | @ <a href="setup_editcss">CSS</a>, |
| 1311 | @ <a href="setup_header">Header</a>, |
| 1312 | @ <a href="setup_footer">Footer</a>, and |
| 1313 | @ <a href="setup_logo">Logo</a> that determines the look and feel |
| 1314 |
+20
-3
| --- src/timeline.c | ||
| +++ src/timeline.c | ||
| @@ -179,11 +179,11 @@ | ||
| 179 | 179 | ** 2. Date/Time |
| 180 | 180 | ** 3. Comment string |
| 181 | 181 | ** 4. User |
| 182 | 182 | ** 5. True if is a leaf |
| 183 | 183 | ** 6. background color |
| 184 | -** 7. type ("ci", "w", "t", "e", "div") | |
| 184 | +** 7. type ("ci", "w", "t", "e", "g", "div") | |
| 185 | 185 | ** 8. list of symbolic tags. |
| 186 | 186 | ** 9. tagid for ticket or wiki or event |
| 187 | 187 | ** 10. Short comment to user for repeated tickets and wiki |
| 188 | 188 | */ |
| 189 | 189 | void www_print_timeline( |
| @@ -316,10 +316,13 @@ | ||
| 316 | 316 | @</td> |
| 317 | 317 | if( zBgClr && zBgClr[0] ){ |
| 318 | 318 | @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> |
| 319 | 319 | }else{ |
| 320 | 320 | @ <td class="timelineTableCell"> |
| 321 | + } | |
| 322 | + if( pGraph && zType[0]!='c' ){ | |
| 323 | + @ • | |
| 321 | 324 | } |
| 322 | 325 | if( zType[0]=='c' ){ |
| 323 | 326 | hyperlink_to_uuid(zUuid); |
| 324 | 327 | if( isLeaf ){ |
| 325 | 328 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -892,15 +895,23 @@ | ||
| 892 | 895 | int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */ |
| 893 | 896 | int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ |
| 894 | 897 | int noMerge = P("nomerge")!=0; /* Do not follow merge links */ |
| 895 | 898 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 896 | 899 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 900 | + int pd_rid; | |
| 897 | 901 | |
| 898 | 902 | /* To view the timeline, must have permission to read project data. |
| 899 | 903 | */ |
| 904 | + pd_rid = name_to_typed_rid(P("dp"),"ci"); | |
| 905 | + if( pd_rid ){ | |
| 906 | + p_rid = d_rid = pd_rid; | |
| 907 | + } | |
| 900 | 908 | login_check_credentials(); |
| 901 | - if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ login_needed(); return; } | |
| 909 | + if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ | |
| 910 | + login_needed(); | |
| 911 | + return; | |
| 912 | + } | |
| 902 | 913 | if( zTagName && g.perm.Read ){ |
| 903 | 914 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName); |
| 904 | 915 | zThisTag = zTagName; |
| 905 | 916 | }else if( zBrName && g.perm.Read ){ |
| 906 | 917 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName); |
| @@ -1075,19 +1086,20 @@ | ||
| 1075 | 1086 | } |
| 1076 | 1087 | if( (zType[0]=='w' && !g.perm.RdWiki) |
| 1077 | 1088 | || (zType[0]=='t' && !g.perm.RdTkt) |
| 1078 | 1089 | || (zType[0]=='e' && !g.perm.RdWiki) |
| 1079 | 1090 | || (zType[0]=='c' && !g.perm.Read) |
| 1091 | + || (zType[0]=='g' && !g.perm.Read) | |
| 1080 | 1092 | ){ |
| 1081 | 1093 | zType = "all"; |
| 1082 | 1094 | } |
| 1083 | 1095 | if( zType[0]=='a' ){ |
| 1084 | 1096 | if( !g.perm.Read || !g.perm.RdWiki || !g.perm.RdTkt ){ |
| 1085 | 1097 | char cSep = '('; |
| 1086 | 1098 | blob_appendf(&sql, " AND event.type IN "); |
| 1087 | 1099 | if( g.perm.Read ){ |
| 1088 | - blob_appendf(&sql, "%c'ci'", cSep); | |
| 1100 | + blob_appendf(&sql, "%c'ci','g'", cSep); | |
| 1089 | 1101 | cSep = ','; |
| 1090 | 1102 | } |
| 1091 | 1103 | if( g.perm.RdWiki ){ |
| 1092 | 1104 | blob_appendf(&sql, "%c'w','e'", cSep); |
| 1093 | 1105 | cSep = ','; |
| @@ -1107,10 +1119,12 @@ | ||
| 1107 | 1119 | zEType = "wiki edit"; |
| 1108 | 1120 | }else if( zType[0]=='t' ){ |
| 1109 | 1121 | zEType = "ticket change"; |
| 1110 | 1122 | }else if( zType[0]=='e' ){ |
| 1111 | 1123 | zEType = "event"; |
| 1124 | + }else if( zType[0]=='g' ){ | |
| 1125 | + zEType = "tag"; | |
| 1112 | 1126 | } |
| 1113 | 1127 | } |
| 1114 | 1128 | if( zUser ){ |
| 1115 | 1129 | blob_appendf(&sql, " AND (event.user=%Q OR event.euser=%Q)", |
| 1116 | 1130 | zUser, zUser); |
| @@ -1226,10 +1240,13 @@ | ||
| 1226 | 1240 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 1227 | 1241 | } |
| 1228 | 1242 | if( zType[0]!='e' && g.perm.RdWiki ){ |
| 1229 | 1243 | timeline_submenu(&url, "Events Only", "y", "e", 0); |
| 1230 | 1244 | } |
| 1245 | + if( zType[0]!='g' && g.perm.Read ){ | |
| 1246 | + timeline_submenu(&url, "Tags Only", "y", "g", 0); | |
| 1247 | + } | |
| 1231 | 1248 | } |
| 1232 | 1249 | if( nEntry>20 ){ |
| 1233 | 1250 | timeline_submenu(&url, "20 Entries", "n", "20", 0); |
| 1234 | 1251 | } |
| 1235 | 1252 | if( nEntry<200 ){ |
| 1236 | 1253 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -179,11 +179,11 @@ | |
| 179 | ** 2. Date/Time |
| 180 | ** 3. Comment string |
| 181 | ** 4. User |
| 182 | ** 5. True if is a leaf |
| 183 | ** 6. background color |
| 184 | ** 7. type ("ci", "w", "t", "e", "div") |
| 185 | ** 8. list of symbolic tags. |
| 186 | ** 9. tagid for ticket or wiki or event |
| 187 | ** 10. Short comment to user for repeated tickets and wiki |
| 188 | */ |
| 189 | void www_print_timeline( |
| @@ -316,10 +316,13 @@ | |
| 316 | @</td> |
| 317 | if( zBgClr && zBgClr[0] ){ |
| 318 | @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> |
| 319 | }else{ |
| 320 | @ <td class="timelineTableCell"> |
| 321 | } |
| 322 | if( zType[0]=='c' ){ |
| 323 | hyperlink_to_uuid(zUuid); |
| 324 | if( isLeaf ){ |
| 325 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -892,15 +895,23 @@ | |
| 892 | int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */ |
| 893 | int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ |
| 894 | int noMerge = P("nomerge")!=0; /* Do not follow merge links */ |
| 895 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 896 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 897 | |
| 898 | /* To view the timeline, must have permission to read project data. |
| 899 | */ |
| 900 | login_check_credentials(); |
| 901 | if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ login_needed(); return; } |
| 902 | if( zTagName && g.perm.Read ){ |
| 903 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName); |
| 904 | zThisTag = zTagName; |
| 905 | }else if( zBrName && g.perm.Read ){ |
| 906 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName); |
| @@ -1075,19 +1086,20 @@ | |
| 1075 | } |
| 1076 | if( (zType[0]=='w' && !g.perm.RdWiki) |
| 1077 | || (zType[0]=='t' && !g.perm.RdTkt) |
| 1078 | || (zType[0]=='e' && !g.perm.RdWiki) |
| 1079 | || (zType[0]=='c' && !g.perm.Read) |
| 1080 | ){ |
| 1081 | zType = "all"; |
| 1082 | } |
| 1083 | if( zType[0]=='a' ){ |
| 1084 | if( !g.perm.Read || !g.perm.RdWiki || !g.perm.RdTkt ){ |
| 1085 | char cSep = '('; |
| 1086 | blob_appendf(&sql, " AND event.type IN "); |
| 1087 | if( g.perm.Read ){ |
| 1088 | blob_appendf(&sql, "%c'ci'", cSep); |
| 1089 | cSep = ','; |
| 1090 | } |
| 1091 | if( g.perm.RdWiki ){ |
| 1092 | blob_appendf(&sql, "%c'w','e'", cSep); |
| 1093 | cSep = ','; |
| @@ -1107,10 +1119,12 @@ | |
| 1107 | zEType = "wiki edit"; |
| 1108 | }else if( zType[0]=='t' ){ |
| 1109 | zEType = "ticket change"; |
| 1110 | }else if( zType[0]=='e' ){ |
| 1111 | zEType = "event"; |
| 1112 | } |
| 1113 | } |
| 1114 | if( zUser ){ |
| 1115 | blob_appendf(&sql, " AND (event.user=%Q OR event.euser=%Q)", |
| 1116 | zUser, zUser); |
| @@ -1226,10 +1240,13 @@ | |
| 1226 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 1227 | } |
| 1228 | if( zType[0]!='e' && g.perm.RdWiki ){ |
| 1229 | timeline_submenu(&url, "Events Only", "y", "e", 0); |
| 1230 | } |
| 1231 | } |
| 1232 | if( nEntry>20 ){ |
| 1233 | timeline_submenu(&url, "20 Entries", "n", "20", 0); |
| 1234 | } |
| 1235 | if( nEntry<200 ){ |
| 1236 |
| --- src/timeline.c | |
| +++ src/timeline.c | |
| @@ -179,11 +179,11 @@ | |
| 179 | ** 2. Date/Time |
| 180 | ** 3. Comment string |
| 181 | ** 4. User |
| 182 | ** 5. True if is a leaf |
| 183 | ** 6. background color |
| 184 | ** 7. type ("ci", "w", "t", "e", "g", "div") |
| 185 | ** 8. list of symbolic tags. |
| 186 | ** 9. tagid for ticket or wiki or event |
| 187 | ** 10. Short comment to user for repeated tickets and wiki |
| 188 | */ |
| 189 | void www_print_timeline( |
| @@ -316,10 +316,13 @@ | |
| 316 | @</td> |
| 317 | if( zBgClr && zBgClr[0] ){ |
| 318 | @ <td class="timelineTableCell" style="background-color: %h(zBgClr);"> |
| 319 | }else{ |
| 320 | @ <td class="timelineTableCell"> |
| 321 | } |
| 322 | if( pGraph && zType[0]!='c' ){ |
| 323 | @ • |
| 324 | } |
| 325 | if( zType[0]=='c' ){ |
| 326 | hyperlink_to_uuid(zUuid); |
| 327 | if( isLeaf ){ |
| 328 | if( db_exists("SELECT 1 FROM tagxref" |
| @@ -892,15 +895,23 @@ | |
| 895 | int from_rid = name_to_typed_rid(P("from"),"ci"); /* from= for paths */ |
| 896 | int to_rid = name_to_typed_rid(P("to"),"ci"); /* to= for path timelines */ |
| 897 | int noMerge = P("nomerge")!=0; /* Do not follow merge links */ |
| 898 | int me_rid = name_to_typed_rid(P("me"),"ci"); /* me= for common ancestory */ |
| 899 | int you_rid = name_to_typed_rid(P("you"),"ci");/* you= for common ancst */ |
| 900 | int pd_rid; |
| 901 | |
| 902 | /* To view the timeline, must have permission to read project data. |
| 903 | */ |
| 904 | pd_rid = name_to_typed_rid(P("dp"),"ci"); |
| 905 | if( pd_rid ){ |
| 906 | p_rid = d_rid = pd_rid; |
| 907 | } |
| 908 | login_check_credentials(); |
| 909 | if( !g.perm.Read && !g.perm.RdTkt && !g.perm.RdWiki ){ |
| 910 | login_needed(); |
| 911 | return; |
| 912 | } |
| 913 | if( zTagName && g.perm.Read ){ |
| 914 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'", zTagName); |
| 915 | zThisTag = zTagName; |
| 916 | }else if( zBrName && g.perm.Read ){ |
| 917 | tagid = db_int(0, "SELECT tagid FROM tag WHERE tagname='sym-%q'",zBrName); |
| @@ -1075,19 +1086,20 @@ | |
| 1086 | } |
| 1087 | if( (zType[0]=='w' && !g.perm.RdWiki) |
| 1088 | || (zType[0]=='t' && !g.perm.RdTkt) |
| 1089 | || (zType[0]=='e' && !g.perm.RdWiki) |
| 1090 | || (zType[0]=='c' && !g.perm.Read) |
| 1091 | || (zType[0]=='g' && !g.perm.Read) |
| 1092 | ){ |
| 1093 | zType = "all"; |
| 1094 | } |
| 1095 | if( zType[0]=='a' ){ |
| 1096 | if( !g.perm.Read || !g.perm.RdWiki || !g.perm.RdTkt ){ |
| 1097 | char cSep = '('; |
| 1098 | blob_appendf(&sql, " AND event.type IN "); |
| 1099 | if( g.perm.Read ){ |
| 1100 | blob_appendf(&sql, "%c'ci','g'", cSep); |
| 1101 | cSep = ','; |
| 1102 | } |
| 1103 | if( g.perm.RdWiki ){ |
| 1104 | blob_appendf(&sql, "%c'w','e'", cSep); |
| 1105 | cSep = ','; |
| @@ -1107,10 +1119,12 @@ | |
| 1119 | zEType = "wiki edit"; |
| 1120 | }else if( zType[0]=='t' ){ |
| 1121 | zEType = "ticket change"; |
| 1122 | }else if( zType[0]=='e' ){ |
| 1123 | zEType = "event"; |
| 1124 | }else if( zType[0]=='g' ){ |
| 1125 | zEType = "tag"; |
| 1126 | } |
| 1127 | } |
| 1128 | if( zUser ){ |
| 1129 | blob_appendf(&sql, " AND (event.user=%Q OR event.euser=%Q)", |
| 1130 | zUser, zUser); |
| @@ -1226,10 +1240,13 @@ | |
| 1240 | timeline_submenu(&url, "Tickets Only", "y", "t", 0); |
| 1241 | } |
| 1242 | if( zType[0]!='e' && g.perm.RdWiki ){ |
| 1243 | timeline_submenu(&url, "Events Only", "y", "e", 0); |
| 1244 | } |
| 1245 | if( zType[0]!='g' && g.perm.Read ){ |
| 1246 | timeline_submenu(&url, "Tags Only", "y", "g", 0); |
| 1247 | } |
| 1248 | } |
| 1249 | if( nEntry>20 ){ |
| 1250 | timeline_submenu(&url, "20 Entries", "n", "20", 0); |
| 1251 | } |
| 1252 | if( nEntry<200 ){ |
| 1253 |
-2
| --- src/tkt.c | ||
| +++ src/tkt.c | ||
| @@ -170,11 +170,10 @@ | ||
| 170 | 170 | */ |
| 171 | 171 | int ticket_insert(const Manifest *p, int createFlag, int rid){ |
| 172 | 172 | Blob sql; |
| 173 | 173 | Stmt q; |
| 174 | 174 | int i; |
| 175 | - const char *zSep; | |
| 176 | 175 | int rc = 0; |
| 177 | 176 | |
| 178 | 177 | getAllTicketFields(); |
| 179 | 178 | if( createFlag ){ |
| 180 | 179 | db_multi_exec("INSERT OR IGNORE INTO ticket(tkt_uuid, tkt_mtime) " |
| @@ -181,11 +180,10 @@ | ||
| 181 | 180 | "VALUES(%Q, 0)", p->zTicketUuid); |
| 182 | 181 | rc = db_changes(); |
| 183 | 182 | } |
| 184 | 183 | blob_zero(&sql); |
| 185 | 184 | blob_appendf(&sql, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); |
| 186 | - zSep = "SET"; | |
| 187 | 185 | for(i=0; i<p->nField; i++){ |
| 188 | 186 | const char *zName = p->aField[i].zName; |
| 189 | 187 | if( zName[0]=='+' ){ |
| 190 | 188 | zName++; |
| 191 | 189 | if( fieldId(zName)<0 ) continue; |
| 192 | 190 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -170,11 +170,10 @@ | |
| 170 | */ |
| 171 | int ticket_insert(const Manifest *p, int createFlag, int rid){ |
| 172 | Blob sql; |
| 173 | Stmt q; |
| 174 | int i; |
| 175 | const char *zSep; |
| 176 | int rc = 0; |
| 177 | |
| 178 | getAllTicketFields(); |
| 179 | if( createFlag ){ |
| 180 | db_multi_exec("INSERT OR IGNORE INTO ticket(tkt_uuid, tkt_mtime) " |
| @@ -181,11 +180,10 @@ | |
| 181 | "VALUES(%Q, 0)", p->zTicketUuid); |
| 182 | rc = db_changes(); |
| 183 | } |
| 184 | blob_zero(&sql); |
| 185 | blob_appendf(&sql, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); |
| 186 | zSep = "SET"; |
| 187 | for(i=0; i<p->nField; i++){ |
| 188 | const char *zName = p->aField[i].zName; |
| 189 | if( zName[0]=='+' ){ |
| 190 | zName++; |
| 191 | if( fieldId(zName)<0 ) continue; |
| 192 |
| --- src/tkt.c | |
| +++ src/tkt.c | |
| @@ -170,11 +170,10 @@ | |
| 170 | */ |
| 171 | int ticket_insert(const Manifest *p, int createFlag, int rid){ |
| 172 | Blob sql; |
| 173 | Stmt q; |
| 174 | int i; |
| 175 | int rc = 0; |
| 176 | |
| 177 | getAllTicketFields(); |
| 178 | if( createFlag ){ |
| 179 | db_multi_exec("INSERT OR IGNORE INTO ticket(tkt_uuid, tkt_mtime) " |
| @@ -181,11 +180,10 @@ | |
| 180 | "VALUES(%Q, 0)", p->zTicketUuid); |
| 181 | rc = db_changes(); |
| 182 | } |
| 183 | blob_zero(&sql); |
| 184 | blob_appendf(&sql, "UPDATE OR REPLACE ticket SET tkt_mtime=:mtime"); |
| 185 | for(i=0; i<p->nField; i++){ |
| 186 | const char *zName = p->aField[i].zName; |
| 187 | if( zName[0]=='+' ){ |
| 188 | zName++; |
| 189 | if( fieldId(zName)<0 ) continue; |
| 190 |
+1
-3
| --- src/wikiformat.c | ||
| +++ src/wikiformat.c | ||
| @@ -1708,20 +1708,18 @@ | ||
| 1708 | 1708 | /* Enter <verbatim> processing. With verbatim enabled, all other |
| 1709 | 1709 | ** markup other than the corresponding end-tag with the same ID is |
| 1710 | 1710 | ** ignored. |
| 1711 | 1711 | */ |
| 1712 | 1712 | if( markup.iCode==MARKUP_VERBATIM ){ |
| 1713 | - int vAttrIdx, vAttrDidAppend=0; | |
| 1713 | + int vAttrIdx; | |
| 1714 | 1714 | renderer.zVerbatimId = 0; |
| 1715 | 1715 | renderer.inVerbatim = 1; |
| 1716 | 1716 | renderer.preVerbState = renderer.state; |
| 1717 | 1717 | renderer.state &= ~ALLOW_WIKI; |
| 1718 | 1718 | for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){ |
| 1719 | 1719 | if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){ |
| 1720 | 1720 | renderer.zVerbatimId = markup.aAttr[0].zValue; |
| 1721 | - }else if( markup.aAttr[vAttrIdx].iACode == ATTR_TYPE ){ | |
| 1722 | - vAttrDidAppend=1; | |
| 1723 | 1721 | } |
| 1724 | 1722 | } |
| 1725 | 1723 | renderer.wantAutoParagraph = 0; |
| 1726 | 1724 | } |
| 1727 | 1725 | |
| 1728 | 1726 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -1708,20 +1708,18 @@ | |
| 1708 | /* Enter <verbatim> processing. With verbatim enabled, all other |
| 1709 | ** markup other than the corresponding end-tag with the same ID is |
| 1710 | ** ignored. |
| 1711 | */ |
| 1712 | if( markup.iCode==MARKUP_VERBATIM ){ |
| 1713 | int vAttrIdx, vAttrDidAppend=0; |
| 1714 | renderer.zVerbatimId = 0; |
| 1715 | renderer.inVerbatim = 1; |
| 1716 | renderer.preVerbState = renderer.state; |
| 1717 | renderer.state &= ~ALLOW_WIKI; |
| 1718 | for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){ |
| 1719 | if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){ |
| 1720 | renderer.zVerbatimId = markup.aAttr[0].zValue; |
| 1721 | }else if( markup.aAttr[vAttrIdx].iACode == ATTR_TYPE ){ |
| 1722 | vAttrDidAppend=1; |
| 1723 | } |
| 1724 | } |
| 1725 | renderer.wantAutoParagraph = 0; |
| 1726 | } |
| 1727 | |
| 1728 |
| --- src/wikiformat.c | |
| +++ src/wikiformat.c | |
| @@ -1708,20 +1708,18 @@ | |
| 1708 | /* Enter <verbatim> processing. With verbatim enabled, all other |
| 1709 | ** markup other than the corresponding end-tag with the same ID is |
| 1710 | ** ignored. |
| 1711 | */ |
| 1712 | if( markup.iCode==MARKUP_VERBATIM ){ |
| 1713 | int vAttrIdx; |
| 1714 | renderer.zVerbatimId = 0; |
| 1715 | renderer.inVerbatim = 1; |
| 1716 | renderer.preVerbState = renderer.state; |
| 1717 | renderer.state &= ~ALLOW_WIKI; |
| 1718 | for (vAttrIdx = 0; vAttrIdx < markup.nAttr; vAttrIdx++){ |
| 1719 | if( markup.aAttr[vAttrIdx].iACode == ATTR_ID ){ |
| 1720 | renderer.zVerbatimId = markup.aAttr[0].zValue; |
| 1721 | } |
| 1722 | } |
| 1723 | renderer.wantAutoParagraph = 0; |
| 1724 | } |
| 1725 | |
| 1726 |
+1
-4
| --- src/xfer.c | ||
| +++ src/xfer.c | ||
| @@ -1198,20 +1198,19 @@ | ||
| 1198 | 1198 | ** |
| 1199 | 1199 | ** gdb fossil |
| 1200 | 1200 | ** r test-xfer out.txt |
| 1201 | 1201 | */ |
| 1202 | 1202 | void cmd_test_xfer(void){ |
| 1203 | - int notUsed; | |
| 1204 | 1203 | db_find_and_open_repository(0,0); |
| 1205 | 1204 | if( g.argc!=2 && g.argc!=3 ){ |
| 1206 | 1205 | usage("?MESSAGEFILE?"); |
| 1207 | 1206 | } |
| 1208 | 1207 | blob_zero(&g.cgiIn); |
| 1209 | 1208 | blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); |
| 1210 | 1209 | disableLogin = 1; |
| 1211 | 1210 | page_xfer(); |
| 1212 | - fossil_print("%s\n", cgi_extract_content(¬Used)); | |
| 1211 | + fossil_print("%s\n", cgi_extract_content()); | |
| 1213 | 1212 | } |
| 1214 | 1213 | |
| 1215 | 1214 | /* |
| 1216 | 1215 | ** Format strings for progress reporting. |
| 1217 | 1216 | */ |
| @@ -1238,11 +1237,10 @@ | ||
| 1238 | 1237 | int go = 1; /* Loop until zero */ |
| 1239 | 1238 | int nCardSent = 0; /* Number of cards sent */ |
| 1240 | 1239 | int nCardRcvd = 0; /* Number of cards received */ |
| 1241 | 1240 | int nCycle = 0; /* Number of round trips to the server */ |
| 1242 | 1241 | int size; /* Size of a config value */ |
| 1243 | - int nFileSend = 0; | |
| 1244 | 1242 | int origConfigRcvMask; /* Original value of configRcvMask */ |
| 1245 | 1243 | int nFileRecv; /* Number of files received */ |
| 1246 | 1244 | int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ |
| 1247 | 1245 | const char *zCookie; /* Server cookie */ |
| 1248 | 1246 | i64 nSent, nRcvd; /* Bytes sent and received (after compression) */ |
| @@ -1380,11 +1378,10 @@ | ||
| 1380 | 1378 | zRandomness = db_text(0, "SELECT hex(randomblob(20))"); |
| 1381 | 1379 | blob_appendf(&send, "# %s\n", zRandomness); |
| 1382 | 1380 | free(zRandomness); |
| 1383 | 1381 | |
| 1384 | 1382 | /* Exchange messages with the server */ |
| 1385 | - nFileSend = xfer.nFileSent + xfer.nDeltaSent; | |
| 1386 | 1383 | fossil_print(zValueFormat, "Sent:", |
| 1387 | 1384 | blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, |
| 1388 | 1385 | xfer.nFileSent, xfer.nDeltaSent); |
| 1389 | 1386 | nCardSent = 0; |
| 1390 | 1387 | nCardRcvd = 0; |
| 1391 | 1388 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -1198,20 +1198,19 @@ | |
| 1198 | ** |
| 1199 | ** gdb fossil |
| 1200 | ** r test-xfer out.txt |
| 1201 | */ |
| 1202 | void cmd_test_xfer(void){ |
| 1203 | int notUsed; |
| 1204 | db_find_and_open_repository(0,0); |
| 1205 | if( g.argc!=2 && g.argc!=3 ){ |
| 1206 | usage("?MESSAGEFILE?"); |
| 1207 | } |
| 1208 | blob_zero(&g.cgiIn); |
| 1209 | blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); |
| 1210 | disableLogin = 1; |
| 1211 | page_xfer(); |
| 1212 | fossil_print("%s\n", cgi_extract_content(¬Used)); |
| 1213 | } |
| 1214 | |
| 1215 | /* |
| 1216 | ** Format strings for progress reporting. |
| 1217 | */ |
| @@ -1238,11 +1237,10 @@ | |
| 1238 | int go = 1; /* Loop until zero */ |
| 1239 | int nCardSent = 0; /* Number of cards sent */ |
| 1240 | int nCardRcvd = 0; /* Number of cards received */ |
| 1241 | int nCycle = 0; /* Number of round trips to the server */ |
| 1242 | int size; /* Size of a config value */ |
| 1243 | int nFileSend = 0; |
| 1244 | int origConfigRcvMask; /* Original value of configRcvMask */ |
| 1245 | int nFileRecv; /* Number of files received */ |
| 1246 | int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ |
| 1247 | const char *zCookie; /* Server cookie */ |
| 1248 | i64 nSent, nRcvd; /* Bytes sent and received (after compression) */ |
| @@ -1380,11 +1378,10 @@ | |
| 1380 | zRandomness = db_text(0, "SELECT hex(randomblob(20))"); |
| 1381 | blob_appendf(&send, "# %s\n", zRandomness); |
| 1382 | free(zRandomness); |
| 1383 | |
| 1384 | /* Exchange messages with the server */ |
| 1385 | nFileSend = xfer.nFileSent + xfer.nDeltaSent; |
| 1386 | fossil_print(zValueFormat, "Sent:", |
| 1387 | blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, |
| 1388 | xfer.nFileSent, xfer.nDeltaSent); |
| 1389 | nCardSent = 0; |
| 1390 | nCardRcvd = 0; |
| 1391 |
| --- src/xfer.c | |
| +++ src/xfer.c | |
| @@ -1198,20 +1198,19 @@ | |
| 1198 | ** |
| 1199 | ** gdb fossil |
| 1200 | ** r test-xfer out.txt |
| 1201 | */ |
| 1202 | void cmd_test_xfer(void){ |
| 1203 | db_find_and_open_repository(0,0); |
| 1204 | if( g.argc!=2 && g.argc!=3 ){ |
| 1205 | usage("?MESSAGEFILE?"); |
| 1206 | } |
| 1207 | blob_zero(&g.cgiIn); |
| 1208 | blob_read_from_file(&g.cgiIn, g.argc==2 ? "-" : g.argv[2]); |
| 1209 | disableLogin = 1; |
| 1210 | page_xfer(); |
| 1211 | fossil_print("%s\n", cgi_extract_content()); |
| 1212 | } |
| 1213 | |
| 1214 | /* |
| 1215 | ** Format strings for progress reporting. |
| 1216 | */ |
| @@ -1238,11 +1237,10 @@ | |
| 1237 | int go = 1; /* Loop until zero */ |
| 1238 | int nCardSent = 0; /* Number of cards sent */ |
| 1239 | int nCardRcvd = 0; /* Number of cards received */ |
| 1240 | int nCycle = 0; /* Number of round trips to the server */ |
| 1241 | int size; /* Size of a config value */ |
| 1242 | int origConfigRcvMask; /* Original value of configRcvMask */ |
| 1243 | int nFileRecv; /* Number of files received */ |
| 1244 | int mxPhantomReq = 200; /* Max number of phantoms to request per comm */ |
| 1245 | const char *zCookie; /* Server cookie */ |
| 1246 | i64 nSent, nRcvd; /* Bytes sent and received (after compression) */ |
| @@ -1380,11 +1378,10 @@ | |
| 1378 | zRandomness = db_text(0, "SELECT hex(randomblob(20))"); |
| 1379 | blob_appendf(&send, "# %s\n", zRandomness); |
| 1380 | free(zRandomness); |
| 1381 | |
| 1382 | /* Exchange messages with the server */ |
| 1383 | fossil_print(zValueFormat, "Sent:", |
| 1384 | blob_size(&send), nCardSent+xfer.nGimmeSent+xfer.nIGotSent, |
| 1385 | xfer.nFileSent, xfer.nDeltaSent); |
| 1386 | nCardSent = 0; |
| 1387 | nCardRcvd = 0; |
| 1388 |
+40
-29
| --- www/fossil-v-git.wiki | ||
| +++ www/fossil-v-git.wiki | ||
| @@ -19,11 +19,11 @@ | ||
| 19 | 19 | <blockquote><center><table border=1 cellpadding=5> |
| 20 | 20 | <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> |
| 21 | 21 | <tr><td>File versioning only</td> |
| 22 | 22 | <td>Versioning, Tickets, Wiki, and Blog/News</td></tr> |
| 23 | 23 | <tr><td>Sharding</td><td>Replicating</td></tr> |
| 24 | -<tr><td>Huge community</td><td>Road less traveled</td></tr> | |
| 24 | +<tr><td>Developer branches</td><td>Feature branches</td></tr> | |
| 25 | 25 | <tr><td>Complex</td><td>Intuitive</td></tr> |
| 26 | 26 | <tr><td>Separate web tools</td><td>Integrated Web interface</td></tr> |
| 27 | 27 | <tr><td>Lots of little tools</td><td>Single executable</td></tr> |
| 28 | 28 | <tr><td>Pile-of-files repository</td><td>Single file repository</td></tr> |
| 29 | 29 | <tr><td>Uses "<tt>rebase</tt>"</td><td>Immutable</td></tr> |
| @@ -79,38 +79,49 @@ | ||
| 79 | 79 | The [concepts.wiki#workflow | autosync] mode of Fossil makes it easy |
| 80 | 80 | for multiple developers to work on a single branch and maintain |
| 81 | 81 | linear development on that branch and avoid needless forking |
| 82 | 82 | and merging. |
| 83 | 83 | |
| 84 | -<h3>3.3 Community</h3> | |
| 85 | - | |
| 86 | -Git has a huge user community. If following the herd and being | |
| 87 | -like everybody else is important to you, then you should choose Git. | |
| 88 | - | |
| 89 | -Fossil is clearly the "road less traveled": | |
| 90 | - | |
| 91 | -<blockquote> | |
| 92 | -Two roads diverged in a wood, and I —<br> | |
| 93 | -I took the one less traveled by,<br> | |
| 94 | -And that has made all the difference.<br> | |
| 95 | - | |
| 96 | -<small>- Robert Frost, <i>The Road Not Taken</i>, 1916</small> | |
| 97 | -</blockquote> | |
| 98 | -</i></blockquote> | |
| 99 | - | |
| 100 | -Among the advantages of Git's huge user community are that new team | |
| 101 | -members may already be familiar with Git's operation and hence can | |
| 102 | -bypass the VCS learning curve. Also, if you need an add-on tool or | |
| 103 | -script of some kind, a Google search will likely turn up a suitable | |
| 104 | -tool that you can just download and use. A huge community also means | |
| 105 | -that somebody else has likely already encountered and fixed the bugs | |
| 106 | -so that Git will work for you and your project as advertised. | |
| 107 | - | |
| 108 | -Among the advantages of the "road less traveled" is that your particular | |
| 109 | -project will be bigger percentage of the total user base, and is thus | |
| 110 | -more likely to receive personal attention from the Fossil maintainers | |
| 111 | -if you do encounter problems. | |
| 84 | +<h3>3.3 Branches</h3> | |
| 85 | + | |
| 86 | +Git (and especially GitHub) encourages a workflow where each developer | |
| 87 | +has his or her own branch or branches. Developers then send "pull requests" | |
| 88 | +to have their changes be merged into "official" branches by integrators. | |
| 89 | +For example, the Linux kernel team has a hierarchy of integrators with | |
| 90 | +Linus Torvalds at the root. Individual developers each have their own | |
| 91 | +private branches of the source tree into which they make their own changes. | |
| 92 | +They then encourage first-tier integrators to pull those changes. The | |
| 93 | +first-tier integrators merge together changes from multiple contributors | |
| 94 | +then try to get second-tier integrators to pull their branches. The | |
| 95 | +changes merge up the the hierarchy until (hopefully) they are pulled into | |
| 96 | +"Linus's branch", at which time they become part of the "official" Linux. | |
| 97 | + | |
| 98 | +In Git, each branch is "owned" by the person who creates it and works | |
| 99 | +on it. The owner might pull changes from others, but the owner is always | |
| 100 | +in control of the branch. Branches are developer-centric. | |
| 101 | + | |
| 102 | +Fossil, on the other hand, encourages a workflow where branches are | |
| 103 | +associated with features or releases, not individual developers. | |
| 104 | +All developers share all branches in common, and two | |
| 105 | +or more developers can and often do intersperse commits onto the same branch. | |
| 106 | +Branches do not belong to individuals. All branches are read/write | |
| 107 | +accessible to all developers at all times. There is no need | |
| 108 | +for integrators to merge together changes from various independent | |
| 109 | +developers. Instead, all of the developers work together cooperatively | |
| 110 | +and the changes stay integrated naturally. | |
| 111 | + | |
| 112 | +So to a first approximation, branches in Git are developer-centric whereas | |
| 113 | +branches in Fossil are feature-centric. | |
| 114 | + | |
| 115 | +The Git approach scales much better for large projects like the Linux | |
| 116 | +kernel with thousands of contributors who in many cases don't even know | |
| 117 | +each others names. The integrators serve a gatekeeper role to help keep | |
| 118 | +undesirable code out of the official Linux source tree. On the other hand, | |
| 119 | +not many projects are as big or as loosely organized as the Linux kernel. | |
| 120 | +Most project, have a small team of developers who all know each other | |
| 121 | +well and trust each other, and who enjoy working together collaboratively | |
| 122 | +without the overhead and hierarchy of integrators. | |
| 112 | 123 | |
| 113 | 124 | <h3>3.4 Complexity</h3> |
| 114 | 125 | |
| 115 | 126 | Git is a complex system. It can be tricky to use and requires a fair |
| 116 | 127 | amount of knowledge and experience to master. Fossil strives to be |
| 117 | 128 |
| --- www/fossil-v-git.wiki | |
| +++ www/fossil-v-git.wiki | |
| @@ -19,11 +19,11 @@ | |
| 19 | <blockquote><center><table border=1 cellpadding=5> |
| 20 | <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> |
| 21 | <tr><td>File versioning only</td> |
| 22 | <td>Versioning, Tickets, Wiki, and Blog/News</td></tr> |
| 23 | <tr><td>Sharding</td><td>Replicating</td></tr> |
| 24 | <tr><td>Huge community</td><td>Road less traveled</td></tr> |
| 25 | <tr><td>Complex</td><td>Intuitive</td></tr> |
| 26 | <tr><td>Separate web tools</td><td>Integrated Web interface</td></tr> |
| 27 | <tr><td>Lots of little tools</td><td>Single executable</td></tr> |
| 28 | <tr><td>Pile-of-files repository</td><td>Single file repository</td></tr> |
| 29 | <tr><td>Uses "<tt>rebase</tt>"</td><td>Immutable</td></tr> |
| @@ -79,38 +79,49 @@ | |
| 79 | The [concepts.wiki#workflow | autosync] mode of Fossil makes it easy |
| 80 | for multiple developers to work on a single branch and maintain |
| 81 | linear development on that branch and avoid needless forking |
| 82 | and merging. |
| 83 | |
| 84 | <h3>3.3 Community</h3> |
| 85 | |
| 86 | Git has a huge user community. If following the herd and being |
| 87 | like everybody else is important to you, then you should choose Git. |
| 88 | |
| 89 | Fossil is clearly the "road less traveled": |
| 90 | |
| 91 | <blockquote> |
| 92 | Two roads diverged in a wood, and I —<br> |
| 93 | I took the one less traveled by,<br> |
| 94 | And that has made all the difference.<br> |
| 95 | |
| 96 | <small>- Robert Frost, <i>The Road Not Taken</i>, 1916</small> |
| 97 | </blockquote> |
| 98 | </i></blockquote> |
| 99 | |
| 100 | Among the advantages of Git's huge user community are that new team |
| 101 | members may already be familiar with Git's operation and hence can |
| 102 | bypass the VCS learning curve. Also, if you need an add-on tool or |
| 103 | script of some kind, a Google search will likely turn up a suitable |
| 104 | tool that you can just download and use. A huge community also means |
| 105 | that somebody else has likely already encountered and fixed the bugs |
| 106 | so that Git will work for you and your project as advertised. |
| 107 | |
| 108 | Among the advantages of the "road less traveled" is that your particular |
| 109 | project will be bigger percentage of the total user base, and is thus |
| 110 | more likely to receive personal attention from the Fossil maintainers |
| 111 | if you do encounter problems. |
| 112 | |
| 113 | <h3>3.4 Complexity</h3> |
| 114 | |
| 115 | Git is a complex system. It can be tricky to use and requires a fair |
| 116 | amount of knowledge and experience to master. Fossil strives to be |
| 117 |
| --- www/fossil-v-git.wiki | |
| +++ www/fossil-v-git.wiki | |
| @@ -19,11 +19,11 @@ | |
| 19 | <blockquote><center><table border=1 cellpadding=5> |
| 20 | <tr><th width="50%">GIT</th><th width="50%">FOSSIL</th></tr> |
| 21 | <tr><td>File versioning only</td> |
| 22 | <td>Versioning, Tickets, Wiki, and Blog/News</td></tr> |
| 23 | <tr><td>Sharding</td><td>Replicating</td></tr> |
| 24 | <tr><td>Developer branches</td><td>Feature branches</td></tr> |
| 25 | <tr><td>Complex</td><td>Intuitive</td></tr> |
| 26 | <tr><td>Separate web tools</td><td>Integrated Web interface</td></tr> |
| 27 | <tr><td>Lots of little tools</td><td>Single executable</td></tr> |
| 28 | <tr><td>Pile-of-files repository</td><td>Single file repository</td></tr> |
| 29 | <tr><td>Uses "<tt>rebase</tt>"</td><td>Immutable</td></tr> |
| @@ -79,38 +79,49 @@ | |
| 79 | The [concepts.wiki#workflow | autosync] mode of Fossil makes it easy |
| 80 | for multiple developers to work on a single branch and maintain |
| 81 | linear development on that branch and avoid needless forking |
| 82 | and merging. |
| 83 | |
| 84 | <h3>3.3 Branches</h3> |
| 85 | |
| 86 | Git (and especially GitHub) encourages a workflow where each developer |
| 87 | has his or her own branch or branches. Developers then send "pull requests" |
| 88 | to have their changes be merged into "official" branches by integrators. |
| 89 | For example, the Linux kernel team has a hierarchy of integrators with |
| 90 | Linus Torvalds at the root. Individual developers each have their own |
| 91 | private branches of the source tree into which they make their own changes. |
| 92 | They then encourage first-tier integrators to pull those changes. The |
| 93 | first-tier integrators merge together changes from multiple contributors |
| 94 | then try to get second-tier integrators to pull their branches. The |
| 95 | changes merge up the the hierarchy until (hopefully) they are pulled into |
| 96 | "Linus's branch", at which time they become part of the "official" Linux. |
| 97 | |
| 98 | In Git, each branch is "owned" by the person who creates it and works |
| 99 | on it. The owner might pull changes from others, but the owner is always |
| 100 | in control of the branch. Branches are developer-centric. |
| 101 | |
| 102 | Fossil, on the other hand, encourages a workflow where branches are |
| 103 | associated with features or releases, not individual developers. |
| 104 | All developers share all branches in common, and two |
| 105 | or more developers can and often do intersperse commits onto the same branch. |
| 106 | Branches do not belong to individuals. All branches are read/write |
| 107 | accessible to all developers at all times. There is no need |
| 108 | for integrators to merge together changes from various independent |
| 109 | developers. Instead, all of the developers work together cooperatively |
| 110 | and the changes stay integrated naturally. |
| 111 | |
| 112 | So to a first approximation, branches in Git are developer-centric whereas |
| 113 | branches in Fossil are feature-centric. |
| 114 | |
| 115 | The Git approach scales much better for large projects like the Linux |
| 116 | kernel with thousands of contributors who in many cases don't even know |
| 117 | each others names. The integrators serve a gatekeeper role to help keep |
| 118 | undesirable code out of the official Linux source tree. On the other hand, |
| 119 | not many projects are as big or as loosely organized as the Linux kernel. |
| 120 | Most project, have a small team of developers who all know each other |
| 121 | well and trust each other, and who enjoy working together collaboratively |
| 122 | without the overhead and hierarchy of integrators. |
| 123 | |
| 124 | <h3>3.4 Complexity</h3> |
| 125 | |
| 126 | Git is a complex system. It can be tricky to use and requires a fair |
| 127 | amount of knowledge and experience to master. Fossil strives to be |
| 128 |