@@ -197,6 +197,10 @@ pub fn message(m: &str) -> Filter {
197197 to_filter ( Op :: Message ( m. to_string ( ) ) )
198198}
199199
200+ pub fn hook ( h : & str ) -> Filter {
201+ to_filter ( Op :: Hook ( h. to_string ( ) ) )
202+ }
203+
200204pub fn squash ( ids : Option < & [ ( git2:: Oid , Filter ) ] > ) -> Filter {
201205 if let Some ( ids) = ids {
202206 to_filter ( Op :: Squash ( Some (
@@ -276,6 +280,8 @@ enum Op {
276280
277281 RegexReplace ( Vec < ( regex:: Regex , String ) > ) ,
278282
283+ Hook ( String ) ,
284+
279285 Index ,
280286 Invert ,
281287
@@ -388,6 +394,7 @@ fn nesting2(op: &Op) -> usize {
388394 Op :: Compose ( filters) => 1 + filters. iter ( ) . map ( |f| nesting ( * f) ) . fold ( 0 , |a, b| a. max ( b) ) ,
389395 Op :: Exclude ( filter) => 1 + nesting ( * filter) ,
390396 Op :: Workspace ( _) => usize:: MAX / 2 , // divide by 2 to make sure there is enough headroom to avoid overflows
397+ Op :: Hook ( _) => usize:: MAX / 2 , // divide by 2 to make sure there is enough headroom to avoid overflows
391398 Op :: Chain ( a, b) => 1 + nesting ( * a) . max ( nesting ( * b) ) ,
392399 Op :: Subtract ( a, b) => 1 + nesting ( * a) . max ( nesting ( * b) ) ,
393400 Op :: Rev ( filters) => {
@@ -629,6 +636,9 @@ fn spec2(op: &Op) -> String {
629636 Op :: Message ( m) => {
630637 format ! ( ":{}" , parse:: quote( m) )
631638 }
639+ Op :: Hook ( hook) => {
640+ format ! ( ":hook={}" , parse:: quote( hook) )
641+ }
632642 }
633643}
634644
@@ -1063,6 +1073,53 @@ fn apply_to_commit2(
10631073 let filtered_tree = repo. find_tree ( filtered_tree) ?;
10641074 Apply :: from_commit ( commit) ?. with_tree ( filtered_tree)
10651075 }
1076+ Op :: Hook ( hook) => {
1077+ let commit_filter = transaction. lookup_filter_hook ( & hook, commit. id ( ) ) ?;
1078+ let normal_parents = commit
1079+ . parent_ids ( )
1080+ . map ( |x| transaction. get ( filter, x) )
1081+ . collect :: < Option < Vec < _ > > > ( ) ;
1082+ let normal_parents = some_or ! ( normal_parents, { return Ok ( None ) } ) ;
1083+
1084+ // Compute the difference between the current commit's filter and each parent's filter.
1085+ // This determines what new content should be contributed by that parent in the filtered history.
1086+ let extra_parents = commit
1087+ . parents ( )
1088+ . map ( |parent| {
1089+ rs_tracing:: trace_scoped!( "hook parent" , "id" : parent. id( ) . to_string( ) ) ;
1090+
1091+ let pcw = transaction. lookup_filter_hook ( & hook, parent. id ( ) ) ?;
1092+ let f = opt:: optimize ( to_filter ( Op :: Subtract ( commit_filter, pcw) ) ) ;
1093+
1094+ let r = apply_to_commit2 ( & to_op ( f) , & parent, transaction) ;
1095+ r
1096+ } )
1097+ . collect :: < JoshResult < Option < Vec < _ > > > > ( ) ?;
1098+
1099+ let extra_parents = some_or ! ( extra_parents, { return Ok ( None ) } ) ;
1100+
1101+ let extra_parents: Vec < _ > = extra_parents
1102+ . into_iter ( )
1103+ . filter ( |& oid| oid != git2:: Oid :: zero ( ) )
1104+ . collect ( ) ;
1105+
1106+ let filtered_parent_ids: Vec < _ > =
1107+ normal_parents. into_iter ( ) . chain ( extra_parents) . collect ( ) ;
1108+
1109+ let tree_data = apply (
1110+ transaction,
1111+ commit_filter,
1112+ Apply :: from_commit ( commit) ?. with_parents ( filtered_parent_ids. clone ( ) ) ,
1113+ ) ?;
1114+ return Some ( history:: create_filtered_commit (
1115+ commit,
1116+ filtered_parent_ids,
1117+ tree_data,
1118+ transaction,
1119+ filter,
1120+ ) )
1121+ . transpose ( ) ;
1122+ }
10661123 _ => {
10671124 let filtered_parent_ids = commit
10681125 . parent_ids ( )
@@ -1238,6 +1295,7 @@ fn apply2<'a>(transaction: &'a cache::Transaction, op: &Op, x: Apply<'a>) -> Jos
12381295 Op :: Chain ( a, b) => {
12391296 return apply ( transaction, * b, apply ( transaction, * a, x. clone ( ) ) ?) ;
12401297 }
1298+ Op :: Hook ( _) => Err ( josh_error ( "not applicable to tree" ) ) ,
12411299 }
12421300}
12431301
0 commit comments