]> git.ipfire.org Git - thirdparty/git.git/commitdiff
builtin/init-db: allow specifying hash algorithm on command line
authorbrian m. carlson <sandals@crustytoothpaste.net>
Sat, 22 Feb 2020 20:17:38 +0000 (20:17 +0000)
committerJunio C Hamano <gitster@pobox.com>
Mon, 24 Feb 2020 17:33:27 +0000 (09:33 -0800)
Allow the user to specify the hash algorithm on the command line by
using the --object-format option to git init.  Validate that the user is
not attempting to reinitialize a repository with a different hash
algorithm.  Ensure that if we are writing a non-SHA-1 repository that we
set the repository version to 1 and write the objectFormat extension.

Restrict this option to work only when ENABLE_SHA256 is set until the
codebase is in a situation to fully support this.

Signed-off-by: brian m. carlson <sandals@crustytoothpaste.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
Documentation/git-init.txt
builtin/clone.c
builtin/init-db.c
cache.h

index 32880aafb0c55ce29f35490fd734587c38095066..adc6adfd380beb88cfc9e95ad9be39d874b4890e 100644 (file)
@@ -10,7 +10,7 @@ SYNOPSIS
 --------
 [verse]
 'git init' [-q | --quiet] [--bare] [--template=<template_directory>]
-         [--separate-git-dir <git dir>]
+         [--separate-git-dir <git dir>] [--object-format=<format]
          [--shared[=<permissions>]] [directory]
 
 
@@ -48,6 +48,11 @@ Only print error and warning messages; all other output will be suppressed.
 Create a bare repository. If `GIT_DIR` environment is not set, it is set to the
 current working directory.
 
+--object-format=<format>::
+
+Specify the given object format (hash algorithm) for the repository.  The valid
+values are 'sha1' and (if enabled) 'sha256'.  'sha1' is the default.
+
 --template=<template_directory>::
 
 Specify the directory from which templates will be used.  (See the "TEMPLATE
index 4f6150c55c3a447b62de323b5cbe6640a7eb2cf2..961996a110330d1c70f770c2d5fe859ebd8ed7b4 100644 (file)
@@ -1097,7 +1097,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
                }
        }
 
-       init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
+       init_db(git_dir, real_git_dir, option_template, GIT_HASH_UNKNOWN, INIT_DB_QUIET);
 
        if (real_git_dir)
                git_dir = real_git_dir;
index b11f07064dff02519952b916955ca7c50e85328e..d05552f0ae135d9ab7d0459f215cad24d952839d 100644 (file)
@@ -177,7 +177,8 @@ static int needs_work_tree_config(const char *git_dir, const char *work_tree)
 }
 
 static int create_default_files(const char *template_path,
-                               const char *original_git_dir)
+                               const char *original_git_dir,
+                               const struct repository_format *fmt)
 {
        struct stat st1;
        struct strbuf buf = STRBUF_INIT;
@@ -187,6 +188,7 @@ static int create_default_files(const char *template_path,
        int reinit;
        int filemode;
        struct strbuf err = STRBUF_INIT;
+       int repo_version = GIT_REPO_VERSION;
 
        /* Just look for `init.templatedir` */
        init_db_template_dir = NULL; /* re-set in case it was set before */
@@ -244,11 +246,23 @@ static int create_default_files(const char *template_path,
                        exit(1);
        }
 
+#ifndef ENABLE_SHA256
+       if (fmt->hash_algo != GIT_HASH_SHA1)
+               die(_("The hash algorithm %s is not supported in this build."), hash_algos[fmt->hash_algo].name);
+#endif
+
+       if (fmt->hash_algo != GIT_HASH_SHA1)
+               repo_version = GIT_REPO_VERSION_READ;
+
        /* This forces creation of new config file */
        xsnprintf(repo_version_string, sizeof(repo_version_string),
-                 "%d", GIT_REPO_VERSION);
+                 "%d", repo_version);
        git_config_set("core.repositoryformatversion", repo_version_string);
 
+       if (fmt->hash_algo != GIT_HASH_SHA1)
+               git_config_set("extensions.objectformat",
+                              hash_algos[fmt->hash_algo].name);
+
        /* Check filemode trustability */
        path = git_path_buf(&buf, "config");
        filemode = TEST_FILEMODE;
@@ -340,12 +354,26 @@ static void separate_git_dir(const char *git_dir, const char *git_link)
        write_file(git_link, "gitdir: %s", git_dir);
 }
 
+static void validate_hash_algorithm(struct repository_format *repo_fmt, int hash)
+{
+       /*
+        * If we already have an initialized repo, don't allow the user to
+        * specify a different algorithm, as that could cause corruption.
+        * Otherwise, if the user has specified one on the command line, use it.
+        */
+       if (repo_fmt->version >= 0 && hash != GIT_HASH_UNKNOWN && hash != repo_fmt->hash_algo)
+               die(_("attempt to reinitialize repository with different hash"));
+       else if (hash != GIT_HASH_UNKNOWN)
+               repo_fmt->hash_algo = hash;
+}
+
 int init_db(const char *git_dir, const char *real_git_dir,
-           const char *template_dir, unsigned int flags)
+           const char *template_dir, int hash, unsigned int flags)
 {
        int reinit;
        int exist_ok = flags & INIT_DB_EXIST_OK;
        char *original_git_dir = real_pathdup(git_dir, 1);
+       struct repository_format repo_fmt = REPOSITORY_FORMAT_INIT;
 
        if (real_git_dir) {
                struct stat st;
@@ -378,9 +406,11 @@ int init_db(const char *git_dir, const char *real_git_dir,
         * config file, so this will not fail.  What we are catching
         * is an attempt to reinitialize new repository with an old tool.
         */
-       check_repository_format(NULL);
+       check_repository_format(&repo_fmt);
 
-       reinit = create_default_files(template_dir, original_git_dir);
+       validate_hash_algorithm(&repo_fmt, hash);
+
+       reinit = create_default_files(template_dir, original_git_dir, &repo_fmt);
 
        create_object_directory();
 
@@ -482,6 +512,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        const char *work_tree;
        const char *template_dir = NULL;
        unsigned int flags = 0;
+       const char *object_format = NULL;
+       int hash_algo = GIT_HASH_UNKNOWN;
        const struct option init_db_options[] = {
                OPT_STRING(0, "template", &template_dir, N_("template-directory"),
                                N_("directory from which templates will be used")),
@@ -494,6 +526,8 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                OPT_BIT('q', "quiet", &flags, N_("be quiet"), INIT_DB_QUIET),
                OPT_STRING(0, "separate-git-dir", &real_git_dir, N_("gitdir"),
                           N_("separate git dir from working tree")),
+               OPT_STRING(0, "object-format", &object_format, N_("hash"),
+                          N_("specify the hash algorithm to use")),
                OPT_END()
        };
 
@@ -546,6 +580,12 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
                free(cwd);
        }
 
+       if (object_format) {
+               hash_algo = hash_algo_by_name(object_format);
+               if (hash_algo == GIT_HASH_UNKNOWN)
+                       die(_("unknown hash algorithm '%s'"), object_format);
+       }
+
        if (init_shared_repository != -1)
                set_shared_repository(init_shared_repository);
 
@@ -597,5 +637,5 @@ int cmd_init_db(int argc, const char **argv, const char *prefix)
        UNLEAK(work_tree);
 
        flags |= INIT_DB_EXIST_OK;
-       return init_db(git_dir, real_git_dir, template_dir, flags);
+       return init_db(git_dir, real_git_dir, template_dir, hash_algo, flags);
 }
diff --git a/cache.h b/cache.h
index 29ee02a8d412c6875ab01f0cc97fbc9d0bc913a6..7a47e023bae84e7807c052acb6866f0d0f22a76b 100644 (file)
--- a/cache.h
+++ b/cache.h
@@ -627,7 +627,8 @@ int path_inside_repo(const char *prefix, const char *path);
 #define INIT_DB_EXIST_OK 0x0002
 
 int init_db(const char *git_dir, const char *real_git_dir,
-           const char *template_dir, unsigned int flags);
+           const char *template_dir, int hash_algo,
+           unsigned int flags);
 
 void sanitize_stdfds(void);
 int daemonize(void);