Skip to content

Commit de1f68a

Browse files
dschogitster
authored andcommitted
archive --add-virtual-file: allow paths containing colons
By allowing the path to be enclosed in double-quotes, we can avoid the limitation that paths cannot contain colons. Signed-off-by: Johannes Schindelin <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 237a1d1 commit de1f68a

File tree

3 files changed

+38
-14
lines changed

3 files changed

+38
-14
lines changed

Documentation/git-archive.txt

Lines changed: 10 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -69,10 +69,16 @@ OPTIONS
6969
by concatenating the value of the last `--prefix` option (if any)
7070
before this `--add-virtual-file` and `<path>`.
7171
+
72-
The `<path>` cannot contain any colon, the file mode is limited to
73-
a regular file, and the option may be subject to platform-dependent
74-
command-line limits. For non-trivial cases, write an untracked file
75-
and use `--add-file` instead.
72+
The `<path>` argument can start and end with a literal double-quote
73+
character; the contained file name is interpreted as a C-style string,
74+
i.e. the backslash is interpreted as escape character. The path must
75+
be quoted if it contains a colon, to avoid the colon from being
76+
misinterpreted as the separator between the path and the contents, or
77+
if the path begins or ends with a double-quote character.
78+
+
79+
The file mode is limited to a regular file, and the option may be
80+
subject to platform-dependent command-line limits. For non-trivial
81+
cases, write an untracked file and use `--add-file` instead.
7682

7783
--worktree-attributes::
7884
Look for attributes in .gitattributes files in the working tree

archive.c

Lines changed: 20 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "parse-options.h"
1010
#include "unpack-trees.h"
1111
#include "dir.h"
12+
#include "quote.h"
1213

1314
static char const * const archive_usage[] = {
1415
N_("git archive [<options>] <tree-ish> [<path>...]"),
@@ -535,22 +536,31 @@ static int add_file_cb(const struct option *opt, const char *arg, int unset)
535536
die(_("Not a regular file: %s"), path);
536537
info->content = NULL; /* read the file later */
537538
} else if (!strcmp(opt->long_name, "add-virtual-file")) {
538-
const char *colon = strchr(arg, ':');
539-
char *p;
539+
struct strbuf buf = STRBUF_INIT;
540+
const char *p = arg;
541+
542+
if (*p != '"')
543+
p = strchr(p, ':');
544+
else if (unquote_c_style(&buf, p, &p) < 0)
545+
die(_("unclosed quote: '%s'"), arg);
540546

541-
if (!colon)
547+
if (!p || *p != ':')
542548
die(_("missing colon: '%s'"), arg);
543549

544-
p = xstrndup(arg, colon - arg);
545-
if (!args->prefix)
546-
path = p;
547-
else {
548-
path = prefix_filename(args->prefix, p);
549-
free(p);
550+
if (p == arg)
551+
die(_("empty file name: '%s'"), arg);
552+
553+
path = buf.len ?
554+
strbuf_detach(&buf, NULL) : xstrndup(arg, p - arg);
555+
556+
if (args->prefix) {
557+
char *save = path;
558+
path = prefix_filename(args->prefix, path);
559+
free(save);
550560
}
551561
memset(&info->stat, 0, sizeof(info->stat));
552562
info->stat.st_mode = S_IFREG | 0644;
553-
info->content = xstrdup(colon + 1);
563+
info->content = xstrdup(p + 1);
554564
info->stat.st_size = strlen(info->content);
555565
} else {
556566
BUG("add_file_cb() called for %s", opt->long_name);

t/t5003-archive-zip.sh

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,13 +207,21 @@ check_zip with_untracked
207207
check_added with_untracked untracked untracked
208208

209209
test_expect_success UNZIP 'git archive --format=zip --add-virtual-file' '
210+
if test_have_prereq FUNNYNAMES
211+
then
212+
PATHNAME="pathname with : colon"
213+
else
214+
PATHNAME="pathname without colon"
215+
fi &&
210216
git archive --format=zip >with_file_with_content.zip \
217+
--add-virtual-file=\""$PATHNAME"\": \
211218
--add-virtual-file=hello:world $EMPTY_TREE &&
212219
test_when_finished "rm -rf tmp-unpack" &&
213220
mkdir tmp-unpack && (
214221
cd tmp-unpack &&
215222
"$GIT_UNZIP" ../with_file_with_content.zip &&
216223
test_path_is_file hello &&
224+
test_path_is_file "$PATHNAME" &&
217225
test world = $(cat hello)
218226
)
219227
'

0 commit comments

Comments
 (0)