@@ -785,12 +785,55 @@ static int add_excludes(const char *fname, const char *base, int baselen,
785785 size_t size = 0 ;
786786 char * buf ;
787787
788- fd = open (fname , O_RDONLY );
789- if (fd < 0 || fstat (fd , & st ) < 0 ) {
790- if (fd < 0 )
791- warn_on_fopen_errors (fname );
792- else
793- close (fd );
788+ /*
789+ * A performance optimization for status.
790+ *
791+ * During a status scan, git looks in each directory for a .gitignore
792+ * file before scanning the directory. Since .gitignore files are not
793+ * that common, we can waste a lot of time looking for files that are
794+ * not there. Fortunately, the fscache already knows if the directory
795+ * contains a .gitignore file, since it has already read the directory
796+ * and it already has the stat-data.
797+ *
798+ * If the fscache is enabled, use the fscache-lstat() interlude to see
799+ * if the file exists (in the fscache hash maps) before trying to open()
800+ * it.
801+ *
802+ * This causes problem when the .gitignore file is a symlink, because
803+ * we call lstat() rather than stat() on the symlnk and the resulting
804+ * stat-data is for the symlink itself rather than the target file.
805+ * We CANNOT use stat() here because the fscache DOES NOT install an
806+ * interlude for stat() and mingw_stat() always calls "open-fstat-close"
807+ * on the file and defeats the purpose of the optimization here. Since
808+ * symlinks are even more rare than .gitignore files, we force a fstat()
809+ * after our open() to get stat-data for the target file.
810+ */
811+ if (is_fscache_enabled (fname )) {
812+ if (lstat (fname , & st ) < 0 ) {
813+ fd = -1 ;
814+ } else {
815+ fd = open (fname , O_RDONLY );
816+ if (fd < 0 )
817+ warn_on_fopen_errors (fname );
818+ else if (S_ISLNK (st .st_mode ) && fstat (fd , & st ) < 0 ) {
819+ warn_on_fopen_errors (fname );
820+ close (fd );
821+ fd = -1 ;
822+ }
823+ }
824+ } else {
825+ fd = open (fname , O_RDONLY );
826+ if (fd < 0 || fstat (fd , & st ) < 0 ) {
827+ if (fd < 0 )
828+ warn_on_fopen_errors (fname );
829+ else {
830+ close (fd );
831+ fd = -1 ;
832+ }
833+ }
834+ }
835+
836+ if (fd < 0 ) {
794837 if (!istate )
795838 return -1 ;
796839 r = read_skip_worktree_file_from_index (istate , fname ,
0 commit comments