44
55static struct trace_key trace_serialize = TRACE_KEY_INIT (SERIALIZE );
66
7+ /*
8+ * Compute header record for exclude file using format:
9+ * <key> SP <status_char> SP <variant> LF
10+ */
11+ void wt_serialize_compute_exclude_header (struct strbuf * sb ,
12+ const char * key ,
13+ const char * path )
14+ {
15+ struct stat st ;
16+ struct stat_data sd ;
17+
18+ memset (& sd , 0 , sizeof (sd ));
19+
20+ strbuf_setlen (sb , 0 );
21+
22+ if (!path || !* path ) {
23+ strbuf_addf (sb , "%s U (unset)" , key );
24+ } else if (lstat (path , & st ) == -1 ) {
25+ if (is_missing_file_error (errno ))
26+ strbuf_addf (sb , "%s E (not-found) %s" , key , path );
27+ else
28+ strbuf_addf (sb , "%s E (other) %s" , key , path );
29+ } else {
30+ fill_stat_data (& sd , & st );
31+ strbuf_addf (sb , "%s F %d %d %s" ,
32+ key , sd .sd_mtime .sec , sd .sd_mtime .nsec , path );
33+ }
34+ }
35+
36+ static void append_exclude_info (int fd , const char * path , const char * key )
37+ {
38+ struct strbuf sb = STRBUF_INIT ;
39+
40+ wt_serialize_compute_exclude_header (& sb , key , path );
41+
42+ packet_write_fmt (fd , "%s\n" , sb .buf );
43+
44+ strbuf_release (& sb );
45+ }
46+
47+ static void append_core_excludes_file_info (int fd )
48+ {
49+ /*
50+ * Write pathname and mtime of the core/global excludes file to
51+ * the status cache header. Since a change in the global excludes
52+ * will/may change the results reported by status, the deserialize
53+ * code should be able to reject the status cache if the excludes
54+ * file changes since when the cache was written.
55+ *
56+ * The "core.excludefile" setting defaults to $XDG_HOME/git/ignore
57+ * and uses a global variable which should have been set during
58+ * wt_status_collect_untracked().
59+ *
60+ * See dir.c:setup_standard_excludes()
61+ */
62+ append_exclude_info (fd , excludes_file , "core_excludes" );
63+ }
64+
65+ static void append_repo_excludes_file_info (int fd )
66+ {
67+ /*
68+ * Likewise, there is a per-repo excludes file in .git/info/excludes
69+ * that can change the results reported by status. And the deserialize
70+ * code needs to be able to reject the status cache if this file
71+ * changes.
72+ *
73+ * See dir.c:setup_standard_excludes() and git_path_info_excludes().
74+ * We replicate the pathname construction here because of the static
75+ * variables/functions used in dir.c.
76+ */
77+ char * path = git_pathdup ("info/exclude" );
78+
79+ append_exclude_info (fd , path , "repo_excludes" );
80+
81+ free (path );
82+ }
83+
84+ /*
85+ * WARNING: The status cache attempts to preserve the essential in-memory
86+ * status data after a status scan into a "serialization" (aka "status cache")
87+ * file. It allows later "git status --deserialize=<foo>" instances to
88+ * just print the cached status results without scanning the workdir (and
89+ * without reading the index).
90+ *
91+ * The status cache file is valid as long as:
92+ * [1] the set of functional command line options are the same (think "-u").
93+ * [2] repo-local and user-global configuration settings are compatible.
94+ * [3] nothing in the workdir has changed.
95+ *
96+ * We rely on:
97+ * [1.a] We remember the relevant (functional, non-display) command line
98+ * arguments in the status cache header.
99+ * [2.a] We use the mtime of the .git/index to detect staging changes.
100+ * [2.b] We use the mtimes of the excludes files to detect changes that
101+ * might affect untracked file reporting.
102+ *
103+ * But we need external help to verify [3].
104+ * [] This includes changes to tracked files.
105+ * [] This includes changes to tracked .gitignore files that might change
106+ * untracked file reporting.
107+ * [] This includes the creation of new, untracked per-directory .gitignore
108+ * files that might change untracked file reporting.
109+ *
110+ * [3.a] On GVFS repos, we rely on the GVFS service (mount) daemon to
111+ * watch the filesystem and invalidate (delete) the status cache
112+ * when anything changes inside the workdir.
113+ *
114+ * [3.b] TODO This problem is not solved for non-GVFS repos.
115+ * [] It is possible that the untracked-cache index extension
116+ * could help with this but that requires status to read the
117+ * index to load the extension.
118+ * [] It is possible that the new fsmonitor facility could also
119+ * provide this information, but that to requires reading the
120+ * index.
121+ */
122+
7123/*
8124 * Write V1 header fields.
9125 */
@@ -16,6 +132,8 @@ static void wt_serialize_v1_header(struct wt_status *s, int fd)
16132 packet_write_fmt (fd , "index_mtime %d %d\n" ,
17133 s -> repo -> index -> timestamp .sec ,
18134 s -> repo -> index -> timestamp .nsec );
135+ append_core_excludes_file_info (fd );
136+ append_repo_excludes_file_info (fd );
19137
20138 /*
21139 * Write data from wt_status to qualify this status report.
0 commit comments