Fossil SCM
Change the name of the "cherry-pick" command to "cherrypick", though retain "cherry-pick" as an alias. Extend the "cherrypick" and "merge" commands so that they will accept multiple check-ins to be merged in all in one go.
Commit
67fe38c4fea1896ed71694c2ca0e86d5ecf9085ceedc2bdc6301fb597c875e5e
Parent
a080751e5c37083…
1 file changed
+69
-18
+69
-18
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -274,28 +274,34 @@ | ||
| 274 | 274 | } |
| 275 | 275 | |
| 276 | 276 | |
| 277 | 277 | /* |
| 278 | 278 | ** COMMAND: merge |
| 279 | -** COMMAND: cherry-pick | |
| 279 | +** COMMAND: cherry-pick alias | |
| 280 | +** COMMAND: cherrypick | |
| 280 | 281 | ** |
| 281 | -** Usage: %fossil merge ?OPTIONS? ?VERSION? | |
| 282 | +** Usage: %fossil merge ?OPTIONS? ?VERSION ...? | |
| 283 | +** Or: %fossil cherrypick ?OPTIONS? ?VERSION ...? | |
| 282 | 284 | ** |
| 283 | 285 | ** The argument VERSION is a version that should be merged into the |
| 284 | 286 | ** current check-out. All changes from VERSION back to the nearest |
| 285 | 287 | ** common ancestor are merged. Except, if either of the --cherrypick |
| 286 | 288 | ** or --backout options are used only the changes associated with the |
| 287 | 289 | ** single check-in VERSION are merged. The --backout option causes |
| 288 | 290 | ** the changes associated with VERSION to be removed from the current |
| 289 | -** check-out rather than added. When invoked with the name | |
| 290 | -** cherry-pick, this command works exactly like merge --cherrypick. | |
| 291 | +** check-out rather than added. When invoked with the name | |
| 292 | +** "cherrypick" instead of "merge", this command works exactly like | |
| 293 | +** "merge --cherrypick". | |
| 291 | 294 | ** |
| 292 | 295 | ** Files which are renamed in the merged-in branch will be renamed in |
| 293 | 296 | ** the current check-out. |
| 294 | 297 | ** |
| 295 | 298 | ** If the VERSION argument is omitted, then Fossil attempts to find |
| 296 | 299 | ** a recent fork on the current branch to merge. |
| 300 | +** | |
| 301 | +** If there are multiple VERSION arguments, then each VERSION is merged | |
| 302 | +** (or cherrypicked) in the order that they appear on the command-line. | |
| 297 | 303 | ** |
| 298 | 304 | ** Options: |
| 299 | 305 | ** --backout Do a reverse cherrypick merge against VERSION. |
| 300 | 306 | ** In other words, back out the changes that were |
| 301 | 307 | ** added by VERSION. |
| @@ -337,11 +343,14 @@ | ||
| 337 | 343 | int showVfileFlag; /* True if the --show-vfile flag is present */ |
| 338 | 344 | int keepMergeFlag; /* True if --keep-merge-files is present */ |
| 339 | 345 | int nConflict = 0; /* Number of conflicts seen */ |
| 340 | 346 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
| 341 | 347 | char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ |
| 342 | - Stmt q; | |
| 348 | + const char *zVersion; /* The VERSION argument */ | |
| 349 | + int bMultiMerge = 0; /* True if there are two or more VERSION arguments */ | |
| 350 | + int nMerge = 0; /* Number of prior merges processed */ | |
| 351 | + Stmt q; /* SQL statment used for merge processing */ | |
| 343 | 352 | |
| 344 | 353 | |
| 345 | 354 | /* Notation: |
| 346 | 355 | ** |
| 347 | 356 | ** V The current check-out |
| @@ -355,11 +364,11 @@ | ||
| 355 | 364 | forceMissingFlag = find_option("force-missing",0,0)!=0; |
| 356 | 365 | if( !verboseFlag ){ |
| 357 | 366 | verboseFlag = find_option("detail",0,0)!=0; /* deprecated */ |
| 358 | 367 | } |
| 359 | 368 | pickFlag = find_option("cherrypick",0,0)!=0; |
| 360 | - if('c'==*g.zCmdName/*called as cherry-pick, possibly a short form*/){ | |
| 369 | + if('c'==*g.zCmdName /*called as cherrypick, possibly a short form*/){ | |
| 361 | 370 | pickFlag = 1; |
| 362 | 371 | } |
| 363 | 372 | integrateFlag = find_option("integrate",0,0)!=0; |
| 364 | 373 | backoutFlag = find_option("backout",0,0)!=0; |
| 365 | 374 | zBinGlob = find_option("binary",0,1); |
| @@ -401,17 +410,40 @@ | ||
| 401 | 410 | if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "merge") ){ |
| 402 | 411 | fossil_fatal("merge abandoned due to sync failure"); |
| 403 | 412 | } |
| 404 | 413 | } |
| 405 | 414 | |
| 406 | - /* Find mid, the artifactID of the version to be merged into the current | |
| 407 | - ** check-out */ | |
| 408 | - if( g.argc==3 ){ | |
| 415 | + /* | |
| 416 | + ** A "multi-merge" means two or more other check-ins are being merged | |
| 417 | + ** into the current check-in. In other words, there are two or more | |
| 418 | + ** VERSION arguments on the command-line. Multi-merge works by doing | |
| 419 | + ** the merges one by one, as long as there are no conflicts. At the | |
| 420 | + ** bottom of this routine, a jump is made back up to this point if there | |
| 421 | + ** are more merges yet to be done and no errors have yet been seen. | |
| 422 | + ** | |
| 423 | + ** Related variables: | |
| 424 | + ** bMultiMerge True if there are one or more merges yet to do | |
| 425 | + ** zVersion The name of the current checking being merged in | |
| 426 | + ** nMerge Number of prior merges | |
| 427 | + */ | |
| 428 | +merge_next_child: | |
| 429 | + | |
| 430 | + /* Find mid, the artifactID of the version to be merged into | |
| 431 | + ** the current check-out. | |
| 432 | + */ | |
| 433 | + if( g.argc>=3 ){ | |
| 434 | + int i; | |
| 409 | 435 | /* Mid is specified as an argument on the command-line */ |
| 410 | - mid = name_to_typed_rid(g.argv[2], "ci"); | |
| 436 | + zVersion = g.argv[2]; | |
| 437 | + mid = name_to_typed_rid(zVersion, "ci"); | |
| 411 | 438 | if( mid==0 || !is_a_version(mid) ){ |
| 412 | - fossil_fatal("not a version: %s", g.argv[2]); | |
| 439 | + fossil_fatal("not a version: %s", zVersion); | |
| 440 | + } | |
| 441 | + bMultiMerge = g.argc>3; | |
| 442 | + if( bMultiMerge ){ | |
| 443 | + for(i=3; i<g.argc; i++) g.argv[i-1] = g.argv[i]; | |
| 444 | + g.argc--; | |
| 413 | 445 | } |
| 414 | 446 | }else if( g.argc==2 ){ |
| 415 | 447 | /* No version specified on the command-line so pick the most recent |
| 416 | 448 | ** leaf that is (1) not the version currently checked out and (2) |
| 417 | 449 | ** has not already been merged into the current check-out and (3) |
| @@ -467,11 +499,11 @@ | ||
| 467 | 499 | fossil_fatal("incompatible options: --integrate and --cherrypick " |
| 468 | 500 | "with --backout"); |
| 469 | 501 | } |
| 470 | 502 | pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); |
| 471 | 503 | if( pid<=0 ){ |
| 472 | - fossil_fatal("cannot find an ancestor for %s", g.argv[2]); | |
| 504 | + fossil_fatal("cannot find an ancestor for %s", zVersion); | |
| 473 | 505 | } |
| 474 | 506 | }else{ |
| 475 | 507 | if( !zPivot ){ |
| 476 | 508 | pivot_set_primary(mid); |
| 477 | 509 | pivot_set_secondary(vid); |
| @@ -481,11 +513,11 @@ | ||
| 481 | 513 | } |
| 482 | 514 | db_finalize(&q); |
| 483 | 515 | pid = pivot_find(0); |
| 484 | 516 | if( pid<=0 ){ |
| 485 | 517 | fossil_fatal("cannot find a common ancestor between the current " |
| 486 | - "check-out and %s", g.argv[2]); | |
| 518 | + "check-out and %s", zVersion); | |
| 487 | 519 | } |
| 488 | 520 | } |
| 489 | 521 | pivot_set_primary(mid); |
| 490 | 522 | pivot_set_secondary(vid); |
| 491 | 523 | nid = pivot_find(1); |
| @@ -508,27 +540,27 @@ | ||
| 508 | 540 | fossil_print("Merge skipped because it is a no-op. " |
| 509 | 541 | " Use --force to override.\n"); |
| 510 | 542 | return; |
| 511 | 543 | } |
| 512 | 544 | if( integrateFlag && !is_a_leaf(mid)){ |
| 513 | - fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]); | |
| 545 | + fossil_warning("ignoring --integrate: %s is not a leaf", zVersion); | |
| 514 | 546 | integrateFlag = 0; |
| 515 | 547 | } |
| 516 | 548 | if( integrateFlag && content_is_private(mid) ){ |
| 517 | 549 | fossil_warning( |
| 518 | 550 | "ignoring --integrate: %s is on a private branch" |
| 519 | 551 | "\n Use \"fossil amend --close\" (after commit) to close the leaf.", |
| 520 | - g.argv[2]); | |
| 552 | + zVersion); | |
| 521 | 553 | integrateFlag = 0; |
| 522 | 554 | } |
| 523 | 555 | if( verboseFlag ){ |
| 524 | 556 | print_checkin_description(mid, 12, |
| 525 | 557 | integrateFlag ? "integrate:" : "merge-from:"); |
| 526 | 558 | print_checkin_description(pid, 12, "baseline:"); |
| 527 | 559 | } |
| 528 | 560 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 529 | - db_begin_transaction(); | |
| 561 | + if( nMerge==0 ) db_begin_transaction(); | |
| 530 | 562 | if( !dryRunFlag ) undo_begin(); |
| 531 | 563 | if( load_vfile_from_rid(mid) && !forceMissingFlag ){ |
| 532 | 564 | fossil_fatal("missing content, unable to merge"); |
| 533 | 565 | } |
| 534 | 566 | if( load_vfile_from_rid(pid) && !forceMissingFlag ){ |
| @@ -1014,16 +1046,30 @@ | ||
| 1014 | 1046 | |
| 1015 | 1047 | /* Report on conflicts |
| 1016 | 1048 | */ |
| 1017 | 1049 | if( nConflict ){ |
| 1018 | 1050 | fossil_warning("WARNING: %d merge conflicts", nConflict); |
| 1051 | + if( bMultiMerge ){ | |
| 1052 | + int i; | |
| 1053 | + Blob msg; | |
| 1054 | + blob_init(&msg, 0, 0); | |
| 1055 | + blob_appendf(&msg, | |
| 1056 | + "The following %ss were not attempted due to prior conflicts:", | |
| 1057 | + pickFlag ? "cherrypick" : backoutFlag ? "backout" : "merge" | |
| 1058 | + ); | |
| 1059 | + for(i=2; i<g.argc; i++){ | |
| 1060 | + blob_appendf(&msg, " %s", g.argv[i]); | |
| 1061 | + } | |
| 1062 | + fossil_warning("%s", blob_str(&msg)); | |
| 1063 | + blob_zero(&msg); | |
| 1064 | + } | |
| 1019 | 1065 | } |
| 1020 | 1066 | if( nOverwrite ){ |
| 1021 | 1067 | fossil_warning("WARNING: %d unmanaged files were overwritten", |
| 1022 | 1068 | nOverwrite); |
| 1023 | 1069 | } |
| 1024 | - if( dryRunFlag ){ | |
| 1070 | + if( dryRunFlag && !bMultiMerge ){ | |
| 1025 | 1071 | fossil_warning("REMINDER: this was a dry run -" |
| 1026 | 1072 | " no files were actually changed."); |
| 1027 | 1073 | } |
| 1028 | 1074 | |
| 1029 | 1075 | /* |
| @@ -1030,11 +1076,11 @@ | ||
| 1030 | 1076 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 1031 | 1077 | */ |
| 1032 | 1078 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 1033 | 1079 | if( pickFlag ){ |
| 1034 | 1080 | vmerge_insert(-1, mid); |
| 1035 | - /* For a cherry-pick merge, make the default check-in comment the same | |
| 1081 | + /* For a cherrypick merge, make the default check-in comment the same | |
| 1036 | 1082 | ** as the check-in comment on the check-in that is being merged in. */ |
| 1037 | 1083 | db_multi_exec( |
| 1038 | 1084 | "REPLACE INTO vvar(name,value)" |
| 1039 | 1085 | " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event" |
| 1040 | 1086 | " WHERE type='ci' AND objid=%d", |
| @@ -1044,9 +1090,14 @@ | ||
| 1044 | 1090 | vmerge_insert(-2, pid); |
| 1045 | 1091 | }else if( integrateFlag ){ |
| 1046 | 1092 | vmerge_insert(-4, mid); |
| 1047 | 1093 | }else{ |
| 1048 | 1094 | vmerge_insert(0, mid); |
| 1095 | + } | |
| 1096 | + if( bMultiMerge && nConflict==0 ){ | |
| 1097 | + nMerge++; | |
| 1098 | + goto merge_next_child; | |
| 1049 | 1099 | } |
| 1050 | 1100 | if( !dryRunFlag ) undo_finish(); |
| 1101 | + | |
| 1051 | 1102 | db_end_transaction(dryRunFlag); |
| 1052 | 1103 | } |
| 1053 | 1104 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -274,28 +274,34 @@ | |
| 274 | } |
| 275 | |
| 276 | |
| 277 | /* |
| 278 | ** COMMAND: merge |
| 279 | ** COMMAND: cherry-pick |
| 280 | ** |
| 281 | ** Usage: %fossil merge ?OPTIONS? ?VERSION? |
| 282 | ** |
| 283 | ** The argument VERSION is a version that should be merged into the |
| 284 | ** current check-out. All changes from VERSION back to the nearest |
| 285 | ** common ancestor are merged. Except, if either of the --cherrypick |
| 286 | ** or --backout options are used only the changes associated with the |
| 287 | ** single check-in VERSION are merged. The --backout option causes |
| 288 | ** the changes associated with VERSION to be removed from the current |
| 289 | ** check-out rather than added. When invoked with the name |
| 290 | ** cherry-pick, this command works exactly like merge --cherrypick. |
| 291 | ** |
| 292 | ** Files which are renamed in the merged-in branch will be renamed in |
| 293 | ** the current check-out. |
| 294 | ** |
| 295 | ** If the VERSION argument is omitted, then Fossil attempts to find |
| 296 | ** a recent fork on the current branch to merge. |
| 297 | ** |
| 298 | ** Options: |
| 299 | ** --backout Do a reverse cherrypick merge against VERSION. |
| 300 | ** In other words, back out the changes that were |
| 301 | ** added by VERSION. |
| @@ -337,11 +343,14 @@ | |
| 337 | int showVfileFlag; /* True if the --show-vfile flag is present */ |
| 338 | int keepMergeFlag; /* True if --keep-merge-files is present */ |
| 339 | int nConflict = 0; /* Number of conflicts seen */ |
| 340 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
| 341 | char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ |
| 342 | Stmt q; |
| 343 | |
| 344 | |
| 345 | /* Notation: |
| 346 | ** |
| 347 | ** V The current check-out |
| @@ -355,11 +364,11 @@ | |
| 355 | forceMissingFlag = find_option("force-missing",0,0)!=0; |
| 356 | if( !verboseFlag ){ |
| 357 | verboseFlag = find_option("detail",0,0)!=0; /* deprecated */ |
| 358 | } |
| 359 | pickFlag = find_option("cherrypick",0,0)!=0; |
| 360 | if('c'==*g.zCmdName/*called as cherry-pick, possibly a short form*/){ |
| 361 | pickFlag = 1; |
| 362 | } |
| 363 | integrateFlag = find_option("integrate",0,0)!=0; |
| 364 | backoutFlag = find_option("backout",0,0)!=0; |
| 365 | zBinGlob = find_option("binary",0,1); |
| @@ -401,17 +410,40 @@ | |
| 401 | if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "merge") ){ |
| 402 | fossil_fatal("merge abandoned due to sync failure"); |
| 403 | } |
| 404 | } |
| 405 | |
| 406 | /* Find mid, the artifactID of the version to be merged into the current |
| 407 | ** check-out */ |
| 408 | if( g.argc==3 ){ |
| 409 | /* Mid is specified as an argument on the command-line */ |
| 410 | mid = name_to_typed_rid(g.argv[2], "ci"); |
| 411 | if( mid==0 || !is_a_version(mid) ){ |
| 412 | fossil_fatal("not a version: %s", g.argv[2]); |
| 413 | } |
| 414 | }else if( g.argc==2 ){ |
| 415 | /* No version specified on the command-line so pick the most recent |
| 416 | ** leaf that is (1) not the version currently checked out and (2) |
| 417 | ** has not already been merged into the current check-out and (3) |
| @@ -467,11 +499,11 @@ | |
| 467 | fossil_fatal("incompatible options: --integrate and --cherrypick " |
| 468 | "with --backout"); |
| 469 | } |
| 470 | pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); |
| 471 | if( pid<=0 ){ |
| 472 | fossil_fatal("cannot find an ancestor for %s", g.argv[2]); |
| 473 | } |
| 474 | }else{ |
| 475 | if( !zPivot ){ |
| 476 | pivot_set_primary(mid); |
| 477 | pivot_set_secondary(vid); |
| @@ -481,11 +513,11 @@ | |
| 481 | } |
| 482 | db_finalize(&q); |
| 483 | pid = pivot_find(0); |
| 484 | if( pid<=0 ){ |
| 485 | fossil_fatal("cannot find a common ancestor between the current " |
| 486 | "check-out and %s", g.argv[2]); |
| 487 | } |
| 488 | } |
| 489 | pivot_set_primary(mid); |
| 490 | pivot_set_secondary(vid); |
| 491 | nid = pivot_find(1); |
| @@ -508,27 +540,27 @@ | |
| 508 | fossil_print("Merge skipped because it is a no-op. " |
| 509 | " Use --force to override.\n"); |
| 510 | return; |
| 511 | } |
| 512 | if( integrateFlag && !is_a_leaf(mid)){ |
| 513 | fossil_warning("ignoring --integrate: %s is not a leaf", g.argv[2]); |
| 514 | integrateFlag = 0; |
| 515 | } |
| 516 | if( integrateFlag && content_is_private(mid) ){ |
| 517 | fossil_warning( |
| 518 | "ignoring --integrate: %s is on a private branch" |
| 519 | "\n Use \"fossil amend --close\" (after commit) to close the leaf.", |
| 520 | g.argv[2]); |
| 521 | integrateFlag = 0; |
| 522 | } |
| 523 | if( verboseFlag ){ |
| 524 | print_checkin_description(mid, 12, |
| 525 | integrateFlag ? "integrate:" : "merge-from:"); |
| 526 | print_checkin_description(pid, 12, "baseline:"); |
| 527 | } |
| 528 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 529 | db_begin_transaction(); |
| 530 | if( !dryRunFlag ) undo_begin(); |
| 531 | if( load_vfile_from_rid(mid) && !forceMissingFlag ){ |
| 532 | fossil_fatal("missing content, unable to merge"); |
| 533 | } |
| 534 | if( load_vfile_from_rid(pid) && !forceMissingFlag ){ |
| @@ -1014,16 +1046,30 @@ | |
| 1014 | |
| 1015 | /* Report on conflicts |
| 1016 | */ |
| 1017 | if( nConflict ){ |
| 1018 | fossil_warning("WARNING: %d merge conflicts", nConflict); |
| 1019 | } |
| 1020 | if( nOverwrite ){ |
| 1021 | fossil_warning("WARNING: %d unmanaged files were overwritten", |
| 1022 | nOverwrite); |
| 1023 | } |
| 1024 | if( dryRunFlag ){ |
| 1025 | fossil_warning("REMINDER: this was a dry run -" |
| 1026 | " no files were actually changed."); |
| 1027 | } |
| 1028 | |
| 1029 | /* |
| @@ -1030,11 +1076,11 @@ | |
| 1030 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 1031 | */ |
| 1032 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 1033 | if( pickFlag ){ |
| 1034 | vmerge_insert(-1, mid); |
| 1035 | /* For a cherry-pick merge, make the default check-in comment the same |
| 1036 | ** as the check-in comment on the check-in that is being merged in. */ |
| 1037 | db_multi_exec( |
| 1038 | "REPLACE INTO vvar(name,value)" |
| 1039 | " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event" |
| 1040 | " WHERE type='ci' AND objid=%d", |
| @@ -1044,9 +1090,14 @@ | |
| 1044 | vmerge_insert(-2, pid); |
| 1045 | }else if( integrateFlag ){ |
| 1046 | vmerge_insert(-4, mid); |
| 1047 | }else{ |
| 1048 | vmerge_insert(0, mid); |
| 1049 | } |
| 1050 | if( !dryRunFlag ) undo_finish(); |
| 1051 | db_end_transaction(dryRunFlag); |
| 1052 | } |
| 1053 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -274,28 +274,34 @@ | |
| 274 | } |
| 275 | |
| 276 | |
| 277 | /* |
| 278 | ** COMMAND: merge |
| 279 | ** COMMAND: cherry-pick alias |
| 280 | ** COMMAND: cherrypick |
| 281 | ** |
| 282 | ** Usage: %fossil merge ?OPTIONS? ?VERSION ...? |
| 283 | ** Or: %fossil cherrypick ?OPTIONS? ?VERSION ...? |
| 284 | ** |
| 285 | ** The argument VERSION is a version that should be merged into the |
| 286 | ** current check-out. All changes from VERSION back to the nearest |
| 287 | ** common ancestor are merged. Except, if either of the --cherrypick |
| 288 | ** or --backout options are used only the changes associated with the |
| 289 | ** single check-in VERSION are merged. The --backout option causes |
| 290 | ** the changes associated with VERSION to be removed from the current |
| 291 | ** check-out rather than added. When invoked with the name |
| 292 | ** "cherrypick" instead of "merge", this command works exactly like |
| 293 | ** "merge --cherrypick". |
| 294 | ** |
| 295 | ** Files which are renamed in the merged-in branch will be renamed in |
| 296 | ** the current check-out. |
| 297 | ** |
| 298 | ** If the VERSION argument is omitted, then Fossil attempts to find |
| 299 | ** a recent fork on the current branch to merge. |
| 300 | ** |
| 301 | ** If there are multiple VERSION arguments, then each VERSION is merged |
| 302 | ** (or cherrypicked) in the order that they appear on the command-line. |
| 303 | ** |
| 304 | ** Options: |
| 305 | ** --backout Do a reverse cherrypick merge against VERSION. |
| 306 | ** In other words, back out the changes that were |
| 307 | ** added by VERSION. |
| @@ -337,11 +343,14 @@ | |
| 343 | int showVfileFlag; /* True if the --show-vfile flag is present */ |
| 344 | int keepMergeFlag; /* True if --keep-merge-files is present */ |
| 345 | int nConflict = 0; /* Number of conflicts seen */ |
| 346 | int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
| 347 | char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ |
| 348 | const char *zVersion; /* The VERSION argument */ |
| 349 | int bMultiMerge = 0; /* True if there are two or more VERSION arguments */ |
| 350 | int nMerge = 0; /* Number of prior merges processed */ |
| 351 | Stmt q; /* SQL statment used for merge processing */ |
| 352 | |
| 353 | |
| 354 | /* Notation: |
| 355 | ** |
| 356 | ** V The current check-out |
| @@ -355,11 +364,11 @@ | |
| 364 | forceMissingFlag = find_option("force-missing",0,0)!=0; |
| 365 | if( !verboseFlag ){ |
| 366 | verboseFlag = find_option("detail",0,0)!=0; /* deprecated */ |
| 367 | } |
| 368 | pickFlag = find_option("cherrypick",0,0)!=0; |
| 369 | if('c'==*g.zCmdName /*called as cherrypick, possibly a short form*/){ |
| 370 | pickFlag = 1; |
| 371 | } |
| 372 | integrateFlag = find_option("integrate",0,0)!=0; |
| 373 | backoutFlag = find_option("backout",0,0)!=0; |
| 374 | zBinGlob = find_option("binary",0,1); |
| @@ -401,17 +410,40 @@ | |
| 410 | if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "merge") ){ |
| 411 | fossil_fatal("merge abandoned due to sync failure"); |
| 412 | } |
| 413 | } |
| 414 | |
| 415 | /* |
| 416 | ** A "multi-merge" means two or more other check-ins are being merged |
| 417 | ** into the current check-in. In other words, there are two or more |
| 418 | ** VERSION arguments on the command-line. Multi-merge works by doing |
| 419 | ** the merges one by one, as long as there are no conflicts. At the |
| 420 | ** bottom of this routine, a jump is made back up to this point if there |
| 421 | ** are more merges yet to be done and no errors have yet been seen. |
| 422 | ** |
| 423 | ** Related variables: |
| 424 | ** bMultiMerge True if there are one or more merges yet to do |
| 425 | ** zVersion The name of the current checking being merged in |
| 426 | ** nMerge Number of prior merges |
| 427 | */ |
| 428 | merge_next_child: |
| 429 | |
| 430 | /* Find mid, the artifactID of the version to be merged into |
| 431 | ** the current check-out. |
| 432 | */ |
| 433 | if( g.argc>=3 ){ |
| 434 | int i; |
| 435 | /* Mid is specified as an argument on the command-line */ |
| 436 | zVersion = g.argv[2]; |
| 437 | mid = name_to_typed_rid(zVersion, "ci"); |
| 438 | if( mid==0 || !is_a_version(mid) ){ |
| 439 | fossil_fatal("not a version: %s", zVersion); |
| 440 | } |
| 441 | bMultiMerge = g.argc>3; |
| 442 | if( bMultiMerge ){ |
| 443 | for(i=3; i<g.argc; i++) g.argv[i-1] = g.argv[i]; |
| 444 | g.argc--; |
| 445 | } |
| 446 | }else if( g.argc==2 ){ |
| 447 | /* No version specified on the command-line so pick the most recent |
| 448 | ** leaf that is (1) not the version currently checked out and (2) |
| 449 | ** has not already been merged into the current check-out and (3) |
| @@ -467,11 +499,11 @@ | |
| 499 | fossil_fatal("incompatible options: --integrate and --cherrypick " |
| 500 | "with --backout"); |
| 501 | } |
| 502 | pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); |
| 503 | if( pid<=0 ){ |
| 504 | fossil_fatal("cannot find an ancestor for %s", zVersion); |
| 505 | } |
| 506 | }else{ |
| 507 | if( !zPivot ){ |
| 508 | pivot_set_primary(mid); |
| 509 | pivot_set_secondary(vid); |
| @@ -481,11 +513,11 @@ | |
| 513 | } |
| 514 | db_finalize(&q); |
| 515 | pid = pivot_find(0); |
| 516 | if( pid<=0 ){ |
| 517 | fossil_fatal("cannot find a common ancestor between the current " |
| 518 | "check-out and %s", zVersion); |
| 519 | } |
| 520 | } |
| 521 | pivot_set_primary(mid); |
| 522 | pivot_set_secondary(vid); |
| 523 | nid = pivot_find(1); |
| @@ -508,27 +540,27 @@ | |
| 540 | fossil_print("Merge skipped because it is a no-op. " |
| 541 | " Use --force to override.\n"); |
| 542 | return; |
| 543 | } |
| 544 | if( integrateFlag && !is_a_leaf(mid)){ |
| 545 | fossil_warning("ignoring --integrate: %s is not a leaf", zVersion); |
| 546 | integrateFlag = 0; |
| 547 | } |
| 548 | if( integrateFlag && content_is_private(mid) ){ |
| 549 | fossil_warning( |
| 550 | "ignoring --integrate: %s is on a private branch" |
| 551 | "\n Use \"fossil amend --close\" (after commit) to close the leaf.", |
| 552 | zVersion); |
| 553 | integrateFlag = 0; |
| 554 | } |
| 555 | if( verboseFlag ){ |
| 556 | print_checkin_description(mid, 12, |
| 557 | integrateFlag ? "integrate:" : "merge-from:"); |
| 558 | print_checkin_description(pid, 12, "baseline:"); |
| 559 | } |
| 560 | vfile_check_signature(vid, CKSIG_ENOTFILE); |
| 561 | if( nMerge==0 ) db_begin_transaction(); |
| 562 | if( !dryRunFlag ) undo_begin(); |
| 563 | if( load_vfile_from_rid(mid) && !forceMissingFlag ){ |
| 564 | fossil_fatal("missing content, unable to merge"); |
| 565 | } |
| 566 | if( load_vfile_from_rid(pid) && !forceMissingFlag ){ |
| @@ -1014,16 +1046,30 @@ | |
| 1046 | |
| 1047 | /* Report on conflicts |
| 1048 | */ |
| 1049 | if( nConflict ){ |
| 1050 | fossil_warning("WARNING: %d merge conflicts", nConflict); |
| 1051 | if( bMultiMerge ){ |
| 1052 | int i; |
| 1053 | Blob msg; |
| 1054 | blob_init(&msg, 0, 0); |
| 1055 | blob_appendf(&msg, |
| 1056 | "The following %ss were not attempted due to prior conflicts:", |
| 1057 | pickFlag ? "cherrypick" : backoutFlag ? "backout" : "merge" |
| 1058 | ); |
| 1059 | for(i=2; i<g.argc; i++){ |
| 1060 | blob_appendf(&msg, " %s", g.argv[i]); |
| 1061 | } |
| 1062 | fossil_warning("%s", blob_str(&msg)); |
| 1063 | blob_zero(&msg); |
| 1064 | } |
| 1065 | } |
| 1066 | if( nOverwrite ){ |
| 1067 | fossil_warning("WARNING: %d unmanaged files were overwritten", |
| 1068 | nOverwrite); |
| 1069 | } |
| 1070 | if( dryRunFlag && !bMultiMerge ){ |
| 1071 | fossil_warning("REMINDER: this was a dry run -" |
| 1072 | " no files were actually changed."); |
| 1073 | } |
| 1074 | |
| 1075 | /* |
| @@ -1030,11 +1076,11 @@ | |
| 1076 | ** Clean up the mid and pid VFILE entries. Then commit the changes. |
| 1077 | */ |
| 1078 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 1079 | if( pickFlag ){ |
| 1080 | vmerge_insert(-1, mid); |
| 1081 | /* For a cherrypick merge, make the default check-in comment the same |
| 1082 | ** as the check-in comment on the check-in that is being merged in. */ |
| 1083 | db_multi_exec( |
| 1084 | "REPLACE INTO vvar(name,value)" |
| 1085 | " SELECT 'ci-comment', coalesce(ecomment,comment) FROM event" |
| 1086 | " WHERE type='ci' AND objid=%d", |
| @@ -1044,9 +1090,14 @@ | |
| 1090 | vmerge_insert(-2, pid); |
| 1091 | }else if( integrateFlag ){ |
| 1092 | vmerge_insert(-4, mid); |
| 1093 | }else{ |
| 1094 | vmerge_insert(0, mid); |
| 1095 | } |
| 1096 | if( bMultiMerge && nConflict==0 ){ |
| 1097 | nMerge++; |
| 1098 | goto merge_next_child; |
| 1099 | } |
| 1100 | if( !dryRunFlag ) undo_finish(); |
| 1101 | |
| 1102 | db_end_transaction(dryRunFlag); |
| 1103 | } |
| 1104 |