Fossil SCM
Enhance the "fossil merge" command so that if the VERSION argument is omitted, Fossil tries to merge any forks of the current branch.
Commit
9ee47de25474d706b9b953076324cebe9a4bf1dd
Parent
1dd493231a854cd…
1 file changed
+75
-8
+75
-8
| --- src/merge.c | ||
| +++ src/merge.c | ||
| @@ -57,19 +57,22 @@ | ||
| 57 | 57 | |
| 58 | 58 | |
| 59 | 59 | /* |
| 60 | 60 | ** COMMAND: merge |
| 61 | 61 | ** |
| 62 | -** Usage: %fossil merge ?OPTIONS? VERSION | |
| 62 | +** Usage: %fossil merge ?OPTIONS? ?VERSION? | |
| 63 | 63 | ** |
| 64 | 64 | ** The argument VERSION is a version that should be merged into the |
| 65 | 65 | ** current checkout. All changes from VERSION back to the nearest |
| 66 | 66 | ** common ancestor are merged. Except, if either of the --cherrypick or |
| 67 | 67 | ** --backout options are used only the changes associated with the |
| 68 | 68 | ** single check-in VERSION are merged. The --backout option causes |
| 69 | 69 | ** the changes associated with VERSION to be removed from the current |
| 70 | 70 | ** checkout rather than added. |
| 71 | +** | |
| 72 | +** If the VERSION argument is omitted, then Fossil attempts to find | |
| 73 | +** a recent fork on the current branch to merge. | |
| 71 | 74 | ** |
| 72 | 75 | ** Only file content is merged. The result continues to use the |
| 73 | 76 | ** file and directory names from the current checkout even if those |
| 74 | 77 | ** names might have been changed in the branch being merged in. |
| 75 | 78 | ** |
| @@ -131,24 +134,88 @@ | ||
| 131 | 134 | zBinGlob = find_option("binary",0,1); |
| 132 | 135 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 133 | 136 | forceFlag = find_option("force","f",0)!=0; |
| 134 | 137 | zPivot = find_option("baseline",0,1); |
| 135 | 138 | capture_case_sensitive_option(); |
| 136 | - if( g.argc!=3 ){ | |
| 137 | - usage("VERSION"); | |
| 138 | - } | |
| 139 | + verify_all_options(); | |
| 139 | 140 | db_must_be_within_tree(); |
| 140 | 141 | caseSensitive = filenames_are_case_sensitive(); |
| 141 | 142 | if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
| 142 | 143 | vid = db_lget_int("checkout", 0); |
| 143 | 144 | if( vid==0 ){ |
| 144 | 145 | fossil_fatal("nothing is checked out"); |
| 145 | 146 | } |
| 146 | - mid = name_to_typed_rid(g.argv[2], "ci"); | |
| 147 | - if( mid==0 || !is_a_version(mid) ){ | |
| 148 | - fossil_fatal("not a version: %s", g.argv[2]); | |
| 147 | + | |
| 148 | + /* Find mid, the artifactID of the version to be merged into the current | |
| 149 | + ** check-out */ | |
| 150 | + if( g.argc==3 ){ | |
| 151 | + /* Mid is specified as an argument on the command-line */ | |
| 152 | + mid = name_to_typed_rid(g.argv[2], "ci"); | |
| 153 | + if( mid==0 || !is_a_version(mid) ){ | |
| 154 | + fossil_fatal("not a version: %s", g.argv[2]); | |
| 155 | + } | |
| 156 | + }else if( g.argc==2 ){ | |
| 157 | + /* No version specified on the command-line so pick the most recent | |
| 158 | + ** leaf that is (1) not the version currently checked out and (2) | |
| 159 | + ** has not already been merged into the current checkout and (3) | |
| 160 | + ** the leaf is not closed and (4) the leaf is in the same branch | |
| 161 | + ** as the current checkout. | |
| 162 | + */ | |
| 163 | + Stmt q; | |
| 164 | + if( pickFlag || backoutFlag ){ | |
| 165 | + fossil_fatal("cannot use --cherrypick or --backout with a fork merge"); | |
| 166 | + } | |
| 167 | + mid = db_int(0, | |
| 168 | + "SELECT leaf.rid" | |
| 169 | + " FROM leaf, event" | |
| 170 | + " WHERE leaf.rid=event.objid" | |
| 171 | + " AND leaf.rid!=%d" /* Constraint (1) */ | |
| 172 | + " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */ | |
| 173 | + " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */ | |
| 174 | + " WHERE rid=leaf.rid" | |
| 175 | + " AND tagid=%d" | |
| 176 | + " AND tagtype>0)" | |
| 177 | + " AND (SELECT value FROM tagxref" /* Constraint (4) */ | |
| 178 | + " WHERE tagid=%d AND rid=%d" | |
| 179 | + " AND tagtype>0" | |
| 180 | + " ORDER BY mtime DESC LIMIT 1) = " | |
| 181 | + " (SELECT value FROM tagxref" | |
| 182 | + " WHERE tagid=%d AND rid=leaf.rid" | |
| 183 | + " AND tagtype>0" | |
| 184 | + " ORDER BY mtime DESC LIMIT 1)" | |
| 185 | + " ORDER BY event.mtime DESC LIMIT 1", | |
| 186 | + vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH | |
| 187 | + ); | |
| 188 | + if( mid==0 ){ | |
| 189 | + fossil_fatal("no unmerged forks of branch \"%s\"", | |
| 190 | + db_text(0, "SELECT value FROM tagxref" | |
| 191 | + " WHERE tagid=%d AND rid=%d" | |
| 192 | + " AND tagtype>0" | |
| 193 | + " ORDER BY mtime DESC LIMIT 1", TAG_BRANCH, vid) | |
| 194 | + ); | |
| 195 | + } | |
| 196 | + db_prepare(&q, | |
| 197 | + "SELECT blob.uuid," | |
| 198 | + " datetime(event.mtime,'localtime')," | |
| 199 | + " coalesce(ecomment, comment)," | |
| 200 | + " coalesce(euser, user)" | |
| 201 | + " FROM event, blob" | |
| 202 | + " WHERE event.objid=%d AND blob.rid=%d", | |
| 203 | + mid, mid | |
| 204 | + ); | |
| 205 | + if( db_step(&q)==SQLITE_ROW ){ | |
| 206 | + char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", | |
| 207 | + db_column_text(&q, 0), db_column_text(&q, 1), | |
| 208 | + db_column_text(&q, 3), db_column_text(&q, 2)); | |
| 209 | + comment_print(zCom, 0, 79); | |
| 210 | + fossil_free(zCom); | |
| 211 | + } | |
| 212 | + db_finalize(&q); | |
| 213 | + }else{ | |
| 214 | + usage("?OPTIONS? ?VERSION?"); | |
| 149 | 215 | } |
| 216 | + | |
| 150 | 217 | if( zPivot ){ |
| 151 | 218 | pid = name_to_typed_rid(zPivot, "ci"); |
| 152 | 219 | if( pid==0 || !is_a_version(pid) ){ |
| 153 | 220 | fossil_fatal("not a version: %s", zPivot); |
| 154 | 221 | } |
| @@ -347,11 +414,11 @@ | ||
| 347 | 414 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 348 | 415 | ); |
| 349 | 416 | while( db_step(&q)==SQLITE_ROW ){ |
| 350 | 417 | int idm = db_column_int(&q, 0); |
| 351 | 418 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 352 | - fossil_warning("WARNING - no common ancestor: %s\n", zName); | |
| 419 | + fossil_warning("WARNING - no common ancestor: %s", zName); | |
| 353 | 420 | free(zName); |
| 354 | 421 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 355 | 422 | } |
| 356 | 423 | db_finalize(&q); |
| 357 | 424 | |
| 358 | 425 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -57,19 +57,22 @@ | |
| 57 | |
| 58 | |
| 59 | /* |
| 60 | ** COMMAND: merge |
| 61 | ** |
| 62 | ** Usage: %fossil merge ?OPTIONS? VERSION |
| 63 | ** |
| 64 | ** The argument VERSION is a version that should be merged into the |
| 65 | ** current checkout. All changes from VERSION back to the nearest |
| 66 | ** common ancestor are merged. Except, if either of the --cherrypick or |
| 67 | ** --backout options are used only the changes associated with the |
| 68 | ** single check-in VERSION are merged. The --backout option causes |
| 69 | ** the changes associated with VERSION to be removed from the current |
| 70 | ** checkout rather than added. |
| 71 | ** |
| 72 | ** Only file content is merged. The result continues to use the |
| 73 | ** file and directory names from the current checkout even if those |
| 74 | ** names might have been changed in the branch being merged in. |
| 75 | ** |
| @@ -131,24 +134,88 @@ | |
| 131 | zBinGlob = find_option("binary",0,1); |
| 132 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 133 | forceFlag = find_option("force","f",0)!=0; |
| 134 | zPivot = find_option("baseline",0,1); |
| 135 | capture_case_sensitive_option(); |
| 136 | if( g.argc!=3 ){ |
| 137 | usage("VERSION"); |
| 138 | } |
| 139 | db_must_be_within_tree(); |
| 140 | caseSensitive = filenames_are_case_sensitive(); |
| 141 | if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
| 142 | vid = db_lget_int("checkout", 0); |
| 143 | if( vid==0 ){ |
| 144 | fossil_fatal("nothing is checked out"); |
| 145 | } |
| 146 | mid = name_to_typed_rid(g.argv[2], "ci"); |
| 147 | if( mid==0 || !is_a_version(mid) ){ |
| 148 | fossil_fatal("not a version: %s", g.argv[2]); |
| 149 | } |
| 150 | if( zPivot ){ |
| 151 | pid = name_to_typed_rid(zPivot, "ci"); |
| 152 | if( pid==0 || !is_a_version(pid) ){ |
| 153 | fossil_fatal("not a version: %s", zPivot); |
| 154 | } |
| @@ -347,11 +414,11 @@ | |
| 347 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 348 | ); |
| 349 | while( db_step(&q)==SQLITE_ROW ){ |
| 350 | int idm = db_column_int(&q, 0); |
| 351 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 352 | fossil_warning("WARNING - no common ancestor: %s\n", zName); |
| 353 | free(zName); |
| 354 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 355 | } |
| 356 | db_finalize(&q); |
| 357 | |
| 358 |
| --- src/merge.c | |
| +++ src/merge.c | |
| @@ -57,19 +57,22 @@ | |
| 57 | |
| 58 | |
| 59 | /* |
| 60 | ** COMMAND: merge |
| 61 | ** |
| 62 | ** Usage: %fossil merge ?OPTIONS? ?VERSION? |
| 63 | ** |
| 64 | ** The argument VERSION is a version that should be merged into the |
| 65 | ** current checkout. All changes from VERSION back to the nearest |
| 66 | ** common ancestor are merged. Except, if either of the --cherrypick or |
| 67 | ** --backout options are used only the changes associated with the |
| 68 | ** single check-in VERSION are merged. The --backout option causes |
| 69 | ** the changes associated with VERSION to be removed from the current |
| 70 | ** checkout rather than added. |
| 71 | ** |
| 72 | ** If the VERSION argument is omitted, then Fossil attempts to find |
| 73 | ** a recent fork on the current branch to merge. |
| 74 | ** |
| 75 | ** Only file content is merged. The result continues to use the |
| 76 | ** file and directory names from the current checkout even if those |
| 77 | ** names might have been changed in the branch being merged in. |
| 78 | ** |
| @@ -131,24 +134,88 @@ | |
| 134 | zBinGlob = find_option("binary",0,1); |
| 135 | nochangeFlag = find_option("nochange","n",0)!=0; |
| 136 | forceFlag = find_option("force","f",0)!=0; |
| 137 | zPivot = find_option("baseline",0,1); |
| 138 | capture_case_sensitive_option(); |
| 139 | verify_all_options(); |
| 140 | db_must_be_within_tree(); |
| 141 | caseSensitive = filenames_are_case_sensitive(); |
| 142 | if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
| 143 | vid = db_lget_int("checkout", 0); |
| 144 | if( vid==0 ){ |
| 145 | fossil_fatal("nothing is checked out"); |
| 146 | } |
| 147 | |
| 148 | /* Find mid, the artifactID of the version to be merged into the current |
| 149 | ** check-out */ |
| 150 | if( g.argc==3 ){ |
| 151 | /* Mid is specified as an argument on the command-line */ |
| 152 | mid = name_to_typed_rid(g.argv[2], "ci"); |
| 153 | if( mid==0 || !is_a_version(mid) ){ |
| 154 | fossil_fatal("not a version: %s", g.argv[2]); |
| 155 | } |
| 156 | }else if( g.argc==2 ){ |
| 157 | /* No version specified on the command-line so pick the most recent |
| 158 | ** leaf that is (1) not the version currently checked out and (2) |
| 159 | ** has not already been merged into the current checkout and (3) |
| 160 | ** the leaf is not closed and (4) the leaf is in the same branch |
| 161 | ** as the current checkout. |
| 162 | */ |
| 163 | Stmt q; |
| 164 | if( pickFlag || backoutFlag ){ |
| 165 | fossil_fatal("cannot use --cherrypick or --backout with a fork merge"); |
| 166 | } |
| 167 | mid = db_int(0, |
| 168 | "SELECT leaf.rid" |
| 169 | " FROM leaf, event" |
| 170 | " WHERE leaf.rid=event.objid" |
| 171 | " AND leaf.rid!=%d" /* Constraint (1) */ |
| 172 | " AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */ |
| 173 | " AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */ |
| 174 | " WHERE rid=leaf.rid" |
| 175 | " AND tagid=%d" |
| 176 | " AND tagtype>0)" |
| 177 | " AND (SELECT value FROM tagxref" /* Constraint (4) */ |
| 178 | " WHERE tagid=%d AND rid=%d" |
| 179 | " AND tagtype>0" |
| 180 | " ORDER BY mtime DESC LIMIT 1) = " |
| 181 | " (SELECT value FROM tagxref" |
| 182 | " WHERE tagid=%d AND rid=leaf.rid" |
| 183 | " AND tagtype>0" |
| 184 | " ORDER BY mtime DESC LIMIT 1)" |
| 185 | " ORDER BY event.mtime DESC LIMIT 1", |
| 186 | vid, TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH |
| 187 | ); |
| 188 | if( mid==0 ){ |
| 189 | fossil_fatal("no unmerged forks of branch \"%s\"", |
| 190 | db_text(0, "SELECT value FROM tagxref" |
| 191 | " WHERE tagid=%d AND rid=%d" |
| 192 | " AND tagtype>0" |
| 193 | " ORDER BY mtime DESC LIMIT 1", TAG_BRANCH, vid) |
| 194 | ); |
| 195 | } |
| 196 | db_prepare(&q, |
| 197 | "SELECT blob.uuid," |
| 198 | " datetime(event.mtime,'localtime')," |
| 199 | " coalesce(ecomment, comment)," |
| 200 | " coalesce(euser, user)" |
| 201 | " FROM event, blob" |
| 202 | " WHERE event.objid=%d AND blob.rid=%d", |
| 203 | mid, mid |
| 204 | ); |
| 205 | if( db_step(&q)==SQLITE_ROW ){ |
| 206 | char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", |
| 207 | db_column_text(&q, 0), db_column_text(&q, 1), |
| 208 | db_column_text(&q, 3), db_column_text(&q, 2)); |
| 209 | comment_print(zCom, 0, 79); |
| 210 | fossil_free(zCom); |
| 211 | } |
| 212 | db_finalize(&q); |
| 213 | }else{ |
| 214 | usage("?OPTIONS? ?VERSION?"); |
| 215 | } |
| 216 | |
| 217 | if( zPivot ){ |
| 218 | pid = name_to_typed_rid(zPivot, "ci"); |
| 219 | if( pid==0 || !is_a_version(pid) ){ |
| 220 | fossil_fatal("not a version: %s", zPivot); |
| 221 | } |
| @@ -347,11 +414,11 @@ | |
| 414 | "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0" |
| 415 | ); |
| 416 | while( db_step(&q)==SQLITE_ROW ){ |
| 417 | int idm = db_column_int(&q, 0); |
| 418 | char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm); |
| 419 | fossil_warning("WARNING - no common ancestor: %s", zName); |
| 420 | free(zName); |
| 421 | db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm); |
| 422 | } |
| 423 | db_finalize(&q); |
| 424 | |
| 425 |