From 20e38cba3926a5b42ae1a83c7d4776285bc5c841 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Thu, 10 Sep 2026 17:09:11 +0200 Subject: [PATCH] setup: split up concerns of `init_db()` The function `init_db()` is responsible for creating the on-disk directory structure required for a Git repository. It is used by both git-init(1) and git-clone(1), and because their expected behaviour is different we support a couple of flags: - The `QUIET` flag controls whether the command is quiet or not. For git-init(1) this is user-controllable, whereas for git-clone(1) we're always quiet. - The `EXIST_OK` flag controls whether a preexisting repository is okay or not. For git-init(1) it is, for git-clone(1) it's not. - The `SKIP_REFDB` flag controls whether the reference database should already be created or not. For git-init(1) we do, but for git-clone(1) we don't because it does not yet know about the default branch and about the remote object hash. Furthermore, we're about to add another divergence in behaviour, where we have to also skip creation of the object database in git-clone(1). This is becoming quite cumbersome though. Instead of introducing another flag, start to split up concerns of the function so that we never create the reference or object database. This becomes the responsibility of the caller, which is thus free to defer their creation to a later point in time. This lets us get rid of most of the divergent behaviour: - We don't need the `SKIP_REFDB` and a potential `SKIP_ODB` flags anymore. - We don't need the `QUIET` flag anymore, as nothing prints output except for the final status message that tells the user that the repository has been (re)initialized. But as this message is specific to git-init(1), we can easily move it there. The only piece of information we still have to convey is whether or not reinitialization of a preexisting repository is okay. This is handled by a new `reinit_ok` pointer that, if non-`NULL`, indicates that it is okay to reinitialize the repository. Furthermore, the pointer will be written to to indicate whether the repository was reinitialized or not, which we need in git-init(1) to print the correct initialization message. With these refactorings, `init_db()` is named quite misleadingly though, as we don't create any of the reference or object databases anymore. Rename it to `create_repository()`. Signed-off-by: Patrick Steinhardt Signed-off-by: Junio C Hamano --- builtin/clone.c | 9 ++++---- builtin/init-db.c | 32 +++++++++++++++++++++------- setup.c | 54 +++++++++++++++-------------------------------- setup.h | 43 +++++++++++++++++++++++++++---------- 4 files changed, 78 insertions(+), 60 deletions(-) diff --git a/builtin/clone.c b/builtin/clone.c index 5b25cca510..904d2d859f 100644 --- a/builtin/clone.c +++ b/builtin/clone.c @@ -1185,10 +1185,10 @@ int cmd_clone(int argc, * repository, and reference backends may persist that information into * their on-disk data structures. */ - 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); + create_repository(the_repository, git_dir, real_git_dir, work_tree, + option_template, GIT_HASH_UNKNOWN, ref_storage_format, + do_not_override_repo_unix_permissions, NULL); + create_object_database(the_repository); if (real_git_dir) { free((char *)git_dir); @@ -1445,6 +1445,7 @@ int cmd_clone(int argc, initialize_repository_version(the_repository, hash_algo, the_repository->ref_storage_format, 1); repo_set_hash_algo(the_repository, hash_algo); create_reference_database(the_repository, NULL, 1); + startup_info->have_repository = 1; /* * Before fetching from the remote, download and install bundle diff --git a/builtin/init-db.c b/builtin/init-db.c index e96b1283b7..f2c7e3be6d 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -80,7 +80,7 @@ int cmd_init_db(int argc, char *work_tree = NULL; const char *template_dir = NULL; char *template_dir_to_free = NULL; - unsigned int flags = 0; + int quiet = 0; int bare = startup_info->force_bare_repository ? 1 : -1; const char *object_format = NULL; const char *ref_format = NULL; @@ -102,7 +102,7 @@ int cmd_init_db(int argc, .flags = PARSE_OPT_OPTARG | PARSE_OPT_NONEG, .callback = shared_callback }, - OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET), + OPT_BOOL('q', "quiet", &quiet, N_("be quiet")), OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"), N_("separate git dir from working tree")), OPT_STRING('b', "initial-branch", &initial_branch, N_("name"), @@ -113,7 +113,7 @@ int cmd_init_db(int argc, N_("specify the reference format to use")), OPT_END() }; - int ret; + int reinit; argc = parse_options(argc, argv, prefix, init_db_options, init_db_usage, 0); @@ -247,14 +247,30 @@ int cmd_init_db(int argc, die(_("--separate-git-dir incompatible with bare repository")); } - flags |= INIT_DB_EXIST_OK; - ret = init_db(the_repository, git_dir, real_git_dir, work_tree, - template_dir, hash_algo, ref_storage_format, initial_branch, - init_shared_repository, flags); + create_repository(the_repository, git_dir, real_git_dir, work_tree, + template_dir, hash_algo, ref_storage_format, + init_shared_repository, &reinit); + create_reference_database(the_repository, initial_branch, quiet); + create_object_database(the_repository); + + if (!quiet) { + int len = strlen(git_dir); + + if (reinit) + printf(repo_settings_get_shared_repository(the_repository) + ? _("Reinitialized existing shared Git repository in %s%s\n") + : _("Reinitialized existing Git repository in %s%s\n"), + git_dir, len && git_dir[len-1] != '/' ? "/" : ""); + else + printf(repo_settings_get_shared_repository(the_repository) + ? _("Initialized empty shared Git repository in %s%s\n") + : _("Initialized empty Git repository in %s%s\n"), + git_dir, len && git_dir[len-1] != '/' ? "/" : ""); + } free(template_dir_to_free); free(real_git_dir_to_free); free(work_tree); free(git_dir); - return ret; + return 0; } diff --git a/setup.c b/setup.c index d90654f584..8c7b97f92e 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 @@ -2822,17 +2822,17 @@ static void repository_format_configure(struct repository_format *repo_fmt, } } -int init_db(struct repository *repo, - const char *git_dir, - const char *real_git_dir, - const char *worktree, - const char *template_dir, int hash, - enum ref_storage_format ref_storage_format, - const char *initial_branch, - int init_shared_repository, unsigned int flags) +void create_repository(struct repository *repo, + const char *git_dir, + const char *real_git_dir, + const char *worktree, + const char *template_dir, + int hash, + enum ref_storage_format ref_storage_format, + int init_shared_repository, + int *reinit_ok) { - int reinit; - int exist_ok = flags & INIT_DB_EXIST_OK; + int reinit_ignored; char *original_git_dir = real_pathdup(git_dir, 1); struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT; struct strbuf err = STRBUF_INIT; @@ -2840,10 +2840,10 @@ int init_db(struct repository *repo, if (real_git_dir) { struct stat st; - if (!exist_ok && !stat(git_dir, &st)) + if (!reinit_ok && !stat(git_dir, &st)) die(_("%s already exists"), git_dir); - if (!exist_ok && !stat(real_git_dir, &st)) + if (!reinit_ok && !stat(real_git_dir, &st)) die(_("%s already exists"), real_git_dir); apply_and_export_relative_gitdir(repo, real_git_dir, 1); @@ -2877,8 +2877,10 @@ int init_db(struct repository *repo, safe_create_dir(repo, git_dir, 0); - reinit = create_default_files(repo, template_dir, original_git_dir, - &repo_fmt, init_shared_repository); + if (!reinit_ok) + reinit_ok = &reinit_ignored; + *reinit_ok = create_default_files(repo, template_dir, original_git_dir, + &repo_fmt, init_shared_repository); if (repo_settings_get_shared_repository(repo)) { char buf[10]; @@ -2901,29 +2903,7 @@ int init_db(struct repository *repo, repo_config_set(repo, "receive.denyNonFastforwards", "true"); } - if (!(flags & INIT_DB_SKIP_REFDB)) - create_reference_database(repo, initial_branch, flags & INIT_DB_QUIET); - create_object_database(repo); - - startup_info->have_repository = 1; - - if (!(flags & INIT_DB_QUIET)) { - int len = strlen(git_dir); - - if (reinit) - printf(repo_settings_get_shared_repository(repo) - ? _("Reinitialized existing shared Git repository in %s%s\n") - : _("Reinitialized existing Git repository in %s%s\n"), - git_dir, len && git_dir[len-1] != '/' ? "/" : ""); - else - printf(repo_settings_get_shared_repository(repo) - ? _("Initialized empty shared Git repository in %s%s\n") - : _("Initialized empty Git repository in %s%s\n"), - git_dir, len && git_dir[len-1] != '/' ? "/" : ""); - } - clear_repository_format(&repo_fmt); strbuf_release(&err); free(original_git_dir); - return 0; } diff --git a/setup.h b/setup.h index 763fd384e8..f1c1ed65fb 100644 --- a/setup.h +++ b/setup.h @@ -256,24 +256,45 @@ 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) +/* + * Create the repository by creating the necessary directory structures, + * setting up the configuration and configuring the repository's format. If + * `template_dir` is set, copy over templates from that directory. Furthermore, + * if and only if `reinit_ok` is a non-NULL pointer, then the function may + * reinitialize a preexisting repository. In that case, the pointer will be set + * to `1` in case the repo was reinitialized and `0` if it didn't exist yet. + * + * Note that this function does not create the reference and object databases. + */ +void create_repository(struct repository *repo, + const char *git_dir, + const char *real_git_dir, + const char *worktree, + const char *template_dir, + int hash_algo, + enum ref_storage_format ref_storage_format, + int init_shared_repository, + int *reinit_ok); -int init_db(struct repository *repo, - const char *git_dir, - const char *real_git_dir, - 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); void initialize_repository_version(struct repository *repo, int hash_algo, enum ref_storage_format ref_storage_format, int reinit); + +/* + * Create the reference database for the repository. The repository and its ref + * storage format must have already been configured properly before calling + * this function. When set, `initial_branch` overrides the default branch that + * HEAD will point to. + */ void create_reference_database(struct repository *repo, const char *initial_branch, int quiet); +/* + * Create the object database for the repository. The repository must have + * already been configured properly before calling this function. + */ +void create_object_database(struct repository *repo); + /* * NOTE NOTE NOTE!! *