3434#include "list-objects-filter-options.h"
3535#include "wildmatch.h"
3636#include "strbuf.h"
37+ #include "url.h"
3738
3839#define OPT_QUIET (1 << 0)
3940#define OPT_CACHED (1 << 1)
@@ -435,6 +436,102 @@ struct init_cb {
435436};
436437#define INIT_CB_INIT { 0 }
437438
439+ static int validate_and_set_submodule_gitdir (struct strbuf * gitdir_path ,
440+ const char * submodule_name )
441+ {
442+ const char * value ;
443+ char * key ;
444+
445+ if (validate_submodule_git_dir (gitdir_path -> buf , submodule_name ))
446+ return -1 ;
447+
448+ key = xstrfmt ("submodule.%s.gitdir" , submodule_name );
449+
450+ /* Nothing to do if the config already exists. */
451+ if (!repo_config_get_string_tmp (the_repository , key , & value )) {
452+ free (key );
453+ return 0 ;
454+ }
455+
456+ if (repo_config_set_gently (the_repository , key , gitdir_path -> buf )) {
457+ free (key );
458+ return -1 ;
459+ }
460+
461+ free (key );
462+ return 0 ;
463+ }
464+
465+ static void create_default_gitdir_config (const char * submodule_name )
466+ {
467+ struct strbuf gitdir_path = STRBUF_INIT ;
468+ struct git_hash_ctx ctx ;
469+ char hex_name_hash [GIT_MAX_HEXSZ + 1 ], header [128 ];
470+ unsigned char raw_name_hash [GIT_MAX_RAWSZ ];
471+ int header_len ;
472+
473+ /* Case 1: try the plain module name */
474+ repo_git_path_append (the_repository , & gitdir_path , "modules/%s" , submodule_name );
475+ if (!validate_and_set_submodule_gitdir (& gitdir_path , submodule_name )) {
476+ strbuf_release (& gitdir_path );
477+ return ;
478+ }
479+
480+ /* Case 2.1: Try URI-safe (RFC3986) encoding first, this fixes nested gitdirs */
481+ strbuf_reset (& gitdir_path );
482+ repo_git_path_append (the_repository , & gitdir_path , "modules/" );
483+ strbuf_addstr_urlencode (& gitdir_path , submodule_name , is_rfc3986_unreserved );
484+ if (!validate_and_set_submodule_gitdir (& gitdir_path , submodule_name )) {
485+ strbuf_release (& gitdir_path );
486+ return ;
487+ }
488+
489+ /* Case 2.2: Try extended uppercase URI (RFC3986) encoding, to fix case-folding */
490+ strbuf_reset (& gitdir_path );
491+ repo_git_path_append (the_repository , & gitdir_path , "modules/" );
492+ strbuf_addstr_urlencode (& gitdir_path , submodule_name , is_casefolding_rfc3986_unreserved );
493+ if (!validate_and_set_submodule_gitdir (& gitdir_path , submodule_name ))
494+ return ;
495+
496+ /* Case 2.3: Try some derived gitdir names, see if one sticks */
497+ for (char c = '0' ; c <= '9' ; c ++ ) {
498+ strbuf_reset (& gitdir_path );
499+ repo_git_path_append (the_repository , & gitdir_path , "modules/" );
500+ strbuf_addstr_urlencode (& gitdir_path , submodule_name , is_rfc3986_unreserved );
501+ strbuf_addch (& gitdir_path , c );
502+ if (!validate_and_set_submodule_gitdir (& gitdir_path , submodule_name ))
503+ return ;
504+
505+ strbuf_reset (& gitdir_path );
506+ repo_git_path_append (the_repository , & gitdir_path , "modules/" );
507+ strbuf_addstr_urlencode (& gitdir_path , submodule_name , is_casefolding_rfc3986_unreserved );
508+ strbuf_addch (& gitdir_path , c );
509+ if (!validate_and_set_submodule_gitdir (& gitdir_path , submodule_name ))
510+ return ;
511+ }
512+
513+ /* Case 2.4: If all the above failed, try a hash of the name as a last resort */
514+ header_len = snprintf (header , sizeof (header ), "blob %zu" , strlen (submodule_name ));
515+ the_hash_algo -> init_fn (& ctx );
516+ the_hash_algo -> update_fn (& ctx , header , header_len );
517+ the_hash_algo -> update_fn (& ctx , "\0" , 1 );
518+ the_hash_algo -> update_fn (& ctx , submodule_name , strlen (submodule_name ));
519+ the_hash_algo -> final_fn (raw_name_hash , & ctx );
520+ hash_to_hex_algop_r (hex_name_hash , raw_name_hash , the_hash_algo );
521+ strbuf_reset (& gitdir_path );
522+ repo_git_path_append (the_repository , & gitdir_path , "modules/%s" , hex_name_hash );
523+ if (!validate_and_set_submodule_gitdir (& gitdir_path , submodule_name )) {
524+ strbuf_release (& gitdir_path );
525+ return ;
526+ }
527+
528+ /* Case 3: nothing worked, error out */
529+ die (_ ("failed to set a valid default config for 'submodule.%s.gitdir'. "
530+ "Please ensure it is set, for example by running something like: "
531+ "'git config submodule.%s.gitdir .git/modules/%s'" ),
532+ submodule_name , submodule_name , submodule_name );
533+ }
534+
438535static void init_submodule (const char * path , const char * prefix ,
439536 const char * super_prefix ,
440537 unsigned int flags )
@@ -511,6 +608,10 @@ static void init_submodule(const char *path, const char *prefix,
511608 if (repo_config_set_gently (the_repository , sb .buf , upd ))
512609 die (_ ("Failed to register update mode for submodule path '%s'" ), displaypath );
513610 }
611+
612+ if (the_repository -> repository_format_submodule_path_cfg )
613+ create_default_gitdir_config (sub -> name );
614+
514615 strbuf_release (& sb );
515616 free (displaypath );
516617 free (url );
@@ -1204,6 +1305,82 @@ static int module_summary(int argc, const char **argv, const char *prefix,
12041305 return ret ;
12051306}
12061307
1308+ static int module_gitdir (int argc , const char * * argv , const char * prefix UNUSED ,
1309+ struct repository * repo )
1310+ {
1311+ struct strbuf gitdir = STRBUF_INIT ;
1312+
1313+ if (argc != 2 )
1314+ usage (_ ("git submodule--helper gitdir <name>" ));
1315+
1316+ submodule_name_to_gitdir (& gitdir , repo , argv [1 ]);
1317+
1318+ printf ("%s\n" , gitdir .buf );
1319+
1320+ strbuf_release (& gitdir );
1321+ return 0 ;
1322+ }
1323+
1324+ static int module_migrate (int argc UNUSED , const char * * argv UNUSED ,
1325+ const char * prefix UNUSED , struct repository * repo )
1326+ {
1327+ struct strbuf module_dir = STRBUF_INIT ;
1328+ DIR * dir ;
1329+ struct dirent * de ;
1330+ int repo_version = 0 ;
1331+
1332+ repo_git_path_append (repo , & module_dir , "modules/" );
1333+
1334+ dir = opendir (module_dir .buf );
1335+ if (!dir )
1336+ die (_ ("could not open '%s'" ), module_dir .buf );
1337+
1338+ while ((de = readdir (dir ))) {
1339+ struct strbuf gitdir_path = STRBUF_INIT ;
1340+ char * key ;
1341+ const char * value ;
1342+
1343+ if (is_dot_or_dotdot (de -> d_name ))
1344+ continue ;
1345+
1346+ strbuf_addf (& gitdir_path , "%s/%s" , module_dir .buf , de -> d_name );
1347+ if (!is_git_directory (gitdir_path .buf )) {
1348+ strbuf_release (& gitdir_path );
1349+ continue ;
1350+ }
1351+ strbuf_release (& gitdir_path );
1352+
1353+ key = xstrfmt ("submodule.%s.gitdir" , de -> d_name );
1354+ if (!repo_config_get_string_tmp (repo , key , & value )) {
1355+ /* Already has a gitdir config, nothing to do. */
1356+ free (key );
1357+ continue ;
1358+ }
1359+ free (key );
1360+
1361+ create_default_gitdir_config (de -> d_name );
1362+ }
1363+
1364+ closedir (dir );
1365+ strbuf_release (& module_dir );
1366+
1367+ repo_config_get_int (the_repository , "core.repositoryformatversion" , & repo_version );
1368+ if (repo_version == 0 &&
1369+ repo_config_set_gently (repo , "core.repositoryformatversion" , "1" ))
1370+ die (_ ("could not set core.repositoryformatversion to 1.\n"
1371+ "Please set it for migration to work, for example:\n"
1372+ "git config core.repositoryformatversion 1" ));
1373+
1374+ if (repo_config_set_gently (repo , "extensions.submodulePathConfig" , "true" ))
1375+ die (_ ("could not enable submodulePathConfig extension. It is required\n"
1376+ "for migration to work. Please enable it in the root repo:\n"
1377+ "git config extensions.submodulePathConfig true" ));
1378+
1379+ repo -> repository_format_submodule_path_cfg = 1 ;
1380+
1381+ return 0 ;
1382+ }
1383+
12071384struct sync_cb {
12081385 const char * prefix ;
12091386 const char * super_prefix ;
@@ -1699,10 +1876,6 @@ static int clone_submodule(const struct module_clone_data *clone_data,
16991876 clone_data_path = to_free = xstrfmt ("%s/%s" , repo_get_work_tree (the_repository ),
17001877 clone_data -> path );
17011878
1702- if (validate_submodule_git_dir (sm_gitdir , clone_data -> name ) < 0 )
1703- die (_ ("refusing to create/use '%s' in another submodule's "
1704- "git dir" ), sm_gitdir );
1705-
17061879 if (!file_exists (sm_gitdir )) {
17071880 if (clone_data -> require_init && !stat (clone_data_path , & st ) &&
17081881 !is_empty_dir (clone_data_path ))
@@ -1789,8 +1962,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
17891962 char * head = xstrfmt ("%s/HEAD" , sm_gitdir );
17901963 unlink (head );
17911964 free (head );
1792- die (_ ("refusing to create/use '%s' in another submodule's "
1793- "git dir" ), sm_gitdir );
1965+ die (_ ("refusing to create/use '%s' in another submodule's git dir. "
1966+ "Enabling extensions.submodulePathConfig should fix this." ),
1967+ sm_gitdir );
17941968 }
17951969
17961970 connect_work_tree_and_git_dir (clone_data_path , sm_gitdir , 0 );
@@ -3190,13 +3364,13 @@ static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
31903364
31913365static int add_submodule (const struct add_data * add_data )
31923366{
3193- char * submod_gitdir_path ;
31943367 struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT ;
31953368 struct string_list reference = STRING_LIST_INIT_NODUP ;
31963369 int ret = -1 ;
31973370
31983371 /* perhaps the path already exists and is already a git repo, else clone it */
31993372 if (is_directory (add_data -> sm_path )) {
3373+ char * submod_gitdir_path ;
32003374 struct strbuf sm_path = STRBUF_INIT ;
32013375 strbuf_addstr (& sm_path , add_data -> sm_path );
32023376 submod_gitdir_path = xstrfmt ("%s/.git" , add_data -> sm_path );
@@ -3210,10 +3384,11 @@ static int add_submodule(const struct add_data *add_data)
32103384 free (submod_gitdir_path );
32113385 } else {
32123386 struct child_process cp = CHILD_PROCESS_INIT ;
3387+ struct strbuf submod_gitdir = STRBUF_INIT ;
32133388
3214- submod_gitdir_path = xstrfmt ( ".git/modules/%s" , add_data -> sm_name );
3389+ submodule_name_to_gitdir ( & submod_gitdir , the_repository , add_data -> sm_name );
32153390
3216- if (is_directory (submod_gitdir_path )) {
3391+ if (is_directory (submod_gitdir . buf )) {
32173392 if (!add_data -> force ) {
32183393 struct strbuf msg = STRBUF_INIT ;
32193394 char * die_msg ;
@@ -3222,8 +3397,8 @@ static int add_submodule(const struct add_data *add_data)
32223397 "locally with remote(s):\n" ),
32233398 add_data -> sm_name );
32243399
3225- append_fetch_remotes (& msg , submod_gitdir_path );
3226- free ( submod_gitdir_path );
3400+ append_fetch_remotes (& msg , submod_gitdir . buf );
3401+ strbuf_release ( & submod_gitdir );
32273402
32283403 strbuf_addf (& msg , _ ("If you want to reuse this local git "
32293404 "directory instead of cloning again from\n"
@@ -3241,7 +3416,7 @@ static int add_submodule(const struct add_data *add_data)
32413416 "submodule '%s'\n" ), add_data -> sm_name );
32423417 }
32433418 }
3244- free ( submod_gitdir_path );
3419+ strbuf_release ( & submod_gitdir );
32453420
32463421 clone_data .prefix = add_data -> prefix ;
32473422 clone_data .path = add_data -> sm_path ;
@@ -3569,6 +3744,9 @@ static int module_add(int argc, const char **argv, const char *prefix,
35693744 add_data .progress = !!progress ;
35703745 add_data .dissociate = !!dissociate ;
35713746
3747+ if (the_repository -> repository_format_submodule_path_cfg )
3748+ create_default_gitdir_config (add_data .sm_name );
3749+
35723750 if (add_submodule (& add_data ))
35733751 goto cleanup ;
35743752 configure_added_submodule (& add_data );
@@ -3594,6 +3772,8 @@ int cmd_submodule__helper(int argc,
35943772 NULL
35953773 };
35963774 struct option options [] = {
3775+ OPT_SUBCOMMAND ("migrate-gitdir-configs" , & fn , module_migrate ),
3776+ OPT_SUBCOMMAND ("gitdir" , & fn , module_gitdir ),
35973777 OPT_SUBCOMMAND ("clone" , & fn , module_clone ),
35983778 OPT_SUBCOMMAND ("add" , & fn , module_add ),
35993779 OPT_SUBCOMMAND ("update" , & fn , module_update ),
0 commit comments