Fossil

Check-in [eef34741a9]
Login

Many hyperlinks are disabled.
Use anonymous login to enable hyperlinks.

Overview
Comment:Fix 'fossil revert' to fully revert renames
Downloads: Tarball | ZIP archive
Timelines: family | ancestors | descendants | both | trunk
Files: files | file ages | folders
SHA1: eef34741a998489ca6c1e6e36a00cf588c431aba
User & Date: joel 2013-01-25 23:49:11.216
Original User & Date: Joel 2013-01-25 23:49:11.216
Context
2013-01-26
08:26
Fix revert tests 5 and 6 so they aren't carbon copies. Minor comment cleanup check-in: 1a5ac30583 user: joel tags: trunk
2013-01-25
23:49
Fix 'fossil revert' to fully revert renames check-in: eef34741a9 user: joel tags: trunk
08:53
Replaced a ..\ with $B\. check-in: 461a4d11d1 user: stephan tags: trunk
Changes
Unified Diff Ignore Whitespace Patch
Changes to src/update.c.
665
666
667
668
669
670
671



672
673
674
675
676
677
678
** COMMAND: revert
**
** Usage: %fossil revert ?-r REVISION? ?FILE ...?
**
** Revert to the current repository version of FILE, or to
** the version associated with baseline REVISION if the -r flag
** appears.



**
** Revert all files if no file name is provided.
**
** If a file is reverted accidently, it can be restored using
** the "fossil undo" command.
**
** Options:







>
>
>







665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
** COMMAND: revert
**
** Usage: %fossil revert ?-r REVISION? ?FILE ...?
**
** Revert to the current repository version of FILE, or to
** the version associated with baseline REVISION if the -r flag
** appears.
**
** If FILE was part of a rename operation, both the original file
** and the renamed file are reverted.
**
** Revert all files if no file name is provided.
**
** If a file is reverted accidently, it can be restored using
** the "fossil undo" command.
**
** Options:
704
705
706
707
708
709
710

711










712
713
714
715
716
717
718
  db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);");

  if( g.argc>2 ){
    for(i=2; i<g.argc; i++){
      Blob fname;
      zFile = mprintf("%/", g.argv[i]);
      file_tree_name(zFile, &fname, 1);

      db_multi_exec("REPLACE INTO torevert VALUES(%B)", &fname);










      blob_reset(&fname);
    }
  }else{
    int vid;
    vid = db_lget_int("checkout", 0);
    vfile_check_signature(vid, 0);
    db_multi_exec(







>
|
>
>
>
>
>
>
>
>
>
>







707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
  db_multi_exec("CREATE TEMP TABLE torevert(name UNIQUE);");

  if( g.argc>2 ){
    for(i=2; i<g.argc; i++){
      Blob fname;
      zFile = mprintf("%/", g.argv[i]);
      file_tree_name(zFile, &fname, 1);
      db_multi_exec(
        "REPLACE INTO torevert VALUES(%B);"
        "INSERT OR IGNORE INTO torevert"
        " SELECT pathname"
        "   FROM vfile"
        "  WHERE origname IN(%B)"
        " UNION ALL"
        " SELECT origname"
        "   FROM vfile"
        "  WHERE pathname IN(%B) AND origname IS NOT NULL;",
        &fname, &fname, &fname
      );
      blob_reset(&fname);
    }
  }else{
    int vid;
    vid = db_lget_int("checkout", 0);
    vfile_check_signature(vid, 0);
    db_multi_exec(
746
747
748
749
750
751
752




753


754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
                 zFile, zFile)==0 ){
        fossil_print("UNMANAGE: %s\n", zFile);
      }else{
        undo_save(zFile);
        file_delete(zFull);
        fossil_print("DELETE: %s\n", zFile);
      }




      db_multi_exec("DELETE FROM vfile WHERE pathname=%Q", zFile);


    }else{
      sqlite3_int64 mtime;
      undo_save(zFile);
      if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
        file_delete(zFull);
      }
      if( isLink ){
        symlink_create(blob_str(&record), zFull);
      }else{
        blob_write_to_file(&record, zFull);
      }
      file_wd_setexe(zFull, isExe);
      fossil_print("REVERTED: %s\n", zFile);
      mtime = file_wd_mtime(zFull);
      db_multi_exec(
         "UPDATE vfile"
         "   SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid,"
         "       pathname=coalesce(origname,pathname), origname=NULL"     
         " WHERE pathname=%Q",
         mtime, isExe, isLink, zFile
      );
    }
    blob_reset(&record);
    free(zFull);
  }
  db_finalize(&q);
  undo_finish();
  db_end_transaction(0);
}







>
>
>
>
|
>
>
















|
<
|
|









760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790

791
792
793
794
795
796
797
798
799
800
801
                 zFile, zFile)==0 ){
        fossil_print("UNMANAGE: %s\n", zFile);
      }else{
        undo_save(zFile);
        file_delete(zFull);
        fossil_print("DELETE: %s\n", zFile);
      }
      db_multi_exec(
        "UPDATE vfile"
        "   SET pathname=origname, origname=NULL"
        " WHERE pathname=%Q AND origname!=pathname AND origname IS NOT NULL;"
        "DELETE FROM vfile WHERE pathname=%Q",
        zFile, zFile
      );
    }else{
      sqlite3_int64 mtime;
      undo_save(zFile);
      if( file_wd_size(zFull)>=0 && (isLink || file_wd_islink(zFull)) ){
        file_delete(zFull);
      }
      if( isLink ){
        symlink_create(blob_str(&record), zFull);
      }else{
        blob_write_to_file(&record, zFull);
      }
      file_wd_setexe(zFull, isExe);
      fossil_print("REVERTED: %s\n", zFile);
      mtime = file_wd_mtime(zFull);
      db_multi_exec(
         "UPDATE vfile"
         "   SET mtime=%lld, chnged=0, deleted=0, isexe=%d, islink=%d,mrid=rid"

         " WHERE pathname=%Q OR origname=%Q",
         mtime, isExe, isLink, zFile, zFile
      );
    }
    blob_reset(&record);
    free(zFull);
  }
  db_finalize(&q);
  undo_finish();
  db_end_transaction(0);
}
Added test/revert.test.
















































































































































































































































































































>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
>
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
#
# Tests for 'fossil revert'
# 
#

catch {exec $::fossilexe info} res
puts res=$res
if {![regexp {use --repository} $res]} {
  puts stderr "Cannot run this test within an open checkout"
  return
}
#
# Fossil will write data on $HOME, running 'fossil new' here.
# We need not to clutter the $HOME of the test caller.
set env(HOME) [pwd]


# Normalize file status lists (like those returned by 'fossil changes')
# so they can be compared using simple string comparison
#
proc normalize-status-list {list} {
  set normalized [list]
  set matches [regexp -all -inline -line {^\s*([A-Z]+)\s+(.*)$} $list]
  foreach {_ status file} $matches {
    lappend normalized [list $status [string trim $file]]
  }
  set normalized [lsort -index 1 $normalized]
  return $normalized
}

# Test 'fossil revert' against expected results from 'fossil changes' and
# 'fossil addremove --test', as well as by verifying the existence of files
# on the file system. 'fossil undo' is called after each test
#
proc revert-test {testid args} {
  global RESULT
  set passed 1
  
  if {[llength $args] % 2} {
    set revertArgs [lindex $args 0]
    set args [lrange $args 1 end]
  } else {
    set revertArgs {}
  }
  set args [dict merge {
    -changes {} -addremove {} -exists {} -notexists {}
  } $args]
  
  fossil revert {*}$revertArgs
  
  set statusListTests [list -changes changes -addremove {addremove --test}]
  foreach {key fossilArgs} $statusListTests {
    set expected [normalize-status-list [dict get $args $key]]
    set result [normalize-status-list [fossil {*}$fossilArgs]]
    if {$result ne $expected} {
      set passed 0
      protOut "  Expected:\n    [join $expected "\n    "]"
      protOut "  Got:\n    [join $result "\n    "]"
    }
  }
  
  set fileExistsTests [list -exists 1 does -notexists 0 should]
  foreach {key expected verb} $fileExistsTests {
    foreach path [dict get $args $key] {
      if {[file exists $path] != $expected} {
        set passed 0
        protOut "  Failure: File $verb not exist: $path"
      }
    }
  }
  
  fossil undo
  test revert-$testid $passed
}

# Create the repo
#
fossil new rep.fossil
fossil open rep.fossil

# Prepare first commit
#
write_file f1 "f1"
write_file f2 "f2"
write_file f3 "f3"
fossil add f1 f2 f3
fossil commit -m "c1"

# Make changes to be reverted
#
# Add f0
write_file f0 "f0"
fossil add f0
# Remove f1
exec rm f1
fossil rm f1
# Edit f2
write_file f2 "f2.1"
# Rename f3 to f3n
exec mv f3 f3n
fossil mv f3 f3n

# Test 'fossil revert' with no arguments
#
revert-test 1 -addremove {
  ADDED f0
} -exists {f0 f1 f2 f3} -notexists f3n

# Test with a single filename argument
#
revert-test 2 f0 -changes {
  DELETED f1
  EDITED f2
  RENAMED f3n
} -addremove {
  ADDED f0
} -exists {f0 f2 f3n} -notexists f3
#
revert-test 3 f1 -changes {
  ADDED f0
  EDITED f2
  RENAMED f3n
} -exists {f0 f1 f2 f3n} -notexists f3

revert-test 4 f2 -changes {
  ADDED f0
  DELETED f1
  RENAMED f3n
} -exists {f0 f2 f3n} -notexists {f1 f3}

# Both files involved in a rename are reverted regardless of which filename
# is used as an argument to 'fossil revert'

revert-test 5 f3 -changes {
  ADDED f0
  DELETED f1
  EDITED f2
} -exists {f0 f2 f3} -notexists {f1 f3n}

revert-test 6 f3 -changes {
  ADDED f0
  DELETED f1
  EDITED f2
} -exists {f0 f2 f3} -notexists {f1 f3n}

# Test with multiple filename arguments
#
revert-test 7 {f0 f2 f3n} -changes {
  DELETED f1
} -addremove {
  ADDED f0
} -exists {f0 f2 f3} -notexists {f1 f3n}