@@ -1078,10 +1078,9 @@ static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
1078
1078
(!untracked || !untracked -> valid ||
1079
1079
/*
1080
1080
* .. and .gitignore does not exist before
1081
- * (i.e. null exclude_sha1 and skip_worktree is
1082
- * not set). Then we can skip loading .gitignore,
1083
- * which would result in ENOENT anyway.
1084
- * skip_worktree is taken care in read_directory()
1081
+ * (i.e. null exclude_sha1). Then we can skip
1082
+ * loading .gitignore, which would result in
1083
+ * ENOENT anyway.
1085
1084
*/
1086
1085
!is_null_sha1 (untracked -> exclude_sha1 ))) {
1087
1086
/*
@@ -1298,7 +1297,7 @@ static enum exist_status directory_exists_in_index(const char *dirname, int len)
1298
1297
*/
1299
1298
static enum path_treatment treat_directory (struct dir_struct * dir ,
1300
1299
struct untracked_cache_dir * untracked ,
1301
- const char * dirname , int len , int exclude ,
1300
+ const char * dirname , int len , int baselen , int exclude ,
1302
1301
const struct path_simplify * simplify )
1303
1302
{
1304
1303
/* The "len-1" is to strip the final '/' */
@@ -1325,7 +1324,8 @@ static enum path_treatment treat_directory(struct dir_struct *dir,
1325
1324
if (!(dir -> flags & DIR_HIDE_EMPTY_DIRECTORIES ))
1326
1325
return exclude ? path_excluded : path_untracked ;
1327
1326
1328
- untracked = lookup_untracked (dir -> untracked , untracked , dirname , len );
1327
+ untracked = lookup_untracked (dir -> untracked , untracked ,
1328
+ dirname + baselen , len - baselen );
1329
1329
return read_directory_recursive (dir , dirname , len ,
1330
1330
untracked , 1 , simplify );
1331
1331
}
@@ -1445,6 +1445,7 @@ static int get_dtype(struct dirent *de, const char *path, int len)
1445
1445
static enum path_treatment treat_one_path (struct dir_struct * dir ,
1446
1446
struct untracked_cache_dir * untracked ,
1447
1447
struct strbuf * path ,
1448
+ int baselen ,
1448
1449
const struct path_simplify * simplify ,
1449
1450
int dtype , struct dirent * de )
1450
1451
{
@@ -1496,8 +1497,8 @@ static enum path_treatment treat_one_path(struct dir_struct *dir,
1496
1497
return path_none ;
1497
1498
case DT_DIR :
1498
1499
strbuf_addch (path , '/' );
1499
- return treat_directory (dir , untracked , path -> buf , path -> len , exclude ,
1500
- simplify );
1500
+ return treat_directory (dir , untracked , path -> buf , path -> len ,
1501
+ baselen , exclude , simplify );
1501
1502
case DT_REG :
1502
1503
case DT_LNK :
1503
1504
return exclude ? path_excluded : path_untracked ;
@@ -1558,7 +1559,7 @@ static enum path_treatment treat_path(struct dir_struct *dir,
1558
1559
return path_none ;
1559
1560
1560
1561
dtype = DTYPE (de );
1561
- return treat_one_path (dir , untracked , path , simplify , dtype , de );
1562
+ return treat_one_path (dir , untracked , path , baselen , simplify , dtype , de );
1562
1563
}
1563
1564
1564
1565
static void add_untracked (struct untracked_cache_dir * dir , const char * name )
@@ -1828,7 +1829,7 @@ static int treat_leading_path(struct dir_struct *dir,
1828
1829
break ;
1829
1830
if (simplify_away (sb .buf , sb .len , simplify ))
1830
1831
break ;
1831
- if (treat_one_path (dir , NULL , & sb , simplify ,
1832
+ if (treat_one_path (dir , NULL , & sb , baselen , simplify ,
1832
1833
DT_DIR , NULL ) == path_none )
1833
1834
break ; /* do not recurse into it */
1834
1835
if (len <= baselen ) {
@@ -1880,7 +1881,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
1880
1881
const struct pathspec * pathspec )
1881
1882
{
1882
1883
struct untracked_cache_dir * root ;
1883
- int i ;
1884
1884
1885
1885
if (!dir -> untracked || getenv ("GIT_DISABLE_UNTRACKED_CACHE" ))
1886
1886
return NULL ;
@@ -1932,15 +1932,6 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d
1932
1932
if (dir -> exclude_list_group [EXC_CMDL ].nr )
1933
1933
return NULL ;
1934
1934
1935
- /*
1936
- * An optimization in prep_exclude() does not play well with
1937
- * CE_SKIP_WORKTREE. It's a rare case anyway, if a single
1938
- * entry has that bit set, disable the whole untracked cache.
1939
- */
1940
- for (i = 0 ; i < active_nr ; i ++ )
1941
- if (ce_skip_worktree (active_cache [i ]))
1942
- return NULL ;
1943
-
1944
1935
if (!ident_in_untracked (dir -> untracked )) {
1945
1936
warning (_ ("Untracked cache is disabled on this system." ));
1946
1937
return NULL ;
@@ -2625,23 +2616,67 @@ struct untracked_cache *read_untracked_extension(const void *data, unsigned long
2625
2616
return uc ;
2626
2617
}
2627
2618
2619
+ static void invalidate_one_directory (struct untracked_cache * uc ,
2620
+ struct untracked_cache_dir * ucd )
2621
+ {
2622
+ uc -> dir_invalidated ++ ;
2623
+ ucd -> valid = 0 ;
2624
+ ucd -> untracked_nr = 0 ;
2625
+ }
2626
+
2627
+ /*
2628
+ * Normally when an entry is added or removed from a directory,
2629
+ * invalidating that directory is enough. No need to touch its
2630
+ * ancestors. When a directory is shown as "foo/bar/" in git-status
2631
+ * however, deleting or adding an entry may have cascading effect.
2632
+ *
2633
+ * Say the "foo/bar/file" has become untracked, we need to tell the
2634
+ * untracked_cache_dir of "foo" that "bar/" is not an untracked
2635
+ * directory any more (because "bar" is managed by foo as an untracked
2636
+ * "file").
2637
+ *
2638
+ * Similarly, if "foo/bar/file" moves from untracked to tracked and it
2639
+ * was the last untracked entry in the entire "foo", we should show
2640
+ * "foo/" instead. Which means we have to invalidate past "bar" up to
2641
+ * "foo".
2642
+ *
2643
+ * This function traverses all directories from root to leaf. If there
2644
+ * is a chance of one of the above cases happening, we invalidate back
2645
+ * to root. Otherwise we just invalidate the leaf. There may be a more
2646
+ * sophisticated way than checking for SHOW_OTHER_DIRECTORIES to
2647
+ * detect these cases and avoid unnecessary invalidation, for example,
2648
+ * checking for the untracked entry named "bar/" in "foo", but for now
2649
+ * stick to something safe and simple.
2650
+ */
2651
+ static int invalidate_one_component (struct untracked_cache * uc ,
2652
+ struct untracked_cache_dir * dir ,
2653
+ const char * path , int len )
2654
+ {
2655
+ const char * rest = strchr (path , '/' );
2656
+
2657
+ if (rest ) {
2658
+ int component_len = rest - path ;
2659
+ struct untracked_cache_dir * d =
2660
+ lookup_untracked (uc , dir , path , component_len );
2661
+ int ret =
2662
+ invalidate_one_component (uc , d , rest + 1 ,
2663
+ len - (component_len + 1 ));
2664
+ if (ret )
2665
+ invalidate_one_directory (uc , dir );
2666
+ return ret ;
2667
+ }
2668
+
2669
+ invalidate_one_directory (uc , dir );
2670
+ return uc -> dir_flags & DIR_SHOW_OTHER_DIRECTORIES ;
2671
+ }
2672
+
2628
2673
void untracked_cache_invalidate_path (struct index_state * istate ,
2629
2674
const char * path )
2630
2675
{
2631
- const char * sep ;
2632
- struct untracked_cache_dir * d ;
2633
2676
if (!istate -> untracked || !istate -> untracked -> root )
2634
2677
return ;
2635
- sep = strrchr (path , '/' );
2636
- if (sep )
2637
- d = lookup_untracked (istate -> untracked ,
2638
- istate -> untracked -> root ,
2639
- path , sep - path );
2640
- else
2641
- d = istate -> untracked -> root ;
2642
- istate -> untracked -> dir_invalidated ++ ;
2643
- d -> valid = 0 ;
2644
- d -> untracked_nr = 0 ;
2678
+ invalidate_one_component (istate -> untracked , istate -> untracked -> root ,
2679
+ path , strlen (path ));
2645
2680
}
2646
2681
2647
2682
void untracked_cache_remove_from_index (struct index_state * istate ,
0 commit comments