зеркало из https://github.com/microsoft/git.git
Merge branch 'sb/submodule-update-in-c'
"git submodule update" is getting rewritten piece-by-piece into C. * sb/submodule-update-in-c: submodule--helper: introduce new update-module-mode helper submodule--helper: replace connect-gitdir-workingtree by ensure-core-worktree builtin/submodule--helper: factor out method to update a single submodule builtin/submodule--helper: store update_clone information in a struct builtin/submodule--helper: factor out submodule updating git-submodule.sh: rename unused variables git-submodule.sh: align error reporting for update mode to use path
This commit is contained in:
Коммит
4d6d6ef1fc
|
@ -1443,6 +1443,72 @@ static int module_clone(int argc, const char **argv, const char *prefix)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void determine_submodule_update_strategy(struct repository *r,
|
||||||
|
int just_cloned,
|
||||||
|
const char *path,
|
||||||
|
const char *update,
|
||||||
|
struct submodule_update_strategy *out)
|
||||||
|
{
|
||||||
|
const struct submodule *sub = submodule_from_path(r, &null_oid, path);
|
||||||
|
char *key;
|
||||||
|
const char *val;
|
||||||
|
|
||||||
|
key = xstrfmt("submodule.%s.update", sub->name);
|
||||||
|
|
||||||
|
if (update) {
|
||||||
|
trace_printf("parsing update");
|
||||||
|
if (parse_submodule_update_strategy(update, out) < 0)
|
||||||
|
die(_("Invalid update mode '%s' for submodule path '%s'"),
|
||||||
|
update, path);
|
||||||
|
} else if (!repo_config_get_string_const(r, key, &val)) {
|
||||||
|
if (parse_submodule_update_strategy(val, out) < 0)
|
||||||
|
die(_("Invalid update mode '%s' configured for submodule path '%s'"),
|
||||||
|
val, path);
|
||||||
|
} else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
|
||||||
|
trace_printf("loaded thing");
|
||||||
|
out->type = sub->update_strategy.type;
|
||||||
|
out->command = sub->update_strategy.command;
|
||||||
|
} else
|
||||||
|
out->type = SM_UPDATE_CHECKOUT;
|
||||||
|
|
||||||
|
if (just_cloned &&
|
||||||
|
(out->type == SM_UPDATE_MERGE ||
|
||||||
|
out->type == SM_UPDATE_REBASE ||
|
||||||
|
out->type == SM_UPDATE_NONE))
|
||||||
|
out->type = SM_UPDATE_CHECKOUT;
|
||||||
|
|
||||||
|
free(key);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int module_update_module_mode(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
const char *path, *update = NULL;
|
||||||
|
int just_cloned;
|
||||||
|
struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
|
||||||
|
|
||||||
|
if (argc < 3 || argc > 4)
|
||||||
|
die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
|
||||||
|
|
||||||
|
just_cloned = git_config_int("just_cloned", argv[1]);
|
||||||
|
path = argv[2];
|
||||||
|
|
||||||
|
if (argc == 4)
|
||||||
|
update = argv[3];
|
||||||
|
|
||||||
|
determine_submodule_update_strategy(the_repository,
|
||||||
|
just_cloned, path, update,
|
||||||
|
&update_strategy);
|
||||||
|
fputs(submodule_strategy_to_string(&update_strategy), stdout);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct update_clone_data {
|
||||||
|
const struct submodule *sub;
|
||||||
|
struct object_id oid;
|
||||||
|
unsigned just_cloned;
|
||||||
|
};
|
||||||
|
|
||||||
struct submodule_update_clone {
|
struct submodule_update_clone {
|
||||||
/* index into 'list', the list of submodules to look into for cloning */
|
/* index into 'list', the list of submodules to look into for cloning */
|
||||||
int current;
|
int current;
|
||||||
|
@ -1462,8 +1528,9 @@ struct submodule_update_clone {
|
||||||
const char *recursive_prefix;
|
const char *recursive_prefix;
|
||||||
const char *prefix;
|
const char *prefix;
|
||||||
|
|
||||||
/* Machine-readable status lines to be consumed by git-submodule.sh */
|
/* to be consumed by git-submodule.sh */
|
||||||
struct string_list projectlines;
|
struct update_clone_data *update_clone;
|
||||||
|
int update_clone_nr; int update_clone_alloc;
|
||||||
|
|
||||||
/* If we want to stop as fast as possible and return an error */
|
/* If we want to stop as fast as possible and return an error */
|
||||||
unsigned quickstop : 1;
|
unsigned quickstop : 1;
|
||||||
|
@ -1471,11 +1538,13 @@ struct submodule_update_clone {
|
||||||
/* failed clones to be retried again */
|
/* failed clones to be retried again */
|
||||||
const struct cache_entry **failed_clones;
|
const struct cache_entry **failed_clones;
|
||||||
int failed_clones_nr, failed_clones_alloc;
|
int failed_clones_nr, failed_clones_alloc;
|
||||||
|
|
||||||
|
int max_jobs;
|
||||||
};
|
};
|
||||||
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
|
#define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
|
||||||
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
|
SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
|
||||||
NULL, NULL, NULL, \
|
NULL, NULL, NULL, \
|
||||||
STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
|
NULL, 0, 0, 0, NULL, 0, 0, 0}
|
||||||
|
|
||||||
|
|
||||||
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
|
static void next_submodule_warn_missing(struct submodule_update_clone *suc,
|
||||||
|
@ -1569,11 +1638,12 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
|
||||||
strbuf_addf(&sb, "%s/.git", ce->name);
|
strbuf_addf(&sb, "%s/.git", ce->name);
|
||||||
needs_cloning = !file_exists(sb.buf);
|
needs_cloning = !file_exists(sb.buf);
|
||||||
|
|
||||||
strbuf_reset(&sb);
|
ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
|
||||||
strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
|
suc->update_clone_alloc);
|
||||||
oid_to_hex(&ce->oid), ce_stage(ce),
|
oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
|
||||||
needs_cloning, ce->name);
|
suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
|
||||||
string_list_append(&suc->projectlines, sb.buf);
|
suc->update_clone[suc->update_clone_nr].sub = sub;
|
||||||
|
suc->update_clone_nr++;
|
||||||
|
|
||||||
if (!needs_cloning)
|
if (!needs_cloning)
|
||||||
goto cleanup;
|
goto cleanup;
|
||||||
|
@ -1714,11 +1784,44 @@ static int git_update_clone_config(const char *var, const char *value,
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void update_submodule(struct update_clone_data *ucd)
|
||||||
|
{
|
||||||
|
fprintf(stdout, "dummy %s %d\t%s\n",
|
||||||
|
oid_to_hex(&ucd->oid),
|
||||||
|
ucd->just_cloned,
|
||||||
|
ucd->sub->path);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int update_submodules(struct submodule_update_clone *suc)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
run_processes_parallel(suc->max_jobs,
|
||||||
|
update_clone_get_next_task,
|
||||||
|
update_clone_start_failure,
|
||||||
|
update_clone_task_finished,
|
||||||
|
suc);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* We saved the output and put it out all at once now.
|
||||||
|
* That means:
|
||||||
|
* - the listener does not have to interleave their (checkout)
|
||||||
|
* work with our fetching. The writes involved in a
|
||||||
|
* checkout involve more straightforward sequential I/O.
|
||||||
|
* - the listener can avoid doing any work if fetching failed.
|
||||||
|
*/
|
||||||
|
if (suc->quickstop)
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
for (i = 0; i < suc->update_clone_nr; i++)
|
||||||
|
update_submodule(&suc->update_clone[i]);
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int update_clone(int argc, const char **argv, const char *prefix)
|
static int update_clone(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
const char *update = NULL;
|
const char *update = NULL;
|
||||||
int max_jobs = 1;
|
|
||||||
struct string_list_item *item;
|
|
||||||
struct pathspec pathspec;
|
struct pathspec pathspec;
|
||||||
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
|
struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
|
||||||
|
|
||||||
|
@ -1740,7 +1843,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
||||||
OPT_STRING(0, "depth", &suc.depth, "<depth>",
|
OPT_STRING(0, "depth", &suc.depth, "<depth>",
|
||||||
N_("Create a shallow clone truncated to the "
|
N_("Create a shallow clone truncated to the "
|
||||||
"specified number of revisions")),
|
"specified number of revisions")),
|
||||||
OPT_INTEGER('j', "jobs", &max_jobs,
|
OPT_INTEGER('j', "jobs", &suc.max_jobs,
|
||||||
N_("parallel jobs")),
|
N_("parallel jobs")),
|
||||||
OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
|
OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
|
||||||
N_("whether the initial clone should follow the shallow recommendation")),
|
N_("whether the initial clone should follow the shallow recommendation")),
|
||||||
|
@ -1756,8 +1859,8 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
||||||
};
|
};
|
||||||
suc.prefix = prefix;
|
suc.prefix = prefix;
|
||||||
|
|
||||||
update_clone_config_from_gitmodules(&max_jobs);
|
update_clone_config_from_gitmodules(&suc.max_jobs);
|
||||||
git_config(git_update_clone_config, &max_jobs);
|
git_config(git_update_clone_config, &suc.max_jobs);
|
||||||
|
|
||||||
argc = parse_options(argc, argv, prefix, module_update_clone_options,
|
argc = parse_options(argc, argv, prefix, module_update_clone_options,
|
||||||
git_submodule_helper_usage, 0);
|
git_submodule_helper_usage, 0);
|
||||||
|
@ -1772,27 +1875,7 @@ static int update_clone(int argc, const char **argv, const char *prefix)
|
||||||
if (pathspec.nr)
|
if (pathspec.nr)
|
||||||
suc.warn_if_uninitialized = 1;
|
suc.warn_if_uninitialized = 1;
|
||||||
|
|
||||||
run_processes_parallel(max_jobs,
|
return update_submodules(&suc);
|
||||||
update_clone_get_next_task,
|
|
||||||
update_clone_start_failure,
|
|
||||||
update_clone_task_finished,
|
|
||||||
&suc);
|
|
||||||
|
|
||||||
/*
|
|
||||||
* We saved the output and put it out all at once now.
|
|
||||||
* That means:
|
|
||||||
* - the listener does not have to interleave their (checkout)
|
|
||||||
* work with our fetching. The writes involved in a
|
|
||||||
* checkout involve more straightforward sequential I/O.
|
|
||||||
* - the listener can avoid doing any work if fetching failed.
|
|
||||||
*/
|
|
||||||
if (suc.quickstop)
|
|
||||||
return 1;
|
|
||||||
|
|
||||||
for_each_string_list_item(item, &suc.projectlines)
|
|
||||||
fprintf(stdout, "%s", item->string);
|
|
||||||
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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)
|
||||||
|
@ -1938,6 +2021,45 @@ static int push_check(int argc, const char **argv, const char *prefix)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
|
||||||
|
{
|
||||||
|
const struct submodule *sub;
|
||||||
|
const char *path;
|
||||||
|
char *cw;
|
||||||
|
struct repository subrepo;
|
||||||
|
|
||||||
|
if (argc != 2)
|
||||||
|
BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
|
||||||
|
|
||||||
|
path = argv[1];
|
||||||
|
|
||||||
|
sub = submodule_from_path(the_repository, &null_oid, path);
|
||||||
|
if (!sub)
|
||||||
|
BUG("We could get the submodule handle before?");
|
||||||
|
|
||||||
|
if (repo_submodule_init(&subrepo, the_repository, path))
|
||||||
|
die(_("could not get a repository handle for submodule '%s'"), path);
|
||||||
|
|
||||||
|
if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
|
||||||
|
char *cfg_file, *abs_path;
|
||||||
|
const char *rel_path;
|
||||||
|
struct strbuf sb = STRBUF_INIT;
|
||||||
|
|
||||||
|
cfg_file = repo_git_path(&subrepo, "config");
|
||||||
|
|
||||||
|
abs_path = absolute_pathdup(path);
|
||||||
|
rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
|
||||||
|
|
||||||
|
git_config_set_in_file(cfg_file, "core.worktree", rel_path);
|
||||||
|
|
||||||
|
free(cfg_file);
|
||||||
|
free(abs_path);
|
||||||
|
strbuf_release(&sb);
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
|
static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
|
||||||
{
|
{
|
||||||
int i;
|
int i;
|
||||||
|
@ -2015,7 +2137,9 @@ static struct cmd_struct commands[] = {
|
||||||
{"list", module_list, 0},
|
{"list", module_list, 0},
|
||||||
{"name", module_name, 0},
|
{"name", module_name, 0},
|
||||||
{"clone", module_clone, 0},
|
{"clone", module_clone, 0},
|
||||||
|
{"update-module-mode", module_update_module_mode, 0},
|
||||||
{"update-clone", update_clone, 0},
|
{"update-clone", update_clone, 0},
|
||||||
|
{"ensure-core-worktree", ensure_core_worktree, 0},
|
||||||
{"relative-path", resolve_relative_path, 0},
|
{"relative-path", resolve_relative_path, 0},
|
||||||
{"resolve-relative-url", resolve_relative_url, 0},
|
{"resolve-relative-url", resolve_relative_url, 0},
|
||||||
{"resolve-relative-url-test", resolve_relative_url_test, 0},
|
{"resolve-relative-url-test", resolve_relative_url_test, 0},
|
||||||
|
|
|
@ -534,31 +534,19 @@ cmd_update()
|
||||||
"$@" || echo "#unmatched" $?
|
"$@" || echo "#unmatched" $?
|
||||||
} | {
|
} | {
|
||||||
err=
|
err=
|
||||||
while read -r mode sha1 stage just_cloned sm_path
|
while read -r quickabort sha1 just_cloned sm_path
|
||||||
do
|
do
|
||||||
die_if_unmatched "$mode" "$sha1"
|
die_if_unmatched "$quickabort" "$sha1"
|
||||||
|
|
||||||
name=$(git submodule--helper name "$sm_path") || exit
|
git submodule--helper ensure-core-worktree "$sm_path"
|
||||||
if ! test -z "$update"
|
|
||||||
then
|
update_module=$(git submodule--helper update-module-mode $just_cloned "$sm_path" $update)
|
||||||
update_module=$update
|
|
||||||
else
|
|
||||||
update_module=$(git config submodule."$name".update)
|
|
||||||
if test -z "$update_module"
|
|
||||||
then
|
|
||||||
update_module="checkout"
|
|
||||||
fi
|
|
||||||
fi
|
|
||||||
|
|
||||||
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
|
displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
|
||||||
|
|
||||||
if test $just_cloned -eq 1
|
if test $just_cloned -eq 1
|
||||||
then
|
then
|
||||||
subsha1=
|
subsha1=
|
||||||
case "$update_module" in
|
|
||||||
merge | rebase | none)
|
|
||||||
update_module=checkout ;;
|
|
||||||
esac
|
|
||||||
else
|
else
|
||||||
subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
|
subsha1=$(sanitize_submodule_env; cd "$sm_path" &&
|
||||||
git rev-parse --verify HEAD) ||
|
git rev-parse --verify HEAD) ||
|
||||||
|
@ -630,7 +618,7 @@ cmd_update()
|
||||||
must_die_on_failure=yes
|
must_die_on_failure=yes
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
die "$(eval_gettext "Invalid update mode '$update_module' for submodule '$name'")"
|
die "$(eval_gettext "Invalid update mode '$update_module' for submodule path '$path'")"
|
||||||
esac
|
esac
|
||||||
|
|
||||||
if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")
|
if (sanitize_submodule_env; cd "$sm_path" && $command "$sha1")
|
||||||
|
|
Загрузка…
Ссылка в новой задаче