{"thread":{"id":"45359","subject":"[PATCH 0/1] archive: learn to include submodules in output archive","startedAt":"2017-03-12T07:54:48Z","lastAt":"2017-03-13T23:18:15Z","messageCount":6,"participants":["Nikhil Benesch","Junio C Hamano","Stefan Beller"],"isPatch":true,"patchVersion":1,"patchTotal":1},"messages":[{"id":"313845","messageId":"20170312075404.23951-1-nikhil.benesch@gmail.com","threadId":"45359","inReplyTo":null,"subject":"[PATCH 0/1] archive: learn to include submodules in output archive","fromName":"Nikhil Benesch","fromEmail":"nikhil.benesch@gmail.com","sentAt":"2017-03-12T07:54:03Z","receivedAt":"2017-03-12T07:54:48Z","isPatch":true,"sender":{"key":"nikhil.benesch@gmail.com","avatar":null},"body":"Reviving an old patch from Lars Hjemli to teach `git archive` to\n`--recurse-submodules`, which is, in my opinion, a sorely needed feature. I'm\nafraid this is the first patch I've submitted for review, so I wasn't sure who\nto CC. Apologies if I've gotten the wrong folks.\n\nNikhil Benesch (1):\n  archive: learn to include submodules in output archive\n\n Documentation/git-archive.txt |   8 ++-\n archive.c                     |  22 +++++----\n archive.h                     |   1 +\n submodule.c                   |   2 +-\n submodule.h                   |   1 +\n t/t5005-archive-submodules.sh | 112 ++++++++++++++++++++++++++++++++++++++++++\n 6 files changed, 133 insertions(+), 13 deletions(-)\n create mode 100755 t/t5005-archive-submodules.sh\n\n-- \n2.12.0.244.g625568cd8.dirty\n\n"},{"id":"313846","messageId":"20170312075404.23951-2-nikhil.benesch@gmail.com","threadId":"45359","inReplyTo":"20170312075404.23951-1-nikhil.benesch@gmail.com","subject":"[PATCH 1/1] archive: learn to include submodules in output archive","fromName":"Nikhil Benesch","fromEmail":"nikhil.benesch@gmail.com","sentAt":"2017-03-12T07:54:04Z","receivedAt":"2017-03-12T07:55:00Z","isPatch":true,"sender":{"key":"nikhil.benesch@gmail.com","avatar":null},"body":"This commit is a revival of Lars Hjemli's 2009 patch to provide an\noption to include submodules in the output of `git archive`.\n\nThe `--recurse-submodules` option (named consistently with fetch, clone,\nand ls-files) will recursively traverse submodules in the repository and\nconsider their contents for inclusion in the output archive, subject to\nany pathspec filters. Like other commands that have learned\n`--recurse-submodules`, submodules that have not been checked out will\nnot be traversed.\n\nSigned-off-by: Nikhil Benesch <nikhil.benesch@gmail.com>\n---\n Documentation/git-archive.txt |   8 ++-\n archive.c                     |  22 +++++----\n archive.h                     |   1 +\n submodule.c                   |   2 +-\n submodule.h                   |   1 +\n t/t5005-archive-submodules.sh | 112 ++++++++++++++++++++++++++++++++++++++++++\n 6 files changed, 133 insertions(+), 13 deletions(-)\n create mode 100755 t/t5005-archive-submodules.sh\n\ndiff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt\nindex cfa1e4ebe..f223f9e05 100644\n--- a/Documentation/git-archive.txt\n+++ b/Documentation/git-archive.txt\n@@ -11,8 +11,8 @@ SYNOPSIS\n [verse]\n 'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]\n \t      [-o <file> | --output=<file>] [--worktree-attributes]\n-\t      [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>\n-\t      [<path>...]\n+\t      [--recurse-submodules] [--remote=<repo> [--exec=<git-upload-archive>]]\n+\t      <tree-ish> [<path>...]\n \n DESCRIPTION\n -----------\n@@ -59,6 +59,10 @@ OPTIONS\n \tLook for attributes in .gitattributes files in the working tree\n \tas well (see <<ATTRIBUTES>>).\n \n+--recurse-submodules::\n+\tRecursively include the contents of any checked-out submodules in\n+\tthe archive.\n+\n <extra>::\n \tThis can be any options that the archiver backend understands.\n \tSee next section.\ndiff --git a/archive.c b/archive.c\nindex 60b889198..8d060bad3 100644\n--- a/archive.c\n+++ b/archive.c\n@@ -7,6 +7,7 @@\n #include \"parse-options.h\"\n #include \"unpack-trees.h\"\n #include \"dir.h\"\n+#include \"submodule.h\"\n \n static char const * const archive_usage[] = {\n \tN_(\"git archive [<options>] <tree-ish> [<path>...]\"),\n@@ -132,18 +133,15 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,\n \t\targs->convert = ATTR_TRUE(check->items[1].value);\n \t}\n \n-\tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n-\t\tif (args->verbose)\n-\t\t\tfprintf(stderr, \"%.*s\\n\", (int)path.len, path.buf);\n-\t\terr = write_entry(args, sha1, path.buf, path.len, mode);\n-\t\tif (err)\n-\t\t\treturn err;\n-\t\treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n-\t}\n-\n \tif (args->verbose)\n \t\tfprintf(stderr, \"%.*s\\n\", (int)path.len, path.buf);\n-\treturn write_entry(args, sha1, path.buf, path.len, mode);\n+\terr = write_entry(args, sha1, path.buf, path.len, mode);\n+\tif (err)\n+\t\treturn err;\n+\tif (S_ISDIR(mode) || (S_ISGITLINK(mode) && args->recurse_submodules &&\n+\t\t\t      !add_submodule_odb(path_without_prefix)))\n+\t\treturn READ_TREE_RECURSIVE;\n+\treturn 0;\n }\n \n static int write_archive_entry_buf(const unsigned char *sha1, struct strbuf *base,\n@@ -411,6 +409,7 @@ static int parse_archive_args(int argc, const char **argv,\n \tint verbose = 0;\n \tint i;\n \tint list = 0;\n+\tint recurse_submodules = 0;\n \tint worktree_attributes = 0;\n \tstruct option opts[] = {\n \t\tOPT_GROUP(\"\"),\n@@ -419,6 +418,8 @@ static int parse_archive_args(int argc, const char **argv,\n \t\t\tN_(\"prepend prefix to each pathname in the archive\")),\n \t\tOPT_STRING('o', \"output\", &output, N_(\"file\"),\n \t\t\tN_(\"write the archive to this file\")),\n+\t\tOPT_BOOL(0, \"recurse-submodules\", &recurse_submodules,\n+\t\t\tN_(\"recurse through submodules\")),\n \t\tOPT_BOOL(0, \"worktree-attributes\", &worktree_attributes,\n \t\t\tN_(\"read .gitattributes in working directory\")),\n \t\tOPT__VERBOSE(&verbose, N_(\"report archived files on stderr\")),\n@@ -484,6 +485,7 @@ static int parse_archive_args(int argc, const char **argv,\n \t\t}\n \t}\n \targs->verbose = verbose;\n+\targs->recurse_submodules = recurse_submodules;\n \targs->base = base;\n \targs->baselen = strlen(base);\n \targs->worktree_attributes = worktree_attributes;\ndiff --git a/archive.h b/archive.h\nindex 415e0152e..96e217ac5 100644\n--- a/archive.h\n+++ b/archive.h\n@@ -12,6 +12,7 @@ struct archiver_args {\n \ttime_t time;\n \tstruct pathspec pathspec;\n \tunsigned int verbose : 1;\n+\tunsigned int recurse_submodules : 1;\n \tunsigned int worktree_attributes : 1;\n \tunsigned int convert : 1;\n \tint compression_level;\ndiff --git a/submodule.c b/submodule.c\nindex 3b98766a6..5fe5a3a8e 100644\n--- a/submodule.c\n+++ b/submodule.c\n@@ -121,7 +121,7 @@ void stage_updated_gitmodules(void)\n \t\tdie(_(\"staging updated .gitmodules failed\"));\n }\n \n-static int add_submodule_odb(const char *path)\n+int add_submodule_odb(const char *path)\n {\n \tstruct strbuf objects_directory = STRBUF_INIT;\n \tint ret = 0;\ndiff --git a/submodule.h b/submodule.h\nindex 05ab674f0..d59fd2537 100644\n--- a/submodule.h\n+++ b/submodule.h\n@@ -35,6 +35,7 @@ extern int is_staging_gitmodules_ok(void);\n extern int update_path_in_gitmodules(const char *oldpath, const char *newpath);\n extern int remove_path_from_gitmodules(const char *path);\n extern void stage_updated_gitmodules(void);\n+extern int add_submodule_odb(const char *path);\n extern void set_diffopt_flags_from_submodule_config(struct diff_options *,\n \t\tconst char *path);\n extern int submodule_config(const char *var, const char *value, void *cb);\ndiff --git a/t/t5005-archive-submodules.sh b/t/t5005-archive-submodules.sh\nnew file mode 100755\nindex 000000000..747e38627\n--- /dev/null\n+++ b/t/t5005-archive-submodules.sh\n@@ -0,0 +1,112 @@\n+#!/bin/sh\n+\n+test_description='git archive can include submodule content'\n+\n+. ./test-lib.sh\n+\n+add_file()\n+{\n+\tgit add $1 &&\n+\tgit commit -m \"added $1\"\n+}\n+\n+add_submodule()\n+{\n+\tmkdir $1 && (\n+\t\tcd $1 &&\n+\t\tgit init &&\n+\t\techo \"File $2\" >$2 &&\n+\t\tadd_file $2\n+\t) &&\n+\tadd_file $1\n+}\n+\n+test_expect_success 'by default, submodules are not included' '\n+\techo \"File 1\" >1 &&\n+\tadd_file 1 &&\n+\tadd_submodule 2 3 &&\n+\tadd_submodule 4 5 &&\n+\tcat <<EOF >expected &&\n+1\n+2/\n+4/\n+EOF\n+\tgit archive HEAD >normal.tar &&\n+\ttar -tf normal.tar >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'with --recurse-submodules, checked out submodules are included' '\n+\tcat <<EOF >expected &&\n+1\n+2/\n+2/3\n+4/\n+4/5\n+EOF\n+\tgit archive --recurse-submodules HEAD >full.tar &&\n+\ttar -tf full.tar >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'submodules in submodules are supported' '\n+\t(cd 4 && add_submodule 6 7) &&\n+\tadd_file 4 &&\n+\tcat <<EOF >expected &&\n+1\n+2/\n+2/3\n+4/\n+4/5\n+4/6/\n+4/6/7\n+EOF\n+\tgit archive --recurse-submodules HEAD >recursive.tar &&\n+\ttar -tf recursive.tar >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'packed submodules are supported' '\n+\tmsg=$(cd 2 && git repack -ad && git count-objects) &&\n+\ttest \"$msg\" = \"0 objects, 0 kilobytes\" &&\n+\tgit archive --recurse-submodules HEAD >packed.tar &&\n+\ttar -tf packed.tar >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'pathspecs supported' '\n+\tcat <<EOF >expected &&\n+2/3\n+4/6/7\n+EOF\n+\tgit archive --recurse-submodules HEAD >recursive.tar &&\n+\ttar -tf recursive.tar 4/6/7 2/3 >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'missing submodule packs triggers an error' '\n+\tmv 2/.git/objects/pack .git/packdir2 &&\n+\ttest_must_fail git archive --recurse-submodules HEAD\n+'\n+\n+test_expect_success '--recurse-submodules skips non-checked out submodules' '\n+\tcat <<EOF >expected &&\n+1\n+2/\n+4/\n+4/5\n+4/6/\n+4/6/7\n+EOF\n+\trm -rf 2/.git &&\n+\tgit archive --recurse-submodules HEAD >partial.tar &&\n+\ttar -tf partial.tar >actual &&\n+\ttest_cmp expected actual\n+'\n+\n+test_expect_success 'missing objects in a submodule triggers an error' '\n+\tfind 4/.git/objects -type f | xargs rm &&\n+\ttest_must_fail git archive --recurse-submodules HEAD\n+'\n+\n+test_done\n-- \n2.12.0.244.g625568cd8.dirty\n\n"},{"id":"313872","messageId":"xmqqtw6yt3l4.fsf@gitster.mtv.corp.google.com","threadId":"45359","inReplyTo":"20170312075404.23951-2-nikhil.benesch@gmail.com","subject":"Re: [PATCH 1/1] archive: learn to include submodules in output archive","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-13T00:36:39Z","receivedAt":"2017-03-13T00:37:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nikhil Benesch <nikhil.benesch@gmail.com> writes:\n\n> This commit is a revival of Lars Hjemli's 2009 patch to provide an\n> option to include submodules in the output of `git archive`.\n>\n> The `--recurse-submodules` option (named consistently with fetch, clone,\n> and ls-files) will recursively traverse submodules in the repository and\n> consider their contents for inclusion in the output archive, subject to\n> any pathspec filters. Like other commands that have learned\n> `--recurse-submodules`, submodules that have not been checked out will\n> not be traversed.\n>\n> Signed-off-by: Nikhil Benesch <nikhil.benesch@gmail.com>\n> ---\n\nI'll let others comment on the proposed log message.\n\n> diff --git a/Documentation/git-archive.txt b/Documentation/git-archive.txt\n> index cfa1e4ebe..f223f9e05 100644\n> --- a/Documentation/git-archive.txt\n> +++ b/Documentation/git-archive.txt\n> @@ -11,8 +11,8 @@ SYNOPSIS\n>  [verse]\n>  'git archive' [--format=<fmt>] [--list] [--prefix=<prefix>/] [<extra>]\n>  \t      [-o <file> | --output=<file>] [--worktree-attributes]\n> -\t      [--remote=<repo> [--exec=<git-upload-archive>]] <tree-ish>\n> -\t      [<path>...]\n> +\t      [--recurse-submodules] [--remote=<repo> [--exec=<git-upload-archive>]]\n> +\t      <tree-ish> [<path>...]\n\nWith the reflowing of lines it was not immediately obvious, but the\nonly change is to addd [--recurse-submodules] in front of the\nexisting [--remote=<repo>] option.  It would have probably made more\nsense to add new things at the end, just because these options can\nbe given in any order.\n\n> +--recurse-submodules::\n> +\tRecursively include the contents of any checked-out submodules in\n> +\tthe archive.\n\nOK.  \n\nA question to the submodule folks: Is \"checked-out\" the right terminology\nin this context?  I am wondering if we have reached more official set\nof words to express submodule states discussed in [*1*].\n\n> -\tif (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n> -\t\tif (args->verbose)\n> -\t\t\tfprintf(stderr, \"%.*s\\n\", (int)path.len, path.buf);\n> -\t\terr = write_entry(args, sha1, path.buf, path.len, mode);\n> -\t\tif (err)\n> -\t\t\treturn err;\n> -\t\treturn (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n> -\t}\n> -\n>  \tif (args->verbose)\n>  \t\tfprintf(stderr, \"%.*s\\n\", (int)path.len, path.buf);\n> -\treturn write_entry(args, sha1, path.buf, path.len, mode);\n> +\terr = write_entry(args, sha1, path.buf, path.len, mode);\n> +\tif (err)\n> +\t\treturn err;\n> +\tif (S_ISDIR(mode) || (S_ISGITLINK(mode) && args->recurse_submodules &&\n> +\t\t\t      !add_submodule_odb(path_without_prefix)))\n> +\t\treturn READ_TREE_RECURSIVE;\n> +\treturn 0;\n\nSo, we used to (and without the option we still) stop recursing when\nwe see a gitlink after asking write_entry() to write the path itself\nout, but with the option, we keep going.\n\nHow does pathspec limiting work with this codepath?  If you have a\nsuperproject with a regular file \"sub/README\" that belongs to the\nsuperproject itself, and a submodule at \"sub/module/\", what makes\nsure that this command\n\n    $ git archive --recurse-submodules HEAD -- 'sub/R*' 'sub/module/lib/'\n\nlooks only in 'lib/' part of the submodule?\n\n> diff --git a/t/t5005-archive-submodules.sh b/t/t5005-archive-submodules.sh\n> new file mode 100755\n> index 000000000..747e38627\n> --- /dev/null\n> +++ b/t/t5005-archive-submodules.sh\n> @@ -0,0 +1,112 @@\n> +#!/bin/sh\n> +\n> +test_description='git archive can include submodule content'\n> +\n> +. ./test-lib.sh\n> +\n> +add_file()\n> +{\n\nStyle.  A shell function begins like so (see Documentation/CodingGuidelines):\n\n\tadd_file () {\n\n> +\tgit add $1 &&\n\nPut dq around \"$1\" to make it easier to reuse, even if you know you\nonly happen to use pathnames without any $IFS whitespace characters.\n\nI think all of these comments apply to the other shell function you\nadded to this file..\n\n> +test_expect_success 'by default, submodules are not included' '\n> +\techo \"File 1\" >1 &&\n> +\tadd_file 1 &&\n> +\tadd_submodule 2 3 &&\n> +\tadd_submodule 4 5 &&\n> +\tcat <<EOF >expected &&\n> +1\n> +2/\n> +4/\n> +EOF\n\nUse <<-EOF to allow you to indent your here-doc data.  Also when\nyour here-doc data does not need any $variable_interpolation, quote\nthe end marker to help reduce reviewer's mental burden, i.e.\n\n\tcat <<-\\EOF >expected &&\n\t1\n\t2/\n\t4/\n\tEOF\n\nThe same comment applies to other tests (I won't even repeat this).\n\n> +\tgit archive HEAD >normal.tar &&\n> +\ttar -tf normal.tar >actual &&\n\nLose \"-\" from \"-tf\"; that's the canonical and the most portable way\nto spell the option to \"tar\".\n\n> +test_expect_success 'packed submodules are supported' '\n> +\tmsg=$(cd 2 && git repack -ad && git count-objects) &&\n> +\ttest \"$msg\" = \"0 objects, 0 kilobytes\" &&\n> +\tgit archive --recurse-submodules HEAD >packed.tar &&\n> +\ttar -tf packed.tar >actual &&\n> +\ttest_cmp expected actual\n> +'\n\nI am not sure how packing would be expected to break anything, but\nan extra test may not hurt.\n\nI notice that you only test the case where the submodule's \".git\" \nis embedded in its working tree (as opposed to \".git\" being a\n\"gitdir:\" file that points at the real location of the repository,\nsomewhere inside \".git/modules/\" of the superproject).  You probably\nwant to make sure that also works, too.\n\nI also notice that you do not use any pathspec in your \"git archive\"\ninvocation.  You'd want to make sure that works as expected.\n\nThanks.\n\n\n[Reference]\n\n*1* <20170209020855.23486-1-sbeller@google.com>\n"},{"id":"313993","messageId":"CAGZ79kZrbvJz+S434BmEA_qeMOUXHk60yDSwdcKef62-Bz8nyw@mail.gmail.com","threadId":"45359","inReplyTo":"20170312075404.23951-2-nikhil.benesch@gmail.com","subject":"Re: [PATCH 1/1] archive: learn to include submodules in output archive","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-03-13T22:12:07Z","receivedAt":"2017-03-13T22:12:16Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"Welcome to the Git community!\n\nOn Sat, Mar 11, 2017 at 11:54 PM, Nikhil Benesch\n<nikhil.benesch@gmail.com> wrote:\n> This commit is a revival of Lars Hjemli's 2009 patch to provide an\n> option to include submodules in the output of `git archive`.\n\nI am unaware of said patch, could you link to it, e.g.\non https://public-inbox.org/git/ ?\n\n>\n> The `--recurse-submodules` option (named consistently with fetch, clone,\n> and ls-files)\n\n... and unlike fetch and push we do not need to introduce extra options?\n(or they can be added later when the need arises)\n\n> will recursively traverse submodules in the repository and\n> consider their contents for inclusion in the output archive, subject to\n> any pathspec filters.\n\nok.\n\n> Like other commands that have learned\n> `--recurse-submodules`, submodules that have not been checked out will\n> not be traversed.\n\nJunio writes:\n> A question to the submodule folks: Is \"checked-out\" the right terminology\n> in this context?  I am wondering if we have reached more official set\n> of words to express submodule states discussed in [*1*].\n\nhttp://public-inbox.org/git/20170209020855.23486-1-sbeller@google.com/\n\nThe \"checked-out\" here would translate to \"populated\" in said proposal.\n\nI guess that is sufficient for the first implementation, but eventually we\nmight be interested in \"recurse-submodules=active/init\" as well.\nConsider the case, where you delete a submodule and commit it.\nThen you still want to be able to create an archive for HEAD^ (with\nsubmodules). So in that case we'd want to recurse into any submodule\nthat has a git directory with the commit as recorded by the superproject,\ni.e. the example given would refer to \"depopulated\" in the referenced\nproposal.\n\nWhen the initialization is missing, we may not be interested in that\nsubmodule any more, but we don't know for the user, so a user may\nwant to ask for \"archive --recurse-submodules={all / initialized-only /\nall-submoduless-with-git-dir, none, working-tree}\". No need to add all\nthese options in the first patch, but keep that in mind for future\nextensions.\n\n> @@ -59,6 +59,10 @@ OPTIONS\n>         Look for attributes in .gitattributes files in the working tree\n>         as well (see <<ATTRIBUTES>>).\n>\n> +--recurse-submodules::\n> +       Recursively include the contents of any checked-out submodules in\n> +       the archive.\n> +\n\nHere is \"any\", in the commit message we had \"subject to any pathspec filters.\"\n\n> @@ -132,18 +133,15 @@ static int write_archive_entry(const unsigned char *sha1, const char *base,\n>                 args->convert = ATTR_TRUE(check->items[1].value);\n>         }\n>\n> -       if (S_ISDIR(mode) || S_ISGITLINK(mode)) {\n> -               if (args->verbose)\n> -                       fprintf(stderr, \"%.*s\\n\", (int)path.len, path.buf);\n> -               err = write_entry(args, sha1, path.buf, path.len, mode);\n> -               if (err)\n> -                       return err;\n> -               return (S_ISDIR(mode) ? READ_TREE_RECURSIVE : 0);\n> -       }\n> -\n>         if (args->verbose)\n>                 fprintf(stderr, \"%.*s\\n\", (int)path.len, path.buf);\n> -       return write_entry(args, sha1, path.buf, path.len, mode);\n> +       err = write_entry(args, sha1, path.buf, path.len, mode);\n> +       if (err)\n> +               return err;\n> +       if (S_ISDIR(mode) || (S_ISGITLINK(mode) && args->recurse_submodules &&\n> +                             !add_submodule_odb(path_without_prefix)))\n\nThis is a bit hard to read. Maybe reformatting can help\n\n     if (S_ISDIR(mode) ||\n        (S_ISGITLINK(mode) &&\n         args->recurse_submodules &&\n         !add_submodule_odb(path_without_prefix)))\n        return ...\n\nThough I wonder if we need to special case the\nreturn value of add_submodule_odb as that could\nbe an error instead of fall through \"return 0;\" ?\n\n> @@ -419,6 +418,8 @@ static int parse_archive_args(int argc, const char **argv,\n>                         N_(\"prepend prefix to each pathname in the archive\")),\n>                 OPT_STRING('o', \"output\", &output, N_(\"file\"),\n>                         N_(\"write the archive to this file\")),\n> +               OPT_BOOL(0, \"recurse-submodules\", &recurse_submodules,\n> +                       N_(\"recurse through submodules\")),\n\nThis is the first time hearing \"through\" used with submodules.\nI guess it makes sense when looking at the contents on disk as\na tree data structure.\n\npush:    N_(\"control recursive pushing of submodules\"),\nfetch:    N_(\"control recursive fetching of submodules\"),\ngrep:    N_(\"recursivley search in each submodule\")),\nls-files:    N_(\"recurse through submodules\")),\n\nOk, we introduced recursing \"through\" submodules with ls-files.\n\n...\n> +\n> +add_submodule()\n> +{\n> +       mkdir $1 && (\n> +               cd $1 &&\n> +               git init &&\n> +               echo \"File $2\" >$2 &&\n> +               add_file $2\n\ntest_create_repo / test_commit\nmight come in handy here as well.\n\n> +       ) &&\n> +       add_file $1\n> +}\n> +\n> +test_expect_success 'by default, submodules are not included' '\n\nThis test case may be covered elsewhere (in the default archive tests)\nalready, though not spelled out as such?\n\n> +test_expect_success 'with --recurse-submodules, checked out submodules are included' '\n> +       cat <<EOF >expected &&\n\nIn the modern parts of Git we indent the content of the here-doc-text\n(If the operator is “<<-” instead of “<<”, then leading tabs in the\nhere-doc-text are stripped.)\ni.e. cat <<-\\EOF >expect\n    well indented text\n    that doesn't break visual alignment\n    of tests.\n    EOF\n    git archive ...\n\nThere are a lot of old tests still out there, so it is easy to\nfind them for guidance first. :/\n\n\n> +test_expect_success 'submodules in submodules are supported' '\n\ncool! Usually these are referred to as \"nested submodules\" in\ncase you want to shorten the description.\n\n> +test_expect_success 'packed submodules are supported' '\n\nNot sure what we try to test here? The internal representation\nof the submodule ought to not matter.\n\n> +       msg=$(cd 2 && git repack -ad && git count-objects) &&\n> +       test \"$msg\" = \"0 objects, 0 kilobytes\" &&\n\nI read that in submodule tests before; t7408 that tests if\nsubmodules with alternates are useful. I am not convinced we\nneed this test here?\n\n> +test_expect_success 'pathspecs supported' '\n..\n> +       git archive --recurse-submodules HEAD >recursive.tar &&\n\nThe test ought to test that Git can use pathspecs ...\n\n> +       tar -tf recursive.tar 4/6/7 2/3 >actual &&\n\n... unlike tar. We consider all external tools to be perfect within\nthe git test suite. So we rather want to test for the absence of\npaths, that were not given as a pathspec to the git archive command.\n\n> +test_expect_success 'missing submodule packs triggers an error' '\n\ncool!\n\n> +       mv 2/.git/objects/pack .git/packdir2 &&\n\nUh :/ please do not assume we have the submodule at\n<path>/.git. See 293ab15ee (submodule: teach rm to remove\nsubmodules unless they contain a git directory, 2012) for example.\n\n> +       test_must_fail git archive --recurse-submodules HEAD\n\nDo we want to also check for a sensible error message here?\ne.g.\n    test_must_fail git archive ... >out &&\n    test_i18n_grep \"<message>\" out\n\n> +test_expect_success '--recurse-submodules skips non-checked out submodules' '\n\nI read that as \"skips unpopulated\" ...\n\n\nThanks,\nStefan\n"},{"id":"314004","messageId":"CAGZ79kZbcLFJPUt3wGsYX-XgAO+xW1ZDGJqN-q=r8i5Zbv_tTw@mail.gmail.com","threadId":"45359","inReplyTo":"CAGZ79kZrbvJz+S434BmEA_qeMOUXHk60yDSwdcKef62-Bz8nyw@mail.gmail.com","subject":"Re: [PATCH 1/1] archive: learn to include submodules in output archive","fromName":"Stefan Beller","fromEmail":"sbeller@google.com","sentAt":"2017-03-13T22:57:44Z","receivedAt":"2017-03-13T22:59:05Z","isPatch":true,"sender":{"key":"stefanbeller@gmail.com","avatar":"https://avatars.githubusercontent.com/u/455868?v=4"},"body":"On Mon, Mar 13, 2017 at 3:12 PM, Stefan Beller <sbeller@google.com> wrote:\n\n>> will recursively traverse submodules in the repository and\n>> consider their contents for inclusion in the output archive, subject to\n>> any pathspec filters.\n\ngit-archive pays attention to export-ignore and export-subst attribute\nas read from .gitattributes or $GIT_DIR/info/attributes\n\nWhen recursing into submodules, we'd need to clarify if the attributes\nfrom the superproject or from the submodules are applied; or both.\n\nThanks,\nStefan\n"},{"id":"314008","messageId":"xmqqpohklqa8.fsf@gitster.mtv.corp.google.com","threadId":"45359","inReplyTo":"CAGZ79kZbcLFJPUt3wGsYX-XgAO+xW1ZDGJqN-q=r8i5Zbv_tTw@mail.gmail.com","subject":"Re: [PATCH 1/1] archive: learn to include submodules in output archive","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2017-03-13T23:18:07Z","receivedAt":"2017-03-13T23:18:15Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Stefan Beller <sbeller@google.com> writes:\n\n> On Mon, Mar 13, 2017 at 3:12 PM, Stefan Beller <sbeller@google.com> wrote:\n>\n>>> will recursively traverse submodules in the repository and\n>>> consider their contents for inclusion in the output archive, subject to\n>>> any pathspec filters.\n>\n> git-archive pays attention to export-ignore and export-subst attribute\n> as read from .gitattributes or $GIT_DIR/info/attributes\n>\n> When recursing into submodules, we'd need to clarify if the attributes\n> from the superproject or from the submodules are applied; or both.\n\nI think the most natural expectation is for the output from the\n\"archive --recurse-submodules\" command is to be logical\nconcatenation of \"archive\" run at the top-level and submodules,\nadjusting the output from the latter with leading paths to the\nsubmodules.  For that to happen, the attributes that apply to paths\ninside a submodule must come from that submodule's setting.\n\n"}]}