@@ -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