Merge branch 'rs/archive-from-subdirectory-fixes'
"git archive" run from a subdirectory mishandled attributes and paths outside the current directory. * rs/archive-from-subdirectory-fixes: archive: improve support for running in subdirectory
This commit is contained in:
commit
de73a20756
75
archive.c
75
archive.c
@ -173,6 +173,29 @@ static int write_archive_entry(const struct object_id *oid, const char *base,
|
|||||||
args->convert = check_attr_export_subst(check);
|
args->convert = check_attr_export_subst(check);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (args->prefix) {
|
||||||
|
static struct strbuf new_path = STRBUF_INIT;
|
||||||
|
static struct strbuf buf = STRBUF_INIT;
|
||||||
|
const char *rel;
|
||||||
|
|
||||||
|
rel = relative_path(path_without_prefix, args->prefix, &buf);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We don't add an entry for the current working
|
||||||
|
* directory when we are at the root; skip it also when
|
||||||
|
* we're in a subdirectory or submodule. Skip entries
|
||||||
|
* higher up as well.
|
||||||
|
*/
|
||||||
|
if (!strcmp(rel, "./") || starts_with(rel, "../"))
|
||||||
|
return S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0;
|
||||||
|
|
||||||
|
/* rel can refer to path, so don't edit it in place */
|
||||||
|
strbuf_reset(&new_path);
|
||||||
|
strbuf_add(&new_path, args->base, args->baselen);
|
||||||
|
strbuf_addstr(&new_path, rel);
|
||||||
|
strbuf_swap(&path, &new_path);
|
||||||
|
}
|
||||||
|
|
||||||
if (args->verbose)
|
if (args->verbose)
|
||||||
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
fprintf(stderr, "%.*s\n", (int)path.len, path.buf);
|
||||||
|
|
||||||
@ -408,6 +431,27 @@ static int reject_entry(const struct object_id *oid UNUSED,
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int reject_outside(const struct object_id *oid UNUSED,
|
||||||
|
struct strbuf *base, const char *filename,
|
||||||
|
unsigned mode, void *context)
|
||||||
|
{
|
||||||
|
struct archiver_args *args = context;
|
||||||
|
struct strbuf buf = STRBUF_INIT;
|
||||||
|
struct strbuf path = STRBUF_INIT;
|
||||||
|
int ret = 0;
|
||||||
|
|
||||||
|
if (S_ISDIR(mode))
|
||||||
|
return READ_TREE_RECURSIVE;
|
||||||
|
|
||||||
|
strbuf_addbuf(&path, base);
|
||||||
|
strbuf_addstr(&path, filename);
|
||||||
|
if (starts_with(relative_path(path.buf, args->prefix, &buf), "../"))
|
||||||
|
ret = -1;
|
||||||
|
strbuf_release(&buf);
|
||||||
|
strbuf_release(&path);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static int path_exists(struct archiver_args *args, const char *path)
|
static int path_exists(struct archiver_args *args, const char *path)
|
||||||
{
|
{
|
||||||
const char *paths[] = { path, NULL };
|
const char *paths[] = { path, NULL };
|
||||||
@ -415,8 +459,13 @@ static int path_exists(struct archiver_args *args, const char *path)
|
|||||||
int ret;
|
int ret;
|
||||||
|
|
||||||
ctx.args = args;
|
ctx.args = args;
|
||||||
parse_pathspec(&ctx.pathspec, 0, 0, "", paths);
|
parse_pathspec(&ctx.pathspec, 0, PATHSPEC_PREFER_CWD,
|
||||||
|
args->prefix, paths);
|
||||||
ctx.pathspec.recursive = 1;
|
ctx.pathspec.recursive = 1;
|
||||||
|
if (args->prefix && read_tree(args->repo, args->tree, &ctx.pathspec,
|
||||||
|
reject_outside, args))
|
||||||
|
die(_("pathspec '%s' matches files outside the "
|
||||||
|
"current directory"), path);
|
||||||
ret = read_tree(args->repo, args->tree,
|
ret = read_tree(args->repo, args->tree,
|
||||||
&ctx.pathspec,
|
&ctx.pathspec,
|
||||||
reject_entry, &ctx);
|
reject_entry, &ctx);
|
||||||
@ -432,9 +481,8 @@ static void parse_pathspec_arg(const char **pathspec,
|
|||||||
* Also if pathspec patterns are dependent, we're in big
|
* Also if pathspec patterns are dependent, we're in big
|
||||||
* trouble as we test each one separately
|
* trouble as we test each one separately
|
||||||
*/
|
*/
|
||||||
parse_pathspec(&ar_args->pathspec, 0,
|
parse_pathspec(&ar_args->pathspec, 0, PATHSPEC_PREFER_CWD,
|
||||||
PATHSPEC_PREFER_FULL,
|
ar_args->prefix, pathspec);
|
||||||
"", pathspec);
|
|
||||||
ar_args->pathspec.recursive = 1;
|
ar_args->pathspec.recursive = 1;
|
||||||
if (pathspec) {
|
if (pathspec) {
|
||||||
while (*pathspec) {
|
while (*pathspec) {
|
||||||
@ -446,8 +494,7 @@ static void parse_pathspec_arg(const char **pathspec,
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void parse_treeish_arg(const char **argv,
|
static void parse_treeish_arg(const char **argv,
|
||||||
struct archiver_args *ar_args, const char *prefix,
|
struct archiver_args *ar_args, int remote)
|
||||||
int remote)
|
|
||||||
{
|
{
|
||||||
const char *name = argv[0];
|
const char *name = argv[0];
|
||||||
const struct object_id *commit_oid;
|
const struct object_id *commit_oid;
|
||||||
@ -487,20 +534,6 @@ static void parse_treeish_arg(const char **argv,
|
|||||||
if (!tree)
|
if (!tree)
|
||||||
die(_("not a tree object: %s"), oid_to_hex(&oid));
|
die(_("not a tree object: %s"), oid_to_hex(&oid));
|
||||||
|
|
||||||
if (prefix) {
|
|
||||||
struct object_id tree_oid;
|
|
||||||
unsigned short mode;
|
|
||||||
int err;
|
|
||||||
|
|
||||||
err = get_tree_entry(ar_args->repo,
|
|
||||||
&tree->object.oid,
|
|
||||||
prefix, &tree_oid,
|
|
||||||
&mode);
|
|
||||||
if (err || !S_ISDIR(mode))
|
|
||||||
die(_("current working directory is untracked"));
|
|
||||||
|
|
||||||
tree = parse_tree_indirect(&tree_oid);
|
|
||||||
}
|
|
||||||
ar_args->refname = ref;
|
ar_args->refname = ref;
|
||||||
ar_args->tree = tree;
|
ar_args->tree = tree;
|
||||||
ar_args->commit_oid = commit_oid;
|
ar_args->commit_oid = commit_oid;
|
||||||
@ -718,7 +751,7 @@ int write_archive(int argc, const char **argv, const char *prefix,
|
|||||||
setup_git_directory();
|
setup_git_directory();
|
||||||
}
|
}
|
||||||
|
|
||||||
parse_treeish_arg(argv, &args, prefix, remote);
|
parse_treeish_arg(argv, &args, remote);
|
||||||
parse_pathspec_arg(argv + 1, &args);
|
parse_pathspec_arg(argv + 1, &args);
|
||||||
|
|
||||||
rc = ar->write_archive(ar, &args);
|
rc = ar->write_archive(ar, &args);
|
||||||
|
@ -426,6 +426,19 @@ test_expect_success 'catch non-matching pathspec' '
|
|||||||
test_must_fail git archive -v HEAD -- "*.abc" >/dev/null
|
test_must_fail git archive -v HEAD -- "*.abc" >/dev/null
|
||||||
'
|
'
|
||||||
|
|
||||||
|
test_expect_success 'reject paths outside the current directory' '
|
||||||
|
test_must_fail git -C a/bin archive HEAD .. >/dev/null 2>err &&
|
||||||
|
grep "outside the current directory" err
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_success 'allow pathspecs that resolve to the current directory' '
|
||||||
|
git -C a/bin archive -v HEAD ../bin >/dev/null 2>actual &&
|
||||||
|
cat >expect <<-\EOF &&
|
||||||
|
sh
|
||||||
|
EOF
|
||||||
|
test_cmp expect actual
|
||||||
|
'
|
||||||
|
|
||||||
# Pull the size and date of each entry in a tarfile using the system tar.
|
# Pull the size and date of each entry in a tarfile using the system tar.
|
||||||
#
|
#
|
||||||
# We'll pull out only the year from the date; that avoids any question of
|
# We'll pull out only the year from the date; that avoids any question of
|
||||||
|
@ -33,6 +33,13 @@ test_expect_success 'setup' '
|
|||||||
echo ignored-by-tree.d export-ignore >>.gitattributes &&
|
echo ignored-by-tree.d export-ignore >>.gitattributes &&
|
||||||
git add ignored-by-tree ignored-by-tree.d .gitattributes &&
|
git add ignored-by-tree ignored-by-tree.d .gitattributes &&
|
||||||
|
|
||||||
|
mkdir subdir &&
|
||||||
|
>subdir/included &&
|
||||||
|
>subdir/ignored-by-subtree &&
|
||||||
|
>subdir/ignored-by-tree &&
|
||||||
|
echo ignored-by-subtree export-ignore >subdir/.gitattributes &&
|
||||||
|
git add subdir &&
|
||||||
|
|
||||||
echo ignored by worktree >ignored-by-worktree &&
|
echo ignored by worktree >ignored-by-worktree &&
|
||||||
echo ignored-by-worktree export-ignore >.gitattributes &&
|
echo ignored-by-worktree export-ignore >.gitattributes &&
|
||||||
git add ignored-by-worktree &&
|
git add ignored-by-worktree &&
|
||||||
@ -93,6 +100,15 @@ test_expect_exists archive-pathspec-wildcard/ignored-by-worktree
|
|||||||
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d
|
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d
|
||||||
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file
|
test_expect_missing archive-pathspec-wildcard/excluded-by-pathspec.d/file
|
||||||
|
|
||||||
|
test_expect_success 'git -C subdir archive' '
|
||||||
|
git -C subdir archive HEAD >archive-subdir.tar &&
|
||||||
|
extract_tar_to_dir archive-subdir
|
||||||
|
'
|
||||||
|
|
||||||
|
test_expect_exists archive-subdir/included
|
||||||
|
test_expect_missing archive-subdir/ignored-by-subtree
|
||||||
|
test_expect_missing archive-subdir/ignored-by-tree
|
||||||
|
|
||||||
test_expect_success 'git archive with worktree attributes' '
|
test_expect_success 'git archive with worktree attributes' '
|
||||||
git archive --worktree-attributes HEAD >worktree.tar &&
|
git archive --worktree-attributes HEAD >worktree.tar &&
|
||||||
(mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar
|
(mkdir worktree && cd worktree && "$TAR" xf -) <worktree.tar
|
||||||
|
Loading…
Reference in New Issue
Block a user