From ef8fb7fd96f548a1f2a05463d7102cab2798cc82 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 31 Aug 2026 12:02:05 +0200 Subject: [PATCH] builtin/clone: defer setup of the object database When cloning a repository we defer initialization of the reference database. This is because we don't yet know all details required for us to initialize the refdb in the first place. Most importantly, what we are missing is information about the object hash. We don't do the same thing for the object database yet, but here we essentially have the same problem. While the "files" database does not need any information about the object format at creation time, alternate backends are likely to require that information so that they can properly set up their data structures. Besides this forward-looking future proofing though, we also have a second use case for deferring initialization of the object database, namely alternates. When initializing the object database we do not yet know whether we'll need alternates or not because this depends on the repository we're about to clone from. If it is a local repository and the user has passed "--refernce{,-if-able}", then we will end up writing alternates into the object database. The ugly part though is that we cannot determine where the repository is getting cloned from before it has been initialized. While we of course already have access to the user-provided URI, that URI can be very well rewritten via "url..insteadOf". We can of course read the global- and system-level configuration to resolve it. But we explicitly resolve the URI a second time after we have initialized the repository because it can happen that we copy a ".git/config" over from our templates, and that file may cause us to rewrite the path. In a subsequent commit though we'll start to write alternates as part of the repository initialization, so we'll need to have the URI properly resolved before we can initialize the object database. This is ugly, but as mentioned above it makes sense for us to defer its initialization anyway so that we also know about the object hash already. Introduce a new flag that makes `init_db()` skip initializing the object database. Expose `create_object_database()` and make use of it after we have resolved the URI. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/clone.c | 12 ++++++++---- setup.c | 8 +++++--- setup.h | 15 ++++++++++----- 3 files changed, 23 insertions(+), 12 deletions(-) diff --git a/builtin/clone.c b/builtin/clone.c index 5b25cca510..0a67492ebd 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -1184,11 +1184,14 @@ int cmd_clone(int argc, * database. We do not yet know about the object format of the * repository, and reference backends may persist that information into * their on-disk data structures. + * + * Furthermore, we skip initializing the object database so that we can + * first resolve potential alternates before creating it. */ init_db(the_repository, git_dir, real_git_dir, work_tree, option_template, GIT_HASH_UNKNOWN, ref_storage_format, NULL, do_not_override_repo_unix_permissions, - INIT_DB_QUIET | INIT_DB_SKIP_REFDB); + INIT_DB_QUIET | INIT_DB_SKIP_REFDB | INIT_DB_SKIP_ODB); if (real_git_dir) { free((char *)git_dir); @@ -1311,9 +1314,6 @@ int cmd_clone(int argc, strbuf_reset(&key); } - if (option_required_reference.nr || option_optional_reference.nr) - setup_reference(); - remote = remote_get_early(remote_name); if (!option_rev) @@ -1342,6 +1342,10 @@ int cmd_clone(int argc, if (option_local > 0 && !is_local) warning(_("--local is ignored")); + create_object_database(the_repository); + if (option_required_reference.nr || option_optional_reference.nr) + setup_reference(); + transport = transport_get(remote, path ? path : remote->url.v[0]); transport_set_verbosity(transport, option_verbosity, option_progress); transport->family = family; diff --git a/setup.c b/setup.c index d90654f584..e654e27d05 100644 --- a/setup.c +++ b/setup.c @@ -2647,7 +2647,7 @@ static int create_default_files(struct repository *repo, return reinit; } -static void create_object_database(struct repository *repo) +void create_object_database(struct repository *repo) { /* * Create the "objects" directory in the common directory. This is done @@ -2829,7 +2829,8 @@ int init_db(struct repository *repo, const char *template_dir, int hash, enum ref_storage_format ref_storage_format, const char *initial_branch, - int init_shared_repository, unsigned int flags) + int init_shared_repository, + enum init_db_flags flags) { int reinit; int exist_ok = flags & INIT_DB_EXIST_OK; @@ -2903,7 +2904,8 @@ int init_db(struct repository *repo, if (!(flags & INIT_DB_SKIP_REFDB)) create_reference_database(repo, initial_branch, flags & INIT_DB_QUIET); - create_object_database(repo); + if (!(flags & INIT_DB_SKIP_ODB)) + create_object_database(repo); startup_info->have_repository = 1; diff --git a/setup.h b/setup.h index 763fd384e8..570ebcd150 100644 --- a/setup.h +++ b/setup.h @@ -256,9 +256,12 @@ int apply_repository_format(struct repository *repo, const char *get_template_dir(const char *option_template); -#define INIT_DB_QUIET (1 << 0) -#define INIT_DB_EXIST_OK (1 << 1) -#define INIT_DB_SKIP_REFDB (1 << 2) +enum init_db_flags { + INIT_DB_QUIET = (1 << 0), + INIT_DB_EXIST_OK = (1 << 1), + INIT_DB_SKIP_REFDB = (1 << 2), + INIT_DB_SKIP_ODB = (1 << 3), +}; int init_db(struct repository *repo, const char *git_dir, @@ -266,13 +269,15 @@ int init_db(struct repository *repo, const char *worktree, const char *template_dir, int hash_algo, enum ref_storage_format ref_storage_format, - const char *initial_branch, int init_shared_repository, - unsigned int flags); + const char *initial_branch, + int init_shared_repository, + enum init_db_flags flags); void initialize_repository_version(struct repository *repo, int hash_algo, enum ref_storage_format ref_storage_format, int reinit); void create_reference_database(struct repository *repo, const char *initial_branch, int quiet); +void create_object_database(struct repository *repo); /* * NOTE NOTE NOTE!!