Fossil SCM

fossil-scm / src / merge.c
Source Blame History 1650 lines
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 }

Keyboard Shortcuts

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