@@ -2748,7 +2748,7 @@ struct add_data {
27482748 const char * prefix ;
27492749 const char * branch ;
27502750 const char * reference_path ;
2751- const char * sm_path ;
2751+ char * sm_path ;
27522752 const char * sm_name ;
27532753 const char * repo ;
27542754 const char * realrepo ;
@@ -3047,6 +3047,168 @@ static int add_config(int argc, const char **argv, const char *prefix)
30473047 return 0 ;
30483048}
30493049
3050+ static void die_on_index_match (const char * path , int force )
3051+ {
3052+ struct pathspec ps ;
3053+ const char * args [] = { path , NULL };
3054+ parse_pathspec (& ps , 0 , PATHSPEC_PREFER_CWD , NULL , args );
3055+
3056+ if (read_cache_preload (NULL ) < 0 )
3057+ die (_ ("index file corrupt" ));
3058+
3059+ if (ps .nr ) {
3060+ int i ;
3061+ char * ps_matched = xcalloc (ps .nr , 1 );
3062+
3063+ /* TODO: audit for interaction with sparse-index. */
3064+ ensure_full_index (& the_index );
3065+
3066+ /*
3067+ * Since there is only one pathspec, we just need
3068+ * need to check ps_matched[0] to know if a cache
3069+ * entry matched.
3070+ */
3071+ for (i = 0 ; i < active_nr ; i ++ ) {
3072+ ce_path_match (& the_index , active_cache [i ], & ps ,
3073+ ps_matched );
3074+
3075+ if (ps_matched [0 ]) {
3076+ if (!force )
3077+ die (_ ("'%s' already exists in the index" ),
3078+ path );
3079+ if (!S_ISGITLINK (active_cache [i ]-> ce_mode ))
3080+ die (_ ("'%s' already exists in the index "
3081+ "and is not a submodule" ), path );
3082+ break ;
3083+ }
3084+ }
3085+ free (ps_matched );
3086+ }
3087+ }
3088+
3089+ static void die_on_repo_without_commits (const char * path )
3090+ {
3091+ struct strbuf sb = STRBUF_INIT ;
3092+ strbuf_addstr (& sb , path );
3093+ if (is_nonbare_repository_dir (& sb )) {
3094+ struct object_id oid ;
3095+ if (resolve_gitlink_ref (path , "HEAD" , & oid ) < 0 )
3096+ die (_ ("'%s' does not have a commit checked out" ), path );
3097+ }
3098+ }
3099+
3100+ static int module_add (int argc , const char * * argv , const char * prefix )
3101+ {
3102+ int force = 0 , quiet = 0 , progress = 0 , dissociate = 0 ;
3103+ struct add_data add_data = ADD_DATA_INIT ;
3104+
3105+ struct option options [] = {
3106+ OPT_STRING ('b' , "branch" , & add_data .branch , N_ ("branch" ),
3107+ N_ ("branch of repository to add as submodule" )),
3108+ OPT__FORCE (& force , N_ ("allow adding an otherwise ignored submodule path" ),
3109+ PARSE_OPT_NOCOMPLETE ),
3110+ OPT__QUIET (& quiet , N_ ("print only error messages" )),
3111+ OPT_BOOL (0 , "progress" , & progress , N_ ("force cloning progress" )),
3112+ OPT_STRING (0 , "reference" , & add_data .reference_path , N_ ("repository" ),
3113+ N_ ("reference repository" )),
3114+ OPT_BOOL (0 , "dissociate" , & dissociate , N_ ("borrow the objects from reference repositories" )),
3115+ OPT_STRING (0 , "name" , & add_data .sm_name , N_ ("name" ),
3116+ N_ ("sets the submodule’s name to the given string "
3117+ "instead of defaulting to its path" )),
3118+ OPT_INTEGER (0 , "depth" , & add_data .depth , N_ ("depth for shallow clones" )),
3119+ OPT_END ()
3120+ };
3121+
3122+ const char * const usage [] = {
3123+ N_ ("git submodule--helper add [<options>] [--] <repository> [<path>]" ),
3124+ NULL
3125+ };
3126+
3127+ argc = parse_options (argc , argv , prefix , options , usage , 0 );
3128+
3129+ if (!is_writing_gitmodules_ok ())
3130+ die (_ ("please make sure that the .gitmodules file is in the working tree" ));
3131+
3132+ if (prefix && * prefix &&
3133+ add_data .reference_path && !is_absolute_path (add_data .reference_path ))
3134+ add_data .reference_path = xstrfmt ("%s%s" , prefix , add_data .reference_path );
3135+
3136+ if (argc == 0 || argc > 2 )
3137+ usage_with_options (usage , options );
3138+
3139+ add_data .repo = argv [0 ];
3140+ if (argc == 1 )
3141+ add_data .sm_path = git_url_basename (add_data .repo , 0 , 0 );
3142+ else
3143+ add_data .sm_path = xstrdup (argv [1 ]);
3144+
3145+ if (prefix && * prefix && !is_absolute_path (add_data .sm_path ))
3146+ add_data .sm_path = xstrfmt ("%s%s" , prefix , add_data .sm_path );
3147+
3148+ if (starts_with_dot_dot_slash (add_data .repo ) ||
3149+ starts_with_dot_slash (add_data .repo )) {
3150+ if (prefix )
3151+ die (_ ("Relative path can only be used from the toplevel "
3152+ "of the working tree" ));
3153+
3154+ /* dereference source url relative to parent's url */
3155+ add_data .realrepo = compute_submodule_clone_url (add_data .repo , NULL , 1 );
3156+ } else if (is_dir_sep (add_data .repo [0 ]) || strchr (add_data .repo , ':' )) {
3157+ add_data .realrepo = add_data .repo ;
3158+ } else {
3159+ die (_ ("repo URL: '%s' must be absolute or begin with ./|../" ),
3160+ add_data .repo );
3161+ }
3162+
3163+ /*
3164+ * normalize path:
3165+ * multiple //; leading ./; /./; /../;
3166+ */
3167+ normalize_path_copy (add_data .sm_path , add_data .sm_path );
3168+ strip_dir_trailing_slashes (add_data .sm_path );
3169+
3170+ die_on_index_match (add_data .sm_path , force );
3171+ die_on_repo_without_commits (add_data .sm_path );
3172+
3173+ if (!force ) {
3174+ int exit_code = -1 ;
3175+ struct strbuf sb = STRBUF_INIT ;
3176+ struct child_process cp = CHILD_PROCESS_INIT ;
3177+ cp .git_cmd = 1 ;
3178+ cp .no_stdout = 1 ;
3179+ strvec_pushl (& cp .args , "add" , "--dry-run" , "--ignore-missing" ,
3180+ "--no-warn-embedded-repo" , add_data .sm_path , NULL );
3181+ if ((exit_code = pipe_command (& cp , NULL , 0 , NULL , 0 , & sb , 0 ))) {
3182+ strbuf_complete_line (& sb );
3183+ fputs (sb .buf , stderr );
3184+ free (add_data .sm_path );
3185+ return exit_code ;
3186+ }
3187+ strbuf_release (& sb );
3188+ }
3189+
3190+ if (!add_data .sm_name )
3191+ add_data .sm_name = add_data .sm_path ;
3192+
3193+ if (check_submodule_name (add_data .sm_name ))
3194+ die (_ ("'%s' is not a valid submodule name" ), add_data .sm_name );
3195+
3196+ add_data .prefix = prefix ;
3197+ add_data .force = !!force ;
3198+ add_data .quiet = !!quiet ;
3199+ add_data .progress = !!progress ;
3200+ add_data .dissociate = !!dissociate ;
3201+
3202+ if (add_submodule (& add_data )) {
3203+ free (add_data .sm_path );
3204+ return 1 ;
3205+ }
3206+ configure_added_submodule (& add_data );
3207+ free (add_data .sm_path );
3208+
3209+ return 0 ;
3210+ }
3211+
30503212#define SUPPORT_SUPER_PREFIX (1<<0)
30513213
30523214struct cmd_struct {
@@ -3061,6 +3223,7 @@ static struct cmd_struct commands[] = {
30613223 {"clone" , module_clone , 0 },
30623224 {"add-clone" , add_clone , 0 },
30633225 {"add-config" , add_config , 0 },
3226+ {"add" , module_add , SUPPORT_SUPER_PREFIX },
30643227 {"update-module-mode" , module_update_module_mode , 0 },
30653228 {"update-clone" , update_clone , 0 },
30663229 {"ensure-core-worktree" , ensure_core_worktree , 0 },
0 commit comments