Fossil SCM
Add the --keep option to the "open" and "checkout" commands. Added the --latest option to "checkout". These changes allow one to shift the baseline version and repository of a checkout without changing any files in the checkout.
Commit
915bfd99fec69f978f199412bdb2c3da54a24156
Parent
7b32e45bd765551…
2 files changed
+62
-22
+20
-5
+62
-22
| --- src/checkout.c | ||
| +++ src/checkout.c | ||
| @@ -135,63 +135,104 @@ | ||
| 135 | 135 | |
| 136 | 136 | /* |
| 137 | 137 | ** COMMAND: checkout |
| 138 | 138 | ** COMMAND: co |
| 139 | 139 | ** |
| 140 | -** Usage: %fossil checkout VERSION ?-f|--force? | |
| 140 | +** Usage: %fossil checkout VERSION ?-f|--force? ?--keep? | |
| 141 | 141 | ** |
| 142 | 142 | ** Check out a version specified on the command-line. This command |
| 143 | -** will not overwrite edited files in the current checkout unless | |
| 144 | -** the --force option appears on the command-line. | |
| 143 | +** will abort if there are edited files in the current checkout unless | |
| 144 | +** the --force option appears on the command-line. The --keep option | |
| 145 | +** leaves files on disk unchanged, except the manifest and manifest.uuid | |
| 146 | +** files. | |
| 147 | +** | |
| 148 | +** The --latest flag can be used in place of VERSION to checkout the | |
| 149 | +** latest version in the repository. | |
| 145 | 150 | ** |
| 146 | 151 | ** See also the "update" command. |
| 147 | 152 | */ |
| 148 | 153 | void checkout_cmd(void){ |
| 149 | - int forceFlag; | |
| 150 | - int noWrite; | |
| 154 | + int forceFlag; /* Force checkout even if edits exist */ | |
| 155 | + int keepFlag; /* Do not change any files on disk */ | |
| 156 | + int latestFlag; /* Checkout the latest version */ | |
| 157 | + char *zVers; /* Version to checkout */ | |
| 151 | 158 | int vid, prior; |
| 152 | 159 | Blob cksum1, cksum1b, cksum2; |
| 153 | 160 | |
| 154 | 161 | db_must_be_within_tree(); |
| 155 | 162 | db_begin_transaction(); |
| 156 | 163 | forceFlag = find_option("force","f",0)!=0; |
| 157 | - noWrite = find_option("dontwrite",0,0)!=0; | |
| 158 | - if( g.argc!=3 ) usage("?--force? VERSION"); | |
| 164 | + keepFlag = find_option("keep",0,0)!=0; | |
| 165 | + latestFlag = find_option("latest",0,0)!=0; | |
| 166 | + if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ | |
| 167 | + usage("VERSION|--latest ?--force? ?--keep?"); | |
| 168 | + } | |
| 159 | 169 | if( !forceFlag && unsaved_changes()==1 ){ |
| 160 | 170 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 161 | 171 | } |
| 162 | 172 | if( forceFlag ){ |
| 163 | 173 | db_multi_exec("DELETE FROM vfile"); |
| 164 | 174 | prior = 0; |
| 165 | 175 | }else{ |
| 166 | 176 | prior = db_lget_int("checkout",0); |
| 167 | 177 | } |
| 168 | - vid = load_vfile(g.argv[2]); | |
| 178 | + if( latestFlag ){ | |
| 179 | + compute_leaves(db_lget_int("checkout",0), 1); | |
| 180 | + zVers = db_text(0, "SELECT uuid FROM leaves, event, blob" | |
| 181 | + " WHERE event.objid=leaves.rid AND blob.rid=leaves.rid" | |
| 182 | + " ORDER BY event.mtime DESC"); | |
| 183 | + if( zVers==0 ){ | |
| 184 | + fossil_fatal("cannot local \"latest\" checkout"); | |
| 185 | + } | |
| 186 | + }else{ | |
| 187 | + zVers = g.argv[2]; | |
| 188 | + } | |
| 189 | + vid = load_vfile(zVers); | |
| 169 | 190 | if( prior==vid ){ |
| 170 | 191 | return; |
| 171 | 192 | } |
| 172 | - if( !noWrite ){ | |
| 193 | + if( !keepFlag ){ | |
| 173 | 194 | uncheckout(prior); |
| 174 | 195 | } |
| 175 | 196 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 176 | - if( !noWrite ){ | |
| 197 | + if( !keepFlag ){ | |
| 177 | 198 | vfile_to_disk(vid, 0, 1); |
| 178 | - manifest_to_disk(vid); | |
| 179 | - db_lset_int("checkout", vid); | |
| 180 | - undo_reset(); | |
| 181 | 199 | } |
| 200 | + manifest_to_disk(vid); | |
| 201 | + db_lset_int("checkout", vid); | |
| 202 | + undo_reset(); | |
| 182 | 203 | db_multi_exec("DELETE FROM vmerge"); |
| 183 | - vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); | |
| 184 | - vfile_aggregate_checksum_disk(vid, &cksum2); | |
| 185 | - if( blob_compare(&cksum1, &cksum2) ){ | |
| 186 | - printf("WARNING: manifest checksum does not agree with disk\n"); | |
| 187 | - } | |
| 188 | - if( blob_compare(&cksum1, &cksum1b) ){ | |
| 189 | - printf("WARNING: manifest checksum does not agree with manifest\n"); | |
| 204 | + if( !keepFlag ){ | |
| 205 | + vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); | |
| 206 | + vfile_aggregate_checksum_disk(vid, &cksum2); | |
| 207 | + if( blob_compare(&cksum1, &cksum2) ){ | |
| 208 | + printf("WARNING: manifest checksum does not agree with disk\n"); | |
| 209 | + } | |
| 210 | + if( blob_compare(&cksum1, &cksum1b) ){ | |
| 211 | + printf("WARNING: manifest checksum does not agree with manifest\n"); | |
| 212 | + } | |
| 190 | 213 | } |
| 191 | 214 | db_end_transaction(0); |
| 192 | 215 | } |
| 216 | + | |
| 217 | +/* | |
| 218 | +** Unlink the local database file | |
| 219 | +*/ | |
| 220 | +void unlink_local_database(void){ | |
| 221 | + static const char *azFile[] = { | |
| 222 | + "%s_FOSSIL_", | |
| 223 | + "%s_FOSSIL_-journal", | |
| 224 | + "%s.fos", | |
| 225 | + "%s.fos-journal", | |
| 226 | + }; | |
| 227 | + int i; | |
| 228 | + for(i=0; i<sizeof(azFile)/sizeof(azFile[0]); i++){ | |
| 229 | + char *z = mprintf(azFile[i], g.zLocalRoot); | |
| 230 | + unlink(z); | |
| 231 | + free(z); | |
| 232 | + } | |
| 233 | +} | |
| 193 | 234 | |
| 194 | 235 | /* |
| 195 | 236 | ** COMMAND: close |
| 196 | 237 | ** |
| 197 | 238 | ** Usage: %fossil close ?-f|--force? |
| @@ -205,8 +246,7 @@ | ||
| 205 | 246 | db_must_be_within_tree(); |
| 206 | 247 | if( !forceFlag && unsaved_changes()==1 ){ |
| 207 | 248 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 208 | 249 | } |
| 209 | 250 | db_close(); |
| 210 | - unlink(mprintf("%s_FOSSIL_", g.zLocalRoot)); | |
| 211 | - unlink(mprintf("%s_FOSSIL_-journal", g.zLocalRoot)); | |
| 251 | + unlink_local_database(); | |
| 212 | 252 | } |
| 213 | 253 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -135,63 +135,104 @@ | |
| 135 | |
| 136 | /* |
| 137 | ** COMMAND: checkout |
| 138 | ** COMMAND: co |
| 139 | ** |
| 140 | ** Usage: %fossil checkout VERSION ?-f|--force? |
| 141 | ** |
| 142 | ** Check out a version specified on the command-line. This command |
| 143 | ** will not overwrite edited files in the current checkout unless |
| 144 | ** the --force option appears on the command-line. |
| 145 | ** |
| 146 | ** See also the "update" command. |
| 147 | */ |
| 148 | void checkout_cmd(void){ |
| 149 | int forceFlag; |
| 150 | int noWrite; |
| 151 | int vid, prior; |
| 152 | Blob cksum1, cksum1b, cksum2; |
| 153 | |
| 154 | db_must_be_within_tree(); |
| 155 | db_begin_transaction(); |
| 156 | forceFlag = find_option("force","f",0)!=0; |
| 157 | noWrite = find_option("dontwrite",0,0)!=0; |
| 158 | if( g.argc!=3 ) usage("?--force? VERSION"); |
| 159 | if( !forceFlag && unsaved_changes()==1 ){ |
| 160 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 161 | } |
| 162 | if( forceFlag ){ |
| 163 | db_multi_exec("DELETE FROM vfile"); |
| 164 | prior = 0; |
| 165 | }else{ |
| 166 | prior = db_lget_int("checkout",0); |
| 167 | } |
| 168 | vid = load_vfile(g.argv[2]); |
| 169 | if( prior==vid ){ |
| 170 | return; |
| 171 | } |
| 172 | if( !noWrite ){ |
| 173 | uncheckout(prior); |
| 174 | } |
| 175 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 176 | if( !noWrite ){ |
| 177 | vfile_to_disk(vid, 0, 1); |
| 178 | manifest_to_disk(vid); |
| 179 | db_lset_int("checkout", vid); |
| 180 | undo_reset(); |
| 181 | } |
| 182 | db_multi_exec("DELETE FROM vmerge"); |
| 183 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 184 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 185 | if( blob_compare(&cksum1, &cksum2) ){ |
| 186 | printf("WARNING: manifest checksum does not agree with disk\n"); |
| 187 | } |
| 188 | if( blob_compare(&cksum1, &cksum1b) ){ |
| 189 | printf("WARNING: manifest checksum does not agree with manifest\n"); |
| 190 | } |
| 191 | db_end_transaction(0); |
| 192 | } |
| 193 | |
| 194 | /* |
| 195 | ** COMMAND: close |
| 196 | ** |
| 197 | ** Usage: %fossil close ?-f|--force? |
| @@ -205,8 +246,7 @@ | |
| 205 | db_must_be_within_tree(); |
| 206 | if( !forceFlag && unsaved_changes()==1 ){ |
| 207 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 208 | } |
| 209 | db_close(); |
| 210 | unlink(mprintf("%s_FOSSIL_", g.zLocalRoot)); |
| 211 | unlink(mprintf("%s_FOSSIL_-journal", g.zLocalRoot)); |
| 212 | } |
| 213 |
| --- src/checkout.c | |
| +++ src/checkout.c | |
| @@ -135,63 +135,104 @@ | |
| 135 | |
| 136 | /* |
| 137 | ** COMMAND: checkout |
| 138 | ** COMMAND: co |
| 139 | ** |
| 140 | ** Usage: %fossil checkout VERSION ?-f|--force? ?--keep? |
| 141 | ** |
| 142 | ** Check out a version specified on the command-line. This command |
| 143 | ** will abort if there are edited files in the current checkout unless |
| 144 | ** the --force option appears on the command-line. The --keep option |
| 145 | ** leaves files on disk unchanged, except the manifest and manifest.uuid |
| 146 | ** files. |
| 147 | ** |
| 148 | ** The --latest flag can be used in place of VERSION to checkout the |
| 149 | ** latest version in the repository. |
| 150 | ** |
| 151 | ** See also the "update" command. |
| 152 | */ |
| 153 | void checkout_cmd(void){ |
| 154 | int forceFlag; /* Force checkout even if edits exist */ |
| 155 | int keepFlag; /* Do not change any files on disk */ |
| 156 | int latestFlag; /* Checkout the latest version */ |
| 157 | char *zVers; /* Version to checkout */ |
| 158 | int vid, prior; |
| 159 | Blob cksum1, cksum1b, cksum2; |
| 160 | |
| 161 | db_must_be_within_tree(); |
| 162 | db_begin_transaction(); |
| 163 | forceFlag = find_option("force","f",0)!=0; |
| 164 | keepFlag = find_option("keep",0,0)!=0; |
| 165 | latestFlag = find_option("latest",0,0)!=0; |
| 166 | if( (latestFlag!=0 && g.argc!=2) || (latestFlag==0 && g.argc!=3) ){ |
| 167 | usage("VERSION|--latest ?--force? ?--keep?"); |
| 168 | } |
| 169 | if( !forceFlag && unsaved_changes()==1 ){ |
| 170 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 171 | } |
| 172 | if( forceFlag ){ |
| 173 | db_multi_exec("DELETE FROM vfile"); |
| 174 | prior = 0; |
| 175 | }else{ |
| 176 | prior = db_lget_int("checkout",0); |
| 177 | } |
| 178 | if( latestFlag ){ |
| 179 | compute_leaves(db_lget_int("checkout",0), 1); |
| 180 | zVers = db_text(0, "SELECT uuid FROM leaves, event, blob" |
| 181 | " WHERE event.objid=leaves.rid AND blob.rid=leaves.rid" |
| 182 | " ORDER BY event.mtime DESC"); |
| 183 | if( zVers==0 ){ |
| 184 | fossil_fatal("cannot local \"latest\" checkout"); |
| 185 | } |
| 186 | }else{ |
| 187 | zVers = g.argv[2]; |
| 188 | } |
| 189 | vid = load_vfile(zVers); |
| 190 | if( prior==vid ){ |
| 191 | return; |
| 192 | } |
| 193 | if( !keepFlag ){ |
| 194 | uncheckout(prior); |
| 195 | } |
| 196 | db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
| 197 | if( !keepFlag ){ |
| 198 | vfile_to_disk(vid, 0, 1); |
| 199 | } |
| 200 | manifest_to_disk(vid); |
| 201 | db_lset_int("checkout", vid); |
| 202 | undo_reset(); |
| 203 | db_multi_exec("DELETE FROM vmerge"); |
| 204 | if( !keepFlag ){ |
| 205 | vfile_aggregate_checksum_manifest(vid, &cksum1, &cksum1b); |
| 206 | vfile_aggregate_checksum_disk(vid, &cksum2); |
| 207 | if( blob_compare(&cksum1, &cksum2) ){ |
| 208 | printf("WARNING: manifest checksum does not agree with disk\n"); |
| 209 | } |
| 210 | if( blob_compare(&cksum1, &cksum1b) ){ |
| 211 | printf("WARNING: manifest checksum does not agree with manifest\n"); |
| 212 | } |
| 213 | } |
| 214 | db_end_transaction(0); |
| 215 | } |
| 216 | |
| 217 | /* |
| 218 | ** Unlink the local database file |
| 219 | */ |
| 220 | void unlink_local_database(void){ |
| 221 | static const char *azFile[] = { |
| 222 | "%s_FOSSIL_", |
| 223 | "%s_FOSSIL_-journal", |
| 224 | "%s.fos", |
| 225 | "%s.fos-journal", |
| 226 | }; |
| 227 | int i; |
| 228 | for(i=0; i<sizeof(azFile)/sizeof(azFile[0]); i++){ |
| 229 | char *z = mprintf(azFile[i], g.zLocalRoot); |
| 230 | unlink(z); |
| 231 | free(z); |
| 232 | } |
| 233 | } |
| 234 | |
| 235 | /* |
| 236 | ** COMMAND: close |
| 237 | ** |
| 238 | ** Usage: %fossil close ?-f|--force? |
| @@ -205,8 +246,7 @@ | |
| 246 | db_must_be_within_tree(); |
| 247 | if( !forceFlag && unsaved_changes()==1 ){ |
| 248 | fossil_fatal("there are unsaved changes in the current checkout"); |
| 249 | } |
| 250 | db_close(); |
| 251 | unlink_local_database(); |
| 252 | } |
| 253 |
M
src/db.c
+20
-5
| --- src/db.c | ||
| +++ src/db.c | ||
| @@ -1243,23 +1243,29 @@ | ||
| 1243 | 1243 | } |
| 1244 | 1244 | |
| 1245 | 1245 | /* |
| 1246 | 1246 | ** COMMAND: open |
| 1247 | 1247 | ** |
| 1248 | -** Usage: %fossil open FILENAME | |
| 1248 | +** Usage: %fossil open FILENAME ?VERSION? ?--keep? | |
| 1249 | 1249 | ** |
| 1250 | 1250 | ** Open a connection to the local repository in FILENAME. A checkout |
| 1251 | 1251 | ** for the repository is created with its root at the working directory. |
| 1252 | +** If VERSION is specified then that version is checked out. Otherwise | |
| 1253 | +** the latest version is checked out. No files other than "manifest" | |
| 1254 | +** and "manifest.uuid" are modified if the --keep option is present. | |
| 1255 | +** | |
| 1252 | 1256 | ** See also the "close" command. |
| 1253 | 1257 | */ |
| 1254 | 1258 | void cmd_open(void){ |
| 1255 | 1259 | Blob path; |
| 1256 | 1260 | int vid; |
| 1257 | - static char *azNewArgv[] = { 0, "update", "--latest", 0 }; | |
| 1261 | + int keepFlag; | |
| 1262 | + static char *azNewArgv[] = { 0, "checkout", "--latest", 0, 0, 0 }; | |
| 1258 | 1263 | url_proxy_options(); |
| 1259 | - if( g.argc!=3 ){ | |
| 1260 | - usage("REPOSITORY-FILENAME"); | |
| 1264 | + keepFlag = find_option("keep",0,0)!=0; | |
| 1265 | + if( g.argc!=3 && g.argc!=4 ){ | |
| 1266 | + usage("REPOSITORY-FILENAME ?VERSION?"); | |
| 1261 | 1267 | } |
| 1262 | 1268 | if( db_open_local() ){ |
| 1263 | 1269 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1264 | 1270 | } |
| 1265 | 1271 | file_canonical_name(g.argv[2], &path); |
| @@ -1271,14 +1277,23 @@ | ||
| 1271 | 1277 | vid = db_int(0, "SELECT pid FROM plink y" |
| 1272 | 1278 | " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); |
| 1273 | 1279 | if( vid==0 ){ |
| 1274 | 1280 | db_lset_int("checkout", 1); |
| 1275 | 1281 | }else{ |
| 1282 | + char **oldArgv = g.argv; | |
| 1283 | + int oldArgc = g.argc; | |
| 1276 | 1284 | db_lset_int("checkout", vid); |
| 1285 | + azNewArgv[0] = g.argv[0]; | |
| 1277 | 1286 | g.argv = azNewArgv; |
| 1278 | 1287 | g.argc = 3; |
| 1279 | - update_cmd(); | |
| 1288 | + if( oldArgc==4 ){ | |
| 1289 | + azNewArgv[g.argc-1] = oldArgv[3]; | |
| 1290 | + } | |
| 1291 | + if( keepFlag ){ | |
| 1292 | + azNewArgv[g.argc++] = "--keep"; | |
| 1293 | + } | |
| 1294 | + checkout_cmd(); | |
| 1280 | 1295 | g.argc = 2; |
| 1281 | 1296 | info_cmd(); |
| 1282 | 1297 | } |
| 1283 | 1298 | } |
| 1284 | 1299 | |
| 1285 | 1300 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1243,23 +1243,29 @@ | |
| 1243 | } |
| 1244 | |
| 1245 | /* |
| 1246 | ** COMMAND: open |
| 1247 | ** |
| 1248 | ** Usage: %fossil open FILENAME |
| 1249 | ** |
| 1250 | ** Open a connection to the local repository in FILENAME. A checkout |
| 1251 | ** for the repository is created with its root at the working directory. |
| 1252 | ** See also the "close" command. |
| 1253 | */ |
| 1254 | void cmd_open(void){ |
| 1255 | Blob path; |
| 1256 | int vid; |
| 1257 | static char *azNewArgv[] = { 0, "update", "--latest", 0 }; |
| 1258 | url_proxy_options(); |
| 1259 | if( g.argc!=3 ){ |
| 1260 | usage("REPOSITORY-FILENAME"); |
| 1261 | } |
| 1262 | if( db_open_local() ){ |
| 1263 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1264 | } |
| 1265 | file_canonical_name(g.argv[2], &path); |
| @@ -1271,14 +1277,23 @@ | |
| 1271 | vid = db_int(0, "SELECT pid FROM plink y" |
| 1272 | " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); |
| 1273 | if( vid==0 ){ |
| 1274 | db_lset_int("checkout", 1); |
| 1275 | }else{ |
| 1276 | db_lset_int("checkout", vid); |
| 1277 | g.argv = azNewArgv; |
| 1278 | g.argc = 3; |
| 1279 | update_cmd(); |
| 1280 | g.argc = 2; |
| 1281 | info_cmd(); |
| 1282 | } |
| 1283 | } |
| 1284 | |
| 1285 |
| --- src/db.c | |
| +++ src/db.c | |
| @@ -1243,23 +1243,29 @@ | |
| 1243 | } |
| 1244 | |
| 1245 | /* |
| 1246 | ** COMMAND: open |
| 1247 | ** |
| 1248 | ** Usage: %fossil open FILENAME ?VERSION? ?--keep? |
| 1249 | ** |
| 1250 | ** Open a connection to the local repository in FILENAME. A checkout |
| 1251 | ** for the repository is created with its root at the working directory. |
| 1252 | ** If VERSION is specified then that version is checked out. Otherwise |
| 1253 | ** the latest version is checked out. No files other than "manifest" |
| 1254 | ** and "manifest.uuid" are modified if the --keep option is present. |
| 1255 | ** |
| 1256 | ** See also the "close" command. |
| 1257 | */ |
| 1258 | void cmd_open(void){ |
| 1259 | Blob path; |
| 1260 | int vid; |
| 1261 | int keepFlag; |
| 1262 | static char *azNewArgv[] = { 0, "checkout", "--latest", 0, 0, 0 }; |
| 1263 | url_proxy_options(); |
| 1264 | keepFlag = find_option("keep",0,0)!=0; |
| 1265 | if( g.argc!=3 && g.argc!=4 ){ |
| 1266 | usage("REPOSITORY-FILENAME ?VERSION?"); |
| 1267 | } |
| 1268 | if( db_open_local() ){ |
| 1269 | fossil_panic("already within an open tree rooted at %s", g.zLocalRoot); |
| 1270 | } |
| 1271 | file_canonical_name(g.argv[2], &path); |
| @@ -1271,14 +1277,23 @@ | |
| 1277 | vid = db_int(0, "SELECT pid FROM plink y" |
| 1278 | " WHERE NOT EXISTS(SELECT 1 FROM plink x WHERE x.cid=y.pid)"); |
| 1279 | if( vid==0 ){ |
| 1280 | db_lset_int("checkout", 1); |
| 1281 | }else{ |
| 1282 | char **oldArgv = g.argv; |
| 1283 | int oldArgc = g.argc; |
| 1284 | db_lset_int("checkout", vid); |
| 1285 | azNewArgv[0] = g.argv[0]; |
| 1286 | g.argv = azNewArgv; |
| 1287 | g.argc = 3; |
| 1288 | if( oldArgc==4 ){ |
| 1289 | azNewArgv[g.argc-1] = oldArgv[3]; |
| 1290 | } |
| 1291 | if( keepFlag ){ |
| 1292 | azNewArgv[g.argc++] = "--keep"; |
| 1293 | } |
| 1294 | checkout_cmd(); |
| 1295 | g.argc = 2; |
| 1296 | info_cmd(); |
| 1297 | } |
| 1298 | } |
| 1299 | |
| 1300 |