Signed-off-by: Stefan Beller <sbel...@google.com>
---
 Documentation/git-clone.txt    |  4 ++++
 builtin/submodule--helper.c    | 47 ++++++++++++++++++++++++++++++++++++++++++
 t/t7408-submodule-reference.sh | 29 +++++++++++++++++++++++++-
 3 files changed, 79 insertions(+), 1 deletion(-)

diff --git a/Documentation/git-clone.txt b/Documentation/git-clone.txt
index e316c4b..cadf138 100644
--- a/Documentation/git-clone.txt
+++ b/Documentation/git-clone.txt
@@ -103,6 +103,10 @@ objects from the source repository into a pack in the 
cloned repository.
 +
 *NOTE*: see the NOTE for the `--shared` option, and also the
 `--dissociate` option.
++
+When using --reference any submodule that is cloned
+sets up a corresponding alternate at $GIT_DIR/modules if such a
+an alternate exists.
 
 --dissociate::
        Borrow the objects from reference repositories specified
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index f360473..fc14843 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -635,6 +635,45 @@ static void next_submodule_warn_missing(struct 
submodule_update_clone *suc,
        }
 }
 
+struct submodule_alternate_setup {
+       struct submodule_update_clone *suc;
+       const char *submodule_name;
+       struct child_process *child;
+       struct strbuf *out;
+};
+
+int add_possible_reference(struct alternate_object_database *alt, void *sas_cb)
+{
+       struct submodule_alternate_setup *sas = sas_cb;
+
+       /* directory name, minus trailing slash */
+       size_t namelen = alt->name - alt->base - 1;
+       struct strbuf name = STRBUF_INIT;
+       strbuf_add(&name, alt->base, namelen);
+
+       /*
+        * If the alternate object store is another repository, try the
+        * standard layout with .git/modules/<name>/objects
+        */
+       if (ends_with(name.buf, ".git/objects")) {
+               struct strbuf sb = STRBUF_INIT;
+               strbuf_add(&sb, name.buf, name.len - strlen("objects"));
+               /*
+                * We need to end the new path with '/' to mark it as a dir,
+                * otherwise a submodule name containing '/' will be broken
+                * as the last part of a missing submodule reference would
+                * be taken as a file name.
+                */
+               strbuf_addf(&sb, "modules/%s/", sas->submodule_name);
+               argv_array_pushf(&sas->child->args,
+                                "--reference-if-able=%s", sb.buf);
+               strbuf_release(&sb);
+       }
+
+       strbuf_release(&name);
+       return 0;
+}
+
 /**
  * Determine whether 'ce' needs to be cloned. If so, prepare the 'child' to
  * run the clone. Returns 1 if 'ce' needs to be cloned, 0 otherwise.
@@ -650,6 +689,7 @@ static int prepare_to_clone_next_submodule(const struct 
cache_entry *ce,
        const char *displaypath = NULL;
        char *url = NULL;
        int needs_cloning = 0;
+       struct submodule_alternate_setup sas;
 
        if (ce_stage(ce)) {
                if (suc->recursive_prefix)
@@ -728,6 +768,13 @@ static int prepare_to_clone_next_submodule(const struct 
cache_entry *ce,
                for_each_string_list_item(item, &suc->references)
                        argv_array_pushl(&child->args, "--reference", 
item->string, NULL);
        }
+
+       sas.submodule_name = sub->name;
+       sas.suc = suc;
+       sas.child = child;
+       sas.out = out;
+       foreach_alt_odb(add_possible_reference, &sas);
+
        if (suc->depth)
                argv_array_push(&child->args, suc->depth);
 
diff --git a/t/t7408-submodule-reference.sh b/t/t7408-submodule-reference.sh
index 4a1b8f0..a9b89a3 100755
--- a/t/t7408-submodule-reference.sh
+++ b/t/t7408-submodule-reference.sh
@@ -7,7 +7,6 @@ test_description='test clone --reference'
 . ./test-lib.sh
 
 base_dir=$(pwd)
-
 test_alternate_is_used () {
        alternates_file="$1" &&
        working_dir="$2" &&
@@ -73,4 +72,32 @@ test_expect_success 'updating superproject keeps alternates' 
'
        test_alternate_is_used 
super-clone/.git/modules/sub/objects/info/alternates super-clone/sub
 '
 
+test_expect_success 'submodules use alternates when cloning a superproject' '
+       test_when_finished "rm -rf super-clone" &&
+       git clone --reference super --recursive super super-clone &&
+       (
+               cd super-clone &&
+               # test superproject has alternates setup correctly
+               test_alternate_is_used .git/objects/info/alternates . &&
+               # test submodule has correct setup
+               test_alternate_is_used .git/modules/sub/objects/info/alternates 
sub
+       )
+'
+
+test_expect_success 'cloning superproject, missing submodule alternates' '
+       test_when_finished "rm -rf super-clone" &&
+       git clone super super2 &&
+       git clone --recursive --reference super2 super2 super-clone &&
+       (
+               cd super-clone &&
+               # test superproject has alternates setup correctly
+               test_alternate_is_used .git/objects/info/alternates . &&
+               # update of the submodule succeeds
+               git submodule update --init &&
+               # and we have no alternates:
+               test_must_fail test_alternate_is_used 
.git/modules/sub/objects/info/alternates sub &&
+               test_path_is_file sub/file1
+       )
+'
+
 test_done
-- 
2.9.2.583.gd6329be.dirty

--
To unsubscribe from this list: send the line "unsubscribe git" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to