Fossil SCM

Fix timeline displays of the form "/timeline?from=UUID&ft=TAG" (using from= and ft=) so that the first link out of UUID is allowed to be a cherrypick.

drh 2026-07-10 12:06 UTC trunk
Commit 39efcebe0b280568a7226337167bec501f0f02f98d2550dd28928f319936ae35
2 files changed +19 +19 -3
+19
--- src/path.c
+++ src/path.c
@@ -168,10 +168,14 @@
168168
/*
169169
** Compute the shortest path from iFrom to iTo
170170
**
171171
** If directOnly is true, then use only the "primary" links from parent to
172172
** child. In other words, ignore merges.
173
+**
174
+** If oneWayOnly is 1, then only follow edges from parent to child.
175
+** If oneWayOnly is 2, that is like 1 except the first edge out of iFrom
176
+** is allowed to be cherrypick edge.
173177
**
174178
** Return a pointer to the beginning of the path (the iFrom node).
175179
** Elements of the path can be traversed by following the PathNode.u.pTo
176180
** pointer chain.
177181
**
@@ -217,10 +221,25 @@
217221
"UNION ALL "
218222
"SELECT pid, 0 FROM plink WHERE :back AND cid=:pid"
219223
);
220224
}
221225
bag_init(&seen);
226
+ if( oneWayOnly==2 ){
227
+ Stmt s2;
228
+ db_prepare(&s2,
229
+ "SELECT childid FROM cherrypick WHERE parentid=%d AND NOT isExclude",
230
+ iFrom
231
+ );
232
+ while( db_step(&s2)==SQLITE_ROW ){
233
+ int cid = db_column_int(&s2,0);
234
+ PathNode *pNew;
235
+ if( bag_find(&seen, cid) ) continue;
236
+ pNew = path_new_node(cid, path.pStart, 1);
237
+ if( pHidden && bag_find(pHidden,cid) ) pNew->isHidden = 1;
238
+ }
239
+ db_finalize(&s2);
240
+ }
222241
while( (p = pqueuex_extract_ptr(&path.pending))!=0 ){
223242
if( path_debug ){
224243
printf("PULL %s %g\n", path_rid_desc(p->rid), p->u.rCost);
225244
}
226245
if( p->rid==iTo ){
227246
--- src/path.c
+++ src/path.c
@@ -168,10 +168,14 @@
168 /*
169 ** Compute the shortest path from iFrom to iTo
170 **
171 ** If directOnly is true, then use only the "primary" links from parent to
172 ** child. In other words, ignore merges.
 
 
 
 
173 **
174 ** Return a pointer to the beginning of the path (the iFrom node).
175 ** Elements of the path can be traversed by following the PathNode.u.pTo
176 ** pointer chain.
177 **
@@ -217,10 +221,25 @@
217 "UNION ALL "
218 "SELECT pid, 0 FROM plink WHERE :back AND cid=:pid"
219 );
220 }
221 bag_init(&seen);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
222 while( (p = pqueuex_extract_ptr(&path.pending))!=0 ){
223 if( path_debug ){
224 printf("PULL %s %g\n", path_rid_desc(p->rid), p->u.rCost);
225 }
226 if( p->rid==iTo ){
227
--- src/path.c
+++ src/path.c
@@ -168,10 +168,14 @@
168 /*
169 ** Compute the shortest path from iFrom to iTo
170 **
171 ** If directOnly is true, then use only the "primary" links from parent to
172 ** child. In other words, ignore merges.
173 **
174 ** If oneWayOnly is 1, then only follow edges from parent to child.
175 ** If oneWayOnly is 2, that is like 1 except the first edge out of iFrom
176 ** is allowed to be cherrypick edge.
177 **
178 ** Return a pointer to the beginning of the path (the iFrom node).
179 ** Elements of the path can be traversed by following the PathNode.u.pTo
180 ** pointer chain.
181 **
@@ -217,10 +221,25 @@
221 "UNION ALL "
222 "SELECT pid, 0 FROM plink WHERE :back AND cid=:pid"
223 );
224 }
225 bag_init(&seen);
226 if( oneWayOnly==2 ){
227 Stmt s2;
228 db_prepare(&s2,
229 "SELECT childid FROM cherrypick WHERE parentid=%d AND NOT isExclude",
230 iFrom
231 );
232 while( db_step(&s2)==SQLITE_ROW ){
233 int cid = db_column_int(&s2,0);
234 PathNode *pNew;
235 if( bag_find(&seen, cid) ) continue;
236 pNew = path_new_node(cid, path.pStart, 1);
237 if( pHidden && bag_find(pHidden,cid) ) pNew->isHidden = 1;
238 }
239 db_finalize(&s2);
240 }
241 while( (p = pqueuex_extract_ptr(&path.pending))!=0 ){
242 if( path_debug ){
243 printf("PULL %s %g\n", path_rid_desc(p->rid), p->u.rCost);
244 }
245 if( p->rid==iTo ){
246
+19 -3
--- src/timeline.c
+++ src/timeline.c
@@ -1509,10 +1509,18 @@
15091509
** when moving either forwards are backwards in time from a
15101510
** particular starting point (iFrom). Return the rid of that
15111511
** first check-in. If there are no check-ins in the descendant
15121512
** or ancestor set of check-in iFrom that match the tag, then
15131513
** return 0.
1514
+**
1515
+** If looking fowards (if bForward is true) then the first link
1516
+** is allowed to be a cherrypick, but subsequent links must be
1517
+** either full merges or normal check-ins. The idea is that we
1518
+** are looking for the first use of the code in the iFrom check-in
1519
+** that has the zEnd tag. The first link is allowed to be a cherrypick
1520
+** because the code in question crosses that link, but the code does
1521
+** not cross any subsequent cherrypick.
15141522
*/
15151523
static int timeline_endpoint(
15161524
int iFrom, /* Starting point */
15171525
const char *zEnd, /* Tag we are searching for */
15181526
int bForward /* 1: forwards in time (descendants) 0: backwards */
@@ -1532,10 +1540,14 @@
15321540
if( tagId ){
15331541
db_prepare(&q,
15341542
"WITH RECURSIVE dx(id,mtime) AS ("
15351543
" SELECT %d, event.mtime FROM event WHERE objid=%d"
15361544
" UNION"
1545
+ " SELECT cp.childid, event.mtime FROM cherrypick AS cp, event"
1546
+ " WHERE cp.parentid=%d AND NOT cp.isExclude"
1547
+ " AND event.objid=cp.childid"
1548
+ " UNION"
15371549
" SELECT plink.cid, plink.mtime"
15381550
" FROM dx, plink"
15391551
" WHERE plink.pid=dx.id"
15401552
" AND plink.mtime<=(SELECT max(event.mtime) FROM tagxref, event"
15411553
" WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
@@ -1542,24 +1554,28 @@
15421554
" AND event.objid=tagxref.rid)"
15431555
" ORDER BY plink.mtime)"
15441556
"SELECT id FROM dx, tagxref"
15451557
" WHERE tagid=%d AND tagtype>0 AND rid=id"
15461558
" ORDER BY dx.mtime LIMIT 1",
1547
- iFrom, iFrom, tagId, tagId
1559
+ iFrom, iFrom, iFrom, tagId, tagId
15481560
);
15491561
}else{
15501562
db_prepare(&q,
15511563
"WITH RECURSIVE dx(id,mtime) AS ("
15521564
" SELECT %d, event.mtime FROM event WHERE objid=%d"
1565
+ " UNION"
1566
+ " SELECT cp.childid, event.mtime FROM cherrypick AS cp, event"
1567
+ " WHERE cp.parentid=%d AND NOT cp.isExclude"
1568
+ " AND event.objid=cp.childid"
15531569
" UNION"
15541570
" SELECT plink.cid, plink.mtime"
15551571
" FROM dx, plink"
15561572
" WHERE plink.pid=dx.id"
15571573
" AND plink.mtime<=(SELECT mtime FROM event WHERE objid=%d)"
15581574
" ORDER BY plink.mtime)"
15591575
"SELECT id FROM dx WHERE id=%d",
1560
- iFrom, iFrom, endId, endId
1576
+ iFrom, iFrom, iFrom, endId, endId
15611577
);
15621578
}
15631579
}else{
15641580
if( tagId ){
15651581
db_prepare(&q,
@@ -2221,11 +2237,11 @@
22212237
22222238
if( from_rid && to_rid ){
22232239
if( from_to_mode==0 ){
22242240
p = path_shortest(from_rid, to_rid, 0, 0, 0, cost);
22252241
}else if( from_to_mode==1 ){
2226
- p = path_shortest(from_rid, to_rid, 0, 1, 0, cost);
2242
+ p = path_shortest(from_rid, to_rid, 0, 2, 0, cost);
22272243
earlierRid = commonAncs = from_rid;
22282244
laterRid = to_rid;
22292245
}else{
22302246
p = path_shortest(to_rid, from_rid, 0, 1, 0, cost);
22312247
earlierRid = commonAncs = to_rid;
22322248
--- src/timeline.c
+++ src/timeline.c
@@ -1509,10 +1509,18 @@
1509 ** when moving either forwards are backwards in time from a
1510 ** particular starting point (iFrom). Return the rid of that
1511 ** first check-in. If there are no check-ins in the descendant
1512 ** or ancestor set of check-in iFrom that match the tag, then
1513 ** return 0.
 
 
 
 
 
 
 
 
1514 */
1515 static int timeline_endpoint(
1516 int iFrom, /* Starting point */
1517 const char *zEnd, /* Tag we are searching for */
1518 int bForward /* 1: forwards in time (descendants) 0: backwards */
@@ -1532,10 +1540,14 @@
1532 if( tagId ){
1533 db_prepare(&q,
1534 "WITH RECURSIVE dx(id,mtime) AS ("
1535 " SELECT %d, event.mtime FROM event WHERE objid=%d"
1536 " UNION"
 
 
 
 
1537 " SELECT plink.cid, plink.mtime"
1538 " FROM dx, plink"
1539 " WHERE plink.pid=dx.id"
1540 " AND plink.mtime<=(SELECT max(event.mtime) FROM tagxref, event"
1541 " WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
@@ -1542,24 +1554,28 @@
1542 " AND event.objid=tagxref.rid)"
1543 " ORDER BY plink.mtime)"
1544 "SELECT id FROM dx, tagxref"
1545 " WHERE tagid=%d AND tagtype>0 AND rid=id"
1546 " ORDER BY dx.mtime LIMIT 1",
1547 iFrom, iFrom, tagId, tagId
1548 );
1549 }else{
1550 db_prepare(&q,
1551 "WITH RECURSIVE dx(id,mtime) AS ("
1552 " SELECT %d, event.mtime FROM event WHERE objid=%d"
 
 
 
 
1553 " UNION"
1554 " SELECT plink.cid, plink.mtime"
1555 " FROM dx, plink"
1556 " WHERE plink.pid=dx.id"
1557 " AND plink.mtime<=(SELECT mtime FROM event WHERE objid=%d)"
1558 " ORDER BY plink.mtime)"
1559 "SELECT id FROM dx WHERE id=%d",
1560 iFrom, iFrom, endId, endId
1561 );
1562 }
1563 }else{
1564 if( tagId ){
1565 db_prepare(&q,
@@ -2221,11 +2237,11 @@
2221
2222 if( from_rid && to_rid ){
2223 if( from_to_mode==0 ){
2224 p = path_shortest(from_rid, to_rid, 0, 0, 0, cost);
2225 }else if( from_to_mode==1 ){
2226 p = path_shortest(from_rid, to_rid, 0, 1, 0, cost);
2227 earlierRid = commonAncs = from_rid;
2228 laterRid = to_rid;
2229 }else{
2230 p = path_shortest(to_rid, from_rid, 0, 1, 0, cost);
2231 earlierRid = commonAncs = to_rid;
2232
--- src/timeline.c
+++ src/timeline.c
@@ -1509,10 +1509,18 @@
1509 ** when moving either forwards are backwards in time from a
1510 ** particular starting point (iFrom). Return the rid of that
1511 ** first check-in. If there are no check-ins in the descendant
1512 ** or ancestor set of check-in iFrom that match the tag, then
1513 ** return 0.
1514 **
1515 ** If looking fowards (if bForward is true) then the first link
1516 ** is allowed to be a cherrypick, but subsequent links must be
1517 ** either full merges or normal check-ins. The idea is that we
1518 ** are looking for the first use of the code in the iFrom check-in
1519 ** that has the zEnd tag. The first link is allowed to be a cherrypick
1520 ** because the code in question crosses that link, but the code does
1521 ** not cross any subsequent cherrypick.
1522 */
1523 static int timeline_endpoint(
1524 int iFrom, /* Starting point */
1525 const char *zEnd, /* Tag we are searching for */
1526 int bForward /* 1: forwards in time (descendants) 0: backwards */
@@ -1532,10 +1540,14 @@
1540 if( tagId ){
1541 db_prepare(&q,
1542 "WITH RECURSIVE dx(id,mtime) AS ("
1543 " SELECT %d, event.mtime FROM event WHERE objid=%d"
1544 " UNION"
1545 " SELECT cp.childid, event.mtime FROM cherrypick AS cp, event"
1546 " WHERE cp.parentid=%d AND NOT cp.isExclude"
1547 " AND event.objid=cp.childid"
1548 " UNION"
1549 " SELECT plink.cid, plink.mtime"
1550 " FROM dx, plink"
1551 " WHERE plink.pid=dx.id"
1552 " AND plink.mtime<=(SELECT max(event.mtime) FROM tagxref, event"
1553 " WHERE tagxref.tagid=%d AND tagxref.tagtype>0"
@@ -1542,24 +1554,28 @@
1554 " AND event.objid=tagxref.rid)"
1555 " ORDER BY plink.mtime)"
1556 "SELECT id FROM dx, tagxref"
1557 " WHERE tagid=%d AND tagtype>0 AND rid=id"
1558 " ORDER BY dx.mtime LIMIT 1",
1559 iFrom, iFrom, iFrom, tagId, tagId
1560 );
1561 }else{
1562 db_prepare(&q,
1563 "WITH RECURSIVE dx(id,mtime) AS ("
1564 " SELECT %d, event.mtime FROM event WHERE objid=%d"
1565 " UNION"
1566 " SELECT cp.childid, event.mtime FROM cherrypick AS cp, event"
1567 " WHERE cp.parentid=%d AND NOT cp.isExclude"
1568 " AND event.objid=cp.childid"
1569 " UNION"
1570 " SELECT plink.cid, plink.mtime"
1571 " FROM dx, plink"
1572 " WHERE plink.pid=dx.id"
1573 " AND plink.mtime<=(SELECT mtime FROM event WHERE objid=%d)"
1574 " ORDER BY plink.mtime)"
1575 "SELECT id FROM dx WHERE id=%d",
1576 iFrom, iFrom, iFrom, endId, endId
1577 );
1578 }
1579 }else{
1580 if( tagId ){
1581 db_prepare(&q,
@@ -2221,11 +2237,11 @@
2237
2238 if( from_rid && to_rid ){
2239 if( from_to_mode==0 ){
2240 p = path_shortest(from_rid, to_rid, 0, 0, 0, cost);
2241 }else if( from_to_mode==1 ){
2242 p = path_shortest(from_rid, to_rid, 0, 2, 0, cost);
2243 earlierRid = commonAncs = from_rid;
2244 laterRid = to_rid;
2245 }else{
2246 p = path_shortest(to_rid, from_rid, 0, 1, 0, cost);
2247 earlierRid = commonAncs = to_rid;
2248

Keyboard Shortcuts

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