@@ -41,8 +41,14 @@ fn make_app() -> clap::Command<'static> {
4141 )
4242 . arg (
4343 clap:: Arg :: new ( "squash" )
44- . help ( "Only output one commit, without history" )
45- . long ( "squash" ) ,
44+ . help ( "Produce a history that contains only commits pointed to by references mathing the given pattern" )
45+ . long ( "squash" )
46+ . takes_value ( true ) ,
47+ )
48+ . arg (
49+ clap:: Arg :: new ( "single" )
50+ . help ( "Produce a history that contains only one single commit" )
51+ . long ( "single" ) ,
4652 )
4753 . arg (
4854 clap:: Arg :: new ( "discover" )
@@ -148,10 +154,6 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
148154
149155 let mut filterobj = josh:: filter:: parse ( & specstr) ?;
150156
151- if args. is_present ( "squash" ) {
152- filterobj = josh:: filter:: chain ( josh:: filter:: parse ( ":SQUASH" ) ?, filterobj) ;
153- }
154-
155157 if args. is_present ( "print-filter" ) {
156158 let filterobj = if args. is_present ( "reverse" ) {
157159 josh:: filter:: invert ( filterobj) ?
@@ -172,6 +174,31 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
172174 let transaction = josh:: cache:: Transaction :: new ( repo, None ) ;
173175 let repo = transaction. repo ( ) ;
174176
177+ let input_ref = args. value_of ( "input" ) . unwrap ( ) ;
178+
179+ let mut refs = vec ! [ ] ;
180+ let mut ids = vec ! [ ] ;
181+
182+ let reference = repo. resolve_reference_from_short_name ( input_ref) . unwrap ( ) ;
183+ let input_ref = reference. name ( ) . unwrap ( ) . to_string ( ) ;
184+ refs. push ( ( input_ref. clone ( ) , reference. target ( ) . unwrap ( ) ) ) ;
185+
186+ if args. is_present ( "single" ) {
187+ filterobj = josh:: filter:: chain ( josh:: filter:: squash ( None ) , filterobj) ;
188+ }
189+
190+ if let Some ( pattern) = args. value_of ( "squash" ) {
191+ let pattern = pattern. to_string ( ) ;
192+ for reference in repo. references_glob ( & pattern) . unwrap ( ) {
193+ let reference = reference?;
194+ if let Some ( target) = reference. target ( ) {
195+ ids. push ( ( target, reference. name ( ) . unwrap ( ) . to_string ( ) ) ) ;
196+ refs. push ( ( reference. name ( ) . unwrap ( ) . to_string ( ) , target) ) ;
197+ }
198+ }
199+ filterobj = josh:: filter:: chain ( josh:: filter:: squash ( Some ( & ids) ) , filterobj) ;
200+ } ;
201+
175202 let odb = repo. odb ( ) ?;
176203 let mp = if args. is_present ( "pack" ) {
177204 let mempack = odb. add_new_mempack_backend ( 1000 ) ?;
@@ -198,10 +225,8 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
198225 }
199226 } ) ;
200227
201- let input_ref = args. value_of ( "input" ) . unwrap ( ) ;
202-
203228 if args. is_present ( "discover" ) {
204- let r = repo. revparse_single ( input_ref) ?;
229+ let r = repo. revparse_single ( & input_ref) ?;
205230 let hs = josh:: housekeeping:: find_all_workspaces_and_subdirectories ( & r. peel_to_tree ( ) ?) ?;
206231 for i in hs {
207232 if i. contains ( ":workspace=" ) {
@@ -220,23 +245,10 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
220245
221246 let update_target = args. value_of ( "update" ) . unwrap ( ) ;
222247
223- let src = input_ref;
224248 let target = update_target;
225249
226250 let reverse = args. is_present ( "reverse" ) ;
227251
228- let t = if reverse {
229- "refs/JOSH_TMP" . to_owned ( )
230- } else {
231- target. to_string ( )
232- } ;
233- let src_r = repo
234- . revparse_ext ( src) ?
235- . 1
236- . ok_or ( josh:: josh_error ( "reference not found" ) ) ?;
237-
238- let src = src_r. name ( ) . unwrap ( ) . to_string ( ) ;
239-
240252 let check_permissions = args. is_present ( "check-permission" ) ;
241253 let mut permissions_filter = josh:: filter:: empty ( ) ;
242254 if check_permissions {
@@ -274,28 +286,31 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
274286 permissions_filter = josh:: filter:: empty ( ) ;
275287 }
276288
277- let old_oid = if let Ok ( id) = transaction. repo ( ) . refname_to_id ( & t ) {
289+ let old_oid = if let Ok ( id) = transaction. repo ( ) . refname_to_id ( & target ) {
278290 id
279291 } else {
280292 git2:: Oid :: zero ( )
281293 } ;
282- let mut updated_refs = josh:: filter_refs (
283- & transaction,
284- filterobj,
285- & [ ( src. clone ( ) , src_r. target ( ) . unwrap ( ) ) ] ,
286- permissions_filter,
287- ) ?;
288- updated_refs[ 0 ] . 0 = t;
289- josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
290- if args. value_of ( "update" ) != Some ( "FILTERED_HEAD" )
291- && updated_refs. len ( ) == 1
292- && updated_refs[ 0 ] . 1 == old_oid
293- {
294- println ! (
295- "Warning: reference {} wasn't updated" ,
296- args. value_of( "update" ) . unwrap( )
297- ) ;
294+
295+ let mut updated_refs = josh:: filter_refs ( & transaction, filterobj, & refs, permissions_filter) ?;
296+ for i in 0 ..updated_refs. len ( ) {
297+ if updated_refs[ i] . 0 == input_ref {
298+ if reverse {
299+ updated_refs[ i] . 0 = "refs/JOSH_TMP" . to_string ( ) ;
300+ } else {
301+ updated_refs[ i] . 0 = target. to_string ( ) ;
302+ }
303+ } else {
304+ updated_refs[ i] . 0 =
305+ updated_refs[ i]
306+ . 0
307+ . replacen ( "refs/heads/" , "refs/heads/filtered/" , 1 ) ;
308+ updated_refs[ i] . 0 = updated_refs[ i]
309+ . 0
310+ . replacen ( "refs/tags/" , "refs/tags/filtered/" , 1 ) ;
311+ }
298312 }
313+ josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
299314
300315 #[ cfg( feature = "search" ) ]
301316 if let Some ( searchstring) = args. value_of ( "search" ) {
@@ -334,7 +349,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
334349 if reverse {
335350 let new = repo. revparse_single ( target) . unwrap ( ) . id ( ) ;
336351 let old = repo. revparse_single ( "JOSH_TMP" ) . unwrap ( ) . id ( ) ;
337- let unfiltered_old = repo. revparse_single ( input_ref) . unwrap ( ) . id ( ) ;
352+ let unfiltered_old = repo. revparse_single ( & input_ref) . unwrap ( ) . id ( ) ;
338353
339354 match josh:: history:: unapply_filter (
340355 & transaction,
@@ -347,7 +362,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
347362 & mut None ,
348363 ) {
349364 Ok ( rewritten) => {
350- repo. reference ( & src , rewritten, true , "unapply_filter" ) ?;
365+ repo. reference ( & input_ref , rewritten, true , "unapply_filter" ) ?;
351366 }
352367 Err ( JoshError ( msg) ) => {
353368 println ! ( "{}" , msg) ;
@@ -356,6 +371,17 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
356371 }
357372 }
358373
374+ if !reverse
375+ && args. value_of ( "update" ) != Some ( "FILTERED_HEAD" )
376+ && updated_refs. len ( ) == 1
377+ && updated_refs[ 0 ] . 1 == old_oid
378+ {
379+ println ! (
380+ "Warning: reference {} wasn't updated" ,
381+ args. value_of( "update" ) . unwrap( )
382+ ) ;
383+ }
384+
359385 if let Some ( gql_query) = args. value_of ( "graphql" ) {
360386 let context = josh:: graphql:: context ( transaction. try_clone ( ) ?, transaction. try_clone ( ) ?) ;
361387 * context. allow_refs . lock ( ) ? = true ;
0 commit comments