Fossil SCM

Futher enhancements to merge: Correct merging happens even on files whose names have changed since the pivot.

drh 2010-12-13 20:12 trunk
Commit c52927c76d94a9b70ed7ec98ef312fc912ec100d
3 files changed +3 -3 +168 -29 +15 -1
+3 -3
--- src/checkin.c
+++ src/checkin.c
@@ -179,18 +179,18 @@
179179
char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
180180
if( isBrief ){
181181
printf("%s\n", zPathname);
182182
}else if( isNew ){
183183
printf("ADDED %s\n", zPathname);
184
+ }else if( isDeleted ){
185
+ printf("DELETED %s\n", zPathname);
184186
}else if( !file_isfile(zFullName) ){
185187
if( access(zFullName, 0)==0 ){
186188
printf("NOT_A_FILE %s\n", zPathname);
187189
}else{
188190
printf("MISSING %s\n", zPathname);
189191
}
190
- }else if( isDeleted ){
191
- printf("DELETED %s\n", zPathname);
192192
}else if( chnged ){
193193
printf("EDITED %s\n", zPathname);
194194
}else if( renamed ){
195195
printf("RENAMED %s\n", zPathname);
196196
}else{
@@ -694,11 +694,11 @@
694694
/* For a new branch, cancel all prior propagating tags */
695695
Stmt q;
696696
db_prepare(&q,
697697
"SELECT tagname FROM tagxref, tag"
698698
" WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
699
- " AND tagtype>0 AND tagname GLOB 'sym-*'"
699
+ " AND tagtype==2 AND tagname GLOB 'sym-*'"
700700
" AND tagname!='sym-'||%Q"
701701
" ORDER BY tagname",
702702
vid, zBranch);
703703
while( db_step(&q)==SQLITE_ROW ){
704704
const char *zTag = db_column_text(&q, 0);
705705
--- src/checkin.c
+++ src/checkin.c
@@ -179,18 +179,18 @@
179 char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
180 if( isBrief ){
181 printf("%s\n", zPathname);
182 }else if( isNew ){
183 printf("ADDED %s\n", zPathname);
 
 
184 }else if( !file_isfile(zFullName) ){
185 if( access(zFullName, 0)==0 ){
186 printf("NOT_A_FILE %s\n", zPathname);
187 }else{
188 printf("MISSING %s\n", zPathname);
189 }
190 }else if( isDeleted ){
191 printf("DELETED %s\n", zPathname);
192 }else if( chnged ){
193 printf("EDITED %s\n", zPathname);
194 }else if( renamed ){
195 printf("RENAMED %s\n", zPathname);
196 }else{
@@ -694,11 +694,11 @@
694 /* For a new branch, cancel all prior propagating tags */
695 Stmt q;
696 db_prepare(&q,
697 "SELECT tagname FROM tagxref, tag"
698 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
699 " AND tagtype>0 AND tagname GLOB 'sym-*'"
700 " AND tagname!='sym-'||%Q"
701 " ORDER BY tagname",
702 vid, zBranch);
703 while( db_step(&q)==SQLITE_ROW ){
704 const char *zTag = db_column_text(&q, 0);
705
--- src/checkin.c
+++ src/checkin.c
@@ -179,18 +179,18 @@
179 char *zFullName = mprintf("%s/%s", g.zLocalRoot, zPathname);
180 if( isBrief ){
181 printf("%s\n", zPathname);
182 }else if( isNew ){
183 printf("ADDED %s\n", zPathname);
184 }else if( isDeleted ){
185 printf("DELETED %s\n", zPathname);
186 }else if( !file_isfile(zFullName) ){
187 if( access(zFullName, 0)==0 ){
188 printf("NOT_A_FILE %s\n", zPathname);
189 }else{
190 printf("MISSING %s\n", zPathname);
191 }
 
 
192 }else if( chnged ){
193 printf("EDITED %s\n", zPathname);
194 }else if( renamed ){
195 printf("RENAMED %s\n", zPathname);
196 }else{
@@ -694,11 +694,11 @@
694 /* For a new branch, cancel all prior propagating tags */
695 Stmt q;
696 db_prepare(&q,
697 "SELECT tagname FROM tagxref, tag"
698 " WHERE tagxref.rid=%d AND tagxref.tagid=tag.tagid"
699 " AND tagtype==2 AND tagname GLOB 'sym-*'"
700 " AND tagname!='sym-'||%Q"
701 " ORDER BY tagname",
702 vid, zBranch);
703 while( db_step(&q)==SQLITE_ROW ){
704 const char *zTag = db_column_text(&q, 0);
705
+168 -29
--- src/merge.c
+++ src/merge.c
@@ -50,23 +50,37 @@
5050
**
5151
** --nochange | -n Dryrun: do not actually make any changes; just
5252
** show what would have happened.
5353
*/
5454
void merge_cmd(void){
55
- int vid; /* Current version */
56
- int mid; /* Version we are merging from */
57
- int pid; /* The pivot version - most recent common ancestor */
55
+ int vid; /* Current version "V" */
56
+ int mid; /* Version we are merging from "M" */
57
+ int pid; /* The pivot version - most recent common ancestor P */
5858
int detailFlag; /* True if the --detail option is present */
5959
int pickFlag; /* True if the --cherrypick option is present */
6060
int backoutFlag; /* True if the --backout option is present */
6161
int nochangeFlag; /* True if the --nochange or -n option is present */
6262
const char *zBinGlob; /* The value of --binary */
63
+ int debugFlag; /* True if --debug is present */
64
+ int nChng; /* Number of file name changes */
65
+ int *aChng; /* An array of file name changes */
66
+ int i; /* Loop counter */
67
+ int nConflict = 0; /* Number of conflicts seen */
6368
Stmt q;
6469
70
+
71
+ /* Notation:
72
+ **
73
+ ** V The current checkout
74
+ ** M The version being merged in
75
+ ** P The "pivot" - the most recent common ancestor of V and M.
76
+ */
77
+
6578
detailFlag = find_option("detail",0,0)!=0;
6679
pickFlag = find_option("cherrypick",0,0)!=0;
6780
backoutFlag = find_option("backout",0,0)!=0;
81
+ debugFlag = find_option("debug",0,0)!=0;
6882
zBinGlob = find_option("binary",0,1);
6983
nochangeFlag = find_option("nochange","n",0)!=0;
7084
if( g.argc!=3 ){
7185
usage("VERSION");
7286
}
@@ -129,53 +143,134 @@
129143
" idp INTEGER," /* VFILE entry for the pivot */
130144
" idm INTEGER," /* VFILE entry for version merging in */
131145
" chnged BOOLEAN," /* True if current version has been edited */
132146
" ridv INTEGER," /* Record ID for current version */
133147
" ridp INTEGER," /* Record ID for pivot */
134
- " ridm INTEGER" /* Record ID for merge */
148
+ " ridm INTEGER," /* Record ID for merge */
149
+ " fnp TEXT," /* The filename in the pivot */
150
+ " fnm TEXT" /* the filename in the merged version */
135151
");"
136152
);
153
+
154
+ /* Add files found in V
155
+ */
156
+ db_multi_exec(
157
+ "INSERT OR IGNORE INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,chnged)"
158
+ " SELECT pathname, pathname, pathname, 0, 0, 0, 0, 0, 0, 0 "
159
+ " FROM vfile WHERE vid=%d",
160
+ vid
161
+ );
162
+
163
+ /*
164
+ ** Compute name changes from P->V
165
+ */
166
+ find_filename_changes(vid, pid, &nChng, &aChng);
167
+ if( nChng ){
168
+ for(i=0; i<nChng; i++){
169
+ db_multi_exec(
170
+ "UPDATE fv SET fnp=(SELECT name FROM filename WHERE fnid=%d)"
171
+ " WHERE fn=(SELECT name FROM filename WHERE fnid=%d)",
172
+ aChng[i*2+1], aChng[i*2]
173
+ );
174
+ }
175
+ fossil_free(aChng);
176
+ }
177
+
178
+ /* Add files found in P
179
+ */
180
+ db_multi_exec(
181
+ "INSERT OR IGNORE INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,chnged)"
182
+ " SELECT pathname, pathname, pathname, 0, 0, 0, 0, 0, 0, 0 "
183
+ " FROM vfile"
184
+ " WHERE vid=%d AND pathname NOT IN (SELECT fnp FROM fv)",
185
+ pid
186
+ );
187
+
188
+ /*
189
+ ** Compute name changes from P->M
190
+ */
191
+ find_filename_changes(pid, mid, &nChng, &aChng);
192
+ if( nChng ){
193
+ if( nChng>4 ) db_multi_exec("CREATE INDEX fv_fnp ON fv(fnp)");
194
+ for(i=0; i<nChng; i++){
195
+ db_multi_exec(
196
+ "UPDATE fv SET fnm=(SELECT name FROM filename WHERE fnid=%d)"
197
+ " WHERE fnp=(SELECT name FROM filename WHERE fnid=%d)",
198
+ aChng[i*2+1], aChng[i*2]
199
+ );
200
+ }
201
+ fossil_free(aChng);
202
+ }
203
+
204
+ /* Add files found in M
205
+ */
137206
db_multi_exec(
138
- "INSERT OR IGNORE INTO fv"
139
- " SELECT pathname, 0, 0, 0, 0, 0, 0, 0 FROM vfile WHERE vid IN (%d,%d,%d);",
140
- pid, vid, mid
207
+ "INSERT OR IGNORE INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,chnged)"
208
+ " SELECT pathname, pathname, pathname, 0, 0, 0, 0, 0, 0, 0 "
209
+ " FROM vfile"
210
+ " WHERE vid=%d"
211
+ " AND pathname NOT IN (SELECT fnp FROM fv UNION SELECT fnm FROM fv)",
212
+ mid
141213
);
214
+
215
+ /*
216
+ ** Compute the file version ids for V, P, and M.
217
+ */
142218
db_multi_exec(
143219
"UPDATE fv SET"
144
- " idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
145
- " ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
146
- " idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
147
- " ridm=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
220
+ " idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnp),0),"
221
+ " ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnp),0),"
222
+ " idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnm),0),"
223
+ " ridm=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnm),0),"
148224
" idv=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
149225
" ridv=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
150226
" chnged=coalesce((SELECT chnged FROM vfile"
151227
" WHERE vid=%d AND pathname=fn),0)",
152228
pid, pid, mid, mid, vid, vid, vid
153229
);
230
+
231
+ if( debugFlag ){
232
+ db_prepare(&q,
233
+ "SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm FROM fv"
234
+ );
235
+ while( db_step(&q)==SQLITE_ROW ){
236
+ printf("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d\n",
237
+ db_column_int(&q, 0),
238
+ db_column_int(&q, 5),
239
+ db_column_int(&q, 6),
240
+ db_column_int(&q, 7),
241
+ db_column_int(&q, 4));
242
+ printf(" fn = [%s]\n", db_column_text(&q, 1));
243
+ printf(" fnp = [%s]\n", db_column_text(&q, 2));
244
+ printf(" fnm = [%s]\n", db_column_text(&q, 3));
245
+ }
246
+ db_finalize(&q);
247
+ }
154248
155249
/*
156
- ** Find files in mid and vid but not in pid and report conflicts.
157
- ** The file in mid will be ignored. It will be treated as if it
250
+ ** Find files in M and V but not in P and report conflicts.
251
+ ** The file in M will be ignored. It will be treated as if it
158252
** does not exist.
159253
*/
160254
db_prepare(&q,
161255
"SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
162256
);
163257
while( db_step(&q)==SQLITE_ROW ){
164258
int idm = db_column_int(&q, 0);
165259
char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
166
- printf("WARNING: conflict on %s\n", zName);
260
+ printf("WARNING - no common ancestor: %s\n", zName);
167261
free(zName);
168262
db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
169263
}
170264
db_finalize(&q);
171265
172266
/*
173
- ** Add to vid files that are not in pid but are in mid
267
+ ** Add to V files that are not in V or P but are in M
174268
*/
175269
db_prepare(&q,
176
- "SELECT idm, rowid, fn FROM fv WHERE idp=0 AND idv=0 AND idm>0"
270
+ "SELECT idm, rowid, fnm FROM fv AS x"
271
+ " WHERE idp=0 AND idv=0 AND idm>0"
177272
);
178273
while( db_step(&q)==SQLITE_ROW ){
179274
int idm = db_column_int(&q, 0);
180275
int rowid = db_column_int(&q, 1);
181276
int idv;
@@ -195,40 +290,39 @@
195290
}
196291
}
197292
db_finalize(&q);
198293
199294
/*
200
- ** Find files that have changed from pid->mid but not pid->vid.
201
- ** Copy the mid content over into vid.
295
+ ** Find files that have changed from P->M but not P->V.
296
+ ** Copy the M content over into V.
202297
*/
203298
db_prepare(&q,
204
- "SELECT idv, ridm FROM fv"
299
+ "SELECT idv, ridm, fn FROM fv"
205300
" WHERE idp>0 AND idv>0 AND idm>0"
206301
" AND ridm!=ridp AND ridv=ridp AND NOT chnged"
207302
);
208303
while( db_step(&q)==SQLITE_ROW ){
209304
int idv = db_column_int(&q, 0);
210305
int ridm = db_column_int(&q, 1);
211
- char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idv);
306
+ const char *zName = db_column_text(&q, 2);
212307
/* Copy content from idm over into idv. Overwrite idv. */
213308
printf("UPDATE %s\n", zName);
214309
if( !nochangeFlag ){
215310
undo_save(zName);
216311
db_multi_exec(
217312
"UPDATE vfile SET mrid=%d, chnged=2 WHERE id=%d", ridm, idv
218313
);
219314
vfile_to_disk(0, idv, 0, 0);
220315
}
221
- free(zName);
222316
}
223317
db_finalize(&q);
224318
225319
/*
226
- ** Do a three-way merge on files that have changes pid->mid and pid->vid
320
+ ** Do a three-way merge on files that have changes on both P->M and P->V.
227321
*/
228322
db_prepare(&q,
229
- "SELECT ridm, idv, ridp, ridv, %s FROM fv"
323
+ "SELECT ridm, idv, ridp, ridv, %s, fn FROM fv"
230324
" WHERE idp>0 AND idv>0 AND idm>0"
231325
" AND ridm!=ridp AND (ridv!=ridp OR chnged)",
232326
glob_expr("fv.fn", zBinGlob)
233327
);
234328
while( db_step(&q)==SQLITE_ROW ){
@@ -235,12 +329,12 @@
235329
int ridm = db_column_int(&q, 0);
236330
int idv = db_column_int(&q, 1);
237331
int ridp = db_column_int(&q, 2);
238332
int ridv = db_column_int(&q, 3);
239333
int isBinary = db_column_int(&q, 4);
334
+ const char *zName = db_column_text(&q, 5);
240335
int rc;
241
- char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idv);
242336
char *zFullPath;
243337
Blob m, p, v, r;
244338
/* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
245339
if( detailFlag ){
246340
printf("MERGE %s (pivot=%d v1=%d v2=%d)\n", zName, ridp, ridm, ridv);
@@ -261,15 +355,16 @@
261355
}
262356
if( rc>=0 ){
263357
if( !nochangeFlag ) blob_write_to_file(&r, zFullPath);
264358
if( rc>0 ){
265359
printf("***** %d merge conflicts in %s\n", rc, zName);
360
+ nConflict++;
266361
}
267362
}else{
268363
printf("***** Cannot merge binary file %s\n", zName);
364
+ nConflict++;
269365
}
270
- free(zName);
271366
blob_reset(&p);
272367
blob_reset(&m);
273368
blob_reset(&v);
274369
blob_reset(&r);
275370
db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
@@ -276,33 +371,77 @@
276371
idv,ridm);
277372
}
278373
db_finalize(&q);
279374
280375
/*
281
- ** Drop files from vid that are in pid but not in mid
376
+ ** Drop files that are in P and V but not in M
282377
*/
283378
db_prepare(&q,
284
- "SELECT idv FROM fv"
379
+ "SELECT idv, fn, chnged FROM fv"
285380
" WHERE idp>0 AND idv>0 AND idm=0"
286381
);
287382
while( db_step(&q)==SQLITE_ROW ){
288383
int idv = db_column_int(&q, 0);
289
- char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idv);
384
+ const char *zName = db_column_text(&q, 1);
385
+ int chnged = db_column_int(&q, 2);
290386
/* Delete the file idv */
291387
printf("DELETE %s\n", zName);
388
+ if( chnged ){
389
+ printf("WARNING: local edits lost for %s\n", zName);
390
+ nConflict++;
391
+ }
292392
undo_save(zName);
293393
db_multi_exec(
294394
"UPDATE vfile SET deleted=1 WHERE id=%d", idv
295395
);
296396
if( !nochangeFlag ){
297397
char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
298398
unlink(zFullPath);
299399
free(zFullPath);
300400
}
301
- free(zName);
401
+ }
402
+ db_finalize(&q);
403
+
404
+ /*
405
+ ** Rename files that have taken a rename on P->M but which keep the same
406
+ ** name o P->V. If a file is renamed on P->V only or on both P->V and
407
+ ** P->M then we retain the V name of the file.
408
+ */
409
+ db_prepare(&q,
410
+ "SELECT idv, fnp, fnm FROM fv"
411
+ " WHERE idv>0 AND idp>0 AND idm>0 AND fnp=fn AND fnm!=fnp"
412
+ );
413
+ while( db_step(&q)==SQLITE_ROW ){
414
+ int idv = db_column_int(&q, 0);
415
+ const char *zOldName = db_column_text(&q, 1);
416
+ const char *zNewName = db_column_text(&q, 2);
417
+ printf("RENAME %s -> %s\n", zOldName, zNewName);
418
+ undo_save(zOldName);
419
+ undo_save(zNewName);
420
+ db_multi_exec(
421
+ "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
422
+ " WHERE id=%d AND vid=%d", zNewName, idv, vid
423
+ );
424
+ if( !nochangeFlag ){
425
+ char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName);
426
+ char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
427
+ file_copy(zFullOldPath, zFullNewPath);
428
+ unlink(zFullOldPath);
429
+ free(zFullNewPath);
430
+ free(zFullOldPath);
431
+ }
302432
}
303433
db_finalize(&q);
434
+
435
+
436
+ /* Report on conflicts
437
+ */
438
+ if( nConflict ){
439
+ printf("WARNING: %d merge conflicts.\n"
440
+ " ... Use \"fossil undo\" to back out this merge\n",
441
+ nConflict);
442
+ }
304443
305444
/*
306445
** Clean up the mid and pid VFILE entries. Then commit the changes.
307446
*/
308447
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
309448
--- src/merge.c
+++ src/merge.c
@@ -50,23 +50,37 @@
50 **
51 ** --nochange | -n Dryrun: do not actually make any changes; just
52 ** show what would have happened.
53 */
54 void merge_cmd(void){
55 int vid; /* Current version */
56 int mid; /* Version we are merging from */
57 int pid; /* The pivot version - most recent common ancestor */
58 int detailFlag; /* True if the --detail option is present */
59 int pickFlag; /* True if the --cherrypick option is present */
60 int backoutFlag; /* True if the --backout option is present */
61 int nochangeFlag; /* True if the --nochange or -n option is present */
62 const char *zBinGlob; /* The value of --binary */
 
 
 
 
 
63 Stmt q;
64
 
 
 
 
 
 
 
 
65 detailFlag = find_option("detail",0,0)!=0;
66 pickFlag = find_option("cherrypick",0,0)!=0;
67 backoutFlag = find_option("backout",0,0)!=0;
 
68 zBinGlob = find_option("binary",0,1);
69 nochangeFlag = find_option("nochange","n",0)!=0;
70 if( g.argc!=3 ){
71 usage("VERSION");
72 }
@@ -129,53 +143,134 @@
129 " idp INTEGER," /* VFILE entry for the pivot */
130 " idm INTEGER," /* VFILE entry for version merging in */
131 " chnged BOOLEAN," /* True if current version has been edited */
132 " ridv INTEGER," /* Record ID for current version */
133 " ridp INTEGER," /* Record ID for pivot */
134 " ridm INTEGER" /* Record ID for merge */
 
 
135 ");"
136 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
137 db_multi_exec(
138 "INSERT OR IGNORE INTO fv"
139 " SELECT pathname, 0, 0, 0, 0, 0, 0, 0 FROM vfile WHERE vid IN (%d,%d,%d);",
140 pid, vid, mid
 
 
 
141 );
 
 
 
 
142 db_multi_exec(
143 "UPDATE fv SET"
144 " idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
145 " ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
146 " idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
147 " ridm=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
148 " idv=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
149 " ridv=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
150 " chnged=coalesce((SELECT chnged FROM vfile"
151 " WHERE vid=%d AND pathname=fn),0)",
152 pid, pid, mid, mid, vid, vid, vid
153 );
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
154
155 /*
156 ** Find files in mid and vid but not in pid and report conflicts.
157 ** The file in mid will be ignored. It will be treated as if it
158 ** does not exist.
159 */
160 db_prepare(&q,
161 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
162 );
163 while( db_step(&q)==SQLITE_ROW ){
164 int idm = db_column_int(&q, 0);
165 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
166 printf("WARNING: conflict on %s\n", zName);
167 free(zName);
168 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
169 }
170 db_finalize(&q);
171
172 /*
173 ** Add to vid files that are not in pid but are in mid
174 */
175 db_prepare(&q,
176 "SELECT idm, rowid, fn FROM fv WHERE idp=0 AND idv=0 AND idm>0"
 
177 );
178 while( db_step(&q)==SQLITE_ROW ){
179 int idm = db_column_int(&q, 0);
180 int rowid = db_column_int(&q, 1);
181 int idv;
@@ -195,40 +290,39 @@
195 }
196 }
197 db_finalize(&q);
198
199 /*
200 ** Find files that have changed from pid->mid but not pid->vid.
201 ** Copy the mid content over into vid.
202 */
203 db_prepare(&q,
204 "SELECT idv, ridm FROM fv"
205 " WHERE idp>0 AND idv>0 AND idm>0"
206 " AND ridm!=ridp AND ridv=ridp AND NOT chnged"
207 );
208 while( db_step(&q)==SQLITE_ROW ){
209 int idv = db_column_int(&q, 0);
210 int ridm = db_column_int(&q, 1);
211 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idv);
212 /* Copy content from idm over into idv. Overwrite idv. */
213 printf("UPDATE %s\n", zName);
214 if( !nochangeFlag ){
215 undo_save(zName);
216 db_multi_exec(
217 "UPDATE vfile SET mrid=%d, chnged=2 WHERE id=%d", ridm, idv
218 );
219 vfile_to_disk(0, idv, 0, 0);
220 }
221 free(zName);
222 }
223 db_finalize(&q);
224
225 /*
226 ** Do a three-way merge on files that have changes pid->mid and pid->vid
227 */
228 db_prepare(&q,
229 "SELECT ridm, idv, ridp, ridv, %s FROM fv"
230 " WHERE idp>0 AND idv>0 AND idm>0"
231 " AND ridm!=ridp AND (ridv!=ridp OR chnged)",
232 glob_expr("fv.fn", zBinGlob)
233 );
234 while( db_step(&q)==SQLITE_ROW ){
@@ -235,12 +329,12 @@
235 int ridm = db_column_int(&q, 0);
236 int idv = db_column_int(&q, 1);
237 int ridp = db_column_int(&q, 2);
238 int ridv = db_column_int(&q, 3);
239 int isBinary = db_column_int(&q, 4);
 
240 int rc;
241 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idv);
242 char *zFullPath;
243 Blob m, p, v, r;
244 /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
245 if( detailFlag ){
246 printf("MERGE %s (pivot=%d v1=%d v2=%d)\n", zName, ridp, ridm, ridv);
@@ -261,15 +355,16 @@
261 }
262 if( rc>=0 ){
263 if( !nochangeFlag ) blob_write_to_file(&r, zFullPath);
264 if( rc>0 ){
265 printf("***** %d merge conflicts in %s\n", rc, zName);
 
266 }
267 }else{
268 printf("***** Cannot merge binary file %s\n", zName);
 
269 }
270 free(zName);
271 blob_reset(&p);
272 blob_reset(&m);
273 blob_reset(&v);
274 blob_reset(&r);
275 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
@@ -276,33 +371,77 @@
276 idv,ridm);
277 }
278 db_finalize(&q);
279
280 /*
281 ** Drop files from vid that are in pid but not in mid
282 */
283 db_prepare(&q,
284 "SELECT idv FROM fv"
285 " WHERE idp>0 AND idv>0 AND idm=0"
286 );
287 while( db_step(&q)==SQLITE_ROW ){
288 int idv = db_column_int(&q, 0);
289 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idv);
 
290 /* Delete the file idv */
291 printf("DELETE %s\n", zName);
 
 
 
 
292 undo_save(zName);
293 db_multi_exec(
294 "UPDATE vfile SET deleted=1 WHERE id=%d", idv
295 );
296 if( !nochangeFlag ){
297 char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
298 unlink(zFullPath);
299 free(zFullPath);
300 }
301 free(zName);
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
302 }
303 db_finalize(&q);
 
 
 
 
 
 
 
 
 
304
305 /*
306 ** Clean up the mid and pid VFILE entries. Then commit the changes.
307 */
308 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
309
--- src/merge.c
+++ src/merge.c
@@ -50,23 +50,37 @@
50 **
51 ** --nochange | -n Dryrun: do not actually make any changes; just
52 ** show what would have happened.
53 */
54 void merge_cmd(void){
55 int vid; /* Current version "V" */
56 int mid; /* Version we are merging from "M" */
57 int pid; /* The pivot version - most recent common ancestor P */
58 int detailFlag; /* True if the --detail option is present */
59 int pickFlag; /* True if the --cherrypick option is present */
60 int backoutFlag; /* True if the --backout option is present */
61 int nochangeFlag; /* True if the --nochange or -n option is present */
62 const char *zBinGlob; /* The value of --binary */
63 int debugFlag; /* True if --debug is present */
64 int nChng; /* Number of file name changes */
65 int *aChng; /* An array of file name changes */
66 int i; /* Loop counter */
67 int nConflict = 0; /* Number of conflicts seen */
68 Stmt q;
69
70
71 /* Notation:
72 **
73 ** V The current checkout
74 ** M The version being merged in
75 ** P The "pivot" - the most recent common ancestor of V and M.
76 */
77
78 detailFlag = find_option("detail",0,0)!=0;
79 pickFlag = find_option("cherrypick",0,0)!=0;
80 backoutFlag = find_option("backout",0,0)!=0;
81 debugFlag = find_option("debug",0,0)!=0;
82 zBinGlob = find_option("binary",0,1);
83 nochangeFlag = find_option("nochange","n",0)!=0;
84 if( g.argc!=3 ){
85 usage("VERSION");
86 }
@@ -129,53 +143,134 @@
143 " idp INTEGER," /* VFILE entry for the pivot */
144 " idm INTEGER," /* VFILE entry for version merging in */
145 " chnged BOOLEAN," /* True if current version has been edited */
146 " ridv INTEGER," /* Record ID for current version */
147 " ridp INTEGER," /* Record ID for pivot */
148 " ridm INTEGER," /* Record ID for merge */
149 " fnp TEXT," /* The filename in the pivot */
150 " fnm TEXT" /* the filename in the merged version */
151 ");"
152 );
153
154 /* Add files found in V
155 */
156 db_multi_exec(
157 "INSERT OR IGNORE INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,chnged)"
158 " SELECT pathname, pathname, pathname, 0, 0, 0, 0, 0, 0, 0 "
159 " FROM vfile WHERE vid=%d",
160 vid
161 );
162
163 /*
164 ** Compute name changes from P->V
165 */
166 find_filename_changes(vid, pid, &nChng, &aChng);
167 if( nChng ){
168 for(i=0; i<nChng; i++){
169 db_multi_exec(
170 "UPDATE fv SET fnp=(SELECT name FROM filename WHERE fnid=%d)"
171 " WHERE fn=(SELECT name FROM filename WHERE fnid=%d)",
172 aChng[i*2+1], aChng[i*2]
173 );
174 }
175 fossil_free(aChng);
176 }
177
178 /* Add files found in P
179 */
180 db_multi_exec(
181 "INSERT OR IGNORE INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,chnged)"
182 " SELECT pathname, pathname, pathname, 0, 0, 0, 0, 0, 0, 0 "
183 " FROM vfile"
184 " WHERE vid=%d AND pathname NOT IN (SELECT fnp FROM fv)",
185 pid
186 );
187
188 /*
189 ** Compute name changes from P->M
190 */
191 find_filename_changes(pid, mid, &nChng, &aChng);
192 if( nChng ){
193 if( nChng>4 ) db_multi_exec("CREATE INDEX fv_fnp ON fv(fnp)");
194 for(i=0; i<nChng; i++){
195 db_multi_exec(
196 "UPDATE fv SET fnm=(SELECT name FROM filename WHERE fnid=%d)"
197 " WHERE fnp=(SELECT name FROM filename WHERE fnid=%d)",
198 aChng[i*2+1], aChng[i*2]
199 );
200 }
201 fossil_free(aChng);
202 }
203
204 /* Add files found in M
205 */
206 db_multi_exec(
207 "INSERT OR IGNORE INTO fv(fn,fnp,fnm,idv,idp,idm,ridv,ridp,ridm,chnged)"
208 " SELECT pathname, pathname, pathname, 0, 0, 0, 0, 0, 0, 0 "
209 " FROM vfile"
210 " WHERE vid=%d"
211 " AND pathname NOT IN (SELECT fnp FROM fv UNION SELECT fnm FROM fv)",
212 mid
213 );
214
215 /*
216 ** Compute the file version ids for V, P, and M.
217 */
218 db_multi_exec(
219 "UPDATE fv SET"
220 " idp=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnp),0),"
221 " ridp=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnp),0),"
222 " idm=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fnm),0),"
223 " ridm=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fnm),0),"
224 " idv=coalesce((SELECT id FROM vfile WHERE vid=%d AND pathname=fn),0),"
225 " ridv=coalesce((SELECT rid FROM vfile WHERE vid=%d AND pathname=fn),0),"
226 " chnged=coalesce((SELECT chnged FROM vfile"
227 " WHERE vid=%d AND pathname=fn),0)",
228 pid, pid, mid, mid, vid, vid, vid
229 );
230
231 if( debugFlag ){
232 db_prepare(&q,
233 "SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm FROM fv"
234 );
235 while( db_step(&q)==SQLITE_ROW ){
236 printf("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d\n",
237 db_column_int(&q, 0),
238 db_column_int(&q, 5),
239 db_column_int(&q, 6),
240 db_column_int(&q, 7),
241 db_column_int(&q, 4));
242 printf(" fn = [%s]\n", db_column_text(&q, 1));
243 printf(" fnp = [%s]\n", db_column_text(&q, 2));
244 printf(" fnm = [%s]\n", db_column_text(&q, 3));
245 }
246 db_finalize(&q);
247 }
248
249 /*
250 ** Find files in M and V but not in P and report conflicts.
251 ** The file in M will be ignored. It will be treated as if it
252 ** does not exist.
253 */
254 db_prepare(&q,
255 "SELECT idm FROM fv WHERE idp=0 AND idv>0 AND idm>0"
256 );
257 while( db_step(&q)==SQLITE_ROW ){
258 int idm = db_column_int(&q, 0);
259 char *zName = db_text(0, "SELECT pathname FROM vfile WHERE id=%d", idm);
260 printf("WARNING - no common ancestor: %s\n", zName);
261 free(zName);
262 db_multi_exec("UPDATE fv SET idm=0 WHERE idm=%d", idm);
263 }
264 db_finalize(&q);
265
266 /*
267 ** Add to V files that are not in V or P but are in M
268 */
269 db_prepare(&q,
270 "SELECT idm, rowid, fnm FROM fv AS x"
271 " WHERE idp=0 AND idv=0 AND idm>0"
272 );
273 while( db_step(&q)==SQLITE_ROW ){
274 int idm = db_column_int(&q, 0);
275 int rowid = db_column_int(&q, 1);
276 int idv;
@@ -195,40 +290,39 @@
290 }
291 }
292 db_finalize(&q);
293
294 /*
295 ** Find files that have changed from P->M but not P->V.
296 ** Copy the M content over into V.
297 */
298 db_prepare(&q,
299 "SELECT idv, ridm, fn FROM fv"
300 " WHERE idp>0 AND idv>0 AND idm>0"
301 " AND ridm!=ridp AND ridv=ridp AND NOT chnged"
302 );
303 while( db_step(&q)==SQLITE_ROW ){
304 int idv = db_column_int(&q, 0);
305 int ridm = db_column_int(&q, 1);
306 const char *zName = db_column_text(&q, 2);
307 /* Copy content from idm over into idv. Overwrite idv. */
308 printf("UPDATE %s\n", zName);
309 if( !nochangeFlag ){
310 undo_save(zName);
311 db_multi_exec(
312 "UPDATE vfile SET mrid=%d, chnged=2 WHERE id=%d", ridm, idv
313 );
314 vfile_to_disk(0, idv, 0, 0);
315 }
 
316 }
317 db_finalize(&q);
318
319 /*
320 ** Do a three-way merge on files that have changes on both P->M and P->V.
321 */
322 db_prepare(&q,
323 "SELECT ridm, idv, ridp, ridv, %s, fn FROM fv"
324 " WHERE idp>0 AND idv>0 AND idm>0"
325 " AND ridm!=ridp AND (ridv!=ridp OR chnged)",
326 glob_expr("fv.fn", zBinGlob)
327 );
328 while( db_step(&q)==SQLITE_ROW ){
@@ -235,12 +329,12 @@
329 int ridm = db_column_int(&q, 0);
330 int idv = db_column_int(&q, 1);
331 int ridp = db_column_int(&q, 2);
332 int ridv = db_column_int(&q, 3);
333 int isBinary = db_column_int(&q, 4);
334 const char *zName = db_column_text(&q, 5);
335 int rc;
 
336 char *zFullPath;
337 Blob m, p, v, r;
338 /* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */
339 if( detailFlag ){
340 printf("MERGE %s (pivot=%d v1=%d v2=%d)\n", zName, ridp, ridm, ridv);
@@ -261,15 +355,16 @@
355 }
356 if( rc>=0 ){
357 if( !nochangeFlag ) blob_write_to_file(&r, zFullPath);
358 if( rc>0 ){
359 printf("***** %d merge conflicts in %s\n", rc, zName);
360 nConflict++;
361 }
362 }else{
363 printf("***** Cannot merge binary file %s\n", zName);
364 nConflict++;
365 }
 
366 blob_reset(&p);
367 blob_reset(&m);
368 blob_reset(&v);
369 blob_reset(&r);
370 db_multi_exec("INSERT OR IGNORE INTO vmerge(id,merge) VALUES(%d,%d)",
@@ -276,33 +371,77 @@
371 idv,ridm);
372 }
373 db_finalize(&q);
374
375 /*
376 ** Drop files that are in P and V but not in M
377 */
378 db_prepare(&q,
379 "SELECT idv, fn, chnged FROM fv"
380 " WHERE idp>0 AND idv>0 AND idm=0"
381 );
382 while( db_step(&q)==SQLITE_ROW ){
383 int idv = db_column_int(&q, 0);
384 const char *zName = db_column_text(&q, 1);
385 int chnged = db_column_int(&q, 2);
386 /* Delete the file idv */
387 printf("DELETE %s\n", zName);
388 if( chnged ){
389 printf("WARNING: local edits lost for %s\n", zName);
390 nConflict++;
391 }
392 undo_save(zName);
393 db_multi_exec(
394 "UPDATE vfile SET deleted=1 WHERE id=%d", idv
395 );
396 if( !nochangeFlag ){
397 char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName);
398 unlink(zFullPath);
399 free(zFullPath);
400 }
401 }
402 db_finalize(&q);
403
404 /*
405 ** Rename files that have taken a rename on P->M but which keep the same
406 ** name o P->V. If a file is renamed on P->V only or on both P->V and
407 ** P->M then we retain the V name of the file.
408 */
409 db_prepare(&q,
410 "SELECT idv, fnp, fnm FROM fv"
411 " WHERE idv>0 AND idp>0 AND idm>0 AND fnp=fn AND fnm!=fnp"
412 );
413 while( db_step(&q)==SQLITE_ROW ){
414 int idv = db_column_int(&q, 0);
415 const char *zOldName = db_column_text(&q, 1);
416 const char *zNewName = db_column_text(&q, 2);
417 printf("RENAME %s -> %s\n", zOldName, zNewName);
418 undo_save(zOldName);
419 undo_save(zNewName);
420 db_multi_exec(
421 "UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)"
422 " WHERE id=%d AND vid=%d", zNewName, idv, vid
423 );
424 if( !nochangeFlag ){
425 char *zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName);
426 char *zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName);
427 file_copy(zFullOldPath, zFullNewPath);
428 unlink(zFullOldPath);
429 free(zFullNewPath);
430 free(zFullOldPath);
431 }
432 }
433 db_finalize(&q);
434
435
436 /* Report on conflicts
437 */
438 if( nConflict ){
439 printf("WARNING: %d merge conflicts.\n"
440 " ... Use \"fossil undo\" to back out this merge\n",
441 nConflict);
442 }
443
444 /*
445 ** Clean up the mid and pid VFILE entries. Then commit the changes.
446 */
447 db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid);
448
+15 -1
--- test/merge5.test
+++ test/merge5.test
@@ -19,11 +19,15 @@
1919
#
2020
2121
# Verify the results of a check-out
2222
#
2323
proc checkout-test {testid expected_content} {
24
- eval fossil sha1sum [lsort [glob -nocomplain *.txt]]
24
+ set flist {}
25
+ foreach {status filename} [exec $::fossilexe ls -l] {
26
+ if {$status!="DELETED"} {lappend flist $filename}
27
+ }
28
+ eval fossil sha1sum [lsort $flist]
2529
global RESULT
2630
regsub -all {\n *} [string trim $expected_content] "\n " expected
2731
regsub -all {\n *} [string trim $RESULT] "\n " result
2832
if {$result!=$expected} {
2933
protOut " Expected:\n $expected"
@@ -227,5 +231,15 @@
227231
6e167b139c294bed560e2e30b352361b101e1f39 four.txt
228232
ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt
229233
278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt
230234
}
231235
fossil undo
236
+
237
+# Merge br5 (which includes a file rename) into chng3
238
+#
239
+fossil update chng3
240
+fossil merge br5
241
+checkout-test 130 {
242
+ 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt
243
+ 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt
244
+ e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt
245
+}
232246
--- test/merge5.test
+++ test/merge5.test
@@ -19,11 +19,15 @@
19 #
20
21 # Verify the results of a check-out
22 #
23 proc checkout-test {testid expected_content} {
24 eval fossil sha1sum [lsort [glob -nocomplain *.txt]]
 
 
 
 
25 global RESULT
26 regsub -all {\n *} [string trim $expected_content] "\n " expected
27 regsub -all {\n *} [string trim $RESULT] "\n " result
28 if {$result!=$expected} {
29 protOut " Expected:\n $expected"
@@ -227,5 +231,15 @@
227 6e167b139c294bed560e2e30b352361b101e1f39 four.txt
228 ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt
229 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt
230 }
231 fossil undo
 
 
 
 
 
 
 
 
 
 
232
--- test/merge5.test
+++ test/merge5.test
@@ -19,11 +19,15 @@
19 #
20
21 # Verify the results of a check-out
22 #
23 proc checkout-test {testid expected_content} {
24 set flist {}
25 foreach {status filename} [exec $::fossilexe ls -l] {
26 if {$status!="DELETED"} {lappend flist $filename}
27 }
28 eval fossil sha1sum [lsort $flist]
29 global RESULT
30 regsub -all {\n *} [string trim $expected_content] "\n " expected
31 regsub -all {\n *} [string trim $RESULT] "\n " result
32 if {$result!=$expected} {
33 protOut " Expected:\n $expected"
@@ -227,5 +231,15 @@
231 6e167b139c294bed560e2e30b352361b101e1f39 four.txt
232 ed24d19d726d173f18dbf4a9a0f8514daa3e3ca4 three.txt
233 278a402316510f6ae4a77186796a6bde78c7dbc1 two.txt
234 }
235 fossil undo
236
237 # Merge br5 (which includes a file rename) into chng3
238 #
239 fossil update chng3
240 fossil merge br5
241 checkout-test 130 {
242 7eaf64a2c9141277b4c24259c7766d6a77047af7 one.txt
243 98e47f99bb9fed4fdcd407f553615ca7f15a38a2 three.txt
244 e58c5da3e6007d0e30600ea31611813093ad180f two-rename.txt
245 }
246

Keyboard Shortcuts

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