repository: do not initialize HEAD if it's provided by templates When using templates to initialize a git repository, then git-init(1) will copy over all contents of the template directory. These will be preferred over the default ones created by git-init(1). While we mostly do the same, there is the exception of "HEAD". While we do copy over the template's HEAD file, afterwards we'll immediately re-initialize its contents with either the default "ref: refs/origin/master" or the init option's `initial_head` field. Let's fix the inconsistency with upstream git-init(1) by not overwriting the template HEAD, but only if the user hasn't set `opts.initial_head`. If the `initial_head` field has been supplied, we should use that indifferent from whether the template contained a HEAD file or not. Add tests to verify we correctly use the template directory's HEAD file and that `initial_head` overrides the template.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84
diff --git a/src/repository.c b/src/repository.c
index eefc76f..d707965 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -2056,7 +2056,8 @@ int git_repository_init_ext(
const char *given_repo,
git_repository_init_options *opts)
{
- git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT, common_path = GIT_BUF_INIT;
+ git_buf repo_path = GIT_BUF_INIT, wd_path = GIT_BUF_INIT,
+ common_path = GIT_BUF_INIT, head_path = GIT_BUF_INIT;
const char *wd;
int error;
@@ -2086,6 +2087,15 @@ int git_repository_init_ext(
} else {
if ((error = repo_init_structure(repo_path.ptr, wd, opts)) < 0 ||
(error = repo_init_config(repo_path.ptr, wd, opts->flags, opts->mode)) < 0 ||
+ (error = git_buf_joinpath(&head_path, repo_path.ptr, GIT_HEAD_FILE)) < 0)
+ goto out;
+
+ /*
+ * Only set the new HEAD if the file does not exist already via
+ * a template or if the caller has explicitly supplied an
+ * initial HEAD value.
+ */
+ if ((!git_path_exists(head_path.ptr) || opts->initial_head) &&
(error = git_repository_create_head(repo_path.ptr, opts->initial_head)) < 0)
goto out;
}
@@ -2098,6 +2108,7 @@ int git_repository_init_ext(
goto out;
out:
+ git_buf_dispose(&head_path);
git_buf_dispose(&common_path);
git_buf_dispose(&repo_path);
git_buf_dispose(&wd_path);
diff --git a/tests/repo/template.c b/tests/repo/template.c
index e86582a..7ccd935 100644
--- a/tests/repo/template.c
+++ b/tests/repo/template.c
@@ -249,6 +249,41 @@ void test_repo_template__extended_with_template_and_shared_mode(void)
validate_templates(_repo, "template");
}
+void test_repo_template__templated_head_is_used(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ git_buf head = GIT_BUF_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+
+ setup_templates("template", true);
+ cl_git_mkfile("template/HEAD", "foobar\n");
+ setup_repo("repo", &opts);
+
+ cl_git_pass(git_futils_readbuffer(&head, "repo/.git/HEAD"));
+ cl_assert_equal_s("foobar\n", head.ptr);
+
+ git_buf_dispose(&head);
+}
+
+void test_repo_template__initial_head_option_overrides_template_head(void)
+{
+ git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;
+ git_buf head = GIT_BUF_INIT;
+
+ opts.flags = GIT_REPOSITORY_INIT_MKPATH | GIT_REPOSITORY_INIT_EXTERNAL_TEMPLATE;
+ opts.initial_head = "manual";
+
+ setup_templates("template", true);
+ cl_git_mkfile("template/HEAD", "foobar\n");
+ setup_repo("repo", &opts);
+
+ cl_git_pass(git_futils_readbuffer(&head, "repo/.git/HEAD"));
+ cl_assert_equal_s("ref: refs/heads/manual\n", head.ptr);
+
+ git_buf_dispose(&head);
+}
+
void test_repo_template__empty_template_path(void)
{
git_repository_init_options opts = GIT_REPOSITORY_INIT_OPTIONS_INIT;