@@ -269,7 +269,9 @@ static int expire_reflog(const char *ref, const unsigned char *sha1, int unused,
269269 int status = 0 ;
270270
271271 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
273275 * getting updated.
274276 */
275277 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
331333 return 0 ;
332334}
333335
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 )
335345{
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 ;
340370 return 0 ;
341371 }
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+ }
346410 return 0 ;
347411 }
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 ;
349460}
350461
351462static int cmd_reflog_expire (int argc , const char * * argv , const char * prefix )
352463{
353464 struct cmd_reflog_expire_cb cb ;
354465 unsigned long now = time (NULL );
355466 int i , status , do_all ;
467+ int explicit_expiry = 0 ;
356468
357469 git_config (reflog_expire_config , NULL );
358470
@@ -367,20 +479,18 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
367479 cb .expire_total = default_reflog_expire ;
368480 cb .expire_unreachable = default_reflog_expire_unreachable ;
369481
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-
376482 for (i = 1 ; i < argc ; i ++ ) {
377483 const char * arg = argv [i ];
378484 if (!strcmp (arg , "--dry-run" ) || !strcmp (arg , "-n" ))
379485 cb .dry_run = 1 ;
380- else if (!prefixcmp (arg , "--expire=" ))
486+ else if (!prefixcmp (arg , "--expire=" )) {
381487 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=" )) {
383491 cb .expire_unreachable = approxidate (arg + 21 );
492+ explicit_expiry |= EXPIRE_UNREACH ;
493+ }
384494 else if (!strcmp (arg , "--stale-fix" ))
385495 cb .stalefix = 1 ;
386496 else if (!strcmp (arg , "--rewrite" ))
@@ -400,6 +510,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
400510 else
401511 break ;
402512 }
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+ */
403519 if (cb .stalefix ) {
404520 init_revisions (& cb .revs , prefix );
405521 if (cb .verbose )
@@ -417,6 +533,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
417533 for_each_reflog (collect_reflog , & collected );
418534 for (i = 0 ; i < collected .nr ; i ++ ) {
419535 struct collected_reflog * e = collected .e [i ];
536+ set_reflog_expiry_param (& cb , explicit_expiry , e -> reflog );
420537 status |= expire_reflog (e -> reflog , e -> sha1 , 0 , & cb );
421538 free (e );
422539 }
@@ -430,6 +547,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
430547 status |= error ("%s points nowhere!" , ref );
431548 continue ;
432549 }
550+ set_reflog_expiry_param (& cb , explicit_expiry , ref );
433551 status |= expire_reflog (ref , sha1 , 0 , & cb );
434552 }
435553 return status ;
0 commit comments