Fossil SCM
For file history graphs, use merge arrows to show when the same file appears in multiple check-ins.
Commit
6ea10c5e990d2e6eb6f5a0d8638eb8be6d7bace7
Parent
1d2608b7f4d7486…
1 file changed
+52
-21
+52
-21
| --- src/graph.c | ||
| +++ src/graph.c | ||
| @@ -205,31 +205,36 @@ | ||
| 205 | 205 | pRow = pRow->pNext; |
| 206 | 206 | } |
| 207 | 207 | for(i=0; i<32; i++){ |
| 208 | 208 | if( (inUseMask & (1<<i))==0 ){ |
| 209 | 209 | int dist; |
| 210 | - if( iNearto<=0 ) return i; | |
| 210 | + if( iNearto<=0 ){ | |
| 211 | + if( i>p->mxRail ) p->mxRail = i; | |
| 212 | + return i; | |
| 213 | + } | |
| 211 | 214 | dist = i - iNearto; |
| 212 | 215 | if( dist<0 ) dist = -dist; |
| 213 | 216 | if( dist<iBestDist ){ |
| 214 | 217 | iBestDist = dist; |
| 215 | 218 | iBest = i; |
| 216 | 219 | } |
| 217 | 220 | } |
| 218 | 221 | } |
| 219 | 222 | if( iBestDist>1000 ) p->nErr++; |
| 223 | + if( iBest>p->mxRail ) p->mxRail = iBest; | |
| 220 | 224 | return iBest; |
| 221 | 225 | } |
| 222 | 226 | |
| 223 | 227 | /* |
| 224 | 228 | ** Compute the complete graph |
| 225 | 229 | */ |
| 226 | 230 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 227 | - GraphRow *pRow, *pDesc, *pDup; | |
| 231 | + GraphRow *pRow, *pDesc, *pDup, *pLoop; | |
| 228 | 232 | int i; |
| 229 | 233 | u32 mask; |
| 230 | 234 | u32 inUse; |
| 235 | + int hasDup = 0; /* True if one or more isDup entries */ | |
| 231 | 236 | |
| 232 | 237 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 233 | 238 | |
| 234 | 239 | /* Initialize all rows */ |
| 235 | 240 | p->nHash = p->nRow*2 + 1; |
| @@ -237,10 +242,11 @@ | ||
| 237 | 242 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 238 | 243 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 239 | 244 | pRow->iRail = -1; |
| 240 | 245 | pRow->mergeOut = -1; |
| 241 | 246 | if( (pDup = hashFind(p, pRow->rid))!=0 ){ |
| 247 | + hasDup = 1; | |
| 242 | 248 | pDup->isDup = 1; |
| 243 | 249 | } |
| 244 | 250 | hashInsert(p, pRow, 1); |
| 245 | 251 | } |
| 246 | 252 | p->mxRail = -1; |
| @@ -301,46 +307,49 @@ | ||
| 301 | 307 | */ |
| 302 | 308 | inUse = (1<<(p->mxRail+1))-1; |
| 303 | 309 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 304 | 310 | int parentRid; |
| 305 | 311 | if( pRow->iRail>=0 ) continue; |
| 306 | - assert( pRow->nParent>0 ); | |
| 307 | - parentRid = pRow->aParent[0]; | |
| 308 | - pDesc = hashFind(p, parentRid); | |
| 309 | - if( pDesc==0 ){ | |
| 310 | - /* Time skew */ | |
| 311 | - pRow->iRail = ++p->mxRail; | |
| 312 | - pRow->railInUse = 1<<pRow->iRail; | |
| 313 | - continue; | |
| 314 | - } | |
| 315 | - if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ | |
| 316 | - pRow->iRail = pDesc->iRail; | |
| 312 | + if( pRow->isDup ){ | |
| 313 | + pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0); | |
| 314 | + pDesc = pRow; | |
| 317 | 315 | }else{ |
| 318 | - pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); | |
| 316 | + assert( pRow->nParent>0 ); | |
| 317 | + parentRid = pRow->aParent[0]; | |
| 318 | + pDesc = hashFind(p, parentRid); | |
| 319 | + if( pDesc==0 ){ | |
| 320 | + /* Time skew */ | |
| 321 | + pRow->iRail = ++p->mxRail; | |
| 322 | + pRow->railInUse = 1<<pRow->iRail; | |
| 323 | + continue; | |
| 324 | + } | |
| 325 | + if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ | |
| 326 | + pRow->iRail = pDesc->iRail; | |
| 327 | + }else{ | |
| 328 | + pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); | |
| 329 | + } | |
| 330 | + pDesc->aiRaiser[pRow->iRail] = pRow->idx; | |
| 319 | 331 | } |
| 320 | - pDesc->aiRaiser[pRow->iRail] = pRow->idx; | |
| 321 | 332 | mask = 1<<pRow->iRail; |
| 322 | 333 | if( pRow->isLeaf ){ |
| 323 | 334 | inUse &= ~mask; |
| 324 | 335 | }else{ |
| 325 | 336 | inUse |= mask; |
| 326 | 337 | } |
| 327 | - for(pDesc = pRow; ; pDesc=pDesc->pNext){ | |
| 328 | - assert( pDesc!=0 ); | |
| 329 | - pDesc->railInUse |= mask; | |
| 330 | - if( pDesc->rid==parentRid ) break; | |
| 338 | + for(pLoop=pRow; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ | |
| 339 | + pLoop->railInUse |= mask; | |
| 331 | 340 | } |
| 341 | + pDesc->railInUse |= mask; | |
| 332 | 342 | } |
| 333 | 343 | |
| 334 | 344 | /* |
| 335 | 345 | ** Insert merge rails and merge arrows |
| 336 | 346 | */ |
| 337 | 347 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 338 | 348 | for(i=1; i<pRow->nParent; i++){ |
| 339 | 349 | int parentRid = pRow->aParent[i]; |
| 340 | - for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; | |
| 341 | - pDesc=pDesc->pNext){} | |
| 350 | + pDesc = hashFind(p, parentRid); | |
| 342 | 351 | if( pDesc==0 ) continue; |
| 343 | 352 | if( pDesc->mergeOut<0 ){ |
| 344 | 353 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 345 | 354 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 346 | 355 | pDesc->mergeUpto = pRow->idx; |
| @@ -348,10 +357,32 @@ | ||
| 348 | 357 | pDesc->railInUse |= mask; |
| 349 | 358 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 350 | 359 | pDesc=pDesc->pNext){ |
| 351 | 360 | pDesc->railInUse |= mask; |
| 352 | 361 | } |
| 362 | + } | |
| 363 | + pRow->mergeIn |= 1<<pDesc->mergeOut; | |
| 364 | + } | |
| 365 | + } | |
| 366 | + | |
| 367 | + /* | |
| 368 | + ** Insert merge rails from primaries to duplicates. | |
| 369 | + */ | |
| 370 | + if( hasDup ){ | |
| 371 | + for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ | |
| 372 | + if( !pRow->isDup ) continue; | |
| 373 | + pDesc = hashFind(p, pRow->rid); | |
| 374 | + assert( pDesc!=0 && pDesc!=pRow ); | |
| 375 | + if( pDesc->mergeOut<0 ){ | |
| 376 | + int iTarget = (pRow->iRail + pDesc->iRail)/2; | |
| 377 | + pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); | |
| 378 | + pDesc->mergeUpto = pRow->idx; | |
| 379 | + mask = 1<<pDesc->mergeOut; | |
| 380 | + pDesc->railInUse |= mask; | |
| 381 | + for(pLoop=pRow->pNext; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ | |
| 382 | + pLoop->railInUse |= mask; | |
| 383 | + } | |
| 353 | 384 | } |
| 354 | 385 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 355 | 386 | } |
| 356 | 387 | } |
| 357 | 388 | |
| 358 | 389 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -205,31 +205,36 @@ | |
| 205 | pRow = pRow->pNext; |
| 206 | } |
| 207 | for(i=0; i<32; i++){ |
| 208 | if( (inUseMask & (1<<i))==0 ){ |
| 209 | int dist; |
| 210 | if( iNearto<=0 ) return i; |
| 211 | dist = i - iNearto; |
| 212 | if( dist<0 ) dist = -dist; |
| 213 | if( dist<iBestDist ){ |
| 214 | iBestDist = dist; |
| 215 | iBest = i; |
| 216 | } |
| 217 | } |
| 218 | } |
| 219 | if( iBestDist>1000 ) p->nErr++; |
| 220 | return iBest; |
| 221 | } |
| 222 | |
| 223 | /* |
| 224 | ** Compute the complete graph |
| 225 | */ |
| 226 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 227 | GraphRow *pRow, *pDesc, *pDup; |
| 228 | int i; |
| 229 | u32 mask; |
| 230 | u32 inUse; |
| 231 | |
| 232 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 233 | |
| 234 | /* Initialize all rows */ |
| 235 | p->nHash = p->nRow*2 + 1; |
| @@ -237,10 +242,11 @@ | |
| 237 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 238 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 239 | pRow->iRail = -1; |
| 240 | pRow->mergeOut = -1; |
| 241 | if( (pDup = hashFind(p, pRow->rid))!=0 ){ |
| 242 | pDup->isDup = 1; |
| 243 | } |
| 244 | hashInsert(p, pRow, 1); |
| 245 | } |
| 246 | p->mxRail = -1; |
| @@ -301,46 +307,49 @@ | |
| 301 | */ |
| 302 | inUse = (1<<(p->mxRail+1))-1; |
| 303 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 304 | int parentRid; |
| 305 | if( pRow->iRail>=0 ) continue; |
| 306 | assert( pRow->nParent>0 ); |
| 307 | parentRid = pRow->aParent[0]; |
| 308 | pDesc = hashFind(p, parentRid); |
| 309 | if( pDesc==0 ){ |
| 310 | /* Time skew */ |
| 311 | pRow->iRail = ++p->mxRail; |
| 312 | pRow->railInUse = 1<<pRow->iRail; |
| 313 | continue; |
| 314 | } |
| 315 | if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ |
| 316 | pRow->iRail = pDesc->iRail; |
| 317 | }else{ |
| 318 | pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); |
| 319 | } |
| 320 | pDesc->aiRaiser[pRow->iRail] = pRow->idx; |
| 321 | mask = 1<<pRow->iRail; |
| 322 | if( pRow->isLeaf ){ |
| 323 | inUse &= ~mask; |
| 324 | }else{ |
| 325 | inUse |= mask; |
| 326 | } |
| 327 | for(pDesc = pRow; ; pDesc=pDesc->pNext){ |
| 328 | assert( pDesc!=0 ); |
| 329 | pDesc->railInUse |= mask; |
| 330 | if( pDesc->rid==parentRid ) break; |
| 331 | } |
| 332 | } |
| 333 | |
| 334 | /* |
| 335 | ** Insert merge rails and merge arrows |
| 336 | */ |
| 337 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 338 | for(i=1; i<pRow->nParent; i++){ |
| 339 | int parentRid = pRow->aParent[i]; |
| 340 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 341 | pDesc=pDesc->pNext){} |
| 342 | if( pDesc==0 ) continue; |
| 343 | if( pDesc->mergeOut<0 ){ |
| 344 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 345 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 346 | pDesc->mergeUpto = pRow->idx; |
| @@ -348,10 +357,32 @@ | |
| 348 | pDesc->railInUse |= mask; |
| 349 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 350 | pDesc=pDesc->pNext){ |
| 351 | pDesc->railInUse |= mask; |
| 352 | } |
| 353 | } |
| 354 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 355 | } |
| 356 | } |
| 357 | |
| 358 |
| --- src/graph.c | |
| +++ src/graph.c | |
| @@ -205,31 +205,36 @@ | |
| 205 | pRow = pRow->pNext; |
| 206 | } |
| 207 | for(i=0; i<32; i++){ |
| 208 | if( (inUseMask & (1<<i))==0 ){ |
| 209 | int dist; |
| 210 | if( iNearto<=0 ){ |
| 211 | if( i>p->mxRail ) p->mxRail = i; |
| 212 | return i; |
| 213 | } |
| 214 | dist = i - iNearto; |
| 215 | if( dist<0 ) dist = -dist; |
| 216 | if( dist<iBestDist ){ |
| 217 | iBestDist = dist; |
| 218 | iBest = i; |
| 219 | } |
| 220 | } |
| 221 | } |
| 222 | if( iBestDist>1000 ) p->nErr++; |
| 223 | if( iBest>p->mxRail ) p->mxRail = iBest; |
| 224 | return iBest; |
| 225 | } |
| 226 | |
| 227 | /* |
| 228 | ** Compute the complete graph |
| 229 | */ |
| 230 | void graph_finish(GraphContext *p, int omitDescenders){ |
| 231 | GraphRow *pRow, *pDesc, *pDup, *pLoop; |
| 232 | int i; |
| 233 | u32 mask; |
| 234 | u32 inUse; |
| 235 | int hasDup = 0; /* True if one or more isDup entries */ |
| 236 | |
| 237 | if( p==0 || p->pFirst==0 || p->nErr ) return; |
| 238 | |
| 239 | /* Initialize all rows */ |
| 240 | p->nHash = p->nRow*2 + 1; |
| @@ -237,10 +242,11 @@ | |
| 242 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 243 | if( pRow->pNext ) pRow->pNext->pPrev = pRow; |
| 244 | pRow->iRail = -1; |
| 245 | pRow->mergeOut = -1; |
| 246 | if( (pDup = hashFind(p, pRow->rid))!=0 ){ |
| 247 | hasDup = 1; |
| 248 | pDup->isDup = 1; |
| 249 | } |
| 250 | hashInsert(p, pRow, 1); |
| 251 | } |
| 252 | p->mxRail = -1; |
| @@ -301,46 +307,49 @@ | |
| 307 | */ |
| 308 | inUse = (1<<(p->mxRail+1))-1; |
| 309 | for(pRow=p->pLast; pRow; pRow=pRow->pPrev){ |
| 310 | int parentRid; |
| 311 | if( pRow->iRail>=0 ) continue; |
| 312 | if( pRow->isDup ){ |
| 313 | pRow->iRail = findFreeRail(p, pRow->idx, pRow->idx, inUse, 0); |
| 314 | pDesc = pRow; |
| 315 | }else{ |
| 316 | assert( pRow->nParent>0 ); |
| 317 | parentRid = pRow->aParent[0]; |
| 318 | pDesc = hashFind(p, parentRid); |
| 319 | if( pDesc==0 ){ |
| 320 | /* Time skew */ |
| 321 | pRow->iRail = ++p->mxRail; |
| 322 | pRow->railInUse = 1<<pRow->iRail; |
| 323 | continue; |
| 324 | } |
| 325 | if( pDesc->aiRaiser[pDesc->iRail]==0 && pDesc->zBranch==pRow->zBranch ){ |
| 326 | pRow->iRail = pDesc->iRail; |
| 327 | }else{ |
| 328 | pRow->iRail = findFreeRail(p, 0, pDesc->idx, inUse, pDesc->iRail); |
| 329 | } |
| 330 | pDesc->aiRaiser[pRow->iRail] = pRow->idx; |
| 331 | } |
| 332 | mask = 1<<pRow->iRail; |
| 333 | if( pRow->isLeaf ){ |
| 334 | inUse &= ~mask; |
| 335 | }else{ |
| 336 | inUse |= mask; |
| 337 | } |
| 338 | for(pLoop=pRow; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ |
| 339 | pLoop->railInUse |= mask; |
| 340 | } |
| 341 | pDesc->railInUse |= mask; |
| 342 | } |
| 343 | |
| 344 | /* |
| 345 | ** Insert merge rails and merge arrows |
| 346 | */ |
| 347 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 348 | for(i=1; i<pRow->nParent; i++){ |
| 349 | int parentRid = pRow->aParent[i]; |
| 350 | pDesc = hashFind(p, parentRid); |
| 351 | if( pDesc==0 ) continue; |
| 352 | if( pDesc->mergeOut<0 ){ |
| 353 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 354 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 355 | pDesc->mergeUpto = pRow->idx; |
| @@ -348,10 +357,32 @@ | |
| 357 | pDesc->railInUse |= mask; |
| 358 | for(pDesc=pRow->pNext; pDesc && pDesc->rid!=parentRid; |
| 359 | pDesc=pDesc->pNext){ |
| 360 | pDesc->railInUse |= mask; |
| 361 | } |
| 362 | } |
| 363 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 364 | } |
| 365 | } |
| 366 | |
| 367 | /* |
| 368 | ** Insert merge rails from primaries to duplicates. |
| 369 | */ |
| 370 | if( hasDup ){ |
| 371 | for(pRow=p->pFirst; pRow; pRow=pRow->pNext){ |
| 372 | if( !pRow->isDup ) continue; |
| 373 | pDesc = hashFind(p, pRow->rid); |
| 374 | assert( pDesc!=0 && pDesc!=pRow ); |
| 375 | if( pDesc->mergeOut<0 ){ |
| 376 | int iTarget = (pRow->iRail + pDesc->iRail)/2; |
| 377 | pDesc->mergeOut = findFreeRail(p, pRow->idx, pDesc->idx, 0, iTarget); |
| 378 | pDesc->mergeUpto = pRow->idx; |
| 379 | mask = 1<<pDesc->mergeOut; |
| 380 | pDesc->railInUse |= mask; |
| 381 | for(pLoop=pRow->pNext; pLoop && pLoop!=pDesc; pLoop=pLoop->pNext){ |
| 382 | pLoop->railInUse |= mask; |
| 383 | } |
| 384 | } |
| 385 | pRow->mergeIn |= 1<<pDesc->mergeOut; |
| 386 | } |
| 387 | } |
| 388 | |
| 389 |