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