@@ -98,6 +98,7 @@ enum Op {
9898    Fold , 
9999    Paths , 
100100    Squash ( Option < std:: collections:: HashMap < git2:: Oid ,  ( String ,  String ,  String ) > > ) , 
101+     Rev ( std:: collections:: HashMap < git2:: Oid ,  Filter > ) , 
101102    Linear , 
102103
103104    RegexReplace ( regex:: Regex ,  String ) , 
@@ -194,6 +195,13 @@ fn nesting2(op: &Op) -> usize {
194195        Op :: Workspace ( _)  => usize:: MAX , 
195196        Op :: Chain ( a,  b)  => 1  + nesting ( * a) . max ( nesting ( * b) ) , 
196197        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+         } 
197205        _ => 0 , 
198206    } 
199207} 
@@ -223,12 +231,20 @@ fn spec2(op: &Op) -> String {
223231        Op :: Exclude ( b)  => { 
224232            format ! ( ":exclude[{}]" ,  spec( * b) ) 
225233        } 
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+         } 
226242        Op :: Workspace ( path)  => { 
227243            format ! ( ":workspace={}" ,  parse:: quote( & path. to_string_lossy( ) ) ) 
228244        } 
229245        Op :: RegexReplace ( regex,  replacement)  => { 
230246            format ! ( 
231-                 ":replace={}, {}" , 
247+                 ":replace={}; {}" , 
232248                parse:: quote( & regex. to_string( ) ) , 
233249                parse:: quote( & replacement) 
234250            ) 
@@ -384,6 +400,27 @@ fn apply_to_commit2(
384400    rs_tracing:: trace_scoped!( "apply_to_commit" ,  "spec" :  spec( filter) ,  "commit" :  commit. id( ) . to_string( ) ) ; 
385401
386402    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+         } 
387424        Op :: Squash ( Some ( ids) )  => { 
388425            if  let  Some ( _)  = ids. get ( & commit. id ( ) )  { 
389426                commit. tree ( ) ?
@@ -619,7 +656,7 @@ fn apply2<'a>(
619656        Op :: Squash ( None )  => Ok ( tree) , 
620657        Op :: Squash ( Some ( _) )  => Err ( josh_error ( "not applicable to tree" ) ) , 
621658        Op :: Linear  => Ok ( tree) , 
622- 
659+          Op :: Rev ( _ )  =>  Err ( josh_error ( "not applicable to tree" ) ) , 
623660        Op :: RegexReplace ( regex,  replacement)  => { 
624661            tree:: regex_replace ( tree. id ( ) ,  & regex,  & replacement,  transaction) 
625662        } 
@@ -712,7 +749,11 @@ pub fn unapply<'a>(
712749    parent_tree :  git2:: Tree < ' a > , 
713750)  -> JoshResult < git2:: Tree < ' a > >  { 
714751    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+         ) ?; 
716757        let  stripped = tree:: subtract ( transaction,  parent_tree. id ( ) ,  matching. id ( ) ) ?; 
717758        let  new_tree = apply ( transaction,  inverted,  tree) ?; 
718759
@@ -733,7 +774,8 @@ pub fn unapply<'a>(
733774    } 
734775
735776    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 ( ) ) ?; 
737779        return  unapply ( 
738780            transaction, 
739781            a, 
0 commit comments