@@ -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,127 @@ 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+ /* Nothing matched -- use the default value */
445+ if (!(slot & EXPIRE_TOTAL ))
446+ cb -> expire_total = default_reflog_expire ;
447+ if (!(slot & EXPIRE_UNREACH ))
448+ cb -> expire_unreachable = default_reflog_expire_unreachable ;
349449}
350450
351451static int cmd_reflog_expire (int argc , const char * * argv , const char * prefix )
352452{
353453 struct cmd_reflog_expire_cb cb ;
354454 unsigned long now = time (NULL );
355455 int i , status , do_all ;
456+ int explicit_expiry = 0 ;
356457
357458 git_config (reflog_expire_config , NULL );
358459
@@ -367,20 +468,18 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
367468 cb .expire_total = default_reflog_expire ;
368469 cb .expire_unreachable = default_reflog_expire_unreachable ;
369470
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-
376471 for (i = 1 ; i < argc ; i ++ ) {
377472 const char * arg = argv [i ];
378473 if (!strcmp (arg , "--dry-run" ) || !strcmp (arg , "-n" ))
379474 cb .dry_run = 1 ;
380- else if (!prefixcmp (arg , "--expire=" ))
475+ else if (!prefixcmp (arg , "--expire=" )) {
381476 cb .expire_total = approxidate (arg + 9 );
382- else if (!prefixcmp (arg , "--expire-unreachable=" ))
477+ explicit_expiry |= EXPIRE_TOTAL ;
478+ }
479+ else if (!prefixcmp (arg , "--expire-unreachable=" )) {
383480 cb .expire_unreachable = approxidate (arg + 21 );
481+ explicit_expiry |= EXPIRE_UNREACH ;
482+ }
384483 else if (!strcmp (arg , "--stale-fix" ))
385484 cb .stalefix = 1 ;
386485 else if (!strcmp (arg , "--rewrite" ))
@@ -400,6 +499,12 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
400499 else
401500 break ;
402501 }
502+
503+ /*
504+ * We can trust the commits and objects reachable from refs
505+ * even in older repository. We cannot trust what's reachable
506+ * from reflog if the repository was pruned with older git.
507+ */
403508 if (cb .stalefix ) {
404509 init_revisions (& cb .revs , prefix );
405510 if (cb .verbose )
@@ -417,6 +522,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
417522 for_each_reflog (collect_reflog , & collected );
418523 for (i = 0 ; i < collected .nr ; i ++ ) {
419524 struct collected_reflog * e = collected .e [i ];
525+ set_reflog_expiry_param (& cb , explicit_expiry , e -> reflog );
420526 status |= expire_reflog (e -> reflog , e -> sha1 , 0 , & cb );
421527 free (e );
422528 }
@@ -430,6 +536,7 @@ static int cmd_reflog_expire(int argc, const char **argv, const char *prefix)
430536 status |= error ("%s points nowhere!" , ref );
431537 continue ;
432538 }
539+ set_reflog_expiry_param (& cb , explicit_expiry , ref );
433540 status |= expire_reflog (ref , sha1 , 0 , & cb );
434541 }
435542 return status ;
0 commit comments