148
* If the file 1) corresponds to an existing index entry with
149
* skip-worktree set, or 2) does not exist in the index but is
150
* outside the sparse checkout definition, add a skip-worktree bit
151
- * to the new index entry.
151
+ * to the new index entry. Note that a sparse index will be expanded
152
+ * if this entry is outside the sparse cone - this is necessary
153
+ * to properly construct the reset sparse directory.
154
*/
155
pos = cache_name_pos(one->path, strlen(one->path));
156
if ((pos >= 0 && ce_skip_worktree(active_cache[pos])) ||
168
}
169
}
170
171
+static int pathspec_needs_expanded_index(const struct pathspec *pathspec)
172
+{
173
+ unsigned int i, pos;
174
+ int res = 0;
175
+ char *skip_worktree_seen = NULL;
176
+
177
+ /*
178
+ * When using a magic pathspec, assume for the sake of simplicity that
179
+ * the index needs to be expanded to match all matchable files.
180
+ */
181
+ if (pathspec->magic)
182
+ return 1;
183
+
184
+ for (i = 0; i < pathspec->nr; i++) {
185
+ struct pathspec_item item = pathspec->items[i];
186
+
187
+ /*
188
+ * If the pathspec item has a wildcard, the index should be expanded
189
+ * if the pathspec has the possibility of matching a subset of entries inside
190
+ * of a sparse directory (but not the entire directory).
191
+ *
192
+ * If the pathspec item is a literal path, the index only needs to be expanded
193
+ * if a) the pathspec isn't in the sparse checkout cone (to make sure we don't
194
+ * expand for in-cone files) and b) it doesn't match any sparse directories
195
+ * (since we can reset whole sparse directories without expanding them).
196
+ */
197
+ if (item.nowildcard_len < item.len) {
198
+ /*
199
+ * Special case: if the pattern is a path inside the cone
200
+ * followed by only wildcards, the pattern cannot match
201
+ * partial sparse directories, so we don't expand the index.
202
+ */
203
+ if (path_in_cone_mode_sparse_checkout(item.original, &the_index) &&
204
+ strspn(item.original + item.nowildcard_len, "*") == item.len - item.nowildcard_len)
205
+ continue;
206
+
207
+ for (pos = 0; pos < active_nr; pos++) {
208
+ struct cache_entry *ce = active_cache[pos];
209
+
210
+ if (!S_ISSPARSEDIR(ce->ce_mode))
211
+ continue;
212
+
213
+ /*
214
+ * If the pre-wildcard length is longer than the sparse
215
+ * directory name and the sparse directory is the first
216
+ * component of the pathspec, need to expand the index.
217
+ */
218
+ if (item.nowildcard_len > ce_namelen(ce) &&
219
+ !strncmp(item.original, ce->name, ce_namelen(ce))) {
220
+ res = 1;
221
+ break;
222
+ }
223
+
224
+ /*
225
+ * If the pre-wildcard length is shorter than the sparse
226
+ * directory and the pathspec does not match the whole
227
+ * directory, need to expand the index.
228
+ */
229
+ if (!strncmp(item.original, ce->name, item.nowildcard_len) &&
230
+ wildmatch(item.original, ce->name, 0)) {
231
+ res = 1;
232
+ break;
233
+ }
234
+ }
235
+ } else if (!path_in_cone_mode_sparse_checkout(item.original, &the_index) &&
236
+ !matches_skip_worktree(pathspec, i, &skip_worktree_seen))
237
+ res = 1;
238
+
239
+ if (res > 0)
240
+ break;
241
+ }
242
+
243
+ free(skip_worktree_seen);
244
+ return res;
245
+}
246
+
247
static int read_from_tree(const struct pathspec *pathspec,
248
struct object_id *tree_oid,
249
int intent_to_add)
256
opt.format_callback = update_index_from_diff;
257
opt.format_callback_data = &intent_to_add;
258
opt.flags.override_submodule_config = 1;
259
+ opt.flags.recursive = 1;
260
opt.repo = the_repository;
261
+ opt.change = diff_change;
262
+ opt.add_remove = diff_addremove;
263
+
264
+ if (pathspec->nr && the_index.sparse_index && pathspec_needs_expanded_index(pathspec))
265
+ ensure_full_index(&the_index);
266
183
- ensure_full_index(&the_index);
267
if (do_diff_cache(tree_oid, &opt))
268
return 1;
269
diffcore_std(&opt);