Fossil SCM

Fix revert -r option to mark a reverted file as edited if the reverted-to version does not exactly match the checkout version, even if the file size is equal

andygoth 2016-11-15 23:29 trunk
Commit f9080683f04371609df7a92597f5a1e86689f61d
3 files changed +4 -6 +2 -6 +125 -72
+4 -6
--- src/db.c
+++ src/db.c
@@ -2215,21 +2215,19 @@
22152215
g.zLocalRoot, zName);
22162216
if( !g.localOpen ){
22172217
/* Repository is in the process of being opened, but files have not been
22182218
* written to disk. Load from the database. */
22192219
Blob noWarnFile;
2220
- if( historical_version_of_file(g.zOpenRevision,
2221
- blob_str(&versionedPathname),
2222
- &setting, 0, 0, 0, 2)!=2 ){
2220
+ if( historical_blob(g.zOpenRevision, blob_str(&versionedPathname),
2221
+ &setting, 0) ){
22232222
found = 1;
22242223
}
22252224
/* See if there's a no-warn flag */
22262225
blob_append(&versionedPathname, ".no-warn", -1);
22272226
blob_zero(&noWarnFile);
2228
- if( historical_version_of_file(g.zOpenRevision,
2229
- blob_str(&versionedPathname),
2230
- &noWarnFile, 0, 0, 0, 2)!=2 ){
2227
+ if( historical_blob(g.zOpenRevision, blob_str(&versionedPathname),
2228
+ &noWarnFile, 0) ){
22312229
noWarn = 1;
22322230
}
22332231
blob_reset(&noWarnFile);
22342232
}else if( file_size(blob_str(&versionedPathname))>=0 ){
22352233
/* File exists, and contains the value for this setting. Load from
22362234
--- src/db.c
+++ src/db.c
@@ -2215,21 +2215,19 @@
2215 g.zLocalRoot, zName);
2216 if( !g.localOpen ){
2217 /* Repository is in the process of being opened, but files have not been
2218 * written to disk. Load from the database. */
2219 Blob noWarnFile;
2220 if( historical_version_of_file(g.zOpenRevision,
2221 blob_str(&versionedPathname),
2222 &setting, 0, 0, 0, 2)!=2 ){
2223 found = 1;
2224 }
2225 /* See if there's a no-warn flag */
2226 blob_append(&versionedPathname, ".no-warn", -1);
2227 blob_zero(&noWarnFile);
2228 if( historical_version_of_file(g.zOpenRevision,
2229 blob_str(&versionedPathname),
2230 &noWarnFile, 0, 0, 0, 2)!=2 ){
2231 noWarn = 1;
2232 }
2233 blob_reset(&noWarnFile);
2234 }else if( file_size(blob_str(&versionedPathname))>=0 ){
2235 /* File exists, and contains the value for this setting. Load from
2236
--- src/db.c
+++ src/db.c
@@ -2215,21 +2215,19 @@
2215 g.zLocalRoot, zName);
2216 if( !g.localOpen ){
2217 /* Repository is in the process of being opened, but files have not been
2218 * written to disk. Load from the database. */
2219 Blob noWarnFile;
2220 if( historical_blob(g.zOpenRevision, blob_str(&versionedPathname),
2221 &setting, 0) ){
 
2222 found = 1;
2223 }
2224 /* See if there's a no-warn flag */
2225 blob_append(&versionedPathname, ".no-warn", -1);
2226 blob_zero(&noWarnFile);
2227 if( historical_blob(g.zOpenRevision, blob_str(&versionedPathname),
2228 &noWarnFile, 0) ){
 
2229 noWarn = 1;
2230 }
2231 blob_reset(&noWarnFile);
2232 }else if( file_size(blob_str(&versionedPathname))>=0 ){
2233 /* File exists, and contains the value for this setting. Load from
2234
+2 -6
--- src/finfo.c
+++ src/finfo.c
@@ -124,11 +124,11 @@
124124
/* We should be done with options.. */
125125
verify_all_options();
126126
127127
file_tree_name(g.argv[2], &fname, 0, 1);
128128
if( zRevision ){
129
- historical_version_of_file(zRevision, blob_str(&fname), &record, 0,0,0,0);
129
+ historical_blob(zRevision, blob_str(&fname), &record, 1);
130130
}else{
131131
int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
132132
&fname, filename_collation());
133133
if( rid==0 ){
134134
fossil_fatal("no history for file: %b", &fname);
@@ -249,11 +249,10 @@
249249
**
250250
** See also: finfo
251251
*/
252252
void cat_cmd(void){
253253
int i;
254
- int rc;
255254
Blob content, fname;
256255
const char *zRev;
257256
db_find_and_open_repository(0, 0);
258257
zRev = find_option("r","r",1);
259258
@@ -261,14 +260,11 @@
261260
verify_all_options();
262261
263262
for(i=2; i<g.argc; i++){
264263
file_tree_name(g.argv[i], &fname, 0, 1);
265264
blob_zero(&content);
266
- rc = historical_version_of_file(zRev, blob_str(&fname), &content, 0,0,0,2);
267
- if( rc==2 ){
268
- fossil_fatal("no such file: %s", g.argv[i]);
269
- }
265
+ historical_blob(zRev, blob_str(&fname), &content, 1);
270266
blob_write_to_file(&content, "-");
271267
blob_reset(&fname);
272268
blob_reset(&content);
273269
}
274270
}
275271
--- src/finfo.c
+++ src/finfo.c
@@ -124,11 +124,11 @@
124 /* We should be done with options.. */
125 verify_all_options();
126
127 file_tree_name(g.argv[2], &fname, 0, 1);
128 if( zRevision ){
129 historical_version_of_file(zRevision, blob_str(&fname), &record, 0,0,0,0);
130 }else{
131 int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
132 &fname, filename_collation());
133 if( rid==0 ){
134 fossil_fatal("no history for file: %b", &fname);
@@ -249,11 +249,10 @@
249 **
250 ** See also: finfo
251 */
252 void cat_cmd(void){
253 int i;
254 int rc;
255 Blob content, fname;
256 const char *zRev;
257 db_find_and_open_repository(0, 0);
258 zRev = find_option("r","r",1);
259
@@ -261,14 +260,11 @@
261 verify_all_options();
262
263 for(i=2; i<g.argc; i++){
264 file_tree_name(g.argv[i], &fname, 0, 1);
265 blob_zero(&content);
266 rc = historical_version_of_file(zRev, blob_str(&fname), &content, 0,0,0,2);
267 if( rc==2 ){
268 fossil_fatal("no such file: %s", g.argv[i]);
269 }
270 blob_write_to_file(&content, "-");
271 blob_reset(&fname);
272 blob_reset(&content);
273 }
274 }
275
--- src/finfo.c
+++ src/finfo.c
@@ -124,11 +124,11 @@
124 /* We should be done with options.. */
125 verify_all_options();
126
127 file_tree_name(g.argv[2], &fname, 0, 1);
128 if( zRevision ){
129 historical_blob(zRevision, blob_str(&fname), &record, 1);
130 }else{
131 int rid = db_int(0, "SELECT rid FROM vfile WHERE pathname=%B %s",
132 &fname, filename_collation());
133 if( rid==0 ){
134 fossil_fatal("no history for file: %b", &fname);
@@ -249,11 +249,10 @@
249 **
250 ** See also: finfo
251 */
252 void cat_cmd(void){
253 int i;
 
254 Blob content, fname;
255 const char *zRev;
256 db_find_and_open_repository(0, 0);
257 zRev = find_option("r","r",1);
258
@@ -261,14 +260,11 @@
260 verify_all_options();
261
262 for(i=2; i<g.argc; i++){
263 file_tree_name(g.argv[i], &fname, 0, 1);
264 blob_zero(&content);
265 historical_blob(zRev, blob_str(&fname), &content, 1);
 
 
 
266 blob_write_to_file(&content, "-");
267 blob_reset(&fname);
268 blob_reset(&content);
269 }
270 }
271
+125 -72
--- src/update.c
+++ src/update.c
@@ -630,68 +630,100 @@
630630
blob_reset(&dirsList);
631631
fossil_free(zEmptyDirs);
632632
}
633633
}
634634
635
-
636
-/*
637
-** Get the contents of a file within the check-in "revision". If
638
-** revision==NULL then get the file content for the current checkout.
639
-*/
640
-int historical_version_of_file(
641
- const char *revision, /* The check-in containing the file */
642
- const char *file, /* Full treename of the file */
643
- Blob *content, /* Put the content here */
644
- int *pIsLink, /* Set to true if file is link. */
645
- int *pIsExe, /* Set to true if file is executable */
646
- int *pIsBin, /* Set to true if file is binary */
647
- int errCode /* Error code if file not found. Panic if <= 0. */
648
-){
649
- Manifest *pManifest;
650
- ManifestFile *pFile;
651
- int rid=0;
652
-
653
- if( revision ){
654
- rid = name_to_typed_rid(revision,"ci");
655
- }else if( !g.localOpen ){
656
- rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
657
- }else{
658
- rid = db_lget_int("checkout", 0);
659
- }
660
- if( !is_a_version(rid) ){
661
- if( errCode>0 ) return errCode;
662
- fossil_fatal("no such check-in: %s", revision);
663
- }
664
- pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
665
-
666
- if( pManifest ){
667
- pFile = manifest_file_find(pManifest, file);
668
- if( pFile ){
669
- int rc;
670
- rid = uuid_to_rid(pFile->zUuid, 0);
671
- if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE );
672
- if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK );
673
- manifest_destroy(pManifest);
674
- rc = content_get(rid, content);
675
- if( rc && pIsBin ){
676
- *pIsBin = looks_like_binary(content);
677
- }
678
- return rc;
679
- }
680
- manifest_destroy(pManifest);
681
- if( errCode<=0 ){
682
- fossil_fatal("file %s does not exist in check-in: %s", file, revision);
683
- }
684
- }else if( errCode<=0 ){
685
- if( revision==0 ){
686
- revision = db_text("current", "SELECT uuid FROM blob WHERE rid=%d", rid);
687
- }
688
- fossil_fatal("could not parse manifest for check-in: %s", revision);
689
- }
690
- return errCode;
691
-}
692
-
635
+/*
636
+** Get the manifest record for a given revision, or the current checkout if
637
+** zRevision is NULL.
638
+*/
639
+Manifest *historical_manifest(
640
+ const char *zRevision /* The check-in to query, or NULL for current */
641
+){
642
+ int vid;
643
+ Manifest *pManifest;
644
+
645
+ /* Determine the check-in manifest artifact ID. Panic on failure. */
646
+ if( zRevision ){
647
+ vid = name_to_typed_rid(zRevision, "ci");
648
+ }else if( !g.localOpen ){
649
+ vid = name_to_typed_rid(db_get("main-branch", "trunk"), "ci");
650
+ }else{
651
+ vid = db_lget_int("checkout", 0);
652
+ if( !is_a_version(vid) ){
653
+ zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
654
+ if( zRevision ){
655
+ fossil_fatal("checkout artifact is not a check-in: %s", zRevision);
656
+ }else{
657
+ fossil_fatal("invalid checkout artifact ID: %d", vid);
658
+ }
659
+ }
660
+ }
661
+
662
+ /* Parse the manifest, given its artifact ID. Panic on failure. */
663
+ if( !(pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0)) ){
664
+ if( zRevision ){
665
+ fossil_fatal("could not parse manifest for check-in: %s", zRevision);
666
+ }else{
667
+ fossil_fatal("could not parse manifest for current checkout");
668
+ }
669
+ }
670
+
671
+ /* Return the manifest pointer. The caller must use manifest_destroy() to
672
+ * clean up when finished using the manifest. */
673
+ return pManifest;
674
+}
675
+
676
+/*
677
+** Get the contents of a file within the check-in "zRevision". If
678
+** zRevision==NULL then get the file content for the current checkout.
679
+*/
680
+int historical_blob(
681
+ const char *zRevision, /* The check-in containing the file */
682
+ const char *zFile, /* Full treename of the file */
683
+ Blob *pBlob, /* Put the content here */
684
+ int fatal /* If nonzero, panic if file/artifact not found */
685
+){
686
+ int result = 0;
687
+
688
+ /* Get the manifest for the requested check-in version. This call unavoidably
689
+ * panics on failure even if fatal is not set. */
690
+ Manifest *pManifest = historical_manifest(zRevision);
691
+
692
+ /* Try to find the file record within the manifest. */
693
+ ManifestFile *pFile = manifest_file_find(pManifest, zFile);
694
+
695
+ if( !pFile ){
696
+ /* Process file-not-found errors. */
697
+ if( fatal ){
698
+ if( zRevision ){
699
+ fossil_fatal("file %s does not exist in check-in %s", zFile, zRevision);
700
+ }else{
701
+ fossil_fatal("no such file: %s", zFile);
702
+ }
703
+ }
704
+ }else{
705
+ /* Get the file's contents. */
706
+ result = content_get(fast_uuid_to_rid(pFile->zUuid), pBlob);
707
+
708
+ /* Process artifact-not-found errors. */
709
+ if( !result && fatal ){
710
+ if( zRevision ){
711
+ fossil_fatal("missing artifact %s for file %s in check-in %s",
712
+ pFile->zUuid, zFile, zRevision);
713
+ }else{
714
+ fossil_fatal("missing artifact %s for file %s", pFile->zUuid, zFile);
715
+ }
716
+ }
717
+ }
718
+
719
+ /* Deallocate the parsed manifest structure. */
720
+ manifest_destroy(pManifest);
721
+
722
+ /* Return 1 on success and (assuming fatal is not set) 0 if not found. */
723
+ return result;
724
+}
693725
694726
/*
695727
** COMMAND: revert
696728
**
697729
** Usage: %fossil revert ?-r REVISION? ?FILE ...?
@@ -712,15 +744,18 @@
712744
** -r REVISION revert given FILE(s) back to given REVISION
713745
**
714746
** See also: redo, undo, update
715747
*/
716748
void revert_cmd(void){
717
- const char *zFile;
718
- const char *zRevision;
719
- Blob record;
749
+ Manifest *pCoManifest; /* Manifest of current checkout */
750
+ Manifest *pRvManifest; /* Manifest of selected revert version */
751
+ ManifestFile *pCoFile; /* File within current checkout manifest */
752
+ ManifestFile *pRvFile; /* File within revert version manifest */
753
+ const char *zFile; /* Filename relative to checkout root */
754
+ const char *zRevision; /* Selected revert version, NULL if current */
755
+ Blob record = BLOB_INITIALIZER; /* Contents of each reverted file */
720756
int i;
721
- int errCode;
722757
Stmt q;
723758
724759
undo_capture_command_line();
725760
zRevision = find_option("revision", "r", 1);
726761
verify_all_options();
@@ -730,10 +765,15 @@
730765
}
731766
if( zRevision && g.argc<3 ){
732767
fossil_fatal("the --revision option does not work for the entire tree");
733768
}
734769
db_must_be_within_tree();
770
+
771
+ /* Get manifests of revert version and (if different) current checkout. */
772
+ pRvManifest = historical_manifest(zRevision);
773
+ pCoManifest = zRevision ? historical_manifest(0) : 0;
774
+
735775
db_begin_transaction();
736776
undo_begin();
737777
db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);");
738778
739779
if( g.argc>2 ){
@@ -775,18 +815,15 @@
775815
if( zRevision==0 ){
776816
int vid = db_lget_int("checkout", 0);
777817
zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
778818
}
779819
while( db_step(&q)==SQLITE_ROW ){
780
- int isExe = 0;
781
- int isLink = 0;
782820
char *zFull;
783821
zFile = db_column_text(&q, 0);
784822
zFull = mprintf("%/%/", g.zLocalRoot, zFile);
785
- errCode = historical_version_of_file(zRevision, zFile, &record,
786
- &isLink, &isExe, 0, 2);
787
- if( errCode==2 ){
823
+ pRvFile = manifest_file_find(pRvManifest, zFile);
824
+ if( !pRvFile ){
788825
if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
789826
zFile, zFile)==0 ){
790827
fossil_print("UNMANAGE %s\n", zFile);
791828
}else{
792829
undo_save(zFile);
@@ -800,31 +837,47 @@
800837
"DELETE FROM vfile WHERE pathname=%Q",
801838
zFile, zFile
802839
);
803840
}else{
804841
sqlite3_int64 mtime;
842
+ int rvChnged = 0;
843
+ int rvPerm = manifest_file_mperm(pRvFile);
844
+
845
+ /* Determine if reverted-to file is different than checked out file. */
846
+ if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){
847
+ rvChnged = manifest_file_mperm(pRvFile)!=rvPerm
848
+ || fossil_strcmp(pRvFile->zUuid, pCoFile->zUuid)!=0;
849
+ }
850
+
851
+ /* Get contents of reverted-to file. */
852
+ content_get(fast_uuid_to_rid(pRvFile->zUuid), &record);
853
+
805854
undo_save(zFile);
806
- if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(0)) ){
855
+ if( file_wd_size(zFull)>=0 && (rvPerm==PERM_LNK || file_wd_islink(0)) ){
807856
file_delete(zFull);
808857
}
809
- if( isLink ){
858
+ if( rvPerm==PERM_LNK ){
810859
symlink_create(blob_str(&record), zFull);
811860
}else{
812861
blob_write_to_file(&record, zFull);
813862
}
814
- file_wd_setexe(zFull, isExe);
863
+ file_wd_setexe(zFull, rvPerm==PERM_EXE);
815864
fossil_print("REVERT %s\n", zFile);
816865
mtime = file_wd_mtime(zFull);
817866
db_multi_exec(
818867
"UPDATE vfile"
819
- " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"
868
+ " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,mrid=rid"
820869
" WHERE pathname=%Q OR origname=%Q",
821
- mtime, isExe, isLink, zFile, zFile
870
+ mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile
822871
);
823872
}
824873
blob_reset(&record);
825874
free(zFull);
826875
}
827876
db_finalize(&q);
828877
undo_finish();
829878
db_end_transaction(0);
879
+
880
+ /* Deallocate parsed manifest structures. */
881
+ manifest_destroy(pRvManifest);
882
+ manifest_destroy(pCoManifest);
830883
}
831884
--- src/update.c
+++ src/update.c
@@ -630,68 +630,100 @@
630 blob_reset(&dirsList);
631 fossil_free(zEmptyDirs);
632 }
633 }
634
635
636 /*
637 ** Get the contents of a file within the check-in "revision". If
638 ** revision==NULL then get the file content for the current checkout.
639 */
640 int historical_version_of_file(
641 const char *revision, /* The check-in containing the file */
642 const char *file, /* Full treename of the file */
643 Blob *content, /* Put the content here */
644 int *pIsLink, /* Set to true if file is link. */
645 int *pIsExe, /* Set to true if file is executable */
646 int *pIsBin, /* Set to true if file is binary */
647 int errCode /* Error code if file not found. Panic if <= 0. */
648 ){
649 Manifest *pManifest;
650 ManifestFile *pFile;
651 int rid=0;
652
653 if( revision ){
654 rid = name_to_typed_rid(revision,"ci");
655 }else if( !g.localOpen ){
656 rid = name_to_typed_rid(db_get("main-branch","trunk"),"ci");
657 }else{
658 rid = db_lget_int("checkout", 0);
659 }
660 if( !is_a_version(rid) ){
661 if( errCode>0 ) return errCode;
662 fossil_fatal("no such check-in: %s", revision);
663 }
664 pManifest = manifest_get(rid, CFTYPE_MANIFEST, 0);
665
666 if( pManifest ){
667 pFile = manifest_file_find(pManifest, file);
668 if( pFile ){
669 int rc;
670 rid = uuid_to_rid(pFile->zUuid, 0);
671 if( pIsExe ) *pIsExe = ( manifest_file_mperm(pFile)==PERM_EXE );
672 if( pIsLink ) *pIsLink = ( manifest_file_mperm(pFile)==PERM_LNK );
673 manifest_destroy(pManifest);
674 rc = content_get(rid, content);
675 if( rc && pIsBin ){
676 *pIsBin = looks_like_binary(content);
677 }
678 return rc;
679 }
680 manifest_destroy(pManifest);
681 if( errCode<=0 ){
682 fossil_fatal("file %s does not exist in check-in: %s", file, revision);
683 }
684 }else if( errCode<=0 ){
685 if( revision==0 ){
686 revision = db_text("current", "SELECT uuid FROM blob WHERE rid=%d", rid);
687 }
688 fossil_fatal("could not parse manifest for check-in: %s", revision);
689 }
690 return errCode;
691 }
692
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
693
694 /*
695 ** COMMAND: revert
696 **
697 ** Usage: %fossil revert ?-r REVISION? ?FILE ...?
@@ -712,15 +744,18 @@
712 ** -r REVISION revert given FILE(s) back to given REVISION
713 **
714 ** See also: redo, undo, update
715 */
716 void revert_cmd(void){
717 const char *zFile;
718 const char *zRevision;
719 Blob record;
 
 
 
 
720 int i;
721 int errCode;
722 Stmt q;
723
724 undo_capture_command_line();
725 zRevision = find_option("revision", "r", 1);
726 verify_all_options();
@@ -730,10 +765,15 @@
730 }
731 if( zRevision && g.argc<3 ){
732 fossil_fatal("the --revision option does not work for the entire tree");
733 }
734 db_must_be_within_tree();
 
 
 
 
 
735 db_begin_transaction();
736 undo_begin();
737 db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);");
738
739 if( g.argc>2 ){
@@ -775,18 +815,15 @@
775 if( zRevision==0 ){
776 int vid = db_lget_int("checkout", 0);
777 zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
778 }
779 while( db_step(&q)==SQLITE_ROW ){
780 int isExe = 0;
781 int isLink = 0;
782 char *zFull;
783 zFile = db_column_text(&q, 0);
784 zFull = mprintf("%/%/", g.zLocalRoot, zFile);
785 errCode = historical_version_of_file(zRevision, zFile, &record,
786 &isLink, &isExe, 0, 2);
787 if( errCode==2 ){
788 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
789 zFile, zFile)==0 ){
790 fossil_print("UNMANAGE %s\n", zFile);
791 }else{
792 undo_save(zFile);
@@ -800,31 +837,47 @@
800 "DELETE FROM vfile WHERE pathname=%Q",
801 zFile, zFile
802 );
803 }else{
804 sqlite3_int64 mtime;
 
 
 
 
 
 
 
 
 
 
 
 
805 undo_save(zFile);
806 if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(0)) ){
807 file_delete(zFull);
808 }
809 if( isLink ){
810 symlink_create(blob_str(&record), zFull);
811 }else{
812 blob_write_to_file(&record, zFull);
813 }
814 file_wd_setexe(zFull, isExe);
815 fossil_print("REVERT %s\n", zFile);
816 mtime = file_wd_mtime(zFull);
817 db_multi_exec(
818 "UPDATE vfile"
819 " SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"
820 " WHERE pathname=%Q OR origname=%Q",
821 mtime, isExe, isLink, zFile, zFile
822 );
823 }
824 blob_reset(&record);
825 free(zFull);
826 }
827 db_finalize(&q);
828 undo_finish();
829 db_end_transaction(0);
 
 
 
 
830 }
831
--- src/update.c
+++ src/update.c
@@ -630,68 +630,100 @@
630 blob_reset(&dirsList);
631 fossil_free(zEmptyDirs);
632 }
633 }
634
635 /*
636 ** Get the manifest record for a given revision, or the current checkout if
637 ** zRevision is NULL.
638 */
639 Manifest *historical_manifest(
640 const char *zRevision /* The check-in to query, or NULL for current */
641 ){
642 int vid;
643 Manifest *pManifest;
644
645 /* Determine the check-in manifest artifact ID. Panic on failure. */
646 if( zRevision ){
647 vid = name_to_typed_rid(zRevision, "ci");
648 }else if( !g.localOpen ){
649 vid = name_to_typed_rid(db_get("main-branch", "trunk"), "ci");
650 }else{
651 vid = db_lget_int("checkout", 0);
652 if( !is_a_version(vid) ){
653 zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
654 if( zRevision ){
655 fossil_fatal("checkout artifact is not a check-in: %s", zRevision);
656 }else{
657 fossil_fatal("invalid checkout artifact ID: %d", vid);
658 }
659 }
660 }
661
662 /* Parse the manifest, given its artifact ID. Panic on failure. */
663 if( !(pManifest = manifest_get(vid, CFTYPE_MANIFEST, 0)) ){
664 if( zRevision ){
665 fossil_fatal("could not parse manifest for check-in: %s", zRevision);
666 }else{
667 fossil_fatal("could not parse manifest for current checkout");
668 }
669 }
670
671 /* Return the manifest pointer. The caller must use manifest_destroy() to
672 * clean up when finished using the manifest. */
673 return pManifest;
674 }
675
676 /*
677 ** Get the contents of a file within the check-in "zRevision". If
678 ** zRevision==NULL then get the file content for the current checkout.
679 */
680 int historical_blob(
681 const char *zRevision, /* The check-in containing the file */
682 const char *zFile, /* Full treename of the file */
683 Blob *pBlob, /* Put the content here */
684 int fatal /* If nonzero, panic if file/artifact not found */
685 ){
686 int result = 0;
687
688 /* Get the manifest for the requested check-in version. This call unavoidably
689 * panics on failure even if fatal is not set. */
690 Manifest *pManifest = historical_manifest(zRevision);
691
692 /* Try to find the file record within the manifest. */
693 ManifestFile *pFile = manifest_file_find(pManifest, zFile);
694
695 if( !pFile ){
696 /* Process file-not-found errors. */
697 if( fatal ){
698 if( zRevision ){
699 fossil_fatal("file %s does not exist in check-in %s", zFile, zRevision);
700 }else{
701 fossil_fatal("no such file: %s", zFile);
702 }
703 }
704 }else{
705 /* Get the file's contents. */
706 result = content_get(fast_uuid_to_rid(pFile->zUuid), pBlob);
707
708 /* Process artifact-not-found errors. */
709 if( !result && fatal ){
710 if( zRevision ){
711 fossil_fatal("missing artifact %s for file %s in check-in %s",
712 pFile->zUuid, zFile, zRevision);
713 }else{
714 fossil_fatal("missing artifact %s for file %s", pFile->zUuid, zFile);
715 }
716 }
717 }
718
719 /* Deallocate the parsed manifest structure. */
720 manifest_destroy(pManifest);
721
722 /* Return 1 on success and (assuming fatal is not set) 0 if not found. */
723 return result;
724 }
725
726 /*
727 ** COMMAND: revert
728 **
729 ** Usage: %fossil revert ?-r REVISION? ?FILE ...?
@@ -712,15 +744,18 @@
744 ** -r REVISION revert given FILE(s) back to given REVISION
745 **
746 ** See also: redo, undo, update
747 */
748 void revert_cmd(void){
749 Manifest *pCoManifest; /* Manifest of current checkout */
750 Manifest *pRvManifest; /* Manifest of selected revert version */
751 ManifestFile *pCoFile; /* File within current checkout manifest */
752 ManifestFile *pRvFile; /* File within revert version manifest */
753 const char *zFile; /* Filename relative to checkout root */
754 const char *zRevision; /* Selected revert version, NULL if current */
755 Blob record = BLOB_INITIALIZER; /* Contents of each reverted file */
756 int i;
 
757 Stmt q;
758
759 undo_capture_command_line();
760 zRevision = find_option("revision", "r", 1);
761 verify_all_options();
@@ -730,10 +765,15 @@
765 }
766 if( zRevision && g.argc<3 ){
767 fossil_fatal("the --revision option does not work for the entire tree");
768 }
769 db_must_be_within_tree();
770
771 /* Get manifests of revert version and (if different) current checkout. */
772 pRvManifest = historical_manifest(zRevision);
773 pCoManifest = zRevision ? historical_manifest(0) : 0;
774
775 db_begin_transaction();
776 undo_begin();
777 db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);");
778
779 if( g.argc>2 ){
@@ -775,18 +815,15 @@
815 if( zRevision==0 ){
816 int vid = db_lget_int("checkout", 0);
817 zRevision = db_text(0, "SELECT uuid FROM blob WHERE rid=%d", vid);
818 }
819 while( db_step(&q)==SQLITE_ROW ){
 
 
820 char *zFull;
821 zFile = db_column_text(&q, 0);
822 zFull = mprintf("%/%/", g.zLocalRoot, zFile);
823 pRvFile = manifest_file_find(pRvManifest, zFile);
824 if( !pRvFile ){
 
825 if( db_int(0, "SELECT rid FROM vfile WHERE pathname=%Q OR origname=%Q",
826 zFile, zFile)==0 ){
827 fossil_print("UNMANAGE %s\n", zFile);
828 }else{
829 undo_save(zFile);
@@ -800,31 +837,47 @@
837 "DELETE FROM vfile WHERE pathname=%Q",
838 zFile, zFile
839 );
840 }else{
841 sqlite3_int64 mtime;
842 int rvChnged = 0;
843 int rvPerm = manifest_file_mperm(pRvFile);
844
845 /* Determine if reverted-to file is different than checked out file. */
846 if( pCoManifest && (pCoFile = manifest_file_find(pCoManifest, zFile)) ){
847 rvChnged = manifest_file_mperm(pRvFile)!=rvPerm
848 || fossil_strcmp(pRvFile->zUuid, pCoFile->zUuid)!=0;
849 }
850
851 /* Get contents of reverted-to file. */
852 content_get(fast_uuid_to_rid(pRvFile->zUuid), &record);
853
854 undo_save(zFile);
855 if( file_wd_size(zFull)>=0 && (rvPerm==PERM_LNK || file_wd_islink(0)) ){
856 file_delete(zFull);
857 }
858 if( rvPerm==PERM_LNK ){
859 symlink_create(blob_str(&record), zFull);
860 }else{
861 blob_write_to_file(&record, zFull);
862 }
863 file_wd_setexe(zFull, rvPerm==PERM_EXE);
864 fossil_print("REVERT %s\n", zFile);
865 mtime = file_wd_mtime(zFull);
866 db_multi_exec(
867 "UPDATE vfile"
868 " SET mtime=%lld, chnged=%d, deleted=0, isexe=%d, islink=%d,mrid=rid"
869 " WHERE pathname=%Q OR origname=%Q",
870 mtime, rvChnged, rvPerm==PERM_EXE, rvPerm==PERM_LNK, zFile, zFile
871 );
872 }
873 blob_reset(&record);
874 free(zFull);
875 }
876 db_finalize(&q);
877 undo_finish();
878 db_end_transaction(0);
879
880 /* Deallocate parsed manifest structures. */
881 manifest_destroy(pRvManifest);
882 manifest_destroy(pCoManifest);
883 }
884

Keyboard Shortcuts

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