Skip to content

Commit e96980e

Browse files
peffgitster
authored andcommitted
builtin-add: simplify (and increase accuracy of) exclude handling
Previously, the code would always set up the excludes, and then manually pick through the pathspec we were given, assuming that non-added but existing paths were just ignored. This was mostly correct, but would erroneously mark a totally empty directory as 'ignored'. Instead, we now use the collect_ignored option of dir_struct, which unambiguously tells us whether a path was ignored. This simplifies the code, and means empty directories are now just not mentioned at all. Furthermore, we now conditionally ask dir_struct to respect excludes, depending on whether the '-f' flag has been set. This means we don't have to pick through the result, checking for an 'ignored' flag; ignored entries were either added or not in the first place. We can safely get rid of the special 'ignored' flags to dir_entry, which were not used anywhere else. Signed-off-by: Jeff King <[email protected]> Signed-off-by: Jonas Fonseca <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 2abd31b commit e96980e

File tree

3 files changed

+36
-53
lines changed

3 files changed

+36
-53
lines changed

builtin-add.c

Lines changed: 21 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -40,42 +40,29 @@ static void prune_directory(struct dir_struct *dir, const char **pathspec, int p
4040
dir->nr = dst - dir->entries;
4141

4242
for (i = 0; i < specs; i++) {
43-
struct stat st;
44-
const char *match;
45-
if (seen[i])
46-
continue;
47-
48-
match = pathspec[i];
49-
if (!match[0])
50-
continue;
51-
52-
/* Existing file? We must have ignored it */
53-
if (!lstat(match, &st)) {
54-
struct dir_entry *ent;
55-
56-
ent = dir_add_name(dir, match, strlen(match));
57-
ent->ignored = 1;
58-
if (S_ISDIR(st.st_mode))
59-
ent->ignored_dir = 1;
60-
continue;
61-
}
62-
die("pathspec '%s' did not match any files", match);
43+
if (!seen[i] && !file_exists(pathspec[i]))
44+
die("pathspec '%s' did not match any files",
45+
pathspec[i]);
6346
}
6447
}
6548

66-
static void fill_directory(struct dir_struct *dir, const char **pathspec)
49+
static void fill_directory(struct dir_struct *dir, const char **pathspec,
50+
int ignored_too)
6751
{
6852
const char *path, *base;
6953
int baselen;
7054

7155
/* Set up the default git porcelain excludes */
7256
memset(dir, 0, sizeof(*dir));
73-
dir->exclude_per_dir = ".gitignore";
74-
path = git_path("info/exclude");
75-
if (!access(path, R_OK))
76-
add_excludes_from_file(dir, path);
77-
if (!access(excludes_file, R_OK))
78-
add_excludes_from_file(dir, excludes_file);
57+
if (!ignored_too) {
58+
dir->collect_ignored = 1;
59+
dir->exclude_per_dir = ".gitignore";
60+
path = git_path("info/exclude");
61+
if (!access(path, R_OK))
62+
add_excludes_from_file(dir, path);
63+
if (!access(excludes_file, R_OK))
64+
add_excludes_from_file(dir, excludes_file);
65+
}
7966

8067
/*
8168
* Calculate common prefix for the pathspec, and
@@ -219,13 +206,11 @@ int cmd_add(int argc, const char **argv, const char *prefix)
219206
}
220207
pathspec = get_pathspec(prefix, argv + i);
221208

222-
fill_directory(&dir, pathspec);
209+
fill_directory(&dir, pathspec, ignored_too);
223210

224211
if (show_only) {
225212
const char *sep = "", *eof = "";
226213
for (i = 0; i < dir.nr; i++) {
227-
if (!ignored_too && dir.entries[i]->ignored)
228-
continue;
229214
printf("%s%s", sep, dir.entries[i]->name);
230215
sep = " ";
231216
eof = "\n";
@@ -237,25 +222,13 @@ int cmd_add(int argc, const char **argv, const char *prefix)
237222
if (read_cache() < 0)
238223
die("index file corrupt");
239224

240-
if (!ignored_too) {
241-
int has_ignored = 0;
242-
for (i = 0; i < dir.nr; i++)
243-
if (dir.entries[i]->ignored)
244-
has_ignored = 1;
245-
if (has_ignored) {
246-
fprintf(stderr, ignore_warning);
247-
for (i = 0; i < dir.nr; i++) {
248-
if (!dir.entries[i]->ignored)
249-
continue;
250-
fprintf(stderr, "%s", dir.entries[i]->name);
251-
if (dir.entries[i]->ignored_dir)
252-
fprintf(stderr, " (directory)");
253-
fputc('\n', stderr);
254-
}
255-
fprintf(stderr,
256-
"Use -f if you really want to add them.\n");
257-
exit(1);
225+
if (dir.ignored_nr) {
226+
fprintf(stderr, ignore_warning);
227+
for (i = 0; i < dir.ignored_nr; i++) {
228+
fprintf(stderr, "%s\n", dir.ignored[i]->name);
258229
}
230+
fprintf(stderr, "Use -f if you really want to add them.\n");
231+
exit(1);
259232
}
260233

261234
for (i = 0; i < dir.nr; i++)

dir.c

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -275,7 +275,6 @@ static struct dir_entry *dir_entry_new(const char *pathname, int len) {
275275
struct dir_entry *ent;
276276

277277
ent = xmalloc(sizeof(*ent) + len + 1);
278-
ent->ignored = ent->ignored_dir = 0;
279278
ent->len = len;
280279
memcpy(ent->name, pathname, len);
281280
ent->name[len] = 0;
@@ -432,6 +431,18 @@ static int simplify_away(const char *path, int pathlen, const struct path_simpli
432431
return 0;
433432
}
434433

434+
static int in_pathspec(const char *path, int len, const struct path_simplify *simplify)
435+
{
436+
if (simplify) {
437+
for (; simplify->path; simplify++) {
438+
if (len == simplify->len
439+
&& !memcmp(path, simplify->path, len))
440+
return 1;
441+
}
442+
}
443+
return 0;
444+
}
445+
435446
/*
436447
* Read a directory tree. We currently ignore anything but
437448
* directories, regular files and symlinks. That's because git
@@ -472,7 +483,8 @@ static int read_directory_recursive(struct dir_struct *dir, const char *path, co
472483
continue;
473484

474485
exclude = excluded(dir, fullname);
475-
if (exclude && dir->collect_ignored)
486+
if (exclude && dir->collect_ignored
487+
&& in_pathspec(fullname, baselen + len, simplify))
476488
dir_add_ignored(dir, fullname, baselen + len);
477489
if (exclude != dir->show_ignored) {
478490
if (!dir->show_ignored || DTYPE(de) != DT_DIR) {

dir.h

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -13,9 +13,7 @@
1313

1414

1515
struct dir_entry {
16-
unsigned int ignored : 1;
17-
unsigned int ignored_dir : 1;
18-
unsigned int len : 30;
16+
unsigned int len;
1917
char name[FLEX_ARRAY]; /* more */
2018
};
2119

0 commit comments

Comments
 (0)