Fossil SCM
Prevent check-ins against a closed leaf. Add the --branch and --bgcolor options to the "ci" and "commit" commands.
Commit
4ac75b9107e129c7393f8c8608d9abb58f903d5c
Parent
cd965de68208d33…
1 file changed
+64
-9
+64
-9
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -367,23 +367,40 @@ | ||
| 367 | 367 | |
| 368 | 368 | /* |
| 369 | 369 | ** COMMAND: ci |
| 370 | 370 | ** COMMAND: commit |
| 371 | 371 | ** |
| 372 | -** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...? | |
| 372 | +** Usage: %fossil commit ?OPTIONS? ?FILE...? | |
| 373 | 373 | ** |
| 374 | 374 | ** Create a new version containing all of the changes in the current |
| 375 | 375 | ** checkout. You will be prompted to enter a check-in comment unless |
| 376 | 376 | ** the "-m" option is used to specify a comment line. You will be |
| 377 | 377 | ** prompted for your GPG passphrase in order to sign the new manifest |
| 378 | 378 | ** unless the "--nosign" options is used. All files that have |
| 379 | 379 | ** changed will be committed unless some subset of files is specified |
| 380 | 380 | ** on the command line. |
| 381 | +** | |
| 382 | +** The --branch option followed by a branch name cases the new check-in | |
| 383 | +** to be placed in the named branch. The --bgcolor option can be followed | |
| 384 | +** by a color name (ex: '#ffc0c0') to specify the background color of | |
| 385 | +** entries in the new branch when shown in the web timeline interface. | |
| 386 | +** | |
| 387 | +** A check-in is not permitted to fork unless the --force or -f | |
| 388 | +** option appears. A check-in is not allowed against a closed check-in. | |
| 389 | +** | |
| 390 | +** Options: | |
| 391 | +** | |
| 392 | +** --comment|-m COMMENT-TEXT | |
| 393 | +** --branch NEW-BRANCH-NAME | |
| 394 | +** --bgcolor COLOR | |
| 395 | +** --nosign | |
| 396 | +** --force|-f | |
| 397 | +** | |
| 381 | 398 | */ |
| 382 | 399 | void commit_cmd(void){ |
| 383 | 400 | int rc; |
| 384 | - int vid, nrid, nvid, wouldFork=0; | |
| 401 | + int vid, nrid, nvid; | |
| 385 | 402 | Blob comment; |
| 386 | 403 | const char *zComment; |
| 387 | 404 | Stmt q; |
| 388 | 405 | Stmt q2; |
| 389 | 406 | char *zUuid, *zDate; |
| @@ -390,31 +407,35 @@ | ||
| 390 | 407 | int noSign = 0; /* True to omit signing the manifest using GPG */ |
| 391 | 408 | int isAMerge = 0; /* True if checking in a merge */ |
| 392 | 409 | int forceFlag = 0; /* Force a fork */ |
| 393 | 410 | char *zManifestFile; /* Name of the manifest file */ |
| 394 | 411 | int nBasename; /* Length of "g.zLocalRoot/" */ |
| 412 | + const char *zBranch; /* Create a new branch with this name */ | |
| 413 | + const char *zBgColor; /* Set background color when branching */ | |
| 395 | 414 | Blob filename; /* complete filename */ |
| 396 | 415 | Blob manifest; |
| 397 | 416 | Blob muuid; /* Manifest uuid */ |
| 398 | 417 | Blob mcksum; /* Self-checksum on the manifest */ |
| 399 | 418 | Blob cksum1, cksum2; /* Before and after commit checksums */ |
| 400 | 419 | Blob cksum1b; /* Checksum recorded in the manifest */ |
| 401 | 420 | |
| 402 | 421 | url_proxy_options(); |
| 403 | - noSign = find_option("nosign","",0)!=0; | |
| 422 | + noSign = find_option("nosign",0,0)!=0; | |
| 404 | 423 | zComment = find_option("comment","m",1); |
| 405 | 424 | forceFlag = find_option("force", "f", 0)!=0; |
| 425 | + zBranch = find_option("branch","b",1); | |
| 426 | + zBgColor = find_option("bgcolor",0,1); | |
| 406 | 427 | db_must_be_within_tree(); |
| 407 | 428 | noSign = db_get_boolean("omitsign", 0)|noSign; |
| 408 | 429 | if( db_get_boolean("clearsign", 1)==0 ){ noSign = 1; } |
| 409 | 430 | verify_all_options(); |
| 410 | 431 | |
| 411 | 432 | /* |
| 412 | 433 | ** Autosync if requested. |
| 413 | 434 | */ |
| 414 | 435 | autosync(AUTOSYNC_PULL); |
| 415 | - | |
| 436 | + | |
| 416 | 437 | /* There are two ways this command may be executed. If there are |
| 417 | 438 | ** no arguments following the word "commit", then all modified files |
| 418 | 439 | ** in the checked out directory are committed. If one or more arguments |
| 419 | 440 | ** follows "commit", then only those files are committed. |
| 420 | 441 | ** |
| @@ -458,16 +479,28 @@ | ||
| 458 | 479 | fossil_panic("file %s has not changed", blob_str(&unmodified)); |
| 459 | 480 | } |
| 460 | 481 | } |
| 461 | 482 | |
| 462 | 483 | vid = db_lget_int("checkout", 0); |
| 463 | - if( !is_a_leaf(vid) ){ | |
| 464 | - wouldFork=1; | |
| 465 | - if( forceFlag==0 ){ | |
| 466 | - fossil_fatal("would fork. \"update\" first or use -f or --force."); | |
| 467 | - } | |
| 484 | + | |
| 485 | + /* | |
| 486 | + ** Do not allow a commit that will cause a fork unless the --force flag | |
| 487 | + ** is used. | |
| 488 | + */ | |
| 489 | + if( zBranch==0 && forceFlag==0 && !is_a_leaf(vid) ){ | |
| 490 | + fossil_fatal("would fork. \"update\" first or use -f or --force."); | |
| 491 | + } | |
| 492 | + | |
| 493 | + /* | |
| 494 | + ** Do not allow a commit against a closed leaf | |
| 495 | + */ | |
| 496 | + if( db_exists("SELECT 1 FROM tagxref" | |
| 497 | + " WHERE tagid=%d AND rid=%d AND tagtype>0", | |
| 498 | + TAG_CLOSED, vid) ){ | |
| 499 | + fossil_fatal("cannot commit against a closed leaf"); | |
| 468 | 500 | } |
| 501 | + | |
| 469 | 502 | vfile_aggregate_checksum_disk(vid, &cksum1); |
| 470 | 503 | if( zComment ){ |
| 471 | 504 | blob_zero(&comment); |
| 472 | 505 | blob_append(&comment, zComment, -1); |
| 473 | 506 | }else{ |
| @@ -565,10 +598,32 @@ | ||
| 565 | 598 | } |
| 566 | 599 | db_reset(&q2); |
| 567 | 600 | |
| 568 | 601 | blob_appendf(&manifest, "\n"); |
| 569 | 602 | blob_appendf(&manifest, "R %b\n", &cksum1); |
| 603 | + if( zBranch && zBranch[0] ){ | |
| 604 | + Stmt q; | |
| 605 | + if( zBgColor && zBgColor[0] ){ | |
| 606 | + blob_appendf(&manifest, "T *bgcolor * %F\n", zBgColor); | |
| 607 | + } | |
| 608 | + blob_appendf(&manifest, "T *branch * %F\n", zBranch); | |
| 609 | + blob_appendf(&manifest, "T *sym-%F *\n", zBranch); | |
| 610 | + | |
| 611 | + /* Cancel all other symbolic tags */ | |
| 612 | + db_prepare(&q, | |
| 613 | + "SELECT tagname FROM tagxref, tag" | |
| 614 | + " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid" | |
| 615 | + " AND tagtype>0 AND tagname GLOB 'sym-*'" | |
| 616 | + " AND tagname!='sym-'||%Q" | |
| 617 | + " ORDER BY tagname", | |
| 618 | + vid, zBranch); | |
| 619 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 620 | + const char *zTag = db_column_text(&q, 0); | |
| 621 | + blob_appendf(&manifest, "T -%s *\n", zTag); | |
| 622 | + } | |
| 623 | + db_finalize(&q); | |
| 624 | + } | |
| 570 | 625 | blob_appendf(&manifest, "U %F\n", g.zLogin); |
| 571 | 626 | md5sum_blob(&manifest, &mcksum); |
| 572 | 627 | blob_appendf(&manifest, "Z %b\n", &mcksum); |
| 573 | 628 | zManifestFile = mprintf("%smanifest", g.zLocalRoot); |
| 574 | 629 | if( !noSign && clearsign(&manifest, &manifest) ){ |
| 575 | 630 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -367,23 +367,40 @@ | |
| 367 | |
| 368 | /* |
| 369 | ** COMMAND: ci |
| 370 | ** COMMAND: commit |
| 371 | ** |
| 372 | ** Usage: %fossil commit ?-m COMMENT? ?--nosign? ?FILE...? |
| 373 | ** |
| 374 | ** Create a new version containing all of the changes in the current |
| 375 | ** checkout. You will be prompted to enter a check-in comment unless |
| 376 | ** the "-m" option is used to specify a comment line. You will be |
| 377 | ** prompted for your GPG passphrase in order to sign the new manifest |
| 378 | ** unless the "--nosign" options is used. All files that have |
| 379 | ** changed will be committed unless some subset of files is specified |
| 380 | ** on the command line. |
| 381 | */ |
| 382 | void commit_cmd(void){ |
| 383 | int rc; |
| 384 | int vid, nrid, nvid, wouldFork=0; |
| 385 | Blob comment; |
| 386 | const char *zComment; |
| 387 | Stmt q; |
| 388 | Stmt q2; |
| 389 | char *zUuid, *zDate; |
| @@ -390,31 +407,35 @@ | |
| 390 | int noSign = 0; /* True to omit signing the manifest using GPG */ |
| 391 | int isAMerge = 0; /* True if checking in a merge */ |
| 392 | int forceFlag = 0; /* Force a fork */ |
| 393 | char *zManifestFile; /* Name of the manifest file */ |
| 394 | int nBasename; /* Length of "g.zLocalRoot/" */ |
| 395 | Blob filename; /* complete filename */ |
| 396 | Blob manifest; |
| 397 | Blob muuid; /* Manifest uuid */ |
| 398 | Blob mcksum; /* Self-checksum on the manifest */ |
| 399 | Blob cksum1, cksum2; /* Before and after commit checksums */ |
| 400 | Blob cksum1b; /* Checksum recorded in the manifest */ |
| 401 | |
| 402 | url_proxy_options(); |
| 403 | noSign = find_option("nosign","",0)!=0; |
| 404 | zComment = find_option("comment","m",1); |
| 405 | forceFlag = find_option("force", "f", 0)!=0; |
| 406 | db_must_be_within_tree(); |
| 407 | noSign = db_get_boolean("omitsign", 0)|noSign; |
| 408 | if( db_get_boolean("clearsign", 1)==0 ){ noSign = 1; } |
| 409 | verify_all_options(); |
| 410 | |
| 411 | /* |
| 412 | ** Autosync if requested. |
| 413 | */ |
| 414 | autosync(AUTOSYNC_PULL); |
| 415 | |
| 416 | /* There are two ways this command may be executed. If there are |
| 417 | ** no arguments following the word "commit", then all modified files |
| 418 | ** in the checked out directory are committed. If one or more arguments |
| 419 | ** follows "commit", then only those files are committed. |
| 420 | ** |
| @@ -458,16 +479,28 @@ | |
| 458 | fossil_panic("file %s has not changed", blob_str(&unmodified)); |
| 459 | } |
| 460 | } |
| 461 | |
| 462 | vid = db_lget_int("checkout", 0); |
| 463 | if( !is_a_leaf(vid) ){ |
| 464 | wouldFork=1; |
| 465 | if( forceFlag==0 ){ |
| 466 | fossil_fatal("would fork. \"update\" first or use -f or --force."); |
| 467 | } |
| 468 | } |
| 469 | vfile_aggregate_checksum_disk(vid, &cksum1); |
| 470 | if( zComment ){ |
| 471 | blob_zero(&comment); |
| 472 | blob_append(&comment, zComment, -1); |
| 473 | }else{ |
| @@ -565,10 +598,32 @@ | |
| 565 | } |
| 566 | db_reset(&q2); |
| 567 | |
| 568 | blob_appendf(&manifest, "\n"); |
| 569 | blob_appendf(&manifest, "R %b\n", &cksum1); |
| 570 | blob_appendf(&manifest, "U %F\n", g.zLogin); |
| 571 | md5sum_blob(&manifest, &mcksum); |
| 572 | blob_appendf(&manifest, "Z %b\n", &mcksum); |
| 573 | zManifestFile = mprintf("%smanifest", g.zLocalRoot); |
| 574 | if( !noSign && clearsign(&manifest, &manifest) ){ |
| 575 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -367,23 +367,40 @@ | |
| 367 | |
| 368 | /* |
| 369 | ** COMMAND: ci |
| 370 | ** COMMAND: commit |
| 371 | ** |
| 372 | ** Usage: %fossil commit ?OPTIONS? ?FILE...? |
| 373 | ** |
| 374 | ** Create a new version containing all of the changes in the current |
| 375 | ** checkout. You will be prompted to enter a check-in comment unless |
| 376 | ** the "-m" option is used to specify a comment line. You will be |
| 377 | ** prompted for your GPG passphrase in order to sign the new manifest |
| 378 | ** unless the "--nosign" options is used. All files that have |
| 379 | ** changed will be committed unless some subset of files is specified |
| 380 | ** on the command line. |
| 381 | ** |
| 382 | ** The --branch option followed by a branch name cases the new check-in |
| 383 | ** to be placed in the named branch. The --bgcolor option can be followed |
| 384 | ** by a color name (ex: '#ffc0c0') to specify the background color of |
| 385 | ** entries in the new branch when shown in the web timeline interface. |
| 386 | ** |
| 387 | ** A check-in is not permitted to fork unless the --force or -f |
| 388 | ** option appears. A check-in is not allowed against a closed check-in. |
| 389 | ** |
| 390 | ** Options: |
| 391 | ** |
| 392 | ** --comment|-m COMMENT-TEXT |
| 393 | ** --branch NEW-BRANCH-NAME |
| 394 | ** --bgcolor COLOR |
| 395 | ** --nosign |
| 396 | ** --force|-f |
| 397 | ** |
| 398 | */ |
| 399 | void commit_cmd(void){ |
| 400 | int rc; |
| 401 | int vid, nrid, nvid; |
| 402 | Blob comment; |
| 403 | const char *zComment; |
| 404 | Stmt q; |
| 405 | Stmt q2; |
| 406 | char *zUuid, *zDate; |
| @@ -390,31 +407,35 @@ | |
| 407 | int noSign = 0; /* True to omit signing the manifest using GPG */ |
| 408 | int isAMerge = 0; /* True if checking in a merge */ |
| 409 | int forceFlag = 0; /* Force a fork */ |
| 410 | char *zManifestFile; /* Name of the manifest file */ |
| 411 | int nBasename; /* Length of "g.zLocalRoot/" */ |
| 412 | const char *zBranch; /* Create a new branch with this name */ |
| 413 | const char *zBgColor; /* Set background color when branching */ |
| 414 | Blob filename; /* complete filename */ |
| 415 | Blob manifest; |
| 416 | Blob muuid; /* Manifest uuid */ |
| 417 | Blob mcksum; /* Self-checksum on the manifest */ |
| 418 | Blob cksum1, cksum2; /* Before and after commit checksums */ |
| 419 | Blob cksum1b; /* Checksum recorded in the manifest */ |
| 420 | |
| 421 | url_proxy_options(); |
| 422 | noSign = find_option("nosign",0,0)!=0; |
| 423 | zComment = find_option("comment","m",1); |
| 424 | forceFlag = find_option("force", "f", 0)!=0; |
| 425 | zBranch = find_option("branch","b",1); |
| 426 | zBgColor = find_option("bgcolor",0,1); |
| 427 | db_must_be_within_tree(); |
| 428 | noSign = db_get_boolean("omitsign", 0)|noSign; |
| 429 | if( db_get_boolean("clearsign", 1)==0 ){ noSign = 1; } |
| 430 | verify_all_options(); |
| 431 | |
| 432 | /* |
| 433 | ** Autosync if requested. |
| 434 | */ |
| 435 | autosync(AUTOSYNC_PULL); |
| 436 | |
| 437 | /* There are two ways this command may be executed. If there are |
| 438 | ** no arguments following the word "commit", then all modified files |
| 439 | ** in the checked out directory are committed. If one or more arguments |
| 440 | ** follows "commit", then only those files are committed. |
| 441 | ** |
| @@ -458,16 +479,28 @@ | |
| 479 | fossil_panic("file %s has not changed", blob_str(&unmodified)); |
| 480 | } |
| 481 | } |
| 482 | |
| 483 | vid = db_lget_int("checkout", 0); |
| 484 | |
| 485 | /* |
| 486 | ** Do not allow a commit that will cause a fork unless the --force flag |
| 487 | ** is used. |
| 488 | */ |
| 489 | if( zBranch==0 && forceFlag==0 && !is_a_leaf(vid) ){ |
| 490 | fossil_fatal("would fork. \"update\" first or use -f or --force."); |
| 491 | } |
| 492 | |
| 493 | /* |
| 494 | ** Do not allow a commit against a closed leaf |
| 495 | */ |
| 496 | if( db_exists("SELECT 1 FROM tagxref" |
| 497 | " WHERE tagid=%d AND rid=%d AND tagtype>0", |
| 498 | TAG_CLOSED, vid) ){ |
| 499 | fossil_fatal("cannot commit against a closed leaf"); |
| 500 | } |
| 501 | |
| 502 | vfile_aggregate_checksum_disk(vid, &cksum1); |
| 503 | if( zComment ){ |
| 504 | blob_zero(&comment); |
| 505 | blob_append(&comment, zComment, -1); |
| 506 | }else{ |
| @@ -565,10 +598,32 @@ | |
| 598 | } |
| 599 | db_reset(&q2); |
| 600 | |
| 601 | blob_appendf(&manifest, "\n"); |
| 602 | blob_appendf(&manifest, "R %b\n", &cksum1); |
| 603 | if( zBranch && zBranch[0] ){ |
| 604 | Stmt q; |
| 605 | if( zBgColor && zBgColor[0] ){ |
| 606 | blob_appendf(&manifest, "T *bgcolor * %F\n", zBgColor); |
| 607 | } |
| 608 | blob_appendf(&manifest, "T *branch * %F\n", zBranch); |
| 609 | blob_appendf(&manifest, "T *sym-%F *\n", zBranch); |
| 610 | |
| 611 | /* Cancel all other symbolic tags */ |
| 612 | db_prepare(&q, |
| 613 | "SELECT tagname FROM tagxref, tag" |
| 614 | " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid" |
| 615 | " AND tagtype>0 AND tagname GLOB 'sym-*'" |
| 616 | " AND tagname!='sym-'||%Q" |
| 617 | " ORDER BY tagname", |
| 618 | vid, zBranch); |
| 619 | while( db_step(&q)==SQLITE_ROW ){ |
| 620 | const char *zTag = db_column_text(&q, 0); |
| 621 | blob_appendf(&manifest, "T -%s *\n", zTag); |
| 622 | } |
| 623 | db_finalize(&q); |
| 624 | } |
| 625 | blob_appendf(&manifest, "U %F\n", g.zLogin); |
| 626 | md5sum_blob(&manifest, &mcksum); |
| 627 | blob_appendf(&manifest, "Z %b\n", &mcksum); |
| 628 | zManifestFile = mprintf("%smanifest", g.zLocalRoot); |
| 629 | if( !noSign && clearsign(&manifest, &manifest) ){ |
| 630 |