1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
//! What:
//! Reads of the files ref storage that answer a question without a Git process,
//! and refuse to answer anything they cannot prove equal to Git's answer.
//! Why:
//! `git symbolic-ref --quiet HEAD` only reads the worktree's `HEAD` file and,
//! for a branch, checks that the branch is not itself a symbolic ref.
//! A strict reader of the plain spellings saves a process on every commit,
//! and every other spelling (a different ref name shape, a link,
//! a symbolic chain,
//! reftable storage) returns `None`,
//! which sends the caller to Git.
//!
//! In TS you'd write (pseudocode):
//! ```ts
//! const head = readHeadFile(layout); // undefined means "ask Git"
//! ```
/// Bounded no-follow reading of a regular file.
use crateread_regular_file;
/// The ref storage backend and the symbolic `HEAD` answer.
use crate;
/// Borrowed filesystem paths.
use Path;
/// The longest `HEAD` file this reader looks at;
/// a real one is a short line.
/// Exempt from a citation under `LQM` (class: reader fallback): a file, chain or count past this bound makes the reader
/// decline and real Git answer, so a Git start is added and no result changes. Classed once in
/// `doc/planning/cli-git-shipped-limits-audit.md`, "Exempt limits"; the coordinator's pick under the owner's delegation,
/// open to the owner's veto.
const HEAD_LIMIT: u64 = 512;
/// The longest loose branch file this reader looks at;
/// a real one is an object name and a newline.
/// Exempt from a citation under `LQM` (class: reader fallback): a file, chain or count past this bound makes the reader
/// decline and real Git answer, so a Git start is added and no result changes. Classed once in
/// `doc/planning/cli-git-shipped-limits-audit.md`, "Exempt limits"; the coordinator's pick under the owner's delegation,
/// open to the owner's veto.
const LOOSE_REF_LIMIT: u64 = 256;
/// What:
/// Where one worktree's ref files live and what format they are in.
/// Why:
/// The per-worktree `HEAD` is in the Git directory,
/// the branches are in the common directory,
/// and the length of an object name depends on the object format.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// type RefFilesLayout = { gitDir: string; commonDir: string; refFormat: 'files' | 'reftable'; objectFormat: string };
/// ```
/// What:
/// The number of hexadecimal digits of an object name under an object format,
/// or `None` for a format this reader does not know.
/// Why:
/// Git accepts a detached `HEAD` only with the repository's own name length.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// ({ sha1: 40, sha256: 64 } as const)[objectFormat]
/// ```
/// What:
/// Whether `text` is exactly one object name of `length` lowercase hexadecimal digits that is not the null name.
/// Why:
/// Git also accepts uppercase digits and trailing spaces;
/// refusing them only costs a fallback,
/// and the null name has a meaning of its own.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// new RegExp(`^[0-9a-f]{${length}}$`).test(text) && !/^0+$/.test(text)
/// ```
/// What:
/// Whether `name` is a branch ref name of a plain, always valid shape:
/// `refs/heads/` and then components of ASCII letters,
/// digits, `.`, `_` and `-`.
/// Why:
/// Git refuses names with a component that starts with `.` or ends with `.lock`,
/// a `..`, an empty component or a trailing `.`;
/// the plain alphabet needs no other rule,
/// and any other spelling is left to Git.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// /^refs\/heads\/([A-Za-z0-9_-][A-Za-z0-9._-]*)(\/[A-Za-z0-9_-][A-Za-z0-9._-]*)*$/.test(name) && ...
/// ```
/// What:
/// Whether the loose file of a branch, if there is one, is a plain object name.
/// Why:
/// `symbolic-ref` follows a branch that is itself a symbolic ref and fails on a broken one;
/// a missing loose file is an unborn or packed branch,
/// and packed refs cannot be symbolic.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const text = await readFile(join(commonDir, name)).catch(notFound); return text === undefined || isObjectName(text.trimEnd('\n'));
/// ```
/// What:
/// `git symbolic-ref --quiet HEAD` answered from the worktree's `HEAD` file,
/// or `None` when the file is not one of the two plain spellings.
/// Why:
/// `ref: <plain branch>` and a lone object name are the only shapes the commit path meets;
/// the file is read afresh on every call,
/// so a landing that calls this under its lock sees the file as it is then.
///
/// In TS you'd write (pseudocode):
/// ```ts
/// const text = await readFile(join(gitDir, 'HEAD'), 'utf8'); // 'ref: refs/heads/x\n' or '<oid>\n'
/// ```
/// Files ref reader controls stay out of the release executable.
pub