Both fetch and push still use alternates to access submodules in some
other code paths, but this is progress towards eliminating the alternates
hack that conflates access to the_repository and other repositories.

Signed-off-by: Jonathan Nieder <jrnie...@gmail.com>
Signed-off-by: Stefan Beller <sbel...@google.com>
---
 submodule.c | 52 ++++++++++++++++++++++++++++++++++++++--------------
 1 file changed, 38 insertions(+), 14 deletions(-)

diff --git a/submodule.c b/submodule.c
index dc57c176e8..1504812842 100644
--- a/submodule.c
+++ b/submodule.c
@@ -811,14 +811,15 @@ static int append_oid_to_argv(const struct object_id 
*oid, void *data)
 
 struct has_commit_data {
        int result;
-       const char *path;
+       struct repository *repo;
 };
 
 static int check_has_commit(const struct object_id *oid, void *data)
 {
        struct has_commit_data *cb = data;
+       struct repository *r = cb->repo;
 
-       enum object_type type = sha1_object_info(the_repository, oid->hash, 
NULL);
+       enum object_type type = sha1_object_info(r, oid->hash, NULL);
 
        switch (type) {
        case OBJ_COMMIT:
@@ -832,24 +833,43 @@ static int check_has_commit(const struct object_id *oid, 
void *data)
                return 0;
        default:
                die(_("submodule entry '%s' (%s) is a %s, not a commit"),
-                   cb->path, oid_to_hex(oid), typename(type));
+                   r->submodule_prefix, oid_to_hex(oid), typename(type));
        }
 }
 
+/*
+ * Initialize 'out' based on the provided submodule path.
+ *
+ * Unlike repo_submodule_init, this tolerates submodules not present
+ * in .gitmodules. NEEDSWORK: The repo_submodule_init behavior is
+ * preferrable. This function exists only to preserve historical behavior.
+ *
+ * Returns 0 on success, -1 when the submodule is not present.
+ */
+static int open_submodule(struct repository *out, const char *path)
+{
+       struct strbuf sb = STRBUF_INIT;
+
+       if (submodule_to_gitdir(&sb, path))
+               return -1;
+
+       if (repo_init(out, sb.buf, NULL)) {
+               strbuf_release(&sb);
+               return -1;
+       }
+
+       out->submodule_prefix = xstrdup(path);
+
+       strbuf_release(&sb);
+       return 0;
+}
+
 static int submodule_has_commits(const char *path, struct oid_array *commits)
 {
-       struct has_commit_data has_commit = { 1, path };
+       struct repository sub;
+       struct has_commit_data has_commit = { 1, &sub };
 
-       /*
-        * Perform a cheap, but incorrect check for the existence of 'commits'.
-        * This is done by adding the submodule's object store to the in-core
-        * object store, and then querying for each commit's existence.  If we
-        * do not have the commit object anywhere, there is no chance we have
-        * it in the object store of the correct submodule and have it
-        * reachable from a ref, so we can fail early without spawning rev-list
-        * which is expensive.
-        */
-       if (add_submodule_odb(path))
+       if (open_submodule(&sub, path))
                return 0;
 
        oid_array_for_each_unique(commits, check_has_commit, &has_commit);
@@ -878,6 +898,7 @@ static int submodule_has_commits(const char *path, struct 
oid_array *commits)
                strbuf_release(&out);
        }
 
+       repo_clear(&sub);
        return has_commit.result;
 }
 
@@ -897,6 +918,9 @@ static int submodule_needs_pushing(const char *path, struct 
oid_array *commits)
                 */
                return 0;
 
+       /* The submodule odb is needed for access to its refs. */
+       if (add_submodule_odb(path))
+               BUG("submodule '%s' is both present and absent", path);
        if (for_each_remote_ref_submodule(path, has_remote, NULL) > 0) {
                struct child_process cp = CHILD_PROCESS_INIT;
                struct strbuf buf = STRBUF_INIT;
-- 
2.15.1.433.g936d1b9894.dirty

Reply via email to