@@ -98,6 +98,7 @@ enum Op {
98
98
Fold ,
99
99
Paths ,
100
100
Squash ( Option < std:: collections:: HashMap < git2:: Oid , ( String , String , String ) > > ) ,
101
+ Rev ( std:: collections:: HashMap < git2:: Oid , Filter > ) ,
101
102
Linear ,
102
103
103
104
RegexReplace ( regex:: Regex , String ) ,
@@ -194,6 +195,13 @@ fn nesting2(op: &Op) -> usize {
194
195
Op :: Workspace ( _) => usize:: MAX ,
195
196
Op :: Chain ( a, b) => 1 + nesting ( * a) . max ( nesting ( * b) ) ,
196
197
Op :: Subtract ( a, b) => 1 + nesting ( * a) . max ( nesting ( * b) ) ,
198
+ Op :: Rev ( filters) => {
199
+ 1 + filters
200
+ . values ( )
201
+ . map ( |filter| nesting ( * filter) )
202
+ . max ( )
203
+ . unwrap_or ( 0 )
204
+ }
197
205
_ => 0 ,
198
206
}
199
207
}
@@ -223,12 +231,20 @@ fn spec2(op: &Op) -> String {
223
231
Op :: Exclude ( b) => {
224
232
format ! ( ":exclude[{}]" , spec( * b) )
225
233
}
234
+ Op :: Rev ( filters) => {
235
+ let mut v = filters
236
+ . iter ( )
237
+ . map ( |( k, v) | format ! ( "{}{}" , k, spec( * v) ) )
238
+ . collect :: < Vec < _ > > ( ) ;
239
+ v. sort ( ) ;
240
+ format ! ( ":rev({})" , v. join( "," ) )
241
+ }
226
242
Op :: Workspace ( path) => {
227
243
format ! ( ":workspace={}" , parse:: quote( & path. to_string_lossy( ) ) )
228
244
}
229
245
Op :: RegexReplace ( regex, replacement) => {
230
246
format ! (
231
- ":replace={}, {}" ,
247
+ ":replace={}; {}" ,
232
248
parse:: quote( & regex. to_string( ) ) ,
233
249
parse:: quote( & replacement)
234
250
)
@@ -384,6 +400,27 @@ fn apply_to_commit2(
384
400
rs_tracing:: trace_scoped!( "apply_to_commit" , "spec" : spec( filter) , "commit" : commit. id( ) . to_string( ) ) ;
385
401
386
402
let filtered_tree = match & to_op ( filter) {
403
+ Op :: Rev ( filters) => {
404
+ let nf = * filters
405
+ . get ( & git2:: Oid :: zero ( ) )
406
+ . unwrap_or ( & to_filter ( Op :: Nop ) ) ;
407
+
408
+ for ( id, startfilter) in filters {
409
+ if * id == commit. id ( ) {
410
+ let mut f2 = filters. clone ( ) ;
411
+ f2. remove ( id) ;
412
+ f2. insert ( git2:: Oid :: zero ( ) , * startfilter) ;
413
+ if let Some ( start) = apply_to_commit2 ( & Op :: Rev ( f2) , & commit, transaction) ? {
414
+ transaction. insert ( filter, commit. id ( ) , start, true ) ;
415
+ return Ok ( Some ( start) ) ;
416
+ } else {
417
+ return Ok ( None ) ;
418
+ }
419
+ }
420
+ }
421
+
422
+ apply ( transaction, nf, commit. tree ( ) ?) ?
423
+ }
387
424
Op :: Squash ( Some ( ids) ) => {
388
425
if let Some ( _) = ids. get ( & commit. id ( ) ) {
389
426
commit. tree ( ) ?
@@ -619,7 +656,7 @@ fn apply2<'a>(
619
656
Op :: Squash ( None ) => Ok ( tree) ,
620
657
Op :: Squash ( Some ( _) ) => Err ( josh_error ( "not applicable to tree" ) ) ,
621
658
Op :: Linear => Ok ( tree) ,
622
-
659
+ Op :: Rev ( _ ) => Err ( josh_error ( "not applicable to tree" ) ) ,
623
660
Op :: RegexReplace ( regex, replacement) => {
624
661
tree:: regex_replace ( tree. id ( ) , & regex, & replacement, transaction)
625
662
}
@@ -712,7 +749,11 @@ pub fn unapply<'a>(
712
749
parent_tree : git2:: Tree < ' a > ,
713
750
) -> JoshResult < git2:: Tree < ' a > > {
714
751
if let Ok ( inverted) = invert ( filter) {
715
- let matching = apply ( transaction, chain ( filter, inverted) , parent_tree. clone ( ) ) ?;
752
+ let matching = apply (
753
+ transaction,
754
+ chain ( invert ( inverted) ?, inverted) ,
755
+ parent_tree. clone ( ) ,
756
+ ) ?;
716
757
let stripped = tree:: subtract ( transaction, parent_tree. id ( ) , matching. id ( ) ) ?;
717
758
let new_tree = apply ( transaction, inverted, tree) ?;
718
759
@@ -733,7 +774,8 @@ pub fn unapply<'a>(
733
774
}
734
775
735
776
if let Op :: Chain ( a, b) = to_op ( filter) {
736
- let p = apply ( transaction, a, parent_tree. clone ( ) ) ?;
777
+ let i = if let Ok ( i) = invert ( a) { invert ( i) ? } else { a } ;
778
+ let p = apply ( transaction, i, parent_tree. clone ( ) ) ?;
737
779
return unapply (
738
780
transaction,
739
781
a,
0 commit comments