@@ -50,6 +50,20 @@ static char *get_default_remote(void)
5050 return ret ;
5151}
5252
53+ static int print_default_remote (int argc , const char * * argv , const char * prefix )
54+ {
55+ const char * remote ;
56+
57+ if (argc != 1 )
58+ die (_ ("submodule--helper print-default-remote takes no arguments" ));
59+
60+ remote = get_default_remote ();
61+ if (remote )
62+ printf ("%s\n" , remote );
63+
64+ return 0 ;
65+ }
66+
5367static int starts_with_dot_slash (const char * str )
5468{
5569 return str [0 ] == '.' && is_dir_sep (str [1 ]);
@@ -358,6 +372,25 @@ static void module_list_active(struct module_list *list)
358372 * list = active_modules ;
359373}
360374
375+ static char * get_up_path (const char * path )
376+ {
377+ int i ;
378+ struct strbuf sb = STRBUF_INIT ;
379+
380+ for (i = count_slashes (path ); i ; i -- )
381+ strbuf_addstr (& sb , "../" );
382+
383+ /*
384+ * Check if 'path' ends with slash or not
385+ * for having the same output for dir/sub_dir
386+ * and dir/sub_dir/
387+ */
388+ if (!is_dir_sep (path [strlen (path ) - 1 ]))
389+ strbuf_addstr (& sb , "../" );
390+
391+ return strbuf_detach (& sb , NULL );
392+ }
393+
361394static int module_list (int argc , const char * * argv , const char * prefix )
362395{
363396 int i ;
@@ -718,6 +751,164 @@ static int module_name(int argc, const char **argv, const char *prefix)
718751 return 0 ;
719752}
720753
754+ struct sync_cb {
755+ const char * prefix ;
756+ unsigned int flags ;
757+ };
758+
759+ #define SYNC_CB_INIT { NULL, 0 }
760+
761+ static void sync_submodule (const char * path , const char * prefix ,
762+ unsigned int flags )
763+ {
764+ const struct submodule * sub ;
765+ char * remote_key = NULL ;
766+ char * sub_origin_url , * super_config_url , * displaypath ;
767+ struct strbuf sb = STRBUF_INIT ;
768+ struct child_process cp = CHILD_PROCESS_INIT ;
769+ char * sub_config_path = NULL ;
770+
771+ if (!is_submodule_active (the_repository , path ))
772+ return ;
773+
774+ sub = submodule_from_path (& null_oid , path );
775+
776+ if (sub && sub -> url ) {
777+ if (starts_with_dot_dot_slash (sub -> url ) ||
778+ starts_with_dot_slash (sub -> url )) {
779+ char * remote_url , * up_path ;
780+ char * remote = get_default_remote ();
781+ strbuf_addf (& sb , "remote.%s.url" , remote );
782+
783+ if (git_config_get_string (sb .buf , & remote_url ))
784+ remote_url = xgetcwd ();
785+
786+ up_path = get_up_path (path );
787+ sub_origin_url = relative_url (remote_url , sub -> url , up_path );
788+ super_config_url = relative_url (remote_url , sub -> url , NULL );
789+
790+ free (remote );
791+ free (up_path );
792+ free (remote_url );
793+ } else {
794+ sub_origin_url = xstrdup (sub -> url );
795+ super_config_url = xstrdup (sub -> url );
796+ }
797+ } else {
798+ sub_origin_url = xstrdup ("" );
799+ super_config_url = xstrdup ("" );
800+ }
801+
802+ displaypath = get_submodule_displaypath (path , prefix );
803+
804+ if (!(flags & OPT_QUIET ))
805+ printf (_ ("Synchronizing submodule url for '%s'\n" ),
806+ displaypath );
807+
808+ strbuf_reset (& sb );
809+ strbuf_addf (& sb , "submodule.%s.url" , sub -> name );
810+ if (git_config_set_gently (sb .buf , super_config_url ))
811+ die (_ ("failed to register url for submodule path '%s'" ),
812+ displaypath );
813+
814+ if (!is_submodule_populated_gently (path , NULL ))
815+ goto cleanup ;
816+
817+ prepare_submodule_repo_env (& cp .env_array );
818+ cp .git_cmd = 1 ;
819+ cp .dir = path ;
820+ argv_array_pushl (& cp .args , "submodule--helper" ,
821+ "print-default-remote" , NULL );
822+
823+ strbuf_reset (& sb );
824+ if (capture_command (& cp , & sb , 0 ))
825+ die (_ ("failed to get the default remote for submodule '%s'" ),
826+ path );
827+
828+ strbuf_strip_suffix (& sb , "\n" );
829+ remote_key = xstrfmt ("remote.%s.url" , sb .buf );
830+
831+ strbuf_reset (& sb );
832+ submodule_to_gitdir (& sb , path );
833+ strbuf_addstr (& sb , "/config" );
834+
835+ if (git_config_set_in_file_gently (sb .buf , remote_key , sub_origin_url ))
836+ die (_ ("failed to update remote for submodule '%s'" ),
837+ path );
838+
839+ if (flags & OPT_RECURSIVE ) {
840+ struct child_process cpr = CHILD_PROCESS_INIT ;
841+
842+ cpr .git_cmd = 1 ;
843+ cpr .dir = path ;
844+ prepare_submodule_repo_env (& cpr .env_array );
845+
846+ argv_array_push (& cpr .args , "--super-prefix" );
847+ argv_array_pushf (& cpr .args , "%s/" , displaypath );
848+ argv_array_pushl (& cpr .args , "submodule--helper" , "sync" ,
849+ "--recursive" , NULL );
850+
851+ if (flags & OPT_QUIET )
852+ argv_array_push (& cpr .args , "--quiet" );
853+
854+ if (run_command (& cpr ))
855+ die (_ ("failed to recurse into submodule '%s'" ),
856+ path );
857+ }
858+
859+ cleanup :
860+ free (super_config_url );
861+ free (sub_origin_url );
862+ strbuf_release (& sb );
863+ free (remote_key );
864+ free (displaypath );
865+ free (sub_config_path );
866+ }
867+
868+ static void sync_submodule_cb (const struct cache_entry * list_item , void * cb_data )
869+ {
870+ struct sync_cb * info = cb_data ;
871+ sync_submodule (list_item -> name , info -> prefix , info -> flags );
872+
873+ }
874+
875+ static int module_sync (int argc , const char * * argv , const char * prefix )
876+ {
877+ struct sync_cb info = SYNC_CB_INIT ;
878+ struct pathspec pathspec ;
879+ struct module_list list = MODULE_LIST_INIT ;
880+ int quiet = 0 ;
881+ int recursive = 0 ;
882+
883+ struct option module_sync_options [] = {
884+ OPT__QUIET (& quiet , N_ ("Suppress output of synchronizing submodule url" )),
885+ OPT_BOOL (0 , "recursive" , & recursive ,
886+ N_ ("Recurse into nested submodules" )),
887+ OPT_END ()
888+ };
889+
890+ const char * const git_submodule_helper_usage [] = {
891+ N_ ("git submodule--helper sync [--quiet] [--recursive] [<path>]" ),
892+ NULL
893+ };
894+
895+ argc = parse_options (argc , argv , prefix , module_sync_options ,
896+ git_submodule_helper_usage , 0 );
897+
898+ if (module_list_compute (argc , argv , prefix , & pathspec , & list ) < 0 )
899+ return 1 ;
900+
901+ info .prefix = prefix ;
902+ if (quiet )
903+ info .flags |= OPT_QUIET ;
904+ if (recursive )
905+ info .flags |= OPT_RECURSIVE ;
906+
907+ for_each_listed_submodule (& list , sync_submodule_cb , & info );
908+
909+ return 0 ;
910+ }
911+
721912static int clone_submodule (const char * path , const char * gitdir , const char * url ,
722913 const char * depth , struct string_list * reference ,
723914 int quiet , int progress )
@@ -1498,6 +1689,8 @@ static struct cmd_struct commands[] = {
14981689 {"resolve-relative-url-test" , resolve_relative_url_test , 0 },
14991690 {"init" , module_init , SUPPORT_SUPER_PREFIX },
15001691 {"status" , module_status , SUPPORT_SUPER_PREFIX },
1692+ {"print-default-remote" , print_default_remote , 0 },
1693+ {"sync" , module_sync , SUPPORT_SUPER_PREFIX },
15011694 {"remote-branch" , resolve_remote_submodule_branch , 0 },
15021695 {"push-check" , push_check , 0 },
15031696 {"absorb-git-dirs" , absorb_git_dirs , SUPPORT_SUPER_PREFIX },
0 commit comments