Merge branch 'ps/submodule-ref-format'

Support to specify ref backend for submodules has been enhanced.

* ps/submodule-ref-format:
  object: fix leaking packfiles when closing object store
  submodule: fix leaking seen submodule names
  submodule: fix leaking fetch tasks
  builtin/submodule: allow "add" to use different ref storage format
  refs: fix ref storage format for submodule ref stores
  builtin/clone: propagate ref storage format to submodules
  builtin/submodule: allow cloning with different ref storage format
  git-submodule.sh: break overly long command lines
This commit is contained in:
Junio C Hamano
2024-08-15 13:22:14 -07:00
10 changed files with 298 additions and 25 deletions

View File

@ -34,7 +34,7 @@ COMMANDS
With no arguments, shows the status of existing submodules. Several With no arguments, shows the status of existing submodules. Several
subcommands are available to perform operations on the submodules. subcommands are available to perform operations on the submodules.
add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--depth <depth>] [--] <repository> [<path>]:: add [-b <branch>] [-f|--force] [--name <name>] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--] <repository> [<path>]::
Add the given repository as a submodule at the given path Add the given repository as a submodule at the given path
to the changeset to be committed next to the current to the changeset to be committed next to the current
project: the current project is termed the "superproject". project: the current project is termed the "superproject".
@ -71,6 +71,9 @@ submodule repositories will be kept together in the same relative
location, and only the superproject's URL needs to be provided. location, and only the superproject's URL needs to be provided.
git-submodule will correctly locate the submodule using the relative git-submodule will correctly locate the submodule using the relative
URL in `.gitmodules`. URL in `.gitmodules`.
+
If `--ref-format <format>` is specified, the ref storage format of newly
cloned submodules will be set accordingly.
status [--cached] [--recursive] [--] [<path>...]:: status [--cached] [--recursive] [--] [<path>...]::
Show the status of the submodules. This will print the SHA-1 of the Show the status of the submodules. This will print the SHA-1 of the
@ -136,7 +139,7 @@ If you really want to remove a submodule from the repository and commit
that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal that use linkgit:git-rm[1] instead. See linkgit:gitsubmodules[7] for removal
options. options.
update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]:: update [--init] [--remote] [-N|--no-fetch] [--[no-]recommend-shallow] [-f|--force] [--checkout|--rebase|--merge] [--reference <repository>] [--ref-format <format>] [--depth <depth>] [--recursive] [--jobs <n>] [--[no-]single-branch] [--filter <filter-spec>] [--] [<path>...]::
+ +
-- --
Update the registered submodules to match what the superproject Update the registered submodules to match what the superproject
@ -185,6 +188,9 @@ submodule with the `--init` option.
If `--recursive` is specified, this command will recurse into the If `--recursive` is specified, this command will recurse into the
registered submodules, and update any nested submodules within. registered submodules, and update any nested submodules within.
If `--ref-format <format>` is specified, the ref storage format of newly
cloned submodules will be set accordingly.
If `--filter <filter-spec>` is specified, the given partial clone filter will be If `--filter <filter-spec>` is specified, the given partial clone filter will be
applied to the submodule. See linkgit:git-rev-list[1] for details on filter applied to the submodule. See linkgit:git-rev-list[1] for details on filter
specifications. specifications.

View File

@ -729,7 +729,8 @@ static int git_sparse_checkout_init(const char *repo)
return result; return result;
} }
static int checkout(int submodule_progress, int filter_submodules) static int checkout(int submodule_progress, int filter_submodules,
enum ref_storage_format ref_storage_format)
{ {
struct object_id oid; struct object_id oid;
char *head; char *head;
@ -813,6 +814,10 @@ static int checkout(int submodule_progress, int filter_submodules)
strvec_push(&cmd.args, "--no-fetch"); strvec_push(&cmd.args, "--no-fetch");
} }
if (ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
strvec_pushf(&cmd.args, "--ref-format=%s",
ref_storage_format_to_name(ref_storage_format));
if (filter_submodules && filter_options.choice) if (filter_submodules && filter_options.choice)
strvec_pushf(&cmd.args, "--filter=%s", strvec_pushf(&cmd.args, "--filter=%s",
expand_list_objects_filter_spec(&filter_options)); expand_list_objects_filter_spec(&filter_options));
@ -1536,7 +1541,8 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
return 1; return 1;
junk_mode = JUNK_LEAVE_REPO; junk_mode = JUNK_LEAVE_REPO;
err = checkout(submodule_progress, filter_submodules); err = checkout(submodule_progress, filter_submodules,
ref_storage_format);
free(remote_name); free(remote_name);
strbuf_release(&reflog_msg); strbuf_release(&reflog_msg);

View File

@ -1532,6 +1532,7 @@ struct module_clone_data {
const char *url; const char *url;
int depth; int depth;
struct list_objects_filter_options *filter_options; struct list_objects_filter_options *filter_options;
enum ref_storage_format ref_storage_format;
unsigned int quiet: 1; unsigned int quiet: 1;
unsigned int progress: 1; unsigned int progress: 1;
unsigned int dissociate: 1; unsigned int dissociate: 1;
@ -1540,6 +1541,7 @@ struct module_clone_data {
}; };
#define MODULE_CLONE_DATA_INIT { \ #define MODULE_CLONE_DATA_INIT { \
.single_branch = -1, \ .single_branch = -1, \
.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
} }
struct submodule_alternate_setup { struct submodule_alternate_setup {
@ -1738,6 +1740,9 @@ static int clone_submodule(const struct module_clone_data *clone_data,
strvec_pushl(&cp.args, "--reference", strvec_pushl(&cp.args, "--reference",
item->string, NULL); item->string, NULL);
} }
if (clone_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
strvec_pushf(&cp.args, "--ref-format=%s",
ref_storage_format_to_name(clone_data->ref_storage_format));
if (clone_data->dissociate) if (clone_data->dissociate)
strvec_push(&cp.args, "--dissociate"); strvec_push(&cp.args, "--dissociate");
if (sm_gitdir && *sm_gitdir) if (sm_gitdir && *sm_gitdir)
@ -1832,6 +1837,7 @@ static int module_clone(int argc, const char **argv, const char *prefix)
struct string_list reference = STRING_LIST_INIT_NODUP; struct string_list reference = STRING_LIST_INIT_NODUP;
struct list_objects_filter_options filter_options = struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT; LIST_OBJECTS_FILTER_INIT;
const char *ref_storage_format = NULL;
struct option module_clone_options[] = { struct option module_clone_options[] = {
OPT_STRING(0, "prefix", &clone_data.prefix, OPT_STRING(0, "prefix", &clone_data.prefix,
@ -1849,6 +1855,8 @@ static int module_clone(int argc, const char **argv, const char *prefix)
OPT_STRING_LIST(0, "reference", &reference, OPT_STRING_LIST(0, "reference", &reference,
N_("repo"), N_("repo"),
N_("reference repository")), N_("reference repository")),
OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &dissociate, OPT_BOOL(0, "dissociate", &dissociate,
N_("use --reference only while cloning")), N_("use --reference only while cloning")),
OPT_INTEGER(0, "depth", &clone_data.depth, OPT_INTEGER(0, "depth", &clone_data.depth,
@ -1874,6 +1882,11 @@ static int module_clone(int argc, const char **argv, const char *prefix)
argc = parse_options(argc, argv, prefix, module_clone_options, argc = parse_options(argc, argv, prefix, module_clone_options,
git_submodule_helper_usage, 0); git_submodule_helper_usage, 0);
if (ref_storage_format) {
clone_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
if (clone_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
die(_("unknown ref storage format '%s'"), ref_storage_format);
}
clone_data.dissociate = !!dissociate; clone_data.dissociate = !!dissociate;
clone_data.quiet = !!quiet; clone_data.quiet = !!quiet;
clone_data.progress = !!progress; clone_data.progress = !!progress;
@ -1973,6 +1986,7 @@ struct update_data {
struct submodule_update_strategy update_strategy; struct submodule_update_strategy update_strategy;
struct list_objects_filter_options *filter_options; struct list_objects_filter_options *filter_options;
struct module_list list; struct module_list list;
enum ref_storage_format ref_storage_format;
int depth; int depth;
int max_jobs; int max_jobs;
int single_branch; int single_branch;
@ -1996,6 +2010,7 @@ struct update_data {
#define UPDATE_DATA_INIT { \ #define UPDATE_DATA_INIT { \
.update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \ .update_strategy = SUBMODULE_UPDATE_STRATEGY_INIT, \
.list = MODULE_LIST_INIT, \ .list = MODULE_LIST_INIT, \
.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
.recommend_shallow = -1, \ .recommend_shallow = -1, \
.references = STRING_LIST_INIT_DUP, \ .references = STRING_LIST_INIT_DUP, \
.single_branch = -1, \ .single_branch = -1, \
@ -2131,6 +2146,9 @@ static int prepare_to_clone_next_submodule(const struct cache_entry *ce,
expand_list_objects_filter_spec(suc->update_data->filter_options)); expand_list_objects_filter_spec(suc->update_data->filter_options));
if (suc->update_data->require_init) if (suc->update_data->require_init)
strvec_push(&child->args, "--require-init"); strvec_push(&child->args, "--require-init");
if (suc->update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
strvec_pushf(&child->args, "--ref-format=%s",
ref_storage_format_to_name(suc->update_data->ref_storage_format));
strvec_pushl(&child->args, "--path", sub->path, NULL); strvec_pushl(&child->args, "--path", sub->path, NULL);
strvec_pushl(&child->args, "--name", sub->name, NULL); strvec_pushl(&child->args, "--name", sub->name, NULL);
strvec_pushl(&child->args, "--url", url, NULL); strvec_pushl(&child->args, "--url", url, NULL);
@ -2565,6 +2583,9 @@ static void update_data_to_args(const struct update_data *update_data,
for_each_string_list_item(item, &update_data->references) for_each_string_list_item(item, &update_data->references)
strvec_pushl(args, "--reference", item->string, NULL); strvec_pushl(args, "--reference", item->string, NULL);
} }
if (update_data->ref_storage_format != REF_STORAGE_FORMAT_UNKNOWN)
strvec_pushf(args, "--ref-format=%s",
ref_storage_format_to_name(update_data->ref_storage_format));
if (update_data->filter_options && update_data->filter_options->choice) if (update_data->filter_options && update_data->filter_options->choice)
strvec_pushf(args, "--filter=%s", strvec_pushf(args, "--filter=%s",
expand_list_objects_filter_spec( expand_list_objects_filter_spec(
@ -2740,6 +2761,7 @@ static int module_update(int argc, const char **argv, const char *prefix)
struct update_data opt = UPDATE_DATA_INIT; struct update_data opt = UPDATE_DATA_INIT;
struct list_objects_filter_options filter_options = struct list_objects_filter_options filter_options =
LIST_OBJECTS_FILTER_INIT; LIST_OBJECTS_FILTER_INIT;
const char *ref_storage_format = NULL;
int ret; int ret;
struct option module_update_options[] = { struct option module_update_options[] = {
OPT__SUPER_PREFIX(&opt.super_prefix), OPT__SUPER_PREFIX(&opt.super_prefix),
@ -2763,6 +2785,8 @@ static int module_update(int argc, const char **argv, const char *prefix)
SM_UPDATE_REBASE), SM_UPDATE_REBASE),
OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"), OPT_STRING_LIST(0, "reference", &opt.references, N_("repo"),
N_("reference repository")), N_("reference repository")),
OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &opt.dissociate, OPT_BOOL(0, "dissociate", &opt.dissociate,
N_("use --reference only while cloning")), N_("use --reference only while cloning")),
OPT_INTEGER(0, "depth", &opt.depth, OPT_INTEGER(0, "depth", &opt.depth,
@ -2806,6 +2830,12 @@ static int module_update(int argc, const char **argv, const char *prefix)
module_update_options); module_update_options);
} }
if (ref_storage_format) {
opt.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
if (opt.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
die(_("unknown ref storage format '%s'"), ref_storage_format);
}
opt.filter_options = &filter_options; opt.filter_options = &filter_options;
opt.prefix = prefix; opt.prefix = prefix;
@ -3101,13 +3131,17 @@ struct add_data {
const char *sm_name; const char *sm_name;
const char *repo; const char *repo;
const char *realrepo; const char *realrepo;
enum ref_storage_format ref_storage_format;
int depth; int depth;
unsigned int force: 1; unsigned int force: 1;
unsigned int quiet: 1; unsigned int quiet: 1;
unsigned int progress: 1; unsigned int progress: 1;
unsigned int dissociate: 1; unsigned int dissociate: 1;
}; };
#define ADD_DATA_INIT { .depth = -1 } #define ADD_DATA_INIT { \
.depth = -1, \
.ref_storage_format = REF_STORAGE_FORMAT_UNKNOWN, \
}
static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path) static void append_fetch_remotes(struct strbuf *msg, const char *git_dir_path)
{ {
@ -3201,6 +3235,7 @@ static int add_submodule(const struct add_data *add_data)
string_list_append(&reference, p)->util = p; string_list_append(&reference, p)->util = p;
} }
clone_data.ref_storage_format = add_data->ref_storage_format;
clone_data.dissociate = add_data->dissociate; clone_data.dissociate = add_data->dissociate;
if (add_data->depth >= 0) if (add_data->depth >= 0)
clone_data.depth = add_data->depth; clone_data.depth = add_data->depth;
@ -3366,6 +3401,7 @@ static int module_add(int argc, const char **argv, const char *prefix)
{ {
int force = 0, quiet = 0, progress = 0, dissociate = 0; int force = 0, quiet = 0, progress = 0, dissociate = 0;
struct add_data add_data = ADD_DATA_INIT; struct add_data add_data = ADD_DATA_INIT;
const char *ref_storage_format = NULL;
char *to_free = NULL; char *to_free = NULL;
struct option options[] = { struct option options[] = {
OPT_STRING('b', "branch", &add_data.branch, N_("branch"), OPT_STRING('b', "branch", &add_data.branch, N_("branch"),
@ -3376,6 +3412,8 @@ static int module_add(int argc, const char **argv, const char *prefix)
OPT_BOOL(0, "progress", &progress, N_("force cloning progress")), OPT_BOOL(0, "progress", &progress, N_("force cloning progress")),
OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"), OPT_STRING(0, "reference", &add_data.reference_path, N_("repository"),
N_("reference repository")), N_("reference repository")),
OPT_STRING(0, "ref-format", &ref_storage_format, N_("format"),
N_("specify the reference format to use")),
OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")), OPT_BOOL(0, "dissociate", &dissociate, N_("borrow the objects from reference repositories")),
OPT_STRING(0, "name", &add_data.sm_name, N_("name"), OPT_STRING(0, "name", &add_data.sm_name, N_("name"),
N_("sets the submodule's name to the given string " N_("sets the submodule's name to the given string "
@ -3402,6 +3440,12 @@ static int module_add(int argc, const char **argv, const char *prefix)
if (argc == 0 || argc > 2) if (argc == 0 || argc > 2)
usage_with_options(usage, options); usage_with_options(usage, options);
if (ref_storage_format) {
add_data.ref_storage_format = ref_storage_format_by_name(ref_storage_format);
if (add_data.ref_storage_format == REF_STORAGE_FORMAT_UNKNOWN)
die(_("unknown ref storage format '%s'"), ref_storage_format);
}
add_data.repo = argv[0]; add_data.repo = argv[0];
if (argc == 1) if (argc == 1)
add_data.sm_path = git_url_basename(add_data.repo, 0, 0); add_data.sm_path = git_url_basename(add_data.repo, 0, 0);

View File

@ -94,6 +94,14 @@ cmd_add()
--reference=*) --reference=*)
reference_path="${1#--reference=}" reference_path="${1#--reference=}"
;; ;;
--ref-format)
case "$2" in '') usage ;; esac
ref_format="--ref-format=$2"
shift
;;
--ref-format=*)
ref_format="$1"
;;
--dissociate) --dissociate)
dissociate=1 dissociate=1
;; ;;
@ -129,7 +137,18 @@ cmd_add()
usage usage
fi fi
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add ${quiet:+--quiet} ${force:+--force} ${progress:+"--progress"} ${branch:+--branch "$branch"} ${reference_path:+--reference "$reference_path"} ${dissociate:+--dissociate} ${custom_name:+--name "$custom_name"} ${depth:+"$depth"} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper add \
${quiet:+--quiet} \
${force:+--force} \
${progress:+"--progress"} \
${branch:+--branch "$branch"} \
${reference_path:+--reference "$reference_path"} \
${ref_format:+"$ref_format"} \
${dissociate:+--dissociate} \
${custom_name:+--name "$custom_name"} \
${depth:+"$depth"} \
-- \
"$@"
} }
# #
@ -160,7 +179,11 @@ cmd_foreach()
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach ${quiet:+--quiet} ${recursive:+--recursive} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper foreach \
${quiet:+--quiet} \
${recursive:+--recursive} \
-- \
"$@"
} }
# #
@ -191,7 +214,10 @@ cmd_init()
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init ${quiet:+--quiet} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper init \
${quiet:+--quiet} \
-- \
"$@"
} }
# #
@ -227,7 +253,12 @@ cmd_deinit()
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${quiet:+--quiet} ${force:+--force} ${deinit_all:+--all} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit \
${quiet:+--quiet} \
${force:+--force} \
${deinit_all:+--all} \
-- \
"$@"
} }
# #
@ -268,6 +299,14 @@ cmd_update()
-r|--rebase) -r|--rebase)
rebase=1 rebase=1
;; ;;
--ref-format)
case "$2" in '') usage ;; esac
ref_format="--ref-format=$2"
shift
;;
--ref-format=*)
ref_format="$1"
;;
--reference) --reference)
case "$2" in '') usage ;; esac case "$2" in '') usage ;; esac
reference="--reference=$2" reference="--reference=$2"
@ -349,6 +388,7 @@ cmd_update()
${rebase:+--rebase} \ ${rebase:+--rebase} \
${merge:+--merge} \ ${merge:+--merge} \
${checkout:+--checkout} \ ${checkout:+--checkout} \
${ref_format:+"$ref_format"} \
${reference:+"$reference"} \ ${reference:+"$reference"} \
${dissociate:+"--dissociate"} \ ${dissociate:+"--dissociate"} \
${depth:+"$depth"} \ ${depth:+"$depth"} \
@ -399,7 +439,12 @@ cmd_set_branch() {
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch ${quiet:+--quiet} ${branch:+--branch "$branch"} ${default:+--default} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-branch \
${quiet:+--quiet} \
${branch:+--branch "$branch"} \
${default:+--default} \
-- \
"$@"
} }
# #
@ -428,7 +473,10 @@ cmd_set_url() {
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url ${quiet:+--quiet} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper set-url \
${quiet:+--quiet} \
-- \
"$@"
} }
# #
@ -480,7 +528,13 @@ cmd_summary() {
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary ${files:+--files} ${cached:+--cached} ${for_status:+--for-status} ${summary_limit:+-n $summary_limit} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper summary \
${files:+--files} \
${cached:+--cached} \
${for_status:+--for-status} \
${summary_limit:+-n $summary_limit} \
-- \
"$@"
} }
# #
# List all submodules, prefixed with: # List all submodules, prefixed with:
@ -521,8 +575,14 @@ cmd_status()
shift shift
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status ${quiet:+--quiet} ${cached:+--cached} ${recursive:+--recursive} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper status \
${quiet:+--quiet} \
${cached:+--cached} \
${recursive:+--recursive} \
-- \
"$@"
} }
# #
# Sync remote urls for submodules # Sync remote urls for submodules
# This makes the value for remote.$remote.url match the value # This makes the value for remote.$remote.url match the value
@ -554,7 +614,11 @@ cmd_sync()
esac esac
done done
git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync ${quiet:+--quiet} ${recursive:+--recursive} -- "$@" git ${wt_prefix:+-C "$wt_prefix"} submodule--helper sync \
${quiet:+--quiet} \
${recursive:+--recursive} \
-- \
"$@"
} }
cmd_absorbgitdirs() cmd_absorbgitdirs()

View File

@ -614,6 +614,15 @@ void raw_object_store_clear(struct raw_object_store *o)
INIT_LIST_HEAD(&o->packed_git_mru); INIT_LIST_HEAD(&o->packed_git_mru);
close_object_store(o); close_object_store(o);
/*
* `close_object_store()` only closes the packfiles, but doesn't free
* them. We thus have to do this manually.
*/
for (struct packed_git *p = o->packed_git, *next; p; p = next) {
next = p->next;
free(p);
}
o->packed_git = NULL; o->packed_git = NULL;
hashmap_clear(&o->pack_map); hashmap_clear(&o->pack_map);

2
refs.c
View File

@ -2009,7 +2009,7 @@ struct ref_store *repo_get_submodule_ref_store(struct repository *repo,
free(subrepo); free(subrepo);
goto done; goto done;
} }
refs = ref_store_init(subrepo, repo->ref_storage_format, refs = ref_store_init(subrepo, subrepo->ref_storage_format,
submodule_sb.buf, submodule_sb.buf,
REF_STORE_READ | REF_STORE_ODB); REF_STORE_READ | REF_STORE_ODB);
register_ref_store_map(&repo->submodule_ref_stores, "submodule", register_ref_store_map(&repo->submodule_ref_stores, "submodule",

View File

@ -1496,7 +1496,7 @@ static const struct submodule *get_non_gitmodules_submodule(const char *path)
return (const struct submodule *) ret; return (const struct submodule *) ret;
} }
static void fetch_task_release(struct fetch_task *p) static void fetch_task_free(struct fetch_task *p)
{ {
if (p->free_sub) if (p->free_sub)
free((void*)p->sub); free((void*)p->sub);
@ -1508,6 +1508,7 @@ static void fetch_task_release(struct fetch_task *p)
FREE_AND_NULL(p->repo); FREE_AND_NULL(p->repo);
strvec_clear(&p->git_args); strvec_clear(&p->git_args);
free(p);
} }
static struct repository *get_submodule_repo_for(struct repository *r, static struct repository *get_submodule_repo_for(struct repository *r,
@ -1576,8 +1577,7 @@ static struct fetch_task *fetch_task_create(struct submodule_parallel_fetch *spf
return task; return task;
cleanup: cleanup:
fetch_task_release(task); fetch_task_free(task);
free(task);
return NULL; return NULL;
} }
@ -1607,8 +1607,7 @@ get_fetch_task_from_index(struct submodule_parallel_fetch *spf,
} else { } else {
struct strbuf empty_submodule_path = STRBUF_INIT; struct strbuf empty_submodule_path = STRBUF_INIT;
fetch_task_release(task); fetch_task_free(task);
free(task);
/* /*
* An empty directory is normal, * An empty directory is normal,
@ -1654,8 +1653,7 @@ get_fetch_task_from_changed(struct submodule_parallel_fetch *spf,
cs_data->path, cs_data->path,
repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV)); repo_find_unique_abbrev(the_repository, cs_data->super_oid, DEFAULT_ABBREV));
fetch_task_release(task); fetch_task_free(task);
free(task);
continue; continue;
} }
@ -1763,7 +1761,7 @@ static int fetch_start_failure(struct strbuf *err UNUSED,
spf->result = 1; spf->result = 1;
fetch_task_release(task); fetch_task_free(task);
return 0; return 0;
} }
@ -1828,8 +1826,7 @@ static int fetch_finish(int retvalue, struct strbuf *err UNUSED,
} }
out: out:
fetch_task_release(task); fetch_task_free(task);
return 0; return 0;
} }
@ -1883,6 +1880,7 @@ int fetch_submodules(struct repository *r,
strvec_clear(&spf.args); strvec_clear(&spf.args);
out: out:
free_submodules_data(&spf.changed_submodule_names); free_submodules_data(&spf.changed_submodule_names);
string_list_clear(&spf.seen_submodule_names, 0);
return spf.result; return spf.result;
} }

View File

@ -5,6 +5,7 @@ test_description='pull can handle submodules'
GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh . ./test-lib.sh
. "$TEST_DIRECTORY"/lib-submodule-update.sh . "$TEST_DIRECTORY"/lib-submodule-update.sh

View File

@ -15,6 +15,7 @@ also by committing .gitmodules and then just removing it from the filesystem.
GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1 GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB=1
export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB export GIT_TEST_FATAL_REGISTER_SUBMODULE_ODB
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh . ./test-lib.sh
test_expect_success 'setup' ' test_expect_success 'setup' '

View File

@ -0,0 +1,144 @@
#!/bin/sh
test_description='submodules handle mixed ref storage formats'
TEST_PASSES_SANITIZE_LEAK=true
. ./test-lib.sh
test_ref_format () {
echo "$2" >expect &&
git -C "$1" rev-parse --show-ref-format >actual &&
test_cmp expect actual
}
for OTHER_FORMAT in files reftable
do
if test "$OTHER_FORMAT" = "$GIT_DEFAULT_REF_FORMAT"
then
continue
fi
test_expect_success 'setup' '
git config set --global protocol.file.allow always &&
# Some tests migrate the ref storage format, which does not work with
# reflogs at the time of writing these tests.
git config set --global core.logAllRefUpdates false
'
test_expect_success 'add existing repository with different ref storage format' '
test_when_finished "rm -rf parent" &&
git init parent &&
(
cd parent &&
test_commit parent &&
git init --ref-format=$OTHER_FORMAT submodule &&
test_commit -C submodule submodule &&
git submodule add ./submodule
)
'
test_expect_success 'add submodules with different ref storage format' '
test_when_finished "rm -rf submodule upstream" &&
git init submodule &&
test_commit -C submodule submodule-initial &&
git init upstream &&
test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
git -C upstream submodule add --ref-format="$OTHER_FORMAT" "file://$(pwd)/submodule" &&
test_ref_format upstream/submodule "$OTHER_FORMAT"
'
test_expect_success 'recursive clone propagates ref storage format' '
test_when_finished "rm -rf submodule upstream downstream" &&
git init submodule &&
test_commit -C submodule submodule-initial &&
git init upstream &&
git -C upstream submodule add "file://$(pwd)/submodule" &&
git -C upstream commit -am "add submodule" &&
# The upstream repository and its submodule should be using the default
# ref format.
test_ref_format upstream "$GIT_DEFAULT_REF_FORMAT" &&
test_ref_format upstream/submodule "$GIT_DEFAULT_REF_FORMAT" &&
# The cloned repositories should use the other ref format that we have
# specified via `--ref-format`. The option should propagate to cloned
# submodules.
git clone --ref-format=$OTHER_FORMAT --recurse-submodules \
upstream downstream &&
test_ref_format downstream "$OTHER_FORMAT" &&
test_ref_format downstream/submodule "$OTHER_FORMAT"
'
test_expect_success 'clone submodules with different ref storage format' '
test_when_finished "rm -rf submodule upstream downstream" &&
git init submodule &&
test_commit -C submodule submodule-initial &&
git init upstream &&
git -C upstream submodule add "file://$(pwd)/submodule" &&
git -C upstream commit -m "upstream submodule" &&
git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
test_ref_format downstream/submodule "$OTHER_FORMAT"
'
test_expect_success 'status with mixed submodule ref storages' '
test_when_finished "rm -rf submodule main" &&
git init submodule &&
test_commit -C submodule submodule-initial &&
git init main &&
git -C main submodule add "file://$(pwd)/submodule" &&
git -C main commit -m "add submodule" &&
git -C main/submodule refs migrate --ref-format=$OTHER_FORMAT &&
# The main repository should use the default ref format now, whereas
# the submodule should use the other format.
test_ref_format main "$GIT_DEFAULT_REF_FORMAT" &&
test_ref_format main/submodule "$OTHER_FORMAT" &&
cat >expect <<-EOF &&
$(git -C main/submodule rev-parse HEAD) submodule (submodule-initial)
EOF
git -C main submodule status >actual &&
test_cmp expect actual
'
test_expect_success 'recursive pull with mixed formats' '
test_when_finished "rm -rf submodule upstream downstream" &&
# Set up the initial structure with an upstream repository that has a
# submodule, as well as a downstream clone of the upstream repository.
git init submodule &&
test_commit -C submodule submodule-initial &&
git init upstream &&
git -C upstream submodule add "file://$(pwd)/submodule" &&
git -C upstream commit -m "upstream submodule" &&
# Clone the upstream repository such that the main repo and its
# submodules have different formats.
git clone --no-recurse-submodules "file://$(pwd)/upstream" downstream &&
git -C downstream submodule update --init --ref-format=$OTHER_FORMAT &&
test_ref_format downstream "$GIT_DEFAULT_REF_FORMAT" &&
test_ref_format downstream/submodule "$OTHER_FORMAT" &&
# Update the upstream submodule as well as the owning repository such
# that we can do a recursive pull.
test_commit -C submodule submodule-update &&
git -C upstream/submodule pull &&
git -C upstream commit -am "update the submodule" &&
git -C downstream pull --recurse-submodules &&
git -C upstream/submodule rev-parse HEAD >expect &&
git -C downstream/submodule rev-parse HEAD >actual &&
test_cmp expect actual
'
done
test_done