Fossil SCM

Add the "fossil bisect skip" command.

drh 2020-07-09 20:44 trunk
Commit 9e7262b4e0304740c35839f35a84a358484f217e63e597edb26891e4b1a8ce8f
3 files changed +96 -20 +20 -7 +3 -3
+96 -20
--- src/bisect.c
+++ src/bisect.c
@@ -37,17 +37,30 @@
3737
void bisect_path(void){
3838
PathNode *p;
3939
bisect.bad = db_lget_int("bisect-bad", 0);
4040
bisect.good = db_lget_int("bisect-good", 0);
4141
if( bisect.good>0 && bisect.bad==0 ){
42
- path_shortest(bisect.good, bisect.good, 0, 0);
42
+ path_shortest(bisect.good, bisect.good, 0, 0, 0);
4343
}else if( bisect.bad>0 && bisect.good==0 ){
44
- path_shortest(bisect.bad, bisect.bad, 0, 0);
44
+ path_shortest(bisect.bad, bisect.bad, 0, 0, 0);
4545
}else if( bisect.bad==0 && bisect.good==0 ){
4646
fossil_fatal("neither \"good\" nor \"bad\" versions have been identified");
4747
}else{
48
- p = path_shortest(bisect.good, bisect.bad, bisect_option("direct-only"), 0);
48
+ Bag skip;
49
+ int bDirect = bisect_option("direct-only");
50
+ char *zLog = db_lget("bisect-log","");
51
+ Blob log, id;
52
+ bag_init(&skip);
53
+ blob_init(&log, zLog, -1);
54
+ while( blob_token(&log, &id) ){
55
+ if( blob_str(&id)[0]=='s' ){
56
+ bag_insert(&skip, atoi(blob_str(&id)+1));
57
+ }
58
+ }
59
+ blob_reset(&log);
60
+ p = path_shortest(bisect.good, bisect.bad, bDirect, 0, &skip);
61
+ bag_clear(&skip);
4962
if( p==0 ){
5063
char *zBad = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.bad);
5164
char *zGood = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.good);
5265
fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
5366
zGood, zBad);
@@ -167,31 +180,51 @@
167180
db_multi_exec(
168181
"REPLACE INTO vvar(name,value) VALUES('bisect-log',"
169182
"COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
170183
" || '%d')", rid);
171184
}
185
+
186
+/*
187
+** Append a new skip entry to the bisect log.
188
+*/
189
+static void bisect_append_skip(int rid){
190
+ db_multi_exec(
191
+ "UPDATE vvar SET value=value||' s%d' WHERE name='bisect-log'", rid
192
+ );
193
+}
172194
173195
/*
174196
** Create a TEMP table named "bilog" that contains the complete history
175197
** of the current bisect.
198
+**
199
+** If iCurrent>0 then it is the RID of the current checkout and is included
200
+** in the history table.
201
+**
202
+** If zDesc is not NULL, then it is the bid= query parameter to /timeline
203
+** that describes a bisect. Use the information in zDesc rather than in
204
+** the bisect-log variable.
205
+**
206
+** If bDetail is true, then also include information about every node
207
+** in between the inner-most GOOD and BAD nodes.
176208
*/
177
-int bisect_create_bilog_table(int iCurrent, const char *zDesc){
209
+int bisect_create_bilog_table(int iCurrent, const char *zDesc, int bDetail){
178210
char *zLog;
179211
Blob log, id;
180212
Stmt q;
181213
int cnt = 0;
182214
int lastGood = -1;
183215
int lastBad = -1;
184216
185217
if( zDesc!=0 ){
186218
blob_init(&log, 0, 0);
187
- while( zDesc[0]=='y' || zDesc[0]=='n' ){
219
+ while( zDesc[0]=='y' || zDesc[0]=='n' || zDesc[0]=='s' ){
188220
int i;
189221
char c;
190222
int rid;
191223
if( blob_size(&log) ) blob_append(&log, " ", 1);
192224
if( zDesc[0]=='n' ) blob_append(&log, "-", 1);
225
+ if( zDesc[0]=='s' ) blob_append(&log, "s", 1);
193226
for(i=1; ((c = zDesc[i])>='0' && c<='9') || (c>='a' && c<='f'); i++){}
194227
if( i==1 ) break;
195228
rid = db_int(0,
196229
"SELECT rid FROM blob"
197230
" WHERE uuid LIKE '%.*q%%'"
@@ -214,20 +247,27 @@
214247
");"
215248
);
216249
db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)"
217250
" VALUES(:seq,:stat,:rid)");
218251
while( blob_token(&log, &id) ){
219
- int rid = atoi(blob_str(&id));
252
+ int rid;
220253
db_bind_int(&q, ":seq", ++cnt);
221
- if( rid>0 ){
222
- db_bind_text(&q, ":stat","GOOD");
254
+ if( blob_str(&id)[0]=='s' ){
255
+ rid = atoi(blob_str(&id)+1);
256
+ db_bind_text(&q, ":stat", "SKIP");
223257
db_bind_int(&q, ":rid", rid);
224
- lastGood = rid;
225258
}else{
226
- db_bind_text(&q, ":stat", "BAD");
227
- db_bind_int(&q, ":rid", -rid);
228
- lastBad = -rid;
259
+ rid = atoi(blob_str(&id));
260
+ if( rid>0 ){
261
+ db_bind_text(&q, ":stat","GOOD");
262
+ db_bind_int(&q, ":rid", rid);
263
+ lastGood = rid;
264
+ }else{
265
+ db_bind_text(&q, ":stat", "BAD");
266
+ db_bind_int(&q, ":rid", -rid);
267
+ lastBad = -rid;
268
+ }
229269
}
230270
db_step(&q);
231271
db_reset(&q);
232272
}
233273
if( iCurrent>0 ){
@@ -235,13 +275,13 @@
235275
db_bind_text(&q, ":stat", "CURRENT");
236276
db_bind_int(&q, ":rid", iCurrent);
237277
db_step(&q);
238278
db_reset(&q);
239279
}
240
- if( lastGood>0 && lastBad>0 ){
280
+ if( bDetail && lastGood>0 && lastBad>0 ){
241281
PathNode *p;
242
- p = path_shortest(lastGood, lastBad, bisect_option("direct-only"),0);
282
+ p = path_shortest(lastGood, lastBad, bisect_option("direct-only"),0, 0);
243283
while( p ){
244284
db_bind_null(&q, ":seq");
245285
db_bind_null(&q, ":stat");
246286
db_bind_int(&q, ":rid", p->rid);
247287
db_step(&q);
@@ -267,14 +307,25 @@
267307
Blob log;
268308
Blob link = BLOB_INITIALIZER;
269309
Blob id;
270310
blob_init(&log, zLog, -1);
271311
while( blob_token(&log, &id) ){
272
- int rid = atoi(blob_str(&id));
273
- char *zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d",
274
- rid<0 ? -rid : rid);
275
- blob_appendf(&link, "%c%.10s", rid<0 ? 'n' : 'y', zUuid);
312
+ const char *zUuid;
313
+ int rid;
314
+ char cPrefix = 'y';
315
+ if( blob_str(&id)[0]=='s' ){
316
+ rid = atoi(blob_str(&id)+1);
317
+ cPrefix = 's';
318
+ }else{
319
+ rid = atoi(blob_str(&id));
320
+ if( rid<0 ){
321
+ cPrefix = 'n';
322
+ rid = -rid;
323
+ }
324
+ }
325
+ zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d", rid);
326
+ blob_appendf(&link, "%c%.10s", cPrefix, zUuid);
276327
}
277328
zResult = mprintf("%s", blob_str(&link));
278329
blob_reset(&link);
279330
blob_reset(&log);
280331
blob_reset(&id);
@@ -286,11 +337,11 @@
286337
** sorted either chronologically by bisect time, or by check-in time.
287338
*/
288339
static void bisect_chart(int sortByCkinTime){
289340
Stmt q;
290341
int iCurrent = db_lget_int("checkout",0);
291
- bisect_create_bilog_table(iCurrent, 0);
342
+ bisect_create_bilog_table(iCurrent, 0, 0);
292343
db_prepare(&q,
293344
"SELECT bilog.seq, bilog.stat,"
294345
" substr(blob.uuid,1,16), datetime(event.mtime),"
295346
" blob.rid==%d"
296347
" FROM bilog, blob, event"
@@ -359,10 +410,17 @@
359410
** > fossil bisect reset
360411
**
361412
** Reinitialize a bisect session. This cancels prior bisect history
362413
** and allows a bisect session to start over from the beginning.
363414
**
415
+** > fossil bisect skip ?VERSION?
416
+**
417
+** Cause VERSION (or the current checkout if VERSION is omitted) to
418
+** be ignored for the purpose of the current bisect. This might
419
+** be done, for example, because VERSION does not compile correctly
420
+** or is otherwise unsuitable to participate in this bisect.
421
+**
364422
** > fossil bisect vlist|ls|status ?-a|--all?
365423
**
366424
** List the versions in between "bad" and "good".
367425
**
368426
** > fossil bisect ui
@@ -424,10 +482,28 @@
424482
bisect_append_log(ridGood);
425483
if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
426484
zCmd = "next";
427485
n = 4;
428486
}
487
+ }
488
+ }else if( strncmp(zCmd, "skip", n)==0 ){
489
+ int ridSkip;
490
+ foundCmd = 1;
491
+ if( g.argc==3 ){
492
+ ridSkip = db_lget_int("checkout",0);
493
+ }else{
494
+ ridSkip = name_to_typed_rid(g.argv[3], "ci");
495
+ }
496
+ if( ridSkip>0 ){
497
+ bisect_append_skip(ridSkip);
498
+ if( bisect_option("auto-next")
499
+ && db_lget_int("bisect-bad",0)>0
500
+ && db_lget_int("bisect-good",0)>0
501
+ ){
502
+ zCmd = "next";
503
+ n = 4;
504
+ }
429505
}
430506
}else if( strncmp(zCmd, "undo", n)==0 ){
431507
char *zLog;
432508
Blob log, id;
433509
int ridBad = 0;
@@ -470,11 +546,11 @@
470546
bisect_path();
471547
pMid = path_midpoint();
472548
if( pMid==0 ){
473549
fossil_print("bisect complete\n");
474550
}else{
475
- int nSpan = path_length();
551
+ int nSpan = path_length_not_hidden();
476552
int nStep = path_search_depth();
477553
g.argv[1] = "update";
478554
g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
479555
g.argc = 3;
480556
g.fNoSync = 1;
481557
--- src/bisect.c
+++ src/bisect.c
@@ -37,17 +37,30 @@
37 void bisect_path(void){
38 PathNode *p;
39 bisect.bad = db_lget_int("bisect-bad", 0);
40 bisect.good = db_lget_int("bisect-good", 0);
41 if( bisect.good>0 && bisect.bad==0 ){
42 path_shortest(bisect.good, bisect.good, 0, 0);
43 }else if( bisect.bad>0 && bisect.good==0 ){
44 path_shortest(bisect.bad, bisect.bad, 0, 0);
45 }else if( bisect.bad==0 && bisect.good==0 ){
46 fossil_fatal("neither \"good\" nor \"bad\" versions have been identified");
47 }else{
48 p = path_shortest(bisect.good, bisect.bad, bisect_option("direct-only"), 0);
 
 
 
 
 
 
 
 
 
 
 
 
 
49 if( p==0 ){
50 char *zBad = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.bad);
51 char *zGood = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.good);
52 fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
53 zGood, zBad);
@@ -167,31 +180,51 @@
167 db_multi_exec(
168 "REPLACE INTO vvar(name,value) VALUES('bisect-log',"
169 "COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
170 " || '%d')", rid);
171 }
 
 
 
 
 
 
 
 
 
172
173 /*
174 ** Create a TEMP table named "bilog" that contains the complete history
175 ** of the current bisect.
 
 
 
 
 
 
 
 
 
 
176 */
177 int bisect_create_bilog_table(int iCurrent, const char *zDesc){
178 char *zLog;
179 Blob log, id;
180 Stmt q;
181 int cnt = 0;
182 int lastGood = -1;
183 int lastBad = -1;
184
185 if( zDesc!=0 ){
186 blob_init(&log, 0, 0);
187 while( zDesc[0]=='y' || zDesc[0]=='n' ){
188 int i;
189 char c;
190 int rid;
191 if( blob_size(&log) ) blob_append(&log, " ", 1);
192 if( zDesc[0]=='n' ) blob_append(&log, "-", 1);
 
193 for(i=1; ((c = zDesc[i])>='0' && c<='9') || (c>='a' && c<='f'); i++){}
194 if( i==1 ) break;
195 rid = db_int(0,
196 "SELECT rid FROM blob"
197 " WHERE uuid LIKE '%.*q%%'"
@@ -214,20 +247,27 @@
214 ");"
215 );
216 db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)"
217 " VALUES(:seq,:stat,:rid)");
218 while( blob_token(&log, &id) ){
219 int rid = atoi(blob_str(&id));
220 db_bind_int(&q, ":seq", ++cnt);
221 if( rid>0 ){
222 db_bind_text(&q, ":stat","GOOD");
 
223 db_bind_int(&q, ":rid", rid);
224 lastGood = rid;
225 }else{
226 db_bind_text(&q, ":stat", "BAD");
227 db_bind_int(&q, ":rid", -rid);
228 lastBad = -rid;
 
 
 
 
 
 
 
229 }
230 db_step(&q);
231 db_reset(&q);
232 }
233 if( iCurrent>0 ){
@@ -235,13 +275,13 @@
235 db_bind_text(&q, ":stat", "CURRENT");
236 db_bind_int(&q, ":rid", iCurrent);
237 db_step(&q);
238 db_reset(&q);
239 }
240 if( lastGood>0 && lastBad>0 ){
241 PathNode *p;
242 p = path_shortest(lastGood, lastBad, bisect_option("direct-only"),0);
243 while( p ){
244 db_bind_null(&q, ":seq");
245 db_bind_null(&q, ":stat");
246 db_bind_int(&q, ":rid", p->rid);
247 db_step(&q);
@@ -267,14 +307,25 @@
267 Blob log;
268 Blob link = BLOB_INITIALIZER;
269 Blob id;
270 blob_init(&log, zLog, -1);
271 while( blob_token(&log, &id) ){
272 int rid = atoi(blob_str(&id));
273 char *zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d",
274 rid<0 ? -rid : rid);
275 blob_appendf(&link, "%c%.10s", rid<0 ? 'n' : 'y', zUuid);
 
 
 
 
 
 
 
 
 
 
 
276 }
277 zResult = mprintf("%s", blob_str(&link));
278 blob_reset(&link);
279 blob_reset(&log);
280 blob_reset(&id);
@@ -286,11 +337,11 @@
286 ** sorted either chronologically by bisect time, or by check-in time.
287 */
288 static void bisect_chart(int sortByCkinTime){
289 Stmt q;
290 int iCurrent = db_lget_int("checkout",0);
291 bisect_create_bilog_table(iCurrent, 0);
292 db_prepare(&q,
293 "SELECT bilog.seq, bilog.stat,"
294 " substr(blob.uuid,1,16), datetime(event.mtime),"
295 " blob.rid==%d"
296 " FROM bilog, blob, event"
@@ -359,10 +410,17 @@
359 ** > fossil bisect reset
360 **
361 ** Reinitialize a bisect session. This cancels prior bisect history
362 ** and allows a bisect session to start over from the beginning.
363 **
 
 
 
 
 
 
 
364 ** > fossil bisect vlist|ls|status ?-a|--all?
365 **
366 ** List the versions in between "bad" and "good".
367 **
368 ** > fossil bisect ui
@@ -424,10 +482,28 @@
424 bisect_append_log(ridGood);
425 if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
426 zCmd = "next";
427 n = 4;
428 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
429 }
430 }else if( strncmp(zCmd, "undo", n)==0 ){
431 char *zLog;
432 Blob log, id;
433 int ridBad = 0;
@@ -470,11 +546,11 @@
470 bisect_path();
471 pMid = path_midpoint();
472 if( pMid==0 ){
473 fossil_print("bisect complete\n");
474 }else{
475 int nSpan = path_length();
476 int nStep = path_search_depth();
477 g.argv[1] = "update";
478 g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
479 g.argc = 3;
480 g.fNoSync = 1;
481
--- src/bisect.c
+++ src/bisect.c
@@ -37,17 +37,30 @@
37 void bisect_path(void){
38 PathNode *p;
39 bisect.bad = db_lget_int("bisect-bad", 0);
40 bisect.good = db_lget_int("bisect-good", 0);
41 if( bisect.good>0 && bisect.bad==0 ){
42 path_shortest(bisect.good, bisect.good, 0, 0, 0);
43 }else if( bisect.bad>0 && bisect.good==0 ){
44 path_shortest(bisect.bad, bisect.bad, 0, 0, 0);
45 }else if( bisect.bad==0 && bisect.good==0 ){
46 fossil_fatal("neither \"good\" nor \"bad\" versions have been identified");
47 }else{
48 Bag skip;
49 int bDirect = bisect_option("direct-only");
50 char *zLog = db_lget("bisect-log","");
51 Blob log, id;
52 bag_init(&skip);
53 blob_init(&log, zLog, -1);
54 while( blob_token(&log, &id) ){
55 if( blob_str(&id)[0]=='s' ){
56 bag_insert(&skip, atoi(blob_str(&id)+1));
57 }
58 }
59 blob_reset(&log);
60 p = path_shortest(bisect.good, bisect.bad, bDirect, 0, &skip);
61 bag_clear(&skip);
62 if( p==0 ){
63 char *zBad = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.bad);
64 char *zGood = db_text(0,"SELECT uuid FROM blob WHERE rid=%d",bisect.good);
65 fossil_fatal("no path from good ([%S]) to bad ([%S]) or back",
66 zGood, zBad);
@@ -167,31 +180,51 @@
180 db_multi_exec(
181 "REPLACE INTO vvar(name,value) VALUES('bisect-log',"
182 "COALESCE((SELECT value||' ' FROM vvar WHERE name='bisect-log'),'')"
183 " || '%d')", rid);
184 }
185
186 /*
187 ** Append a new skip entry to the bisect log.
188 */
189 static void bisect_append_skip(int rid){
190 db_multi_exec(
191 "UPDATE vvar SET value=value||' s%d' WHERE name='bisect-log'", rid
192 );
193 }
194
195 /*
196 ** Create a TEMP table named "bilog" that contains the complete history
197 ** of the current bisect.
198 **
199 ** If iCurrent>0 then it is the RID of the current checkout and is included
200 ** in the history table.
201 **
202 ** If zDesc is not NULL, then it is the bid= query parameter to /timeline
203 ** that describes a bisect. Use the information in zDesc rather than in
204 ** the bisect-log variable.
205 **
206 ** If bDetail is true, then also include information about every node
207 ** in between the inner-most GOOD and BAD nodes.
208 */
209 int bisect_create_bilog_table(int iCurrent, const char *zDesc, int bDetail){
210 char *zLog;
211 Blob log, id;
212 Stmt q;
213 int cnt = 0;
214 int lastGood = -1;
215 int lastBad = -1;
216
217 if( zDesc!=0 ){
218 blob_init(&log, 0, 0);
219 while( zDesc[0]=='y' || zDesc[0]=='n' || zDesc[0]=='s' ){
220 int i;
221 char c;
222 int rid;
223 if( blob_size(&log) ) blob_append(&log, " ", 1);
224 if( zDesc[0]=='n' ) blob_append(&log, "-", 1);
225 if( zDesc[0]=='s' ) blob_append(&log, "s", 1);
226 for(i=1; ((c = zDesc[i])>='0' && c<='9') || (c>='a' && c<='f'); i++){}
227 if( i==1 ) break;
228 rid = db_int(0,
229 "SELECT rid FROM blob"
230 " WHERE uuid LIKE '%.*q%%'"
@@ -214,20 +247,27 @@
247 ");"
248 );
249 db_prepare(&q, "INSERT OR IGNORE INTO bilog(seq,stat,rid)"
250 " VALUES(:seq,:stat,:rid)");
251 while( blob_token(&log, &id) ){
252 int rid;
253 db_bind_int(&q, ":seq", ++cnt);
254 if( blob_str(&id)[0]=='s' ){
255 rid = atoi(blob_str(&id)+1);
256 db_bind_text(&q, ":stat", "SKIP");
257 db_bind_int(&q, ":rid", rid);
 
258 }else{
259 rid = atoi(blob_str(&id));
260 if( rid>0 ){
261 db_bind_text(&q, ":stat","GOOD");
262 db_bind_int(&q, ":rid", rid);
263 lastGood = rid;
264 }else{
265 db_bind_text(&q, ":stat", "BAD");
266 db_bind_int(&q, ":rid", -rid);
267 lastBad = -rid;
268 }
269 }
270 db_step(&q);
271 db_reset(&q);
272 }
273 if( iCurrent>0 ){
@@ -235,13 +275,13 @@
275 db_bind_text(&q, ":stat", "CURRENT");
276 db_bind_int(&q, ":rid", iCurrent);
277 db_step(&q);
278 db_reset(&q);
279 }
280 if( bDetail && lastGood>0 && lastBad>0 ){
281 PathNode *p;
282 p = path_shortest(lastGood, lastBad, bisect_option("direct-only"),0, 0);
283 while( p ){
284 db_bind_null(&q, ":seq");
285 db_bind_null(&q, ":stat");
286 db_bind_int(&q, ":rid", p->rid);
287 db_step(&q);
@@ -267,14 +307,25 @@
307 Blob log;
308 Blob link = BLOB_INITIALIZER;
309 Blob id;
310 blob_init(&log, zLog, -1);
311 while( blob_token(&log, &id) ){
312 const char *zUuid;
313 int rid;
314 char cPrefix = 'y';
315 if( blob_str(&id)[0]=='s' ){
316 rid = atoi(blob_str(&id)+1);
317 cPrefix = 's';
318 }else{
319 rid = atoi(blob_str(&id));
320 if( rid<0 ){
321 cPrefix = 'n';
322 rid = -rid;
323 }
324 }
325 zUuid = db_text(0,"SELECT lower(uuid) FROM blob WHERE rid=%d", rid);
326 blob_appendf(&link, "%c%.10s", cPrefix, zUuid);
327 }
328 zResult = mprintf("%s", blob_str(&link));
329 blob_reset(&link);
330 blob_reset(&log);
331 blob_reset(&id);
@@ -286,11 +337,11 @@
337 ** sorted either chronologically by bisect time, or by check-in time.
338 */
339 static void bisect_chart(int sortByCkinTime){
340 Stmt q;
341 int iCurrent = db_lget_int("checkout",0);
342 bisect_create_bilog_table(iCurrent, 0, 0);
343 db_prepare(&q,
344 "SELECT bilog.seq, bilog.stat,"
345 " substr(blob.uuid,1,16), datetime(event.mtime),"
346 " blob.rid==%d"
347 " FROM bilog, blob, event"
@@ -359,10 +410,17 @@
410 ** > fossil bisect reset
411 **
412 ** Reinitialize a bisect session. This cancels prior bisect history
413 ** and allows a bisect session to start over from the beginning.
414 **
415 ** > fossil bisect skip ?VERSION?
416 **
417 ** Cause VERSION (or the current checkout if VERSION is omitted) to
418 ** be ignored for the purpose of the current bisect. This might
419 ** be done, for example, because VERSION does not compile correctly
420 ** or is otherwise unsuitable to participate in this bisect.
421 **
422 ** > fossil bisect vlist|ls|status ?-a|--all?
423 **
424 ** List the versions in between "bad" and "good".
425 **
426 ** > fossil bisect ui
@@ -424,10 +482,28 @@
482 bisect_append_log(ridGood);
483 if( bisect_option("auto-next") && db_lget_int("bisect-bad",0)>0 ){
484 zCmd = "next";
485 n = 4;
486 }
487 }
488 }else if( strncmp(zCmd, "skip", n)==0 ){
489 int ridSkip;
490 foundCmd = 1;
491 if( g.argc==3 ){
492 ridSkip = db_lget_int("checkout",0);
493 }else{
494 ridSkip = name_to_typed_rid(g.argv[3], "ci");
495 }
496 if( ridSkip>0 ){
497 bisect_append_skip(ridSkip);
498 if( bisect_option("auto-next")
499 && db_lget_int("bisect-bad",0)>0
500 && db_lget_int("bisect-good",0)>0
501 ){
502 zCmd = "next";
503 n = 4;
504 }
505 }
506 }else if( strncmp(zCmd, "undo", n)==0 ){
507 char *zLog;
508 Blob log, id;
509 int ridBad = 0;
@@ -470,11 +546,11 @@
546 bisect_path();
547 pMid = path_midpoint();
548 if( pMid==0 ){
549 fossil_print("bisect complete\n");
550 }else{
551 int nSpan = path_length_not_hidden();
552 int nStep = path_search_depth();
553 g.argv[1] = "update";
554 g.argv[2] = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pMid->rid);
555 g.argc = 3;
556 g.fNoSync = 1;
557
+20 -7
--- src/path.c
+++ src/path.c
@@ -44,10 +44,11 @@
4444
static struct {
4545
PathNode *pCurrent; /* Current generation of nodes */
4646
PathNode *pAll; /* All nodes */
4747
Bag seen; /* Nodes seen before */
4848
int nStep; /* Number of steps from first to last */
49
+ int nNotHidden; /* Number of steps not counting hidden nodes */
4950
PathNode *pStart; /* Earliest node */
5051
PathNode *pEnd; /* Most recent */
5152
} path;
5253
5354
/*
@@ -59,10 +60,15 @@
5960
/*
6061
** Return the number of steps in the computed path.
6162
*/
6263
int path_length(void){ return path.nStep; }
6364
65
+/*
66
+** Return the number of non-hidden steps in the computed path.
67
+*/
68
+int path_length_not_hidden(void){ return path.nNotHidden; }
69
+
6470
/*
6571
** Create a new node
6672
*/
6773
static PathNode *path_new_node(int rid, PathNode *pFrom, int isParent){
6874
PathNode *p;
@@ -121,11 +127,12 @@
121127
*/
122128
PathNode *path_shortest(
123129
int iFrom, /* Path starts here */
124130
int iTo, /* Path ends here */
125131
int directOnly, /* No merge links if true */
126
- int oneWayOnly /* Parent->child only if true */
132
+ int oneWayOnly, /* Parent->child only if true */
133
+ Bag *pHidden /* Hidden nodes */
127134
){
128135
Stmt s;
129136
PathNode *pPrev;
130137
PathNode *p;
131138
@@ -165,14 +172,18 @@
165172
while( db_step(&s)==SQLITE_ROW ){
166173
int cid = db_column_int(&s, 0);
167174
int isParent = db_column_int(&s, 1);
168175
if( bag_find(&path.seen, cid) ) continue;
169176
p = path_new_node(cid, pPrev, isParent);
177
+ if( pHidden && bag_find(pHidden,cid) ) p->isHidden = 1;
170178
if( cid==iTo ){
171179
db_finalize(&s);
172180
path.pEnd = p;
173181
path_reverse_path();
182
+ for(p=path.pStart->u.pTo; p; p=p->u.pTo ){
183
+ if( !p->isHidden ) path.nNotHidden++;
184
+ }
174185
return path.pStart;
175186
}
176187
}
177188
db_reset(&s);
178189
pPrev = pPrev->u.pPeer;
@@ -188,22 +199,24 @@
188199
** 2 steps, return 0.
189200
*/
190201
PathNode *path_midpoint(void){
191202
PathNode *p;
192203
int i;
193
- if( path.nStep<2 ) return 0;
194
- for(p=path.pEnd, i=0; p && i<path.nStep/2; p=p->pFrom, i++){}
204
+ if( path.nNotHidden<2 ) return 0;
205
+ for(p=path.pEnd, i=0; p && (p->isHidden || i<path.nNotHidden/2); p=p->pFrom){
206
+ if( !p->isHidden ) i++;
207
+ }
195208
return p;
196209
}
197210
198211
/*
199212
** Return an estimate of the number of comparisons remaining in order
200213
** to bisect path. This is based on the log2() of path.nStep.
201214
*/
202215
int path_search_depth(void){
203216
int i, j;
204
- for(i=0, j=1; j<path.nStep; i++, j+=j){}
217
+ for(i=0, j=1; j<path.nNotHidden; i++, j+=j){}
205218
return i;
206219
}
207220
208221
/*
209222
** Compute the shortest path between two check-ins and then transfer
@@ -215,11 +228,11 @@
215228
int cid /* RID for check-in at the end of the path */
216229
){
217230
PathNode *pPath;
218231
int gen = 0;
219232
Stmt ins;
220
- pPath = path_shortest(cid, origid, 1, 0);
233
+ pPath = path_shortest(cid, origid, 1, 0, 0);
221234
db_multi_exec(
222235
"CREATE TEMP TABLE IF NOT EXISTS ancestor("
223236
" rid INT UNIQUE,"
224237
" generation INTEGER PRIMARY KEY"
225238
");"
@@ -257,11 +270,11 @@
257270
directOnly = find_option("no-merge",0,0)!=0;
258271
oneWay = find_option("one-way",0,0)!=0;
259272
if( g.argc!=4 ) usage("VERSION1 VERSION2");
260273
iFrom = name_to_rid(g.argv[2]);
261274
iTo = name_to_rid(g.argv[3]);
262
- p = path_shortest(iFrom, iTo, directOnly, oneWay);
275
+ p = path_shortest(iFrom, iTo, directOnly, oneWay, 0);
263276
if( p==0 ){
264277
fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
265278
}
266279
for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
267280
char *z;
@@ -430,11 +443,11 @@
430443
}else if(0==iTo){
431444
fossil_fatal("Invalid 'to' RID: 0");
432445
}
433446
if( iFrom==iTo ) return;
434447
path_reset();
435
- p = path_shortest(iFrom, iTo, 1, revOk==0);
448
+ p = path_shortest(iFrom, iTo, 1, revOk==0, 0);
436449
if( p==0 ) return;
437450
path_reverse_path();
438451
db_prepare(&q1,
439452
"SELECT pfnid, fnid FROM mlink"
440453
" WHERE mid=:mid AND (pfnid>0 OR fid==0)"
441454
--- src/path.c
+++ src/path.c
@@ -44,10 +44,11 @@
44 static struct {
45 PathNode *pCurrent; /* Current generation of nodes */
46 PathNode *pAll; /* All nodes */
47 Bag seen; /* Nodes seen before */
48 int nStep; /* Number of steps from first to last */
 
49 PathNode *pStart; /* Earliest node */
50 PathNode *pEnd; /* Most recent */
51 } path;
52
53 /*
@@ -59,10 +60,15 @@
59 /*
60 ** Return the number of steps in the computed path.
61 */
62 int path_length(void){ return path.nStep; }
63
 
 
 
 
 
64 /*
65 ** Create a new node
66 */
67 static PathNode *path_new_node(int rid, PathNode *pFrom, int isParent){
68 PathNode *p;
@@ -121,11 +127,12 @@
121 */
122 PathNode *path_shortest(
123 int iFrom, /* Path starts here */
124 int iTo, /* Path ends here */
125 int directOnly, /* No merge links if true */
126 int oneWayOnly /* Parent->child only if true */
 
127 ){
128 Stmt s;
129 PathNode *pPrev;
130 PathNode *p;
131
@@ -165,14 +172,18 @@
165 while( db_step(&s)==SQLITE_ROW ){
166 int cid = db_column_int(&s, 0);
167 int isParent = db_column_int(&s, 1);
168 if( bag_find(&path.seen, cid) ) continue;
169 p = path_new_node(cid, pPrev, isParent);
 
170 if( cid==iTo ){
171 db_finalize(&s);
172 path.pEnd = p;
173 path_reverse_path();
 
 
 
174 return path.pStart;
175 }
176 }
177 db_reset(&s);
178 pPrev = pPrev->u.pPeer;
@@ -188,22 +199,24 @@
188 ** 2 steps, return 0.
189 */
190 PathNode *path_midpoint(void){
191 PathNode *p;
192 int i;
193 if( path.nStep<2 ) return 0;
194 for(p=path.pEnd, i=0; p && i<path.nStep/2; p=p->pFrom, i++){}
 
 
195 return p;
196 }
197
198 /*
199 ** Return an estimate of the number of comparisons remaining in order
200 ** to bisect path. This is based on the log2() of path.nStep.
201 */
202 int path_search_depth(void){
203 int i, j;
204 for(i=0, j=1; j<path.nStep; i++, j+=j){}
205 return i;
206 }
207
208 /*
209 ** Compute the shortest path between two check-ins and then transfer
@@ -215,11 +228,11 @@
215 int cid /* RID for check-in at the end of the path */
216 ){
217 PathNode *pPath;
218 int gen = 0;
219 Stmt ins;
220 pPath = path_shortest(cid, origid, 1, 0);
221 db_multi_exec(
222 "CREATE TEMP TABLE IF NOT EXISTS ancestor("
223 " rid INT UNIQUE,"
224 " generation INTEGER PRIMARY KEY"
225 ");"
@@ -257,11 +270,11 @@
257 directOnly = find_option("no-merge",0,0)!=0;
258 oneWay = find_option("one-way",0,0)!=0;
259 if( g.argc!=4 ) usage("VERSION1 VERSION2");
260 iFrom = name_to_rid(g.argv[2]);
261 iTo = name_to_rid(g.argv[3]);
262 p = path_shortest(iFrom, iTo, directOnly, oneWay);
263 if( p==0 ){
264 fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
265 }
266 for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
267 char *z;
@@ -430,11 +443,11 @@
430 }else if(0==iTo){
431 fossil_fatal("Invalid 'to' RID: 0");
432 }
433 if( iFrom==iTo ) return;
434 path_reset();
435 p = path_shortest(iFrom, iTo, 1, revOk==0);
436 if( p==0 ) return;
437 path_reverse_path();
438 db_prepare(&q1,
439 "SELECT pfnid, fnid FROM mlink"
440 " WHERE mid=:mid AND (pfnid>0 OR fid==0)"
441
--- src/path.c
+++ src/path.c
@@ -44,10 +44,11 @@
44 static struct {
45 PathNode *pCurrent; /* Current generation of nodes */
46 PathNode *pAll; /* All nodes */
47 Bag seen; /* Nodes seen before */
48 int nStep; /* Number of steps from first to last */
49 int nNotHidden; /* Number of steps not counting hidden nodes */
50 PathNode *pStart; /* Earliest node */
51 PathNode *pEnd; /* Most recent */
52 } path;
53
54 /*
@@ -59,10 +60,15 @@
60 /*
61 ** Return the number of steps in the computed path.
62 */
63 int path_length(void){ return path.nStep; }
64
65 /*
66 ** Return the number of non-hidden steps in the computed path.
67 */
68 int path_length_not_hidden(void){ return path.nNotHidden; }
69
70 /*
71 ** Create a new node
72 */
73 static PathNode *path_new_node(int rid, PathNode *pFrom, int isParent){
74 PathNode *p;
@@ -121,11 +127,12 @@
127 */
128 PathNode *path_shortest(
129 int iFrom, /* Path starts here */
130 int iTo, /* Path ends here */
131 int directOnly, /* No merge links if true */
132 int oneWayOnly, /* Parent->child only if true */
133 Bag *pHidden /* Hidden nodes */
134 ){
135 Stmt s;
136 PathNode *pPrev;
137 PathNode *p;
138
@@ -165,14 +172,18 @@
172 while( db_step(&s)==SQLITE_ROW ){
173 int cid = db_column_int(&s, 0);
174 int isParent = db_column_int(&s, 1);
175 if( bag_find(&path.seen, cid) ) continue;
176 p = path_new_node(cid, pPrev, isParent);
177 if( pHidden && bag_find(pHidden,cid) ) p->isHidden = 1;
178 if( cid==iTo ){
179 db_finalize(&s);
180 path.pEnd = p;
181 path_reverse_path();
182 for(p=path.pStart->u.pTo; p; p=p->u.pTo ){
183 if( !p->isHidden ) path.nNotHidden++;
184 }
185 return path.pStart;
186 }
187 }
188 db_reset(&s);
189 pPrev = pPrev->u.pPeer;
@@ -188,22 +199,24 @@
199 ** 2 steps, return 0.
200 */
201 PathNode *path_midpoint(void){
202 PathNode *p;
203 int i;
204 if( path.nNotHidden<2 ) return 0;
205 for(p=path.pEnd, i=0; p && (p->isHidden || i<path.nNotHidden/2); p=p->pFrom){
206 if( !p->isHidden ) i++;
207 }
208 return p;
209 }
210
211 /*
212 ** Return an estimate of the number of comparisons remaining in order
213 ** to bisect path. This is based on the log2() of path.nStep.
214 */
215 int path_search_depth(void){
216 int i, j;
217 for(i=0, j=1; j<path.nNotHidden; i++, j+=j){}
218 return i;
219 }
220
221 /*
222 ** Compute the shortest path between two check-ins and then transfer
@@ -215,11 +228,11 @@
228 int cid /* RID for check-in at the end of the path */
229 ){
230 PathNode *pPath;
231 int gen = 0;
232 Stmt ins;
233 pPath = path_shortest(cid, origid, 1, 0, 0);
234 db_multi_exec(
235 "CREATE TEMP TABLE IF NOT EXISTS ancestor("
236 " rid INT UNIQUE,"
237 " generation INTEGER PRIMARY KEY"
238 ");"
@@ -257,11 +270,11 @@
270 directOnly = find_option("no-merge",0,0)!=0;
271 oneWay = find_option("one-way",0,0)!=0;
272 if( g.argc!=4 ) usage("VERSION1 VERSION2");
273 iFrom = name_to_rid(g.argv[2]);
274 iTo = name_to_rid(g.argv[3]);
275 p = path_shortest(iFrom, iTo, directOnly, oneWay, 0);
276 if( p==0 ){
277 fossil_fatal("no path from %s to %s", g.argv[1], g.argv[2]);
278 }
279 for(n=1, p=path.pStart; p; p=p->u.pTo, n++){
280 char *z;
@@ -430,11 +443,11 @@
443 }else if(0==iTo){
444 fossil_fatal("Invalid 'to' RID: 0");
445 }
446 if( iFrom==iTo ) return;
447 path_reset();
448 p = path_shortest(iFrom, iTo, 1, revOk==0, 0);
449 if( p==0 ) return;
450 path_reverse_path();
451 db_prepare(&q1,
452 "SELECT pfnid, fnid FROM mlink"
453 " WHERE mid=:mid AND (pfnid>0 OR fid==0)"
454
+3 -3
--- src/timeline.c
+++ src/timeline.c
@@ -1913,19 +1913,19 @@
19131913
&& fossil_strcmp(g.zIpAddr,"127.0.0.1")==0
19141914
&& db_open_local(0)
19151915
){
19161916
int iCurrent = db_lget_int("checkout",0);
19171917
char *zPerm = bisect_permalink();
1918
- bisect_create_bilog_table(iCurrent, 0);
1918
+ bisect_create_bilog_table(iCurrent, 0, 1);
19191919
tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
19201920
zType = "ci";
19211921
disableY = 1;
19221922
style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm);
19231923
}else{
19241924
bisectLocal = 0;
19251925
}
1926
- if( zBisect!=0 && bisect_create_bilog_table(0, zBisect) ){
1926
+ if( zBisect!=0 && bisect_create_bilog_table(0, zBisect, 1) ){
19271927
tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
19281928
zType = "ci";
19291929
disableY = 1;
19301930
}else{
19311931
zBisect = 0;
@@ -1962,11 +1962,11 @@
19621962
const char *zTo = 0;
19631963
Blob ins;
19641964
int nNodeOnPath = 0;
19651965
19661966
if( from_rid && to_rid ){
1967
- p = path_shortest(from_rid, to_rid, noMerge, 0);
1967
+ p = path_shortest(from_rid, to_rid, noMerge, 0, 0);
19681968
zFrom = P("from");
19691969
zTo = P("to");
19701970
}else{
19711971
if( path_common_ancestor(me_rid, you_rid) ){
19721972
p = path_first();
19731973
--- src/timeline.c
+++ src/timeline.c
@@ -1913,19 +1913,19 @@
1913 && fossil_strcmp(g.zIpAddr,"127.0.0.1")==0
1914 && db_open_local(0)
1915 ){
1916 int iCurrent = db_lget_int("checkout",0);
1917 char *zPerm = bisect_permalink();
1918 bisect_create_bilog_table(iCurrent, 0);
1919 tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
1920 zType = "ci";
1921 disableY = 1;
1922 style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm);
1923 }else{
1924 bisectLocal = 0;
1925 }
1926 if( zBisect!=0 && bisect_create_bilog_table(0, zBisect) ){
1927 tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
1928 zType = "ci";
1929 disableY = 1;
1930 }else{
1931 zBisect = 0;
@@ -1962,11 +1962,11 @@
1962 const char *zTo = 0;
1963 Blob ins;
1964 int nNodeOnPath = 0;
1965
1966 if( from_rid && to_rid ){
1967 p = path_shortest(from_rid, to_rid, noMerge, 0);
1968 zFrom = P("from");
1969 zTo = P("to");
1970 }else{
1971 if( path_common_ancestor(me_rid, you_rid) ){
1972 p = path_first();
1973
--- src/timeline.c
+++ src/timeline.c
@@ -1913,19 +1913,19 @@
1913 && fossil_strcmp(g.zIpAddr,"127.0.0.1")==0
1914 && db_open_local(0)
1915 ){
1916 int iCurrent = db_lget_int("checkout",0);
1917 char *zPerm = bisect_permalink();
1918 bisect_create_bilog_table(iCurrent, 0, 1);
1919 tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
1920 zType = "ci";
1921 disableY = 1;
1922 style_submenu_element("Permalink", "%R/timeline?bid=%z", zPerm);
1923 }else{
1924 bisectLocal = 0;
1925 }
1926 if( zBisect!=0 && bisect_create_bilog_table(0, zBisect, 1) ){
1927 tmFlags |= TIMELINE_UNHIDE | TIMELINE_BISECT | TIMELINE_FILLGAPS;
1928 zType = "ci";
1929 disableY = 1;
1930 }else{
1931 zBisect = 0;
@@ -1962,11 +1962,11 @@
1962 const char *zTo = 0;
1963 Blob ins;
1964 int nNodeOnPath = 0;
1965
1966 if( from_rid && to_rid ){
1967 p = path_shortest(from_rid, to_rid, noMerge, 0, 0);
1968 zFrom = P("from");
1969 zTo = P("to");
1970 }else{
1971 if( path_common_ancestor(me_rid, you_rid) ){
1972 p = path_first();
1973

Keyboard Shortcuts

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