Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Changes In Branch conflict-tracking Excluding Merge-Ins
This is equivalent to a diff from e40e4faabb to 65f495bc06
2012-10-22
| ||
13:23 | Merge the changes to show unresolved conflicts in "fossil status" and to prevent committing unresolved conflicts. check-in: 7d34d1748a user: drh tags: trunk | |
2012-10-21
| ||
00:54 | Fix a crash bug that comes up when trying to view the history of files whose names contain charaters that require URL escapes. This is a cherry-pick of [65f495bc06767] which was committed to the wrong branch. check-in: 9c6f9e7a8c user: drh tags: trunk | |
00:52 | Fix a crash bug that comes up when trying to view the history of files whose names contain charaters that require URL escapes. Closed-Leaf check-in: 65f495bc06 user: drh tags: conflict-tracking | |
2012-10-20
| ||
00:29 | Report unresolved conflicts on "fossil status". Refuse to commit with unresolved conflicts if the --conflict flag is omitted from "fossil commit". check-in: 1fb2ca625b user: drh tags: conflict-tracking | |
2012-10-19
| ||
18:36 | Add a mention of the ability to do dynamic loading of Tcl to the change log. (This change originally checked into the wrong branch.) check-in: e40e4faabb user: drh tags: trunk | |
17:04 | Fix a typo in the Style document. check-in: 2116906fb1 user: drh tags: trunk | |
Changes to src/checkin.c.
85 85 }else if( isDeleted ){ 86 86 blob_appendf(report, "DELETED %s\n", zDisplayName); 87 87 }else if( isChnged==2 ){ 88 88 blob_appendf(report, "UPDATED_BY_MERGE %s\n", zDisplayName); 89 89 }else if( isChnged==3 ){ 90 90 blob_appendf(report, "ADDED_BY_MERGE %s\n", zDisplayName); 91 91 }else if( isChnged==1 ){ 92 - blob_appendf(report, "EDITED %s\n", zDisplayName); 92 + if( file_contains_merge_marker(zFullName) ){ 93 + blob_appendf(report, "CONFLICT %s\n", zDisplayName); 94 + }else{ 95 + blob_appendf(report, "EDITED %s\n", zDisplayName); 96 + } 93 97 }else if( isRenamed ){ 94 98 blob_appendf(report, "RENAMED %s\n", zDisplayName); 95 99 } 96 100 free(zFullName); 97 101 } 98 102 blob_reset(&rewrittenPathname); 99 103 db_finalize(&q); ................................................................................ 974 978 ** --comment|-m COMMENT-TEXT use COMMENT-TEXT as commit comment 975 979 ** --delta use a delta manifest in the commit process 976 980 ** --force|-f allow forking with this commit 977 981 ** --message-file|-M FILE read the commit comment from given file 978 982 ** --nosign do not attempt to sign this commit with gpg 979 983 ** --private do not sync changes and their descendants 980 984 ** --tag TAG-NAME assign given tag TAG-NAME to the checkin 985 +** --conflict allow unresolved merge conflicts 981 986 ** 982 987 ** See also: branch, changes, checkout, extra, sync 983 988 */ 984 989 void commit_cmd(void){ 985 990 int hasChanges; /* True if unsaved changes exist */ 986 991 int vid; /* blob-id of parent version */ 987 992 int nrid; /* blob-id of a modified file */ ................................................................................ 991 996 Stmt q; /* Query to find files that have been modified */ 992 997 char *zUuid; /* UUID of the new check-in */ 993 998 int noSign = 0; /* True to omit signing the manifest using GPG */ 994 999 int isAMerge = 0; /* True if checking in a merge */ 995 1000 int forceFlag = 0; /* Force a fork */ 996 1001 int forceDelta = 0; /* Force a delta-manifest */ 997 1002 int forceBaseline = 0; /* Force a baseline-manifest */ 1003 + int allowConflict = 0; /* Allow unresolve merge conflicts */ 998 1004 char *zManifestFile; /* Name of the manifest file */ 999 1005 int useCksum; /* True if checksums should be computed and verified */ 1000 1006 int outputManifest; /* True to output "manifest" and "manifest.uuid" */ 1001 1007 int testRun; /* True for a test run. Debugging only */ 1002 1008 const char *zBranch; /* Create a new branch with this name */ 1003 1009 const char *zBrClr; /* Set background color when branching */ 1004 1010 const char *zColor; /* One-time check-in color */ ................................................................................ 1010 1016 const char **azTag = 0;/* Array of all --tag arguments */ 1011 1017 Blob manifest; /* Manifest in baseline form */ 1012 1018 Blob muuid; /* Manifest uuid */ 1013 1019 Blob cksum1, cksum2; /* Before and after commit checksums */ 1014 1020 Blob cksum1b; /* Checksum recorded in the manifest */ 1015 1021 int szD; /* Size of the delta manifest */ 1016 1022 int szB; /* Size of the baseline manifest */ 1023 + int nConflict = 0; /* Number of unresolved merge conflicts */ 1017 1024 1018 1025 url_proxy_options(); 1019 1026 noSign = find_option("nosign",0,0)!=0; 1020 1027 forceDelta = find_option("delta",0,0)!=0; 1021 1028 forceBaseline = find_option("baseline",0,0)!=0; 1022 1029 if( forceDelta && forceBaseline ){ 1023 1030 fossil_fatal("cannot use --delta and --baseline together"); ................................................................................ 1038 1045 if( find_option("private",0,0) ){ 1039 1046 g.markPrivate = 1; 1040 1047 if( zBranch==0 ) zBranch = "private"; 1041 1048 if( zBrClr==0 && zColor==0 ) zBrClr = "#fec084"; /* Orange */ 1042 1049 } 1043 1050 zDateOvrd = find_option("date-override",0,1); 1044 1051 zUserOvrd = find_option("user-override",0,1); 1052 + allowConflict = find_option("conflict",0,0)!=0; 1045 1053 db_must_be_within_tree(); 1046 1054 noSign = db_get_boolean("omitsign", 0)|noSign; 1047 1055 if( db_get_boolean("clearsign", 0)==0 ){ noSign = 1; } 1048 1056 useCksum = db_get_boolean("repo-cksum", 1); 1049 1057 outputManifest = db_get_boolean("manifest", 0); 1050 1058 verify_all_options(); 1051 1059 ................................................................................ 1192 1200 } 1193 1201 1194 1202 /* Step 1: Insert records for all modified files into the blob 1195 1203 ** table. If there were arguments passed to this command, only 1196 1204 ** the identified fils are inserted (if they have been modified). 1197 1205 */ 1198 1206 db_prepare(&q, 1199 - "SELECT id, %Q || pathname, mrid, %s FROM vfile " 1207 + "SELECT id, %Q || pathname, mrid, %s, chnged FROM vfile " 1200 1208 "WHERE chnged==1 AND NOT deleted AND is_selected(id)", 1201 1209 g.zLocalRoot, glob_expr("pathname", db_get("crnl-glob","")) 1202 1210 ); 1203 1211 while( db_step(&q)==SQLITE_ROW ){ 1204 1212 int id, rid; 1205 1213 const char *zFullname; 1206 1214 Blob content; 1207 - int crnlOk; 1215 + int crnlOk, chnged; 1208 1216 1209 1217 id = db_column_int(&q, 0); 1210 1218 zFullname = db_column_text(&q, 1); 1211 1219 rid = db_column_int(&q, 2); 1212 1220 crnlOk = db_column_int(&q, 3); 1221 + chnged = db_column_int(&q, 4); 1213 1222 1214 1223 blob_zero(&content); 1215 1224 if( file_wd_islink(zFullname) ){ 1216 1225 /* Instead of file content, put link destination path */ 1217 1226 blob_read_link(&content, zFullname); 1218 1227 }else{ 1219 1228 blob_read_from_file(&content, zFullname); 1220 1229 } 1221 1230 if( !crnlOk ) cr_warning(&content, zFullname); 1231 + if( chnged==1 && contains_merge_marker(&content) ){ 1232 + nConflict++; 1233 + fossil_print("possible unresolved merge conflict in %s\n", 1234 + zFullname+strlen(g.zLocalRoot)); 1235 + } 1222 1236 nrid = content_put(&content); 1223 1237 blob_reset(&content); 1224 1238 if( rid>0 ){ 1225 1239 content_deltify(rid, nrid, 0); 1226 1240 } 1227 1241 db_multi_exec("UPDATE vfile SET mrid=%d, rid=%d WHERE id=%d", nrid,nrid,id); 1228 1242 db_multi_exec("INSERT OR IGNORE INTO unsent VALUES(%d)", nrid); 1229 1243 } 1230 1244 db_finalize(&q); 1245 + if( nConflict && !allowConflict ){ 1246 + fossil_fatal("abort due to unresolve merge conflicts"); 1247 + } 1231 1248 1232 1249 /* Create the new manifest */ 1233 1250 if( blob_size(&comment)==0 ){ 1234 1251 blob_append(&comment, "(no comment)", -1); 1235 1252 } 1236 1253 if( forceDelta ){ 1237 1254 blob_zero(&manifest);
Changes to src/finfo.c.
287 287 } 288 288 blob_appendf(&sql," ORDER BY event.mtime DESC /*sort*/"); 289 289 if( (n = atoi(PD("n","0")))>0 ){ 290 290 blob_appendf(&sql, " LIMIT %d", n); 291 291 url_add_parameter(&url, "n", P("n")); 292 292 } 293 293 if( firstChngOnly ){ 294 - style_submenu_element("Full", "Show all changes", 294 + style_submenu_element("Full", "Show all changes","%s", 295 295 url_render(&url, "fco", "0", 0, 0)); 296 296 }else{ 297 - style_submenu_element("Simplified", "Show only first use of a change", 297 + style_submenu_element("Simplified", "Show only first use of a change","%s", 298 298 url_render(&url, "fco", "1", 0, 0)); 299 299 } 300 300 db_prepare(&q, blob_str(&sql)); 301 301 blob_reset(&sql); 302 302 blob_zero(&title); 303 303 blob_appendf(&title, "History of "); 304 304 hyperlinked_path(zFilename, &title, 0);
Changes to src/merge3.c.
131 131 blob_copy_lines(pOut, pSrc, aC[i+2]); 132 132 sz -= aC[i] + aC[i+1]; 133 133 i += 3; 134 134 } 135 135 return i; 136 136 } 137 137 138 +/* 139 +** Text of boundary markers for merge conflicts. 140 +*/ 141 +static char const * const mergeMarker[] = { 142 + /*123456789 123456789 123456789 123456789 123456789 123456789 123456789*/ 143 + "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n", 144 + "======= COMMON ANCESTOR content follows ============================\n", 145 + "======= MERGED IN content follows ==================================\n", 146 + ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n" 147 +}; 138 148 139 149 140 150 /* 141 151 ** Do a three-way merge. Initialize pOut to contain the result. 142 152 ** 143 153 ** The merge is an edit against pV2. Both pV1 and pV2 have a 144 154 ** common origin at pPivot. Apply the changes of pPivot ==> pV1 ................................................................................ 152 162 static int blob_merge(Blob *pPivot, Blob *pV1, Blob *pV2, Blob *pOut){ 153 163 int *aC1; /* Changes from pPivot to pV1 */ 154 164 int *aC2; /* Changes from pPivot to pV2 */ 155 165 int i1, i2; /* Index into aC1[] and aC2[] */ 156 166 int nCpy, nDel, nIns; /* Number of lines to copy, delete, or insert */ 157 167 int limit1, limit2; /* Sizes of aC1[] and aC2[] */ 158 168 int nConflict = 0; /* Number of merge conflicts seen so far */ 159 - static const char zBegin[] = 160 - "<<<<<<< BEGIN MERGE CONFLICT: local copy shown first <<<<<<<<<<<<<<<\n"; 161 - static const char zMid1[] = 162 - "======= COMMON ANCESTOR content follows ============================\n"; 163 - static const char zMid2[] = 164 - "======= MERGED IN content follows ==================================\n"; 165 - static const char zEnd[] = 166 - ">>>>>>> END MERGE CONFLICT >>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>>\n"; 167 169 168 170 blob_zero(pOut); /* Merge results stored in pOut */ 169 171 170 172 /* Compute the edits that occur from pPivot => pV1 (into aC1) 171 173 ** and pPivot => pV2 (into aC2). Each of the aC1 and aC2 arrays is 172 174 ** an array of integer triples. Within each triple, the first integer 173 175 ** is the number of lines of text to copy directly from the pivot, ................................................................................ 264 266 */ 265 267 int sz = 1; /* Size of the conflict in lines */ 266 268 nConflict++; 267 269 while( !ends_at_CPY(&aC1[i1], sz) || !ends_at_CPY(&aC2[i2], sz) ){ 268 270 sz++; 269 271 } 270 272 DEBUG( printf("CONFLICT %d\n", sz); ) 271 - blob_appendf(pOut, zBegin); 273 + blob_appendf(pOut, mergeMarker[0]); 272 274 i1 = output_one_side(pOut, pV1, aC1, i1, sz); 273 - blob_appendf(pOut, zMid1); 275 + blob_appendf(pOut, mergeMarker[1]); 274 276 blob_copy_lines(pOut, pPivot, sz); 275 - blob_appendf(pOut, zMid2); 277 + blob_appendf(pOut, mergeMarker[2]); 276 278 i2 = output_one_side(pOut, pV2, aC2, i2, sz); 277 - blob_appendf(pOut, zEnd); 279 + blob_appendf(pOut, mergeMarker[3]); 278 280 } 279 281 280 282 /* If we are finished with an edit triple, advance to the next 281 283 ** triple. 282 284 */ 283 285 if( i1<limit1 && aC1[i1]==0 && aC1[i1+1]==0 && aC1[i1+2]==0 ) i1+=3; 284 286 if( i2<limit2 && aC2[i2]==0 && aC2[i2+1]==0 && aC2[i2+2]==0 ) i2+=3; ................................................................................ 299 301 blob_copy_lines(pOut, pV2, aC2[i2+2]); 300 302 } 301 303 302 304 free(aC1); 303 305 free(aC2); 304 306 return nConflict; 305 307 } 308 + 309 +/* 310 +** Return true if the input string contains a merge marker on a line by 311 +** itself. 312 +*/ 313 +int contains_merge_marker(Blob *p){ 314 + int i, j; 315 + int len = (int)strlen(mergeMarker[0]); 316 + const char *z = blob_buffer(p); 317 + int n = blob_size(p) - len + 1; 318 + assert( len==(int)strlen(mergeMarker[1]) ); 319 + assert( len==(int)strlen(mergeMarker[2]) ); 320 + assert( len==(int)strlen(mergeMarker[3]) ); 321 + assert( sizeof(mergeMarker)/sizeof(mergeMarker[0])==4 ); 322 + for(i=0; i<n; ){ 323 + for(j=0; j<4; j++){ 324 + if( memcmp(&z[i], mergeMarker[j], len)==0 ) return 1; 325 + } 326 + while( i<n && z[i]!='\n' ){ i++; } 327 + while( i<n && z[i]=='\n' ){ i++; } 328 + } 329 + return 0; 330 +} 331 + 332 +/* 333 +** Return true if the named file contains an unresolved merge marker line. 334 +*/ 335 +int file_contains_merge_marker(const char *zFullpath){ 336 + Blob file; 337 + int rc; 338 + blob_read_from_file(&file, zFullpath); 339 + rc = contains_merge_marker(&file); 340 + blob_reset(&file); 341 + return rc; 342 +} 306 343 307 344 /* 308 345 ** COMMAND: test-3-way-merge 309 346 ** 310 347 ** Usage: %fossil test-3-way-merge PIVOT V1 V2 MERGED 311 348 ** 312 349 ** Combine change in going from PIVOT->VERSION1 with the change going