Fossil SCM

Enhancements to the "update" command. Missing files are reverted. One or more files can be specified on the "update" command line after the VERSION and only the files named will be updated.

drh 2009-12-17 22:55 trunk
Commit 2d996b080e1675dad33430598f4f4a75a089f201
1 file changed +67 -21
+67 -21
--- src/update.c
+++ src/update.c
@@ -36,20 +36,24 @@
3636
}
3737
3838
/*
3939
** COMMAND: update
4040
**
41
-** Usage: %fossil update ?VERSION? ?OPTIONS?
41
+** Usage: %fossil update ?VERSION? ?FILES...?
4242
**
4343
** Change the version of the current checkout to VERSION. Any uncommitted
4444
** changes are retained and applied to the new checkout.
4545
**
4646
** The VERSION argument can be a specific version or tag or branch name.
4747
** If the VERSION argument is omitted, then the leaf of the the subtree
4848
** that begins at the current version is used, if there is only a single
49
-** leaf. Instead of specifying VERSION, use the --latest option to update
50
-** to the most recent check-in.
49
+** leaf. VERSION can also be "current" to select the leaf of the current
50
+** version or "latest" to select the most recent check-in.
51
+**
52
+** If one or more FILES are listed after the VERSION then only the
53
+** named files are candidates to be updated. If FILES is omitted, all
54
+** files in the current checkout are subject to be updated.
5155
**
5256
** The -n or --nochange option causes this command to do a "dry run". It
5357
** prints out what would have happened but does not actually make any
5458
** changes to the current checkout or the repository.
5559
**
@@ -66,29 +70,35 @@
6670
6771
url_proxy_options();
6872
latestFlag = find_option("latest",0, 0)!=0;
6973
nochangeFlag = find_option("nochange","n",0)!=0;
7074
verboseFlag = find_option("verbose","v",0)!=0;
71
- if( g.argc!=3 && g.argc!=2 ){
72
- usage("?VERSION?");
73
- }
7475
db_must_be_within_tree();
7576
vid = db_lget_int("checkout", 0);
7677
if( vid==0 ){
7778
fossil_fatal("cannot find current version");
7879
}
7980
if( db_exists("SELECT 1 FROM vmerge") ){
8081
fossil_fatal("cannot update an uncommitted merge");
8182
}
8283
83
- if( g.argc==3 ){
84
- tid = name_to_rid(g.argv[2]);
85
- if( tid==0 ){
86
- fossil_fatal("not a version: %s", g.argv[2]);
87
- }
88
- if( !is_a_version(tid) ){
89
- fossil_fatal("not a version: %s", g.argv[2]);
84
+ if( g.argc>=3 ){
85
+ if( strcmp(g.argv[2], "current")==0 ){
86
+ /* If VERSION is "current", then use the same algorithm to find the
87
+ ** target as if VERSION were omitted. */
88
+ }else if( strcmp(g.argv[2], "latest")==0 ){
89
+ /* If VERSION is "latest", then use the same algorithm to find the
90
+ ** target as if VERSION were omitted and the --latest flag is present.
91
+ */
92
+ latestFlag = 1;
93
+ }else{
94
+ tid = name_to_rid(g.argv[2]);
95
+ if( tid==0 ){
96
+ fossil_fatal("no such version: %s", g.argv[2]);
97
+ }else if( !is_a_version(tid) ){
98
+ fossil_fatal("no such version: %s", g.argv[2]);
99
+ }
90100
}
91101
}
92102
if( !nochangeFlag ) autosync(AUTOSYNC_PULL);
93103
94104
if( tid==0 ){
@@ -120,11 +130,11 @@
120130
** in the current checkout, the pivot, and the version being merged.
121131
*/
122132
db_multi_exec(
123133
"DROP TABLE IF EXISTS fv;"
124134
"CREATE TEMP TABLE fv("
125
- " fn TEXT PRIMARY KEY," /* The filename */
135
+ " fn TEXT PRIMARY KEY," /* The filename relative to root */
126136
" idv INTEGER," /* VFILE entry for current version */
127137
" idt INTEGER," /* VFILE entry for target version */
128138
" chnged BOOLEAN," /* True if current version has been edited */
129139
" ridv INTEGER," /* Record ID for current version */
130140
" ridt INTEGER " /* Record ID for target */
@@ -159,22 +169,46 @@
159169
"UPDATE fv SET idv=%d, ridv=%d, chnged=%d WHERE fn=%Q",
160170
id, rid, chnged, fn
161171
);
162172
}
163173
db_finalize(&q);
174
+
175
+ /* If FILES appear on the command-line, remove from the "fv" table
176
+ ** every entry that is not named on the command-line.
177
+ */
178
+ if( g.argc>=4 ){
179
+ Blob sql; /* SQL statement to purge unwanted entries */
180
+ char *zSep = "("; /* Separator in the list of filenames */
181
+ Blob treename; /* Normalized filename */
182
+ int i; /* Loop counter */
183
+
184
+ blob_zero(&sql);
185
+ blob_append(&sql, "DELETE FROM fv WHERE fn NOT IN ", -1);
186
+ for(i=3; i<g.argc; i++){
187
+ file_tree_name(g.argv[i], &treename, 1);
188
+ blob_appendf(&sql, "%s'%q'", zSep, blob_str(&treename));
189
+ blob_reset(&treename);
190
+ zSep = ",";
191
+ }
192
+ blob_append(&sql, ")", -1);
193
+ db_multi_exec(blob_str(&sql));
194
+ blob_reset(&sql);
195
+ }
164196
165197
db_prepare(&q,
166198
"SELECT fn, idv, ridv, idt, ridt, chnged FROM fv ORDER BY 1"
167199
);
168200
while( db_step(&q)==SQLITE_ROW ){
169
- const char *zName = db_column_text(&q, 0); /* The filename */
201
+ const char *zName = db_column_text(&q, 0); /* The filename from root */
170202
int idv = db_column_int(&q, 1); /* VFILE entry for current */
171203
int ridv = db_column_int(&q, 2); /* RecordID for current */
172204
int idt = db_column_int(&q, 3); /* VFILE entry for target */
173205
int ridt = db_column_int(&q, 4); /* RecordID for target */
174206
int chnged = db_column_int(&q, 5); /* Current is edited */
207
+ char *zFullPath; /* Full pathname of the file */
175208
209
+ zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
176210
if( idv>0 && ridv==0 && idt>0 ){
177211
/* Conflict. This file has been added to the current checkout
178212
** but also exists in the target checkout. Use the current version.
179213
*/
180214
printf("CONFLICT %s\n", zName);
@@ -184,18 +218,25 @@
184218
undo_save(zName);
185219
if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
186220
}else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){
187221
/* The file is unedited. Change it to the target version */
188222
printf("UPDATE %s\n", zName);
223
+ undo_save(zName);
224
+ if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
225
+ }else if( idt>0 && idv>0 && file_size(zFullPath)<0 ){
226
+ /* The file missing from the local check-out. Restore it to the
227
+ ** version that appears in the target. */
228
+ printf("UPDATE %s\n", zName);
189229
undo_save(zName);
190230
if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
191231
}else if( idt==0 && idv>0 ){
192232
if( ridv==0 ){
193233
/* Added in current checkout. Continue to hold the file as
194234
** as an addition */
195235
db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
196236
}else if( chnged ){
237
+ /* Edited locally but deleted from the target. Delete it. */
197238
printf("CONFLICT %s\n", zName);
198239
}else{
199240
char *zFullPath;
200241
printf("REMOVE %s\n", zName);
201242
undo_save(zName);
@@ -205,14 +246,12 @@
205246
}
206247
}else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
207248
/* Merge the changes in the current tree into the target version */
208249
Blob e, r, t, v;
209250
int rc;
210
- char *zFullPath;
211251
printf("MERGE %s\n", zName);
212252
undo_save(zName);
213
- zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
214253
content_get(ridt, &t);
215254
content_get(ridv, &v);
216255
blob_zero(&e);
217256
blob_read_from_file(&e, zFullPath);
218257
rc = blob_merge(&v, &e, &t, &r);
@@ -222,30 +261,37 @@
222261
printf("***** %d merge conflicts in %s\n", rc, zName);
223262
}
224263
}else{
225264
printf("***** Cannot merge binary file %s\n", zName);
226265
}
227
- free(zFullPath);
228266
blob_reset(&v);
229267
blob_reset(&e);
230268
blob_reset(&t);
231269
blob_reset(&r);
232270
}else if( verboseFlag ){
233271
printf("UNCHANGED %s\n", zName);
234272
}
273
+ free(zFullPath);
235274
}
236275
db_finalize(&q);
237276
238277
/*
239278
** Clean up the mid and pid VFILE entries. Then commit the changes.
240279
*/
241280
if( nochangeFlag ){
242281
db_end_transaction(1); /* With --nochange, rollback changes */
243282
}else{
244
- db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
245
- manifest_to_disk(tid);
246
- db_lset_int("checkout", tid);
283
+ if( g.argc<=3 ){
284
+ /* All files updated. Shift the current checkout to the target. */
285
+ db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
286
+ manifest_to_disk(tid);
287
+ db_lset_int("checkout", tid);
288
+ }else{
289
+ /* A subset of files have been checked out. Keep the current
290
+ ** checkout unchanged. */
291
+ db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
292
+ }
247293
db_end_transaction(0);
248294
}
249295
}
250296
251297
252298
--- src/update.c
+++ src/update.c
@@ -36,20 +36,24 @@
36 }
37
38 /*
39 ** COMMAND: update
40 **
41 ** Usage: %fossil update ?VERSION? ?OPTIONS?
42 **
43 ** Change the version of the current checkout to VERSION. Any uncommitted
44 ** changes are retained and applied to the new checkout.
45 **
46 ** The VERSION argument can be a specific version or tag or branch name.
47 ** If the VERSION argument is omitted, then the leaf of the the subtree
48 ** that begins at the current version is used, if there is only a single
49 ** leaf. Instead of specifying VERSION, use the --latest option to update
50 ** to the most recent check-in.
 
 
 
 
51 **
52 ** The -n or --nochange option causes this command to do a "dry run". It
53 ** prints out what would have happened but does not actually make any
54 ** changes to the current checkout or the repository.
55 **
@@ -66,29 +70,35 @@
66
67 url_proxy_options();
68 latestFlag = find_option("latest",0, 0)!=0;
69 nochangeFlag = find_option("nochange","n",0)!=0;
70 verboseFlag = find_option("verbose","v",0)!=0;
71 if( g.argc!=3 && g.argc!=2 ){
72 usage("?VERSION?");
73 }
74 db_must_be_within_tree();
75 vid = db_lget_int("checkout", 0);
76 if( vid==0 ){
77 fossil_fatal("cannot find current version");
78 }
79 if( db_exists("SELECT 1 FROM vmerge") ){
80 fossil_fatal("cannot update an uncommitted merge");
81 }
82
83 if( g.argc==3 ){
84 tid = name_to_rid(g.argv[2]);
85 if( tid==0 ){
86 fossil_fatal("not a version: %s", g.argv[2]);
87 }
88 if( !is_a_version(tid) ){
89 fossil_fatal("not a version: %s", g.argv[2]);
 
 
 
 
 
 
 
 
 
90 }
91 }
92 if( !nochangeFlag ) autosync(AUTOSYNC_PULL);
93
94 if( tid==0 ){
@@ -120,11 +130,11 @@
120 ** in the current checkout, the pivot, and the version being merged.
121 */
122 db_multi_exec(
123 "DROP TABLE IF EXISTS fv;"
124 "CREATE TEMP TABLE fv("
125 " fn TEXT PRIMARY KEY," /* The filename */
126 " idv INTEGER," /* VFILE entry for current version */
127 " idt INTEGER," /* VFILE entry for target version */
128 " chnged BOOLEAN," /* True if current version has been edited */
129 " ridv INTEGER," /* Record ID for current version */
130 " ridt INTEGER " /* Record ID for target */
@@ -159,22 +169,46 @@
159 "UPDATE fv SET idv=%d, ridv=%d, chnged=%d WHERE fn=%Q",
160 id, rid, chnged, fn
161 );
162 }
163 db_finalize(&q);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
164
165 db_prepare(&q,
166 "SELECT fn, idv, ridv, idt, ridt, chnged FROM fv ORDER BY 1"
167 );
168 while( db_step(&q)==SQLITE_ROW ){
169 const char *zName = db_column_text(&q, 0); /* The filename */
170 int idv = db_column_int(&q, 1); /* VFILE entry for current */
171 int ridv = db_column_int(&q, 2); /* RecordID for current */
172 int idt = db_column_int(&q, 3); /* VFILE entry for target */
173 int ridt = db_column_int(&q, 4); /* RecordID for target */
174 int chnged = db_column_int(&q, 5); /* Current is edited */
 
175
 
176 if( idv>0 && ridv==0 && idt>0 ){
177 /* Conflict. This file has been added to the current checkout
178 ** but also exists in the target checkout. Use the current version.
179 */
180 printf("CONFLICT %s\n", zName);
@@ -184,18 +218,25 @@
184 undo_save(zName);
185 if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
186 }else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){
187 /* The file is unedited. Change it to the target version */
188 printf("UPDATE %s\n", zName);
 
 
 
 
 
 
189 undo_save(zName);
190 if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
191 }else if( idt==0 && idv>0 ){
192 if( ridv==0 ){
193 /* Added in current checkout. Continue to hold the file as
194 ** as an addition */
195 db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
196 }else if( chnged ){
 
197 printf("CONFLICT %s\n", zName);
198 }else{
199 char *zFullPath;
200 printf("REMOVE %s\n", zName);
201 undo_save(zName);
@@ -205,14 +246,12 @@
205 }
206 }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
207 /* Merge the changes in the current tree into the target version */
208 Blob e, r, t, v;
209 int rc;
210 char *zFullPath;
211 printf("MERGE %s\n", zName);
212 undo_save(zName);
213 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
214 content_get(ridt, &t);
215 content_get(ridv, &v);
216 blob_zero(&e);
217 blob_read_from_file(&e, zFullPath);
218 rc = blob_merge(&v, &e, &t, &r);
@@ -222,30 +261,37 @@
222 printf("***** %d merge conflicts in %s\n", rc, zName);
223 }
224 }else{
225 printf("***** Cannot merge binary file %s\n", zName);
226 }
227 free(zFullPath);
228 blob_reset(&v);
229 blob_reset(&e);
230 blob_reset(&t);
231 blob_reset(&r);
232 }else if( verboseFlag ){
233 printf("UNCHANGED %s\n", zName);
234 }
 
235 }
236 db_finalize(&q);
237
238 /*
239 ** Clean up the mid and pid VFILE entries. Then commit the changes.
240 */
241 if( nochangeFlag ){
242 db_end_transaction(1); /* With --nochange, rollback changes */
243 }else{
244 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
245 manifest_to_disk(tid);
246 db_lset_int("checkout", tid);
 
 
 
 
 
 
 
247 db_end_transaction(0);
248 }
249 }
250
251
252
--- src/update.c
+++ src/update.c
@@ -36,20 +36,24 @@
36 }
37
38 /*
39 ** COMMAND: update
40 **
41 ** Usage: %fossil update ?VERSION? ?FILES...?
42 **
43 ** Change the version of the current checkout to VERSION. Any uncommitted
44 ** changes are retained and applied to the new checkout.
45 **
46 ** The VERSION argument can be a specific version or tag or branch name.
47 ** If the VERSION argument is omitted, then the leaf of the the subtree
48 ** that begins at the current version is used, if there is only a single
49 ** leaf. VERSION can also be "current" to select the leaf of the current
50 ** version or "latest" to select the most recent check-in.
51 **
52 ** If one or more FILES are listed after the VERSION then only the
53 ** named files are candidates to be updated. If FILES is omitted, all
54 ** files in the current checkout are subject to be updated.
55 **
56 ** The -n or --nochange option causes this command to do a "dry run". It
57 ** prints out what would have happened but does not actually make any
58 ** changes to the current checkout or the repository.
59 **
@@ -66,29 +70,35 @@
70
71 url_proxy_options();
72 latestFlag = find_option("latest",0, 0)!=0;
73 nochangeFlag = find_option("nochange","n",0)!=0;
74 verboseFlag = find_option("verbose","v",0)!=0;
 
 
 
75 db_must_be_within_tree();
76 vid = db_lget_int("checkout", 0);
77 if( vid==0 ){
78 fossil_fatal("cannot find current version");
79 }
80 if( db_exists("SELECT 1 FROM vmerge") ){
81 fossil_fatal("cannot update an uncommitted merge");
82 }
83
84 if( g.argc>=3 ){
85 if( strcmp(g.argv[2], "current")==0 ){
86 /* If VERSION is "current", then use the same algorithm to find the
87 ** target as if VERSION were omitted. */
88 }else if( strcmp(g.argv[2], "latest")==0 ){
89 /* If VERSION is "latest", then use the same algorithm to find the
90 ** target as if VERSION were omitted and the --latest flag is present.
91 */
92 latestFlag = 1;
93 }else{
94 tid = name_to_rid(g.argv[2]);
95 if( tid==0 ){
96 fossil_fatal("no such version: %s", g.argv[2]);
97 }else if( !is_a_version(tid) ){
98 fossil_fatal("no such version: %s", g.argv[2]);
99 }
100 }
101 }
102 if( !nochangeFlag ) autosync(AUTOSYNC_PULL);
103
104 if( tid==0 ){
@@ -120,11 +130,11 @@
130 ** in the current checkout, the pivot, and the version being merged.
131 */
132 db_multi_exec(
133 "DROP TABLE IF EXISTS fv;"
134 "CREATE TEMP TABLE fv("
135 " fn TEXT PRIMARY KEY," /* The filename relative to root */
136 " idv INTEGER," /* VFILE entry for current version */
137 " idt INTEGER," /* VFILE entry for target version */
138 " chnged BOOLEAN," /* True if current version has been edited */
139 " ridv INTEGER," /* Record ID for current version */
140 " ridt INTEGER " /* Record ID for target */
@@ -159,22 +169,46 @@
169 "UPDATE fv SET idv=%d, ridv=%d, chnged=%d WHERE fn=%Q",
170 id, rid, chnged, fn
171 );
172 }
173 db_finalize(&q);
174
175 /* If FILES appear on the command-line, remove from the "fv" table
176 ** every entry that is not named on the command-line.
177 */
178 if( g.argc>=4 ){
179 Blob sql; /* SQL statement to purge unwanted entries */
180 char *zSep = "("; /* Separator in the list of filenames */
181 Blob treename; /* Normalized filename */
182 int i; /* Loop counter */
183
184 blob_zero(&sql);
185 blob_append(&sql, "DELETE FROM fv WHERE fn NOT IN ", -1);
186 for(i=3; i<g.argc; i++){
187 file_tree_name(g.argv[i], &treename, 1);
188 blob_appendf(&sql, "%s'%q'", zSep, blob_str(&treename));
189 blob_reset(&treename);
190 zSep = ",";
191 }
192 blob_append(&sql, ")", -1);
193 db_multi_exec(blob_str(&sql));
194 blob_reset(&sql);
195 }
196
197 db_prepare(&q,
198 "SELECT fn, idv, ridv, idt, ridt, chnged FROM fv ORDER BY 1"
199 );
200 while( db_step(&q)==SQLITE_ROW ){
201 const char *zName = db_column_text(&q, 0); /* The filename from root */
202 int idv = db_column_int(&q, 1); /* VFILE entry for current */
203 int ridv = db_column_int(&q, 2); /* RecordID for current */
204 int idt = db_column_int(&q, 3); /* VFILE entry for target */
205 int ridt = db_column_int(&q, 4); /* RecordID for target */
206 int chnged = db_column_int(&q, 5); /* Current is edited */
207 char *zFullPath; /* Full pathname of the file */
208
209 zFullPath = mprintf("%s/%s", g.zLocalRoot, zName);
210 if( idv>0 && ridv==0 && idt>0 ){
211 /* Conflict. This file has been added to the current checkout
212 ** but also exists in the target checkout. Use the current version.
213 */
214 printf("CONFLICT %s\n", zName);
@@ -184,18 +218,25 @@
218 undo_save(zName);
219 if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
220 }else if( idt>0 && idv>0 && ridt!=ridv && chnged==0 ){
221 /* The file is unedited. Change it to the target version */
222 printf("UPDATE %s\n", zName);
223 undo_save(zName);
224 if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
225 }else if( idt>0 && idv>0 && file_size(zFullPath)<0 ){
226 /* The file missing from the local check-out. Restore it to the
227 ** version that appears in the target. */
228 printf("UPDATE %s\n", zName);
229 undo_save(zName);
230 if( !nochangeFlag ) vfile_to_disk(0, idt, 0);
231 }else if( idt==0 && idv>0 ){
232 if( ridv==0 ){
233 /* Added in current checkout. Continue to hold the file as
234 ** as an addition */
235 db_multi_exec("UPDATE vfile SET vid=%d WHERE id=%d", tid, idv);
236 }else if( chnged ){
237 /* Edited locally but deleted from the target. Delete it. */
238 printf("CONFLICT %s\n", zName);
239 }else{
240 char *zFullPath;
241 printf("REMOVE %s\n", zName);
242 undo_save(zName);
@@ -205,14 +246,12 @@
246 }
247 }else if( idt>0 && idv>0 && ridt!=ridv && chnged ){
248 /* Merge the changes in the current tree into the target version */
249 Blob e, r, t, v;
250 int rc;
 
251 printf("MERGE %s\n", zName);
252 undo_save(zName);
 
253 content_get(ridt, &t);
254 content_get(ridv, &v);
255 blob_zero(&e);
256 blob_read_from_file(&e, zFullPath);
257 rc = blob_merge(&v, &e, &t, &r);
@@ -222,30 +261,37 @@
261 printf("***** %d merge conflicts in %s\n", rc, zName);
262 }
263 }else{
264 printf("***** Cannot merge binary file %s\n", zName);
265 }
 
266 blob_reset(&v);
267 blob_reset(&e);
268 blob_reset(&t);
269 blob_reset(&r);
270 }else if( verboseFlag ){
271 printf("UNCHANGED %s\n", zName);
272 }
273 free(zFullPath);
274 }
275 db_finalize(&q);
276
277 /*
278 ** Clean up the mid and pid VFILE entries. Then commit the changes.
279 */
280 if( nochangeFlag ){
281 db_end_transaction(1); /* With --nochange, rollback changes */
282 }else{
283 if( g.argc<=3 ){
284 /* All files updated. Shift the current checkout to the target. */
285 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", tid);
286 manifest_to_disk(tid);
287 db_lset_int("checkout", tid);
288 }else{
289 /* A subset of files have been checked out. Keep the current
290 ** checkout unchanged. */
291 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
292 }
293 db_end_transaction(0);
294 }
295 }
296
297
298

Keyboard Shortcuts

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