submodule: allow runtime enabling extensions.submodulePathConfig
Add a new config `init.defaultSubmodulePathConfig` which allows enabling `extensions.submodulePathConfig` for new submodules by default (those created via git init or clone). Important: setting init.defaultSubmodulePathConfig = true does not globally enable `extensions.submodulePathConfig`. Existing repositories will still have the extension disabled and will require migration (for example via git submodule--helper command added in the next commit). Suggested-by: Patrick Steinhardt <ps@pks.im> Suggested-by: Junio C Hamano <gitster@pobox.com> Signed-off-by: Adrian Ratiu <adrian.ratiu@collabora.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Adrian Ratiu committed
Jan 12, 2026 at 20:46 UTC
c349bad72969d59758e1294b4e9964dccd967fa0
4 files changed
+142
Documentation/config/extensions.adoc
+4
@@ -95,6 +95,10 @@ Git will error out if a module does not have a corresponding
95
Existing (pre-extension) submodules need to be migrated by adding the missing
96
config entries. This is done manually for now, e.g. for each submodule:
97
`git config submodule.<name>.gitdir .git/modules/<name>`.
98
++
99
+The extension can be enabled automatically for new repositories by setting
100
+`init.defaultSubmodulePathConfig` to `true`, for example by running
101
+`git config --global init.defaultSubmodulePathConfig true`.
102
103
worktreeConfig:::
104
If enabled, then worktrees will load config settings from the
Documentation/config/init.adoc
+6
@@ -18,3 +18,9 @@ endif::[]
18
See `--ref-format=` in linkgit:git-init[1]. Both the command line
19
option and the `GIT_DEFAULT_REF_FORMAT` environment variable take
20
precedence over this config.
21
+
22
+init.defaultSubmodulePathConfig::
23
+ A boolean that specifies if `git init` and `git clone` should
24
+ automatically set `extensions.submodulePathConfig` to `true`. This
25
+ allows all new repositories to automatically use the submodule path
26
+ extension. Defaults to `false` when unset.
setup.c
+10
@@ -2228,6 +2228,7 @@ void initialize_repository_version(int hash_algo,
2228
{
2229
struct strbuf repo_version = STRBUF_INIT;
2230
int target_version = GIT_REPO_VERSION;
2231
+ int default_submodule_path_config = 0;
2232
2233
/*
2234
* Note that we initialize the repository version to 1 when the ref
@@ -2266,6 +2267,15 @@ void initialize_repository_version(int hash_algo,
2267
clear_repository_format(&repo_fmt);
2268
}
2269
2270
+ repo_config_get_bool(the_repository, "init.defaultSubmodulePathConfig",
2271
+ &default_submodule_path_config);
2272
+ if (default_submodule_path_config) {
2273
+ /* extensions.submodulepathconfig requires at least version 1 */
2274
+ if (target_version == 0)
2275
+ target_version = 1;
2276
+ repo_config_set(the_repository, "extensions.submodulepathconfig", "true");
2277
+ }
2278
+
2279
strbuf_addf(&repo_version, "%d", target_version);
2280
repo_config_set(the_repository, "core.repositoryformatversion", repo_version.buf);
2281
t/t7425-submodule-gitdir-path-extension.sh
+122
@@ -157,4 +157,126 @@ test_expect_success 'fetch mixed submodule changes and verify updates' '
157
)
158
'
159
160
+test_expect_success '`git init` respects init.defaultSubmodulePathConfig' '
161
+ test_config_global init.defaultSubmodulePathConfig true &&
162
+ git init repo-init &&
163
+ git -C repo-init config extensions.submodulePathConfig >actual &&
164
+ echo true >expect &&
165
+ test_cmp expect actual &&
166
+ # create a submodule and check gitdir
167
+ (
168
+ cd repo-init &&
169
+ git init -b main sub &&
170
+ test_commit -C sub sub-initial &&
171
+ git submodule add ./sub sub &&
172
+ git config submodule.sub.gitdir >actual &&
173
+ echo ".git/modules/sub" >expect &&
174
+ test_cmp expect actual
175
+ )
176
+'
177
+
178
+test_expect_success '`git init` does not set extension by default' '
179
+ git init upstream &&
180
+ test_commit -C upstream initial &&
181
+ test_must_fail git -C upstream config extensions.submodulePathConfig &&
182
+ # create a pair of submodules and check gitdir is not created
183
+ git init -b main sub &&
184
+ test_commit -C sub sub-initial &&
185
+ (
186
+ cd upstream &&
187
+ git submodule add ../sub sub1 &&
188
+ test_path_is_dir .git/modules/sub1 &&
189
+ test_must_fail git config submodule.sub1.gitdir &&
190
+ git submodule add ../sub sub2 &&
191
+ test_path_is_dir .git/modules/sub2 &&
192
+ test_must_fail git config submodule.sub2.gitdir &&
193
+ git commit -m "Add submodules"
194
+ )
195
+'
196
+
197
+test_expect_success '`git clone` does not set extension by default' '
198
+ test_when_finished "rm -rf repo-clone-no-ext" &&
199
+ git clone upstream repo-clone-no-ext &&
200
+ (
201
+ cd repo-clone-no-ext &&
202
+
203
+ test_must_fail git config extensions.submodulePathConfig &&
204
+ test_path_is_missing .git/modules/sub1 &&
205
+ test_path_is_missing .git/modules/sub2 &&
206
+
207
+ # create a submodule and check gitdir is not created
208
+ git submodule add ../sub sub3 &&
209
+ test_must_fail git config submodule.sub3.gitdir
210
+ )
211
+'
212
+
213
+test_expect_success '`git clone --recurse-submodules` does not set extension by default' '
214
+ test_when_finished "rm -rf repo-clone-no-ext" &&
215
+ git clone --recurse-submodules upstream repo-clone-no-ext &&
216
+ (
217
+ cd repo-clone-no-ext &&
218
+
219
+ # verify that that submodules do not have gitdir set
220
+ test_must_fail git config extensions.submodulePathConfig &&
221
+ test_path_is_dir .git/modules/sub1 &&
222
+ test_must_fail git config submodule.sub1.gitdir &&
223
+ test_path_is_dir .git/modules/sub2 &&
224
+ test_must_fail git config submodule.sub2.gitdir &&
225
+
226
+ # create another submodule and check that gitdir is not created
227
+ git submodule add ../sub sub3 &&
228
+ test_path_is_dir .git/modules/sub3 &&
229
+ test_must_fail git config submodule.sub3.gitdir
230
+ )
231
+
232
+'
233
+
234
+test_expect_success '`git clone` respects init.defaultSubmodulePathConfig' '
235
+ test_when_finished "rm -rf repo-clone" &&
236
+ test_config_global init.defaultSubmodulePathConfig true &&
237
+ git clone upstream repo-clone &&
238
+ (
239
+ cd repo-clone &&
240
+
241
+ # verify new repo extension is inherited from global config
242
+ git config extensions.submodulePathConfig >actual &&
243
+ echo true >expect &&
244
+ test_cmp expect actual &&
245
+
246
+ # new submodule has a gitdir config
247
+ git submodule add ../sub sub &&
248
+ test_path_is_dir .git/modules/sub &&
249
+ git config submodule.sub.gitdir >actual &&
250
+ echo ".git/modules/sub" >expect &&
251
+ test_cmp expect actual
252
+ )
253
+'
254
+
255
+test_expect_success '`git clone --recurse-submodules` respects init.defaultSubmodulePathConfig' '
256
+ test_when_finished "rm -rf repo-clone-recursive" &&
257
+ test_config_global init.defaultSubmodulePathConfig true &&
258
+ git clone --recurse-submodules upstream repo-clone-recursive &&
259
+ (
260
+ cd repo-clone-recursive &&
261
+
262
+ # verify new repo extension is inherited from global config
263
+ git config extensions.submodulePathConfig >actual &&
264
+ echo true >expect &&
265
+ test_cmp expect actual &&
266
+
267
+ # previous submodules should exist
268
+ git config submodule.sub1.gitdir &&
269
+ git config submodule.sub2.gitdir &&
270
+ test_path_is_dir .git/modules/sub1 &&
271
+ test_path_is_dir .git/modules/sub2 &&
272
+
273
+ # create another submodule and check that gitdir is created
274
+ git submodule add ../sub new-sub &&
275
+ test_path_is_dir .git/modules/new-sub &&
276
+ git config submodule.new-sub.gitdir >actual &&
277
+ echo ".git/modules/new-sub" >expect &&
278
+ test_cmp expect actual
279
+ )
280
+'
281
+
282
test_done