Skip to content

Commit 4318094

Browse files
rscharfegitster
authored andcommitted
archive: don't add empty directories to archives
While git doesn't track empty directories, git archive can be tricked into putting some into archives. One way is to construct an empty tree object, as t5004 does. While that is supported by the object database, it can't be represented in the index and thus it's unlikely to occur in the wild. Another way is using the literal name of a directory in an exclude pathspec -- its contents are are excluded, but the directory stub is included. That's inconsistent: exclude pathspecs containing wildcards don't leave empty directories in the archive. Yet another way is have a few levels of nested subdirectories (e.g. d1/d2/d3/file1) and ignoring the entries at the leaves (e.g. file1). The directories with the ignored content are ignored as well (e.g. d3), but their empty parents are included (e.g. d2). As empty directories are not supported by git, they should also not be written into archives. If an empty directory is really needed then it can be tracked and archived by placing an empty .gitignore file in it. There already is a mechanism in place for suppressing empty directories. When read_tree_recursive() encounters a directory excluded by a pathspec then it enters it anyway because it might contain included entries. It calls the callback function before it is able to decide if the directory is actually needed. For that reason git archive adds directories to a queue and writes entries for them only when it encounters the first child item -- but currently only if pathspecs with wildcards are used. Queue *all* directories, no matter if there even are pathspecs present. This prevents git archive from writing entries for empty directories in all cases. Suggested-by: Jeff King <peff@peff.net> Signed-off-by: Rene Scharfe <l.s.r@web.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
1 parent 5ff247a commit 4318094

4 files changed

Lines changed: 6 additions & 21 deletions

File tree

archive.c

Lines changed: 2 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -121,11 +121,6 @@ static int check_attr_export_subst(const struct attr_check *check)
121121
return check && ATTR_TRUE(check->items[1].value);
122122
}
123123

124-
static int should_queue_directories(const struct archiver_args *args)
125-
{
126-
return args->pathspec.has_wildcard;
127-
}
128-
129124
static int write_archive_entry(const unsigned char *sha1, const char *base,
130125
int baselen, const char *filename, unsigned mode, int stage,
131126
void *context)
@@ -147,7 +142,7 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
147142
strbuf_addch(&path, '/');
148143
path_without_prefix = path.buf + args->baselen;
149144

150-
if (!S_ISDIR(mode) || !should_queue_directories(args)) {
145+
if (!S_ISDIR(mode)) {
151146
const struct attr_check *check;
152147
check = get_archive_attrs(path_without_prefix);
153148
if (check_attr_export_ignore(check))
@@ -169,14 +164,6 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,
169164
return write_entry(args, sha1, path.buf, path.len, mode);
170165
}
171166

172-
static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base,
173-
const char *filename, unsigned mode, int stage,
174-
void *context)
175-
{
176-
return write_archive_entry(sha1, base->buf, base->len,
177-
filename, mode, stage, context);
178-
}
179-
180167
static void queue_directory(const unsigned char *sha1,
181168
struct strbuf *base, const char *filename,
182169
unsigned mode, int stage, struct archiver_context *c)
@@ -290,9 +277,7 @@ int write_archive_entries(struct archiver_args *args,
290277
}
291278

292279
err = read_tree_recursive(args->tree, "", 0, 0, &args->pathspec,
293-
should_queue_directories(args) ?
294-
queue_or_write_archive_entry :
295-
write_archive_entry_buf,
280+
queue_or_write_archive_entry,
296281
&context);
297282
if (err == READ_TREE_RECURSIVE)
298283
err = 0;

t/t5001-archive-attr.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,7 @@ test_expect_missing archive-pathspec/ignored-by-tree
7373
test_expect_missing archive-pathspec/ignored-by-tree.d
7474
test_expect_missing archive-pathspec/ignored-by-tree.d/file
7575
test_expect_exists archive-pathspec/ignored-by-worktree
76-
test_expect_missing archive-pathspec/excluded-by-pathspec.d failure
76+
test_expect_missing archive-pathspec/excluded-by-pathspec.d
7777
test_expect_missing archive-pathspec/excluded-by-pathspec.d/file
7878

7979
test_expect_success 'git archive with wildcard pathspec' '

t/t5002-archive-attr-pattern.sh

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ test_expect_missing archive/deep/and/slashless/ &&
7676
test_expect_missing archive/deep/and/slashless/foo &&
7777
test_expect_missing archive/deep/with/wildcard/ &&
7878
test_expect_missing archive/deep/with/wildcard/foo &&
79-
test_expect_exists archive/one-level-lower/
79+
test_expect_missing archive/one-level-lower/
8080
test_expect_missing archive/one-level-lower/two-levels-lower/ignored-only-if-dir/
8181
test_expect_missing archive/one-level-lower/two-levels-lower/ignored-ony-if-dir/ignored-by-ignored-dir
8282

t/t5004-archive-corner-cases.sh

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,14 +108,14 @@ test_expect_success 'archive empty subtree with no pathspec' '
108108
git archive --format=tar $root_tree >subtree-all.tar &&
109109
make_dir extract &&
110110
"$TAR" xf subtree-all.tar -C extract &&
111-
check_dir extract sub
111+
check_dir extract
112112
'
113113

114114
test_expect_success 'archive empty subtree by direct pathspec' '
115115
git archive --format=tar $root_tree -- sub >subtree-path.tar &&
116116
make_dir extract &&
117117
"$TAR" xf subtree-path.tar -C extract &&
118-
check_dir extract sub
118+
check_dir extract
119119
'
120120

121121
ZIPINFO=zipinfo

0 commit comments

Comments
 (0)