@@ -41,8 +41,14 @@ fn make_app() -> clap::Command<'static> {
41
41
)
42
42
. arg (
43
43
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 matching 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" ) ,
46
52
)
47
53
. arg (
48
54
clap:: Arg :: new ( "discover" )
@@ -152,10 +158,6 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
152
158
153
159
let mut filterobj = josh:: filter:: parse ( & specstr) ?;
154
160
155
- if args. is_present ( "squash" ) {
156
- filterobj = josh:: filter:: chain ( josh:: filter:: parse ( ":SQUASH" ) ?, filterobj) ;
157
- }
158
-
159
161
if args. is_present ( "print-filter" ) {
160
162
let filterobj = if args. is_present ( "reverse" ) {
161
163
josh:: filter:: invert ( filterobj) ?
@@ -176,6 +178,31 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
176
178
let transaction = josh:: cache:: Transaction :: new ( repo, None ) ;
177
179
let repo = transaction. repo ( ) ;
178
180
181
+ let input_ref = args. value_of ( "input" ) . unwrap ( ) ;
182
+
183
+ let mut refs = vec ! [ ] ;
184
+ let mut ids = vec ! [ ] ;
185
+
186
+ let reference = repo. resolve_reference_from_short_name ( input_ref) . unwrap ( ) ;
187
+ let input_ref = reference. name ( ) . unwrap ( ) . to_string ( ) ;
188
+ refs. push ( ( input_ref. clone ( ) , reference. target ( ) . unwrap ( ) ) ) ;
189
+
190
+ if args. is_present ( "single" ) {
191
+ filterobj = josh:: filter:: chain ( josh:: filter:: squash ( None ) , filterobj) ;
192
+ }
193
+
194
+ if let Some ( pattern) = args. value_of ( "squash" ) {
195
+ let pattern = pattern. to_string ( ) ;
196
+ for reference in repo. references_glob ( & pattern) . unwrap ( ) {
197
+ let reference = reference?;
198
+ if let Some ( target) = reference. target ( ) {
199
+ ids. push ( ( target, reference. name ( ) . unwrap ( ) . to_string ( ) ) ) ;
200
+ refs. push ( ( reference. name ( ) . unwrap ( ) . to_string ( ) , target) ) ;
201
+ }
202
+ }
203
+ filterobj = josh:: filter:: chain ( josh:: filter:: squash ( Some ( & ids) ) , filterobj) ;
204
+ } ;
205
+
179
206
let odb = repo. odb ( ) ?;
180
207
let mp = if args. is_present ( "pack" ) {
181
208
let mempack = odb. add_new_mempack_backend ( 1000 ) ?;
@@ -202,10 +229,8 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
202
229
}
203
230
} ) ;
204
231
205
- let input_ref = args. value_of ( "input" ) . unwrap ( ) ;
206
-
207
232
if args. is_present ( "discover" ) {
208
- let r = repo. revparse_single ( input_ref) ?;
233
+ let r = repo. revparse_single ( & input_ref) ?;
209
234
let hs = josh:: housekeeping:: find_all_workspaces_and_subdirectories ( & r. peel_to_tree ( ) ?) ?;
210
235
for i in hs {
211
236
if i. contains ( ":workspace=" ) {
@@ -224,23 +249,10 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
224
249
225
250
let update_target = args. value_of ( "update" ) . unwrap ( ) ;
226
251
227
- let src = input_ref;
228
252
let target = update_target;
229
253
230
254
let reverse = args. is_present ( "reverse" ) ;
231
255
232
- let t = if reverse {
233
- "refs/JOSH_TMP" . to_owned ( )
234
- } else {
235
- target. to_string ( )
236
- } ;
237
- let src_r = repo
238
- . revparse_ext ( src) ?
239
- . 1
240
- . ok_or ( josh:: josh_error ( "reference not found" ) ) ?;
241
-
242
- let src = src_r. name ( ) . unwrap ( ) . to_string ( ) ;
243
-
244
256
let check_permissions = args. is_present ( "check-permission" ) ;
245
257
let mut permissions_filter = josh:: filter:: empty ( ) ;
246
258
if check_permissions {
@@ -278,28 +290,31 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
278
290
permissions_filter = josh:: filter:: empty ( ) ;
279
291
}
280
292
281
- let old_oid = if let Ok ( id) = transaction. repo ( ) . refname_to_id ( & t ) {
293
+ let old_oid = if let Ok ( id) = transaction. repo ( ) . refname_to_id ( & target ) {
282
294
id
283
295
} else {
284
296
git2:: Oid :: zero ( )
285
297
} ;
286
- let mut updated_refs = josh:: filter_refs (
287
- & transaction,
288
- filterobj,
289
- & [ ( src. clone ( ) , src_r. target ( ) . unwrap ( ) ) ] ,
290
- permissions_filter,
291
- ) ?;
292
- updated_refs[ 0 ] . 0 = t;
293
- josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
294
- if args. value_of ( "update" ) != Some ( "FILTERED_HEAD" )
295
- && updated_refs. len ( ) == 1
296
- && updated_refs[ 0 ] . 1 == old_oid
297
- {
298
- println ! (
299
- "Warning: reference {} wasn't updated" ,
300
- args. value_of( "update" ) . unwrap( )
301
- ) ;
298
+
299
+ let mut updated_refs = josh:: filter_refs ( & transaction, filterobj, & refs, permissions_filter) ?;
300
+ for i in 0 ..updated_refs. len ( ) {
301
+ if updated_refs[ i] . 0 == input_ref {
302
+ if reverse {
303
+ updated_refs[ i] . 0 = "refs/JOSH_TMP" . to_string ( ) ;
304
+ } else {
305
+ updated_refs[ i] . 0 = target. to_string ( ) ;
306
+ }
307
+ } else {
308
+ updated_refs[ i] . 0 =
309
+ updated_refs[ i]
310
+ . 0
311
+ . replacen ( "refs/heads/" , "refs/heads/filtered/" , 1 ) ;
312
+ updated_refs[ i] . 0 = updated_refs[ i]
313
+ . 0
314
+ . replacen ( "refs/tags/" , "refs/tags/filtered/" , 1 ) ;
315
+ }
302
316
}
317
+ josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
303
318
304
319
#[ cfg( feature = "search" ) ]
305
320
if let Some ( searchstring) = args. value_of ( "search" ) {
@@ -338,7 +353,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
338
353
if reverse {
339
354
let new = repo. revparse_single ( target) . unwrap ( ) . id ( ) ;
340
355
let old = repo. revparse_single ( "JOSH_TMP" ) . unwrap ( ) . id ( ) ;
341
- let unfiltered_old = repo. revparse_single ( input_ref) . unwrap ( ) . id ( ) ;
356
+ let unfiltered_old = repo. revparse_single ( & input_ref) . unwrap ( ) . id ( ) ;
342
357
343
358
match josh:: history:: unapply_filter (
344
359
& transaction,
@@ -351,7 +366,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
351
366
& mut None ,
352
367
) {
353
368
Ok ( rewritten) => {
354
- repo. reference ( & src , rewritten, true , "unapply_filter" ) ?;
369
+ repo. reference ( & input_ref , rewritten, true , "unapply_filter" ) ?;
355
370
}
356
371
Err ( JoshError ( msg) ) => {
357
372
println ! ( "{}" , msg) ;
@@ -360,6 +375,17 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
360
375
}
361
376
}
362
377
378
+ if !reverse
379
+ && args. value_of ( "update" ) != Some ( "FILTERED_HEAD" )
380
+ && updated_refs. len ( ) == 1
381
+ && updated_refs[ 0 ] . 1 == old_oid
382
+ {
383
+ println ! (
384
+ "Warning: reference {} wasn't updated" ,
385
+ args. value_of( "update" ) . unwrap( )
386
+ ) ;
387
+ }
388
+
363
389
if let Some ( gql_query) = args. value_of ( "graphql" ) {
364
390
let context = josh:: graphql:: context ( transaction. try_clone ( ) ?, transaction. try_clone ( ) ?) ;
365
391
* context. allow_refs . lock ( ) ? = true ;
0 commit comments