]> git.ipfire.org Git - thirdparty/git.git/commitdiff
submodule: hash the submodule name for the gitdir path
authorAdrian Ratiu <adrian.ratiu@collabora.com>
Mon, 12 Jan 2026 18:46:31 +0000 (20:46 +0200)
committerJunio C Hamano <gitster@pobox.com>
Mon, 12 Jan 2026 19:56:57 +0000 (11:56 -0800)
If none of the previous plain-text / encoding / derivation steps work
and case 2.4 is reached, then try a hash of the submodule name to see
if that can be a valid gitdir before giving up and throwing an error.

This is a "last resort" type of measure to avoid conflicts since it
loses the human readability of the gitdir path. This logic will be
reached in rare cases, as can be seen in the test we added.

Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
builtin/submodule--helper.c
t/t7425-submodule-gitdir-path-extension.sh

index 746f9fa63c3be9a7b9f4f95d55d228103e64aeaf..2fa71c814cb6df3cd3b606a03da088a47c3569f8 100644 (file)
@@ -465,6 +465,10 @@ static int validate_and_set_submodule_gitdir(struct strbuf *gitdir_path,
 static void create_default_gitdir_config(const char *submodule_name)
 {
        struct strbuf gitdir_path = STRBUF_INIT;
+       struct git_hash_ctx ctx;
+       char hex_name_hash[GIT_MAX_HEXSZ + 1], header[128];
+       unsigned char raw_name_hash[GIT_MAX_RAWSZ];
+       int header_len;
 
        /* Case 1: try the plain module name */
        repo_git_path_append(the_repository, &gitdir_path, "modules/%s", submodule_name);
@@ -506,6 +510,21 @@ static void create_default_gitdir_config(const char *submodule_name)
                        return;
        }
 
+       /* Case 2.4: If all the above failed, try a hash of the name as a last resort */
+       header_len = snprintf(header, sizeof(header), "blob %zu", strlen(submodule_name));
+       the_hash_algo->init_fn(&ctx);
+       the_hash_algo->update_fn(&ctx, header, header_len);
+       the_hash_algo->update_fn(&ctx, "\0", 1);
+       the_hash_algo->update_fn(&ctx, submodule_name, strlen(submodule_name));
+       the_hash_algo->final_fn(raw_name_hash, &ctx);
+       hash_to_hex_algop_r(hex_name_hash, raw_name_hash, the_hash_algo);
+       strbuf_reset(&gitdir_path);
+       repo_git_path_append(the_repository, &gitdir_path, "modules/%s", hex_name_hash);
+       if (!validate_and_set_submodule_gitdir(&gitdir_path, submodule_name)) {
+               strbuf_release(&gitdir_path);
+               return;
+       }
+
        /* Case 3: nothing worked, error out */
        die(_("failed to set a valid default config for 'submodule.%s.gitdir'. "
              "Please ensure it is set, for example by running something like: "
index 3cca93c8972b0130de7903c081e6575b5fe87d19..a76e64a9f7d7d3f955c24929bf2ef40744973d00 100755 (executable)
@@ -438,4 +438,63 @@ test_expect_success CASE_INSENSITIVE_FS 'verify case-folding conflicts are corre
        verify_submodule_gitdir_path cloned-folding "fooBar" "modules/fooBar0"
 '
 
+test_expect_success CASE_INSENSITIVE_FS 'verify hashing conflict resolution as a last resort' '
+       git clone -c extensions.submodulePathConfig=true main cloned-hash &&
+       (
+               cd cloned-hash &&
+
+               # conflict: add all submodule conflicting variants until we reach the
+               # final hashing conflict resolution for submodule "foo"
+               git submodule add ../new-sub "foo" &&
+               git submodule add ../new-sub "foo0" &&
+               git submodule add ../new-sub "foo1" &&
+               git submodule add ../new-sub "foo2" &&
+               git submodule add ../new-sub "foo3" &&
+               git submodule add ../new-sub "foo4" &&
+               git submodule add ../new-sub "foo5" &&
+               git submodule add ../new-sub "foo6" &&
+               git submodule add ../new-sub "foo7" &&
+               git submodule add ../new-sub "foo8" &&
+               git submodule add ../new-sub "foo9" &&
+               git submodule add ../new-sub "%46oo" &&
+               git submodule add ../new-sub "%46oo0" &&
+               git submodule add ../new-sub "%46oo1" &&
+               git submodule add ../new-sub "%46oo2" &&
+               git submodule add ../new-sub "%46oo3" &&
+               git submodule add ../new-sub "%46oo4" &&
+               git submodule add ../new-sub "%46oo5" &&
+               git submodule add ../new-sub "%46oo6" &&
+               git submodule add ../new-sub "%46oo7" &&
+               git submodule add ../new-sub "%46oo8" &&
+               git submodule add ../new-sub "%46oo9" &&
+               test_commit add-foo-variants &&
+               git submodule add ../new-sub "Foo" &&
+               test_commit add-uppercase-foo
+       ) &&
+       verify_submodule_gitdir_path cloned-hash "foo" "modules/foo" &&
+       verify_submodule_gitdir_path cloned-hash "foo0" "modules/foo0" &&
+       verify_submodule_gitdir_path cloned-hash "foo1" "modules/foo1" &&
+       verify_submodule_gitdir_path cloned-hash "foo2" "modules/foo2" &&
+       verify_submodule_gitdir_path cloned-hash "foo3" "modules/foo3" &&
+       verify_submodule_gitdir_path cloned-hash "foo4" "modules/foo4" &&
+       verify_submodule_gitdir_path cloned-hash "foo5" "modules/foo5" &&
+       verify_submodule_gitdir_path cloned-hash "foo6" "modules/foo6" &&
+       verify_submodule_gitdir_path cloned-hash "foo7" "modules/foo7" &&
+       verify_submodule_gitdir_path cloned-hash "foo8" "modules/foo8" &&
+       verify_submodule_gitdir_path cloned-hash "foo9" "modules/foo9" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo" "modules/%46oo" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo0" "modules/%46oo0" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo1" "modules/%46oo1" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo2" "modules/%46oo2" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo3" "modules/%46oo3" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo4" "modules/%46oo4" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo5" "modules/%46oo5" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo6" "modules/%46oo6" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo7" "modules/%46oo7" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo8" "modules/%46oo8" &&
+       verify_submodule_gitdir_path cloned-hash "%46oo9" "modules/%46oo9" &&
+       hash=$(printf "Foo" | git hash-object --stdin) &&
+       verify_submodule_gitdir_path cloned-hash "Foo" "modules/${hash}"
+'
+
 test_done