@@ -521,6 +521,7 @@ void add_exclude(const char *string, const char *base,
521521 x -> baselen = baselen ;
522522 x -> flags = flags ;
523523 x -> srcpos = srcpos ;
524+ string_list_init (& x -> sticky_paths , 1 );
524525 ALLOC_GROW (el -> excludes , el -> nr + 1 , el -> alloc );
525526 el -> excludes [el -> nr ++ ] = x ;
526527 x -> el = el ;
@@ -561,8 +562,10 @@ void clear_exclude_list(struct exclude_list *el)
561562{
562563 int i ;
563564
564- for (i = 0 ; i < el -> nr ; i ++ )
565+ for (i = 0 ; i < el -> nr ; i ++ ) {
566+ string_list_clear (& el -> excludes [i ]-> sticky_paths , 0 );
565567 free (el -> excludes [i ]);
568+ }
566569 free (el -> excludes );
567570 free (el -> filebuf );
568571
@@ -889,6 +892,44 @@ int match_pathname(const char *pathname, int pathlen,
889892 WM_PATHNAME ) == 0 ;
890893}
891894
895+ static void add_sticky (struct exclude * exc , const char * pathname , int pathlen )
896+ {
897+ struct strbuf sb = STRBUF_INIT ;
898+ int i ;
899+
900+ for (i = exc -> sticky_paths .nr - 1 ; i >= 0 ; i -- ) {
901+ const char * sticky = exc -> sticky_paths .items [i ].string ;
902+ int len = strlen (sticky );
903+
904+ if (pathlen < len && sticky [pathlen ] == '/' &&
905+ !strncmp (pathname , sticky , pathlen ))
906+ return ;
907+ }
908+
909+ strbuf_add (& sb , pathname , pathlen );
910+ string_list_append_nodup (& exc -> sticky_paths , strbuf_detach (& sb , NULL ));
911+ }
912+
913+ static int match_sticky (struct exclude * exc , const char * pathname , int pathlen , int dtype )
914+ {
915+ int i ;
916+
917+ for (i = exc -> sticky_paths .nr - 1 ; i >= 0 ; i -- ) {
918+ const char * sticky = exc -> sticky_paths .items [i ].string ;
919+ int len = strlen (sticky );
920+
921+ if (pathlen == len && dtype == DT_DIR &&
922+ !strncmp (pathname , sticky , len ))
923+ return 1 ;
924+
925+ if (pathlen > len && pathname [len ] == '/' &&
926+ !strncmp (pathname , sticky , len ))
927+ return 1 ;
928+ }
929+
930+ return 0 ;
931+ }
932+
892933/*
893934 * Scan the given exclude list in reverse to see whether pathname
894935 * should be ignored. The first match (i.e. the last on the list), if
@@ -914,6 +955,16 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
914955 const char * exclude = x -> pattern ;
915956 int prefix = x -> nowildcardlen ;
916957
958+ if (x -> sticky_paths .nr ) {
959+ if (* dtype == DT_UNKNOWN )
960+ * dtype = get_dtype (NULL , pathname , pathlen );
961+ if (match_sticky (x , pathname , pathlen , * dtype )) {
962+ exc = x ;
963+ break ;
964+ }
965+ continue ;
966+ }
967+
917968 if (x -> flags & EXC_FLAG_MUSTBEDIR ) {
918969 if (* dtype == DT_UNKNOWN )
919970 * dtype = get_dtype (NULL , pathname , pathlen );
@@ -947,9 +998,10 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
947998 return NULL ;
948999 }
9491000
950- trace_printf_key (& trace_exclude , "exclude: %.*s vs %s at line %d => %s\n" ,
1001+ trace_printf_key (& trace_exclude , "exclude: %.*s vs %s at line %d => %s%s \n" ,
9511002 pathlen , pathname , exc -> pattern , exc -> srcpos ,
952- exc -> flags & EXC_FLAG_NEGATIVE ? "no" : "yes" );
1003+ exc -> flags & EXC_FLAG_NEGATIVE ? "no" : "yes" ,
1004+ exc -> sticky_paths .nr ? " (stuck)" : "" );
9531005 return exc ;
9541006}
9551007
@@ -2005,6 +2057,25 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
20052057 return root ;
20062058}
20072059
2060+ static void clear_sticky (struct dir_struct * dir )
2061+ {
2062+ struct exclude_list_group * g ;
2063+ struct exclude_list * el ;
2064+ struct exclude * x ;
2065+ int i , j , k ;
2066+
2067+ for (i = EXC_CMDL ; i <= EXC_FILE ; i ++ ) {
2068+ g = & dir -> exclude_list_group [i ];
2069+ for (j = g -> nr - 1 ; j >= 0 ; j -- ) {
2070+ el = & g -> el [j ];
2071+ for (k = el -> nr - 1 ; 0 <= k ; k -- ) {
2072+ x = el -> excludes [k ];
2073+ string_list_clear (& x -> sticky_paths , 0 );
2074+ }
2075+ }
2076+ }
2077+ }
2078+
20082079int read_directory (struct dir_struct * dir , const char * path , int len , const struct pathspec * pathspec )
20092080{
20102081 struct path_simplify * simplify ;
0 commit comments