From: Phillip Wood <phillip.wood123@gmail.com>
To: Heather Lapointe via GitGitGadget <gitgitgadget@gmail.com>,
git@vger.kernel.org
Cc: "René Scharfe" <l.s.r@web.de>,
"Heather Lapointe" <alpha@alphaservcomputing.solutions>
Subject: Re: [PATCH v3 0/9] archive: Add --recurse-submodules to git-archive command
Date: Mon, 17 Oct 2022 14:57:13 +0100 [thread overview]
Message-ID: <8acd4fac-491f-7ab5-88be-b7804b37d23b@dunelm.org.uk> (raw)
In-Reply-To: <pull.1359.v3.git.git.1665973401.gitgitgadget@gmail.com>
Hi Heather
On 17/10/2022 03:23, Heather Lapointe via GitGitGadget wrote:
> This makes it possible to include submodule contents in an archive command.
>
> The inspiration for this change comes from this Github thread,
> https://github.com/dear-github/dear-github/issues/214, with at least 160
> 👍🏻 's at the time of writing. (I stumbled upon it because I wanted it as
> well).
>
> I figured the underlying implementation wouldn't be too difficult with most
> of the plumbing already in place, so I decided to add the relevant logic to
> the client git-archive command.
>
> One of the trickier parts of this implementation involved teaching read_tree
> about submodules. Some of the troublesome areas were still using the
> the_repository references to look up commit or tree or oid information. I
> ended up deciding that read_tree_fn_t would probably be best off having a
> concrete repo reference since it allows changing the context to a subrepo
> where needed (even though some of the usages did not need it specifically).
>
> I am open to feedback since this is all quite new to me :)
I've had a quick read through and I thought this patch series was well
structured and easy to follow for someone like me who is not familiar
with the archive code. I've left a few mostly high-level comments on
some of the individual patches. The commit messages are all pretty brief
and would benefit from a bit more explaintion of why the changes are
being made. From a brief read through the code changes themselves all
looked pretty good.
Best Wishes
Phillip
> Alphadelta14 (1):
> tree: do not use the_repository for tree traversal methods.
>
> Heather Lapointe (8):
> tree: update cases to use repo_ tree methods
> tree: increase test coverage for tree.c
> tree: handle submodule case for read_tree_at properly
> tree: add repository parameter to read_tree_fn_t
> archive: pass repo objects to write_archive handlers
> archive: remove global repository from archive_args
> archive: add --recurse-submodules to git-archive command
> archive: add tests for git archive --recurse-submodules
>
> Documentation/git-archive.txt | 6 +-
> Makefile | 1 +
> archive-tar.c | 15 ++--
> archive-zip.c | 15 ++--
> archive.c | 138 ++++++++++++++++++++----------
> archive.h | 16 +++-
> builtin/checkout.c | 4 +-
> builtin/log.c | 4 +-
> builtin/ls-files.c | 8 +-
> builtin/ls-tree.c | 34 +++++---
> merge-recursive.c | 4 +-
> merge.c | 4 +-
> reset.c | 2 +-
> revision.c | 4 +-
> sequencer.c | 6 +-
> sparse-index.c | 4 +-
> t/helper/test-tool.c | 1 +
> t/helper/test-tool.h | 1 +
> t/helper/test-tree-read-tree-at.c | 41 +++++++++
> t/t1023-tree-read-tree-at.sh | 65 ++++++++++++++
> t/t5005-archive-submodules.sh | 83 ++++++++++++++++++
> tree.c | 93 ++++++++++++++------
> tree.h | 16 ++--
> wt-status.c | 4 +-
> 24 files changed, 448 insertions(+), 121 deletions(-)
> create mode 100644 t/helper/test-tree-read-tree-at.c
> create mode 100755 t/t1023-tree-read-tree-at.sh
> create mode 100755 t/t5005-archive-submodules.sh
>
>
> base-commit: e85701b4af5b7c2a9f3a1b07858703318dce365d
> Published-As: https://github.com/gitgitgadget/git/releases/tag/pr-git-1359%2FAlphadelta14%2Farchive-recurse-submodules-v3
> Fetch-It-Via: git fetch https://github.com/gitgitgadget/git pr-git-1359/Alphadelta14/archive-recurse-submodules-v3
> Pull-Request: https://github.com/git/git/pull/1359
>
> Range-diff vs v2:
>
> -: ----------- > 1: 79959a54eb4 tree: do not use the_repository for tree traversal methods.
> -: ----------- > 2: 2291e0f9b5c tree: update cases to use repo_ tree methods
> -: ----------- > 3: 9a07c6932f4 tree: increase test coverage for tree.c
> 2: 68f7830c6d9 ! 4: d3d1738e670 archive: fix a case of submodule in submodule traversal
> @@
> ## Metadata ##
> -Author: Alphadelta14 <alpha@alphaservcomputing.solutions>
> +Author: Heather Lapointe <alpha@alphaservcomputing.solutions>
>
> ## Commit message ##
> - archive: fix a case of submodule in submodule traversal
> + tree: handle submodule case for read_tree_at properly
>
> - repo_submodule_init actually expects the path relative to submodule_prefix.
> - We preform a simple strip to the correct path.
> + This supports traversal into an actual submodule for read_tree_at.
> + The logic is blocked on pathspec->recurse_submodules now,
> + but previously hadn't been executed due to all fn() cases
> + returning early for submodules.
>
> - Signed-off-by: Alphadelta14 <alpha@alphaservcomputing.solutions>
> + Signed-off-by: Heather Lapointe <alpha@alphaservcomputing.solutions>
>
> ## tree.c ##
> +@@
> + #include "alloc.h"
> + #include "tree-walk.h"
> + #include "repository.h"
> ++#include "pathspec.h"
> +
> + const char *tree_type = "tree";
> +
> @@ tree.c: int read_tree_at(struct repository *r,
> - struct repository subrepo;
> - struct repository* subrepo_p = &subrepo;
> - struct tree* submodule_tree;
> + return -1;
> + }
> +
> +- if (S_ISDIR(entry.mode))
> ++ if (S_ISDIR(entry.mode)) {
> + oidcpy(&oid, &entry.oid);
> +- else if (S_ISGITLINK(entry.mode)) {
> +- struct commit *commit;
> +
> +- commit = lookup_commit(r, &entry.oid);
> ++ len = tree_entry_len(&entry);
> ++ strbuf_add(base, entry.path, len);
> ++ strbuf_addch(base, '/');
> ++ retval = read_tree_at(r, lookup_tree(r, &oid),
> ++ base, pathspec,
> ++ fn, context);
> ++ strbuf_setlen(base, oldlen);
> ++ if (retval)
> ++ return -1;
> ++ } else if (pathspec->recurse_submodules && S_ISGITLINK(entry.mode)) {
> ++ struct commit *commit;
> ++ struct repository subrepo;
> ++ struct repository* subrepo_p = &subrepo;
> ++ struct tree* submodule_tree;
> + char *submodule_rel_path;
> + int name_base_len = 0;
> -
> -- if (repo_submodule_init(subrepo_p, r, entry.path, null_oid()))
> -- die("couldn't init submodule %s%s", base->buf, entry.path);
> ++
> + len = tree_entry_len(&entry);
> + strbuf_add(base, entry.path, len);
> + submodule_rel_path = base->buf;
> @@ tree.c: int read_tree_at(struct repository *r,
> +
> + if (repo_submodule_init(subrepo_p, r, submodule_rel_path, null_oid()))
> + die("couldn't init submodule %s", base->buf);
> -
> - if (repo_read_index(subrepo_p) < 0)
> - die("index file corrupt");
> -
> - commit = lookup_commit(subrepo_p, &entry.oid);
> ++
> ++ if (repo_read_index(subrepo_p) < 0)
> ++ die("index file corrupt");
> ++
> ++ commit = lookup_commit(subrepo_p, &entry.oid);
> if (!commit)
> - die("Commit %s in submodule path %s%s not found",
> + die("Commit %s in submodule path %s not found",
> oid_to_hex(&entry.oid),
> - base->buf, entry.path);
> -+ base->buf);
> -
> - if (repo_parse_commit(subrepo_p, commit))
> +-
> +- // FIXME: This is the wrong repo instance (it refers to the superproject)
> +- // it will always fail as is (will fix in later patch)
> +- // This current codepath isn't executed by any existing callbacks
> +- // so it wouldn't show up as an issue at this time.
> +- if (repo_parse_commit(r, commit))
> - die("Invalid commit %s in submodule path %s%s",
> ++ base->buf);
> ++
> ++ if (repo_parse_commit(subrepo_p, commit))
> + die("Invalid commit %s in submodule path %s",
> oid_to_hex(&entry.oid),
> - base->buf, entry.path);
> + base->buf);
>
> - submodule_tree = repo_get_commit_tree(subrepo_p, commit);
> - oidcpy(&oid, submodule_tree ? &submodule_tree->object.oid : NULL);
> +- oidcpy(&oid, get_commit_tree_oid(commit));
> +- }
> +- else
> +- continue;
> ++ submodule_tree = repo_get_commit_tree(subrepo_p, commit);
> ++ oidcpy(&oid, submodule_tree ? &submodule_tree->object.oid : NULL);
>
> -- len = tree_entry_len(&entry);
> -- strbuf_add(base, entry.path, len);
> - strbuf_addch(base, '/');
> +- len = tree_entry_len(&entry);
> +- strbuf_add(base, entry.path, len);
> +- strbuf_addch(base, '/');
> +- retval = read_tree_at(r, lookup_tree(r, &oid),
> +- base, pathspec,
> +- fn, context);
> +- strbuf_setlen(base, oldlen);
> +- if (retval)
> +- return -1;
> ++ strbuf_addch(base, '/');
> +
> - retval = read_tree_at(subrepo_p, lookup_tree(subrepo_p, &oid),
> - base, pathspec,
> - fn, context);
> - if (retval) {
> -- die("failed to read tree for %s%s", base->buf, entry.path);
> ++ retval = read_tree_at(subrepo_p, lookup_tree(subrepo_p, &oid),
> ++ base, pathspec,
> ++ fn, context);
> ++ if (retval)
> + die("failed to read tree for %s", base->buf);
> - return -1;
> - }
> - strbuf_setlen(base, oldlen);
> ++ strbuf_setlen(base, oldlen);
> ++ repo_clear(subrepo_p);
> ++ }
> ++ // else, this is a file (or a submodule, but no pathspec->recurse_submodules)
> + }
> + return 0;
> + }
> -: ----------- > 5: 376345fdf66 tree: add repository parameter to read_tree_fn_t
> 1: 41664a59029 ! 6: 1b9b049d64f archive: add --recurse-submodules to git-archive command
> @@
> ## Metadata ##
> -Author: Alphadelta14 <alpha@alphaservcomputing.solutions>
> +Author: Heather Lapointe <alpha@alphaservcomputing.solutions>
>
> ## Commit message ##
> - archive: add --recurse-submodules to git-archive command
> + archive: pass repo objects to write_archive handlers
>
> - This makes it possible to include submodule contents in an archive command.
> -
> - This required updating the general read_tree callbacks to support sub-repos
> - by not using the_repository global references where possible.
> -
> - archive: update streaming to use target repo
> - archive: add test cases for git archive --recurse-submodules
> + Use contextual repos instead of the_repository or args->repo
> + to ensure that submodules will be handled correctly
> + since they use multiple repo instances.
>
> Signed-off-by: Heather Lapointe <alpha@alphaservcomputing.solutions>
>
> @@ archive-tar.c: static unsigned long offset;
> static int tar_umask = 002;
>
> static int write_tar_filter_archive(const struct archiver *ar,
> -+ struct repository *repo,
> ++ struct repository *repo,
> struct archiver_args *args);
>
> /*
> @@ archive-tar.c: static void write_extended_header(struct archiver_args *args,
> }
>
> -static int write_tar_entry(struct archiver_args *args,
> -+static int write_tar_entry(struct repository *repo,
> ++static int write_tar_entry(
> ++ struct repository *repo,
> + struct archiver_args *args,
> const struct object_id *oid,
> const char *path, size_t pathlen,
> @@ archive-tar.c: static void tgz_write_block(const void *data)
> static const char internal_gzip_command[] = "git archive gzip";
>
> static int write_tar_filter_archive(const struct archiver *ar,
> -+ struct repository *repo,
> ++ struct repository *repo,
> struct archiver_args *args)
> {
> #if ZLIB_VERNUM >= 0x1221
> @@ archive-zip.c: static int entry_is_binary(struct index_state *istate, const char
> #define STREAM_BUFFER_SIZE (1024 * 16)
>
> -static int write_zip_entry(struct archiver_args *args,
> -+static int write_zip_entry(struct repository *repo,
> ++static int write_zip_entry(
> ++ struct repository *repo,
> + struct archiver_args *args,
> const struct object_id *oid,
> const char *path, size_t pathlen,
> @@ archive-zip.c: static int archive_zip_config(const char *var, const char *value,
> }
>
> static int write_zip_archive(const struct archiver *ar UNUSED,
> -+ struct repository *repo,
> ++ struct repository *repo,
> struct archiver_args *args)
> {
> int err;
> @@ archive-zip.c: static int write_zip_archive(const struct archiver *ar UNUSED,
>
>
> ## archive.c ##
> -@@
> - #include "unpack-trees.h"
> - #include "dir.h"
> - #include "quote.h"
> -+#include "submodule.h"
> -
> - static char const * const archive_usage[] = {
> - N_("git archive [<options>] <tree-ish> [<path>...]"),
> -@@ archive.c: static void format_subst(const struct commit *commit,
> - }
> -
> - static void *object_file_to_archive(const struct archiver_args *args,
> -+ struct repository *repo,
> - const char *path,
> - const struct object_id *oid,
> - unsigned int mode,
> -@@ archive.c: static void *object_file_to_archive(const struct archiver_args *args,
> - (args->tree ? &args->tree->object.oid : NULL), oid);
> -
> - path += args->baselen;
> -- buffer = read_object_file(oid, type, sizep);
> -+ buffer = repo_read_object_file(repo, oid, type, sizep);
> - if (buffer && S_ISREG(mode)) {
> - struct strbuf buf = STRBUF_INIT;
> - size_t size = 0;
> -
> - strbuf_attach(&buf, buffer, *sizep, *sizep + 1);
> -- convert_to_working_tree(args->repo->index, path, buf.buf, buf.len, &buf, &meta);
> -+ convert_to_working_tree(repo->index, path, buf.buf, buf.len, &buf, &meta);
> - if (commit)
> - format_subst(commit, buf.buf, buf.len, &buf, args->pretty_ctx);
> - buffer = strbuf_detach(&buf, &size);
> @@ archive.c: static int check_attr_export_subst(const struct attr_check *check)
> return check && ATTR_TRUE(check->items[1].value);
> }
>
> -static int write_archive_entry(const struct object_id *oid, const char *base,
> -+static int write_archive_entry(struct repository *repo, const struct object_id *oid, const char *base,
> ++static int write_archive_entry(
> ++ struct repository *repo,
> ++ const struct object_id *oid, const char *base,
> int baselen, const char *filename, unsigned mode,
> void *context)
> {
> @@ archive.c: static int write_archive_entry(const struct object_id *oid, const cha
> + err = write_entry(repo, args, oid, path.buf, path.len, mode, NULL, 0);
> if (err)
> return err;
> -- return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
> -+ return READ_TREE_RECURSIVE;
> - }
> -
> - if (args->verbose)
> + return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);
> @@ archive.c: static int write_archive_entry(const struct object_id *oid, const char *base,
>
> /* Stream it? */
> if (S_ISREG(mode) && !args->convert &&
> - oid_object_info(args->repo, oid, &size) == OBJ_BLOB &&
> -- size > big_file_threshold)
> -- return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
> + oid_object_info(repo, oid, &size) == OBJ_BLOB &&
> -+ size > big_file_threshold) {
> -+ err = write_entry(repo, args, oid, path.buf, path.len, mode, NULL, size);
> -+ if (err) {
> -+ die("Failed to write file %.*s", (int)path.len, path.buf);
> -+ }
> -+ return err;
> -+ }
> + size > big_file_threshold)
> +- return write_entry(args, oid, path.buf, path.len, mode, NULL, size);
> ++ return write_entry(repo, args, oid, path.buf, path.len, mode, NULL, size);
>
> -- buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
> -+ buffer = object_file_to_archive(args, repo, path.buf, oid, mode, &type, &size);
> + buffer = object_file_to_archive(args, path.buf, oid, mode, &type, &size);
> if (!buffer)
> return error(_("cannot read '%s'"), oid_to_hex(oid));
> - err = write_entry(args, oid, path.buf, path.len, mode, buffer, size);
> @@ archive.c: static void queue_directory(const struct object_id *oid,
> }
>
> -static int write_directory(struct archiver_context *c)
> -+static void queue_submodule(struct repository *superproject,
> -+ const struct object_id *oid,
> -+ struct strbuf *base, const char *filename,
> -+ unsigned mode, struct archiver_context *c)
> -+{
> -+ struct repository subrepo;
> -+
> -+ if (repo_submodule_init(&subrepo, superproject, filename, null_oid()))
> -+ return;
> -+
> -+ if (repo_read_index(&subrepo) < 0)
> -+ die("index file corrupt");
> -+
> -+ queue_directory(oid, base, filename, mode, c);
> -+
> -+ repo_clear(&subrepo);
> -+}
> -+
> -+static int write_directory(struct repository *repo, struct archiver_context *c)
> ++static int write_directory(
> ++ struct repository *repo,
> ++ struct archiver_context *c)
> {
> struct directory *d = c->bottom;
> int ret;
> @@ archive.c: static int write_directory(struct archiver_context *c)
> + write_directory(repo, c) ||
> + write_archive_entry(repo, &d->oid, d->path, d->baselen,
> d->path + d->baselen, d->mode,
> -- c) != READ_TREE_RECURSIVE;
> -+ c);
> + c) != READ_TREE_RECURSIVE;
> free(d);
> -- return ret ? -1 : 0;
> -+ if (ret == READ_TREE_RECURSIVE)
> -+ return 0;
> -+ return ret;
> - }
> -
> --static int queue_or_write_archive_entry(const struct object_id *oid,
> -+static int queue_or_write_archive_entry(
> -+ struct repository *repo, const struct object_id *oid,
> - struct strbuf *base, const char *filename,
> - unsigned mode, void *context)
> - {
> -@@ archive.c: static int queue_or_write_archive_entry(const struct object_id *oid,
> - /* Borrow base, but restore its original value when done. */
> - strbuf_addstr(base, filename);
> - strbuf_addch(base, '/');
> -- check = get_archive_attrs(c->args->repo->index, base->buf);
> -+ check = get_archive_attrs(repo->index, base->buf);
> - strbuf_setlen(base, baselen);
> -
> - if (check_attr_export_ignore(check))
> - return 0;
> - queue_directory(oid, base, filename, mode, c);
> +@@ archive.c: static int queue_or_write_archive_entry(
> return READ_TREE_RECURSIVE;
> -+ } else if (c->args->recurse_submodules && S_ISGITLINK(mode)) {
> -+ if (is_submodule_active(repo, filename)) {
> -+ queue_submodule(repo, oid, base, filename, mode, c);
> -+ return READ_TREE_RECURSIVE;
> -+ }
> }
>
> - if (write_directory(c))
> -+ if (write_directory(repo, c))
> ++ if (write_directory(r, c))
> return -1;
> - return write_archive_entry(oid, base->buf, base->len, filename, mode,
> -+ return write_archive_entry(repo, oid, base->buf, base->len, filename, mode,
> ++ return write_archive_entry(r, oid, base->buf, base->len, filename, mode,
> context);
> }
>
> @@ archive.c: struct extra_file_info {
> };
>
> -int write_archive_entries(struct archiver_args *args,
> -+int write_archive_entries(struct repository *repo,
> ++int write_archive_entries(
> ++ struct repository *repo,
> + struct archiver_args *args,
> write_archive_entry_fn_t write_entry)
> {
> @@ archive.c: int write_archive_entries(struct archiver_args *args,
> len, 040777, NULL, 0);
> if (err)
> return err;
> -@@ archive.c: int write_archive_entries(struct archiver_args *args,
> - memset(&opts, 0, sizeof(opts));
> - opts.index_only = 1;
> - opts.head_idx = -1;
> -- opts.src_index = args->repo->index;
> -- opts.dst_index = args->repo->index;
> -+ opts.src_index = repo->index;
> -+ opts.dst_index = repo->index;
> - opts.fn = oneway_merge;
> - init_tree_desc(&t, args->tree->buffer, args->tree->size);
> - if (unpack_trees(1, &t, &opts))
> -@@ archive.c: int write_archive_entries(struct archiver_args *args,
> - git_attr_set_direction(GIT_ATTR_INDEX);
> - }
> -
> -- err = read_tree(args->repo, args->tree,
> -+ err = read_tree(repo, args->tree,
> - &args->pathspec,
> - queue_or_write_archive_entry,
> - &context);
> @@ archive.c: int write_archive_entries(struct archiver_args *args,
> if (strbuf_read_file(&content, path, info->stat.st_size) < 0)
> err = error_errno(_("cannot read '%s'"), path);
> @@ archive.c: int write_archive_entries(struct archiver_args *args,
> path, strlen(path),
> canon_mode(info->stat.st_mode),
> info->content, info->stat.st_size);
> -@@ archive.c: struct path_exists_context {
> - struct archiver_args *args;
> - };
> -
> --static int reject_entry(const struct object_id *oid UNUSED,
> -+static int reject_entry(struct repository *repo, const struct object_id *oid UNUSED,
> - struct strbuf *base,
> - const char *filename, unsigned mode,
> - void *context)
> -@@ archive.c: static int reject_entry(const struct object_id *oid UNUSED,
> - struct strbuf sb = STRBUF_INIT;
> - strbuf_addbuf(&sb, base);
> - strbuf_addstr(&sb, filename);
> -- if (!match_pathspec(ctx->args->repo->index,
> -+ if (!match_pathspec(repo->index,
> - &ctx->pathspec,
> - sb.buf, sb.len, 0, NULL, 1))
> - ret = READ_TREE_RECURSIVE;
> -@@ archive.c: static void parse_pathspec_arg(const char **pathspec,
> - PATHSPEC_PREFER_FULL,
> - "", pathspec);
> - ar_args->pathspec.recursive = 1;
> -+ ar_args->pathspec.recurse_submodules = ar_args->recurse_submodules;
> - if (pathspec) {
> - while (*pathspec) {
> - if (**pathspec && !path_exists(ar_args, *pathspec))
> -@@ archive.c: static int parse_archive_args(int argc, const char **argv,
> - int verbose = 0;
> - int i;
> - int list = 0;
> -+ int recurse_submodules = 0;
> - int worktree_attributes = 0;
> - struct option opts[] = {
> - OPT_GROUP(""),
> -@@ archive.c: static int parse_archive_args(int argc, const char **argv,
> - add_file_cb, (intptr_t)&base },
> - OPT_STRING('o', "output", &output, N_("file"),
> - N_("write the archive to this file")),
> -+ OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
> -+ N_("include submodules in archive")),
> - OPT_BOOL(0, "worktree-attributes", &worktree_attributes,
> - N_("read .gitattributes in working directory")),
> - OPT__VERBOSE(&verbose, N_("report archived files on stderr")),
> -@@ archive.c: static int parse_archive_args(int argc, const char **argv,
> - args->base = base;
> - args->baselen = strlen(base);
> - args->worktree_attributes = worktree_attributes;
> -+ args->recurse_submodules = recurse_submodules;
> -
> - return argc;
> - }
> @@ archive.c: int write_archive(int argc, const char **argv, const char *prefix,
> parse_treeish_arg(argv, &args, prefix, remote);
> parse_pathspec_arg(argv + 1, &args);
> @@ archive.c: int write_archive(int argc, const char **argv, const char *prefix,
> free(args.refname);
>
> ## archive.h ##
> -@@ archive.h: struct archiver_args {
> - timestamp_t time;
> - struct pathspec pathspec;
> - unsigned int verbose : 1;
> -+ unsigned int recurse_submodules : 1;
> - unsigned int worktree_attributes : 1;
> - unsigned int convert : 1;
> - int compression_level;
> @@ archive.h: const char *archive_format_from_filename(const char *filename);
> #define ARCHIVER_HIGH_COMPRESSION_LEVELS 4
> struct archiver {
> const char *name;
> - int (*write_archive)(const struct archiver *, struct archiver_args *);
> -+ int (*write_archive)(const struct archiver *, struct repository *repo, struct archiver_args *);
> ++ int (*write_archive)(
> ++ const struct archiver *,
> ++ struct repository *,
> ++ struct archiver_args *);
> unsigned flags;
> char *filter_command;
> };
> @@ archive.h: void init_tar_archiver(void);
> void init_archivers(void);
>
> -typedef int (*write_archive_entry_fn_t)(struct archiver_args *args,
> -+typedef int (*write_archive_entry_fn_t)(struct repository *repo,
> ++typedef int (*write_archive_entry_fn_t)(
> ++ struct repository *repo,
> + struct archiver_args *args,
> const struct object_id *oid,
> const char *path, size_t pathlen,
> @@ archive.h: void init_tar_archiver(void);
> void *buffer, unsigned long size);
>
> -int write_archive_entries(struct archiver_args *args, write_archive_entry_fn_t write_entry);
> -+int write_archive_entries(struct repository *repo, struct archiver_args *args, write_archive_entry_fn_t write_entry);
> ++int write_archive_entries(
> ++ struct repository *repo,
> ++ struct archiver_args *args,
> ++ write_archive_entry_fn_t write_entry);
>
> #endif /* ARCHIVE_H */
> -
> - ## builtin/checkout.c ##
> -@@ builtin/checkout.c: static int post_checkout_hook(struct commit *old_commit, struct commit *new_comm
> -
> - }
> -
> --static int update_some(const struct object_id *oid, struct strbuf *base,
> -+static int update_some(struct repository *repo UNUSED, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode, void *context UNUSED)
> - {
> - int len;
> -
> - ## builtin/log.c ##
> -@@ builtin/log.c: static int show_tag_object(const struct object_id *oid, struct rev_info *rev)
> - return 0;
> - }
> -
> --static int show_tree_object(const struct object_id *oid UNUSED,
> -+static int show_tree_object(struct repository *repo UNUSED, const struct object_id *oid UNUSED,
> - struct strbuf *base UNUSED,
> - const char *pathname, unsigned mode,
> - void *context)
> -
> - ## builtin/ls-files.c ##
> -@@ builtin/ls-files.c: static int get_common_prefix_len(const char *common_prefix)
> - return common_prefix_len;
> - }
> -
> --static int read_one_entry_opt(struct index_state *istate,
> -+static int read_one_entry_opt(struct repository *repo UNUSED, struct index_state *istate,
> - const struct object_id *oid,
> - struct strbuf *base,
> - const char *pathname,
> -@@ builtin/ls-files.c: static int read_one_entry_opt(struct index_state *istate,
> - return add_index_entry(istate, ce, opt);
> - }
> -
> --static int read_one_entry(const struct object_id *oid, struct strbuf *base,
> -+static int read_one_entry(struct repository *repo, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode,
> - void *context)
> - {
> - struct index_state *istate = context;
> -- return read_one_entry_opt(istate, oid, base, pathname,
> -+ return read_one_entry_opt(repo, istate, oid, base, pathname,
> - mode,
> - ADD_CACHE_OK_TO_ADD|ADD_CACHE_SKIP_DFCHECK);
> - }
> -@@ builtin/ls-files.c: static int read_one_entry(const struct object_id *oid, struct strbuf *base,
> - * This is used when the caller knows there is no existing entries at
> - * the stage that will conflict with the entry being added.
> - */
> --static int read_one_entry_quick(const struct object_id *oid, struct strbuf *base,
> -+static int read_one_entry_quick(struct repository *repo, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode,
> - void *context)
> - {
> - struct index_state *istate = context;
> -- return read_one_entry_opt(istate, oid, base, pathname,
> -+ return read_one_entry_opt(repo, istate, oid, base, pathname,
> - mode, ADD_CACHE_JUST_APPEND);
> - }
> -
> -
> - ## builtin/ls-tree.c ##
> -@@ builtin/ls-tree.c: static int show_recursive(const char *base, size_t baselen, const char *pathname
> - return 0;
> - }
> -
> --static int show_tree_fmt(const struct object_id *oid, struct strbuf *base,
> -+static int show_tree_fmt(struct repository *repo UNUSED, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode, void *context UNUSED)
> - {
> - size_t baselen;
> -@@ builtin/ls-tree.c: static void show_tree_common_default_long(struct strbuf *base,
> - strbuf_setlen(base, baselen);
> - }
> -
> --static int show_tree_default(const struct object_id *oid, struct strbuf *base,
> -+static int show_tree_default(struct repository *repo UNUSED, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode,
> - void *context UNUSED)
> - {
> -@@ builtin/ls-tree.c: static int show_tree_default(const struct object_id *oid, struct strbuf *base,
> - return recurse;
> - }
> -
> --static int show_tree_long(const struct object_id *oid, struct strbuf *base,
> -+static int show_tree_long(struct repository *repo, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode,
> - void *context UNUSED)
> - {
> -@@ builtin/ls-tree.c: static int show_tree_long(const struct object_id *oid, struct strbuf *base,
> -
> - if (data.type == OBJ_BLOB) {
> - unsigned long size;
> -- if (oid_object_info(the_repository, data.oid, &size) == OBJ_BAD)
> -+ if (oid_object_info(repo, data.oid, &size) == OBJ_BAD)
> - xsnprintf(size_text, sizeof(size_text), "BAD");
> - else
> - xsnprintf(size_text, sizeof(size_text),
> -@@ builtin/ls-tree.c: static int show_tree_long(const struct object_id *oid, struct strbuf *base,
> - }
> -
> - printf("%06o %s %s %7s\t", data.mode, type_name(data.type),
> -- find_unique_abbrev(data.oid, abbrev), size_text);
> -+ repo_find_unique_abbrev(repo, data.oid, abbrev), size_text);
> - show_tree_common_default_long(base, pathname, data.base->len);
> - return recurse;
> - }
> -
> --static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
> -+static int show_tree_name_only(struct repository *repo UNUSED, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode,
> - void *context UNUSED)
> - {
> -@@ builtin/ls-tree.c: static int show_tree_name_only(const struct object_id *oid, struct strbuf *base,
> - return recurse;
> - }
> -
> --static int show_tree_object(const struct object_id *oid, struct strbuf *base,
> -+static int show_tree_object(struct repository *repo, const struct object_id *oid, struct strbuf *base,
> - const char *pathname, unsigned mode,
> - void *context UNUSED)
> - {
> -@@ builtin/ls-tree.c: static int show_tree_object(const struct object_id *oid, struct strbuf *base,
> - if (early >= 0)
> - return early;
> -
> -- printf("%s%c", find_unique_abbrev(oid, abbrev), line_termination);
> -+ printf("%s%c", repo_find_unique_abbrev(repo, oid, abbrev), line_termination);
> - return recurse;
> - }
> -
> -
> - ## list-objects.c ##
> -@@ list-objects.c: static void process_tree(struct traversal_context *ctx,
> - !revs->include_check_obj(&tree->object, revs->include_check_data))
> - return;
> -
> -- failed_parse = parse_tree_gently(tree, 1);
> -+ failed_parse = parse_tree_gently(revs->repo, tree, 1);
> - if (failed_parse) {
> - if (revs->ignore_missing_links)
> - return;
> -
> - ## merge-recursive.c ##
> -@@ merge-recursive.c: static void unpack_trees_finish(struct merge_options *opt)
> - clear_unpack_trees_porcelain(&opt->priv->unpack_opts);
> - }
> -
> --static int save_files_dirs(const struct object_id *oid UNUSED,
> -+static int save_files_dirs(struct repository *repo UNUSED, const struct object_id *oid UNUSED,
> - struct strbuf *base, const char *path,
> - unsigned int mode, void *context)
> - {
> -
> - ## revision.c ##
> -@@ revision.c: static void mark_tree_contents_uninteresting(struct repository *r,
> - struct tree_desc desc;
> - struct name_entry entry;
> -
> -- if (parse_tree_gently(tree, 1) < 0)
> -+ if (parse_tree_gently(r, tree, 1) < 0)
> - return;
> -
> - init_tree_desc(&desc, tree->buffer, tree->size);
> -@@ revision.c: static void add_children_by_path(struct repository *r,
> - if (!tree)
> - return;
> -
> -- if (parse_tree_gently(tree, 1) < 0)
> -+ if (parse_tree_gently(r, tree, 1) < 0)
> - return;
> -
> - init_tree_desc(&desc, tree->buffer, tree->size);
> -
> - ## sparse-index.c ##
> -@@ sparse-index.c: static void set_index_entry(struct index_state *istate, int nr, struct cache_ent
> - add_name_hash(istate, ce);
> - }
> -
> --static int add_path_to_index(const struct object_id *oid,
> -+static int add_path_to_index(struct repository *repo UNUSED, const struct object_id *oid,
> - struct strbuf *base, const char *path,
> - unsigned int mode, void *context)
> - {
> -
> - ## t/t5005-archive-submodules.sh (new) ##
> -@@
> -+#!/bin/sh
> -+
> -+test_description='git archive --recurse-submodules test'
> -+
> -+. ./test-lib.sh
> -+. "$TEST_DIRECTORY"/lib-submodule-update.sh
> -+
> -+test_expect_success 'setup' '
> -+ create_lib_submodule_repo &&
> -+ git -C submodule_update_repo checkout valid_sub1 &&
> -+ git -C submodule_update_repo submodule update
> -+'
> -+
> -+check_tar() {
> -+ tarfile=$1.tar
> -+ listfile=$1.lst
> -+ dir=$1
> -+ dir_with_prefix=$dir/$2
> -+
> -+ test_expect_success ' extract tar archive' '
> -+ (mkdir $dir && cd $dir && "$TAR" xf -) <$tarfile
> -+ '
> -+}
> -+
> -+check_added() {
> -+ dir=$1
> -+ path_in_fs=$2
> -+ path_in_archive=$3
> -+
> -+ test_expect_success " validate extra file $path_in_archive" '
> -+ test -f $dir/$path_in_archive &&
> -+ diff -r $path_in_fs $dir/$path_in_archive
> -+ '
> -+}
> -+
> -+check_not_added() {
> -+ dir=$1
> -+ path_in_archive=$2
> -+
> -+ test_expect_success " validate unpresent file $path_in_archive" '
> -+ ! test -f $dir/$path_in_archive &&
> -+ ! test -d $dir/$path_in_archive
> -+ '
> -+}
> -+
> -+test_expect_success 'archive without recurse, non-init' '
> -+ reset_work_tree_to valid_sub1 &&
> -+ git -C submodule_update archive HEAD >b.tar
> -+'
> -+
> -+check_tar b
> -+check_added b submodule_update/file1 file1
> -+check_not_added b sub1/file1
> -+
> -+test_expect_success 'archive with recurse, non-init' '
> -+ reset_work_tree_to valid_sub1 &&
> -+ ! git -C submodule_update archive --recurse-submodules HEAD >b2-err.tar
> -+'
> -+
> -+test_expect_success 'archive with recurse, init' '
> -+ reset_work_tree_to valid_sub1 &&
> -+ git -C submodule_update submodule update --init &&
> -+ git -C submodule_update ls-files --recurse-submodules &&
> -+ git -C submodule_update ls-tree HEAD &&
> -+ git -C submodule_update archive --recurse-submodules HEAD >b2.tar
> -+'
> -+
> -+check_tar b2
> -+check_added b2 submodule_update/sub1/file1 sub1/file1
> -+
> -+test_expect_success 'archive with recurse with big files' '
> -+ reset_work_tree_to valid_sub1 &&
> -+ test_config core.bigfilethreshold 1 &&
> -+ git -C submodule_update submodule update --init &&
> -+ git -C submodule_update ls-files --recurse-submodules &&
> -+ git -C submodule_update ls-tree HEAD &&
> -+ git -C submodule_update archive --recurse-submodules HEAD >b3.tar
> -+'
> -+
> -+check_tar b3
> -+check_added b3 submodule_update/sub1/file1 sub1/file1
> -+
> -+
> -+test_done
> -
> - ## tree.c ##
> -@@
> - #include "alloc.h"
> - #include "tree-walk.h"
> - #include "repository.h"
> -+#include "pathspec.h"
> -
> - const char *tree_type = "tree";
> -
> -@@ tree.c: int read_tree_at(struct repository *r,
> - int len, oldlen = base->len;
> - enum interesting retval = entry_not_interesting;
> -
> -- if (parse_tree(tree))
> -- return -1;
> -+ if (repo_parse_tree(r, tree))
> -+ die("Failed to parse tree");
> -
> - init_tree_desc(&desc, tree->buffer, tree->size);
> -
> -@@ tree.c: int read_tree_at(struct repository *r,
> - continue;
> - }
> -
> -- switch (fn(&entry.oid, base,
> -+ switch (fn(r, &entry.oid, base,
> - entry.path, entry.mode, context)) {
> - case 0:
> - continue;
> -@@ tree.c: int read_tree_at(struct repository *r,
> - return -1;
> - }
> -
> -- if (S_ISDIR(entry.mode))
> -+ if (S_ISDIR(entry.mode)) {
> - oidcpy(&oid, &entry.oid);
> -- else if (S_ISGITLINK(entry.mode)) {
> -+ len = tree_entry_len(&entry);
> -+ strbuf_add(base, entry.path, len);
> -+ strbuf_addch(base, '/');
> -+ retval = read_tree_at(r, lookup_tree(r, &oid),
> -+ base, pathspec,
> -+ fn, context);
> -+ strbuf_setlen(base, oldlen);
> -+ if (retval)
> -+ return -1;
> -+ } else if (pathspec->recurse_submodules && S_ISGITLINK(entry.mode)) {
> - struct commit *commit;
> -+ struct repository subrepo;
> -+ struct repository* subrepo_p = &subrepo;
> -+ struct tree* submodule_tree;
> -
> -- commit = lookup_commit(r, &entry.oid);
> -+ if (repo_submodule_init(subrepo_p, r, entry.path, null_oid()))
> -+ die("couldn't init submodule %s%s", base->buf, entry.path);
> -+
> -+ if (repo_read_index(subrepo_p) < 0)
> -+ die("index file corrupt");
> -+
> -+ commit = lookup_commit(subrepo_p, &entry.oid);
> - if (!commit)
> - die("Commit %s in submodule path %s%s not found",
> - oid_to_hex(&entry.oid),
> - base->buf, entry.path);
> -
> -- if (parse_commit(commit))
> -+ if (repo_parse_commit(subrepo_p, commit))
> - die("Invalid commit %s in submodule path %s%s",
> - oid_to_hex(&entry.oid),
> - base->buf, entry.path);
> -
> -- oidcpy(&oid, get_commit_tree_oid(commit));
> -+ submodule_tree = repo_get_commit_tree(subrepo_p, commit);
> -+ oidcpy(&oid, submodule_tree ? &submodule_tree->object.oid : NULL);
> -+
> -+ len = tree_entry_len(&entry);
> -+ strbuf_add(base, entry.path, len);
> -+ strbuf_addch(base, '/');
> -+ retval = read_tree_at(subrepo_p, lookup_tree(subrepo_p, &oid),
> -+ base, pathspec,
> -+ fn, context);
> -+ if (retval) {
> -+ die("failed to read tree for %s%s", base->buf, entry.path);
> -+ return -1;
> -+ }
> -+ strbuf_setlen(base, oldlen);
> -+ repo_clear(subrepo_p);
> - }
> -- else
> -- continue;
> -
> -- len = tree_entry_len(&entry);
> -- strbuf_add(base, entry.path, len);
> -- strbuf_addch(base, '/');
> -- retval = read_tree_at(r, lookup_tree(r, &oid),
> -- base, pathspec,
> -- fn, context);
> -- strbuf_setlen(base, oldlen);
> -- if (retval)
> -- return -1;
> - }
> - return 0;
> - }
> -@@ tree.c: int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size)
> - return 0;
> - }
> -
> --int parse_tree_gently(struct tree *item, int quiet_on_missing)
> -+int parse_tree_gently(struct repository *r, struct tree *item, int quiet_on_missing)
> - {
> - enum object_type type;
> - void *buffer;
> -@@ tree.c: int parse_tree_gently(struct tree *item, int quiet_on_missing)
> -
> - if (item->object.parsed)
> - return 0;
> -- buffer = read_object_file(&item->object.oid, &type, &size);
> -+ buffer = repo_read_object_file(r, &item->object.oid, &type, &size);
> - if (!buffer)
> - return quiet_on_missing ? -1 :
> - error("Could not read %s",
> -
> - ## tree.h ##
> -@@ tree.h: struct tree *lookup_tree(struct repository *r, const struct object_id *oid);
> -
> - int parse_tree_buffer(struct tree *item, void *buffer, unsigned long size);
> -
> --int parse_tree_gently(struct tree *tree, int quiet_on_missing);
> --static inline int parse_tree(struct tree *tree)
> -+int parse_tree_gently(struct repository *r, struct tree *tree, int quiet_on_missing);
> -+static inline int repo_parse_tree(struct repository *r, struct tree *tree)
> - {
> -- return parse_tree_gently(tree, 0);
> -+ return parse_tree_gently(r, tree, 0);
> - }
> -+#ifndef NO_THE_REPOSITORY_COMPATIBILITY_MACROS
> -+#define parse_tree(tree) repo_parse_tree(the_repository, tree)
> -+#endif
> - void free_tree_buffer(struct tree *tree);
> -
> - /* Parses and returns the tree in the given ent, chasing tags and commits. */
> -@@ tree.h: struct tree *parse_tree_indirect(const struct object_id *oid);
> - int cmp_cache_name_compare(const void *a_, const void *b_);
> -
> - #define READ_TREE_RECURSIVE 1
> --typedef int (*read_tree_fn_t)(const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
> -+typedef int (*read_tree_fn_t)(struct repository *, const struct object_id *, struct strbuf *, const char *, unsigned int, void *);
> -
> - int read_tree_at(struct repository *r,
> - struct tree *tree, struct strbuf *base,
> -
> - ## wt-status.c ##
> -@@ wt-status.c: static void wt_status_collect_changes_index(struct wt_status *s)
> - release_revisions(&rev);
> - }
> -
> --static int add_file_to_list(const struct object_id *oid,
> -+static int add_file_to_list(struct repository *repo UNUSED, const struct object_id *oid,
> - struct strbuf *base, const char *path,
> - unsigned int mode, void *context)
> - {
> -: ----------- > 7: 2443c9b1b6e archive: remove global repository from archive_args
> -: ----------- > 8: 4672e3d9586 archive: add --recurse-submodules to git-archive command
> -: ----------- > 9: f88ebbaf17c archive: add tests for git archive --recurse-submodules
>
next prev parent reply other threads:[~2022-10-17 13:57 UTC|newest]
Thread overview: 48+ messages / expand[flat|nested] mbox.gz Atom feed top
2022-10-12 17:52 [PATCH] archive: add --recurse-submodules to git-archive command Heather Lapointe via GitGitGadget
2022-10-13 11:35 ` [PATCH v2 0/2] archive: Add " Heather Lapointe via GitGitGadget
2022-10-13 11:35 ` [PATCH v2 1/2] archive: add " Alphadelta14 via GitGitGadget
2022-10-13 17:53 ` René Scharfe
2022-10-13 21:37 ` Heather Lapointe
2022-10-13 11:36 ` [PATCH v2 2/2] archive: fix a case of submodule in submodule traversal Alphadelta14 via GitGitGadget
2022-10-13 17:53 ` [PATCH v2 0/2] archive: Add --recurse-submodules to git-archive command René Scharfe
2022-10-13 21:23 ` Heather Lapointe
2022-10-14 9:47 ` René Scharfe
2022-10-17 2:23 ` [PATCH v3 0/9] " Heather Lapointe via GitGitGadget
2022-10-17 2:23 ` [PATCH v3 1/9] tree: do not use the_repository for tree traversal methods Alphadelta14 via GitGitGadget
2022-10-17 13:26 ` Junio C Hamano
2022-10-26 22:33 ` Glen Choo
2022-10-27 18:09 ` Jonathan Tan
2022-10-27 18:50 ` Junio C Hamano
2022-10-17 2:23 ` [PATCH v3 2/9] tree: update cases to use repo_ tree methods Heather Lapointe via GitGitGadget
2022-10-17 2:23 ` [PATCH v3 3/9] tree: increase test coverage for tree.c Heather Lapointe via GitGitGadget
2022-10-17 13:34 ` Phillip Wood
2022-10-17 13:36 ` Junio C Hamano
2022-10-27 18:28 ` Jonathan Tan
2022-10-17 2:23 ` [PATCH v3 4/9] tree: handle submodule case for read_tree_at properly Heather Lapointe via GitGitGadget
2022-10-17 13:48 ` Phillip Wood
2022-10-17 13:56 ` Junio C Hamano
2022-10-26 22:48 ` Glen Choo
2022-10-27 18:43 ` Jonathan Tan
2022-10-17 2:23 ` [PATCH v3 5/9] tree: add repository parameter to read_tree_fn_t Heather Lapointe via GitGitGadget
2022-10-17 2:23 ` [PATCH v3 6/9] archive: pass repo objects to write_archive handlers Heather Lapointe via GitGitGadget
2022-10-17 13:50 ` Phillip Wood
2022-10-17 2:23 ` [PATCH v3 7/9] archive: remove global repository from archive_args Heather Lapointe via GitGitGadget
2022-10-17 2:23 ` [PATCH v3 8/9] archive: add --recurse-submodules to git-archive command Heather Lapointe via GitGitGadget
2022-10-26 23:34 ` Glen Choo
2022-10-27 7:09 ` René Scharfe
2022-10-27 17:29 ` Glen Choo
2022-10-27 17:30 ` Glen Choo
2022-10-27 17:33 ` Glen Choo
2022-10-17 2:23 ` [PATCH v3 9/9] archive: add tests for git archive --recurse-submodules Heather Lapointe via GitGitGadget
2022-10-27 18:54 ` Jonathan Tan
2022-10-27 23:30 ` Glen Choo
2022-10-28 0:17 ` Ævar Arnfjörð Bjarmason
2022-10-17 13:57 ` Phillip Wood [this message]
2022-10-18 18:34 ` [PATCH v3 0/9] archive: Add --recurse-submodules to git-archive command Junio C Hamano
2022-10-18 18:48 ` Heather Lapointe
2022-10-19 16:16 ` Junio C Hamano
2022-10-19 20:44 ` Junio C Hamano
2022-10-20 1:21 ` Junio C Hamano
2022-10-21 1:43 ` Junio C Hamano
2022-10-26 22:14 ` Glen Choo
2022-10-28 18:18 ` Heather Lapointe
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
List information: http://vger.kernel.org/majordomo-info.html
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=8acd4fac-491f-7ab5-88be-b7804b37d23b@dunelm.org.uk \
--to=phillip.wood123@gmail.com \
--cc=alpha@alphaservcomputing.solutions \
--cc=git@vger.kernel.org \
--cc=gitgitgadget@gmail.com \
--cc=l.s.r@web.de \
--cc=phillip.wood@dunelm.org.uk \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
Code repositories for project(s) associated with this public inbox
https://80x24.org/mirrors/git.git
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).