Fossil SCM

Issue warnings if a user tries to commit a check-in where the branch has changed. See the discussion at [forum:/forumpost/7f5ae505e4144a0c|forum thread 7f5ae505e4144a0c].

drh 2024-12-04 12:05 trunk merge
Commit 245371782aa30688e1c11a560348ea66f7cde42fc9f2ea91c3f9a4f591422095
2 files changed +69 -8 +12 -3
+69 -8
--- src/checkin.c
+++ src/checkin.c
@@ -2434,10 +2434,12 @@
24342434
Blob ans; /* Answer to continuation prompts */
24352435
char cReply; /* First character of ans */
24362436
int bRecheck = 0; /* Repeat fork and closed-branch checks*/
24372437
int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
24382438
int mxSize;
2439
+ char *zCurBranch = 0; /* The current branch name of checkout */
2440
+ char *zNewBranch = 0; /* The branch name after update */
24392441
24402442
memset(&sCiInfo, 0, sizeof(sCiInfo));
24412443
url_proxy_options();
24422444
/* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
24432445
useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2508,10 +2510,55 @@
25082510
}
25092511
}else{
25102512
privateParent = content_is_private(vid);
25112513
}
25122514
2515
+ user_select();
2516
+ /*
2517
+ ** Check that the user exists.
2518
+ */
2519
+ if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2520
+ fossil_fatal("no such user: %s", g.zLogin);
2521
+ }
2522
+
2523
+ /*
2524
+ ** Detect if the branch name has changed from the parent check-in
2525
+ ** and prompt if necessary
2526
+ **/
2527
+ zCurBranch = db_text(0,
2528
+ " SELECT value FROM tagxref AS tx"
2529
+ " WHERE rid=(SELECT pid"
2530
+ " FROM tagxref LEFT JOIN event ON srcid=objid"
2531
+ " LEFT JOIN plink ON rid=cid"
2532
+ " WHERE rid=%d AND tagxref.tagid=%d"
2533
+ " AND srcid!=origid"
2534
+ " AND tagtype=2 AND coalesce(euser,user)!=%Q)"
2535
+ " AND tx.tagid=%d",
2536
+ vid, TAG_BRANCH, g.zLogin, TAG_BRANCH
2537
+ );
2538
+ if( zCurBranch!=0 && zCurBranch[0]!=0
2539
+ && forceFlag==0
2540
+ && noPrompt==0
2541
+ ){
2542
+ zNewBranch = branch_of_rid(vid);
2543
+ fossil_warning(
2544
+ "WARNING: The parent check-in [%.10s] has been moved from branch\n"
2545
+ " '%s' over to branch '%s'.",
2546
+ rid_to_uuid(vid), zCurBranch, zNewBranch
2547
+ );
2548
+ prompt_user("Commit anyway? (y/N) ", &ans);
2549
+ cReply = blob_str(&ans)[0];
2550
+ blob_reset(&ans);
2551
+ if( cReply!='y' && cReply!='Y' ){
2552
+ fossil_fatal("Abandoning commit because branch has changed");
2553
+ }
2554
+ fossil_free(zNewBranch);
2555
+ fossil_free(zCurBranch);
2556
+ zCurBranch = branch_of_rid(vid);
2557
+ }
2558
+ if( zCurBranch==0 ) zCurBranch = branch_of_rid(vid);
2559
+
25132560
/* Track the "private" status */
25142561
g.markPrivate = privateFlag || privateParent;
25152562
if( privateFlag && !privateParent ){
25162563
/* Apply default branch name ("private") and color ("orange") if not
25172564
** specified otherwise on the command-line, and if the parent is not
@@ -2639,18 +2686,10 @@
26392686
"'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
26402687
}
26412688
db_finalize(&q);
26422689
}
26432690
2644
- user_select();
2645
- /*
2646
- ** Check that the user exists.
2647
- */
2648
- if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2649
- fossil_fatal("no such user: %s", g.zLogin);
2650
- }
2651
-
26522691
hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
26532692
db_begin_transaction();
26542693
db_record_repository_filename(0);
26552694
if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
26562695
fossil_fatal("nothing has changed; use --allow-empty to override");
@@ -2713,10 +2752,32 @@
27132752
" WHERE tagid=%d AND rid=%d AND tagtype>0"
27142753
" AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch))
27152754
){
27162755
fossil_fatal("cannot commit against a closed leaf");
27172756
}
2757
+
2758
+ /* Require confirmation to continue with the check-in if the branch
2759
+ ** has changed and the committer did not provide the same branch
2760
+ */
2761
+ zNewBranch = branch_of_rid(vid);
2762
+ if( fossil_strcmp(zCurBranch, zNewBranch)!=0
2763
+ && fossil_strcmp(sCiInfo.zBranch, zNewBranch)!=0
2764
+ && forceFlag==0
2765
+ && noPrompt==0
2766
+ ){
2767
+ fossil_warning("parent check-in [%.10s] branch changed from '%s' to '%s'",
2768
+ rid_to_uuid(vid), zCurBranch, zNewBranch);
2769
+ prompt_user("continue (y/N)? ", &ans);
2770
+ cReply = blob_str(&ans)[0];
2771
+ blob_reset(&ans);
2772
+ if( cReply!='y' && cReply!='Y' ){
2773
+ fossil_fatal("Abandoning commit because branch has changed");
2774
+ }
2775
+ fossil_free(zCurBranch);
2776
+ zCurBranch = branch_of_rid(vid);
2777
+ }
2778
+ fossil_free(zNewBranch);
27182779
27192780
/* Always exit the loop on the second pass */
27202781
if( bRecheck ) break;
27212782
27222783
27232784
--- src/checkin.c
+++ src/checkin.c
@@ -2434,10 +2434,12 @@
2434 Blob ans; /* Answer to continuation prompts */
2435 char cReply; /* First character of ans */
2436 int bRecheck = 0; /* Repeat fork and closed-branch checks*/
2437 int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
2438 int mxSize;
 
 
2439
2440 memset(&sCiInfo, 0, sizeof(sCiInfo));
2441 url_proxy_options();
2442 /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
2443 useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2508,10 +2510,55 @@
2508 }
2509 }else{
2510 privateParent = content_is_private(vid);
2511 }
2512
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2513 /* Track the "private" status */
2514 g.markPrivate = privateFlag || privateParent;
2515 if( privateFlag && !privateParent ){
2516 /* Apply default branch name ("private") and color ("orange") if not
2517 ** specified otherwise on the command-line, and if the parent is not
@@ -2639,18 +2686,10 @@
2639 "'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
2640 }
2641 db_finalize(&q);
2642 }
2643
2644 user_select();
2645 /*
2646 ** Check that the user exists.
2647 */
2648 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2649 fossil_fatal("no such user: %s", g.zLogin);
2650 }
2651
2652 hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
2653 db_begin_transaction();
2654 db_record_repository_filename(0);
2655 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
2656 fossil_fatal("nothing has changed; use --allow-empty to override");
@@ -2713,10 +2752,32 @@
2713 " WHERE tagid=%d AND rid=%d AND tagtype>0"
2714 " AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch))
2715 ){
2716 fossil_fatal("cannot commit against a closed leaf");
2717 }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
2718
2719 /* Always exit the loop on the second pass */
2720 if( bRecheck ) break;
2721
2722
2723
--- src/checkin.c
+++ src/checkin.c
@@ -2434,10 +2434,12 @@
2434 Blob ans; /* Answer to continuation prompts */
2435 char cReply; /* First character of ans */
2436 int bRecheck = 0; /* Repeat fork and closed-branch checks*/
2437 int bIgnoreSkew = 0; /* --ignore-clock-skew flag */
2438 int mxSize;
2439 char *zCurBranch = 0; /* The current branch name of checkout */
2440 char *zNewBranch = 0; /* The branch name after update */
2441
2442 memset(&sCiInfo, 0, sizeof(sCiInfo));
2443 url_proxy_options();
2444 /* --sha1sum is an undocumented alias for --hash for backwards compatiblity */
2445 useHash = find_option("hash",0,0)!=0 || find_option("sha1sum",0,0)!=0;
@@ -2508,10 +2510,55 @@
2510 }
2511 }else{
2512 privateParent = content_is_private(vid);
2513 }
2514
2515 user_select();
2516 /*
2517 ** Check that the user exists.
2518 */
2519 if( !db_exists("SELECT 1 FROM user WHERE login=%Q", g.zLogin) ){
2520 fossil_fatal("no such user: %s", g.zLogin);
2521 }
2522
2523 /*
2524 ** Detect if the branch name has changed from the parent check-in
2525 ** and prompt if necessary
2526 **/
2527 zCurBranch = db_text(0,
2528 " SELECT value FROM tagxref AS tx"
2529 " WHERE rid=(SELECT pid"
2530 " FROM tagxref LEFT JOIN event ON srcid=objid"
2531 " LEFT JOIN plink ON rid=cid"
2532 " WHERE rid=%d AND tagxref.tagid=%d"
2533 " AND srcid!=origid"
2534 " AND tagtype=2 AND coalesce(euser,user)!=%Q)"
2535 " AND tx.tagid=%d",
2536 vid, TAG_BRANCH, g.zLogin, TAG_BRANCH
2537 );
2538 if( zCurBranch!=0 && zCurBranch[0]!=0
2539 && forceFlag==0
2540 && noPrompt==0
2541 ){
2542 zNewBranch = branch_of_rid(vid);
2543 fossil_warning(
2544 "WARNING: The parent check-in [%.10s] has been moved from branch\n"
2545 " '%s' over to branch '%s'.",
2546 rid_to_uuid(vid), zCurBranch, zNewBranch
2547 );
2548 prompt_user("Commit anyway? (y/N) ", &ans);
2549 cReply = blob_str(&ans)[0];
2550 blob_reset(&ans);
2551 if( cReply!='y' && cReply!='Y' ){
2552 fossil_fatal("Abandoning commit because branch has changed");
2553 }
2554 fossil_free(zNewBranch);
2555 fossil_free(zCurBranch);
2556 zCurBranch = branch_of_rid(vid);
2557 }
2558 if( zCurBranch==0 ) zCurBranch = branch_of_rid(vid);
2559
2560 /* Track the "private" status */
2561 g.markPrivate = privateFlag || privateParent;
2562 if( privateFlag && !privateParent ){
2563 /* Apply default branch name ("private") and color ("orange") if not
2564 ** specified otherwise on the command-line, and if the parent is not
@@ -2639,18 +2686,10 @@
2686 "'%s' was renamed to '%s'", zFrom, zTo, zFrom, zTo);
2687 }
2688 db_finalize(&q);
2689 }
2690
 
 
 
 
 
 
 
 
2691 hasChanges = unsaved_changes(useHash ? CKSIG_HASH : 0);
2692 db_begin_transaction();
2693 db_record_repository_filename(0);
2694 if( hasChanges==0 && !isAMerge && !allowEmpty && !forceFlag ){
2695 fossil_fatal("nothing has changed; use --allow-empty to override");
@@ -2713,10 +2752,32 @@
2752 " WHERE tagid=%d AND rid=%d AND tagtype>0"
2753 " AND value=%Q", TAG_BRANCH, vid, sCiInfo.zBranch))
2754 ){
2755 fossil_fatal("cannot commit against a closed leaf");
2756 }
2757
2758 /* Require confirmation to continue with the check-in if the branch
2759 ** has changed and the committer did not provide the same branch
2760 */
2761 zNewBranch = branch_of_rid(vid);
2762 if( fossil_strcmp(zCurBranch, zNewBranch)!=0
2763 && fossil_strcmp(sCiInfo.zBranch, zNewBranch)!=0
2764 && forceFlag==0
2765 && noPrompt==0
2766 ){
2767 fossil_warning("parent check-in [%.10s] branch changed from '%s' to '%s'",
2768 rid_to_uuid(vid), zCurBranch, zNewBranch);
2769 prompt_user("continue (y/N)? ", &ans);
2770 cReply = blob_str(&ans)[0];
2771 blob_reset(&ans);
2772 if( cReply!='y' && cReply!='Y' ){
2773 fossil_fatal("Abandoning commit because branch has changed");
2774 }
2775 fossil_free(zCurBranch);
2776 zCurBranch = branch_of_rid(vid);
2777 }
2778 fossil_free(zNewBranch);
2779
2780 /* Always exit the loop on the second pass */
2781 if( bRecheck ) break;
2782
2783
2784
+12 -3
--- src/update.c
+++ src/update.c
@@ -132,10 +132,13 @@
132132
int nUpdate = 0; /* Number of changes of any kind */
133133
int bNosync = 0; /* --nosync. Omit the auto-sync */
134134
int width; /* Width of printed comment lines */
135135
Stmt mtimeXfer; /* Statement to transfer mtimes */
136136
const char *zWidth; /* Width option string value */
137
+ const char *zCurBrName; /* Current branch name */
138
+ const char *zNewBrName; /* New branch name */
139
+ const char *zBrChgMsg = ""; /* Message to display if branch changes */
137140
138141
if( !internalUpdate ){
139142
undo_capture_command_line();
140143
url_proxy_options();
141144
}
@@ -163,10 +166,11 @@
163166
/* We should be done with options.. */
164167
verify_all_options();
165168
166169
db_must_be_within_tree();
167170
vid = db_lget_int("checkout", 0);
171
+ zCurBrName = branch_of_rid(vid);
168172
user_select();
169173
if( !dryRunFlag && !internalUpdate && !bNosync ){
170174
if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "update") ){
171175
fossil_fatal("update abandoned due to sync failure");
172176
}
@@ -563,20 +567,25 @@
563567
free(zFullNewPath);
564568
}
565569
db_finalize(&q);
566570
db_finalize(&mtimeXfer);
567571
fossil_print("%.79c\n",'-');
572
+ zNewBrName = branch_of_rid(tid);
573
+ if( g.argc<3 && fossil_strcmp(zCurBrName, zNewBrName)!=0 ){
574
+ zBrChgMsg = mprintf(" Branch changed from %s to %s.",
575
+ zCurBrName, zNewBrName);
576
+ }
568577
if( nUpdate==0 ){
569578
show_common_info(tid, "checkout:", 1, 0);
570
- fossil_print("%-13s None. Already up-to-date\n", "changes:");
579
+ fossil_print("%-13s None. Already up-to-date.%s\n", "changes:", zBrChgMsg);
571580
}else{
572581
fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid),
573582
db_text("", "SELECT datetime(mtime) || ' UTC' FROM event "
574583
" WHERE objid=%d", vid));
575584
show_common_info(tid, "updated-to:", 1, 0);
576
- fossil_print("%-13s %d file%s modified.\n", "changes:",
577
- nUpdate, nUpdate>1 ? "s" : "");
585
+ fossil_print("%-13s %d file%s modified.%s\n", "changes:",
586
+ nUpdate, nUpdate>1 ? "s" : "", zBrChgMsg);
578587
}
579588
580589
/* Report on conflicts
581590
*/
582591
if( !dryRunFlag ){
583592
--- src/update.c
+++ src/update.c
@@ -132,10 +132,13 @@
132 int nUpdate = 0; /* Number of changes of any kind */
133 int bNosync = 0; /* --nosync. Omit the auto-sync */
134 int width; /* Width of printed comment lines */
135 Stmt mtimeXfer; /* Statement to transfer mtimes */
136 const char *zWidth; /* Width option string value */
 
 
 
137
138 if( !internalUpdate ){
139 undo_capture_command_line();
140 url_proxy_options();
141 }
@@ -163,10 +166,11 @@
163 /* We should be done with options.. */
164 verify_all_options();
165
166 db_must_be_within_tree();
167 vid = db_lget_int("checkout", 0);
 
168 user_select();
169 if( !dryRunFlag && !internalUpdate && !bNosync ){
170 if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "update") ){
171 fossil_fatal("update abandoned due to sync failure");
172 }
@@ -563,20 +567,25 @@
563 free(zFullNewPath);
564 }
565 db_finalize(&q);
566 db_finalize(&mtimeXfer);
567 fossil_print("%.79c\n",'-');
 
 
 
 
 
568 if( nUpdate==0 ){
569 show_common_info(tid, "checkout:", 1, 0);
570 fossil_print("%-13s None. Already up-to-date\n", "changes:");
571 }else{
572 fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid),
573 db_text("", "SELECT datetime(mtime) || ' UTC' FROM event "
574 " WHERE objid=%d", vid));
575 show_common_info(tid, "updated-to:", 1, 0);
576 fossil_print("%-13s %d file%s modified.\n", "changes:",
577 nUpdate, nUpdate>1 ? "s" : "");
578 }
579
580 /* Report on conflicts
581 */
582 if( !dryRunFlag ){
583
--- src/update.c
+++ src/update.c
@@ -132,10 +132,13 @@
132 int nUpdate = 0; /* Number of changes of any kind */
133 int bNosync = 0; /* --nosync. Omit the auto-sync */
134 int width; /* Width of printed comment lines */
135 Stmt mtimeXfer; /* Statement to transfer mtimes */
136 const char *zWidth; /* Width option string value */
137 const char *zCurBrName; /* Current branch name */
138 const char *zNewBrName; /* New branch name */
139 const char *zBrChgMsg = ""; /* Message to display if branch changes */
140
141 if( !internalUpdate ){
142 undo_capture_command_line();
143 url_proxy_options();
144 }
@@ -163,10 +166,11 @@
166 /* We should be done with options.. */
167 verify_all_options();
168
169 db_must_be_within_tree();
170 vid = db_lget_int("checkout", 0);
171 zCurBrName = branch_of_rid(vid);
172 user_select();
173 if( !dryRunFlag && !internalUpdate && !bNosync ){
174 if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "update") ){
175 fossil_fatal("update abandoned due to sync failure");
176 }
@@ -563,20 +567,25 @@
567 free(zFullNewPath);
568 }
569 db_finalize(&q);
570 db_finalize(&mtimeXfer);
571 fossil_print("%.79c\n",'-');
572 zNewBrName = branch_of_rid(tid);
573 if( g.argc<3 && fossil_strcmp(zCurBrName, zNewBrName)!=0 ){
574 zBrChgMsg = mprintf(" Branch changed from %s to %s.",
575 zCurBrName, zNewBrName);
576 }
577 if( nUpdate==0 ){
578 show_common_info(tid, "checkout:", 1, 0);
579 fossil_print("%-13s None. Already up-to-date.%s\n", "changes:", zBrChgMsg);
580 }else{
581 fossil_print("%-13s %.40s %s\n", "updated-from:", rid_to_uuid(vid),
582 db_text("", "SELECT datetime(mtime) || ' UTC' FROM event "
583 " WHERE objid=%d", vid));
584 show_common_info(tid, "updated-to:", 1, 0);
585 fossil_print("%-13s %d file%s modified.%s\n", "changes:",
586 nUpdate, nUpdate>1 ? "s" : "", zBrChgMsg);
587 }
588
589 /* Report on conflicts
590 */
591 if( !dryRunFlag ){
592

Keyboard Shortcuts

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