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