Changes On Branch conflict-tracking
Not logged in

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