Currently: - "git archive" parses trees directly - attr mechanism does not support in-tree attributes Making attr.c support in-tree attributes is quite a non-trivial task, IMHO. Instead this patch makes "git archive" read tree to index first, then start exporting from there. One minor regression: "git archive" now will no longer generate directory entries, only files. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@xxxxxxxxx> --- archive.c | 66 ++++++++++++++++++++++++++++++++--------------- t/t0024-crlf-archive.sh | 2 - 2 files changed, 45 insertions(+), 23 deletions(-) diff --git a/archive.c b/archive.c index 5b54d95..402f6d4 100644 --- a/archive.c +++ b/archive.c @@ -4,6 +4,8 @@ #include "attr.h" #include "archive.h" #include "parse-options.h" +#include "unpack-trees.h" +#include "dir.h" static char const * const archive_usage[] = { "git archive [options] <tree-ish> [path...]", @@ -167,7 +169,9 @@ int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry) { struct archiver_context context; - int err; + struct unpack_trees_options opts; + struct tree_desc t; + int i, prefix_len, err; if (args->baselen > 0 && args->base[args->baselen - 1] == '/') { size_t len = args->baselen; @@ -185,11 +189,42 @@ int write_archive_entries(struct archiver_args *args, context.args = args; context.write_entry = write_entry; - err = read_tree_recursive(args->tree, args->base, args->baselen, 0, - args->pathspec, write_archive_entry, &context); - if (err == READ_TREE_RECURSIVE) - err = 0; - return err; + memset(&opts, 0, sizeof(opts)); + opts.index_only = 1; + opts.head_idx = -1; + opts.src_index = &the_index; + opts.dst_index = &the_index; + opts.fn = oneway_merge; + init_tree_desc(&t, args->tree->buffer, args->tree->size); + if (unpack_trees(1, &t, &opts)) + return -1; + prefix_len = common_prefix(args->pathspec); + if (prefix_len) + prune_cache(args->pathspec[0], prefix_len); + + for (i = 0;i < active_nr;i++) { + struct cache_entry *ce = active_cache[i]; + const char **path; + const char *str, *prefix; + int match = 0; + + if (!args->pathspec || !args->pathspec[0] || !*args->pathspec[0]) + match = 1; + + /* It's not really pathspec, so match_pathspec can't be used */ + for (path = args->pathspec;!match && *path;path++) { + for (str = ce->name, prefix = *path;*prefix && *str == *prefix; str++, prefix++) + ; + if (!*prefix && *str == '/') + match = 1; + } + + if (match) + write_archive_entry(ce->sha1, args->base, args->baselen, + ce->name, ce->ce_mode, ce_stage(ce), + &context); + } + return 0; } static const struct archiver *lookup_archiver(const char *name) @@ -207,9 +242,10 @@ static const struct archiver *lookup_archiver(const char *name) } static void parse_pathspec_arg(const char **pathspec, - struct archiver_args *ar_args) + struct archiver_args *ar_args, + const char *prefix) { - ar_args->pathspec = get_pathspec(ar_args->base, pathspec); + ar_args->pathspec = get_pathspec(prefix, pathspec); } static void parse_treeish_arg(const char **argv, @@ -238,18 +274,6 @@ static void parse_treeish_arg(const char **argv, if (tree == NULL) die("not a tree object"); - if (prefix) { - unsigned char tree_sha1[20]; - unsigned int mode; - int err; - - err = get_tree_entry(tree->object.sha1, prefix, - tree_sha1, &mode); - if (err || !S_ISDIR(mode)) - die("current working directory is untracked"); - - tree = parse_tree_indirect(tree_sha1); - } ar_args->tree = tree; ar_args->commit_sha1 = commit_sha1; ar_args->commit = commit; @@ -356,7 +380,7 @@ int write_archive(int argc, const char **argv, const char *prefix, prefix = setup_git_directory(); parse_treeish_arg(argv, &args, prefix); - parse_pathspec_arg(argv + 1, &args); + parse_pathspec_arg(argv + 1, &args, prefix); git_config(git_default_config, NULL); diff --git a/t/t0024-crlf-archive.sh b/t/t0024-crlf-archive.sh index 695ad5a..1cbe511 100755 --- a/t/t0024-crlf-archive.sh +++ b/t/t0024-crlf-archive.sh @@ -21,7 +21,6 @@ test_expect_success setup ' cat <<\EOF > expected sample -sub/ sub/sample EOF @@ -31,7 +30,6 @@ test_expect_success 'archive without subdir' ' ' cat <<\EOF > expected -sub/ sub/sample EOF -- 1.6.2.2.602.g83ee9f -- To unsubscribe from this list: send the line "unsubscribe git" in the body of a message to majordomo@xxxxxxxxxxxxxxx More majordomo info at http://vger.kernel.org/majordomo-info.html