Fossil SCM
Add the "--tree DIRECTORY" option to the "fossil diff" command.
Commit
07a699738a2f3e9e086bfc82d05599d416ffce4699e8afc350b5229d5043040f
Parent
903142fef8a3c62…
2 files changed
+2
-2
+74
-12
+2
-2
| --- src/checkin.c | ||
| +++ src/checkin.c | ||
| @@ -1563,17 +1563,17 @@ | ||
| 1563 | 1563 | break; |
| 1564 | 1564 | } |
| 1565 | 1565 | diffFiles[i].nName = strlen(diffFiles[i].zName); |
| 1566 | 1566 | diffFiles[i].nUsed = 0; |
| 1567 | 1567 | } |
| 1568 | - diff_against_disk(0, &DCfg, diffFiles, &prompt); | |
| 1568 | + diff_version_to_checkout(0, &DCfg, diffFiles, &prompt); | |
| 1569 | 1569 | for( i=0; diffFiles[i].zName; ++i ){ |
| 1570 | 1570 | fossil_free(diffFiles[i].zName); |
| 1571 | 1571 | } |
| 1572 | 1572 | fossil_free(diffFiles); |
| 1573 | 1573 | }else{ |
| 1574 | - diff_against_disk(0, &DCfg, 0, &prompt); | |
| 1574 | + diff_version_to_checkout(0, &DCfg, 0, &prompt); | |
| 1575 | 1575 | } |
| 1576 | 1576 | } |
| 1577 | 1577 | prompt_for_user_comment(pComment, &prompt); |
| 1578 | 1578 | blob_reset(&prompt); |
| 1579 | 1579 | } |
| 1580 | 1580 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1563,17 +1563,17 @@ | |
| 1563 | break; |
| 1564 | } |
| 1565 | diffFiles[i].nName = strlen(diffFiles[i].zName); |
| 1566 | diffFiles[i].nUsed = 0; |
| 1567 | } |
| 1568 | diff_against_disk(0, &DCfg, diffFiles, &prompt); |
| 1569 | for( i=0; diffFiles[i].zName; ++i ){ |
| 1570 | fossil_free(diffFiles[i].zName); |
| 1571 | } |
| 1572 | fossil_free(diffFiles); |
| 1573 | }else{ |
| 1574 | diff_against_disk(0, &DCfg, 0, &prompt); |
| 1575 | } |
| 1576 | } |
| 1577 | prompt_for_user_comment(pComment, &prompt); |
| 1578 | blob_reset(&prompt); |
| 1579 | } |
| 1580 |
| --- src/checkin.c | |
| +++ src/checkin.c | |
| @@ -1563,17 +1563,17 @@ | |
| 1563 | break; |
| 1564 | } |
| 1565 | diffFiles[i].nName = strlen(diffFiles[i].zName); |
| 1566 | diffFiles[i].nUsed = 0; |
| 1567 | } |
| 1568 | diff_version_to_checkout(0, &DCfg, diffFiles, &prompt); |
| 1569 | for( i=0; diffFiles[i].zName; ++i ){ |
| 1570 | fossil_free(diffFiles[i].zName); |
| 1571 | } |
| 1572 | fossil_free(diffFiles); |
| 1573 | }else{ |
| 1574 | diff_version_to_checkout(0, &DCfg, 0, &prompt); |
| 1575 | } |
| 1576 | } |
| 1577 | prompt_for_user_comment(pComment, &prompt); |
| 1578 | blob_reset(&prompt); |
| 1579 | } |
| 1580 |
+74
-12
| --- src/diffcmd.c | ||
| +++ src/diffcmd.c | ||
| @@ -784,26 +784,27 @@ | ||
| 784 | 784 | blob_reset(&file); |
| 785 | 785 | return rc; |
| 786 | 786 | } |
| 787 | 787 | |
| 788 | 788 | /* |
| 789 | -** Run a diff between the version zFrom and files on disk. zFrom might | |
| 790 | -** be NULL which means to simply show the difference between the edited | |
| 791 | -** files on disk and the check-out on which they are based. | |
| 789 | +** Run a diff between the version zFrom and files on disk in the current | |
| 790 | +** working checkout. zFrom might be NULL which means to simply show the | |
| 791 | +** difference between the edited files on disk and the check-out on which | |
| 792 | +** they are based. | |
| 792 | 793 | ** |
| 793 | 794 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
| 794 | 795 | ** command zDiffCmd to do the diffing. |
| 795 | 796 | ** |
| 796 | 797 | ** When using an external diff program, zBinGlob contains the GLOB patterns |
| 797 | 798 | ** for file names to treat as binary. If fIncludeBinary is zero, these files |
| 798 | 799 | ** will be skipped in addition to files that may contain binary content. |
| 799 | 800 | */ |
| 800 | -void diff_against_disk( | |
| 801 | +void diff_version_to_checkout( | |
| 801 | 802 | const char *zFrom, /* Version to difference from */ |
| 802 | 803 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 803 | 804 | FileDirList *pFileDir, /* Which files to diff */ |
| 804 | - Blob *pOut /* Blob to output diff instead of stdout */ | |
| 805 | + Blob *pOut /* Blob to output diff instead of stdout */ | |
| 805 | 806 | ){ |
| 806 | 807 | int vid; |
| 807 | 808 | Blob sql; |
| 808 | 809 | Stmt q; |
| 809 | 810 | int asNewFile; /* Treat non-existant files as empty files */ |
| @@ -928,20 +929,20 @@ | ||
| 928 | 929 | db_finalize(&q); |
| 929 | 930 | db_end_transaction(1); /* ROLLBACK */ |
| 930 | 931 | } |
| 931 | 932 | |
| 932 | 933 | /* |
| 933 | -** Run a diff between the undo buffer and files on disk. | |
| 934 | +** Run a diff from the undo buffer to files on disk. | |
| 934 | 935 | ** |
| 935 | 936 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
| 936 | 937 | ** command zDiffCmd to do the diffing. |
| 937 | 938 | ** |
| 938 | 939 | ** When using an external diff program, zBinGlob contains the GLOB patterns |
| 939 | 940 | ** for file names to treat as binary. If fIncludeBinary is zero, these files |
| 940 | 941 | ** will be skipped in addition to files that may contain binary content. |
| 941 | 942 | */ |
| 942 | -static void diff_against_undo( | |
| 943 | +static void diff_undo_to_checkout( | |
| 943 | 944 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 944 | 945 | FileDirList *pFileDir /* List of files and directories to diff */ |
| 945 | 946 | ){ |
| 946 | 947 | Stmt q; |
| 947 | 948 | Blob content; |
| @@ -1088,10 +1089,62 @@ | ||
| 1088 | 1089 | } |
| 1089 | 1090 | } |
| 1090 | 1091 | manifest_destroy(pFrom); |
| 1091 | 1092 | manifest_destroy(pTo); |
| 1092 | 1093 | } |
| 1094 | + | |
| 1095 | +/* | |
| 1096 | +** Compute the difference from an external tree of files to the current | |
| 1097 | +** working checkout with its edits. | |
| 1098 | +** | |
| 1099 | +** To put it another way: Every managed file in the current working | |
| 1100 | +** checkout is compared to the file with same under in zTree. The zTree | |
| 1101 | +** files are on the left and the files in the current working directory | |
| 1102 | +** are on the right. | |
| 1103 | +*/ | |
| 1104 | +void diff_tree_to_checkout( | |
| 1105 | + const char *zExternTree, /* Remote tree to use as the baseline */ | |
| 1106 | + DiffConfig *pCfg, /* Diff settings */ | |
| 1107 | + FileDirList *pFileDir /* Only look at these files */ | |
| 1108 | +){ | |
| 1109 | + int vid; | |
| 1110 | + Stmt q; | |
| 1111 | + | |
| 1112 | + vid = db_lget_int("checkout",0); | |
| 1113 | + if( file_isdir(zExternTree, ExtFILE)!=1 ){ | |
| 1114 | + fossil_fatal("\"%s\" is not a directory", zExternTree); | |
| 1115 | + } | |
| 1116 | + db_prepare(&q, | |
| 1117 | + "SELECT pathname FROM vfile WHERE vid=%d ORDER BY pathname", | |
| 1118 | + vid | |
| 1119 | + ); | |
| 1120 | + while( db_step(&q)==SQLITE_ROW ){ | |
| 1121 | + const char *zTreename = db_column_text(&q,0); | |
| 1122 | + char *zLhs = mprintf("%s/%s", zExternTree, zTreename); | |
| 1123 | + char *zRhs = mprintf("%s%s", g.zLocalRoot, zTreename); | |
| 1124 | + Blob rhs; | |
| 1125 | + Blob lhs; | |
| 1126 | + if( file_size(zLhs, ExtFILE)<0 ){ | |
| 1127 | + blob_zero(&lhs); | |
| 1128 | + }else{ | |
| 1129 | + blob_read_from_file(&lhs, zLhs, ExtFILE); | |
| 1130 | + } | |
| 1131 | + blob_read_from_file(&rhs, zRhs, ExtFILE); | |
| 1132 | + if( blob_size(&lhs)!=blob_size(&rhs) | |
| 1133 | + || memcmp(blob_buffer(&lhs), blob_buffer(&rhs), blob_size(&lhs))!=0 | |
| 1134 | + ){ | |
| 1135 | + diff_print_index(zTreename, pCfg, 0); | |
| 1136 | + diff_file_mem(&lhs, &rhs, zTreename, pCfg); | |
| 1137 | + } | |
| 1138 | + blob_reset(&lhs); | |
| 1139 | + blob_reset(&rhs); | |
| 1140 | + fossil_free(zLhs); | |
| 1141 | + fossil_free(zRhs); | |
| 1142 | + } | |
| 1143 | + db_finalize(&q); | |
| 1144 | +} | |
| 1145 | + | |
| 1093 | 1146 | |
| 1094 | 1147 | /* |
| 1095 | 1148 | ** Return the name of the external diff command, or return NULL if |
| 1096 | 1149 | ** no external diff command is defined. |
| 1097 | 1150 | */ |
| @@ -1270,10 +1323,11 @@ | ||
| 1270 | 1323 | ** --strip-trailing-cr Strip trailing CR |
| 1271 | 1324 | ** --tcl Tcl-formatted output used internally by --tk |
| 1272 | 1325 | ** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh") |
| 1273 | 1326 | ** --tk Launch a Tcl/Tk GUI for display |
| 1274 | 1327 | ** --to VERSION Select VERSION as target for the diff |
| 1328 | +** --tree DIR Use files under DIR as the baseline | |
| 1275 | 1329 | ** --undo Diff against the "undo" buffer |
| 1276 | 1330 | ** --unified Unified diff |
| 1277 | 1331 | ** -v|--verbose Output complete text of added or deleted files |
| 1278 | 1332 | ** -h|--versions Show compared versions in the diff header |
| 1279 | 1333 | ** --webpage Format output as a stand-alone HTML webpage |
| @@ -1284,10 +1338,11 @@ | ||
| 1284 | 1338 | int isGDiff; /* True for gdiff. False for normal diff */ |
| 1285 | 1339 | const char *zFrom; /* Source version number */ |
| 1286 | 1340 | const char *zTo; /* Target version number */ |
| 1287 | 1341 | const char *zCheckin; /* Check-in version number */ |
| 1288 | 1342 | const char *zBranch; /* Branch to diff */ |
| 1343 | + const char *zTree; /* The --tree */ | |
| 1289 | 1344 | int againstUndo = 0; /* Diff against files in the undo buffer */ |
| 1290 | 1345 | FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
| 1291 | 1346 | DiffConfig DCfg; /* Diff configuration object */ |
| 1292 | 1347 | |
| 1293 | 1348 | if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ |
| @@ -1297,12 +1352,17 @@ | ||
| 1297 | 1352 | isGDiff = g.argv[1][0]=='g'; |
| 1298 | 1353 | zFrom = find_option("from", "r", 1); |
| 1299 | 1354 | zTo = find_option("to", 0, 1); |
| 1300 | 1355 | zCheckin = find_option("checkin", "ci", 1); |
| 1301 | 1356 | zBranch = find_option("branch", 0, 1); |
| 1357 | + zTree = find_option("tree", 0, 1); | |
| 1302 | 1358 | againstUndo = find_option("undo",0,0)!=0; |
| 1303 | - if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ | |
| 1359 | + if( zTree && (zFrom || zTo || zCheckin || zBranch || againstUndo) ){ | |
| 1360 | + fossil_fatal("cannot use --tree together with --from, --to, --checkin," | |
| 1361 | + " --branch, or --undo"); | |
| 1362 | + } | |
| 1363 | + if( againstUndo && (zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ | |
| 1304 | 1364 | fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
| 1305 | 1365 | " or --branch"); |
| 1306 | 1366 | } |
| 1307 | 1367 | if( zBranch ){ |
| 1308 | 1368 | if( zTo || zFrom || zCheckin ){ |
| @@ -1309,11 +1369,11 @@ | ||
| 1309 | 1369 | fossil_fatal("cannot use --from, --to, or --checkin with --branch"); |
| 1310 | 1370 | } |
| 1311 | 1371 | zTo = zBranch; |
| 1312 | 1372 | zFrom = mprintf("root:%s", zBranch); |
| 1313 | 1373 | } |
| 1314 | - if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){ | |
| 1374 | + if( zCheckin!=0 && (zFrom!=0 || zTo!=0) ){ | |
| 1315 | 1375 | fossil_fatal("cannot use --checkin together with --from or --to"); |
| 1316 | 1376 | } |
| 1317 | 1377 | diff_options(&DCfg, isGDiff, 0); |
| 1318 | 1378 | determine_exec_relative_option(1); |
| 1319 | 1379 | if( 0==zCheckin ){ |
| @@ -1357,18 +1417,20 @@ | ||
| 1357 | 1417 | if( zFrom==0 ){ |
| 1358 | 1418 | fossil_fatal("check-in %s has no parent", zTo); |
| 1359 | 1419 | } |
| 1360 | 1420 | } |
| 1361 | 1421 | diff_begin(&DCfg); |
| 1362 | - if( againstUndo ){ | |
| 1422 | + if( zTree ){ | |
| 1423 | + diff_tree_to_checkout(zTree, &DCfg, pFileDir); | |
| 1424 | + }else if( againstUndo ){ | |
| 1363 | 1425 | if( db_lget_int("undo_available",0)==0 ){ |
| 1364 | 1426 | fossil_print("No undo or redo is available\n"); |
| 1365 | 1427 | return; |
| 1366 | 1428 | } |
| 1367 | - diff_against_undo(&DCfg, pFileDir); | |
| 1429 | + diff_undo_to_checkout(&DCfg, pFileDir); | |
| 1368 | 1430 | }else if( zTo==0 ){ |
| 1369 | - diff_against_disk(zFrom, &DCfg, pFileDir, 0); | |
| 1431 | + diff_version_to_checkout(zFrom, &DCfg, pFileDir, 0); | |
| 1370 | 1432 | }else{ |
| 1371 | 1433 | diff_two_versions(zFrom, zTo, &DCfg, pFileDir); |
| 1372 | 1434 | } |
| 1373 | 1435 | if( pFileDir ){ |
| 1374 | 1436 | int i; |
| 1375 | 1437 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -784,26 +784,27 @@ | |
| 784 | blob_reset(&file); |
| 785 | return rc; |
| 786 | } |
| 787 | |
| 788 | /* |
| 789 | ** Run a diff between the version zFrom and files on disk. zFrom might |
| 790 | ** be NULL which means to simply show the difference between the edited |
| 791 | ** files on disk and the check-out on which they are based. |
| 792 | ** |
| 793 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
| 794 | ** command zDiffCmd to do the diffing. |
| 795 | ** |
| 796 | ** When using an external diff program, zBinGlob contains the GLOB patterns |
| 797 | ** for file names to treat as binary. If fIncludeBinary is zero, these files |
| 798 | ** will be skipped in addition to files that may contain binary content. |
| 799 | */ |
| 800 | void diff_against_disk( |
| 801 | const char *zFrom, /* Version to difference from */ |
| 802 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 803 | FileDirList *pFileDir, /* Which files to diff */ |
| 804 | Blob *pOut /* Blob to output diff instead of stdout */ |
| 805 | ){ |
| 806 | int vid; |
| 807 | Blob sql; |
| 808 | Stmt q; |
| 809 | int asNewFile; /* Treat non-existant files as empty files */ |
| @@ -928,20 +929,20 @@ | |
| 928 | db_finalize(&q); |
| 929 | db_end_transaction(1); /* ROLLBACK */ |
| 930 | } |
| 931 | |
| 932 | /* |
| 933 | ** Run a diff between the undo buffer and files on disk. |
| 934 | ** |
| 935 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
| 936 | ** command zDiffCmd to do the diffing. |
| 937 | ** |
| 938 | ** When using an external diff program, zBinGlob contains the GLOB patterns |
| 939 | ** for file names to treat as binary. If fIncludeBinary is zero, these files |
| 940 | ** will be skipped in addition to files that may contain binary content. |
| 941 | */ |
| 942 | static void diff_against_undo( |
| 943 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 944 | FileDirList *pFileDir /* List of files and directories to diff */ |
| 945 | ){ |
| 946 | Stmt q; |
| 947 | Blob content; |
| @@ -1088,10 +1089,62 @@ | |
| 1088 | } |
| 1089 | } |
| 1090 | manifest_destroy(pFrom); |
| 1091 | manifest_destroy(pTo); |
| 1092 | } |
| 1093 | |
| 1094 | /* |
| 1095 | ** Return the name of the external diff command, or return NULL if |
| 1096 | ** no external diff command is defined. |
| 1097 | */ |
| @@ -1270,10 +1323,11 @@ | |
| 1270 | ** --strip-trailing-cr Strip trailing CR |
| 1271 | ** --tcl Tcl-formatted output used internally by --tk |
| 1272 | ** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh") |
| 1273 | ** --tk Launch a Tcl/Tk GUI for display |
| 1274 | ** --to VERSION Select VERSION as target for the diff |
| 1275 | ** --undo Diff against the "undo" buffer |
| 1276 | ** --unified Unified diff |
| 1277 | ** -v|--verbose Output complete text of added or deleted files |
| 1278 | ** -h|--versions Show compared versions in the diff header |
| 1279 | ** --webpage Format output as a stand-alone HTML webpage |
| @@ -1284,10 +1338,11 @@ | |
| 1284 | int isGDiff; /* True for gdiff. False for normal diff */ |
| 1285 | const char *zFrom; /* Source version number */ |
| 1286 | const char *zTo; /* Target version number */ |
| 1287 | const char *zCheckin; /* Check-in version number */ |
| 1288 | const char *zBranch; /* Branch to diff */ |
| 1289 | int againstUndo = 0; /* Diff against files in the undo buffer */ |
| 1290 | FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
| 1291 | DiffConfig DCfg; /* Diff configuration object */ |
| 1292 | |
| 1293 | if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ |
| @@ -1297,12 +1352,17 @@ | |
| 1297 | isGDiff = g.argv[1][0]=='g'; |
| 1298 | zFrom = find_option("from", "r", 1); |
| 1299 | zTo = find_option("to", 0, 1); |
| 1300 | zCheckin = find_option("checkin", "ci", 1); |
| 1301 | zBranch = find_option("branch", 0, 1); |
| 1302 | againstUndo = find_option("undo",0,0)!=0; |
| 1303 | if( againstUndo && ( zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ |
| 1304 | fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
| 1305 | " or --branch"); |
| 1306 | } |
| 1307 | if( zBranch ){ |
| 1308 | if( zTo || zFrom || zCheckin ){ |
| @@ -1309,11 +1369,11 @@ | |
| 1309 | fossil_fatal("cannot use --from, --to, or --checkin with --branch"); |
| 1310 | } |
| 1311 | zTo = zBranch; |
| 1312 | zFrom = mprintf("root:%s", zBranch); |
| 1313 | } |
| 1314 | if( zCheckin!=0 && ( zFrom!=0 || zTo!=0 ) ){ |
| 1315 | fossil_fatal("cannot use --checkin together with --from or --to"); |
| 1316 | } |
| 1317 | diff_options(&DCfg, isGDiff, 0); |
| 1318 | determine_exec_relative_option(1); |
| 1319 | if( 0==zCheckin ){ |
| @@ -1357,18 +1417,20 @@ | |
| 1357 | if( zFrom==0 ){ |
| 1358 | fossil_fatal("check-in %s has no parent", zTo); |
| 1359 | } |
| 1360 | } |
| 1361 | diff_begin(&DCfg); |
| 1362 | if( againstUndo ){ |
| 1363 | if( db_lget_int("undo_available",0)==0 ){ |
| 1364 | fossil_print("No undo or redo is available\n"); |
| 1365 | return; |
| 1366 | } |
| 1367 | diff_against_undo(&DCfg, pFileDir); |
| 1368 | }else if( zTo==0 ){ |
| 1369 | diff_against_disk(zFrom, &DCfg, pFileDir, 0); |
| 1370 | }else{ |
| 1371 | diff_two_versions(zFrom, zTo, &DCfg, pFileDir); |
| 1372 | } |
| 1373 | if( pFileDir ){ |
| 1374 | int i; |
| 1375 |
| --- src/diffcmd.c | |
| +++ src/diffcmd.c | |
| @@ -784,26 +784,27 @@ | |
| 784 | blob_reset(&file); |
| 785 | return rc; |
| 786 | } |
| 787 | |
| 788 | /* |
| 789 | ** Run a diff between the version zFrom and files on disk in the current |
| 790 | ** working checkout. zFrom might be NULL which means to simply show the |
| 791 | ** difference between the edited files on disk and the check-out on which |
| 792 | ** they are based. |
| 793 | ** |
| 794 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
| 795 | ** command zDiffCmd to do the diffing. |
| 796 | ** |
| 797 | ** When using an external diff program, zBinGlob contains the GLOB patterns |
| 798 | ** for file names to treat as binary. If fIncludeBinary is zero, these files |
| 799 | ** will be skipped in addition to files that may contain binary content. |
| 800 | */ |
| 801 | void diff_version_to_checkout( |
| 802 | const char *zFrom, /* Version to difference from */ |
| 803 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 804 | FileDirList *pFileDir, /* Which files to diff */ |
| 805 | Blob *pOut /* Blob to output diff instead of stdout */ |
| 806 | ){ |
| 807 | int vid; |
| 808 | Blob sql; |
| 809 | Stmt q; |
| 810 | int asNewFile; /* Treat non-existant files as empty files */ |
| @@ -928,20 +929,20 @@ | |
| 929 | db_finalize(&q); |
| 930 | db_end_transaction(1); /* ROLLBACK */ |
| 931 | } |
| 932 | |
| 933 | /* |
| 934 | ** Run a diff from the undo buffer to files on disk. |
| 935 | ** |
| 936 | ** Use the internal diff logic if zDiffCmd is NULL. Otherwise call the |
| 937 | ** command zDiffCmd to do the diffing. |
| 938 | ** |
| 939 | ** When using an external diff program, zBinGlob contains the GLOB patterns |
| 940 | ** for file names to treat as binary. If fIncludeBinary is zero, these files |
| 941 | ** will be skipped in addition to files that may contain binary content. |
| 942 | */ |
| 943 | static void diff_undo_to_checkout( |
| 944 | DiffConfig *pCfg, /* Flags controlling diff output */ |
| 945 | FileDirList *pFileDir /* List of files and directories to diff */ |
| 946 | ){ |
| 947 | Stmt q; |
| 948 | Blob content; |
| @@ -1088,10 +1089,62 @@ | |
| 1089 | } |
| 1090 | } |
| 1091 | manifest_destroy(pFrom); |
| 1092 | manifest_destroy(pTo); |
| 1093 | } |
| 1094 | |
| 1095 | /* |
| 1096 | ** Compute the difference from an external tree of files to the current |
| 1097 | ** working checkout with its edits. |
| 1098 | ** |
| 1099 | ** To put it another way: Every managed file in the current working |
| 1100 | ** checkout is compared to the file with same under in zTree. The zTree |
| 1101 | ** files are on the left and the files in the current working directory |
| 1102 | ** are on the right. |
| 1103 | */ |
| 1104 | void diff_tree_to_checkout( |
| 1105 | const char *zExternTree, /* Remote tree to use as the baseline */ |
| 1106 | DiffConfig *pCfg, /* Diff settings */ |
| 1107 | FileDirList *pFileDir /* Only look at these files */ |
| 1108 | ){ |
| 1109 | int vid; |
| 1110 | Stmt q; |
| 1111 | |
| 1112 | vid = db_lget_int("checkout",0); |
| 1113 | if( file_isdir(zExternTree, ExtFILE)!=1 ){ |
| 1114 | fossil_fatal("\"%s\" is not a directory", zExternTree); |
| 1115 | } |
| 1116 | db_prepare(&q, |
| 1117 | "SELECT pathname FROM vfile WHERE vid=%d ORDER BY pathname", |
| 1118 | vid |
| 1119 | ); |
| 1120 | while( db_step(&q)==SQLITE_ROW ){ |
| 1121 | const char *zTreename = db_column_text(&q,0); |
| 1122 | char *zLhs = mprintf("%s/%s", zExternTree, zTreename); |
| 1123 | char *zRhs = mprintf("%s%s", g.zLocalRoot, zTreename); |
| 1124 | Blob rhs; |
| 1125 | Blob lhs; |
| 1126 | if( file_size(zLhs, ExtFILE)<0 ){ |
| 1127 | blob_zero(&lhs); |
| 1128 | }else{ |
| 1129 | blob_read_from_file(&lhs, zLhs, ExtFILE); |
| 1130 | } |
| 1131 | blob_read_from_file(&rhs, zRhs, ExtFILE); |
| 1132 | if( blob_size(&lhs)!=blob_size(&rhs) |
| 1133 | || memcmp(blob_buffer(&lhs), blob_buffer(&rhs), blob_size(&lhs))!=0 |
| 1134 | ){ |
| 1135 | diff_print_index(zTreename, pCfg, 0); |
| 1136 | diff_file_mem(&lhs, &rhs, zTreename, pCfg); |
| 1137 | } |
| 1138 | blob_reset(&lhs); |
| 1139 | blob_reset(&rhs); |
| 1140 | fossil_free(zLhs); |
| 1141 | fossil_free(zRhs); |
| 1142 | } |
| 1143 | db_finalize(&q); |
| 1144 | } |
| 1145 | |
| 1146 | |
| 1147 | /* |
| 1148 | ** Return the name of the external diff command, or return NULL if |
| 1149 | ** no external diff command is defined. |
| 1150 | */ |
| @@ -1270,10 +1323,11 @@ | |
| 1323 | ** --strip-trailing-cr Strip trailing CR |
| 1324 | ** --tcl Tcl-formatted output used internally by --tk |
| 1325 | ** --tclsh PATH Tcl/Tk shell used for --tk (default: "tclsh") |
| 1326 | ** --tk Launch a Tcl/Tk GUI for display |
| 1327 | ** --to VERSION Select VERSION as target for the diff |
| 1328 | ** --tree DIR Use files under DIR as the baseline |
| 1329 | ** --undo Diff against the "undo" buffer |
| 1330 | ** --unified Unified diff |
| 1331 | ** -v|--verbose Output complete text of added or deleted files |
| 1332 | ** -h|--versions Show compared versions in the diff header |
| 1333 | ** --webpage Format output as a stand-alone HTML webpage |
| @@ -1284,10 +1338,11 @@ | |
| 1338 | int isGDiff; /* True for gdiff. False for normal diff */ |
| 1339 | const char *zFrom; /* Source version number */ |
| 1340 | const char *zTo; /* Target version number */ |
| 1341 | const char *zCheckin; /* Check-in version number */ |
| 1342 | const char *zBranch; /* Branch to diff */ |
| 1343 | const char *zTree; /* The --tree */ |
| 1344 | int againstUndo = 0; /* Diff against files in the undo buffer */ |
| 1345 | FileDirList *pFileDir = 0; /* Restrict the diff to these files */ |
| 1346 | DiffConfig DCfg; /* Diff configuration object */ |
| 1347 | |
| 1348 | if( find_option("tk",0,0)!=0 || has_option("tclsh") ){ |
| @@ -1297,12 +1352,17 @@ | |
| 1352 | isGDiff = g.argv[1][0]=='g'; |
| 1353 | zFrom = find_option("from", "r", 1); |
| 1354 | zTo = find_option("to", 0, 1); |
| 1355 | zCheckin = find_option("checkin", "ci", 1); |
| 1356 | zBranch = find_option("branch", 0, 1); |
| 1357 | zTree = find_option("tree", 0, 1); |
| 1358 | againstUndo = find_option("undo",0,0)!=0; |
| 1359 | if( zTree && (zFrom || zTo || zCheckin || zBranch || againstUndo) ){ |
| 1360 | fossil_fatal("cannot use --tree together with --from, --to, --checkin," |
| 1361 | " --branch, or --undo"); |
| 1362 | } |
| 1363 | if( againstUndo && (zFrom!=0 || zTo!=0 || zCheckin!=0 || zBranch!=0) ){ |
| 1364 | fossil_fatal("cannot use --undo together with --from, --to, --checkin," |
| 1365 | " or --branch"); |
| 1366 | } |
| 1367 | if( zBranch ){ |
| 1368 | if( zTo || zFrom || zCheckin ){ |
| @@ -1309,11 +1369,11 @@ | |
| 1369 | fossil_fatal("cannot use --from, --to, or --checkin with --branch"); |
| 1370 | } |
| 1371 | zTo = zBranch; |
| 1372 | zFrom = mprintf("root:%s", zBranch); |
| 1373 | } |
| 1374 | if( zCheckin!=0 && (zFrom!=0 || zTo!=0) ){ |
| 1375 | fossil_fatal("cannot use --checkin together with --from or --to"); |
| 1376 | } |
| 1377 | diff_options(&DCfg, isGDiff, 0); |
| 1378 | determine_exec_relative_option(1); |
| 1379 | if( 0==zCheckin ){ |
| @@ -1357,18 +1417,20 @@ | |
| 1417 | if( zFrom==0 ){ |
| 1418 | fossil_fatal("check-in %s has no parent", zTo); |
| 1419 | } |
| 1420 | } |
| 1421 | diff_begin(&DCfg); |
| 1422 | if( zTree ){ |
| 1423 | diff_tree_to_checkout(zTree, &DCfg, pFileDir); |
| 1424 | }else if( againstUndo ){ |
| 1425 | if( db_lget_int("undo_available",0)==0 ){ |
| 1426 | fossil_print("No undo or redo is available\n"); |
| 1427 | return; |
| 1428 | } |
| 1429 | diff_undo_to_checkout(&DCfg, pFileDir); |
| 1430 | }else if( zTo==0 ){ |
| 1431 | diff_version_to_checkout(zFrom, &DCfg, pFileDir, 0); |
| 1432 | }else{ |
| 1433 | diff_two_versions(zFrom, zTo, &DCfg, pFileDir); |
| 1434 | } |
| 1435 | if( pFileDir ){ |
| 1436 | int i; |
| 1437 |