|
dbda8d6…
|
drh
|
1 |
/* |
|
c19f34c…
|
drh
|
2 |
** Copyright (c) 2007 D. Richard Hipp |
|
dbda8d6…
|
drh
|
3 |
** |
|
dbda8d6…
|
drh
|
4 |
** This program is free software; you can redistribute it and/or |
|
c06edd2…
|
drh
|
5 |
** modify it under the terms of the Simplified BSD License (also |
|
c06edd2…
|
drh
|
6 |
** known as the "2-Clause License" or "FreeBSD License".) |
|
c06edd2…
|
drh
|
7 |
|
|
dbda8d6…
|
drh
|
8 |
** This program is distributed in the hope that it will be useful, |
|
c06edd2…
|
drh
|
9 |
** but without any warranty; without even the implied warranty of |
|
c06edd2…
|
drh
|
10 |
** merchantability or fitness for a particular purpose. |
|
dbda8d6…
|
drh
|
11 |
** |
|
dbda8d6…
|
drh
|
12 |
** Author contact information: |
|
dbda8d6…
|
drh
|
13 |
** [email protected] |
|
dbda8d6…
|
drh
|
14 |
** http://www.hwaci.com/drh/ |
|
dbda8d6…
|
drh
|
15 |
** |
|
dbda8d6…
|
drh
|
16 |
******************************************************************************* |
|
dbda8d6…
|
drh
|
17 |
** |
|
dbda8d6…
|
drh
|
18 |
** This file contains code used to merge two or more branches into |
|
dbda8d6…
|
drh
|
19 |
** a single tree. |
|
dbda8d6…
|
drh
|
20 |
*/ |
|
dbda8d6…
|
drh
|
21 |
#include "config.h" |
|
dbda8d6…
|
drh
|
22 |
#include "merge.h" |
|
dbda8d6…
|
drh
|
23 |
#include <assert.h> |
|
dbda8d6…
|
drh
|
24 |
|
|
aa82965…
|
drh
|
25 |
|
|
aa82965…
|
drh
|
26 |
/* |
|
aa82965…
|
drh
|
27 |
** Bring up a Tcl/Tk GUI to show details of the most recent merge. |
|
aa82965…
|
drh
|
28 |
*/ |
|
aa82965…
|
drh
|
29 |
static void merge_info_tk(int bDark, int bAll, int nContext){ |
|
aa82965…
|
drh
|
30 |
int i; |
|
aa82965…
|
drh
|
31 |
Blob script; |
|
aa82965…
|
drh
|
32 |
const char *zTempFile = 0; |
|
97aee32…
|
drh
|
33 |
int bDebug; |
|
aa82965…
|
drh
|
34 |
char *zCmd; |
|
aa82965…
|
drh
|
35 |
const char *zTclsh; |
|
aa82965…
|
drh
|
36 |
zTclsh = find_option("tclsh",0,1); |
|
aa82965…
|
drh
|
37 |
if( zTclsh==0 ){ |
|
aa82965…
|
drh
|
38 |
zTclsh = db_get("tclsh",0); |
|
aa82965…
|
drh
|
39 |
} |
|
aa82965…
|
drh
|
40 |
/* The undocumented --script FILENAME option causes the Tk script to |
|
aa82965…
|
drh
|
41 |
** be written into the FILENAME instead of being run. This is used |
|
aa82965…
|
drh
|
42 |
** for testing and debugging. */ |
|
aa82965…
|
drh
|
43 |
zTempFile = find_option("script",0,1); |
|
f5cb12d…
|
drh
|
44 |
bDebug = find_option("tkdebug",0,0)!=0; |
|
aa82965…
|
drh
|
45 |
verify_all_options(); |
|
aa82965…
|
drh
|
46 |
|
|
aa82965…
|
drh
|
47 |
blob_zero(&script); |
|
f8932be…
|
drh
|
48 |
blob_appendf(&script, "set ncontext %d\n", nContext); |
|
f5cb12d…
|
drh
|
49 |
blob_appendf(&script, "set fossilexe {\"%/\"}\n", g.nameOfExe); |
|
f8932be…
|
drh
|
50 |
blob_appendf(&script, "set fossilcmd {| \"%/\" merge-info}\n", |
|
aa82965…
|
drh
|
51 |
g.nameOfExe); |
|
aa82965…
|
drh
|
52 |
blob_appendf(&script, "set filelist [list"); |
|
aa82965…
|
drh
|
53 |
if( g.argc==2 ){ |
|
aa82965…
|
drh
|
54 |
/* No files named on the command-line. Use every file mentioned |
|
aa82965…
|
drh
|
55 |
** in the MERGESTAT table to generate the file list. */ |
|
aa82965…
|
drh
|
56 |
Stmt q; |
|
3165e1b…
|
drh
|
57 |
int cnt = 0; |
|
aa82965…
|
drh
|
58 |
db_prepare(&q, |
|
0b5dfa9…
|
drh
|
59 |
"WITH priority(op,pri) AS (VALUES('CONFLICT',0),('ERROR',0)," |
|
0b5dfa9…
|
drh
|
60 |
"('MERGE',1),('ADDED',2),('UPDATE',2))" |
|
0b5dfa9…
|
drh
|
61 |
"SELECT coalesce(fnr,fn), op FROM mergestat JOIN priority USING(op)" |
|
0b5dfa9…
|
drh
|
62 |
" %s ORDER BY pri, 1", |
|
aa82965…
|
drh
|
63 |
bAll ? "" : "WHERE op IN ('MERGE','CONFLICT')" /*safe-for-%s*/ |
|
aa82965…
|
drh
|
64 |
); |
|
aa82965…
|
drh
|
65 |
while( db_step(&q)==SQLITE_ROW ){ |
|
aa82965…
|
drh
|
66 |
blob_appendf(&script," %s ", db_column_text(&q,1)); |
|
aa82965…
|
drh
|
67 |
blob_append_tcl_literal(&script, db_column_text(&q,0), |
|
aa82965…
|
drh
|
68 |
db_column_bytes(&q,0)); |
|
aa82965…
|
drh
|
69 |
cnt++; |
|
aa82965…
|
drh
|
70 |
} |
|
aa82965…
|
drh
|
71 |
db_finalize(&q); |
|
aa82965…
|
drh
|
72 |
if( cnt==0 ){ |
|
aa82965…
|
drh
|
73 |
fossil_print( |
|
aa82965…
|
drh
|
74 |
"No interesting changes in this merge. Use --all to see everything\n" |
|
aa82965…
|
drh
|
75 |
); |
|
aa82965…
|
drh
|
76 |
return; |
|
aa82965…
|
drh
|
77 |
} |
|
aa82965…
|
drh
|
78 |
}else{ |
|
aa82965…
|
drh
|
79 |
/* Use only files named on the command-line in the file list. |
|
aa82965…
|
drh
|
80 |
** But verify each file named is actually found in the MERGESTAT |
|
aa82965…
|
drh
|
81 |
** table first. */ |
|
aa82965…
|
drh
|
82 |
for(i=2; i<g.argc; i++){ |
|
aa82965…
|
drh
|
83 |
char *zFile; /* Input filename */ |
|
aa82965…
|
drh
|
84 |
char *zTreename; /* Name of the file in the tree */ |
|
aa82965…
|
drh
|
85 |
Blob fname; /* Filename relative to root */ |
|
aa82965…
|
drh
|
86 |
char *zOp; /* Operation on this file */ |
|
aa82965…
|
drh
|
87 |
zFile = mprintf("%/", g.argv[i]); |
|
aa82965…
|
drh
|
88 |
file_tree_name(zFile, &fname, 0, 1); |
|
aa82965…
|
drh
|
89 |
fossil_free(zFile); |
|
aa82965…
|
drh
|
90 |
zTreename = blob_str(&fname); |
|
aa82965…
|
drh
|
91 |
zOp = db_text(0, "SELECT op FROM mergestat WHERE fn=%Q or fnr=%Q", |
|
aa82965…
|
drh
|
92 |
zTreename, zTreename); |
|
aa82965…
|
drh
|
93 |
blob_appendf(&script, " %s ", zOp); |
|
aa82965…
|
drh
|
94 |
fossil_free(zOp); |
|
aa82965…
|
drh
|
95 |
blob_append_tcl_literal(&script, zTreename, (int)strlen(zTreename)); |
|
aa82965…
|
drh
|
96 |
blob_reset(&fname); |
|
aa82965…
|
drh
|
97 |
} |
|
aa82965…
|
drh
|
98 |
} |
|
aa82965…
|
drh
|
99 |
blob_appendf(&script, "]\n"); |
|
aa82965…
|
drh
|
100 |
blob_appendf(&script, "set darkmode %d\n", bDark!=0); |
|
97aee32…
|
drh
|
101 |
blob_appendf(&script, "set debug %d\n", bDebug!=0); |
|
aa82965…
|
drh
|
102 |
blob_appendf(&script, "%s", builtin_file("merge.tcl", 0)); |
|
aa82965…
|
drh
|
103 |
if( zTempFile ){ |
|
aa82965…
|
drh
|
104 |
blob_write_to_file(&script, zTempFile); |
|
aa82965…
|
drh
|
105 |
fossil_print("To see the merge, run: %s \"%s\"\n", zTclsh, zTempFile); |
|
aa82965…
|
drh
|
106 |
}else{ |
|
aa82965…
|
drh
|
107 |
#if defined(FOSSIL_ENABLE_TCL) |
|
aa82965…
|
drh
|
108 |
Th_FossilInit(TH_INIT_DEFAULT); |
|
aa82965…
|
drh
|
109 |
if( evaluateTclWithEvents(g.interp, &g.tcl, blob_str(&script), |
|
aa82965…
|
drh
|
110 |
blob_size(&script), 1, 1, 0)==TCL_OK ){ |
|
aa82965…
|
drh
|
111 |
blob_reset(&script); |
|
aa82965…
|
drh
|
112 |
return; |
|
aa82965…
|
drh
|
113 |
} |
|
aa82965…
|
drh
|
114 |
/* |
|
aa82965…
|
drh
|
115 |
* If evaluation of the Tcl script fails, the reason may be that Tk |
|
aa82965…
|
drh
|
116 |
* could not be found by the loaded Tcl, or that Tcl cannot be loaded |
|
aa82965…
|
drh
|
117 |
* dynamically (e.g. x64 Tcl with x86 Fossil). Therefore, fallback |
|
aa82965…
|
drh
|
118 |
* to using the external "tclsh", if available. |
|
aa82965…
|
drh
|
119 |
*/ |
|
aa82965…
|
drh
|
120 |
#endif |
|
aa82965…
|
drh
|
121 |
zTempFile = write_blob_to_temp_file(&script); |
|
aa82965…
|
drh
|
122 |
zCmd = mprintf("%$ %$", zTclsh, zTempFile); |
|
97aee32…
|
drh
|
123 |
if( bDebug ){ |
|
97aee32…
|
drh
|
124 |
fossil_print("%s\n", zCmd); |
|
97aee32…
|
drh
|
125 |
fflush(stdout); |
|
97aee32…
|
drh
|
126 |
} |
|
aa82965…
|
drh
|
127 |
fossil_system(zCmd); |
|
aa82965…
|
drh
|
128 |
file_delete(zTempFile); |
|
aa82965…
|
drh
|
129 |
fossil_free(zCmd); |
|
aa82965…
|
drh
|
130 |
} |
|
aa82965…
|
drh
|
131 |
blob_reset(&script); |
|
aa82965…
|
drh
|
132 |
} |
|
aa82965…
|
drh
|
133 |
|
|
aa82965…
|
drh
|
134 |
/* |
|
aa82965…
|
drh
|
135 |
** Generate a TCL list on standard output that can be fed into the |
|
aa82965…
|
drh
|
136 |
** merge.tcl script to show the details of the most recent merge |
|
aa82965…
|
drh
|
137 |
** command associated with file "zFName". zFName must be the filename |
|
aa82965…
|
drh
|
138 |
** relative to the root of the check-in - in other words a "tree name". |
|
aa82965…
|
drh
|
139 |
** |
|
aa82965…
|
drh
|
140 |
** When this routine is called, we know that the mergestat table |
|
aa82965…
|
drh
|
141 |
** exists, but we do not know if zFName is mentioned in that table. |
|
f5cb12d…
|
drh
|
142 |
** |
|
f5cb12d…
|
drh
|
143 |
** The diffMode variable has these values: |
|
f5cb12d…
|
drh
|
144 |
** |
|
f5cb12d…
|
drh
|
145 |
** 0 Standard 3-way diff |
|
f5cb12d…
|
drh
|
146 |
** 12 2-way diff between baseline and local |
|
f5cb12d…
|
drh
|
147 |
** 13 2-way diff between baseline and merge-in |
|
f5cb12d…
|
drh
|
148 |
** 23 2-way diff between local and merge-in |
|
aa82965…
|
drh
|
149 |
*/ |
|
f5cb12d…
|
drh
|
150 |
static void merge_info_tcl(const char *zFName, int nContext, int diffMode){ |
|
aa82965…
|
drh
|
151 |
const char *zTreename;/* Name of the file in the tree */ |
|
aa82965…
|
drh
|
152 |
Stmt q; /* To query the MERGESTAT table */ |
|
aa82965…
|
drh
|
153 |
MergeBuilder mb; /* The merge builder object */ |
|
aa82965…
|
drh
|
154 |
Blob pivot,v1,v2,out; /* Blobs for holding content */ |
|
aa82965…
|
drh
|
155 |
const char *zFN; /* A filename */ |
|
aa82965…
|
drh
|
156 |
int rid; /* RID value */ |
|
aa82965…
|
drh
|
157 |
int sz; /* File size value */ |
|
aa82965…
|
drh
|
158 |
|
|
aa82965…
|
drh
|
159 |
zTreename = zFName; |
|
aa82965…
|
drh
|
160 |
db_prepare(&q, |
|
aa82965…
|
drh
|
161 |
/* 0 1 2 3 4 5 6 7 */ |
|
aa82965…
|
drh
|
162 |
"SELECT fnp, ridp, fn, ridv, sz, fnm, ridm, fnr" |
|
aa82965…
|
drh
|
163 |
" FROM mergestat" |
|
aa82965…
|
drh
|
164 |
" WHERE fnp=%Q OR fnr=%Q", |
|
aa82965…
|
drh
|
165 |
zTreename, zTreename |
|
aa82965…
|
drh
|
166 |
); |
|
aa82965…
|
drh
|
167 |
if( db_step(&q)!=SQLITE_ROW ){ |
|
aa82965…
|
drh
|
168 |
db_finalize(&q); |
|
aa82965…
|
drh
|
169 |
fossil_print("ERROR {don't know anything about file: %s}\n", zTreename); |
|
aa82965…
|
drh
|
170 |
return; |
|
aa82965…
|
drh
|
171 |
} |
|
aa82965…
|
drh
|
172 |
mergebuilder_init_tcl(&mb); |
|
aa82965…
|
drh
|
173 |
mb.nContext = nContext; |
|
aa82965…
|
drh
|
174 |
|
|
f5cb12d…
|
drh
|
175 |
blob_zero(&pivot); |
|
f5cb12d…
|
drh
|
176 |
if( diffMode!=23 ){ |
|
f5cb12d…
|
drh
|
177 |
/* Set up the pivot or baseline */ |
|
f5cb12d…
|
drh
|
178 |
zFN = db_column_text(&q, 0); |
|
f5cb12d…
|
drh
|
179 |
if( zFN==0 ){ |
|
f5cb12d…
|
drh
|
180 |
/* No pivot because the file was added */ |
|
f5cb12d…
|
drh
|
181 |
mb.zPivot = "(no baseline)"; |
|
f5cb12d…
|
drh
|
182 |
}else{ |
|
f5cb12d…
|
drh
|
183 |
mb.zPivot = mprintf("%s (baseline)", file_tail(zFN)); |
|
f5cb12d…
|
drh
|
184 |
rid = db_column_int(&q, 1); |
|
f5cb12d…
|
drh
|
185 |
content_get(rid, &pivot); |
|
f5cb12d…
|
drh
|
186 |
} |
|
f5cb12d…
|
drh
|
187 |
mb.pPivot = &pivot; |
|
f5cb12d…
|
drh
|
188 |
} |
|
f5cb12d…
|
drh
|
189 |
|
|
f5cb12d…
|
drh
|
190 |
blob_zero(&v2); |
|
f5cb12d…
|
drh
|
191 |
if( diffMode!=12 ){ |
|
f5cb12d…
|
drh
|
192 |
/* Set up the merge-in as V2 */ |
|
f5cb12d…
|
drh
|
193 |
zFN = db_column_text(&q, 5); |
|
f5cb12d…
|
drh
|
194 |
if( zFN==0 ){ |
|
f5cb12d…
|
drh
|
195 |
/* File deleted in the merged-in branch */ |
|
f5cb12d…
|
drh
|
196 |
mb.zV2 = "(deleted file)"; |
|
f5cb12d…
|
drh
|
197 |
}else{ |
|
f5cb12d…
|
drh
|
198 |
mb.zV2 = mprintf("%s (merge-in)", file_tail(zFN)); |
|
f5cb12d…
|
drh
|
199 |
rid = db_column_int(&q, 6); |
|
f5cb12d…
|
drh
|
200 |
content_get(rid, &v2); |
|
f5cb12d…
|
drh
|
201 |
} |
|
f5cb12d…
|
drh
|
202 |
mb.pV2 = &v2; |
|
f5cb12d…
|
drh
|
203 |
} |
|
f5cb12d…
|
drh
|
204 |
|
|
f5cb12d…
|
drh
|
205 |
blob_zero(&v1); |
|
f5cb12d…
|
drh
|
206 |
if( diffMode!=13 ){ |
|
f5cb12d…
|
drh
|
207 |
/* Set up the local content as V1 */ |
|
f5cb12d…
|
drh
|
208 |
zFN = db_column_text(&q, 2); |
|
f5cb12d…
|
drh
|
209 |
if( zFN==0 ){ |
|
f5cb12d…
|
drh
|
210 |
/* File added by merge */ |
|
f5cb12d…
|
drh
|
211 |
mb.zV1 = "(no original)"; |
|
f5cb12d…
|
drh
|
212 |
}else{ |
|
f5cb12d…
|
drh
|
213 |
mb.zV1 = mprintf("%s (local)", file_tail(zFN)); |
|
f5cb12d…
|
drh
|
214 |
rid = db_column_int(&q, 3); |
|
f5cb12d…
|
drh
|
215 |
sz = db_column_int(&q, 4); |
|
f5cb12d…
|
drh
|
216 |
if( rid==0 && sz>0 ){ |
|
f5cb12d…
|
drh
|
217 |
/* The origin file had been edited so we'll have to pull its |
|
f5cb12d…
|
drh
|
218 |
** original content out of the undo buffer */ |
|
f5cb12d…
|
drh
|
219 |
Stmt q2; |
|
f5cb12d…
|
drh
|
220 |
db_prepare(&q2, |
|
f5cb12d…
|
drh
|
221 |
"SELECT content FROM undo" |
|
f5cb12d…
|
drh
|
222 |
" WHERE pathname=%Q AND octet_length(content)=%d", |
|
f5cb12d…
|
drh
|
223 |
zFN, sz |
|
f5cb12d…
|
drh
|
224 |
); |
|
f5cb12d…
|
drh
|
225 |
blob_zero(&v1); |
|
f5cb12d…
|
drh
|
226 |
if( db_step(&q2)==SQLITE_ROW ){ |
|
f5cb12d…
|
drh
|
227 |
db_column_blob(&q2, 0, &v1); |
|
f5cb12d…
|
drh
|
228 |
}else{ |
|
f5cb12d…
|
drh
|
229 |
mb.zV1 = "(local content missing)"; |
|
f5cb12d…
|
drh
|
230 |
} |
|
f5cb12d…
|
drh
|
231 |
db_finalize(&q2); |
|
f5cb12d…
|
drh
|
232 |
}else{ |
|
f5cb12d…
|
drh
|
233 |
/* The origin file was unchanged when the merge first occurred */ |
|
f5cb12d…
|
drh
|
234 |
content_get(rid, &v1); |
|
f5cb12d…
|
drh
|
235 |
} |
|
f5cb12d…
|
drh
|
236 |
} |
|
f5cb12d…
|
drh
|
237 |
mb.pV1 = &v1; |
|
f5cb12d…
|
drh
|
238 |
} |
|
f5cb12d…
|
drh
|
239 |
|
|
f5cb12d…
|
drh
|
240 |
blob_zero(&out); |
|
f5cb12d…
|
drh
|
241 |
if( diffMode==0 ){ |
|
f5cb12d…
|
drh
|
242 |
/* Set up the output and do a 3-way diff */ |
|
f5cb12d…
|
drh
|
243 |
zFN = db_column_text(&q, 7); |
|
f5cb12d…
|
drh
|
244 |
if( zFN==0 ){ |
|
f5cb12d…
|
drh
|
245 |
mb.zOut = "(Merge Result)"; |
|
f5cb12d…
|
drh
|
246 |
}else{ |
|
f5cb12d…
|
drh
|
247 |
mb.zOut = mprintf("%s (after merge)", file_tail(zFN)); |
|
f5cb12d…
|
drh
|
248 |
} |
|
f5cb12d…
|
drh
|
249 |
mb.pOut = &out; |
|
f5cb12d…
|
drh
|
250 |
merge_three_blobs(&mb); |
|
f5cb12d…
|
drh
|
251 |
}else{ |
|
f5cb12d…
|
drh
|
252 |
/* Set up to do a two-way diff */ |
|
f5cb12d…
|
drh
|
253 |
Blob *pLeft, *pRight; |
|
f5cb12d…
|
drh
|
254 |
const char *zTagLeft, *zTagRight; |
|
f5cb12d…
|
drh
|
255 |
DiffConfig cfg; |
|
f5cb12d…
|
drh
|
256 |
memset(&cfg, 0, sizeof(cfg)); |
|
f5cb12d…
|
drh
|
257 |
cfg.diffFlags = DIFF_TCL; |
|
f5cb12d…
|
drh
|
258 |
cfg.nContext = mb.nContext; |
|
f5cb12d…
|
drh
|
259 |
if( diffMode==12 || diffMode==13 ){ |
|
f5cb12d…
|
drh
|
260 |
pLeft = &pivot; |
|
f5cb12d…
|
drh
|
261 |
zTagLeft = "baseline"; |
|
f5cb12d…
|
drh
|
262 |
}else{ |
|
f5cb12d…
|
drh
|
263 |
pLeft = &v1; |
|
f5cb12d…
|
drh
|
264 |
zTagLeft = "local"; |
|
f5cb12d…
|
drh
|
265 |
} |
|
f5cb12d…
|
drh
|
266 |
if( diffMode==12 ){ |
|
f5cb12d…
|
drh
|
267 |
pRight = &v1; |
|
f5cb12d…
|
drh
|
268 |
zTagRight = "local"; |
|
f5cb12d…
|
drh
|
269 |
}else{ |
|
f5cb12d…
|
drh
|
270 |
pRight = &v2; |
|
f5cb12d…
|
drh
|
271 |
zTagRight = "merge-in"; |
|
f5cb12d…
|
drh
|
272 |
} |
|
f5cb12d…
|
drh
|
273 |
cfg.azLabel[0] = mprintf("%s (%s)", zFName, zTagLeft); |
|
f5cb12d…
|
drh
|
274 |
cfg.azLabel[1] = mprintf("%s (%s)", zFName, zTagRight); |
|
f5cb12d…
|
drh
|
275 |
diff_print_filenames("", "", &cfg, &out); |
|
f5cb12d…
|
drh
|
276 |
text_diff(pLeft, pRight, &out, &cfg); |
|
f5cb12d…
|
drh
|
277 |
fossil_free((char*)cfg.azLabel[0]); |
|
f5cb12d…
|
drh
|
278 |
fossil_free((char*)cfg.azLabel[1]); |
|
f5cb12d…
|
drh
|
279 |
} |
|
f5cb12d…
|
drh
|
280 |
|
|
f5cb12d…
|
drh
|
281 |
blob_write_to_file(&out, "-"); |
|
aa82965…
|
drh
|
282 |
mb.xDestroy(&mb); |
|
aa82965…
|
drh
|
283 |
blob_reset(&pivot); |
|
aa82965…
|
drh
|
284 |
blob_reset(&v1); |
|
aa82965…
|
drh
|
285 |
blob_reset(&v2); |
|
aa82965…
|
drh
|
286 |
blob_reset(&out); |
|
aa82965…
|
drh
|
287 |
db_finalize(&q); |
|
aa82965…
|
drh
|
288 |
} |
|
aa82965…
|
drh
|
289 |
|
|
aa82965…
|
drh
|
290 |
/* |
|
aa82965…
|
drh
|
291 |
** COMMAND: merge-info |
|
aa82965…
|
drh
|
292 |
** |
|
aa82965…
|
drh
|
293 |
** Usage: %fossil merge-info [OPTIONS] |
|
aa82965…
|
drh
|
294 |
** |
|
aa82965…
|
drh
|
295 |
** Display information about the most recent merge operation. |
|
aa82965…
|
drh
|
296 |
** |
|
aa82965…
|
drh
|
297 |
** Options: |
|
6ebc9e0…
|
brickviking
|
298 |
** -a|--all Show all file changes that happened because of |
|
f8932be…
|
drh
|
299 |
** the merge. Normally only MERGE, CONFLICT, and ERROR |
|
f8932be…
|
drh
|
300 |
** lines are shown |
|
aa82965…
|
drh
|
301 |
** -c|--context N Show N lines of context around each change, |
|
aa82965…
|
drh
|
302 |
** with negative N meaning show all content. Only |
|
aa82965…
|
drh
|
303 |
** meaningful in combination with --tcl or --tk. |
|
aa82965…
|
drh
|
304 |
** --dark Use dark mode for the Tcl/Tk-based GUI |
|
f5cb12d…
|
drh
|
305 |
** --tk Bring up a Tcl/Tk GUI that shows the changes |
|
f5cb12d…
|
drh
|
306 |
** associated with the most recent merge. |
|
f5cb12d…
|
drh
|
307 |
** |
|
f5cb12d…
|
drh
|
308 |
** Options used internally by --tk: |
|
f5cb12d…
|
drh
|
309 |
** --diff12 FILE Bring up a separate --tk diff for just the baseline |
|
f5cb12d…
|
drh
|
310 |
** and local variants of FILE. |
|
f5cb12d…
|
drh
|
311 |
** --diff13 FILE Like --diff12 but for baseline versus merge-in |
|
f5cb12d…
|
drh
|
312 |
** --diff23 FILE Like --diff12 but for local versus merge-in |
|
aa82965…
|
drh
|
313 |
** --tcl FILE Generate (to stdout) a TCL list containing |
|
aa82965…
|
drh
|
314 |
** information needed to display the changes to |
|
aa82965…
|
drh
|
315 |
** FILE caused by the most recent merge. FILE must |
|
aa82965…
|
drh
|
316 |
** be a pathname relative to the root of the check-out. |
|
bbf6c30…
|
brickviking
|
317 |
** |
|
f5cb12d…
|
drh
|
318 |
** Debugging options available only when --tk is used: |
|
f5cb12d…
|
drh
|
319 |
** --tkdebug Show sub-commands run to implement --tk |
|
97aee32…
|
drh
|
320 |
** --script FILE Write script used to implement --tk into FILE |
|
aa82965…
|
drh
|
321 |
*/ |
|
aa82965…
|
drh
|
322 |
void merge_info_cmd(void){ |
|
aa82965…
|
drh
|
323 |
const char *zCnt; |
|
aa82965…
|
drh
|
324 |
const char *zTcl; |
|
aa82965…
|
drh
|
325 |
int bTk; |
|
aa82965…
|
drh
|
326 |
int bDark; |
|
aa82965…
|
drh
|
327 |
int bAll; |
|
aa82965…
|
drh
|
328 |
int nContext; |
|
aa82965…
|
drh
|
329 |
Stmt q; |
|
aa82965…
|
drh
|
330 |
const char *zWhere; |
|
aa82965…
|
drh
|
331 |
int cnt = 0; |
|
f5cb12d…
|
drh
|
332 |
const char *zDiff2 = 0; |
|
f5cb12d…
|
drh
|
333 |
int diffMode = 0; |
|
aa82965…
|
drh
|
334 |
|
|
aa82965…
|
drh
|
335 |
db_must_be_within_tree(); |
|
aa82965…
|
drh
|
336 |
bTk = find_option("tk", 0, 0)!=0; |
|
f5cb12d…
|
drh
|
337 |
zTcl = find_option("tcl", 0, 1); |
|
aa82965…
|
drh
|
338 |
zCnt = find_option("context", "c", 1); |
|
aa82965…
|
drh
|
339 |
bDark = find_option("dark", 0, 0)!=0; |
|
aa82965…
|
drh
|
340 |
bAll = find_option("all", "a", 0)!=0; |
|
f5cb12d…
|
drh
|
341 |
if( (zDiff2 = find_option("diff12", 0, 1))!=0 ){ |
|
f5cb12d…
|
drh
|
342 |
diffMode = 12; |
|
f5cb12d…
|
drh
|
343 |
}else |
|
f5cb12d…
|
drh
|
344 |
if( (zDiff2 = find_option("diff13", 0, 1))!=0 ){ |
|
f5cb12d…
|
drh
|
345 |
diffMode = 13; |
|
f5cb12d…
|
drh
|
346 |
}else |
|
f5cb12d…
|
drh
|
347 |
if( (zDiff2 = find_option("diff23", 0, 1))!=0 ){ |
|
f5cb12d…
|
drh
|
348 |
diffMode = 23; |
|
aa82965…
|
drh
|
349 |
} |
|
f5cb12d…
|
drh
|
350 |
|
|
aa82965…
|
drh
|
351 |
if( zCnt ){ |
|
aa82965…
|
drh
|
352 |
nContext = atoi(zCnt); |
|
aa82965…
|
drh
|
353 |
if( nContext<0 ) nContext = 0xfffffff; |
|
aa82965…
|
drh
|
354 |
}else{ |
|
aa82965…
|
drh
|
355 |
nContext = 6; |
|
aa82965…
|
drh
|
356 |
} |
|
aa82965…
|
drh
|
357 |
if( !db_table_exists("localdb","mergestat") ){ |
|
aa82965…
|
drh
|
358 |
if( zTcl ){ |
|
aa82965…
|
drh
|
359 |
fossil_print("ERROR {no merge data available}\n"); |
|
aa82965…
|
drh
|
360 |
}else{ |
|
aa82965…
|
drh
|
361 |
fossil_print("No merge data is available\n"); |
|
aa82965…
|
drh
|
362 |
} |
|
aa82965…
|
drh
|
363 |
return; |
|
aa82965…
|
drh
|
364 |
} |
|
aa82965…
|
drh
|
365 |
if( bTk ){ |
|
aa82965…
|
drh
|
366 |
merge_info_tk(bDark, bAll, nContext); |
|
aa82965…
|
drh
|
367 |
return; |
|
aa82965…
|
drh
|
368 |
} |
|
aa82965…
|
drh
|
369 |
if( zTcl ){ |
|
f5cb12d…
|
drh
|
370 |
if( diffMode ) zTcl = zDiff2; |
|
f5cb12d…
|
drh
|
371 |
merge_info_tcl(zTcl, nContext, diffMode); |
|
f5cb12d…
|
drh
|
372 |
return; |
|
f5cb12d…
|
drh
|
373 |
} |
|
f5cb12d…
|
drh
|
374 |
if( diffMode ){ |
|
f5cb12d…
|
drh
|
375 |
char *zCmd; |
|
f5cb12d…
|
drh
|
376 |
zCmd = mprintf("merge-info --diff%d %!$ -c %d%s", |
|
f5cb12d…
|
drh
|
377 |
diffMode, zDiff2, nContext, bDark ? " --dark" : ""); |
|
f5cb12d…
|
drh
|
378 |
diff_tk(zCmd, g.argc); |
|
f5cb12d…
|
drh
|
379 |
fossil_free(zCmd); |
|
aa82965…
|
drh
|
380 |
return; |
|
aa82965…
|
drh
|
381 |
} |
|
f5cb12d…
|
drh
|
382 |
|
|
f5cb12d…
|
drh
|
383 |
verify_all_options(); |
|
f5cb12d…
|
drh
|
384 |
if( g.argc>2 ){ |
|
f5cb12d…
|
drh
|
385 |
usage("[OPTIONS]"); |
|
f5cb12d…
|
drh
|
386 |
} |
|
f5cb12d…
|
drh
|
387 |
|
|
aa82965…
|
drh
|
388 |
if( bAll ){ |
|
aa82965…
|
drh
|
389 |
zWhere = ""; |
|
aa82965…
|
drh
|
390 |
}else{ |
|
aa82965…
|
drh
|
391 |
zWhere = "WHERE op IN ('MERGE','CONFLICT','ERROR')"; |
|
aa82965…
|
drh
|
392 |
} |
|
aa82965…
|
drh
|
393 |
db_prepare(&q, |
|
0b5dfa9…
|
drh
|
394 |
"WITH priority(op,pri) AS (VALUES('CONFLICT',0),('ERROR',0)," |
|
0b5dfa9…
|
drh
|
395 |
"('MERGE',1),('ADDED',2),('UPDATE',2))" |
|
0b5dfa9…
|
drh
|
396 |
|
|
aa82965…
|
drh
|
397 |
/* 0 1 2 */ |
|
aa82965…
|
drh
|
398 |
"SELECT op, coalesce(fnr,fn), msg" |
|
0b5dfa9…
|
drh
|
399 |
" FROM mergestat JOIN priority USING(op)" |
|
aa82965…
|
drh
|
400 |
" %s" |
|
0b5dfa9…
|
drh
|
401 |
" ORDER BY pri, coalesce(fnr,fn)", |
|
aa82965…
|
drh
|
402 |
zWhere /*safe-for-%s*/ |
|
aa82965…
|
drh
|
403 |
); |
|
aa82965…
|
drh
|
404 |
while( db_step(&q)==SQLITE_ROW ){ |
|
aa82965…
|
drh
|
405 |
const char *zOp = db_column_text(&q, 0); |
|
aa82965…
|
drh
|
406 |
const char *zName = db_column_text(&q, 1); |
|
aa82965…
|
drh
|
407 |
const char *zErr = db_column_text(&q, 2); |
|
aa82965…
|
drh
|
408 |
if( zErr && fossil_strcmp(zOp,"CONFLICT")!=0 ){ |
|
aa82965…
|
drh
|
409 |
fossil_print("%-9s %s (%s)\n", zOp, zName, zErr); |
|
aa82965…
|
drh
|
410 |
}else{ |
|
aa82965…
|
drh
|
411 |
fossil_print("%-9s %s\n", zOp, zName); |
|
aa82965…
|
drh
|
412 |
} |
|
aa82965…
|
drh
|
413 |
cnt++; |
|
aa82965…
|
drh
|
414 |
} |
|
aa82965…
|
drh
|
415 |
db_finalize(&q); |
|
aa82965…
|
drh
|
416 |
if( !bAll && cnt==0 ){ |
|
aa82965…
|
drh
|
417 |
fossil_print( |
|
0b5dfa9…
|
drh
|
418 |
"No interesting changes in this merge. Use --all to see everything.\n" |
|
aa82965…
|
drh
|
419 |
); |
|
aa82965…
|
drh
|
420 |
} |
|
aa82965…
|
drh
|
421 |
} |
|
aa82965…
|
drh
|
422 |
|
|
aa82965…
|
drh
|
423 |
/* |
|
aa82965…
|
drh
|
424 |
** Erase all information about prior merges. Do this, for example, after |
|
aa82965…
|
drh
|
425 |
** a commit. |
|
aa82965…
|
drh
|
426 |
*/ |
|
aa82965…
|
drh
|
427 |
void merge_info_forget(void){ |
|
55f1366…
|
drh
|
428 |
db_multi_exec( |
|
55f1366…
|
drh
|
429 |
"DROP TABLE IF EXISTS localdb.mergestat;" |
|
55f1366…
|
drh
|
430 |
"DELETE FROM localdb.vvar WHERE name glob 'mergestat-*';" |
|
55f1366…
|
drh
|
431 |
); |
|
aa82965…
|
drh
|
432 |
} |
|
aa82965…
|
drh
|
433 |
|
|
aa82965…
|
drh
|
434 |
|
|
aa82965…
|
drh
|
435 |
/* |
|
aa82965…
|
drh
|
436 |
** Initialize the MERGESTAT table. |
|
aa82965…
|
drh
|
437 |
** |
|
aa82965…
|
drh
|
438 |
** Notes about mergestat: |
|
aa82965…
|
drh
|
439 |
** |
|
aa82965…
|
drh
|
440 |
** * ridv is a positive integer and sz is NULL if the V file contained |
|
aa82965…
|
drh
|
441 |
** no local edits prior to the merge. If the V file was modified prior |
|
aa82965…
|
drh
|
442 |
** to the merge then ridv is NULL and sz is the size of the file prior |
|
aa82965…
|
drh
|
443 |
** to merge. |
|
aa82965…
|
drh
|
444 |
** |
|
aa82965…
|
drh
|
445 |
** * fnp, ridp, fn, ridv, and sz are all NULL for a file that was |
|
aa82965…
|
drh
|
446 |
** added by merge. |
|
aa82965…
|
drh
|
447 |
*/ |
|
aa82965…
|
drh
|
448 |
void merge_info_init(void){ |
|
55f1366…
|
drh
|
449 |
merge_info_forget(); |
|
aa82965…
|
drh
|
450 |
db_multi_exec( |
|
aa82965…
|
drh
|
451 |
"CREATE TABLE localdb.mergestat(\n" |
|
aa82965…
|
drh
|
452 |
" op TEXT, -- 'UPDATE', 'ADDED', 'MERGE', etc...\n" |
|
aa82965…
|
drh
|
453 |
" fnp TEXT, -- Name of the pivot file (P)\n" |
|
aa82965…
|
drh
|
454 |
" ridp INT, -- RID for the pivot file\n" |
|
aa82965…
|
drh
|
455 |
" fn TEXT, -- Name of origin file (V)\n" |
|
aa82965…
|
drh
|
456 |
" ridv INT, -- RID for origin file, or NULL if previously edited\n" |
|
aa82965…
|
drh
|
457 |
" sz INT, -- Size of origin file in bytes, NULL if unedited\n" |
|
aa82965…
|
drh
|
458 |
" fnm TEXT, -- Name of the file being merged in (M)\n" |
|
aa82965…
|
drh
|
459 |
" ridm INT, -- RID for the merge-in file\n" |
|
aa82965…
|
drh
|
460 |
" fnr TEXT, -- Name of the final output file, after all renaming\n" |
|
aa82965…
|
drh
|
461 |
" nc INT DEFAULT 0, -- Number of conflicts\n" |
|
aa82965…
|
drh
|
462 |
" msg TEXT -- Error message\n" |
|
aa82965…
|
drh
|
463 |
");" |
|
aa82965…
|
drh
|
464 |
); |
|
aa82965…
|
drh
|
465 |
} |
|
aa82965…
|
drh
|
466 |
|
|
68d8404…
|
drh
|
467 |
/* |
|
68d8404…
|
drh
|
468 |
** Print information about a particular check-in. |
|
68d8404…
|
drh
|
469 |
*/ |
|
68d8404…
|
drh
|
470 |
void print_checkin_description(int rid, int indent, const char *zLabel){ |
|
68d8404…
|
drh
|
471 |
Stmt q; |
|
68d8404…
|
drh
|
472 |
db_prepare(&q, |
|
ea63a2d…
|
drh
|
473 |
"SELECT datetime(mtime,toLocal())," |
|
68d8404…
|
drh
|
474 |
" coalesce(euser,user), coalesce(ecomment,comment)," |
|
68d8404…
|
drh
|
475 |
" (SELECT uuid FROM blob WHERE rid=%d)," |
|
68d8404…
|
drh
|
476 |
" (SELECT group_concat(substr(tagname,5), ', ') FROM tag, tagxref" |
|
68d8404…
|
drh
|
477 |
" WHERE tagname GLOB 'sym-*' AND tag.tagid=tagxref.tagid" |
|
68d8404…
|
drh
|
478 |
" AND tagxref.rid=%d AND tagxref.tagtype>0)" |
|
ea63a2d…
|
drh
|
479 |
" FROM event WHERE objid=%d", rid, rid, rid); |
|
68d8404…
|
drh
|
480 |
if( db_step(&q)==SQLITE_ROW ){ |
|
68d8404…
|
drh
|
481 |
const char *zTagList = db_column_text(&q, 4); |
|
68d8404…
|
drh
|
482 |
char *zCom; |
|
68d8404…
|
drh
|
483 |
if( zTagList && zTagList[0] ){ |
|
68d8404…
|
drh
|
484 |
zCom = mprintf("%s (%s)", db_column_text(&q, 2), zTagList); |
|
68d8404…
|
drh
|
485 |
}else{ |
|
4c3e172…
|
danield
|
486 |
zCom = fossil_strdup(db_column_text(&q,2)); |
|
68d8404…
|
drh
|
487 |
} |
|
080ab8c…
|
jan.nijtmans
|
488 |
fossil_print("%-*s [%S] by %s on %s\n%*s", |
|
68d8404…
|
drh
|
489 |
indent-1, zLabel, |
|
68d8404…
|
drh
|
490 |
db_column_text(&q, 3), |
|
68d8404…
|
drh
|
491 |
db_column_text(&q, 1), |
|
68d8404…
|
drh
|
492 |
db_column_text(&q, 0), |
|
68d8404…
|
drh
|
493 |
indent, ""); |
|
2476b81…
|
drh
|
494 |
comment_print(zCom, db_column_text(&q,2), indent, -1, get_comment_format()); |
|
68d8404…
|
drh
|
495 |
fossil_free(zCom); |
|
68d8404…
|
drh
|
496 |
} |
|
68d8404…
|
drh
|
497 |
db_finalize(&q); |
|
68d8404…
|
drh
|
498 |
} |
|
68d8404…
|
drh
|
499 |
|
|
68d8404…
|
drh
|
500 |
|
|
5c40f85…
|
jan.nijtmans
|
501 |
/* Pick the most recent leaf that is (1) not equal to vid and (2) |
|
5c40f85…
|
jan.nijtmans
|
502 |
** has not already been merged into vid and (3) the leaf is not |
|
5c40f85…
|
jan.nijtmans
|
503 |
** closed and (4) the leaf is in the same branch as vid. |
|
97f9767…
|
andybradford
|
504 |
** |
|
97f9767…
|
andybradford
|
505 |
** Set vmergeFlag to control whether the vmerge table is checked. |
|
5c40f85…
|
jan.nijtmans
|
506 |
*/ |
|
97f9767…
|
andybradford
|
507 |
int fossil_find_nearest_fork(int vid, int vmergeFlag){ |
|
97f9767…
|
andybradford
|
508 |
Blob sql; |
|
97f9767…
|
andybradford
|
509 |
Stmt q; |
|
97f9767…
|
andybradford
|
510 |
int rid = 0; |
|
97f9767…
|
andybradford
|
511 |
|
|
97f9767…
|
andybradford
|
512 |
blob_zero(&sql); |
|
97f9767…
|
andybradford
|
513 |
blob_append_sql(&sql, |
|
5c40f85…
|
jan.nijtmans
|
514 |
"SELECT leaf.rid" |
|
5c40f85…
|
jan.nijtmans
|
515 |
" FROM leaf, event" |
|
5c40f85…
|
jan.nijtmans
|
516 |
" WHERE leaf.rid=event.objid" |
|
97f9767…
|
andybradford
|
517 |
" AND leaf.rid!=%d", /* Constraint (1) */ |
|
97f9767…
|
andybradford
|
518 |
vid |
|
97f9767…
|
andybradford
|
519 |
); |
|
97f9767…
|
andybradford
|
520 |
if( vmergeFlag ){ |
|
97f9767…
|
andybradford
|
521 |
blob_append_sql(&sql, |
|
97f9767…
|
andybradford
|
522 |
" AND leaf.rid NOT IN (SELECT merge FROM vmerge)" /* Constraint (2) */ |
|
97f9767…
|
andybradford
|
523 |
); |
|
97f9767…
|
andybradford
|
524 |
} |
|
97f9767…
|
andybradford
|
525 |
blob_append_sql(&sql, |
|
5c40f85…
|
jan.nijtmans
|
526 |
" AND NOT EXISTS(SELECT 1 FROM tagxref" /* Constraint (3) */ |
|
5c40f85…
|
jan.nijtmans
|
527 |
" WHERE rid=leaf.rid" |
|
5c40f85…
|
jan.nijtmans
|
528 |
" AND tagid=%d" |
|
5c40f85…
|
jan.nijtmans
|
529 |
" AND tagtype>0)" |
|
5c40f85…
|
jan.nijtmans
|
530 |
" AND (SELECT value FROM tagxref" /* Constraint (4) */ |
|
5c40f85…
|
jan.nijtmans
|
531 |
" WHERE tagid=%d AND rid=%d AND tagtype>0) =" |
|
5c40f85…
|
jan.nijtmans
|
532 |
" (SELECT value FROM tagxref" |
|
5c40f85…
|
jan.nijtmans
|
533 |
" WHERE tagid=%d AND rid=leaf.rid AND tagtype>0)" |
|
5c40f85…
|
jan.nijtmans
|
534 |
" ORDER BY event.mtime DESC LIMIT 1", |
|
97f9767…
|
andybradford
|
535 |
TAG_CLOSED, TAG_BRANCH, vid, TAG_BRANCH |
|
97f9767…
|
andybradford
|
536 |
); |
|
97f9767…
|
andybradford
|
537 |
db_prepare(&q, "%s", blob_sql_text(&sql)); |
|
97f9767…
|
andybradford
|
538 |
blob_reset(&sql); |
|
97f9767…
|
andybradford
|
539 |
if( db_step(&q)==SQLITE_ROW ){ |
|
97f9767…
|
andybradford
|
540 |
rid = db_column_int(&q, 0); |
|
97f9767…
|
andybradford
|
541 |
} |
|
97f9767…
|
andybradford
|
542 |
db_finalize(&q); |
|
97f9767…
|
andybradford
|
543 |
return rid; |
|
97f9767…
|
andybradford
|
544 |
} |
|
97f9767…
|
andybradford
|
545 |
|
|
97f9767…
|
andybradford
|
546 |
/* |
|
560483f…
|
jan.nijtmans
|
547 |
** Check content that was received with rcvid and return true if any |
|
560483f…
|
jan.nijtmans
|
548 |
** fork was created. |
|
560483f…
|
jan.nijtmans
|
549 |
*/ |
|
560483f…
|
jan.nijtmans
|
550 |
int fossil_any_has_fork(int rcvid){ |
|
560483f…
|
jan.nijtmans
|
551 |
static Stmt q; |
|
560483f…
|
jan.nijtmans
|
552 |
int fForkSeen = 0; |
|
560483f…
|
jan.nijtmans
|
553 |
|
|
440ed5d…
|
andybradford
|
554 |
if( rcvid==0 ) return 0; |
|
560483f…
|
jan.nijtmans
|
555 |
db_static_prepare(&q, |
|
560483f…
|
jan.nijtmans
|
556 |
" SELECT pid FROM plink WHERE pid>0 AND isprim" |
|
560483f…
|
jan.nijtmans
|
557 |
" AND cid IN (SELECT blob.rid FROM blob" |
|
560483f…
|
jan.nijtmans
|
558 |
" WHERE rcvid=:rcvid)"); |
|
560483f…
|
jan.nijtmans
|
559 |
db_bind_int(&q, ":rcvid", rcvid); |
|
560483f…
|
jan.nijtmans
|
560 |
while( !fForkSeen && db_step(&q)==SQLITE_ROW ){ |
|
560483f…
|
jan.nijtmans
|
561 |
int pid = db_column_int(&q, 0); |
|
560483f…
|
jan.nijtmans
|
562 |
if( count_nonbranch_children(pid)>1 ){ |
|
560483f…
|
jan.nijtmans
|
563 |
compute_leaves(pid,1); |
|
560483f…
|
jan.nijtmans
|
564 |
if( db_int(0, "SELECT count(*) FROM leaves")>1 ){ |
|
560483f…
|
jan.nijtmans
|
565 |
int rid = db_int(0, "SELECT rid FROM leaves, event" |
|
560483f…
|
jan.nijtmans
|
566 |
" WHERE event.objid=leaves.rid" |
|
560483f…
|
jan.nijtmans
|
567 |
" ORDER BY event.mtime DESC LIMIT 1"); |
|
560483f…
|
jan.nijtmans
|
568 |
fForkSeen = fossil_find_nearest_fork(rid, db_open_local(0))!=0; |
|
560483f…
|
jan.nijtmans
|
569 |
} |
|
560483f…
|
jan.nijtmans
|
570 |
} |
|
560483f…
|
jan.nijtmans
|
571 |
} |
|
560483f…
|
jan.nijtmans
|
572 |
db_finalize(&q); |
|
560483f…
|
jan.nijtmans
|
573 |
return fForkSeen; |
|
560483f…
|
jan.nijtmans
|
574 |
} |
|
560483f…
|
jan.nijtmans
|
575 |
|
|
560483f…
|
jan.nijtmans
|
576 |
/* |
|
41c2220…
|
drh
|
577 |
** Add an entry to the FV table for all files renamed between |
|
41c2220…
|
drh
|
578 |
** version N and the version specified by vid. |
|
41c2220…
|
drh
|
579 |
*/ |
|
41c2220…
|
drh
|
580 |
static void add_renames( |
|
41c2220…
|
drh
|
581 |
const char *zFnCol, /* The FV column for the filename in vid */ |
|
bc36fdc…
|
danield
|
582 |
int vid, /* The desired version's- RID */ |
|
9db696e…
|
danield
|
583 |
int nid, /* The check-in rid for the name pivot */ |
|
b92e460…
|
wyoung
|
584 |
int revOK, /* OK to move backwards (child->parent) if true */ |
|
41c2220…
|
drh
|
585 |
const char *zDebug /* Generate trace output if not NULL */ |
|
41c2220…
|
drh
|
586 |
){ |
|
41c2220…
|
drh
|
587 |
int nChng; /* Number of file name changes */ |
|
41c2220…
|
drh
|
588 |
int *aChng; /* An array of file name changes */ |
|
41c2220…
|
drh
|
589 |
int i; /* Loop counter */ |
|
b92e460…
|
wyoung
|
590 |
find_filename_changes(nid, vid, revOK, &nChng, &aChng, zDebug); |
|
41c2220…
|
drh
|
591 |
if( nChng==0 ) return; |
|
41c2220…
|
drh
|
592 |
for(i=0; i<nChng; i++){ |
|
41c2220…
|
drh
|
593 |
char *zN, *zV; |
|
41c2220…
|
drh
|
594 |
zN = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2]); |
|
41c2220…
|
drh
|
595 |
zV = db_text(0, "SELECT name FROM filename WHERE fnid=%d", aChng[i*2+1]); |
|
41c2220…
|
drh
|
596 |
db_multi_exec( |
|
41c2220…
|
drh
|
597 |
"INSERT OR IGNORE INTO fv(%s,fnn) VALUES(%Q,%Q)", |
|
41c2220…
|
drh
|
598 |
zFnCol /*safe-for-%s*/, zV, zN |
|
41c2220…
|
drh
|
599 |
); |
|
41c2220…
|
drh
|
600 |
if( db_changes()==0 ){ |
|
41c2220…
|
drh
|
601 |
db_multi_exec( |
|
41c2220…
|
drh
|
602 |
"UPDATE fv SET %s=%Q WHERE fnn=%Q", |
|
41c2220…
|
drh
|
603 |
zFnCol /*safe-for-%s*/, zV, zN |
|
41c2220…
|
drh
|
604 |
); |
|
41c2220…
|
drh
|
605 |
} |
|
41c2220…
|
drh
|
606 |
free(zN); |
|
41c2220…
|
drh
|
607 |
free(zV); |
|
41c2220…
|
drh
|
608 |
} |
|
41c2220…
|
drh
|
609 |
free(aChng); |
|
41c2220…
|
drh
|
610 |
} |
|
41c2220…
|
drh
|
611 |
|
|
fff37e6…
|
drh
|
612 |
/* Make an entry in the vmerge table for the given id, and rid. |
|
fff37e6…
|
drh
|
613 |
*/ |
|
fff37e6…
|
drh
|
614 |
static void vmerge_insert(int id, int rid){ |
|
fff37e6…
|
drh
|
615 |
db_multi_exec( |
|
fff37e6…
|
drh
|
616 |
"INSERT OR IGNORE INTO vmerge(id,merge,mhash)" |
|
fff37e6…
|
drh
|
617 |
"VALUES(%d,%d,(SELECT uuid FROM blob WHERE rid=%d))", |
|
fff37e6…
|
drh
|
618 |
id, rid, rid |
|
fff37e6…
|
drh
|
619 |
); |
|
fff37e6…
|
drh
|
620 |
} |
|
fff37e6…
|
drh
|
621 |
|
|
fff37e6…
|
drh
|
622 |
/* |
|
32778cc…
|
drh
|
623 |
** Print the contents of the "fv" table on standard output, for debugging |
|
32778cc…
|
drh
|
624 |
** purposes. |
|
0d4d85b…
|
drh
|
625 |
** |
|
0d4d85b…
|
drh
|
626 |
** Only show entries where a file has changed, unless showAll is true. |
|
32778cc…
|
drh
|
627 |
*/ |
|
0d4d85b…
|
drh
|
628 |
static void debug_fv_dump(int showAll){ |
|
32778cc…
|
drh
|
629 |
Stmt q; |
|
0d4d85b…
|
drh
|
630 |
if( showAll ){ |
|
0d4d85b…
|
drh
|
631 |
db_prepare(&q, |
|
0d4d85b…
|
drh
|
632 |
"SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, " |
|
0d4d85b…
|
drh
|
633 |
" isexe, islinkv, islinkm, fnn FROM fv" |
|
0d4d85b…
|
drh
|
634 |
); |
|
0d4d85b…
|
drh
|
635 |
}else{ |
|
0d4d85b…
|
drh
|
636 |
db_prepare(&q, |
|
0d4d85b…
|
drh
|
637 |
"SELECT rowid, fn, fnp, fnm, chnged, ridv, ridp, ridm, " |
|
0d4d85b…
|
drh
|
638 |
" isexe, islinkv, islinkm, fnn FROM fv" |
|
0d4d85b…
|
drh
|
639 |
" WHERE chnged OR (ridv!=ridm AND ridm!=ridp)" |
|
0d4d85b…
|
drh
|
640 |
); |
|
0d4d85b…
|
drh
|
641 |
} |
|
32778cc…
|
drh
|
642 |
while( db_step(&q)==SQLITE_ROW ){ |
|
32778cc…
|
drh
|
643 |
fossil_print("%3d: ridv=%-4d ridp=%-4d ridm=%-4d chnged=%d isexe=%d " |
|
32778cc…
|
drh
|
644 |
" islinkv=%d islinkm=%d\n", |
|
32778cc…
|
drh
|
645 |
db_column_int(&q, 0), |
|
32778cc…
|
drh
|
646 |
db_column_int(&q, 5), |
|
32778cc…
|
drh
|
647 |
db_column_int(&q, 6), |
|
32778cc…
|
drh
|
648 |
db_column_int(&q, 7), |
|
32778cc…
|
drh
|
649 |
db_column_int(&q, 4), |
|
32778cc…
|
drh
|
650 |
db_column_int(&q, 8), |
|
32778cc…
|
drh
|
651 |
db_column_int(&q, 9), |
|
32778cc…
|
drh
|
652 |
db_column_int(&q, 10)); |
|
32778cc…
|
drh
|
653 |
fossil_print(" fn = [%s]\n", db_column_text(&q, 1)); |
|
32778cc…
|
drh
|
654 |
fossil_print(" fnp = [%s]\n", db_column_text(&q, 2)); |
|
32778cc…
|
drh
|
655 |
fossil_print(" fnm = [%s]\n", db_column_text(&q, 3)); |
|
32778cc…
|
drh
|
656 |
fossil_print(" fnn = [%s]\n", db_column_text(&q, 11)); |
|
32778cc…
|
drh
|
657 |
} |
|
32778cc…
|
drh
|
658 |
db_finalize(&q); |
|
32778cc…
|
drh
|
659 |
} |
|
32778cc…
|
drh
|
660 |
|
|
f35eb8e…
|
drh
|
661 |
/* |
|
f35eb8e…
|
drh
|
662 |
** Print the content of the VFILE table on standard output, for |
|
f35eb8e…
|
drh
|
663 |
** debugging purposes. |
|
f35eb8e…
|
drh
|
664 |
*/ |
|
f35eb8e…
|
drh
|
665 |
static void debug_show_vfile(void){ |
|
f35eb8e…
|
drh
|
666 |
Stmt q; |
|
f35eb8e…
|
drh
|
667 |
int pvid = -1; |
|
f35eb8e…
|
drh
|
668 |
db_prepare(&q, |
|
f35eb8e…
|
drh
|
669 |
"SELECT vid, id, chnged, deleted, isexe, islink, rid, mrid, mtime," |
|
f35eb8e…
|
drh
|
670 |
" pathname, origname, mhash FROM vfile" |
|
f35eb8e…
|
drh
|
671 |
" ORDER BY vid, pathname" |
|
f35eb8e…
|
drh
|
672 |
); |
|
f35eb8e…
|
drh
|
673 |
while( db_step(&q)==SQLITE_ROW ){ |
|
f35eb8e…
|
drh
|
674 |
int vid = db_column_int(&q, 0); |
|
f35eb8e…
|
drh
|
675 |
int chnged = db_column_int(&q, 2); |
|
f35eb8e…
|
drh
|
676 |
int dltd = db_column_int(&q, 3); |
|
f35eb8e…
|
drh
|
677 |
int isexe = db_column_int(&q, 4); |
|
f35eb8e…
|
drh
|
678 |
int islnk = db_column_int(&q, 5); |
|
f35eb8e…
|
drh
|
679 |
int rid = db_column_int(&q, 6); |
|
f35eb8e…
|
drh
|
680 |
int mrid = db_column_int(&q, 7); |
|
f35eb8e…
|
drh
|
681 |
const char *zPath = db_column_text(&q, 9); |
|
f35eb8e…
|
drh
|
682 |
const char *zOrig = db_column_text(&q, 10); |
|
f35eb8e…
|
drh
|
683 |
if( vid!=pvid ){ |
|
f35eb8e…
|
drh
|
684 |
fossil_print("VFILE vid=%d (%z):\n", vid, |
|
f35eb8e…
|
drh
|
685 |
db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid)); |
|
f35eb8e…
|
drh
|
686 |
pvid = vid; |
|
f35eb8e…
|
drh
|
687 |
} |
|
f35eb8e…
|
drh
|
688 |
fossil_print(" rid %-6d mrid %-6d %4s %3s %3s %3s %s", |
|
f35eb8e…
|
drh
|
689 |
rid, mrid, |
|
f35eb8e…
|
drh
|
690 |
chnged ? "chng" : "", |
|
f35eb8e…
|
drh
|
691 |
dltd ? "del" : "", |
|
f35eb8e…
|
drh
|
692 |
isexe ? "exe" : "", |
|
f35eb8e…
|
drh
|
693 |
islnk ? "lnk" : "", zPath); |
|
f35eb8e…
|
drh
|
694 |
if( zOrig && zOrig[0] ){ |
|
f35eb8e…
|
drh
|
695 |
fossil_print(" <- %s\n", zOrig); |
|
f35eb8e…
|
drh
|
696 |
}else{ |
|
f35eb8e…
|
drh
|
697 |
fossil_print("\n"); |
|
f35eb8e…
|
drh
|
698 |
} |
|
f35eb8e…
|
drh
|
699 |
} |
|
f35eb8e…
|
drh
|
700 |
db_finalize(&q); |
|
f35eb8e…
|
drh
|
701 |
} |
|
f35eb8e…
|
drh
|
702 |
|
|
f35eb8e…
|
drh
|
703 |
/* |
|
f35eb8e…
|
drh
|
704 |
** COMMAND: test-show-vfile |
|
f35eb8e…
|
drh
|
705 |
** Usage: %fossil test-show-vfile |
|
f35eb8e…
|
drh
|
706 |
** |
|
f35eb8e…
|
drh
|
707 |
** Show the content of the VFILE table in a local check-out. |
|
f35eb8e…
|
drh
|
708 |
*/ |
|
f35eb8e…
|
drh
|
709 |
void test_show_vfile_cmd(void){ |
|
f35eb8e…
|
drh
|
710 |
if( g.argc!=2 ){ |
|
f35eb8e…
|
drh
|
711 |
fossil_fatal("unknown arguments to the %s command\n", g.argv[1]); |
|
f35eb8e…
|
drh
|
712 |
} |
|
f35eb8e…
|
drh
|
713 |
verify_all_options(); |
|
f35eb8e…
|
drh
|
714 |
db_must_be_within_tree(); |
|
275da70…
|
danield
|
715 |
debug_show_vfile(); |
|
f35eb8e…
|
drh
|
716 |
} |
|
f35eb8e…
|
drh
|
717 |
|
|
32778cc…
|
drh
|
718 |
|
|
32778cc…
|
drh
|
719 |
/* |
|
dbda8d6…
|
drh
|
720 |
** COMMAND: merge |
|
67fe38c…
|
drh
|
721 |
** COMMAND: cherry-pick alias |
|
67fe38c…
|
drh
|
722 |
** COMMAND: cherrypick |
|
7c2577b…
|
drh
|
723 |
** |
|
67fe38c…
|
drh
|
724 |
** Usage: %fossil merge ?OPTIONS? ?VERSION ...? |
|
67fe38c…
|
drh
|
725 |
** Or: %fossil cherrypick ?OPTIONS? ?VERSION ...? |
|
7c2577b…
|
drh
|
726 |
** |
|
b0d1510…
|
drh
|
727 |
** The argument VERSION is a version that should be merged into the |
|
bc36fdc…
|
danield
|
728 |
** current check-out. All changes from VERSION back to the nearest |
|
edd08ef…
|
stephan
|
729 |
** common ancestor are merged. Except, if either of the --cherrypick |
|
edd08ef…
|
stephan
|
730 |
** or --backout options are used only the changes associated with the |
|
7c2577b…
|
drh
|
731 |
** single check-in VERSION are merged. The --backout option causes |
|
7c2577b…
|
drh
|
732 |
** the changes associated with VERSION to be removed from the current |
|
67fe38c…
|
drh
|
733 |
** check-out rather than added. When invoked with the name |
|
67fe38c…
|
drh
|
734 |
** "cherrypick" instead of "merge", this command works exactly like |
|
67fe38c…
|
drh
|
735 |
** "merge --cherrypick". |
|
edd08ef…
|
stephan
|
736 |
** |
|
edd08ef…
|
stephan
|
737 |
** Files which are renamed in the merged-in branch will be renamed in |
|
edd08ef…
|
stephan
|
738 |
** the current check-out. |
|
9ee47de…
|
drh
|
739 |
** |
|
9ee47de…
|
drh
|
740 |
** If the VERSION argument is omitted, then Fossil attempts to find |
|
9ee47de…
|
drh
|
741 |
** a recent fork on the current branch to merge. |
|
67fe38c…
|
drh
|
742 |
** |
|
75c45fd…
|
drh
|
743 |
** Note that this command does not commit the merge, as that is a |
|
75c45fd…
|
drh
|
744 |
** separate step. |
|
75c45fd…
|
drh
|
745 |
** |
|
67fe38c…
|
drh
|
746 |
** If there are multiple VERSION arguments, then each VERSION is merged |
|
67fe38c…
|
drh
|
747 |
** (or cherrypicked) in the order that they appear on the command-line. |
|
9ee47de…
|
drh
|
748 |
** |
|
29a383e…
|
drh
|
749 |
** Options: |
|
29a383e…
|
drh
|
750 |
** --backout Do a reverse cherrypick merge against VERSION. |
|
29a383e…
|
drh
|
751 |
** In other words, back out the changes that were |
|
29a383e…
|
drh
|
752 |
** added by VERSION. |
|
f7b4517…
|
drh
|
753 |
** --baseline BASELINE Use BASELINE as the "pivot" of the merge instead |
|
f7b4517…
|
drh
|
754 |
** of the nearest common ancestor. This allows |
|
f7b4517…
|
drh
|
755 |
** a sequence of changes in a branch to be merged |
|
f7b4517…
|
drh
|
756 |
** without having to merge the entire branch. |
|
7c2577b…
|
drh
|
757 |
** --binary GLOBPATTERN Treat files that match GLOBPATTERN as binary |
|
7c2577b…
|
drh
|
758 |
** and do not try to merge parallel changes. This |
|
7c2577b…
|
drh
|
759 |
** option overrides the "binary-glob" setting. |
|
29a383e…
|
drh
|
760 |
** --cherrypick Do a cherrypick merge VERSION into the current |
|
bc36fdc…
|
danield
|
761 |
** check-out. A cherrypick merge pulls in the changes |
|
29a383e…
|
drh
|
762 |
** of the single check-in VERSION, rather than all |
|
29a383e…
|
drh
|
763 |
** changes back to the nearest common ancestor. |
|
2e56ef4…
|
km
|
764 |
** -f|--force Force the merge even if it would be a no-op |
|
2e56ef4…
|
km
|
765 |
** --force-missing Force the merge even if there is missing content |
|
2e56ef4…
|
km
|
766 |
** --integrate Merged branch will be closed when committing |
|
d20ead1…
|
drh
|
767 |
** -K|--keep-merge-files On merge conflict, retain the temporary files |
|
d20ead1…
|
drh
|
768 |
** used for merging, named *-baseline, *-original, |
|
d20ead1…
|
drh
|
769 |
** and *-merge. |
|
aa82965…
|
drh
|
770 |
** -n|--dry-run Do not actually change files on disk |
|
e8a21ab…
|
drh
|
771 |
** --nosync Do not auto-sync prior to merging |
|
bdc6bb1…
|
danield
|
772 |
** --noundo Do not record changes in the undo log |
|
5214a2a…
|
jan.nijtmans
|
773 |
** -v|--verbose Show additional details of the merge |
|
dbda8d6…
|
drh
|
774 |
*/ |
|
dbda8d6…
|
drh
|
775 |
void merge_cmd(void){ |
|
c52927c…
|
drh
|
776 |
int vid; /* Current version "V" */ |
|
c52927c…
|
drh
|
777 |
int mid; /* Version we are merging from "M" */ |
|
d037468…
|
mistachkin
|
778 |
int pid = 0; /* The pivot version - most recent common ancestor P */ |
|
41c2220…
|
drh
|
779 |
int nid = 0; /* The name pivot version "N" */ |
|
5214a2a…
|
jan.nijtmans
|
780 |
int verboseFlag; /* True if the -v|--verbose option is present */ |
|
69dd259…
|
jan.nijtmans
|
781 |
int integrateFlag; /* True if the --integrate option is present */ |
|
390b414…
|
drh
|
782 |
int pickFlag; /* True if the --cherrypick option is present */ |
|
000af32…
|
drh
|
783 |
int backoutFlag; /* True if the --backout option is present */ |
|
0b86639…
|
jan.nijtmans
|
784 |
int dryRunFlag; /* True if the --dry-run or -n option is present */ |
|
5c420b1…
|
drh
|
785 |
int forceFlag; /* True if the --force or -f option is present */ |
|
16da1b6…
|
andybradford
|
786 |
int forceMissingFlag; /* True if the --force-missing option is present */ |
|
7c2577b…
|
drh
|
787 |
const char *zBinGlob; /* The value of --binary */ |
|
f7b4517…
|
drh
|
788 |
const char *zPivot; /* The value of --baseline */ |
|
c52927c…
|
drh
|
789 |
int debugFlag; /* True if --debug is present */ |
|
f35eb8e…
|
drh
|
790 |
int showVfileFlag; /* True if the --show-vfile flag is present */ |
|
d20ead1…
|
drh
|
791 |
int keepMergeFlag; /* True if --keep-merge-files is present */ |
|
c52927c…
|
drh
|
792 |
int nConflict = 0; /* Number of conflicts seen */ |
|
39f979b…
|
drh
|
793 |
int nOverwrite = 0; /* Number of unmanaged files overwritten */ |
|
41c2220…
|
drh
|
794 |
char vAncestor = 'p'; /* If P is an ancestor of V then 'p', else 'n' */ |
|
67fe38c…
|
drh
|
795 |
const char *zVersion; /* The VERSION argument */ |
|
67fe38c…
|
drh
|
796 |
int bMultiMerge = 0; /* True if there are two or more VERSION arguments */ |
|
67fe38c…
|
drh
|
797 |
int nMerge = 0; /* Number of prior merges processed */ |
|
3a39ae4…
|
drh
|
798 |
int useUndo = 1; /* True to record changes in the undo log */ |
|
e2bdc10…
|
danield
|
799 |
Stmt q; /* SQL statement used for merge processing */ |
|
c52927c…
|
drh
|
800 |
|
|
c52927c…
|
drh
|
801 |
|
|
c52927c…
|
drh
|
802 |
/* Notation: |
|
c52927c…
|
drh
|
803 |
** |
|
bc36fdc…
|
danield
|
804 |
** V The current check-out |
|
c52927c…
|
drh
|
805 |
** M The version being merged in |
|
c52927c…
|
drh
|
806 |
** P The "pivot" - the most recent common ancestor of V and M. |
|
41c2220…
|
drh
|
807 |
** N The "name pivot" - for detecting renames |
|
c52927c…
|
drh
|
808 |
*/ |
|
390b414…
|
drh
|
809 |
|
|
30981b6…
|
drh
|
810 |
undo_capture_command_line(); |
|
5214a2a…
|
jan.nijtmans
|
811 |
verboseFlag = find_option("verbose","v",0)!=0; |
|
16da1b6…
|
andybradford
|
812 |
forceMissingFlag = find_option("force-missing",0,0)!=0; |
|
5214a2a…
|
jan.nijtmans
|
813 |
if( !verboseFlag ){ |
|
5214a2a…
|
jan.nijtmans
|
814 |
verboseFlag = find_option("detail",0,0)!=0; /* deprecated */ |
|
5214a2a…
|
jan.nijtmans
|
815 |
} |
|
390b414…
|
drh
|
816 |
pickFlag = find_option("cherrypick",0,0)!=0; |
|
67fe38c…
|
drh
|
817 |
if('c'==*g.zCmdName /*called as cherrypick, possibly a short form*/){ |
|
0421108…
|
stephan
|
818 |
pickFlag = 1; |
|
0421108…
|
stephan
|
819 |
} |
|
69dd259…
|
jan.nijtmans
|
820 |
integrateFlag = find_option("integrate",0,0)!=0; |
|
7c2577b…
|
drh
|
821 |
backoutFlag = find_option("backout",0,0)!=0; |
|
7c2577b…
|
drh
|
822 |
zBinGlob = find_option("binary",0,1); |
|
0b86639…
|
jan.nijtmans
|
823 |
dryRunFlag = find_option("dry-run","n",0)!=0; |
|
0b86639…
|
jan.nijtmans
|
824 |
if( !dryRunFlag ){ |
|
0b86639…
|
jan.nijtmans
|
825 |
dryRunFlag = find_option("nochange",0,0)!=0; /* deprecated */ |
|
0b86639…
|
jan.nijtmans
|
826 |
} |
|
e8a21ab…
|
drh
|
827 |
if( find_option("nosync",0,0) ) g.fNoSync = 1; |
|
5c420b1…
|
drh
|
828 |
forceFlag = find_option("force","f",0)!=0; |
|
f7b4517…
|
drh
|
829 |
zPivot = find_option("baseline",0,1); |
|
d20ead1…
|
drh
|
830 |
keepMergeFlag = find_option("keep-merge-files", "K",0)!=0; |
|
0d4d85b…
|
drh
|
831 |
|
|
f35eb8e…
|
drh
|
832 |
/* Undocumented --debug and --show-vfile options: |
|
0d4d85b…
|
drh
|
833 |
** |
|
0d4d85b…
|
drh
|
834 |
** When included on the command-line, --debug causes lots of state |
|
0d4d85b…
|
drh
|
835 |
** information to be displayed. This option is undocumented as it |
|
0d4d85b…
|
drh
|
836 |
** might change or be eliminated in future releases. |
|
f35eb8e…
|
drh
|
837 |
** |
|
275da70…
|
danield
|
838 |
** The --show-vfile flag does a dump of the VFILE table for reference. |
|
0d4d85b…
|
drh
|
839 |
** |
|
0d4d85b…
|
drh
|
840 |
** Hints: |
|
0d4d85b…
|
drh
|
841 |
** * Combine --debug and --verbose for still more output. |
|
0d4d85b…
|
drh
|
842 |
** * The --dry-run option is also useful in combination with --debug. |
|
0d4d85b…
|
drh
|
843 |
*/ |
|
0d4d85b…
|
drh
|
844 |
debugFlag = find_option("debug",0,0)!=0; |
|
0d4d85b…
|
drh
|
845 |
if( debugFlag && verboseFlag ) debugFlag = 2; |
|
f35eb8e…
|
drh
|
846 |
showVfileFlag = find_option("show-vfile",0,0)!=0; |
|
3a39ae4…
|
drh
|
847 |
useUndo = find_option("noundo",0,0)==0; |
|
3a39ae4…
|
drh
|
848 |
if( dryRunFlag ) useUndo = 0; |
|
d20ead1…
|
drh
|
849 |
|
|
9ee47de…
|
drh
|
850 |
verify_all_options(); |
|
dbda8d6…
|
drh
|
851 |
db_must_be_within_tree(); |
|
7c2577b…
|
drh
|
852 |
if( zBinGlob==0 ) zBinGlob = db_get("binary-glob",0); |
|
dbda8d6…
|
drh
|
853 |
vid = db_lget_int("checkout", 0); |
|
dbda8d6…
|
drh
|
854 |
if( vid==0 ){ |
|
390b414…
|
drh
|
855 |
fossil_fatal("nothing is checked out"); |
|
390b414…
|
drh
|
856 |
} |
|
2cc7031…
|
drh
|
857 |
if( forceFlag==0 && leaf_is_closed(vid) ){ |
|
2cc7031…
|
drh
|
858 |
fossil_fatal("cannot merge into a closed leaf. Use --force to override"); |
|
2cc7031…
|
drh
|
859 |
} |
|
16501a0…
|
drh
|
860 |
if( !dryRunFlag ){ |
|
346e457…
|
drh
|
861 |
if( autosync_loop(SYNC_PULL + SYNC_VERBOSE*verboseFlag, 1, "merge") ){ |
|
d685096…
|
drh
|
862 |
fossil_fatal("merge abandoned due to sync failure"); |
|
16501a0…
|
drh
|
863 |
} |
|
16501a0…
|
drh
|
864 |
} |
|
16501a0…
|
drh
|
865 |
|
|
67fe38c…
|
drh
|
866 |
/* |
|
67fe38c…
|
drh
|
867 |
** A "multi-merge" means two or more other check-ins are being merged |
|
67fe38c…
|
drh
|
868 |
** into the current check-in. In other words, there are two or more |
|
67fe38c…
|
drh
|
869 |
** VERSION arguments on the command-line. Multi-merge works by doing |
|
67fe38c…
|
drh
|
870 |
** the merges one by one, as long as there are no conflicts. At the |
|
67fe38c…
|
drh
|
871 |
** bottom of this routine, a jump is made back up to this point if there |
|
67fe38c…
|
drh
|
872 |
** are more merges yet to be done and no errors have yet been seen. |
|
67fe38c…
|
drh
|
873 |
** |
|
67fe38c…
|
drh
|
874 |
** Related variables: |
|
67fe38c…
|
drh
|
875 |
** bMultiMerge True if there are one or more merges yet to do |
|
67fe38c…
|
drh
|
876 |
** zVersion The name of the current checking being merged in |
|
67fe38c…
|
drh
|
877 |
** nMerge Number of prior merges |
|
67fe38c…
|
drh
|
878 |
*/ |
|
67fe38c…
|
drh
|
879 |
merge_next_child: |
|
67fe38c…
|
drh
|
880 |
|
|
67fe38c…
|
drh
|
881 |
/* Find mid, the artifactID of the version to be merged into |
|
67fe38c…
|
drh
|
882 |
** the current check-out. |
|
67fe38c…
|
drh
|
883 |
*/ |
|
67fe38c…
|
drh
|
884 |
if( g.argc>=3 ){ |
|
67fe38c…
|
drh
|
885 |
int i; |
|
9ee47de…
|
drh
|
886 |
/* Mid is specified as an argument on the command-line */ |
|
67fe38c…
|
drh
|
887 |
zVersion = g.argv[2]; |
|
67fe38c…
|
drh
|
888 |
mid = name_to_typed_rid(zVersion, "ci"); |
|
9ee47de…
|
drh
|
889 |
if( mid==0 || !is_a_version(mid) ){ |
|
67fe38c…
|
drh
|
890 |
fossil_fatal("not a version: %s", zVersion); |
|
67fe38c…
|
drh
|
891 |
} |
|
67fe38c…
|
drh
|
892 |
bMultiMerge = g.argc>3; |
|
67fe38c…
|
drh
|
893 |
if( bMultiMerge ){ |
|
67fe38c…
|
drh
|
894 |
for(i=3; i<g.argc; i++) g.argv[i-1] = g.argv[i]; |
|
67fe38c…
|
drh
|
895 |
g.argc--; |
|
9ee47de…
|
drh
|
896 |
} |
|
9ee47de…
|
drh
|
897 |
}else if( g.argc==2 ){ |
|
9ee47de…
|
drh
|
898 |
/* No version specified on the command-line so pick the most recent |
|
9ee47de…
|
drh
|
899 |
** leaf that is (1) not the version currently checked out and (2) |
|
bc36fdc…
|
danield
|
900 |
** has not already been merged into the current check-out and (3) |
|
9ee47de…
|
drh
|
901 |
** the leaf is not closed and (4) the leaf is in the same branch |
|
bc36fdc…
|
danield
|
902 |
** as the current check-out. |
|
9ee47de…
|
drh
|
903 |
*/ |
|
9ee47de…
|
drh
|
904 |
Stmt q; |
|
69dd259…
|
jan.nijtmans
|
905 |
if( pickFlag || backoutFlag || integrateFlag){ |
|
5a88b5f…
|
drh
|
906 |
fossil_fatal("cannot use --backout, --cherrypick or --integrate " |
|
5a88b5f…
|
drh
|
907 |
"with a fork merge"); |
|
5c40f85…
|
jan.nijtmans
|
908 |
} |
|
97f9767…
|
andybradford
|
909 |
mid = fossil_find_nearest_fork(vid, db_open_local(0)); |
|
9ee47de…
|
drh
|
910 |
if( mid==0 ){ |
|
9ee47de…
|
drh
|
911 |
fossil_fatal("no unmerged forks of branch \"%s\"", |
|
9ee47de…
|
drh
|
912 |
db_text(0, "SELECT value FROM tagxref" |
|
8a470fd…
|
drh
|
913 |
" WHERE tagid=%d AND rid=%d AND tagtype>0", |
|
8a470fd…
|
drh
|
914 |
TAG_BRANCH, vid) |
|
9ee47de…
|
drh
|
915 |
); |
|
9ee47de…
|
drh
|
916 |
} |
|
9ee47de…
|
drh
|
917 |
db_prepare(&q, |
|
9ee47de…
|
drh
|
918 |
"SELECT blob.uuid," |
|
ea63a2d…
|
drh
|
919 |
" datetime(event.mtime,toLocal())," |
|
9ee47de…
|
drh
|
920 |
" coalesce(ecomment, comment)," |
|
9ee47de…
|
drh
|
921 |
" coalesce(euser, user)" |
|
9ee47de…
|
drh
|
922 |
" FROM event, blob" |
|
9ee47de…
|
drh
|
923 |
" WHERE event.objid=%d AND blob.rid=%d", |
|
ea63a2d…
|
drh
|
924 |
mid, mid |
|
9ee47de…
|
drh
|
925 |
); |
|
6e68958…
|
drh
|
926 |
zVersion = 0; |
|
9ee47de…
|
drh
|
927 |
if( db_step(&q)==SQLITE_ROW ){ |
|
9ee47de…
|
drh
|
928 |
char *zCom = mprintf("Merging fork [%S] at %s by %s: \"%s\"", |
|
9ee47de…
|
drh
|
929 |
db_column_text(&q, 0), db_column_text(&q, 1), |
|
9ee47de…
|
drh
|
930 |
db_column_text(&q, 3), db_column_text(&q, 2)); |
|
2476b81…
|
drh
|
931 |
comment_print(zCom, db_column_text(&q,2), 0, -1, get_comment_format()); |
|
9ee47de…
|
drh
|
932 |
fossil_free(zCom); |
|
6e68958…
|
drh
|
933 |
zVersion = mprintf("%S",db_column_text(&q,0)); |
|
9ee47de…
|
drh
|
934 |
} |
|
9ee47de…
|
drh
|
935 |
db_finalize(&q); |
|
9ee47de…
|
drh
|
936 |
}else{ |
|
9ee47de…
|
drh
|
937 |
usage("?OPTIONS? ?VERSION?"); |
|
39fa691…
|
jan.nijtmans
|
938 |
return; |
|
f7b4517…
|
drh
|
939 |
} |
|
9ee47de…
|
drh
|
940 |
|
|
f7b4517…
|
drh
|
941 |
if( zPivot ){ |
|
2a013f0…
|
drh
|
942 |
pid = name_to_typed_rid(zPivot, "ci"); |
|
f7b4517…
|
drh
|
943 |
if( pid==0 || !is_a_version(pid) ){ |
|
f7b4517…
|
drh
|
944 |
fossil_fatal("not a version: %s", zPivot); |
|
f7b4517…
|
drh
|
945 |
} |
|
f7b4517…
|
drh
|
946 |
if( pickFlag ){ |
|
5a88b5f…
|
drh
|
947 |
fossil_fatal("incompatible options: --cherrypick and --baseline"); |
|
f7b4517…
|
drh
|
948 |
} |
|
41c2220…
|
drh
|
949 |
} |
|
41c2220…
|
drh
|
950 |
if( pickFlag || backoutFlag ){ |
|
69dd259…
|
jan.nijtmans
|
951 |
if( integrateFlag ){ |
|
5a88b5f…
|
drh
|
952 |
fossil_fatal("incompatible options: --integrate and --cherrypick " |
|
5a88b5f…
|
drh
|
953 |
"with --backout"); |
|
69dd259…
|
jan.nijtmans
|
954 |
} |
|
f7b4517…
|
drh
|
955 |
pid = db_int(0, "SELECT pid FROM plink WHERE cid=%d AND isprim", mid); |
|
390b414…
|
drh
|
956 |
if( pid<=0 ){ |
|
67fe38c…
|
drh
|
957 |
fossil_fatal("cannot find an ancestor for %s", zVersion); |
|
f7b4517…
|
drh
|
958 |
} |
|
f7b4517…
|
drh
|
959 |
}else{ |
|
41c2220…
|
drh
|
960 |
if( !zPivot ){ |
|
41c2220…
|
drh
|
961 |
pivot_set_primary(mid); |
|
41c2220…
|
drh
|
962 |
pivot_set_secondary(vid); |
|
41c2220…
|
drh
|
963 |
db_prepare(&q, "SELECT merge FROM vmerge WHERE id=0"); |
|
41c2220…
|
drh
|
964 |
while( db_step(&q)==SQLITE_ROW ){ |
|
41c2220…
|
drh
|
965 |
pivot_set_secondary(db_column_int(&q,0)); |
|
41c2220…
|
drh
|
966 |
} |
|
41c2220…
|
drh
|
967 |
db_finalize(&q); |
|
41c2220…
|
drh
|
968 |
pid = pivot_find(0); |
|
41c2220…
|
drh
|
969 |
if( pid<=0 ){ |
|
41c2220…
|
drh
|
970 |
fossil_fatal("cannot find a common ancestor between the current " |
|
67fe38c…
|
drh
|
971 |
"check-out and %s", zVersion); |
|
41c2220…
|
drh
|
972 |
} |
|
41c2220…
|
drh
|
973 |
} |
|
f7b4517…
|
drh
|
974 |
pivot_set_primary(mid); |
|
f7b4517…
|
drh
|
975 |
pivot_set_secondary(vid); |
|
41c2220…
|
drh
|
976 |
nid = pivot_find(1); |
|
41c2220…
|
drh
|
977 |
if( nid!=pid ){ |
|
41c2220…
|
drh
|
978 |
pivot_set_primary(nid); |
|
41c2220…
|
drh
|
979 |
pivot_set_secondary(pid); |
|
41c2220…
|
drh
|
980 |
nid = pivot_find(1); |
|
390b414…
|
drh
|
981 |
} |
|
390b414…
|
drh
|
982 |
} |
|
f7b4517…
|
drh
|
983 |
if( backoutFlag ){ |
|
f7b4517…
|
drh
|
984 |
int t = pid; |
|
f7b4517…
|
drh
|
985 |
pid = mid; |
|
f7b4517…
|
drh
|
986 |
mid = t; |
|
f7b4517…
|
drh
|
987 |
} |
|
41c2220…
|
drh
|
988 |
if( nid==0 ) nid = pid; |
|
4e3cd6c…
|
drh
|
989 |
if( !is_a_version(pid) ){ |
|
4e3cd6c…
|
drh
|
990 |
fossil_fatal("not a version: record #%d", pid); |
|
4e3cd6c…
|
drh
|
991 |
} |
|
e84be9f…
|
stephan
|
992 |
if( !forceFlag && (mid==pid || mid==vid) ){ |
|
5c420b1…
|
drh
|
993 |
fossil_print("Merge skipped because it is a no-op. " |
|
5c420b1…
|
drh
|
994 |
" Use --force to override.\n"); |
|
bf07943…
|
drh
|
995 |
return; |
|
bf07943…
|
drh
|
996 |
} |
|
f9f7082…
|
jan.nijtmans
|
997 |
if( integrateFlag && !is_a_leaf(mid)){ |
|
67fe38c…
|
drh
|
998 |
fossil_warning("ignoring --integrate: %s is not a leaf", zVersion); |
|
b4beadb…
|
drh
|
999 |
integrateFlag = 0; |
|
b4beadb…
|
drh
|
1000 |
} |
|
b4beadb…
|
drh
|
1001 |
if( integrateFlag && content_is_private(mid) ){ |
|
b4beadb…
|
drh
|
1002 |
fossil_warning( |
|
b4beadb…
|
drh
|
1003 |
"ignoring --integrate: %s is on a private branch" |
|
b4beadb…
|
drh
|
1004 |
"\n Use \"fossil amend --close\" (after commit) to close the leaf.", |
|
67fe38c…
|
drh
|
1005 |
zVersion); |
|
f9f7082…
|
jan.nijtmans
|
1006 |
integrateFlag = 0; |
|
69dd259…
|
jan.nijtmans
|
1007 |
} |
|
5214a2a…
|
jan.nijtmans
|
1008 |
if( verboseFlag ){ |
|
5a88b5f…
|
drh
|
1009 |
print_checkin_description(mid, 12, |
|
5a88b5f…
|
drh
|
1010 |
integrateFlag ? "integrate:" : "merge-from:"); |
|
68d8404…
|
drh
|
1011 |
print_checkin_description(pid, 12, "baseline:"); |
|
68d8404…
|
drh
|
1012 |
} |
|
ae092ec…
|
drh
|
1013 |
vfile_check_signature(vid, CKSIG_ENOTFILE); |
|
67fe38c…
|
drh
|
1014 |
if( nMerge==0 ) db_begin_transaction(); |
|
3a39ae4…
|
drh
|
1015 |
if( useUndo ) undo_begin(); |
|
16da1b6…
|
andybradford
|
1016 |
if( load_vfile_from_rid(mid) && !forceMissingFlag ){ |
|
16da1b6…
|
andybradford
|
1017 |
fossil_fatal("missing content, unable to merge"); |
|
16da1b6…
|
andybradford
|
1018 |
} |
|
16da1b6…
|
andybradford
|
1019 |
if( load_vfile_from_rid(pid) && !forceMissingFlag ){ |
|
16da1b6…
|
andybradford
|
1020 |
fossil_fatal("missing content, unable to merge"); |
|
16da1b6…
|
andybradford
|
1021 |
} |
|
41c2220…
|
drh
|
1022 |
if( zPivot ){ |
|
41c2220…
|
drh
|
1023 |
vAncestor = db_exists( |
|
41c2220…
|
drh
|
1024 |
"WITH RECURSIVE ancestor(id) AS (" |
|
41c2220…
|
drh
|
1025 |
" VALUES(%d)" |
|
496c0fe…
|
jan.nijtmans
|
1026 |
" UNION" |
|
41c2220…
|
drh
|
1027 |
" SELECT pid FROM plink, ancestor" |
|
41c2220…
|
drh
|
1028 |
" WHERE cid=ancestor.id AND pid!=%d AND cid!=%d)" |
|
41c2220…
|
drh
|
1029 |
"SELECT 1 FROM ancestor WHERE id=%d LIMIT 1", |
|
41c2220…
|
drh
|
1030 |
vid, nid, pid, pid |
|
41c2220…
|
drh
|
1031 |
) ? 'p' : 'n'; |
|
41c2220…
|
drh
|
1032 |
} |
|
21acce3…
|
drh
|
1033 |
if( debugFlag ){ |
|
21acce3…
|
drh
|
1034 |
char *z; |
|
41c2220…
|
drh
|
1035 |
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", nid); |
|
32778cc…
|
drh
|
1036 |
fossil_print("N=%-4d %z (file rename pivot)\n", nid, z); |
|
21acce3…
|
drh
|
1037 |
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", pid); |
|
32778cc…
|
drh
|
1038 |
fossil_print("P=%-4d %z (file content pivot)\n", pid, z); |
|
21acce3…
|
drh
|
1039 |
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", mid); |
|
32778cc…
|
drh
|
1040 |
fossil_print("M=%-4d %z (merged-in version)\n", mid, z); |
|
21acce3…
|
drh
|
1041 |
z = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid); |
|
32778cc…
|
drh
|
1042 |
fossil_print("V=%-4d %z (current version)\n", vid, z); |
|
0d4d85b…
|
drh
|
1043 |
fossil_print("vAncestor = '%c'\n", vAncestor); |
|
21acce3…
|
drh
|
1044 |
} |
|
f35eb8e…
|
drh
|
1045 |
if( showVfileFlag ) debug_show_vfile(); |
|
dbda8d6…
|
drh
|
1046 |
|
|
dbda8d6…
|
drh
|
1047 |
/* |
|
dbda8d6…
|
drh
|
1048 |
** The vfile.pathname field is used to match files against each other. The |
|
e2bdc10…
|
danield
|
1049 |
** FV table contains one row for each unique filename in |
|
bc36fdc…
|
danield
|
1050 |
** in the current check-out, the pivot, and the version being merged. |
|
dbda8d6…
|
drh
|
1051 |
*/ |
|
dbda8d6…
|
drh
|
1052 |
db_multi_exec( |
|
dbda8d6…
|
drh
|
1053 |
"DROP TABLE IF EXISTS fv;" |
|
32778cc…
|
drh
|
1054 |
"CREATE TEMP TABLE fv(\n" |
|
32778cc…
|
drh
|
1055 |
" fn TEXT UNIQUE %s,\n" /* The filename */ |
|
32778cc…
|
drh
|
1056 |
" idv INTEGER DEFAULT 0,\n" /* VFILE entry for current version */ |
|
32778cc…
|
drh
|
1057 |
" idp INTEGER DEFAULT 0,\n" /* VFILE entry for the pivot */ |
|
32778cc…
|
drh
|
1058 |
" idm INTEGER DEFAULT 0,\n" /* VFILE entry for version merging in */ |
|
32778cc…
|
drh
|
1059 |
" chnged BOOLEAN,\n" /* True if current version has been edited */ |
|
32778cc…
|
drh
|
1060 |
" ridv INTEGER DEFAULT 0,\n" /* Record ID for current version */ |
|
32778cc…
|
drh
|
1061 |
" ridp INTEGER DEFAULT 0,\n" /* Record ID for pivot */ |
|
32778cc…
|
drh
|
1062 |
" ridm INTEGER DEFAULT 0,\n" /* Record ID for merge */ |
|
32778cc…
|
drh
|
1063 |
" isexe BOOLEAN,\n" /* Execute permission enabled */ |
|
32778cc…
|
drh
|
1064 |
" fnp TEXT UNIQUE %s,\n" /* The filename in the pivot */ |
|
32778cc…
|
drh
|
1065 |
" fnm TEXT UNIQUE %s,\n" /* The filename in the merged version */ |
|
32778cc…
|
drh
|
1066 |
" fnn TEXT UNIQUE %s,\n" /* The filename in the name pivot */ |
|
32778cc…
|
drh
|
1067 |
" islinkv BOOLEAN,\n" /* True if current version is a symlink */ |
|
32778cc…
|
drh
|
1068 |
" islinkm BOOLEAN\n" /* True if merged version in is a symlink */ |
|
41c2220…
|
drh
|
1069 |
");", |
|
41c2220…
|
drh
|
1070 |
filename_collation(), filename_collation(), filename_collation(), |
|
41c2220…
|
drh
|
1071 |
filename_collation() |
|
41c2220…
|
drh
|
1072 |
); |
|
41c2220…
|
drh
|
1073 |
|
|
41c2220…
|
drh
|
1074 |
/* |
|
41c2220…
|
drh
|
1075 |
** Compute name changes from N to V, P, and M |
|
41c2220…
|
drh
|
1076 |
*/ |
|
41c2220…
|
drh
|
1077 |
add_renames("fn", vid, nid, 0, debugFlag ? "N->V" : 0); |
|
41c2220…
|
drh
|
1078 |
add_renames("fnp", pid, nid, 0, debugFlag ? "N->P" : 0); |
|
41c2220…
|
drh
|
1079 |
add_renames("fnm", mid, nid, backoutFlag, debugFlag ? "N->M" : 0); |
|
dc850c9…
|
drh
|
1080 |
if( debugFlag ){ |
|
dc850c9…
|
drh
|
1081 |
fossil_print("******** FV after name change search *******\n"); |
|
dc850c9…
|
drh
|
1082 |
debug_fv_dump(1); |
|
dc850c9…
|
drh
|
1083 |
} |
|
cb4f38e…
|
drh
|
1084 |
if( nid!=pid ){ |
|
cb4f38e…
|
drh
|
1085 |
/* See forum thread https://fossil-scm.org/forum/forumpost/549700437b |
|
cb4f38e…
|
drh
|
1086 |
** |
|
cb4f38e…
|
drh
|
1087 |
** If a filename changes between nid and one of the other check-ins |
|
cb4f38e…
|
drh
|
1088 |
** pid, vid, or mid, then it might not have changed for all of them. |
|
cb4f38e…
|
drh
|
1089 |
** try to fill in the appropriate filename in all slots where the |
|
cb4f38e…
|
drh
|
1090 |
** name is missing. |
|
cb4f38e…
|
drh
|
1091 |
** |
|
cb4f38e…
|
drh
|
1092 |
** This does not work if |
|
cb4f38e…
|
drh
|
1093 |
** (1) The filename changes more than once in between nid and vid/mid |
|
cb4f38e…
|
drh
|
1094 |
** (2) Two or more filenames swap places - for example if A is renamed |
|
cb4f38e…
|
drh
|
1095 |
** to B and B is renamed to A. |
|
cb4f38e…
|
drh
|
1096 |
** The Fossil merge algorithm breaks down in those cases. It will need |
|
cb4f38e…
|
drh
|
1097 |
** to be completely rewritten to handle such complex cases. Such cases |
|
cb4f38e…
|
drh
|
1098 |
** appear to be rare, and also confusing to humans. |
|
cb4f38e…
|
drh
|
1099 |
*/ |
|
cb4f38e…
|
drh
|
1100 |
db_multi_exec( |
|
33e518b…
|
drh
|
1101 |
"UPDATE OR IGNORE fv SET fnp=vfile.pathname FROM vfile" |
|
33e518b…
|
drh
|
1102 |
" WHERE fnp IS NULL" |
|
33e518b…
|
drh
|
1103 |
" AND vfile.pathname = fv.fnn" |
|
33e518b…
|
drh
|
1104 |
" AND vfile.vid=%d;", |
|
33e518b…
|
drh
|
1105 |
pid |
|
33e518b…
|
drh
|
1106 |
); |
|
33e518b…
|
drh
|
1107 |
db_multi_exec( |
|
dc850c9…
|
drh
|
1108 |
"UPDATE OR IGNORE fv SET fn=vfile.pathname FROM vfile" |
|
cb4f38e…
|
drh
|
1109 |
" WHERE fn IS NULL" |
|
33e518b…
|
drh
|
1110 |
" AND vfile.pathname = coalesce(fv.fnp,fv.fnn)" |
|
cb4f38e…
|
drh
|
1111 |
" AND vfile.vid=%d;", |
|
cb4f38e…
|
drh
|
1112 |
vid |
|
33e518b…
|
drh
|
1113 |
); |
|
33e518b…
|
drh
|
1114 |
db_multi_exec( |
|
33e518b…
|
drh
|
1115 |
"UPDATE OR IGNORE fv SET fnm=vfile.pathname FROM vfile" |
|
33e518b…
|
drh
|
1116 |
" WHERE fnm IS NULL" |
|
33e518b…
|
drh
|
1117 |
" AND vfile.pathname = coalesce(fv.fnp,fv.fnn)" |
|
33e518b…
|
drh
|
1118 |
" AND vfile.vid=%d;", |
|
33e518b…
|
drh
|
1119 |
mid |
|
dc850c9…
|
drh
|
1120 |
); |
|
dc850c9…
|
drh
|
1121 |
db_multi_exec( |
|
dc850c9…
|
drh
|
1122 |
"UPDATE OR IGNORE fv SET fnp=vfile.pathname FROM vfile" |
|
cb4f38e…
|
drh
|
1123 |
" WHERE fnp IS NULL" |
|
33e518b…
|
drh
|
1124 |
" AND vfile.pathname IN (fv.fnm,fv.fn)" |
|
cb4f38e…
|
drh
|
1125 |
" AND vfile.vid=%d;", |
|
cb4f38e…
|
drh
|
1126 |
pid |
|
cb4f38e…
|
drh
|
1127 |
); |
|
cb4f38e…
|
drh
|
1128 |
db_multi_exec( |
|
33e518b…
|
drh
|
1129 |
"UPDATE OR IGNORE fv SET fn=vfile.pathname FROM vfile" |
|
33e518b…
|
drh
|
1130 |
" WHERE fn IS NULL" |
|
33e518b…
|
drh
|
1131 |
" AND vfile.pathname = fv.fnm" |
|
33e518b…
|
drh
|
1132 |
" AND vfile.vid=%d;", |
|
33e518b…
|
drh
|
1133 |
vid |
|
33e518b…
|
drh
|
1134 |
); |
|
33e518b…
|
drh
|
1135 |
db_multi_exec( |
|
dc850c9…
|
drh
|
1136 |
"UPDATE OR IGNORE fv SET fnm=vfile.pathname FROM vfile" |
|
cb4f38e…
|
drh
|
1137 |
" WHERE fnm IS NULL" |
|
33e518b…
|
drh
|
1138 |
" AND vfile.pathname = fv.fn" |
|
cb4f38e…
|
drh
|
1139 |
" AND vfile.vid=%d;", |
|
cb4f38e…
|
drh
|
1140 |
mid |
|
cb4f38e…
|
drh
|
1141 |
); |
|
cb4f38e…
|
drh
|
1142 |
} |
|
cb4f38e…
|
drh
|
1143 |
if( debugFlag ){ |
|
dc850c9…
|
drh
|
1144 |
fossil_print("******** FV after name change fill-in *******\n"); |
|
0d4d85b…
|
drh
|
1145 |
debug_fv_dump(1); |
|
32778cc…
|
drh
|
1146 |
} |
|
41c2220…
|
drh
|
1147 |
|
|
41c2220…
|
drh
|
1148 |
/* |
|
41c2220…
|
drh
|
1149 |
** Add files found in V |
|
41c2220…
|
drh
|
1150 |
*/ |
|
41c2220…
|
drh
|
1151 |
db_multi_exec( |
|
41c2220…
|
drh
|
1152 |
"UPDATE OR IGNORE fv SET fn=coalesce(fn%c,fnn) WHERE fn IS NULL;" |
|
41c2220…
|
drh
|
1153 |
"REPLACE INTO fv(fn,fnp,fnm,fnn,idv,ridv,islinkv,isexe,chnged)" |
|
41c2220…
|
drh
|
1154 |
" SELECT pathname, fnp, fnm, fnn, id, rid, islink, vf.isexe, vf.chnged" |
|
41c2220…
|
drh
|
1155 |
" FROM vfile vf" |
|
41c2220…
|
drh
|
1156 |
" LEFT JOIN fv ON fn=coalesce(origname,pathname)" |
|
41c2220…
|
drh
|
1157 |
" AND rid>0 AND vf.chnged NOT IN (3,5)" |
|
41c2220…
|
drh
|
1158 |
" WHERE vid=%d;", |
|
41c2220…
|
drh
|
1159 |
vAncestor, vid |
|
41c2220…
|
drh
|
1160 |
); |
|
0d4d85b…
|
drh
|
1161 |
if( debugFlag>=2 ){ |
|
32778cc…
|
drh
|
1162 |
fossil_print("******** FV after adding files in current version *******\n"); |
|
0d4d85b…
|
drh
|
1163 |
debug_fv_dump(1); |
|
32778cc…
|
drh
|
1164 |
} |
|
41c2220…
|
drh
|
1165 |
|
|
41c2220…
|
drh
|
1166 |
/* |
|
41c2220…
|
drh
|
1167 |
** Add files found in P |
|
41c2220…
|
drh
|
1168 |
*/ |
|
41c2220…
|
drh
|
1169 |
db_multi_exec( |
|
41c2220…
|
drh
|
1170 |
"UPDATE OR IGNORE fv SET fnp=coalesce(fnn," |
|
41c2220…
|
drh
|
1171 |
" (SELECT coalesce(origname,pathname) FROM vfile WHERE id=idv))" |
|
41c2220…
|
drh
|
1172 |
" WHERE fnp IS NULL;" |
|
41c2220…
|
drh
|
1173 |
"INSERT OR IGNORE INTO fv(fnp)" |
|
41c2220…
|
drh
|
1174 |
" SELECT coalesce(origname,pathname) FROM vfile WHERE vid=%d;", |
|
41c2220…
|
drh
|
1175 |
pid |
|
41c2220…
|
drh
|
1176 |
); |
|
0d4d85b…
|
drh
|
1177 |
if( debugFlag>=2 ){ |
|
0d4d85b…
|
drh
|
1178 |
fossil_print("******** FV after adding pivot files *******\n"); |
|
0d4d85b…
|
drh
|
1179 |
debug_fv_dump(1); |
|
0d4d85b…
|
drh
|
1180 |
} |
|
41c2220…
|
drh
|
1181 |
|
|
41c2220…
|
drh
|
1182 |
/* |
|
41c2220…
|
drh
|
1183 |
** Add files found in M |
|
41c2220…
|
drh
|
1184 |
*/ |
|
41c2220…
|
drh
|
1185 |
db_multi_exec( |
|
41c2220…
|
drh
|
1186 |
"UPDATE OR IGNORE fv SET fnm=fnp WHERE fnm IS NULL;" |
|
41c2220…
|
drh
|
1187 |
"INSERT OR IGNORE INTO fv(fnm)" |
|
41c2220…
|
drh
|
1188 |
" SELECT pathname FROM vfile WHERE vid=%d;", |
|
41c2220…
|
drh
|
1189 |
mid |
|
41c2220…
|
drh
|
1190 |
); |
|
0d4d85b…
|
drh
|
1191 |
if( debugFlag>=2 ){ |
|
0d4d85b…
|
drh
|
1192 |
fossil_print("******** FV after adding merge-in files *******\n"); |
|
0d4d85b…
|
drh
|
1193 |
debug_fv_dump(1); |
|
32778cc…
|
drh
|
1194 |
} |
|
41c2220…
|
drh
|
1195 |
|
|
41c2220…
|
drh
|
1196 |
/* |
|
41c2220…
|
drh
|
1197 |
** Compute the file version ids for P and M |
|
41c2220…
|
drh
|
1198 |
*/ |
|
41c2220…
|
drh
|
1199 |
if( pid==vid ){ |
|
41c2220…
|
drh
|
1200 |
db_multi_exec( |
|
41c2220…
|
drh
|
1201 |
"UPDATE fv SET idp=idv, ridp=ridv WHERE ridv>0 AND chnged NOT IN (3,5)" |
|
41c2220…
|
drh
|
1202 |
); |
|
41c2220…
|
drh
|
1203 |
}else{ |
|
41c2220…
|
drh
|
1204 |
db_multi_exec( |
|
33e518b…
|
drh
|
1205 |
"UPDATE fv SET idp=coalesce(vfile.id,0), ridp=coalesce(vfile.rid,0)" |
|
33e518b…
|
drh
|
1206 |
" FROM vfile" |
|
33e518b…
|
drh
|
1207 |
" WHERE vfile.vid=%d AND fv.fnp=vfile.pathname", |
|
33e518b…
|
drh
|
1208 |
pid |
|
41c2220…
|
drh
|
1209 |
); |
|
41c2220…
|
drh
|
1210 |
} |
|
a5a8d04…
|
drh
|
1211 |
db_multi_exec( |
|
a5a8d04…
|
drh
|
1212 |
"UPDATE fv SET" |
|
33e518b…
|
drh
|
1213 |
" idm=coalesce(vfile.id,0)," |
|
33e518b…
|
drh
|
1214 |
" ridm=coalesce(vfile.rid,0)," |
|
33e518b…
|
drh
|
1215 |
" islinkm=coalesce(vfile.islink,0)," |
|
33e518b…
|
drh
|
1216 |
" isexe=coalesce(vfile.isexe,fv.isexe)" |
|
33e518b…
|
drh
|
1217 |
" FROM vfile" |
|
33e518b…
|
drh
|
1218 |
" WHERE vid=%d AND fnm=pathname", |
|
33e518b…
|
drh
|
1219 |
mid |
|
32778cc…
|
drh
|
1220 |
); |
|
41c2220…
|
drh
|
1221 |
|
|
41c2220…
|
drh
|
1222 |
/* |
|
41c2220…
|
drh
|
1223 |
** Update the execute bit on files where it's changed from P->M but not P->V |
|
41c2220…
|
drh
|
1224 |
*/ |
|
41c2220…
|
drh
|
1225 |
db_prepare(&q, |
|
41c2220…
|
drh
|
1226 |
"SELECT idv, fn, fv.isexe FROM fv, vfile p, vfile v" |
|
41c2220…
|
drh
|
1227 |
" WHERE p.id=idp AND v.id=idv AND fv.isexe!=p.isexe AND v.isexe=p.isexe" |
|
41c2220…
|
drh
|
1228 |
); |
|
41c2220…
|
drh
|
1229 |
while( db_step(&q)==SQLITE_ROW ){ |
|
41c2220…
|
drh
|
1230 |
int idv = db_column_int(&q, 0); |
|
41c2220…
|
drh
|
1231 |
const char *zName = db_column_text(&q, 1); |
|
41c2220…
|
drh
|
1232 |
int isExe = db_column_int(&q, 2); |
|
41c2220…
|
drh
|
1233 |
fossil_print("%s %s\n", isExe ? "EXECUTABLE" : "UNEXEC", zName); |
|
41c2220…
|
drh
|
1234 |
if( !dryRunFlag ){ |
|
41c2220…
|
drh
|
1235 |
char *zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); |
|
1772357…
|
drh
|
1236 |
file_setexe(zFullPath, isExe); |
|
41c2220…
|
drh
|
1237 |
free(zFullPath); |
|
41c2220…
|
drh
|
1238 |
db_multi_exec("UPDATE vfile SET isexe=%d WHERE id=%d", isExe, idv); |
|
41c2220…
|
drh
|
1239 |
} |
|
41c2220…
|
drh
|
1240 |
} |
|
41c2220…
|
drh
|
1241 |
db_finalize(&q); |
|
0d4d85b…
|
drh
|
1242 |
if( debugFlag ){ |
|
0d4d85b…
|
drh
|
1243 |
fossil_print("******** FV final *******\n"); |
|
0d4d85b…
|
drh
|
1244 |
debug_fv_dump( debugFlag>=2 ); |
|
0d4d85b…
|
drh
|
1245 |
} |
|
41c2220…
|
drh
|
1246 |
|
|
0d4d85b…
|
drh
|
1247 |
/************************************************************************ |
|
0d4d85b…
|
drh
|
1248 |
** All of the information needed to do the merge is now contained in the |
|
0d4d85b…
|
drh
|
1249 |
** FV table. Starting here, we begin to actually carry out the merge. |
|
0d4d85b…
|
drh
|
1250 |
** |
|
aa82965…
|
drh
|
1251 |
** Begin by constructing the localdb.mergestat table. |
|
aa82965…
|
drh
|
1252 |
*/ |
|
aa82965…
|
drh
|
1253 |
merge_info_init(); |
|
aa82965…
|
drh
|
1254 |
|
|
aa82965…
|
drh
|
1255 |
/* |
|
aa82965…
|
drh
|
1256 |
** Find files that have changed from P->M but not P->V. |
|
c52927c…
|
drh
|
1257 |
** Copy the M content over into V. |
|
c52927c…
|
drh
|
1258 |
*/ |
|
c52927c…
|
drh
|
1259 |
db_prepare(&q, |
|
aa82965…
|
drh
|
1260 |
/* 0 1 2 3 4 5 6 7 */ |
|
aa82965…
|
drh
|
1261 |
"SELECT idv, ridm, fn, islinkm, fnp, ridp, ridv, fnm FROM fv" |
|
dbda8d6…
|
drh
|
1262 |
" WHERE idp>0 AND idv>0 AND idm>0" |
|
dbda8d6…
|
drh
|
1263 |
" AND ridm!=ridp AND ridv=ridp AND NOT chnged" |
|
dbda8d6…
|
drh
|
1264 |
); |
|
dbda8d6…
|
drh
|
1265 |
while( db_step(&q)==SQLITE_ROW ){ |
|
dbda8d6…
|
drh
|
1266 |
int idv = db_column_int(&q, 0); |
|
dbda8d6…
|
drh
|
1267 |
int ridm = db_column_int(&q, 1); |
|
c52927c…
|
drh
|
1268 |
const char *zName = db_column_text(&q, 2); |
|
c97535c…
|
dmitry
|
1269 |
int islinkm = db_column_int(&q, 3); |
|
dbda8d6…
|
drh
|
1270 |
/* Copy content from idm over into idv. Overwrite idv. */ |
|
d8ec765…
|
drh
|
1271 |
fossil_print("UPDATE %s\n", zName); |
|
3a39ae4…
|
drh
|
1272 |
if( useUndo ) undo_save(zName); |
|
0b86639…
|
jan.nijtmans
|
1273 |
if( !dryRunFlag ){ |
|
000af32…
|
drh
|
1274 |
db_multi_exec( |
|
fff37e6…
|
drh
|
1275 |
"UPDATE vfile SET mtime=0, mrid=%d, chnged=%d, islink=%d," |
|
fff37e6…
|
drh
|
1276 |
" mhash=CASE WHEN rid<>%d" |
|
fff37e6…
|
drh
|
1277 |
" THEN (SELECT uuid FROM blob WHERE blob.rid=%d) END" |
|
fff37e6…
|
drh
|
1278 |
" WHERE id=%d", ridm, integrateFlag?4:2, islinkm, ridm, ridm, idv |
|
000af32…
|
drh
|
1279 |
); |
|
000af32…
|
drh
|
1280 |
vfile_to_disk(0, idv, 0, 0); |
|
000af32…
|
drh
|
1281 |
} |
|
aa82965…
|
drh
|
1282 |
db_multi_exec( |
|
aa82965…
|
drh
|
1283 |
"INSERT INTO mergestat(op,fnp,ridp,fn,ridv,fnm,ridm,fnr)" |
|
aa82965…
|
drh
|
1284 |
"VALUES('UPDATE',%Q,%d,%Q,%d,%Q,%d,%Q)", |
|
aa82965…
|
drh
|
1285 |
/* fnp */ db_column_text(&q, 4), |
|
aa82965…
|
drh
|
1286 |
/* ridp */ db_column_int(&q,5), |
|
aa82965…
|
drh
|
1287 |
/* fn */ zName, |
|
aa82965…
|
drh
|
1288 |
/* ridv */ db_column_int(&q,6), |
|
aa82965…
|
drh
|
1289 |
/* fnm */ db_column_text(&q, 7), |
|
aa82965…
|
drh
|
1290 |
/* ridm */ ridm, |
|
aa82965…
|
drh
|
1291 |
/* fnr */ zName |
|
aa82965…
|
drh
|
1292 |
); |
|
dbda8d6…
|
drh
|
1293 |
} |
|
dbda8d6…
|
drh
|
1294 |
db_finalize(&q); |
|
dbda8d6…
|
drh
|
1295 |
|
|
dbda8d6…
|
drh
|
1296 |
/* |
|
c52927c…
|
drh
|
1297 |
** Do a three-way merge on files that have changes on both P->M and P->V. |
|
7c75e47…
|
mgagnon
|
1298 |
** |
|
7c75e47…
|
mgagnon
|
1299 |
** Proceed even if the file doesn't exist on P, just like the common ancestor |
|
7c75e47…
|
mgagnon
|
1300 |
** of M and V is an empty file. In this case, merge conflict marks will be |
|
7c75e47…
|
mgagnon
|
1301 |
** added to the file and user will be forced to take a decision. |
|
dbda8d6…
|
drh
|
1302 |
*/ |
|
dbda8d6…
|
drh
|
1303 |
db_prepare(&q, |
|
aa82965…
|
drh
|
1304 |
/* 0 1 2 3 4 5 6 7 8 */ |
|
6ff817d…
|
drh
|
1305 |
"SELECT ridm, idv, ridp, ridv, %z, fn, isexe, islinkv, islinkm," |
|
aa82965…
|
drh
|
1306 |
/* 9 10 11 */ |
|
aa82965…
|
drh
|
1307 |
" fnp, fnm, chnged" |
|
aa82965…
|
drh
|
1308 |
" FROM fv" |
|
7c75e47…
|
mgagnon
|
1309 |
" WHERE idv>0 AND idm>0" |
|
7c2577b…
|
drh
|
1310 |
" AND ridm!=ridp AND (ridv!=ridp OR chnged)", |
|
7c2577b…
|
drh
|
1311 |
glob_expr("fv.fn", zBinGlob) |
|
dbda8d6…
|
drh
|
1312 |
); |
|
dbda8d6…
|
drh
|
1313 |
while( db_step(&q)==SQLITE_ROW ){ |
|
dbda8d6…
|
drh
|
1314 |
int ridm = db_column_int(&q, 0); |
|
dbda8d6…
|
drh
|
1315 |
int idv = db_column_int(&q, 1); |
|
dbda8d6…
|
drh
|
1316 |
int ridp = db_column_int(&q, 2); |
|
d0305b3…
|
aku
|
1317 |
int ridv = db_column_int(&q, 3); |
|
7c2577b…
|
drh
|
1318 |
int isBinary = db_column_int(&q, 4); |
|
c52927c…
|
drh
|
1319 |
const char *zName = db_column_text(&q, 5); |
|
3ad119b…
|
drh
|
1320 |
int isExe = db_column_int(&q, 6); |
|
e4f1c1f…
|
drh
|
1321 |
int islinkv = db_column_int(&q, 7); |
|
e4f1c1f…
|
drh
|
1322 |
int islinkm = db_column_int(&q, 8); |
|
aa82965…
|
drh
|
1323 |
int chnged = db_column_int(&q, 11); |
|
c52927c…
|
drh
|
1324 |
int rc; |
|
c52927c…
|
drh
|
1325 |
char *zFullPath; |
|
aa82965…
|
drh
|
1326 |
const char *zType = "MERGE"; |
|
b9abb86…
|
drh
|
1327 |
Blob m, p, r; |
|
b9abb86…
|
drh
|
1328 |
/* Do a 3-way merge of idp->idm into idp->idv. The results go into idv. */ |
|
5214a2a…
|
jan.nijtmans
|
1329 |
if( verboseFlag ){ |
|
080ab8c…
|
jan.nijtmans
|
1330 |
fossil_print("MERGE %s (pivot=%d v1=%d v2=%d)\n", |
|
d8ec765…
|
drh
|
1331 |
zName, ridp, ridm, ridv); |
|
d8ec765…
|
drh
|
1332 |
}else{ |
|
d8ec765…
|
drh
|
1333 |
fossil_print("MERGE %s\n", zName); |
|
d8ec765…
|
drh
|
1334 |
} |
|
1772357…
|
drh
|
1335 |
if( islinkv || islinkm ){ |
|
e4f1c1f…
|
drh
|
1336 |
fossil_print("***** Cannot merge symlink %s\n", zName); |
|
080ab8c…
|
jan.nijtmans
|
1337 |
nConflict++; |
|
aa82965…
|
drh
|
1338 |
db_multi_exec( |
|
aa82965…
|
drh
|
1339 |
"INSERT INTO mergestat(op,fnp,ridp,fn,ridv,fnm,ridm,fnr,nc,msg)" |
|
aa82965…
|
drh
|
1340 |
"VALUES('ERROR',%Q,%d,%Q,%d,%Q,%d,%Q,1,'cannot merge symlink')", |
|
aa82965…
|
drh
|
1341 |
/* fnp */ db_column_text(&q, 9), |
|
aa82965…
|
drh
|
1342 |
/* ridp */ ridp, |
|
aa82965…
|
drh
|
1343 |
/* fn */ zName, |
|
aa82965…
|
drh
|
1344 |
/* ridv */ ridv, |
|
aa82965…
|
drh
|
1345 |
/* fnm */ db_column_text(&q, 10), |
|
aa82965…
|
drh
|
1346 |
/* ridm */ ridm, |
|
aa82965…
|
drh
|
1347 |
/* fnr */ zName |
|
aa82965…
|
drh
|
1348 |
); |
|
e4f1c1f…
|
drh
|
1349 |
}else{ |
|
aa82965…
|
drh
|
1350 |
i64 sz; |
|
aa82965…
|
drh
|
1351 |
const char *zErrMsg = 0; |
|
aa82965…
|
drh
|
1352 |
int nc = 0; |
|
aa82965…
|
drh
|
1353 |
|
|
3a39ae4…
|
drh
|
1354 |
if( useUndo ) undo_save(zName); |
|
e4f1c1f…
|
drh
|
1355 |
zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); |
|
aa82965…
|
drh
|
1356 |
sz = file_size(zFullPath, ExtFILE); |
|
e4f1c1f…
|
drh
|
1357 |
content_get(ridp, &p); |
|
e4f1c1f…
|
drh
|
1358 |
content_get(ridm, &m); |
|
e4f1c1f…
|
drh
|
1359 |
if( isBinary ){ |
|
e4f1c1f…
|
drh
|
1360 |
rc = -1; |
|
e4f1c1f…
|
drh
|
1361 |
blob_zero(&r); |
|
e4f1c1f…
|
drh
|
1362 |
}else{ |
|
0b86639…
|
jan.nijtmans
|
1363 |
unsigned mergeFlags = dryRunFlag ? MERGE_DRYRUN : 0; |
|
d20ead1…
|
drh
|
1364 |
if(keepMergeFlag!=0) mergeFlags |= MERGE_KEEP_FILES; |
|
cd2c0e4…
|
drh
|
1365 |
rc = merge_3way(&p, zFullPath, &m, &r, mergeFlags); |
|
e4f1c1f…
|
drh
|
1366 |
} |
|
e4f1c1f…
|
drh
|
1367 |
if( rc>=0 ){ |
|
0b86639…
|
jan.nijtmans
|
1368 |
if( !dryRunFlag ){ |
|
e4f1c1f…
|
drh
|
1369 |
blob_write_to_file(&r, zFullPath); |
|
1772357…
|
drh
|
1370 |
file_setexe(zFullPath, isExe); |
|
e4f1c1f…
|
drh
|
1371 |
} |
|
e4f1c1f…
|
drh
|
1372 |
db_multi_exec("UPDATE vfile SET mtime=0 WHERE id=%d", idv); |
|
e4f1c1f…
|
drh
|
1373 |
if( rc>0 ){ |
|
0d4d85b…
|
drh
|
1374 |
fossil_print("***** %d merge conflict%s in %s\n", |
|
0d4d85b…
|
drh
|
1375 |
rc, rc>1 ? "s" : "", zName); |
|
e4f1c1f…
|
drh
|
1376 |
nConflict++; |
|
aa82965…
|
drh
|
1377 |
nc = rc; |
|
aa82965…
|
drh
|
1378 |
zErrMsg = "merge conflicts"; |
|
aa82965…
|
drh
|
1379 |
zType = "CONFLICT"; |
|
e4f1c1f…
|
drh
|
1380 |
} |
|
e4f1c1f…
|
drh
|
1381 |
}else{ |
|
e4f1c1f…
|
drh
|
1382 |
fossil_print("***** Cannot merge binary file %s\n", zName); |
|
e4f1c1f…
|
drh
|
1383 |
nConflict++; |
|
aa82965…
|
drh
|
1384 |
nc = 1; |
|
aa82965…
|
drh
|
1385 |
zErrMsg = "cannot merge binary file"; |
|
aa82965…
|
drh
|
1386 |
zType = "ERROR"; |
|
e4f1c1f…
|
drh
|
1387 |
} |
|
aa82965…
|
drh
|
1388 |
db_multi_exec( |
|
aa82965…
|
drh
|
1389 |
"INSERT INTO mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,fnr,nc,msg)" |
|
546cbce…
|
drh
|
1390 |
"VALUES(%Q,%Q,%d,%Q,iif(%d,%d,NULL),iif(%d,%lld,NULL),%Q,%d," |
|
aa82965…
|
drh
|
1391 |
"%Q,%d,%Q)", |
|
aa82965…
|
drh
|
1392 |
/* op */ zType, |
|
aa82965…
|
drh
|
1393 |
/* fnp */ db_column_text(&q, 9), |
|
aa82965…
|
drh
|
1394 |
/* ridp */ ridp, |
|
aa82965…
|
drh
|
1395 |
/* fn */ zName, |
|
aa82965…
|
drh
|
1396 |
/* ridv */ chnged==0, ridv, |
|
aa82965…
|
drh
|
1397 |
/* sz */ chnged!=0, sz, |
|
aa82965…
|
drh
|
1398 |
/* fnm */ db_column_text(&q, 10), |
|
aa82965…
|
drh
|
1399 |
/* ridm */ ridm, |
|
aa82965…
|
drh
|
1400 |
/* fnr */ zName, |
|
aa82965…
|
drh
|
1401 |
/* nc */ nc, |
|
aa82965…
|
drh
|
1402 |
/* msg */ zErrMsg |
|
aa82965…
|
drh
|
1403 |
); |
|
aa82965…
|
drh
|
1404 |
fossil_free(zFullPath); |
|
e4f1c1f…
|
drh
|
1405 |
blob_reset(&p); |
|
e4f1c1f…
|
drh
|
1406 |
blob_reset(&m); |
|
e4f1c1f…
|
drh
|
1407 |
blob_reset(&r); |
|
e4f1c1f…
|
drh
|
1408 |
} |
|
fff37e6…
|
drh
|
1409 |
vmerge_insert(idv, ridm); |
|
dbda8d6…
|
drh
|
1410 |
} |
|
dbda8d6…
|
drh
|
1411 |
db_finalize(&q); |
|
dbda8d6…
|
drh
|
1412 |
|
|
dbda8d6…
|
drh
|
1413 |
/* |
|
c52927c…
|
drh
|
1414 |
** Drop files that are in P and V but not in M |
|
dbda8d6…
|
drh
|
1415 |
*/ |
|
dbda8d6…
|
drh
|
1416 |
db_prepare(&q, |
|
aa82965…
|
drh
|
1417 |
"SELECT idv, fn, chnged, ridv FROM fv" |
|
dbda8d6…
|
drh
|
1418 |
" WHERE idp>0 AND idv>0 AND idm=0" |
|
dbda8d6…
|
drh
|
1419 |
); |
|
dbda8d6…
|
drh
|
1420 |
while( db_step(&q)==SQLITE_ROW ){ |
|
dbda8d6…
|
drh
|
1421 |
int idv = db_column_int(&q, 0); |
|
c52927c…
|
drh
|
1422 |
const char *zName = db_column_text(&q, 1); |
|
c52927c…
|
drh
|
1423 |
int chnged = db_column_int(&q, 2); |
|
aa82965…
|
drh
|
1424 |
int ridv = db_column_int(&q, 3); |
|
aa82965…
|
drh
|
1425 |
int sz = -1; |
|
aa82965…
|
drh
|
1426 |
const char *zErrMsg = 0; |
|
aa82965…
|
drh
|
1427 |
int nc = 0; |
|
dbda8d6…
|
drh
|
1428 |
/* Delete the file idv */ |
|
d8ec765…
|
drh
|
1429 |
fossil_print("DELETE %s\n", zName); |
|
c52927c…
|
drh
|
1430 |
if( chnged ){ |
|
aa82965…
|
drh
|
1431 |
char *zFullPath; |
|
451f04f…
|
joel
|
1432 |
fossil_warning("WARNING: local edits lost for %s", zName); |
|
c52927c…
|
drh
|
1433 |
nConflict++; |
|
aa82965…
|
drh
|
1434 |
ridv = 0; |
|
aa82965…
|
drh
|
1435 |
nc = 1; |
|
aa82965…
|
drh
|
1436 |
zErrMsg = "local edits lost"; |
|
aa82965…
|
drh
|
1437 |
zFullPath = mprintf("%s/%s", g.zLocalRoot, zName); |
|
aa82965…
|
drh
|
1438 |
sz = file_size(zFullPath, ExtFILE); |
|
aa82965…
|
drh
|
1439 |
fossil_free(zFullPath); |
|
c52927c…
|
drh
|
1440 |
} |
|
3a39ae4…
|
drh
|
1441 |
if( useUndo ) undo_save(zName); |
|
dbda8d6…
|
drh
|
1442 |
db_multi_exec( |
|
dbda8d6…
|
drh
|
1443 |
"UPDATE vfile SET deleted=1 WHERE id=%d", idv |
|
dbda8d6…
|
drh
|
1444 |
); |
|
0b86639…
|
jan.nijtmans
|
1445 |
if( !dryRunFlag ){ |
|
70744b7…
|
drh
|
1446 |
char *zFullPath = mprintf("%s%s", g.zLocalRoot, zName); |
|
d8ec765…
|
drh
|
1447 |
file_delete(zFullPath); |
|
70744b7…
|
drh
|
1448 |
free(zFullPath); |
|
70744b7…
|
drh
|
1449 |
} |
|
aa82965…
|
drh
|
1450 |
db_multi_exec( |
|
aa82965…
|
drh
|
1451 |
"INSERT INTO localdb.mergestat(op,fnp,ridp,fn,ridv,sz,fnm,ridm,nc,msg)" |
|
aa82965…
|
drh
|
1452 |
"VALUES('DELETE',NULL,NULL,%Q,iif(%d,%d,NULL),iif(%d,%d,NULL)," |
|
aa82965…
|
drh
|
1453 |
"NULL,NULL,%d,%Q)", |
|
aa82965…
|
drh
|
1454 |
/* fn */ zName, |
|
aa82965…
|
drh
|
1455 |
/* ridv */ chnged==0, ridv, |
|
aa82965…
|
drh
|
1456 |
/* sz */ chnged!=0, sz, |
|
aa82965…
|
drh
|
1457 |
/* nc */ nc, |
|
aa82965…
|
drh
|
1458 |
/* msg */ zErrMsg |
|
aa82965…
|
drh
|
1459 |
); |
|
c52927c…
|
drh
|
1460 |
} |
|
c52927c…
|
drh
|
1461 |
db_finalize(&q); |
|
41c2220…
|
drh
|
1462 |
|
|
41c2220…
|
drh
|
1463 |
/* For certain sets of renames (e.g. A -> B and B -> A), a file that is |
|
41c2220…
|
drh
|
1464 |
** being renamed must first be moved to a temporary location to avoid |
|
41c2220…
|
drh
|
1465 |
** being overwritten by another rename operation. A row is added to the |
|
41c2220…
|
drh
|
1466 |
** TMPRN table for each of these temporary renames. |
|
41c2220…
|
drh
|
1467 |
*/ |
|
41c2220…
|
drh
|
1468 |
db_multi_exec( |
|
41c2220…
|
drh
|
1469 |
"DROP TABLE IF EXISTS tmprn;" |
|
41c2220…
|
drh
|
1470 |
"CREATE TEMP TABLE tmprn(fn UNIQUE, tmpfn);" |
|
41c2220…
|
drh
|
1471 |
); |
|
76412c6…
|
andygoth
|
1472 |
|
|
c52927c…
|
drh
|
1473 |
/* |
|
c52927c…
|
drh
|
1474 |
** Rename files that have taken a rename on P->M but which keep the same |
|
76412c6…
|
andygoth
|
1475 |
** name on P->V. If a file is renamed on P->V only or on both P->V and |
|
c52927c…
|
drh
|
1476 |
** P->M then we retain the V name of the file. |
|
c52927c…
|
drh
|
1477 |
*/ |
|
c52927c…
|
drh
|
1478 |
db_prepare(&q, |
|
41c2220…
|
drh
|
1479 |
"SELECT idv, fnp, fnm, isexe FROM fv" |
|
c52927c…
|
drh
|
1480 |
" WHERE idv>0 AND idp>0 AND idm>0 AND fnp=fn AND fnm!=fnp" |
|
c52927c…
|
drh
|
1481 |
); |
|
c52927c…
|
drh
|
1482 |
while( db_step(&q)==SQLITE_ROW ){ |
|
c52927c…
|
drh
|
1483 |
int idv = db_column_int(&q, 0); |
|
c52927c…
|
drh
|
1484 |
const char *zOldName = db_column_text(&q, 1); |
|
c52927c…
|
drh
|
1485 |
const char *zNewName = db_column_text(&q, 2); |
|
41c2220…
|
drh
|
1486 |
int isExe = db_column_int(&q, 3); |
|
d8ec765…
|
drh
|
1487 |
fossil_print("RENAME %s -> %s\n", zOldName, zNewName); |
|
3a39ae4…
|
drh
|
1488 |
if( useUndo ) undo_save(zOldName); |
|
3a39ae4…
|
drh
|
1489 |
if( useUndo ) undo_save(zNewName); |
|
aa82965…
|
drh
|
1490 |
db_multi_exec( |
|
aa82965…
|
drh
|
1491 |
"UPDATE mergestat SET fnr=fnm WHERE fnp=%Q", |
|
aa82965…
|
drh
|
1492 |
zOldName |
|
aa82965…
|
drh
|
1493 |
); |
|
c52927c…
|
drh
|
1494 |
db_multi_exec( |
|
41c2220…
|
drh
|
1495 |
"UPDATE vfile SET pathname=NULL, origname=pathname" |
|
41c2220…
|
drh
|
1496 |
" WHERE vid=%d AND pathname=%Q;" |
|
c52927c…
|
drh
|
1497 |
"UPDATE vfile SET pathname=%Q, origname=coalesce(origname,pathname)" |
|
41c2220…
|
drh
|
1498 |
" WHERE id=%d;", |
|
41c2220…
|
drh
|
1499 |
vid, zNewName, zNewName, idv |
|
c52927c…
|
drh
|
1500 |
); |
|
0b86639…
|
jan.nijtmans
|
1501 |
if( !dryRunFlag ){ |
|
41c2220…
|
drh
|
1502 |
char *zFullOldPath, *zFullNewPath; |
|
41c2220…
|
drh
|
1503 |
zFullOldPath = db_text(0,"SELECT tmpfn FROM tmprn WHERE fn=%Q", zOldName); |
|
41c2220…
|
drh
|
1504 |
if( !zFullOldPath ){ |
|
41c2220…
|
drh
|
1505 |
zFullOldPath = mprintf("%s%s", g.zLocalRoot, zOldName); |
|
41c2220…
|
drh
|
1506 |
} |
|
41c2220…
|
drh
|
1507 |
zFullNewPath = mprintf("%s%s", g.zLocalRoot, zNewName); |
|
1772357…
|
drh
|
1508 |
if( file_size(zFullNewPath, RepoFILE)>=0 ){ |
|
051d0ab…
|
drh
|
1509 |
Blob tmpPath; |
|
1dd2527…
|
drh
|
1510 |
file_tempname(&tmpPath, "", 0); |
|
41c2220…
|
drh
|
1511 |
db_multi_exec("INSERT INTO tmprn(fn,tmpfn) VALUES(%Q,%Q)", |
|
051d0ab…
|
drh
|
1512 |
zNewName, blob_str(&tmpPath)); |
|
1772357…
|
drh
|
1513 |
if( file_islink(zFullNewPath) ){ |
|
051d0ab…
|
drh
|
1514 |
symlink_copy(zFullNewPath, blob_str(&tmpPath)); |
|
41c2220…
|
drh
|
1515 |
}else{ |
|
051d0ab…
|
drh
|
1516 |
file_copy(zFullNewPath, blob_str(&tmpPath)); |
|
41c2220…
|
drh
|
1517 |
} |
|
051d0ab…
|
drh
|
1518 |
blob_reset(&tmpPath); |
|
41c2220…
|
drh
|
1519 |
} |
|
1772357…
|
drh
|
1520 |
if( file_islink(zFullOldPath) ){ |
|
c05f6af…
|
dmitry
|
1521 |
symlink_copy(zFullOldPath, zFullNewPath); |
|
c05f6af…
|
dmitry
|
1522 |
}else{ |
|
c05f6af…
|
dmitry
|
1523 |
file_copy(zFullOldPath, zFullNewPath); |
|
c05f6af…
|
dmitry
|
1524 |
} |
|
1772357…
|
drh
|
1525 |
file_setexe(zFullNewPath, isExe); |
|
d8ec765…
|
drh
|
1526 |
file_delete(zFullOldPath); |
|
c52927c…
|
drh
|
1527 |
free(zFullNewPath); |
|
c52927c…
|
drh
|
1528 |
free(zFullOldPath); |
|
c52927c…
|
drh
|
1529 |
} |
|
c52927c…
|
drh
|
1530 |
} |
|
c52927c…
|
drh
|
1531 |
db_finalize(&q); |
|
c52927c…
|
drh
|
1532 |
|
|
41c2220…
|
drh
|
1533 |
/* A file that has been deleted and replaced by a renamed file will have a |
|
41c2220…
|
drh
|
1534 |
** NULL pathname. Change it to something that makes the output of "status" |
|
41c2220…
|
drh
|
1535 |
** and similar commands make sense for such files and that will (most likely) |
|
41c2220…
|
drh
|
1536 |
** not be an actual existing pathname. |
|
41c2220…
|
drh
|
1537 |
*/ |
|
41c2220…
|
drh
|
1538 |
db_multi_exec( |
|
41c2220…
|
drh
|
1539 |
"UPDATE vfile SET pathname=origname || ' (overwritten by rename)'" |
|
41c2220…
|
drh
|
1540 |
" WHERE pathname IS NULL" |
|
41c2220…
|
drh
|
1541 |
); |
|
41c2220…
|
drh
|
1542 |
|
|
41c2220…
|
drh
|
1543 |
/* |
|
0d4d85b…
|
drh
|
1544 |
** Insert into V any files that are not in V or P but are in M. |
|
41c2220…
|
drh
|
1545 |
*/ |
|
41c2220…
|
drh
|
1546 |
db_prepare(&q, |
|
aa82965…
|
drh
|
1547 |
"SELECT idm, fnm, ridm FROM fv" |
|
41c2220…
|
drh
|
1548 |
" WHERE idp=0 AND idv=0 AND idm>0" |
|
41c2220…
|
drh
|
1549 |
); |
|
41c2220…
|
drh
|
1550 |
while( db_step(&q)==SQLITE_ROW ){ |
|
41c2220…
|
drh
|
1551 |
int idm = db_column_int(&q, 0); |
|
41c2220…
|
drh
|
1552 |
const char *zName; |
|
41c2220…
|
drh
|
1553 |
char *zFullName; |
|
41c2220…
|
drh
|
1554 |
db_multi_exec( |
|
fff37e6…
|
drh
|
1555 |
"REPLACE INTO vfile(vid,chnged,deleted,rid,mrid," |
|
fff37e6…
|
drh
|
1556 |
"isexe,islink,pathname,mhash)" |
|
fff37e6…
|
drh
|
1557 |
" SELECT %d,%d,0,rid,mrid,isexe,islink,pathname," |
|
fff37e6…
|
drh
|
1558 |
"CASE WHEN rid<>mrid" |
|
fff37e6…
|
drh
|
1559 |
" THEN (SELECT uuid FROM blob WHERE blob.rid=vfile.mrid) END " |
|
fff37e6…
|
drh
|
1560 |
"FROM vfile WHERE id=%d", |
|
41c2220…
|
drh
|
1561 |
vid, integrateFlag?5:3, idm |
|
41c2220…
|
drh
|
1562 |
); |
|
41c2220…
|
drh
|
1563 |
zName = db_column_text(&q, 1); |
|
41c2220…
|
drh
|
1564 |
zFullName = mprintf("%s%s", g.zLocalRoot, zName); |
|
1772357…
|
drh
|
1565 |
if( file_isfile_or_link(zFullName) |
|
41c2220…
|
drh
|
1566 |
&& !db_exists("SELECT 1 FROM fv WHERE fn=%Q", zName) ){ |
|
e99e58c…
|
mgagnon
|
1567 |
/* Name of backup file with Original content */ |
|
e99e58c…
|
mgagnon
|
1568 |
char *zOrig = file_newname(zFullName, "original", 1); |
|
e2bdc10…
|
danield
|
1569 |
/* Backup previously unmanaged file before being overwritten */ |
|
e99e58c…
|
mgagnon
|
1570 |
file_copy(zFullName, zOrig); |
|
e99e58c…
|
mgagnon
|
1571 |
fossil_free(zOrig); |
|
e99e58c…
|
mgagnon
|
1572 |
fossil_print("ADDED %s (overwrites an unmanaged file)", zName); |
|
e99e58c…
|
mgagnon
|
1573 |
if( !dryRunFlag ) fossil_print(", original copy backed up locally"); |
|
e99e58c…
|
mgagnon
|
1574 |
fossil_print("\n"); |
|
41c2220…
|
drh
|
1575 |
nOverwrite++; |
|
41c2220…
|
drh
|
1576 |
}else{ |
|
41c2220…
|
drh
|
1577 |
fossil_print("ADDED %s\n", zName); |
|
41c2220…
|
drh
|
1578 |
} |
|
41c2220…
|
drh
|
1579 |
fossil_free(zFullName); |
|
aa82965…
|
drh
|
1580 |
db_multi_exec( |
|
aa82965…
|
drh
|
1581 |
"INSERT INTO mergestat(op,fnm,ridm,fnr)" |
|
aa82965…
|
drh
|
1582 |
"VALUES('ADDED',%Q,%d,%Q)", |
|
aa82965…
|
drh
|
1583 |
/* fnm */ zName, |
|
aa82965…
|
drh
|
1584 |
/* ridm */ db_column_int(&q,2), |
|
aa82965…
|
drh
|
1585 |
/* fnr */ zName |
|
aa82965…
|
drh
|
1586 |
); |
|
3a39ae4…
|
drh
|
1587 |
if( useUndo ) undo_save(zName); |
|
41c2220…
|
drh
|
1588 |
if( !dryRunFlag ){ |
|
41c2220…
|
drh
|
1589 |
vfile_to_disk(0, idm, 0, 0); |
|
41c2220…
|
drh
|
1590 |
} |
|
41c2220…
|
drh
|
1591 |
} |
|
41c2220…
|
drh
|
1592 |
db_finalize(&q); |
|
c52927c…
|
drh
|
1593 |
|
|
c52927c…
|
drh
|
1594 |
/* Report on conflicts |
|
c52927c…
|
drh
|
1595 |
*/ |
|
cd2c0e4…
|
drh
|
1596 |
if( nConflict ){ |
|
cd2c0e4…
|
drh
|
1597 |
fossil_warning("WARNING: %d merge conflicts", nConflict); |
|
67fe38c…
|
drh
|
1598 |
if( bMultiMerge ){ |
|
67fe38c…
|
drh
|
1599 |
int i; |
|
67fe38c…
|
drh
|
1600 |
Blob msg; |
|
67fe38c…
|
drh
|
1601 |
blob_init(&msg, 0, 0); |
|
67fe38c…
|
drh
|
1602 |
blob_appendf(&msg, |
|
67fe38c…
|
drh
|
1603 |
"The following %ss were not attempted due to prior conflicts:", |
|
67fe38c…
|
drh
|
1604 |
pickFlag ? "cherrypick" : backoutFlag ? "backout" : "merge" |
|
67fe38c…
|
drh
|
1605 |
); |
|
67fe38c…
|
drh
|
1606 |
for(i=2; i<g.argc; i++){ |
|
67fe38c…
|
drh
|
1607 |
blob_appendf(&msg, " %s", g.argv[i]); |
|
67fe38c…
|
drh
|
1608 |
} |
|
67fe38c…
|
drh
|
1609 |
fossil_warning("%s", blob_str(&msg)); |
|
67fe38c…
|
drh
|
1610 |
blob_zero(&msg); |
|
67fe38c…
|
drh
|
1611 |
} |
|
cd2c0e4…
|
drh
|
1612 |
} |
|
cd2c0e4…
|
drh
|
1613 |
if( nOverwrite ){ |
|
cd2c0e4…
|
drh
|
1614 |
fossil_warning("WARNING: %d unmanaged files were overwritten", |
|
cd2c0e4…
|
drh
|
1615 |
nOverwrite); |
|
cd2c0e4…
|
drh
|
1616 |
} |
|
67fe38c…
|
drh
|
1617 |
if( dryRunFlag && !bMultiMerge ){ |
|
cd2c0e4…
|
drh
|
1618 |
fossil_warning("REMINDER: this was a dry run -" |
|
d4aee31…
|
stephan
|
1619 |
" no files were actually changed."); |
|
c52927c…
|
drh
|
1620 |
} |
|
b0d1510…
|
drh
|
1621 |
|
|
dbda8d6…
|
drh
|
1622 |
/* |
|
dbda8d6…
|
drh
|
1623 |
** Clean up the mid and pid VFILE entries. Then commit the changes. |
|
dbda8d6…
|
drh
|
1624 |
*/ |
|
dbda8d6…
|
drh
|
1625 |
db_multi_exec("DELETE FROM vfile WHERE vid!=%d", vid); |
|
9c28bca…
|
drh
|
1626 |
if( pickFlag ){ |
|
fff37e6…
|
drh
|
1627 |
vmerge_insert(-1, mid); |
|
67fe38c…
|
drh
|
1628 |
/* For a cherrypick merge, make the default check-in comment the same |
|
9c28bca…
|
drh
|
1629 |
** as the check-in comment on the check-in that is being merged in. */ |
|
9c28bca…
|
drh
|
1630 |
db_multi_exec( |
|
9c28bca…
|
drh
|
1631 |
"REPLACE INTO vvar(name,value)" |
|
9c28bca…
|
drh
|
1632 |
" SELECT 'ci-comment', coalesce(ecomment,comment) FROM event" |
|
9c28bca…
|
drh
|
1633 |
" WHERE type='ci' AND objid=%d", |
|
9c28bca…
|
drh
|
1634 |
mid |
|
9c28bca…
|
drh
|
1635 |
); |
|
91aa222…
|
drh
|
1636 |
}else if( backoutFlag ){ |
|
fff37e6…
|
drh
|
1637 |
vmerge_insert(-2, pid); |
|
69dd259…
|
jan.nijtmans
|
1638 |
}else if( integrateFlag ){ |
|
fff37e6…
|
drh
|
1639 |
vmerge_insert(-4, mid); |
|
91aa222…
|
drh
|
1640 |
}else{ |
|
fff37e6…
|
drh
|
1641 |
vmerge_insert(0, mid); |
|
fff37e6…
|
drh
|
1642 |
} |
|
67fe38c…
|
drh
|
1643 |
if( bMultiMerge && nConflict==0 ){ |
|
67fe38c…
|
drh
|
1644 |
nMerge++; |
|
67fe38c…
|
drh
|
1645 |
goto merge_next_child; |
|
67fe38c…
|
drh
|
1646 |
} |
|
3a39ae4…
|
drh
|
1647 |
if( useUndo ) undo_finish(); |
|
67fe38c…
|
drh
|
1648 |
|
|
0b86639…
|
jan.nijtmans
|
1649 |
db_end_transaction(dryRunFlag); |
|
dbda8d6…
|
drh
|
1650 |
} |