@@ -2760,6 +2760,182 @@ static int module_set_branch(int argc, const char **argv, const char *prefix)
2760
2760
return !!ret ;
2761
2761
}
2762
2762
2763
+ struct add_data {
2764
+ const char * prefix ;
2765
+ const char * branch ;
2766
+ const char * reference_path ;
2767
+ const char * sm_path ;
2768
+ const char * sm_name ;
2769
+ const char * repo ;
2770
+ const char * realrepo ;
2771
+ int depth ;
2772
+ unsigned int force : 1 ;
2773
+ unsigned int quiet : 1 ;
2774
+ unsigned int progress : 1 ;
2775
+ unsigned int dissociate : 1 ;
2776
+ };
2777
+ #define ADD_DATA_INIT { .depth = -1 }
2778
+
2779
+ static void show_fetch_remotes (FILE * output , const char * sm_name , const char * git_dir_path )
2780
+ {
2781
+ struct child_process cp_remote = CHILD_PROCESS_INIT ;
2782
+ struct strbuf sb_remote_out = STRBUF_INIT ;
2783
+
2784
+ cp_remote .git_cmd = 1 ;
2785
+ strvec_pushf (& cp_remote .env_array ,
2786
+ "GIT_DIR=%s" , git_dir_path );
2787
+ strvec_push (& cp_remote .env_array , "GIT_WORK_TREE=." );
2788
+ strvec_pushl (& cp_remote .args , "remote" , "-v" , NULL );
2789
+ if (!capture_command (& cp_remote , & sb_remote_out , 0 )) {
2790
+ char * next_line ;
2791
+ char * line = sb_remote_out .buf ;
2792
+ while ((next_line = strchr (line , '\n' )) != NULL ) {
2793
+ size_t len = next_line - line ;
2794
+ if (strip_suffix_mem (line , & len , " (fetch)" ))
2795
+ fprintf (output , " %.*s\n" , (int )len , line );
2796
+ line = next_line + 1 ;
2797
+ }
2798
+ }
2799
+
2800
+ strbuf_release (& sb_remote_out );
2801
+ }
2802
+
2803
+ static int add_submodule (const struct add_data * add_data )
2804
+ {
2805
+ char * submod_gitdir_path ;
2806
+ struct module_clone_data clone_data = MODULE_CLONE_DATA_INIT ;
2807
+
2808
+ /* perhaps the path already exists and is already a git repo, else clone it */
2809
+ if (is_directory (add_data -> sm_path )) {
2810
+ struct strbuf sm_path = STRBUF_INIT ;
2811
+ strbuf_addstr (& sm_path , add_data -> sm_path );
2812
+ submod_gitdir_path = xstrfmt ("%s/.git" , add_data -> sm_path );
2813
+ if (is_nonbare_repository_dir (& sm_path ))
2814
+ printf (_ ("Adding existing repo at '%s' to the index\n" ),
2815
+ add_data -> sm_path );
2816
+ else
2817
+ die (_ ("'%s' already exists and is not a valid git repo" ),
2818
+ add_data -> sm_path );
2819
+ strbuf_release (& sm_path );
2820
+ free (submod_gitdir_path );
2821
+ } else {
2822
+ struct child_process cp = CHILD_PROCESS_INIT ;
2823
+ submod_gitdir_path = xstrfmt (".git/modules/%s" , add_data -> sm_name );
2824
+
2825
+ if (is_directory (submod_gitdir_path )) {
2826
+ if (!add_data -> force ) {
2827
+ fprintf (stderr , _ ("A git directory for '%s' is found "
2828
+ "locally with remote(s):" ),
2829
+ add_data -> sm_name );
2830
+ show_fetch_remotes (stderr , add_data -> sm_name ,
2831
+ submod_gitdir_path );
2832
+ free (submod_gitdir_path );
2833
+ die (_ ("If you want to reuse this local git "
2834
+ "directory instead of cloning again from\n"
2835
+ " %s\n"
2836
+ "use the '--force' option. If the local git "
2837
+ "directory is not the correct repo\n"
2838
+ "or if you are unsure what this means, choose "
2839
+ "another name with the '--name' option.\n" ),
2840
+ add_data -> realrepo );
2841
+ } else {
2842
+ printf (_ ("Reactivating local git directory for "
2843
+ "submodule '%s'\n" ), add_data -> sm_name );
2844
+ }
2845
+ }
2846
+ free (submod_gitdir_path );
2847
+
2848
+ clone_data .prefix = add_data -> prefix ;
2849
+ clone_data .path = add_data -> sm_path ;
2850
+ clone_data .name = add_data -> sm_name ;
2851
+ clone_data .url = add_data -> realrepo ;
2852
+ clone_data .quiet = add_data -> quiet ;
2853
+ clone_data .progress = add_data -> progress ;
2854
+ if (add_data -> reference_path )
2855
+ string_list_append (& clone_data .reference ,
2856
+ xstrdup (add_data -> reference_path ));
2857
+ clone_data .dissociate = add_data -> dissociate ;
2858
+ if (add_data -> depth >= 0 )
2859
+ clone_data .depth = xstrfmt ("%d" , add_data -> depth );
2860
+
2861
+ if (clone_submodule (& clone_data ))
2862
+ return -1 ;
2863
+
2864
+ prepare_submodule_repo_env (& cp .env_array );
2865
+ cp .git_cmd = 1 ;
2866
+ cp .dir = add_data -> sm_path ;
2867
+ strvec_pushl (& cp .args , "checkout" , "-f" , "-q" , NULL );
2868
+
2869
+ if (add_data -> branch ) {
2870
+ strvec_pushl (& cp .args , "-B" , add_data -> branch , NULL );
2871
+ strvec_pushf (& cp .args , "origin/%s" , add_data -> branch );
2872
+ }
2873
+
2874
+ if (run_command (& cp ))
2875
+ die (_ ("unable to checkout submodule '%s'" ), add_data -> sm_path );
2876
+ }
2877
+ return 0 ;
2878
+ }
2879
+
2880
+ static int add_clone (int argc , const char * * argv , const char * prefix )
2881
+ {
2882
+ int force = 0 , quiet = 0 , dissociate = 0 , progress = 0 ;
2883
+ struct add_data add_data = ADD_DATA_INIT ;
2884
+
2885
+ struct option options [] = {
2886
+ OPT_STRING ('b' , "branch" , & add_data .branch ,
2887
+ N_ ("branch" ),
2888
+ N_ ("branch of repository to checkout on cloning" )),
2889
+ OPT_STRING (0 , "prefix" , & prefix ,
2890
+ N_ ("path" ),
2891
+ N_ ("alternative anchor for relative paths" )),
2892
+ OPT_STRING (0 , "path" , & add_data .sm_path ,
2893
+ N_ ("path" ),
2894
+ N_ ("where the new submodule will be cloned to" )),
2895
+ OPT_STRING (0 , "name" , & add_data .sm_name ,
2896
+ N_ ("string" ),
2897
+ N_ ("name of the new submodule" )),
2898
+ OPT_STRING (0 , "url" , & add_data .realrepo ,
2899
+ N_ ("string" ),
2900
+ N_ ("url where to clone the submodule from" )),
2901
+ OPT_STRING (0 , "reference" , & add_data .reference_path ,
2902
+ N_ ("repo" ),
2903
+ N_ ("reference repository" )),
2904
+ OPT_BOOL (0 , "dissociate" , & dissociate ,
2905
+ N_ ("use --reference only while cloning" )),
2906
+ OPT_INTEGER (0 , "depth" , & add_data .depth ,
2907
+ N_ ("depth for shallow clones" )),
2908
+ OPT_BOOL (0 , "progress" , & progress ,
2909
+ N_ ("force cloning progress" )),
2910
+ OPT__FORCE (& force , N_ ("allow adding an otherwise ignored submodule path" ),
2911
+ PARSE_OPT_NOCOMPLETE ),
2912
+ OPT__QUIET (& quiet , "suppress output for cloning a submodule" ),
2913
+ OPT_END ()
2914
+ };
2915
+
2916
+ const char * const usage [] = {
2917
+ N_ ("git submodule--helper add-clone [<options>...] "
2918
+ "--url <url> --path <path> --name <name>" ),
2919
+ NULL
2920
+ };
2921
+
2922
+ argc = parse_options (argc , argv , prefix , options , usage , 0 );
2923
+
2924
+ if (argc != 0 )
2925
+ usage_with_options (usage , options );
2926
+
2927
+ add_data .prefix = prefix ;
2928
+ add_data .progress = !!progress ;
2929
+ add_data .dissociate = !!dissociate ;
2930
+ add_data .force = !!force ;
2931
+ add_data .quiet = !!quiet ;
2932
+
2933
+ if (add_submodule (& add_data ))
2934
+ return 1 ;
2935
+
2936
+ return 0 ;
2937
+ }
2938
+
2763
2939
#define SUPPORT_SUPER_PREFIX (1<<0)
2764
2940
2765
2941
struct cmd_struct {
@@ -2772,6 +2948,7 @@ static struct cmd_struct commands[] = {
2772
2948
{"list" , module_list , 0 },
2773
2949
{"name" , module_name , 0 },
2774
2950
{"clone" , module_clone , 0 },
2951
+ {"add-clone" , add_clone , 0 },
2775
2952
{"update-module-mode" , module_update_module_mode , 0 },
2776
2953
{"update-clone" , update_clone , 0 },
2777
2954
{"ensure-core-worktree" , ensure_core_worktree , 0 },
0 commit comments