diff options
Diffstat (limited to 'builtin/submodule--helper.c')
-rw-r--r-- | builtin/submodule--helper.c | 248 |
1 files changed, 128 insertions, 120 deletions
diff --git a/builtin/submodule--helper.c b/builtin/submodule--helper.c index a7683d3529..28e66a3d70 100644 --- a/builtin/submodule--helper.c +++ b/builtin/submodule--helper.c @@ -616,6 +616,9 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, int diff_files_result; struct strbuf buf = STRBUF_INIT; const char *git_dir; + struct setup_revision_opt opt = { + .free_removed_argv_elements = 1, + }; if (!submodule_from_path(the_repository, null_oid(), path)) die(_("no submodule mapping found in .gitmodules for path '%s'"), @@ -649,9 +652,7 @@ static void status_submodule(const char *path, const struct object_id *ce_oid, repo_init_revisions(the_repository, &rev, NULL); rev.abbrev = 0; - diff_files_args.nr = setup_revisions(diff_files_args.nr, - diff_files_args.v, - &rev, NULL); + setup_revisions(diff_files_args.nr, diff_files_args.v, &rev, &opt); diff_files_result = run_diff_files(&rev, 0); if (!diff_result_code(&rev.diffopt, diff_files_result)) { @@ -1378,8 +1379,7 @@ static void deinit_submodule(const char *path, const char *prefix, ".git file by using absorbgitdirs."), displaypath); - absorb_git_dir_into_superproject(path, - ABSORB_GITDIR_RECURSE_SUBMODULES); + absorb_git_dir_into_superproject(path); } @@ -1503,6 +1503,8 @@ struct module_clone_data { const char *name; const char *url; const char *depth; + const char *branch; + const char *branch_oid; struct list_objects_filter_options *filter_options; unsigned int quiet: 1; unsigned int progress: 1; @@ -1692,6 +1694,8 @@ static int clone_submodule(const struct module_clone_data *clone_data, strvec_push(&cp.args, clone_data->single_branch ? "--single-branch" : "--no-single-branch"); + if (the_repository->settings.submodule_propagate_branches) + strvec_push(&cp.args, "--detach"); strvec_push(&cp.args, "--"); strvec_push(&cp.args, clone_data->url); @@ -1704,6 +1708,21 @@ static int clone_submodule(const struct module_clone_data *clone_data, if(run_command(&cp)) die(_("clone of '%s' into submodule path '%s' failed"), clone_data->url, clone_data_path); + + if (clone_data->branch) { + struct child_process branch_cp = CHILD_PROCESS_INIT; + + branch_cp.git_cmd = 1; + prepare_other_repo_env(&branch_cp.env, sm_gitdir); + + strvec_pushl(&branch_cp.args, "branch", + clone_data->branch, clone_data->branch_oid, + NULL); + + if (run_command(&branch_cp)) + die(_("could not create branch '%s' in submodule path '%s'"), + clone_data->branch, clone_data_path); + } } else { char *path; @@ -1778,6 +1797,12 @@ static int module_clone(int argc, const char **argv, const char *prefix) N_("disallow cloning into non-empty directory")), OPT_BOOL(0, "single-branch", &clone_data.single_branch, N_("clone only one branch, HEAD or --branch")), + OPT_STRING(0, "branch", &clone_data.branch, + N_("string"), + N_("name of branch to be created")), + OPT_STRING(0, "branch-oid", &clone_data.branch_oid, + N_("object-id"), + N_("commit id for new branch")), OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options), OPT_END() }; @@ -1785,12 +1810,14 @@ static int module_clone(int argc, const char **argv, const char *prefix) N_("git submodule--helper clone [--prefix=<path>] [--quiet] " "[--reference <repository>] [--name <name>] [--depth <depth>] " "[--single-branch] [--filter <filter-spec>] " + "[--branch <branch> --branch-oid <oid>]" "--url <url> --path <path>"), NULL }; argc = parse_options(argc, argv, prefix, module_clone_options, git_submodule_helper_usage, 0); + prepare_repo_settings(the_repository); clone_data.dissociate = !!dissociate; clone_data.quiet = !!quiet; @@ -1802,6 +1829,12 @@ static int module_clone(int argc, const char **argv, const char *prefix) usage_with_options(git_submodule_helper_usage, module_clone_options); + if (!!clone_data.branch != !!clone_data.branch_oid) + BUG("--branch and --branch-oid must be set/unset together"); + if ((clone_data.branch && + !the_repository->settings.submodule_propagate_branches)) + BUG("--branch is only expected with submodule.propagateBranches"); + clone_submodule(&clone_data, &reference); list_objects_filter_release(&filter_options); string_list_clear(&reference, 1); @@ -1884,8 +1917,8 @@ static void submodule_update_clone_release(struct submodule_update_clone *suc) struct update_data { const char *prefix; char *displaypath; + const char *super_branch; enum submodule_update_type update_default; - struct object_id suboid; struct string_list references; struct submodule_update_strategy update_strategy; struct list_objects_filter_options *filter_options; @@ -2059,6 +2092,11 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce, strvec_push(&child->args, suc->update_data->single_branch ? "--single-branch" : "--no-single-branch"); + if (ud->super_branch) { + strvec_pushf(&child->args, "--branch=%s", ud->super_branch); + strvec_pushf(&child->args, "--branch-oid=%s", + oid_to_hex(&ce->oid)); + } cleanup: free(displaypath); @@ -2222,9 +2260,14 @@ static int fetch_in_submodule(const char *module_path, int depth, int quiet, static int run_update_command(const struct update_data *ud, int subforce) { struct child_process cp = CHILD_PROCESS_INIT; - char *oid = oid_to_hex(&ud->oid); + const char *update_target; int ret; + if (ud->update_strategy.type == SM_UPDATE_CHECKOUT && ud->super_branch) + update_target = ud->super_branch; + else + update_target = oid_to_hex(&ud->oid); + switch (ud->update_strategy.type) { case SM_UPDATE_CHECKOUT: cp.git_cmd = 1; @@ -2252,7 +2295,7 @@ static int run_update_command(const struct update_data *ud, int subforce) BUG("unexpected update strategy type: %d", ud->update_strategy.type); } - strvec_push(&cp.args, oid); + strvec_push(&cp.args, update_target); cp.dir = ud->sm_path; prepare_submodule_repo_env(&cp.env); @@ -2260,20 +2303,20 @@ static int run_update_command(const struct update_data *ud, int subforce) switch (ud->update_strategy.type) { case SM_UPDATE_CHECKOUT: die_message(_("Unable to checkout '%s' in submodule path '%s'"), - oid, ud->displaypath); + update_target, ud->displaypath); /* No "ret" assignment, use "git checkout"'s */ break; case SM_UPDATE_REBASE: ret = die_message(_("Unable to rebase '%s' in submodule path '%s'"), - oid, ud->displaypath); + update_target, ud->displaypath); break; case SM_UPDATE_MERGE: ret = die_message(_("Unable to merge '%s' in submodule path '%s'"), - oid, ud->displaypath); + update_target, ud->displaypath); break; case SM_UPDATE_COMMAND: ret = die_message(_("Execution of '%s %s' failed in submodule path '%s'"), - ud->update_strategy.command, oid, ud->displaypath); + ud->update_strategy.command, update_target, ud->displaypath); break; default: BUG("unexpected update strategy type: %d", @@ -2289,19 +2332,19 @@ static int run_update_command(const struct update_data *ud, int subforce) switch (ud->update_strategy.type) { case SM_UPDATE_CHECKOUT: printf(_("Submodule path '%s': checked out '%s'\n"), - ud->displaypath, oid); + ud->displaypath, update_target); break; case SM_UPDATE_REBASE: printf(_("Submodule path '%s': rebased into '%s'\n"), - ud->displaypath, oid); + ud->displaypath, update_target); break; case SM_UPDATE_MERGE: printf(_("Submodule path '%s': merged in '%s'\n"), - ud->displaypath, oid); + ud->displaypath, update_target); break; case SM_UPDATE_COMMAND: printf(_("Submodule path '%s': '%s %s'\n"), - ud->displaypath, ud->update_strategy.command, oid); + ud->displaypath, ud->update_strategy.command, update_target); break; default: BUG("unexpected update strategy type: %d", @@ -2313,7 +2356,7 @@ static int run_update_command(const struct update_data *ud, int subforce) static int run_update_procedure(const struct update_data *ud) { - int subforce = is_null_oid(&ud->suboid) || ud->force; + int subforce = ud->just_cloned || ud->force; if (!ud->nofetch) { /* @@ -2488,7 +2531,10 @@ static void update_data_to_args(const struct update_data *update_data, static int update_submodule(struct update_data *update_data) { + int submodule_up_to_date; int ret; + struct object_id suboid; + const char *submodule_head = NULL; ret = determine_submodule_update_strategy(the_repository, update_data->just_cloned, @@ -2498,9 +2544,9 @@ static int update_submodule(struct update_data *update_data) if (ret) return ret; - if (update_data->just_cloned) - oidcpy(&update_data->suboid, null_oid()); - else if (resolve_gitlink_ref(update_data->sm_path, "HEAD", &update_data->suboid)) + if (!update_data->just_cloned && + resolve_gitlink_ref(update_data->sm_path, "HEAD", &suboid, + &submodule_head)) return die_message(_("Unable to find current revision in submodule path '%s'"), update_data->displaypath); @@ -2527,14 +2573,26 @@ static int update_submodule(struct update_data *update_data) update_data->sm_path); } - if (resolve_gitlink_ref(update_data->sm_path, remote_ref, &update_data->oid)) + if (resolve_gitlink_ref(update_data->sm_path, remote_ref, + &update_data->oid, NULL)) return die_message(_("Unable to find %s revision in submodule path '%s'"), remote_ref, update_data->sm_path); free(remote_ref); } - if (!oideq(&update_data->oid, &update_data->suboid) || update_data->force) { + if (update_data->just_cloned) + submodule_up_to_date = 0; + else if (update_data->super_branch) + /* Check that the submodule's HEAD points to super_branch. */ + submodule_up_to_date = + skip_prefix(submodule_head, "refs/heads/", + &submodule_head) && + !strcmp(update_data->super_branch, submodule_head); + else + submodule_up_to_date = oideq(&update_data->oid, &suboid); + + if (!submodule_up_to_date || update_data->force) { ret = run_update_procedure(update_data); if (ret) return ret; @@ -2546,7 +2604,6 @@ static int update_submodule(struct update_data *update_data) next.prefix = NULL; oidcpy(&next.oid, null_oid()); - oidcpy(&next.suboid, null_oid()); cp.dir = update_data->sm_path; cp.git_cmd = 1; @@ -2579,6 +2636,12 @@ static int update_submodules(struct update_data *update_data) .data = &suc, }; + if (the_repository->settings.submodule_propagate_branches) { + struct branch *current_branch = branch_get(NULL); + if (current_branch) + update_data->super_branch = current_branch->name; + } + suc.update_data = update_data; run_processes_parallel(&opts); @@ -2643,9 +2706,6 @@ static int module_update(int argc, const char **argv, const char *prefix) N_("traverse submodules recursively")), OPT_BOOL('N', "no-fetch", &opt.nofetch, N_("don't fetch new objects from the remote site")), - OPT_STRING(0, "prefix", &opt.prefix, - N_("path"), - N_("path into the working tree")), OPT_SET_INT(0, "checkout", &opt.update_default, N_("use the 'checkout' update strategy (default)"), SM_UPDATE_CHECKOUT), @@ -2691,6 +2751,7 @@ static int module_update(int argc, const char **argv, const char *prefix) argc = parse_options(argc, argv, prefix, module_update_options, git_submodule_helper_usage, 0); + prepare_repo_settings(the_repository); if (opt.require_init) opt.init = 1; @@ -2701,6 +2762,7 @@ static int module_update(int argc, const char **argv, const char *prefix) } opt.filter_options = &filter_options; + opt.prefix = prefix; if (opt.update_default) opt.update_strategy.type = opt.update_default; @@ -2830,13 +2892,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix) int i; struct pathspec pathspec = { 0 }; struct module_list list = MODULE_LIST_INIT; - unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES; struct option embed_gitdir_options[] = { - OPT_STRING(0, "prefix", &prefix, - N_("path"), - N_("path into the working tree")), - OPT_BIT(0, "--recursive", &flags, N_("recurse into submodules"), - ABSORB_GITDIR_RECURSE_SUBMODULES), OPT_END() }; const char *const git_submodule_helper_usage[] = { @@ -2852,7 +2908,7 @@ static int absorb_git_dirs(int argc, const char **argv, const char *prefix) goto cleanup; for (i = 0; i < list.nr; i++) - absorb_git_dir_into_superproject(list.entries[i]->name, flags); + absorb_git_dir_into_superproject(list.entries[i]->name); ret = 0; cleanup: @@ -2861,51 +2917,6 @@ cleanup: return ret; } -static int module_config(int argc, const char **argv, const char *prefix) -{ - enum { - CHECK_WRITEABLE = 1, - DO_UNSET = 2 - } command = 0; - struct option module_config_options[] = { - OPT_CMDMODE(0, "check-writeable", &command, - N_("check if it is safe to write to the .gitmodules file"), - CHECK_WRITEABLE), - OPT_CMDMODE(0, "unset", &command, - N_("unset the config in the .gitmodules file"), - DO_UNSET), - OPT_END() - }; - const char *const git_submodule_helper_usage[] = { - N_("git submodule--helper config <name> [<value>]"), - N_("git submodule--helper config --unset <name>"), - "git submodule--helper config --check-writeable", - NULL - }; - - argc = parse_options(argc, argv, prefix, module_config_options, - git_submodule_helper_usage, PARSE_OPT_KEEP_ARGV0); - - if (argc == 1 && command == CHECK_WRITEABLE) - return is_writing_gitmodules_ok() ? 0 : -1; - - /* Equivalent to ACTION_GET in builtin/config.c */ - if (argc == 2 && command != DO_UNSET) - return print_config_from_gitmodules(the_repository, argv[1]); - - /* Equivalent to ACTION_SET in builtin/config.c */ - if (argc == 3 || (argc == 2 && command == DO_UNSET)) { - const char *value = (argc == 3) ? argv[2] : NULL; - - if (!is_writing_gitmodules_ok()) - die(_("please make sure that the .gitmodules file is in the working tree")); - - return config_set_in_gitmodules_file_gently(argv[1], value); - } - - usage_with_options(git_submodule_helper_usage, module_config_options); -} - static int module_set_url(int argc, const char **argv, const char *prefix) { int quiet = 0; @@ -3280,7 +3291,7 @@ static void die_on_repo_without_commits(const char *path) strbuf_addstr(&sb, path); if (is_nonbare_repository_dir(&sb)) { struct object_id oid; - if (resolve_gitlink_ref(path, "HEAD", &oid) < 0) + if (resolve_gitlink_ref(path, "HEAD", &oid, NULL) < 0) die(_("'%s' does not have a commit checked out"), path); } strbuf_release(&sb); @@ -3404,48 +3415,45 @@ cleanup: return ret; } -#define SUPPORT_SUPER_PREFIX (1<<0) - -struct cmd_struct { - const char *cmd; - int (*fn)(int, const char **, const char *); - unsigned option; -}; - -static struct cmd_struct commands[] = { - {"clone", module_clone, SUPPORT_SUPER_PREFIX}, - {"add", module_add, 0}, - {"update", module_update, SUPPORT_SUPER_PREFIX}, - {"foreach", module_foreach, SUPPORT_SUPER_PREFIX}, - {"init", module_init, 0}, - {"status", module_status, SUPPORT_SUPER_PREFIX}, - {"sync", module_sync, SUPPORT_SUPER_PREFIX}, - {"deinit", module_deinit, 0}, - {"summary", module_summary, 0}, - {"push-check", push_check, 0}, - {"absorbgitdirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX}, - {"config", module_config, 0}, - {"set-url", module_set_url, 0}, - {"set-branch", module_set_branch, 0}, - {"create-branch", module_create_branch, 0}, -}; - int cmd_submodule__helper(int argc, const char **argv, const char *prefix) { - int i; - if (argc < 2 || !strcmp(argv[1], "-h")) - usage("git submodule--helper <command>"); - - for (i = 0; i < ARRAY_SIZE(commands); i++) { - if (!strcmp(argv[1], commands[i].cmd)) { - if (get_super_prefix() && - !(commands[i].option & SUPPORT_SUPER_PREFIX)) - die(_("%s doesn't support --super-prefix"), - commands[i].cmd); - return commands[i].fn(argc - 1, argv + 1, prefix); - } - } + const char *cmd = argv[0]; + const char *subcmd; + parse_opt_subcommand_fn *fn = NULL; + const char *const usage[] = { + N_("git submodule--helper <command>"), + NULL + }; + struct option options[] = { + OPT_SUBCOMMAND("clone", &fn, module_clone), + OPT_SUBCOMMAND("add", &fn, module_add), + OPT_SUBCOMMAND("update", &fn, module_update), + OPT_SUBCOMMAND("foreach", &fn, module_foreach), + OPT_SUBCOMMAND("init", &fn, module_init), + OPT_SUBCOMMAND("status", &fn, module_status), + OPT_SUBCOMMAND("sync", &fn, module_sync), + OPT_SUBCOMMAND("deinit", &fn, module_deinit), + OPT_SUBCOMMAND("summary", &fn, module_summary), + OPT_SUBCOMMAND("push-check", &fn, push_check), + OPT_SUBCOMMAND("absorbgitdirs", &fn, absorb_git_dirs), + OPT_SUBCOMMAND("set-url", &fn, module_set_url), + OPT_SUBCOMMAND("set-branch", &fn, module_set_branch), + OPT_SUBCOMMAND("create-branch", &fn, module_create_branch), + OPT_END() + }; + argc = parse_options(argc, argv, prefix, options, usage, 0); + subcmd = argv[0]; + + if (strcmp(subcmd, "clone") && strcmp(subcmd, "update") && + strcmp(subcmd, "foreach") && strcmp(subcmd, "status") && + strcmp(subcmd, "sync") && strcmp(subcmd, "absorbgitdirs") && + get_super_prefix()) + /* + * xstrfmt() rather than "%s %s" to keep the translated + * string identical to git.c's. + */ + die(_("%s doesn't support --super-prefix"), + xstrfmt("'%s %s'", cmd, subcmd)); - die(_("'%s' is not a valid submodule--helper " - "subcommand"), argv[1]); + return fn(argc, argv, prefix); } |