From: Adrian Ratiu Date: Wed, 19 Nov 2025 21:10:29 GMT Subject: [PATCH v5 6/7] submodule: use hashed name for gitdir Message-ID: <20251119211030.2008441-7-adrian.ratiu@collabora.com> In-Reply-To: <20251119211030.2008441-1-adrian.ratiu@collabora.com> If none of the previous steps work and we reach case 2.4, try to hash the submodule name and 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 gitdir human readability. Itis not such a big deal because users are now supposed to use the submodule..gitdir config as the single source of truth for gitdir paths. This logic will be reached in very rare cases, as can be seen in the test we added. Signed-off-by: Adrian Ratiu --- submodule.c | 20 +++++++++++- t/t7425-submodule-encoding.sh | 59 +++++++++++++++++++++++++++++++++++ 2 files changed, 78 insertions(+), 1 deletion(-) diff --git a/submodule.c b/submodule.c index b3f74f7e3c..2c0df96d55 100644 --- a/submodule.c +++ b/submodule.c @@ -2660,8 +2660,12 @@ static int validate_and_set_submodule_gitdir(struct strbuf *gitdir_path, void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r, const char *submodule_name) { + unsigned char raw_name_hash[GIT_MAX_RAWSZ]; + char hex_name_hash[GIT_MAX_HEXSZ + 1]; + struct git_hash_ctx ctx; const char *gitdir; - char *key; + char *key, header[128]; + int header_len; repo_git_path_append(r, buf, "modules/"); strbuf_addstr(buf, submodule_name); @@ -2732,6 +2736,20 @@ void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r, 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(buf); + repo_git_path_append(r, buf, "modules/"); + strbuf_addstr(buf, hex_name_hash); + if (!validate_and_set_submodule_gitdir(buf, submodule_name)) + return; + /* Case 3: Nothing worked: error out */ die(_("Cannot construct a valid gitdir path for submodule '%s': " "please set a unique git config for 'submodule.%s.gitdir'."), diff --git a/t/t7425-submodule-encoding.sh b/t/t7425-submodule-encoding.sh index 093238939a..10703b34c8 100755 --- a/t/t7425-submodule-encoding.sh +++ b/t/t7425-submodule-encoding.sh @@ -196,4 +196,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.submoduleEncoding=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 -- 2.51.0