@@ -37,9 +37,24 @@ fn make_app() -> clap::Command {
3737 )
3838 . arg (
3939 clap:: Arg :: new ( "squash" )
40+ . help ( "Produce a history that contains only commits pointed to by references matching the given pattern" )
41+ . long ( "squash" )
42+ )
43+ . arg (
44+ clap:: Arg :: new ( "author" )
45+ . help ( "Author to use for commits with rewritten message" )
46+ . long ( "author" )
47+ )
48+ . arg (
49+ clap:: Arg :: new ( "email" )
50+ . help ( "Author email to use for commits with rewritten message" )
51+ . long ( "email" )
52+ )
53+ . arg (
54+ clap:: Arg :: new ( "single" )
4055 . action ( clap:: ArgAction :: SetTrue )
41- . help ( "Only output one commit, without history " )
42- . long ( "squash " ) ,
56+ . help ( "Produce a history that contains only one single commit " )
57+ . long ( "single " ) ,
4358 )
4459 . arg (
4560 clap:: Arg :: new ( "discover" )
@@ -138,10 +153,6 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
138153
139154 let mut filterobj = josh:: filter:: parse ( & specstr) ?;
140155
141- if args. get_flag ( "squash" ) {
142- filterobj = josh:: filter:: chain ( josh:: filter:: parse ( ":SQUASH" ) ?, filterobj) ;
143- }
144-
145156 if args. get_flag ( "print-filter" ) {
146157 let filterobj = if args. get_flag ( "reverse" ) {
147158 josh:: filter:: invert ( filterobj) ?
@@ -162,6 +173,38 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
162173 let transaction = josh:: cache:: Transaction :: new ( repo, None ) ;
163174 let repo = transaction. repo ( ) ;
164175
176+ let input_ref = args. get_one :: < String > ( "input" ) . unwrap ( ) ;
177+
178+ let mut refs = vec ! [ ] ;
179+ let mut ids = vec ! [ ] ;
180+
181+ let reference = repo. resolve_reference_from_short_name ( input_ref) . unwrap ( ) ;
182+ let input_ref = reference. name ( ) . unwrap ( ) . to_string ( ) ;
183+ refs. push ( ( input_ref. clone ( ) , reference. target ( ) . unwrap ( ) ) ) ;
184+
185+ if args. get_flag ( "single" ) {
186+ filterobj = josh:: filter:: chain ( josh:: filter:: squash ( None ) , filterobj) ;
187+ }
188+
189+ if let Some ( pattern) = args. get_one :: < String > ( "squash" ) {
190+ let pattern = pattern. to_string ( ) ;
191+ for reference in repo. references_glob ( & pattern) . unwrap ( ) {
192+ let reference = reference?;
193+ if let Some ( target) = reference. target ( ) {
194+ ids. push ( ( target, reference. name ( ) . unwrap ( ) . to_string ( ) ) ) ;
195+ refs. push ( ( reference. name ( ) . unwrap ( ) . to_string ( ) , target) ) ;
196+ }
197+ }
198+ filterobj = josh:: filter:: chain (
199+ josh:: filter:: squash ( Some ( (
200+ args. get_one :: < String > ( "author" ) . unwrap ( ) ,
201+ args. get_one :: < String > ( "email" ) . unwrap ( ) ,
202+ & ids,
203+ ) ) ) ,
204+ filterobj,
205+ ) ;
206+ } ;
207+
165208 let odb = repo. odb ( ) ?;
166209 let mp = if args. get_flag ( "pack" ) {
167210 let mempack = odb. add_new_mempack_backend ( 1000 ) ?;
@@ -188,10 +231,8 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
188231 }
189232 } ) ;
190233
191- let input_ref = args. get_one :: < String > ( "input" ) . unwrap ( ) ;
192-
193234 if args. get_flag ( "discover" ) {
194- let r = repo. revparse_single ( input_ref) ?;
235+ let r = repo. revparse_single ( & input_ref) ?;
195236 let hs = josh:: housekeeping:: find_all_workspaces_and_subdirectories ( & r. peel_to_tree ( ) ?) ?;
196237 for i in hs {
197238 if i. contains ( ":workspace=" ) {
@@ -210,23 +251,10 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
210251
211252 let update_target = args. get_one :: < String > ( "update" ) . unwrap ( ) ;
212253
213- let src = input_ref;
214254 let target = update_target;
215255
216256 let reverse = args. get_flag ( "reverse" ) ;
217257
218- let t = if reverse {
219- "refs/JOSH_TMP" . to_owned ( )
220- } else {
221- target. to_string ( )
222- } ;
223- let src_r = repo
224- . revparse_ext ( src) ?
225- . 1
226- . ok_or ( josh:: josh_error ( "reference not found" ) ) ?;
227-
228- let src = src_r. name ( ) . unwrap ( ) . to_string ( ) ;
229-
230258 let check_permissions = args. get_flag ( "check-permission" ) ;
231259 let mut permissions_filter = josh:: filter:: empty ( ) ;
232260 if check_permissions {
@@ -264,28 +292,31 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
264292 permissions_filter = josh:: filter:: empty ( ) ;
265293 }
266294
267- let old_oid = if let Ok ( id) = transaction. repo ( ) . refname_to_id ( & t ) {
295+ let old_oid = if let Ok ( id) = transaction. repo ( ) . refname_to_id ( & target ) {
268296 id
269297 } else {
270298 git2:: Oid :: zero ( )
271299 } ;
272- let mut updated_refs = josh:: filter_refs (
273- & transaction,
274- filterobj,
275- & [ ( src. clone ( ) , src_r. target ( ) . unwrap ( ) ) ] ,
276- permissions_filter,
277- ) ?;
278- updated_refs[ 0 ] . 0 = t;
279- josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
280- if args. get_one :: < String > ( "update" ) . map ( |v| v. as_str ( ) ) != Some ( "FILTERED_HEAD" )
281- && updated_refs. len ( ) == 1
282- && updated_refs[ 0 ] . 1 == old_oid
283- {
284- println ! (
285- "Warning: reference {} wasn't updated" ,
286- args. get_one:: <String >( "update" ) . unwrap( )
287- ) ;
300+
301+ let mut updated_refs = josh:: filter_refs ( & transaction, filterobj, & refs, permissions_filter) ?;
302+ for i in 0 ..updated_refs. len ( ) {
303+ if updated_refs[ i] . 0 == input_ref {
304+ if reverse {
305+ updated_refs[ i] . 0 = "refs/JOSH_TMP" . to_string ( ) ;
306+ } else {
307+ updated_refs[ i] . 0 = target. to_string ( ) ;
308+ }
309+ } else {
310+ updated_refs[ i] . 0 =
311+ updated_refs[ i]
312+ . 0
313+ . replacen ( "refs/heads/" , "refs/heads/filtered/" , 1 ) ;
314+ updated_refs[ i] . 0 = updated_refs[ i]
315+ . 0
316+ . replacen ( "refs/tags/" , "refs/tags/filtered/" , 1 ) ;
317+ }
288318 }
319+ josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
289320
290321 #[ cfg( feature = "search" ) ]
291322 if let Some ( searchstring) = args. get_one :: < String > ( "search" ) {
@@ -324,7 +355,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
324355 if reverse {
325356 let new = repo. revparse_single ( target) . unwrap ( ) . id ( ) ;
326357 let old = repo. revparse_single ( "JOSH_TMP" ) . unwrap ( ) . id ( ) ;
327- let unfiltered_old = repo. revparse_single ( input_ref) . unwrap ( ) . id ( ) ;
358+ let unfiltered_old = repo. revparse_single ( & input_ref) . unwrap ( ) . id ( ) ;
328359
329360 match josh:: history:: unapply_filter (
330361 & transaction,
@@ -337,7 +368,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
337368 & mut None ,
338369 ) {
339370 Ok ( rewritten) => {
340- repo. reference ( & src , rewritten, true , "unapply_filter" ) ?;
371+ repo. reference ( & input_ref , rewritten, true , "unapply_filter" ) ?;
341372 }
342373 Err ( JoshError ( msg) ) => {
343374 println ! ( "{}" , msg) ;
@@ -346,6 +377,17 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
346377 }
347378 }
348379
380+ if !reverse
381+ && args. get_one :: < String > ( "update" ) != Some ( & "FILTERED_HEAD" . to_string ( ) )
382+ && updated_refs. len ( ) == 1
383+ && updated_refs[ 0 ] . 1 == old_oid
384+ {
385+ println ! (
386+ "Warning: reference {} wasn't updated" ,
387+ args. get_one:: <String >( "update" ) . unwrap( )
388+ ) ;
389+ }
390+
349391 if let Some ( gql_query) = args. get_one :: < String > ( "graphql" ) {
350392 let context = josh:: graphql:: context ( transaction. try_clone ( ) ?, transaction. try_clone ( ) ?) ;
351393 * context. allow_refs . lock ( ) ? = true ;
0 commit comments