git/list[1] front-page[2] threads[3] people[4] search[5] about
 

[PATCH v9 04/11] submodule: introduce extensions.submodulePathConfig

From
Adrian Ratiu <adrian.ratiu@collabora.com>
Date
Jan 12, 2026, 18:46 UTC
Message-ID
<20260112184632.1334495-5-adrian.ratiu@collabora.com>
In-Reply-To
<20260112184632.1334495-1-adrian.ratiu@collabora.com>

The idea of this extension is to abstract away the submodule gitdir path implementation: everyone is expected to use the config and not worry about how the path is computed internally, either in git or other implementations.

With this extension enabled, the submodule.<name>.gitdir repo config becomes the single source of truth for all submodule gitdir paths.

The submodule.<name>.gitdir config is added automatically for all new submodules when this extension is enabled.

Git will throw an error if the extension is enabled and a config is missing, advising users how to migrate. Migration is manual for now.

E.g. to add a missing config entry for an existing "foo" module: git config submodule.foo.gitdir .git/modules/foo

Suggested-by: Junio C Hamano <gitster@pobox.com>
Suggested-by: Phillip Wood <phillip.wood123@gmail.com>
Suggested-by: Patrick Steinhardt <ps@pks.im>
Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com>
---
 Documentation/config/extensions.adoc       |  23 +++
 Documentation/config/submodule.adoc        |   7 +
 builtin/submodule--helper.c                |  54 ++++++-
 repository.c                               |   1 +
 repository.h                               |   1 +
 setup.c                                    |   7 +
 setup.h                                    |   1 +
 submodule.c                                |  61 ++++----
 t/lib-verify-submodule-gitdir-path.sh      |  24 ++++
 t/meson.build                              |   1 +
 t/t7425-submodule-gitdir-path-extension.sh | 160 +++++++++++++++++++++
 t/t9902-completion.sh                      |   1 +
 12 files changed, 313 insertions(+), 28 deletions(-)
 create mode 100644 t/lib-verify-submodule-gitdir-path.sh
 create mode 100755 t/t7425-submodule-gitdir-path-extension.sh
diff --git a/Documentation/config/extensions.adoc b/Documentation/config/extensions.adoc
index 532456644b..f4f57c9114 100644
--- a/Documentation/config/extensions.adoc
+++ b/Documentation/config/extensions.adoc
@@ -73,6 +73,29 @@ relativeWorktrees:::
 	repaired with either the `--relative-paths` option or with the
 	`worktree.useRelativePaths` config set to `true`.
 
+submodulePathConfig:::
+	This extension is for the minority of users who:
++
+--
+* Encounter errors like `refusing to create ... in another submodule's git dir`
+  due to a number of reasons, like case-insensitive filesystem conflicts when
+  creating modules named `foo` and `Foo`.
+* Require more flexible submodule layouts, for example due to nested names like
+  `foo`, `foo/bar` and `foo/baz` not supported by the default gitdir mechanism
+  which uses `.git/modules/<plain-name>` locations, causing further conflicts.
+--
++
+When `extensions.submodulePathConfig` is enabled, the `submodule.<name>.gitdir`
+config becomes the single source of truth for all submodule gitdir paths and is
+automatically set for all new submodules both during clone and init operations.
++
+Git will error out if a module does not have a corresponding
+`submodule.<name>.gitdir` set.
++
+Existing (pre-extension) submodules need to be migrated by adding the missing
+config entries. This is done manually for now, e.g. for each submodule:
+`git config submodule.<name>.gitdir .git/modules/<name>`.
+
 worktreeConfig:::
 	If enabled, then worktrees will load config settings from the
 	`$GIT_DIR/config.worktree` file in addition to the
diff --git a/Documentation/config/submodule.adoc b/Documentation/config/submodule.adoc
index 0672d99117..74f1659a91 100644
--- a/Documentation/config/submodule.adoc
+++ b/Documentation/config/submodule.adoc
@@ -52,6 +52,13 @@ submodule.<name>.active::
 	submodule.active config option. See linkgit:gitsubmodules[7] for
 	details.
 
+submodule.<name>.gitdir::
+	This sets the gitdir path for submodule <name>. This configuration is
+	respected when `extensions.submodulePathConfig` is enabled, otherwise it
+	has no effect. When enabled, this config becomes the single source of
+	truth for submodule gitdir paths and Git will error if it is missing.
+	See linkgit:git-config[1] for details.
+
 submodule.active::
 	A repeated field which contains a pathspec used to match against a
 	submodule's path to determine if the submodule is of interest to git
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c
index 901213ee71..b3d6f9ff68 100644
--- a/builtin/submodule--helper.c
+++ b/builtin/submodule--helper.c
@@ -435,6 +435,48 @@ struct init_cb {
 };
 #define INIT_CB_INIT { 0 }
 
+static int validate_and_set_submodule_gitdir(struct strbuf *gitdir_path,
+					     const char *submodule_name)
+{
+	const char *value;
+	char *key;
+
+	if (validate_submodule_git_dir(gitdir_path->buf, submodule_name))
+		return -1;
+
+	key = xstrfmt("submodule.%s.gitdir", submodule_name);
+
+	/* Nothing to do if the config already exists. */
+	if (!repo_config_get_string_tmp(the_repository, key, &value)) {
+		free(key);
+		return 0;
+	}
+
+	if (repo_config_set_gently(the_repository, key, gitdir_path->buf)) {
+		free(key);
+		return -1;
+	}
+
+	free(key);
+	return 0;
+}
+
+static void create_default_gitdir_config(const char *submodule_name)
+{
+	struct strbuf gitdir_path = STRBUF_INIT;
+
+	repo_git_path_append(the_repository, &gitdir_path, "modules/%s", submodule_name);
+	if (!validate_and_set_submodule_gitdir(&gitdir_path, submodule_name)) {
+		strbuf_release(&gitdir_path);
+		return;
+	}
+
+	die(_("failed to set a valid default config for 'submodule.%s.gitdir'. "
+	      "Please ensure it is set, for example by running something like: "
+	      "'git config submodule.%s.gitdir .git/modules/%s'"),
+	    submodule_name, submodule_name, submodule_name);
+}
+
 static void init_submodule(const char *path, const char *prefix,
 			   const char *super_prefix,
 			   unsigned int flags)
@@ -511,6 +553,10 @@ static void init_submodule(const char *path, const char *prefix,
 		if (repo_config_set_gently(the_repository, sb.buf, upd))
 			die(_("Failed to register update mode for submodule path '%s'"), displaypath);
 	}
+
+	if (the_repository->repository_format_submodule_path_cfg)
+		create_default_gitdir_config(sub->name);
+
 	strbuf_release(&sb);
 	free(displaypath);
 	free(url);
@@ -1801,8 +1847,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
 		char *head = xstrfmt("%s/HEAD", sm_gitdir);
 		unlink(head);
 		free(head);
-		die(_("refusing to create/use '%s' in another submodule's "
-		      "git dir"), sm_gitdir);
+		die(_("refusing to create/use '%s' in another submodule's git dir. "
+		      "Enabling extensions.submodulePathConfig should fix this."),
+		    sm_gitdir);
 	}
 
 	connect_work_tree_and_git_dir(clone_data_path, sm_gitdir, 0);
@@ -3582,6 +3629,9 @@ static int module_add(int argc, const char **argv, const char *prefix,
 	add_data.progress = !!progress;
 	add_data.dissociate = !!dissociate;
 
+	if (the_repository->repository_format_submodule_path_cfg)
+		create_default_gitdir_config(add_data.sm_name);
+
 	if (add_submodule(&add_data))
 		goto cleanup;
 	configure_added_submodule(&add_data);
diff --git a/repository.c b/repository.c
index c7e75215ac..46a7c99930 100644
--- a/repository.c
+++ b/repository.c
@@ -281,6 +281,7 @@ int repo_init(struct repository *repo,
 	repo->repository_format_worktree_config = format.worktree_config;
 	repo->repository_format_relative_worktrees = format.relative_worktrees;
 	repo->repository_format_precious_objects = format.precious_objects;
+	repo->repository_format_submodule_path_cfg = format.submodule_path_cfg;
 
 	/* take ownership of format.partial_clone */
 	repo->repository_format_partial_clone = format.partial_clone;
diff --git a/repository.h b/repository.h
index 6063c4b846..7141237f97 100644
--- a/repository.h
+++ b/repository.h
@@ -165,6 +165,7 @@ struct repository {
 	int repository_format_worktree_config;
 	int repository_format_relative_worktrees;
 	int repository_format_precious_objects;
+	int repository_format_submodule_path_cfg;
 
 	/* Indicate if a repository has a different 'commondir' from 'gitdir' */
 	unsigned different_commondir:1;
diff --git a/setup.c b/setup.c
index 3a6a048620..428427d689 100644
--- a/setup.c
+++ b/setup.c
@@ -686,6 +686,9 @@ static enum extension_result handle_extension(const char *var,
 	} else if (!strcmp(ext, "relativeworktrees")) {
 		data->relative_worktrees = git_config_bool(var, value);
 		return EXTENSION_OK;
+	} else if (!strcmp(ext, "submodulepathconfig")) {
+		data->submodule_path_cfg = git_config_bool(var, value);
+		return EXTENSION_OK;
 	}
 	return EXTENSION_UNKNOWN;
 }
@@ -1947,6 +1950,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
 				repo_fmt.worktree_config;
 			the_repository->repository_format_relative_worktrees =
 				repo_fmt.relative_worktrees;
+			the_repository->repository_format_submodule_path_cfg =
+				repo_fmt.submodule_path_cfg;
 			/* take ownership of repo_fmt.partial_clone */
 			the_repository->repository_format_partial_clone =
 				repo_fmt.partial_clone;
@@ -2045,6 +2050,8 @@ void check_repository_format(struct repository_format *fmt)
 				    fmt->ref_storage_format);
 	the_repository->repository_format_worktree_config =
 		fmt->worktree_config;
+	the_repository->repository_format_submodule_path_cfg =
+		fmt->submodule_path_cfg;
 	the_repository->repository_format_relative_worktrees =
 		fmt->relative_worktrees;
 	the_repository->repository_format_partial_clone =
diff --git a/setup.h b/setup.h
index d55dcc6608..0738dec244 100644
--- a/setup.h
+++ b/setup.h
@@ -167,6 +167,7 @@ struct repository_format {
 	char *partial_clone; /* value of extensions.partialclone */
 	int worktree_config;
 	int relative_worktrees;
+	int submodule_path_cfg;
 	int is_bare;
 	int hash_algo;
 	int compat_hash_algo;
diff --git a/submodule.c b/submodule.c
index f645372a18..e0cd6f5dcc 100644
--- a/submodule.c
+++ b/submodule.c
@@ -31,6 +31,7 @@
 #include "commit-reach.h"
 #include "read-cache-ll.h"
 #include "setup.h"
+#include "advice.h"
 
 static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
 static int initialized_fetch_ref_tips;
@@ -2158,8 +2159,9 @@ int submodule_move_head(const char *path, const char *super_prefix,
 				if (validate_submodule_git_dir(git_dir,
 							       sub->name) < 0)
 					die(_("refusing to create/use '%s' in "
-					      "another submodule's git dir"),
-					    git_dir);
+					      "another submodule's git dir. "
+					      "Enabling extensions.submodulePathConfig "
+					      "should fix this."), git_dir);
 				free(git_dir);
 			}
 		} else {
@@ -2570,30 +2572,37 @@ int submodule_to_gitdir(struct repository *repo,
 void submodule_name_to_gitdir(struct strbuf *buf, struct repository *r,
 			      const char *submodule_name)
 {
-	/*
-	 * NEEDSWORK: The current way of mapping a submodule's name to
-	 * its location in .git/modules/ has problems with some naming
-	 * schemes. For example, if a submodule is named "foo" and
-	 * another is named "foo/bar" (whether present in the same
-	 * superproject commit or not - the problem will arise if both
-	 * superproject commits have been checked out at any point in
-	 * time), or if two submodule names only have different cases in
-	 * a case-insensitive filesystem.
-	 *
-	 * There are several solutions, including encoding the path in
-	 * some way, introducing a submodule.<name>.gitdir config in
-	 * .git/config (not .gitmodules) that allows overriding what the
-	 * gitdir of a submodule would be (and teach Git, upon noticing
-	 * a clash, to automatically determine a non-clashing name and
-	 * to write such a config), or introducing a
-	 * submodule.<name>.gitdir config in .gitmodules that repo
-	 * administrators can explicitly set. Nothing has been decided,
-	 * so for now, just append the name at the end of the path.
-	 */
-	repo_git_path_append(r, buf, "modules/");
-	strbuf_addstr(buf, submodule_name);
+	if (!r->repository_format_submodule_path_cfg) {
+		/*
+		 * If extensions.submodulePathConfig is disabled,
+		 * continue to use the plain path.
+		 */
+		repo_git_path_append(r, buf, "modules/%s", submodule_name);
+	} else {
+		const char *gitdir;
+		char *key;
+		int ret;
 
-	if (validate_submodule_git_dir(buf->buf, submodule_name) < 0)
+		/* Otherwise the extension is enabled, so use the gitdir config. */
+		key = xstrfmt("submodule.%s.gitdir", submodule_name);
+		ret = repo_config_get_string_tmp(r, key, &gitdir);
+		FREE_AND_NULL(key);
+
+		if (ret)
+			die(_("the 'submodule.%s.gitdir' config does not exist for module '%s'. "
+			      "Please ensure it is set, for example by running something like: "
+			      "'git config submodule.%s.gitdir .git/modules/%s'. For details "
+			      "see the extensions.submodulePathConfig documentation."),
+			    submodule_name, submodule_name, submodule_name, submodule_name);
+
+		strbuf_addstr(buf, gitdir);
+	}
+
+	/* validate because users might have modified the config */
+	if (validate_submodule_git_dir(buf->buf, submodule_name)) {
+		advise(_("enabling extensions.submodulePathConfig might fix the "
+			 "following error, if it's not already enabled."));
 		die(_("refusing to create/use '%s' in another submodule's "
-		      "git dir"), buf->buf);
+		      " git dir."), buf->buf);
+	}
 }
diff --git a/t/lib-verify-submodule-gitdir-path.sh b/t/lib-verify-submodule-gitdir-path.sh
new file mode 100644
index 0000000000..4e0cfdc605
--- /dev/null
+++ b/t/lib-verify-submodule-gitdir-path.sh
@@ -0,0 +1,24 @@
+# Helper to verify if repo $1 contains a submodule named $2 with gitdir path $3
+
+# This does not check filesystem existence. That is done in submodule.c via the
+# submodule_name_to_gitdir() API which this helper ends up calling. The gitdirs
+# might or might not exist (e.g. when adding a new submodule), so this only
+# checks the expected configuration path, which might be overridden by the user.
+
+verify_submodule_gitdir_path () {
+	repo="$1" &&
+	name="$2" &&
+	path="$3" &&
+	(
+		cd "$repo" &&
+		# Compute expected absolute path
+		expected="$(git rev-parse --git-common-dir)/$path" &&
+		expected="$(test-tool path-utils real_path "$expected")" &&
+		# Compute actual absolute path
+		actual="$(git submodule--helper gitdir "$name")" &&
+		actual="$(test-tool path-utils real_path "$actual")" &&
+		echo "$expected" >expect &&
+		echo "$actual" >actual &&
+		test_cmp expect actual
+	)
+}
diff --git a/t/meson.build b/t/meson.build
index 459c52a489..0b1de3251a 100644
--- a/t/meson.build
+++ b/t/meson.build
@@ -887,6 +887,7 @@ integration_tests = [
   't7422-submodule-output.sh',
   't7423-submodule-symlinks.sh',
   't7424-submodule-mixed-ref-formats.sh',
+  't7425-submodule-gitdir-path-extension.sh',
   't7450-bad-git-dotfiles.sh',
   't7500-commit-template-squash-signoff.sh',
   't7501-commit-basic-functionality.sh',
diff --git a/t/t7425-submodule-gitdir-path-extension.sh b/t/t7425-submodule-gitdir-path-extension.sh
new file mode 100755
index 0000000000..453183e27c
--- /dev/null
+++ b/t/t7425-submodule-gitdir-path-extension.sh
@@ -0,0 +1,160 @@
+#!/bin/sh
+
+test_description='submodulePathConfig extension works as expected'
+
+. ./test-lib.sh
+. "$TEST_DIRECTORY"/lib-verify-submodule-gitdir-path.sh
+
+test_expect_success 'setup: allow file protocol' '
+       git config --global protocol.file.allow always
+'
+
+test_expect_success 'create repo with mixed extension submodules' '
+	git init -b main legacy-sub &&
+	test_commit -C legacy-sub legacy-initial &&
+	legacy_rev=$(git -C legacy-sub rev-parse HEAD) &&
+
+	git init -b main new-sub &&
+	test_commit -C new-sub new-initial &&
+	new_rev=$(git -C new-sub rev-parse HEAD) &&
+
+	git init -b main main &&
+	(
+		cd main &&
+		git submodule add ../legacy-sub legacy &&
+		test_commit legacy-sub &&
+
+		# trigger the "die_path_inside_submodule" check
+		test_must_fail git submodule add ../new-sub "legacy/nested" &&
+
+		git config core.repositoryformatversion 1 &&
+		git config extensions.submodulePathConfig true &&
+
+		git submodule add ../new-sub "New Sub" &&
+		test_commit new &&
+
+		# retrigger the "die_path_inside_submodule" check with encoding
+		test_must_fail git submodule add ../new-sub "New Sub/nested2"
+       )
+'
+
+test_expect_success 'verify new submodule gitdir config' '
+	git -C main config submodule."New Sub".gitdir >actual &&
+	echo ".git/modules/New Sub" >expect &&
+	test_cmp expect actual &&
+	verify_submodule_gitdir_path main "New Sub" "modules/New Sub"
+'
+
+test_expect_success 'manual add and verify legacy submodule gitdir config' '
+	# the legacy module should not contain a gitdir config, because it
+	# was added before the extension was enabled. Add and test it.
+	test_must_fail git -C main config submodule.legacy.gitdir &&
+	git -C main config submodule.legacy.gitdir .git/modules/legacy &&
+	git -C main config submodule.legacy.gitdir >actual &&
+	echo ".git/modules/legacy" >expect &&
+	test_cmp expect actual &&
+	verify_submodule_gitdir_path main "legacy" "modules/legacy"
+'
+
+test_expect_success 'gitdir config path is relative for both absolute and relative urls' '
+	test_when_finished "rm -rf relative-cfg-path-test" &&
+	git init -b main relative-cfg-path-test &&
+	(
+		cd relative-cfg-path-test &&
+		git config core.repositoryformatversion 1 &&
+		git config extensions.submodulePathConfig true &&
+
+		# Test with absolute URL
+		git submodule add "$TRASH_DIRECTORY/new-sub" sub-abs &&
+		git config submodule.sub-abs.gitdir >actual &&
+		echo ".git/modules/sub-abs" >expect &&
+		test_cmp expect actual &&
+
+		# Test with relative URL
+		git submodule add ../new-sub sub-rel &&
+		git config submodule.sub-rel.gitdir >actual &&
+		echo ".git/modules/sub-rel" >expect &&
+		test_cmp expect actual
+	)
+'
+
+test_expect_success 'clone from repo with both legacy and new-style submodules' '
+	git clone --recurse-submodules main cloned-non-extension &&
+	(
+		cd cloned-non-extension &&
+
+		test_path_is_dir .git/modules/legacy &&
+		test_path_is_dir .git/modules/"New Sub" &&
+
+		test_must_fail git config submodule.legacy.gitdir &&
+		test_must_fail git config submodule."New Sub".gitdir &&
+
+		git submodule status >list &&
+		test_grep "$legacy_rev legacy" list &&
+		test_grep "$new_rev New Sub" list
+	) &&
+
+	git clone -c extensions.submodulePathConfig=true --recurse-submodules main cloned-extension &&
+	(
+		cd cloned-extension &&
+
+		test_path_is_dir .git/modules/legacy &&
+		test_path_is_dir ".git/modules/New Sub" &&
+
+		git config submodule.legacy.gitdir &&
+		git config submodule."New Sub".gitdir &&
+
+		git submodule status >list &&
+		test_grep "$legacy_rev legacy" list &&
+		test_grep "$new_rev New Sub" list
+	)
+'
+
+test_expect_success 'commit and push changes to encoded submodules' '
+	git -C legacy-sub config receive.denyCurrentBranch updateInstead &&
+	git -C new-sub config receive.denyCurrentBranch updateInstead &&
+	git -C main config receive.denyCurrentBranch updateInstead &&
+	(
+		cd cloned-extension &&
+
+		git -C legacy switch --track -C main origin/main  &&
+		test_commit -C legacy second-commit &&
+		git -C legacy push &&
+
+		git -C "New Sub" switch --track -C main origin/main &&
+		test_commit -C "New Sub" second-commit &&
+		git -C "New Sub" push &&
+
+		# Stage and commit submodule changes in superproject
+		git switch --track -C main origin/main  &&
+		git add legacy "New Sub" &&
+		git commit -m "update submodules" &&
+
+		# push superproject commit to main repo
+		git push
+	) &&
+
+	# update expected legacy & new submodule checksums
+	legacy_rev=$(git -C legacy-sub rev-parse HEAD) &&
+	new_rev=$(git -C new-sub rev-parse HEAD)
+'
+
+test_expect_success 'fetch mixed submodule changes and verify updates' '
+	(
+		cd main &&
+
+		# only update submodules because superproject was
+		# pushed into at the end of last test
+		git submodule update --init --recursive &&
+
+		test_path_is_dir .git/modules/legacy &&
+		test_path_is_dir ".git/modules/New Sub" &&
+
+		# Verify both submodules are at the expected commits
+		git submodule status >list &&
+		test_grep "$legacy_rev legacy" list &&
+		test_grep "$new_rev New Sub" list
+	)
+'
+
+test_done
diff --git a/t/t9902-completion.sh b/t/t9902-completion.sh
index 964e1f1569..ffb9c8b522 100755
--- a/t/t9902-completion.sh
+++ b/t/t9902-completion.sh
@@ -3053,6 +3053,7 @@ test_expect_success 'git config set - variable name - __git_compute_second_level
 	submodule.sub.fetchRecurseSubmodules Z
 	submodule.sub.ignore Z
 	submodule.sub.active Z
+	submodule.sub.gitdir Z
 	EOF
 '
 
-- 
2.52.0
Previous: Adrian RatiuNext: Adrian Ratiu
Message 209 of 219 in “Encode submodule gitdir names to avoid conflicts”
  1. 0/9 Encode submodule gitdir names to avoid conflictsAdrian Ratiu, Aug 16, 2025
  2. 1/9 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Aug 16, 2025
  3. Josh SteadmonAug 20, 2025
  4. Adrian RatiuAug 21, 2025
  5. 2/9 submodule: create new gitdirs under submodules pathAdrian Ratiu, Aug 16, 2025
  6. Phillip WoodSep 8, 2025
  7. Adrian RatiuSep 8, 2025
  8. Phillip WoodSep 9, 2025
  9. Adrian RatiuSep 9, 2025
  10. 3/9 submodule: add gitdir path config overrideAdrian Ratiu, Aug 16, 2025
  11. Josh SteadmonAug 20, 2025
  12. Adrian RatiuAug 21, 2025
  13. Josh SteadmonAug 20, 2025
  14. Adrian RatiuAug 21, 2025
  15. Josh SteadmonAug 20, 2025
  16. Adrian RatiuAug 21, 2025
  17. Phillip WoodSep 8, 2025
  18. Adrian RatiuSep 9, 2025
  19. 4/9 t: submodules: add basic mixed gitdir path testsAdrian Ratiu, Aug 16, 2025
  20. Josh SteadmonAug 20, 2025
  21. Junio C HamanoSep 2, 2025
  22. 5/9 strbuf: bring back is_rfc3986_unreservedAdrian Ratiu, Aug 16, 2025
  23. Ben KnobleAug 16, 2025
  24. Adrian RatiuAug 21, 2025
  25. 6/9 submodule: encode gitdir paths to avoid conflictsAdrian Ratiu, Aug 16, 2025
  26. Jeff KingAug 20, 2025
  27. Adrian RatiuAug 21, 2025
  28. 7/9 submodule: remove validate_submodule_git_dir()Adrian Ratiu, Aug 16, 2025
  29. Phillip WoodSep 8, 2025
  30. 8/9 t: move nested gitdir tests to proper locationAdrian Ratiu, Aug 16, 2025
  31. 9/9 t: add gitdir encoding testsAdrian Ratiu, Aug 16, 2025
  32. Junio C HamanoAug 18, 2025
  33. Adrian RatiuAug 21, 2025
  34. Adrian RatiuAug 17, 2025
  35. 00/10 Encode submodule gitdir names to avoid conflictsAdrian Ratiu, Sep 8, 2025
  36. 01/10 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Sep 8, 2025
  37. Kristoffer HaugsbakkSep 30, 2025
  38. 03/10 submodule: add gitdir path config overrideAdrian Ratiu, Sep 8, 2025
  39. Patrick SteinhardtSep 9, 2025
  40. Adrian RatiuSep 9, 2025
  41. 02/10 submodule: create new gitdirs under submodules pathAdrian Ratiu, Sep 8, 2025
  42. Patrick SteinhardtSep 9, 2025
  43. Adrian RatiuSep 9, 2025
  44. 05/10 strbuf: bring back is_rfc3986_unreservedAdrian Ratiu, Sep 8, 2025
  45. 04/10 t7425: add basic mixed submodule gitdir path testsAdrian Ratiu, Sep 8, 2025
  46. 06/10 submodule: encode gitdir paths to avoid conflictsAdrian Ratiu, Sep 8, 2025
  47. SZEDER GáborSep 10, 2025
  48. Adrian RatiuSep 10, 2025
  49. Kristoffer HaugsbakkSep 10, 2025
  50. Kristoffer HaugsbakkSep 30, 2025
  51. 07/10 submodule: error out if gitdir name is too longAdrian Ratiu, Sep 8, 2025
  52. Jeff KingSep 8, 2025
  53. Adrian RatiuSep 8, 2025
  54. Kristoffer HaugsbakkSep 30, 2025
  55. 08/10 submodule: remove validate_submodule_git_dir()Adrian Ratiu, Sep 8, 2025
  56. Kristoffer HaugsbakkSep 30, 2025
  57. Adrian RatiuOct 3, 2025
  58. 09/10 t7450: move nested gitdir tests to t7425Adrian Ratiu, Sep 8, 2025
  59. 10/10 t7425: add gitdir encoding testsAdrian Ratiu, Sep 8, 2025
  60. 0/5 Encode submodule gitdir names to avoid conflictsAdrian Ratiu, Oct 6, 2025
  61. 2/5 submodule: add gitdir path config overrideAdrian Ratiu, Oct 6, 2025
  62. Junio C HamanoOct 6, 2025
  63. Junio C HamanoOct 7, 2025
  64. Patrick SteinhardtOct 21, 2025
  65. Adrian RatiuOct 21, 2025
  66. Patrick SteinhardtOct 21, 2025
  67. Adrian RatiuOct 21, 2025
  68. 1/5 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Oct 6, 2025
  69. Junio C HamanoOct 6, 2025
  70. Adrian RatiuOct 7, 2025
  71. 4/5 submodule: encode gitdir paths to avoid conflictsAdrian Ratiu, Oct 6, 2025
  72. Junio C HamanoOct 6, 2025
  73. Adrian RatiuOct 7, 2025
  74. Junio C HamanoOct 7, 2025
  75. Adrian RatiuOct 7, 2025
  76. Junio C HamanoOct 7, 2025
  77. 5/5 submodule: error out if gitdir name is too longAdrian Ratiu, Oct 6, 2025
  78. Junio C HamanoOct 6, 2025
  79. Adrian RatiuOct 7, 2025
  80. Junio C HamanoOct 7, 2025
  81. Patrick SteinhardtOct 21, 2025
  82. Adrian RatiuOct 21, 2025
  83. 3/5 strbuf: bring back is_rfc3986_unreservedAdrian Ratiu, Oct 6, 2025
  84. Junio C HamanoOct 6, 2025
  85. Junio C HamanoOct 6, 2025
  86. Adrian RatiuOct 7, 2025
  87. Patrick SteinhardtOct 21, 2025
  88. Junio C HamanoOct 6, 2025
  89. Adrian RatiuOct 7, 2025
  90. Junio C HamanoOct 7, 2025
  91. Adrian RatiuOct 7, 2025
  92. Junio C HamanoOct 7, 2025
  93. Junio C HamanoOct 7, 2025
  94. Adrian RatiuOct 7, 2025
  95. 0/4 Encode submodule gitdir names to avoid conflictsAdrian Ratiu, Nov 7, 2025
  96. 3/4 submodule: add extension to encode gitdir pathsAdrian Ratiu, Nov 7, 2025
  97. 2/4 builtin/credential-store: move is_rfc3986_unreserved to url.[ch]Adrian Ratiu, Nov 7, 2025
  98. 1/4 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Nov 7, 2025
  99. 4/4 submodule: fix case-folding gitdir filesystem colisionsAdrian Ratiu, Nov 7, 2025
  100. Aaron SchrabNov 8, 2025
  101. Adrian RatiuNov 10, 2025
  102. Aaron SchrabNov 10, 2025
  103. Adrian RatiuNov 10, 2025
  104. Junio C HamanoNov 10, 2025
  105. Adrian RatiuNov 10, 2025
  106. Junio C HamanoNov 10, 2025
  107. Adrian RatiuNov 11, 2025
  108. Adrian RatiuNov 12, 2025
  109. Josh SteadmonNov 14, 2025
  110. Adrian RatiuNov 17, 2025
  111. 0/7 Encode submodule gitdir names to avoid conflictsAdrian Ratiu, Nov 19, 2025
  112. 2/7 builtin/credential-store: move is_rfc3986_unreserved to url.[ch]Adrian Ratiu, Nov 19, 2025
  113. Patrick SteinhardtDec 5, 2025
  114. Adrian RatiuDec 5, 2025
  115. 1/7 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Nov 19, 2025
  116. 3/7 submodule: always validate gitdirs inside submodule_name_to_gitdirAdrian Ratiu, Nov 19, 2025
  117. Patrick SteinhardtDec 5, 2025
  118. Adrian RatiuDec 5, 2025
  119. 4/7 submodule: add extension to encode gitdir pathsAdrian Ratiu, Nov 19, 2025
  120. Patrick SteinhardtDec 5, 2025
  121. Adrian RatiuDec 5, 2025
  122. Junio C HamanoDec 5, 2025
  123. Patrick SteinhardtDec 6, 2025
  124. Junio C HamanoDec 6, 2025
  125. Adrian RatiuDec 8, 2025
  126. Patrick SteinhardtDec 8, 2025
  127. Adrian RatiuDec 8, 2025
  128. Adrian RatiuDec 8, 2025
  129. 5/7 submodule: fix case-folding gitdir filesystem colisionsAdrian Ratiu, Nov 19, 2025
  130. 6/7 submodule: use hashed name for gitdirAdrian Ratiu, Nov 19, 2025
  131. 7/7 meson/Makefile: allow setting submodule encoding at build timeAdrian Ratiu, Nov 19, 2025
  132. Patrick SteinhardtDec 5, 2025
  133. Adrian RatiuDec 5, 2025
  134. Junio C HamanoDec 5, 2025
  135. Patrick SteinhardtDec 6, 2025
  136. Junio C HamanoDec 6, 2025
  137. Adrian RatiuDec 8, 2025
  138. Adrian RatiuDec 8, 2025
  139. 00/10 Add submodulePathConfig extension and gitdir encodingAdrian Ratiu, Dec 13, 2025
  140. 02/10 submodule: always validate gitdirs inside submodule_name_to_gitdirAdrian Ratiu, Dec 13, 2025
  141. Patrick SteinhardtDec 16, 2025
  142. 03/10 builtin/submodule--helper: add gitdir commandAdrian Ratiu, Dec 13, 2025
  143. 01/10 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Dec 13, 2025
  144. 04/10 submodule: introduce extensions.submodulePathConfigAdrian Ratiu, Dec 13, 2025
  145. Patrick SteinhardtDec 16, 2025
  146. Adrian RatiuDec 16, 2025
  147. Josh SteadmonDec 16, 2025
  148. Adrian RatiuDec 17, 2025
  149. 05/10 submodule: allow runtime enabling extensions.submodulePathConfigAdrian Ratiu, Dec 13, 2025
  150. Patrick SteinhardtDec 16, 2025
  151. Adrian RatiuDec 16, 2025
  152. 06/10 submodule--helper: add gitdir migration commandAdrian Ratiu, Dec 13, 2025
  153. Patrick SteinhardtDec 16, 2025
  154. Adrian RatiuDec 16, 2025
  155. 07/10 builtin/credential-store: move is_rfc3986_unreserved to url.[ch]Adrian Ratiu, Dec 13, 2025
  156. 08/10 submodule--helper: fix filesystem collisions by encoding gitdir pathsAdrian Ratiu, Dec 13, 2025
  157. 09/10 submodule: fix case-folding gitdir filesystem collisionsAdrian Ratiu, Dec 13, 2025
  158. 10/10 submodule: hash the submodule name for the gitdir pathAdrian Ratiu, Dec 13, 2025
  159. Ben KnobleDec 13, 2025
  160. Adrian RatiuDec 15, 2025
  161. Junio C HamanoDec 16, 2025
  162. Ben KnobleDec 18, 2025
  163. Josh SteadmonDec 16, 2025
  164. Adrian RatiuDec 17, 2025
  165. 00/11 Add submodulePathConfig extension and gitdir encodingAdrian Ratiu, Dec 20, 2025
  166. 01/11 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Dec 20, 2025
  167. 02/11 submodule: always validate gitdirs inside submodule_name_to_gitdirAdrian Ratiu, Dec 20, 2025
  168. 03/11 builtin/submodule--helper: add gitdir commandAdrian Ratiu, Dec 20, 2025
  169. 04/11 submodule: introduce extensions.submodulePathConfigAdrian Ratiu, Dec 20, 2025
  170. Junio C HamanoDec 21, 2025
  171. Adrian RatiuDec 23, 2025
  172. Patrick SteinhardtJan 6, 2026
  173. Adrian RatiuJan 7, 2026
  174. 05/11 submodule: allow runtime enabling extensions.submodulePathConfigAdrian Ratiu, Dec 20, 2025
  175. Patrick SteinhardtJan 6, 2026
  176. Adrian RatiuJan 7, 2026
  177. 06/11 submodule--helper: add gitdir migration commandAdrian Ratiu, Dec 20, 2025
  178. Patrick SteinhardtJan 6, 2026
  179. Adrian RatiuJan 7, 2026
  180. 07/11 builtin/credential-store: move is_rfc3986_unreserved to url.[ch]Adrian Ratiu, Dec 20, 2025
  181. 08/11 submodule--helper: fix filesystem collisions by encoding gitdir pathsAdrian Ratiu, Dec 20, 2025
  182. 09/11 submodule: fix case-folding gitdir filesystem collisionsAdrian Ratiu, Dec 20, 2025
  183. 10/11 submodule: hash the submodule name for the gitdir pathAdrian Ratiu, Dec 20, 2025
  184. 11/11 submodule: detect conflicts with existing gitdir configsAdrian Ratiu, Dec 20, 2025
  185. Patrick SteinhardtJan 6, 2026
  186. Junio C HamanoDec 21, 2025
  187. Patrick SteinhardtJan 6, 2026
  188. 00/11 Add submodulePathConfig extension and gitdir encodingAdrian Ratiu, Jan 7, 2026
  189. 01/11 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Jan 7, 2026
  190. 02/11 submodule: always validate gitdirs inside submodule_name_to_gitdirAdrian Ratiu, Jan 7, 2026
  191. 03/11 builtin/submodule--helper: add gitdir commandAdrian Ratiu, Jan 7, 2026
  192. 04/11 submodule: introduce extensions.submodulePathConfigAdrian Ratiu, Jan 7, 2026
  193. 05/11 submodule: allow runtime enabling extensions.submodulePathConfigAdrian Ratiu, Jan 7, 2026
  194. Patrick SteinhardtJan 8, 2026
  195. 06/11 submodule--helper: add gitdir migration commandAdrian Ratiu, Jan 7, 2026
  196. Patrick SteinhardtJan 8, 2026
  197. 07/11 builtin/credential-store: move is_rfc3986_unreserved to url.[ch]Adrian Ratiu, Jan 7, 2026
  198. 08/11 submodule--helper: fix filesystem collisions by encoding gitdir pathsAdrian Ratiu, Jan 7, 2026
  199. 09/11 submodule: fix case-folding gitdir filesystem collisionsAdrian Ratiu, Jan 7, 2026
  200. 10/11 submodule: hash the submodule name for the gitdir pathAdrian Ratiu, Jan 7, 2026
  201. 11/11 submodule: detect conflicts with existing gitdir configsAdrian Ratiu, Jan 7, 2026
  202. Patrick SteinhardtJan 8, 2026
  203. Josh SteadmonJan 8, 2026
  204. Junio C HamanoJan 11, 2026
  205. 00/11 Add submodulePathConfig extension and gitdir encodingAdrian Ratiu, Jan 12, 2026
  206. 02/11 submodule: always validate gitdirs inside submodule_name_to_gitdirAdrian Ratiu, Jan 12, 2026
  207. 01/11 submodule--helper: use submodule_name_to_gitdir in add_submoduleAdrian Ratiu, Jan 12, 2026
  208. 03/11 builtin/submodule--helper: add gitdir commandAdrian Ratiu, Jan 12, 2026
  209. 04/11 submodule: introduce extensions.submodulePathConfigAdrian Ratiu, Jan 12, 2026
  210. 05/11 submodule: allow runtime enabling extensions.submodulePathConfigAdrian Ratiu, Jan 12, 2026
  211. 06/11 submodule--helper: add gitdir migration commandAdrian Ratiu, Jan 12, 2026
  212. 07/11 builtin/credential-store: move is_rfc3986_unreserved to url.[ch]Adrian Ratiu, Jan 12, 2026
  213. 08/11 submodule--helper: fix filesystem collisions by encoding gitdir pathsAdrian Ratiu, Jan 12, 2026
  214. 09/11 submodule: fix case-folding gitdir filesystem collisionsAdrian Ratiu, Jan 12, 2026
  215. 10/11 submodule: hash the submodule name for the gitdir pathAdrian Ratiu, Jan 12, 2026
  216. 11/11 submodule: detect conflicts with existing gitdir configsAdrian Ratiu, Jan 12, 2026
  217. Junio C HamanoJan 12, 2026
  218. Adrian RatiuJan 12, 2026
  219. Patrick SteinhardtJan 13, 2026

Read the whole thread, see it on lore, or plain text.

$ cat FOOTERMessages come from the public archive at lore.kernel.org/git, fetched every hour. The front page is chosen and written each morning by an AI editor and can be wrong; the threads themselves are the record. About and API. For agents: an MCP server at https://gitlist.dev/mcp, and any thread, story or person page as Markdown by adding .md to its URL (or sending Accept: text/markdown). Details in /llms.txt.