]> git.ipfire.org Git - thirdparty/git.git/blobdiff - setup.c
The fifth batch
[thirdparty/git.git] / setup.c
diff --git a/setup.c b/setup.c
index e3b76e84b5b8676fdd23b7709800e3df24d8c08d..c7d3375645e613e66bfbf2976422b164af851f13 100644 (file)
--- a/setup.c
+++ b/setup.c
@@ -16,6 +16,7 @@
 #include "quote.h"
 #include "trace2.h"
 #include "worktree.h"
 #include "quote.h"
 #include "trace2.h"
 #include "worktree.h"
+#include "exec-cmd.h"
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
 
 static int inside_git_dir = -1;
 static int inside_work_tree = -1;
@@ -591,6 +592,25 @@ static enum extension_result handle_extension(const char *var,
                                     "extensions.objectformat", value);
                data->hash_algo = format;
                return EXTENSION_OK;
                                     "extensions.objectformat", value);
                data->hash_algo = format;
                return EXTENSION_OK;
+       } else if (!strcmp(ext, "compatobjectformat")) {
+               struct string_list_item *item;
+               int format;
+
+               if (!value)
+                       return config_error_nonbool(var);
+               format = hash_algo_by_name(value);
+               if (format == GIT_HASH_UNKNOWN)
+                       return error(_("invalid value for '%s': '%s'"),
+                                    "extensions.compatobjectformat", value);
+               /* For now only support compatObjectFormat being specified once. */
+               for_each_string_list_item(item, &data->v1_only_extensions) {
+                       if (!strcmp(item->string, "compatobjectformat"))
+                               return error(_("'%s' already specified as '%s'"),
+                                       "extensions.compatobjectformat",
+                                       hash_algos[data->compat_hash_algo].name);
+               }
+               data->compat_hash_algo = format;
+               return EXTENSION_OK;
        } else if (!strcmp(ext, "refstorage")) {
                unsigned int format;
 
        } else if (!strcmp(ext, "refstorage")) {
                unsigned int format;
 
@@ -1201,6 +1221,27 @@ static int ensure_valid_ownership(const char *gitfile,
        return data.is_safe;
 }
 
        return data.is_safe;
 }
 
+void die_upon_dubious_ownership(const char *gitfile, const char *worktree,
+                               const char *gitdir)
+{
+       struct strbuf report = STRBUF_INIT, quoted = STRBUF_INIT;
+       const char *path;
+
+       if (ensure_valid_ownership(gitfile, worktree, gitdir, &report))
+               return;
+
+       strbuf_complete(&report, '\n');
+       path = gitfile ? gitfile : gitdir;
+       sq_quote_buf_pretty(&quoted, path);
+
+       die(_("detected dubious ownership in repository at '%s'\n"
+             "%s"
+             "To add an exception for this directory, call:\n"
+             "\n"
+             "\tgit config --global --add safe.directory %s"),
+           path, report.buf, quoted.buf);
+}
+
 static int allowed_bare_repo_cb(const char *key, const char *value,
                                const struct config_context *ctx UNUSED,
                                void *d)
 static int allowed_bare_repo_cb(const char *key, const char *value,
                                const struct config_context *ctx UNUSED,
                                void *d)
@@ -1243,6 +1284,32 @@ static const char *allowed_bare_repo_to_string(
        return NULL;
 }
 
        return NULL;
 }
 
+static int is_implicit_bare_repo(const char *path)
+{
+       /*
+        * what we found is a ".git" directory at the root of
+        * the working tree.
+        */
+       if (ends_with_path_components(path, ".git"))
+               return 1;
+
+       /*
+        * we are inside $GIT_DIR of a secondary worktree of a
+        * non-bare repository.
+        */
+       if (strstr(path, "/.git/worktrees/"))
+               return 1;
+
+       /*
+        * we are inside $GIT_DIR of a worktree of a non-embedded
+        * submodule, whose superproject is not a bare repository.
+        */
+       if (strstr(path, "/.git/modules/"))
+               return 1;
+
+       return 0;
+}
+
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
 /*
  * We cannot decide in this function whether we are in the work tree or
  * not, since the config can only be read _after_ this function was called.
@@ -1372,7 +1439,7 @@ static enum discovery_result setup_git_directory_gently_1(struct strbuf *dir,
                if (is_git_directory(dir->buf)) {
                        trace2_data_string("setup", NULL, "implicit-bare-repository", dir->buf);
                        if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT &&
                if (is_git_directory(dir->buf)) {
                        trace2_data_string("setup", NULL, "implicit-bare-repository", dir->buf);
                        if (get_allowed_bare_repo() == ALLOWED_BARE_REPO_EXPLICIT &&
-                           !ends_with_path_components(dir->buf, ".git"))
+                           !is_implicit_bare_repo(dir->buf))
                                return GIT_DIR_DISALLOWED_BARE;
                        if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
                                return GIT_DIR_INVALID_OWNERSHIP;
                                return GIT_DIR_DISALLOWED_BARE;
                        if (!ensure_valid_ownership(NULL, NULL, dir->buf, report))
                                return GIT_DIR_INVALID_OWNERSHIP;
@@ -1577,6 +1644,8 @@ const char *setup_git_directory_gently(int *nongit_ok)
                }
                if (startup_info->have_repository) {
                        repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
                }
                if (startup_info->have_repository) {
                        repo_set_hash_algo(the_repository, repo_fmt.hash_algo);
+                       repo_set_compat_hash_algo(the_repository,
+                                                 repo_fmt.compat_hash_algo);
                        repo_set_ref_storage_format(the_repository,
                                                    repo_fmt.ref_storage_format);
                        the_repository->repository_format_worktree_config =
                        repo_set_ref_storage_format(the_repository,
                                                    repo_fmt.ref_storage_format);
                        the_repository->repository_format_worktree_config =
@@ -1672,6 +1741,7 @@ void check_repository_format(struct repository_format *fmt)
        check_repository_format_gently(get_git_dir(), fmt, NULL);
        startup_info->have_repository = 1;
        repo_set_hash_algo(the_repository, fmt->hash_algo);
        check_repository_format_gently(get_git_dir(), fmt, NULL);
        startup_info->have_repository = 1;
        repo_set_hash_algo(the_repository, fmt->hash_algo);
+       repo_set_compat_hash_algo(the_repository, fmt->compat_hash_algo);
        repo_set_ref_storage_format(the_repository,
                                    fmt->ref_storage_format);
        the_repository->repository_format_worktree_config =
        repo_set_ref_storage_format(the_repository,
                                    fmt->ref_storage_format);
        the_repository->repository_format_worktree_config =
@@ -1733,6 +1803,57 @@ int daemonize(void)
 #endif
 }
 
 #endif
 }
 
+struct template_dir_cb_data {
+       char *path;
+       int initialized;
+};
+
+static int template_dir_cb(const char *key, const char *value,
+                          const struct config_context *ctx, void *d)
+{
+       struct template_dir_cb_data *data = d;
+
+       if (strcmp(key, "init.templatedir"))
+               return 0;
+
+       if (!value) {
+               data->path = NULL;
+       } else {
+               char *path = NULL;
+
+               FREE_AND_NULL(data->path);
+               if (!git_config_pathname((const char **)&path, key, value))
+                       data->path = path ? path : xstrdup(value);
+       }
+
+       return 0;
+}
+
+const char *get_template_dir(const char *option_template)
+{
+       const char *template_dir = option_template;
+
+       if (!template_dir)
+               template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
+       if (!template_dir) {
+               static struct template_dir_cb_data data;
+
+               if (!data.initialized) {
+                       git_protected_config(template_dir_cb, &data);
+                       data.initialized = 1;
+               }
+               template_dir = data.path;
+       }
+       if (!template_dir) {
+               static char *dir;
+
+               if (!dir)
+                       dir = system_path(DEFAULT_GIT_TEMPLATE_DIR);
+               template_dir = dir;
+       }
+       return template_dir;
+}
+
 #ifdef NO_TRUSTABLE_FILEMODE
 #define TEST_FILEMODE 0
 #else
 #ifdef NO_TRUSTABLE_FILEMODE
 #define TEST_FILEMODE 0
 #else
@@ -1808,8 +1929,9 @@ static void copy_templates_1(struct strbuf *path, struct strbuf *template_path,
        }
 }
 
        }
 }
 
-static void copy_templates(const char *template_dir, const char *init_template_dir)
+static void copy_templates(const char *option_template)
 {
 {
+       const char *template_dir = get_template_dir(option_template);
        struct strbuf path = STRBUF_INIT;
        struct strbuf template_path = STRBUF_INIT;
        size_t template_len;
        struct strbuf path = STRBUF_INIT;
        struct strbuf template_path = STRBUF_INIT;
        size_t template_len;
@@ -1818,16 +1940,8 @@ static void copy_templates(const char *template_dir, const char *init_template_d
        DIR *dir;
        char *to_free = NULL;
 
        DIR *dir;
        char *to_free = NULL;
 
-       if (!template_dir)
-               template_dir = getenv(TEMPLATE_DIR_ENVIRONMENT);
-       if (!template_dir)
-               template_dir = init_template_dir;
-       if (!template_dir)
-               template_dir = to_free = system_path(DEFAULT_GIT_TEMPLATE_DIR);
-       if (!template_dir[0]) {
-               free(to_free);
+       if (!template_dir || !*template_dir)
                return;
                return;
-       }
 
        strbuf_addstr(&template_path, template_dir);
        strbuf_complete(&template_path, '/');
 
        strbuf_addstr(&template_path, template_dir);
        strbuf_complete(&template_path, '/');
@@ -1953,7 +2067,7 @@ void create_reference_database(unsigned int ref_storage_format,
                        die(_("invalid initial branch name: '%s'"),
                            initial_branch);
 
                        die(_("invalid initial branch name: '%s'"),
                            initial_branch);
 
-               if (create_symref("HEAD", ref, NULL) < 0)
+               if (refs_create_symref(get_main_ref_store(the_repository), "HEAD", ref, NULL) < 0)
                        exit(1);
                free(ref);
        }
                        exit(1);
                free(ref);
        }
@@ -1968,7 +2082,6 @@ void create_reference_database(unsigned int ref_storage_format,
 static int create_default_files(const char *template_path,
                                const char *original_git_dir,
                                const struct repository_format *fmt,
 static int create_default_files(const char *template_path,
                                const char *original_git_dir,
                                const struct repository_format *fmt,
-                               int prev_bare_repository,
                                int init_shared_repository)
 {
        struct stat st1;
                                int init_shared_repository)
 {
        struct stat st1;
@@ -1976,7 +2089,6 @@ static int create_default_files(const char *template_path,
        char *path;
        int reinit;
        int filemode;
        char *path;
        int reinit;
        int filemode;
-       const char *init_template_dir = NULL;
        const char *work_tree = get_git_work_tree();
 
        /*
        const char *work_tree = get_git_work_tree();
 
        /*
@@ -1988,9 +2100,7 @@ static int create_default_files(const char *template_path,
         * values (since we've just potentially changed what's available on
         * disk).
         */
         * values (since we've just potentially changed what's available on
         * disk).
         */
-       git_config_get_pathname("init.templatedir", &init_template_dir);
-       copy_templates(template_path, init_template_dir);
-       free((char *)init_template_dir);
+       copy_templates(template_path);
        git_config_clear();
        reset_shared_repository();
        git_config(git_default_config, NULL);
        git_config_clear();
        reset_shared_repository();
        git_config(git_default_config, NULL);
@@ -2003,34 +2113,8 @@ static int create_default_files(const char *template_path,
         */
        if (init_shared_repository != -1)
                set_shared_repository(init_shared_repository);
         */
        if (init_shared_repository != -1)
                set_shared_repository(init_shared_repository);
-       /*
-        * TODO: heed core.bare from config file in templates if no
-        *       command-line override given
-        */
-       is_bare_repository_cfg = prev_bare_repository || !work_tree;
-       /* TODO (continued):
-        *
-        * Unfortunately, the line above is equivalent to
-        *    is_bare_repository_cfg = !work_tree;
-        * which ignores the config entirely even if no `--[no-]bare`
-        * command line option was present.
-        *
-        * To see why, note that before this function, there was this call:
-        *    prev_bare_repository = is_bare_repository()
-        * expanding the right hand side:
-        *                 = is_bare_repository_cfg && !get_git_work_tree()
-        *                 = is_bare_repository_cfg && !work_tree
-        * note that the last simplification above is valid because nothing
-        * calls repo_init() or set_git_work_tree() between any of the
-        * relevant calls in the code, and thus the !get_git_work_tree()
-        * calls will return the same result each time.  So, what we are
-        * interested in computing is the right hand side of the line of
-        * code just above this comment:
-        *     prev_bare_repository || !work_tree
-        *        = is_bare_repository_cfg && !work_tree || !work_tree
-        *        = !work_tree
-        * because "A && !B || !B == !B" for all boolean values of A & B.
-        */
+
+       is_bare_repository_cfg = !work_tree;
 
        /*
         * We would have created the above under user's umask -- under
 
        /*
         * We would have created the above under user's umask -- under
@@ -2182,7 +2266,6 @@ int init_db(const char *git_dir, const char *real_git_dir,
        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;
        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;
-       int prev_bare_repository;
 
        if (real_git_dir) {
                struct stat st;
 
        if (real_git_dir) {
                struct stat st;
@@ -2208,7 +2291,6 @@ int init_db(const char *git_dir, const char *real_git_dir,
 
        safe_create_dir(git_dir, 0);
 
 
        safe_create_dir(git_dir, 0);
 
-       prev_bare_repository = is_bare_repository();
 
        /* Check to see if the repository version is right.
         * Note that a newly created repository does not have
 
        /* Check to see if the repository version is right.
         * Note that a newly created repository does not have
@@ -2221,8 +2303,7 @@ int init_db(const char *git_dir, const char *real_git_dir,
        validate_ref_storage_format(&repo_fmt, ref_storage_format);
 
        reinit = create_default_files(template_dir, original_git_dir,
        validate_ref_storage_format(&repo_fmt, ref_storage_format);
 
        reinit = create_default_files(template_dir, original_git_dir,
-                                     &repo_fmt, prev_bare_repository,
-                                     init_shared_repository);
+                                     &repo_fmt, init_shared_repository);
 
        /*
         * Now that we have set up both the hash algorithm and the ref storage
 
        /*
         * Now that we have set up both the hash algorithm and the ref storage