@@ -37,9 +37,24 @@ fn make_app() -> clap::Command {
37
37
)
38
38
. arg (
39
39
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" )
40
55
. 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 " ) ,
43
58
)
44
59
. arg (
45
60
clap:: Arg :: new ( "discover" )
@@ -138,10 +153,6 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
138
153
139
154
let mut filterobj = josh:: filter:: parse ( & specstr) ?;
140
155
141
- if args. get_flag ( "squash" ) {
142
- filterobj = josh:: filter:: chain ( josh:: filter:: parse ( ":SQUASH" ) ?, filterobj) ;
143
- }
144
-
145
156
if args. get_flag ( "print-filter" ) {
146
157
let filterobj = if args. get_flag ( "reverse" ) {
147
158
josh:: filter:: invert ( filterobj) ?
@@ -162,6 +173,38 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
162
173
let transaction = josh:: cache:: Transaction :: new ( repo, None ) ;
163
174
let repo = transaction. repo ( ) ;
164
175
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
+
165
208
let odb = repo. odb ( ) ?;
166
209
let mp = if args. get_flag ( "pack" ) {
167
210
let mempack = odb. add_new_mempack_backend ( 1000 ) ?;
@@ -188,10 +231,8 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
188
231
}
189
232
} ) ;
190
233
191
- let input_ref = args. get_one :: < String > ( "input" ) . unwrap ( ) ;
192
-
193
234
if args. get_flag ( "discover" ) {
194
- let r = repo. revparse_single ( input_ref) ?;
235
+ let r = repo. revparse_single ( & input_ref) ?;
195
236
let hs = josh:: housekeeping:: find_all_workspaces_and_subdirectories ( & r. peel_to_tree ( ) ?) ?;
196
237
for i in hs {
197
238
if i. contains ( ":workspace=" ) {
@@ -210,23 +251,10 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
210
251
211
252
let update_target = args. get_one :: < String > ( "update" ) . unwrap ( ) ;
212
253
213
- let src = input_ref;
214
254
let target = update_target;
215
255
216
256
let reverse = args. get_flag ( "reverse" ) ;
217
257
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
-
230
258
let check_permissions = args. get_flag ( "check-permission" ) ;
231
259
let mut permissions_filter = josh:: filter:: empty ( ) ;
232
260
if check_permissions {
@@ -264,28 +292,31 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
264
292
permissions_filter = josh:: filter:: empty ( ) ;
265
293
}
266
294
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 ) {
268
296
id
269
297
} else {
270
298
git2:: Oid :: zero ( )
271
299
} ;
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
+ }
288
318
}
319
+ josh:: update_refs ( & transaction, & mut updated_refs, "" ) ;
289
320
290
321
#[ cfg( feature = "search" ) ]
291
322
if let Some ( searchstring) = args. get_one :: < String > ( "search" ) {
@@ -324,7 +355,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
324
355
if reverse {
325
356
let new = repo. revparse_single ( target) . unwrap ( ) . id ( ) ;
326
357
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 ( ) ;
328
359
329
360
match josh:: history:: unapply_filter (
330
361
& transaction,
@@ -337,7 +368,7 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
337
368
& mut None ,
338
369
) {
339
370
Ok ( rewritten) => {
340
- repo. reference ( & src , rewritten, true , "unapply_filter" ) ?;
371
+ repo. reference ( & input_ref , rewritten, true , "unapply_filter" ) ?;
341
372
}
342
373
Err ( JoshError ( msg) ) => {
343
374
println ! ( "{}" , msg) ;
@@ -346,6 +377,17 @@ fn run_filter(args: Vec<String>) -> josh::JoshResult<i32> {
346
377
}
347
378
}
348
379
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
+
349
391
if let Some ( gql_query) = args. get_one :: < String > ( "graphql" ) {
350
392
let context = josh:: graphql:: context ( transaction. try_clone ( ) ?, transaction. try_clone ( ) ?) ;
351
393
* context. allow_refs . lock ( ) ? = true ;
0 commit comments