@@ -269,7 +269,9 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
269
269
int status = 0 ;
270
270
271
271
memset (& cb , 0 , sizeof (cb ));
272
- /* we take the lock for the ref itself to prevent it from
272
+
273
+ /*
274
+ * we take the lock for the ref itself to prevent it from
273
275
* getting updated.
274
276
*/
275
277
lock = lock_any_ref_for_update (ref , sha1 , 0 );
@@ -331,28 +333,138 @@ static int collect_reflog(const char *ref, const unsigned char *sha1, int unused
331
333
return 0 ;
332
334
}
333
335
334
- static int reflog_expire_config (const char * var , const char * value , void * cb )
336
+ static struct reflog_expire_cfg {
337
+ struct reflog_expire_cfg * next ;
338
+ unsigned long expire_total ;
339
+ unsigned long expire_unreachable ;
340
+ size_t len ;
341
+ char pattern [FLEX_ARRAY ];
342
+ } * reflog_expire_cfg , * * reflog_expire_cfg_tail ;
343
+
344
+ static struct reflog_expire_cfg * find_cfg_ent (const char * pattern , size_t len )
335
345
{
336
- if (!strcmp (var , "gc.reflogexpire" )) {
337
- if (!value )
338
- config_error_nonbool (var );
339
- default_reflog_expire = approxidate (value );
346
+ struct reflog_expire_cfg * ent ;
347
+
348
+ if (!reflog_expire_cfg_tail )
349
+ reflog_expire_cfg_tail = & reflog_expire_cfg ;
350
+
351
+ for (ent = reflog_expire_cfg ; ent ; ent = ent -> next )
352
+ if (ent -> len == len &&
353
+ !memcmp (ent -> pattern , pattern , len ))
354
+ return ent ;
355
+
356
+ ent = xcalloc (1 , (sizeof (* ent ) + len ));
357
+ memcpy (ent -> pattern , pattern , len );
358
+ ent -> len = len ;
359
+ * reflog_expire_cfg_tail = ent ;
360
+ reflog_expire_cfg_tail = & (ent -> next );
361
+ return ent ;
362
+ }
363
+
364
+ static int parse_expire_cfg_value (const char * var , const char * value , unsigned long * expire )
365
+ {
366
+ if (!value )
367
+ return config_error_nonbool (var );
368
+ if (!strcmp (value , "never" ) || !strcmp (value , "false" )) {
369
+ * expire = 0 ;
340
370
return 0 ;
341
371
}
342
- if (!strcmp (var , "gc.reflogexpireunreachable" )) {
343
- if (!value )
344
- config_error_nonbool (var );
345
- default_reflog_expire_unreachable = approxidate (value );
372
+ * expire = approxidate (value );
373
+ return 0 ;
374
+ }
375
+
376
+ /* expiry timer slot */
377
+ #define EXPIRE_TOTAL 01
378
+ #define EXPIRE_UNREACH 02
379
+
380
+ static int reflog_expire_config (const char * var , const char * value , void * cb )
381
+ {
382
+ const char * lastdot = strrchr (var , '.' );
383
+ unsigned long expire ;
384
+ int slot ;
385
+ struct reflog_expire_cfg * ent ;
386
+
387
+ if (!lastdot || prefixcmp (var , "gc." ))
388
+ return git_default_config (var , value , cb );
389
+
390
+ if (!strcmp (lastdot , ".reflogexpire" )) {
391
+ slot = EXPIRE_TOTAL ;
392
+ if (parse_expire_cfg_value (var , value , & expire ))
393
+ return -1 ;
394
+ } else if (!strcmp (lastdot , ".reflogexpireunreachable" )) {
395
+ slot = EXPIRE_UNREACH ;
396
+ if (parse_expire_cfg_value (var , value , & expire ))
397
+ return -1 ;
398
+ } else
399
+ return git_default_config (var , value , cb );
400
+
401
+ if (lastdot == var + 2 ) {
402
+ switch (slot ) {
403
+ case EXPIRE_TOTAL :
404
+ default_reflog_expire = expire ;
405
+ break ;
406
+ case EXPIRE_UNREACH :
407
+ default_reflog_expire_unreachable = expire ;
408
+ break ;
409
+ }
346
410
return 0 ;
347
411
}
348
- return git_default_config (var , value , cb );
412
+
413
+ ent = find_cfg_ent (var + 3 , lastdot - (var + 3 ));
414
+ if (!ent )
415
+ return -1 ;
416
+ switch (slot ) {
417
+ case EXPIRE_TOTAL :
418
+ ent -> expire_total = expire ;
419
+ break ;
420
+ case EXPIRE_UNREACH :
421
+ ent -> expire_unreachable = expire ;
422
+ break ;
423
+ }
424
+ return 0 ;
425
+ }
426
+
427
+ static void set_reflog_expiry_param (struct cmd_reflog_expire_cb * cb , int slot , const char * ref )
428
+ {
429
+ struct reflog_expire_cfg * ent ;
430
+
431
+ if (slot == (EXPIRE_TOTAL |EXPIRE_UNREACH ))
432
+ return ; /* both given explicitly -- nothing to tweak */
433
+
434
+ for (ent = reflog_expire_cfg ; ent ; ent = ent -> next ) {
435
+ if (!fnmatch (ent -> pattern , ref , 0 )) {
436
+ if (!(slot & EXPIRE_TOTAL ))
437
+ cb -> expire_total = ent -> expire_total ;
438
+ if (!(slot & EXPIRE_UNREACH ))
439
+ cb -> expire_unreachable = ent -> expire_unreachable ;
440
+ return ;
441
+ }
442
+ }
443
+
444
+ /*
445
+ * If unconfigured, make stash never expire
446
+ */
447
+ if (!strcmp (ref , "refs/stash" )) {
448
+ if (!(slot & EXPIRE_TOTAL ))
449
+ cb -> expire_total = 0 ;
450
+ if (!(slot & EXPIRE_UNREACH ))
451
+ cb -> expire_unreachable = 0 ;
452
+ return ;
453
+ }
454
+
455
+ /* Nothing matched -- use the default value */
456
+ if (!(slot & EXPIRE_TOTAL ))
457
+ cb -> expire_total = default_reflog_expire ;
458
+ if (!(slot & EXPIRE_UNREACH ))
459
+ cb -> expire_unreachable = default_reflog_expire_unreachable ;
349
460
}
350
461
351
462
static int cmd_reflog_expire (int argc , const char * * argv , const char * prefix )
352
463
{
353
464
struct cmd_reflog_expire_cb cb ;
354
465
unsigned long now = time (NULL );
355
466
int i , status , do_all ;
467
+ int explicit_expiry = 0 ;
356
468
357
469
git_config (reflog_expire_config , NULL );
358
470
@@ -367,20 +479,18 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
367
479
cb .expire_total = default_reflog_expire ;
368
480
cb .expire_unreachable = default_reflog_expire_unreachable ;
369
481
370
- /*
371
- * We can trust the commits and objects reachable from refs
372
- * even in older repository. We cannot trust what's reachable
373
- * from reflog if the repository was pruned with older git.
374
- */
375
-
376
482
for (i = 1 ; i < argc ; i ++ ) {
377
483
const char * arg = argv [i ];
378
484
if (!strcmp (arg , "--dry-run" ) || !strcmp (arg , "-n" ))
379
485
cb .dry_run = 1 ;
380
- else if (!prefixcmp (arg , "--expire=" ))
486
+ else if (!prefixcmp (arg , "--expire=" )) {
381
487
cb .expire_total = approxidate (arg + 9 );
382
- else if (!prefixcmp (arg , "--expire-unreachable=" ))
488
+ explicit_expiry |= EXPIRE_TOTAL ;
489
+ }
490
+ else if (!prefixcmp (arg , "--expire-unreachable=" )) {
383
491
cb .expire_unreachable = approxidate (arg + 21 );
492
+ explicit_expiry |= EXPIRE_UNREACH ;
493
+ }
384
494
else if (!strcmp (arg , "--stale-fix" ))
385
495
cb .stalefix = 1 ;
386
496
else if (!strcmp (arg , "--rewrite" ))
@@ -400,6 +510,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
400
510
else
401
511
break ;
402
512
}
513
+
514
+ /*
515
+ * We can trust the commits and objects reachable from refs
516
+ * even in older repository. We cannot trust what's reachable
517
+ * from reflog if the repository was pruned with older git.
518
+ */
403
519
if (cb .stalefix ) {
404
520
init_revisions (& cb .revs , prefix );
405
521
if (cb .verbose )
@@ -417,6 +533,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
417
533
for_each_reflog (collect_reflog , & collected );
418
534
for (i = 0 ; i < collected .nr ; i ++ ) {
419
535
struct collected_reflog * e = collected .e [i ];
536
+ set_reflog_expiry_param (& cb , explicit_expiry , e -> reflog );
420
537
status |= expire_reflog (e -> reflog , e -> sha1 , 0 , & cb );
421
538
free (e );
422
539
}
@@ -430,6 +547,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
430
547
status |= error ("%s points nowhere!" , ref );
431
548
continue ;
432
549
}
550
+ set_reflog_expiry_param (& cb , explicit_expiry , ref );
433
551
status |= expire_reflog (ref , sha1 , 0 , & cb );
434
552
}
435
553
return status ;
0 commit comments