|
|
@ -2009,6 +2009,20 @@ struct submodule_update_clone { |
|
|
|
.max_jobs = 1, \ |
|
|
|
.max_jobs = 1, \ |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct update_data { |
|
|
|
|
|
|
|
const char *recursive_prefix; |
|
|
|
|
|
|
|
const char *sm_path; |
|
|
|
|
|
|
|
const char *displaypath; |
|
|
|
|
|
|
|
struct object_id oid; |
|
|
|
|
|
|
|
struct object_id suboid; |
|
|
|
|
|
|
|
struct submodule_update_strategy update_strategy; |
|
|
|
|
|
|
|
int depth; |
|
|
|
|
|
|
|
unsigned int force: 1; |
|
|
|
|
|
|
|
unsigned int quiet: 1; |
|
|
|
|
|
|
|
unsigned int nofetch: 1; |
|
|
|
|
|
|
|
unsigned int just_cloned: 1; |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
#define UPDATE_DATA_INIT { .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT } |
|
|
|
|
|
|
|
|
|
|
|
static void next_submodule_warn_missing(struct submodule_update_clone *suc, |
|
|
|
static void next_submodule_warn_missing(struct submodule_update_clone *suc, |
|
|
|
struct strbuf *out, const char *displaypath) |
|
|
|
struct strbuf *out, const char *displaypath) |
|
|
@ -2262,6 +2276,181 @@ static int git_update_clone_config(const char *var, const char *value, |
|
|
|
return 0; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int is_tip_reachable(const char *path, struct object_id *oid) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT; |
|
|
|
|
|
|
|
struct strbuf rev = STRBUF_INIT; |
|
|
|
|
|
|
|
char *hex = oid_to_hex(oid); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
cp.git_cmd = 1; |
|
|
|
|
|
|
|
cp.dir = xstrdup(path); |
|
|
|
|
|
|
|
cp.no_stderr = 1; |
|
|
|
|
|
|
|
strvec_pushl(&cp.args, "rev-list", "-n", "1", hex, "--not", "--all", NULL); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prepare_submodule_repo_env(&cp.env_array); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (capture_command(&cp, &rev, GIT_MAX_HEXSZ + 1) || rev.len) |
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int fetch_in_submodule(const char *module_path, int depth, int quiet, struct object_id *oid) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct child_process cp = CHILD_PROCESS_INIT; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prepare_submodule_repo_env(&cp.env_array); |
|
|
|
|
|
|
|
cp.git_cmd = 1; |
|
|
|
|
|
|
|
cp.dir = xstrdup(module_path); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
strvec_push(&cp.args, "fetch"); |
|
|
|
|
|
|
|
if (quiet) |
|
|
|
|
|
|
|
strvec_push(&cp.args, "--quiet"); |
|
|
|
|
|
|
|
if (depth) |
|
|
|
|
|
|
|
strvec_pushf(&cp.args, "--depth=%d", depth); |
|
|
|
|
|
|
|
if (oid) { |
|
|
|
|
|
|
|
char *hex = oid_to_hex(oid); |
|
|
|
|
|
|
|
char *remote = get_default_remote(); |
|
|
|
|
|
|
|
strvec_pushl(&cp.args, remote, hex, NULL); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return run_command(&cp); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int run_update_command(struct update_data *ud, int subforce) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
struct strvec args = STRVEC_INIT; |
|
|
|
|
|
|
|
struct strvec child_env = STRVEC_INIT; |
|
|
|
|
|
|
|
char *oid = oid_to_hex(&ud->oid); |
|
|
|
|
|
|
|
int must_die_on_failure = 0; |
|
|
|
|
|
|
|
int git_cmd; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (ud->update_strategy.type) { |
|
|
|
|
|
|
|
case SM_UPDATE_CHECKOUT: |
|
|
|
|
|
|
|
git_cmd = 1; |
|
|
|
|
|
|
|
strvec_pushl(&args, "checkout", "-q", NULL); |
|
|
|
|
|
|
|
if (subforce) |
|
|
|
|
|
|
|
strvec_push(&args, "-f"); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_REBASE: |
|
|
|
|
|
|
|
git_cmd = 1; |
|
|
|
|
|
|
|
strvec_push(&args, "rebase"); |
|
|
|
|
|
|
|
if (ud->quiet) |
|
|
|
|
|
|
|
strvec_push(&args, "--quiet"); |
|
|
|
|
|
|
|
must_die_on_failure = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_MERGE: |
|
|
|
|
|
|
|
git_cmd = 1; |
|
|
|
|
|
|
|
strvec_push(&args, "merge"); |
|
|
|
|
|
|
|
if (ud->quiet) |
|
|
|
|
|
|
|
strvec_push(&args, "--quiet"); |
|
|
|
|
|
|
|
must_die_on_failure = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_COMMAND: |
|
|
|
|
|
|
|
git_cmd = 0; |
|
|
|
|
|
|
|
strvec_push(&args, ud->update_strategy.command); |
|
|
|
|
|
|
|
must_die_on_failure = 1; |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
BUG("unexpected update strategy type: %s", |
|
|
|
|
|
|
|
submodule_strategy_to_string(&ud->update_strategy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
strvec_push(&args, oid); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
prepare_submodule_repo_env(&child_env); |
|
|
|
|
|
|
|
if (run_command_v_opt_cd_env(args.v, git_cmd ? RUN_GIT_CMD : RUN_USING_SHELL, |
|
|
|
|
|
|
|
ud->sm_path, child_env.v)) { |
|
|
|
|
|
|
|
switch (ud->update_strategy.type) { |
|
|
|
|
|
|
|
case SM_UPDATE_CHECKOUT: |
|
|
|
|
|
|
|
printf(_("Unable to checkout '%s' in submodule path '%s'"), |
|
|
|
|
|
|
|
oid, ud->displaypath); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_REBASE: |
|
|
|
|
|
|
|
printf(_("Unable to rebase '%s' in submodule path '%s'"), |
|
|
|
|
|
|
|
oid, ud->displaypath); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_MERGE: |
|
|
|
|
|
|
|
printf(_("Unable to merge '%s' in submodule path '%s'"), |
|
|
|
|
|
|
|
oid, ud->displaypath); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_COMMAND: |
|
|
|
|
|
|
|
printf(_("Execution of '%s %s' failed in submodule path '%s'"), |
|
|
|
|
|
|
|
ud->update_strategy.command, oid, ud->displaypath); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
BUG("unexpected update strategy type: %s", |
|
|
|
|
|
|
|
submodule_strategy_to_string(&ud->update_strategy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* NEEDSWORK: We are currently printing to stdout with error |
|
|
|
|
|
|
|
* return so that the shell caller handles the error output |
|
|
|
|
|
|
|
* properly. Once we start handling the error messages within |
|
|
|
|
|
|
|
* C, we should use die() instead. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (must_die_on_failure) |
|
|
|
|
|
|
|
return 2; |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* This signifies to the caller in shell that the command |
|
|
|
|
|
|
|
* failed without dying |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
return 1; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
switch (ud->update_strategy.type) { |
|
|
|
|
|
|
|
case SM_UPDATE_CHECKOUT: |
|
|
|
|
|
|
|
printf(_("Submodule path '%s': checked out '%s'\n"), |
|
|
|
|
|
|
|
ud->displaypath, oid); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_REBASE: |
|
|
|
|
|
|
|
printf(_("Submodule path '%s': rebased into '%s'\n"), |
|
|
|
|
|
|
|
ud->displaypath, oid); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_MERGE: |
|
|
|
|
|
|
|
printf(_("Submodule path '%s': merged in '%s'\n"), |
|
|
|
|
|
|
|
ud->displaypath, oid); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
case SM_UPDATE_COMMAND: |
|
|
|
|
|
|
|
printf(_("Submodule path '%s': '%s %s'\n"), |
|
|
|
|
|
|
|
ud->displaypath, ud->update_strategy.command, oid); |
|
|
|
|
|
|
|
break; |
|
|
|
|
|
|
|
default: |
|
|
|
|
|
|
|
BUG("unexpected update strategy type: %s", |
|
|
|
|
|
|
|
submodule_strategy_to_string(&ud->update_strategy)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 0; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int do_run_update_procedure(struct update_data *ud) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int subforce = is_null_oid(&ud->suboid) || ud->force; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!ud->nofetch) { |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Run fetch only if `oid` isn't present or it |
|
|
|
|
|
|
|
* is not reachable from a ref. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (!is_tip_reachable(ud->sm_path, &ud->oid) && |
|
|
|
|
|
|
|
fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, NULL) && |
|
|
|
|
|
|
|
!ud->quiet) |
|
|
|
|
|
|
|
fprintf_ln(stderr, |
|
|
|
|
|
|
|
_("Unable to fetch in submodule path '%s'; " |
|
|
|
|
|
|
|
"trying to directly fetch %s:"), |
|
|
|
|
|
|
|
ud->displaypath, oid_to_hex(&ud->oid)); |
|
|
|
|
|
|
|
/* |
|
|
|
|
|
|
|
* Now we tried the usual fetch, but `oid` may |
|
|
|
|
|
|
|
* not be reachable from any of the refs. |
|
|
|
|
|
|
|
*/ |
|
|
|
|
|
|
|
if (!is_tip_reachable(ud->sm_path, &ud->oid) && |
|
|
|
|
|
|
|
fetch_in_submodule(ud->sm_path, ud->depth, ud->quiet, &ud->oid)) |
|
|
|
|
|
|
|
die(_("Fetched in submodule path '%s', but it did not " |
|
|
|
|
|
|
|
"contain %s. Direct fetching of that commit failed."), |
|
|
|
|
|
|
|
ud->displaypath, oid_to_hex(&ud->oid)); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return run_update_command(ud, subforce); |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static void update_submodule(struct update_clone_data *ucd) |
|
|
|
static void update_submodule(struct update_clone_data *ucd) |
|
|
|
{ |
|
|
|
{ |
|
|
|
fprintf(stdout, "dummy %s %d\t%s\n", |
|
|
|
fprintf(stdout, "dummy %s %d\t%s\n", |
|
|
@ -2359,6 +2548,73 @@ static int update_clone(int argc, const char **argv, const char *prefix) |
|
|
|
return update_submodules(&suc); |
|
|
|
return update_submodules(&suc); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static int run_update_procedure(int argc, const char **argv, const char *prefix) |
|
|
|
|
|
|
|
{ |
|
|
|
|
|
|
|
int force = 0, quiet = 0, nofetch = 0, just_cloned = 0; |
|
|
|
|
|
|
|
char *prefixed_path, *update = NULL; |
|
|
|
|
|
|
|
struct update_data update_data = UPDATE_DATA_INIT; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
struct option options[] = { |
|
|
|
|
|
|
|
OPT__QUIET(&quiet, N_("suppress output for update by rebase or merge")), |
|
|
|
|
|
|
|
OPT__FORCE(&force, N_("force checkout updates"), 0), |
|
|
|
|
|
|
|
OPT_BOOL('N', "no-fetch", &nofetch, |
|
|
|
|
|
|
|
N_("don't fetch new objects from the remote site")), |
|
|
|
|
|
|
|
OPT_BOOL(0, "just-cloned", &just_cloned, |
|
|
|
|
|
|
|
N_("overrides update mode in case the repository is a fresh clone")), |
|
|
|
|
|
|
|
OPT_INTEGER(0, "depth", &update_data.depth, N_("depth for shallow fetch")), |
|
|
|
|
|
|
|
OPT_STRING(0, "prefix", &prefix, |
|
|
|
|
|
|
|
N_("path"), |
|
|
|
|
|
|
|
N_("path into the working tree")), |
|
|
|
|
|
|
|
OPT_STRING(0, "update", &update, |
|
|
|
|
|
|
|
N_("string"), |
|
|
|
|
|
|
|
N_("rebase, merge, checkout or none")), |
|
|
|
|
|
|
|
OPT_STRING(0, "recursive-prefix", &update_data.recursive_prefix, N_("path"), |
|
|
|
|
|
|
|
N_("path into the working tree, across nested " |
|
|
|
|
|
|
|
"submodule boundaries")), |
|
|
|
|
|
|
|
OPT_CALLBACK_F(0, "oid", &update_data.oid, N_("sha1"), |
|
|
|
|
|
|
|
N_("SHA1 expected by superproject"), PARSE_OPT_NONEG, |
|
|
|
|
|
|
|
parse_opt_object_id), |
|
|
|
|
|
|
|
OPT_CALLBACK_F(0, "suboid", &update_data.suboid, N_("subsha1"), |
|
|
|
|
|
|
|
N_("SHA1 of submodule's HEAD"), PARSE_OPT_NONEG, |
|
|
|
|
|
|
|
parse_opt_object_id), |
|
|
|
|
|
|
|
OPT_END() |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
const char *const usage[] = { |
|
|
|
|
|
|
|
N_("git submodule--helper run-update-procedure [<options>] <path>"), |
|
|
|
|
|
|
|
NULL |
|
|
|
|
|
|
|
}; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
argc = parse_options(argc, argv, prefix, options, usage, 0); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (argc != 1) |
|
|
|
|
|
|
|
usage_with_options(usage, options); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update_data.force = !!force; |
|
|
|
|
|
|
|
update_data.quiet = !!quiet; |
|
|
|
|
|
|
|
update_data.nofetch = !!nofetch; |
|
|
|
|
|
|
|
update_data.just_cloned = !!just_cloned; |
|
|
|
|
|
|
|
update_data.sm_path = argv[0]; |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (update_data.recursive_prefix) |
|
|
|
|
|
|
|
prefixed_path = xstrfmt("%s%s", update_data.recursive_prefix, update_data.sm_path); |
|
|
|
|
|
|
|
else |
|
|
|
|
|
|
|
prefixed_path = xstrdup(update_data.sm_path); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
update_data.displaypath = get_submodule_displaypath(prefixed_path, prefix); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
determine_submodule_update_strategy(the_repository, update_data.just_cloned, |
|
|
|
|
|
|
|
update_data.sm_path, update, |
|
|
|
|
|
|
|
&update_data.update_strategy); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
free(prefixed_path); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
if (!oideq(&update_data.oid, &update_data.suboid) || update_data.force) |
|
|
|
|
|
|
|
return do_run_update_procedure(&update_data); |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
return 3; |
|
|
|
|
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
static int resolve_relative_path(int argc, const char **argv, const char *prefix) |
|
|
|
static int resolve_relative_path(int argc, const char **argv, const char *prefix) |
|
|
|
{ |
|
|
|
{ |
|
|
|
struct strbuf sb = STRBUF_INIT; |
|
|
|
struct strbuf sb = STRBUF_INIT; |
|
|
@ -3098,6 +3354,7 @@ static struct cmd_struct commands[] = { |
|
|
|
{"add", module_add, SUPPORT_SUPER_PREFIX}, |
|
|
|
{"add", module_add, SUPPORT_SUPER_PREFIX}, |
|
|
|
{"update-module-mode", module_update_module_mode, 0}, |
|
|
|
{"update-module-mode", module_update_module_mode, 0}, |
|
|
|
{"update-clone", update_clone, 0}, |
|
|
|
{"update-clone", update_clone, 0}, |
|
|
|
|
|
|
|
{"run-update-procedure", run_update_procedure, 0}, |
|
|
|
{"ensure-core-worktree", ensure_core_worktree, 0}, |
|
|
|
{"ensure-core-worktree", ensure_core_worktree, 0}, |
|
|
|
{"relative-path", resolve_relative_path, 0}, |
|
|
|
{"relative-path", resolve_relative_path, 0}, |
|
|
|
{"resolve-relative-url-test", resolve_relative_url_test, 0}, |
|
|
|
{"resolve-relative-url-test", resolve_relative_url_test, 0}, |
|
|
|