From 425772960e70c94d92f69ad6a68e594634a8c889 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 08:14:07 +0200 Subject: [PATCH 1/9] refs: handle ORIG_HEAD via the refdb We have a bunch of references that we treat like pseudo-refs. Those references are (sometimes) read and written by going to the filesystem directly, at other times they are read and written via the refdb. This works alright with the "files" ref storage format given that any root reference never gets packed into the "packed-refs" file, and thus they would always be accessible a loose ref if present. The behaviour is wrong though when considering alternate backends like the "reftable" backend. All references except for pseudo-refs must be read via the backend, and that includes root refs. Historically this part of Git has been ill-defined, and it wasn't quite clear which refs are considered pseudo-refs in the first place. This was clarified in 6fd80375640 (Documentation/glossary: redefine pseudorefs as special refs, 2024-05-15): there only are two pseudorefs, "FETCH_HEAD" and "MERGE_HEAD". The reason why those two references are considered special is that they may contain additional data that doesn't fit into the normal reference format. In any case, our current handling of a couple of root references is broken in this new world. Fix this for "ORIG_HEAD" by exclusively going through the refdb to read and write that reference. Rename the define accordingly to clarify that it is a reference and not a file. --- src/libgit2/refs.h | 9 ++++- src/libgit2/repository.c | 20 ++++------- tests/libgit2/merge/workdir/setup.c | 55 +++++++++++++++++------------ tests/libgit2/worktree/merge.c | 11 +++++- 4 files changed, 56 insertions(+), 39 deletions(-) diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index a06965b60d8..931ef52f1aa 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -32,8 +32,15 @@ extern bool git_reference__enable_symbolic_ref_target_validation; #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled fully-peeled sorted " #define GIT_PACKEDREFS_FILE_MODE 0666 +/* + * Root references. These references aren't really any special, except that + * they're used by Git to store some special state. Other than that those + * references go through the reference database as usual for any other + * reference, as well. + */ +#define GIT_ORIG_HEAD_REF "ORIG_HEAD" + #define GIT_HEAD_FILE "HEAD" -#define GIT_ORIG_HEAD_FILE "ORIG_HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD" #define GIT_REVERT_HEAD_FILE "REVERT_HEAD" diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index a88217e6556..0cdb4ee6651 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3386,23 +3386,15 @@ int git_repository_head_tree(git_tree **tree, git_repository *repo) int git_repository__set_orig_head(git_repository *repo, const git_oid *orig_head) { - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - char orig_head_str[GIT_OID_MAX_HEXSIZE]; + git_reference *ref = NULL; int error = 0; - git_oid_fmt(orig_head_str, orig_head); - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_ORIG_HEAD_FILE)) == 0 && - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_MERGE_FILE_MODE)) == 0 && - (error = git_filebuf_printf(&file, "%.*s\n", (int)git_oid_hexsize(repo->oid_type), orig_head_str)) == 0) - error = git_filebuf_commit(&file); - - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); + if ((error = git_reference_create(&ref, repo, GIT_ORIG_HEAD_REF, + orig_head, 1, NULL)) < 0) + goto out; +out: + git_reference_free(ref); return error; } diff --git a/tests/libgit2/merge/workdir/setup.c b/tests/libgit2/merge/workdir/setup.c index 84496c436e1..9c1b121cb6a 100644 --- a/tests/libgit2/merge/workdir/setup.c +++ b/tests/libgit2/merge/workdir/setup.c @@ -60,6 +60,15 @@ static bool test_file_contents(const char *filename, const char *expected) return equals; } +static bool test_ref_contents(git_repository *repo, const char *filename, + const char *expected_oid) +{ + git_oid actual, expected; + cl_git_pass(git_oid_from_string(&expected, expected_oid, GIT_OID_SHA1)); + cl_git_pass(git_reference_name_to_id(&actual, repo, filename)); + return git_oid_equal(&actual, &expected); +} + static void write_file_contents(const char *filename, const char *output) { git_str file_path_buf = GIT_STR_INIT; @@ -87,7 +96,7 @@ void test_merge_workdir_setup__one_branch(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'\n")); @@ -113,7 +122,7 @@ void test_merge_workdir_setup__one_oid(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'\n")); @@ -141,7 +150,7 @@ void test_merge_workdir_setup__two_branches(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO2_BRANCH "'\n")); @@ -177,7 +186,7 @@ void test_merge_workdir_setup__three_branches(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO2_BRANCH "' and '" OCTO3_BRANCH "'\n")); @@ -215,7 +224,7 @@ void test_merge_workdir_setup__three_oids(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; commit '" OCTO2_OID "'; commit '" OCTO3_OID "'\n")); @@ -245,7 +254,7 @@ void test_merge_workdir_setup__branches_and_oids_1(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'; commit '" OCTO2_OID "'\n")); @@ -284,7 +293,7 @@ void test_merge_workdir_setup__branches_and_oids_2(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "'; commit '" OCTO2_OID "'; commit '" OCTO4_OID "'\n")); @@ -326,7 +335,7 @@ void test_merge_workdir_setup__branches_and_oids_3(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; branches '" OCTO2_BRANCH "' and '" OCTO4_BRANCH "'; commit '" OCTO3_OID "'\n")); @@ -372,7 +381,7 @@ void test_merge_workdir_setup__branches_and_oids_4(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 5)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n" OCTO5_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; branches '" OCTO2_BRANCH "', '" OCTO4_BRANCH "' and '" OCTO5_BRANCH "'; commit '" OCTO3_OID "'\n")); @@ -412,7 +421,7 @@ void test_merge_workdir_setup__three_same_branches(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO1_OID "\n" OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO1_BRANCH "' and '" OCTO1_BRANCH "'\n")); @@ -450,7 +459,7 @@ void test_merge_workdir_setup__three_same_oids(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO1_OID "\n" OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge commit '" OCTO1_OID "'; commit '" OCTO1_OID "'; commit '" OCTO1_OID "'\n")); @@ -521,7 +530,7 @@ void test_merge_workdir_setup__remote_tracking_one_branch(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge remote-tracking branch 'refs/remotes/origin/" OCTO1_BRANCH "'\n")); @@ -554,7 +563,7 @@ void test_merge_workdir_setup__remote_tracking_two_branches(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge remote-tracking branches 'refs/remotes/origin/" OCTO1_BRANCH "' and 'refs/remotes/origin/" OCTO2_BRANCH "'\n")); @@ -594,7 +603,7 @@ void test_merge_workdir_setup__remote_tracking_three_branches(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge remote-tracking branches 'refs/remotes/origin/" OCTO1_BRANCH "', 'refs/remotes/origin/" OCTO2_BRANCH "' and 'refs/remotes/origin/" OCTO3_BRANCH "'\n")); @@ -630,7 +639,7 @@ void test_merge_workdir_setup__normal_branch_and_remote_tracking_branch(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "', remote-tracking branch 'refs/remotes/origin/" OCTO2_BRANCH "'\n")); @@ -664,7 +673,7 @@ void test_merge_workdir_setup__remote_tracking_branch_and_normal_branch(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO2_BRANCH "', remote-tracking branch 'refs/remotes/origin/" OCTO1_BRANCH "'\n")); @@ -707,7 +716,7 @@ void test_merge_workdir_setup__two_remote_tracking_branch_and_two_normal_branche cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "', remote-tracking branches 'refs/remotes/origin/" OCTO2_BRANCH "' and 'refs/remotes/origin/" OCTO4_BRANCH "'\n")); @@ -739,7 +748,7 @@ void test_merge_workdir_setup__pull_one(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 1)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch 'octo1' of http://remote.url/repo.git\n")); @@ -767,7 +776,7 @@ void test_merge_workdir_setup__pull_two(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 2)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO2_BRANCH "' of http://remote.url/repo.git\n")); @@ -800,7 +809,7 @@ void test_merge_workdir_setup__pull_three(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "', '" OCTO2_BRANCH "' and '" OCTO3_BRANCH "' of http://remote.url/repo.git\n")); @@ -833,7 +842,7 @@ void test_merge_workdir_setup__three_remotes(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 3)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "' of http://remote.first/repo.git, branch '" OCTO2_BRANCH "' of http://remote.second/repo.git, branch '" OCTO3_BRANCH "' of http://remote.third/repo.git\n")); @@ -870,7 +879,7 @@ void test_merge_workdir_setup__two_remotes(void) cl_git_pass(git_merge__setup(repo, our_head, (const git_annotated_commit **)their_heads, 4)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n" OCTO2_OID "\n" OCTO3_OID "\n" OCTO4_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branches '" OCTO1_BRANCH "' and '" OCTO3_BRANCH "' of http://remote.first/repo.git, branches '" OCTO2_BRANCH "' and '" OCTO4_BRANCH "' of http://remote.second/repo.git\n")); @@ -1008,7 +1017,7 @@ void test_merge_workdir_setup__retained_after_success(void) cl_git_pass(git_merge(repo, (const git_annotated_commit **)&their_heads[0], 1, NULL, NULL)); cl_assert(test_file_contents(GIT_MERGE_HEAD_FILE, OCTO1_OID "\n")); - cl_assert(test_file_contents(GIT_ORIG_HEAD_FILE, ORIG_HEAD "\n")); + cl_assert(test_ref_contents(repo, GIT_ORIG_HEAD_REF, ORIG_HEAD)); cl_assert(test_file_contents(GIT_MERGE_MODE_FILE, "no-ff")); cl_assert(test_file_contents(GIT_MERGE_MSG_FILE, "Merge branch '" OCTO1_BRANCH "'\n")); diff --git a/tests/libgit2/worktree/merge.c b/tests/libgit2/worktree/merge.c index 5b7e2a837c2..65d618d026e 100644 --- a/tests/libgit2/worktree/merge.c +++ b/tests/libgit2/worktree/merge.c @@ -22,11 +22,14 @@ static worktree_fixture fixture = static const char *merge_files[] = { GIT_MERGE_HEAD_FILE, - GIT_ORIG_HEAD_FILE, GIT_MERGE_MODE_FILE, GIT_MERGE_MSG_FILE, }; +static const char *merge_refs[] = { + GIT_ORIG_HEAD_REF, +}; + void test_worktree_merge__initialize(void) { setup_fixture_worktree(&fixture); @@ -76,6 +79,12 @@ void test_worktree_merge__merge_setup(void) cl_assert(git_fs_path_exists(path.ptr)); } + for (i = 0; i < ARRAY_SIZE(merge_refs); i++) { + git_reference *ref; + cl_git_pass(git_reference_lookup(&ref, fixture.worktree, merge_refs[i])); + git_reference_free(ref); + } + git_str_dispose(&path); git_reference_free(ours_ref); git_reference_free(theirs_ref); From 05e3245de3c81394e734305d005ded34169f8168 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 08:27:43 +0200 Subject: [PATCH 2/9] refs: handle REVERT_HEAD via the refdb Fix handling of "REVERT_HEAD" by exclusively reading and writing it via the reference database. --- src/libgit2/refs.h | 2 +- src/libgit2/repository.c | 26 +++++++++++++++++++++++--- src/libgit2/revert.c | 36 +++++++++++++++++------------------- tests/libgit2/repo/state.c | 35 +++++++++++++++++++++-------------- 4 files changed, 62 insertions(+), 37 deletions(-) diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 931ef52f1aa..2bfb51308f4 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -39,11 +39,11 @@ extern bool git_reference__enable_symbolic_ref_target_validation; * reference, as well. */ #define GIT_ORIG_HEAD_REF "ORIG_HEAD" +#define GIT_REVERT_HEAD_REF "REVERT_HEAD" #define GIT_HEAD_FILE "HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD" -#define GIT_REVERT_HEAD_FILE "REVERT_HEAD" #define GIT_CHERRYPICK_HEAD_FILE "CHERRY_PICK_HEAD" #define GIT_BISECT_LOG_FILE "BISECT_LOG" #define GIT_REBASE_MERGE_DIR "rebase-merge/" diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 0cdb4ee6651..0a36ebc6876 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3694,6 +3694,7 @@ int git_repository_state(git_repository *repo) { git_str repo_path = GIT_STR_INIT; int state = GIT_REPOSITORY_STATE_NONE; + git_reference *ref = NULL; GIT_ASSERT_ARG(repo); @@ -3712,7 +3713,7 @@ int git_repository_state(git_repository *repo) state = GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE; else if (git_fs_path_contains_file(&repo_path, GIT_MERGE_HEAD_FILE)) state = GIT_REPOSITORY_STATE_MERGE; - else if (git_fs_path_contains_file(&repo_path, GIT_REVERT_HEAD_FILE)) { + else if (git_reference_lookup(&ref, repo, GIT_REVERT_HEAD_REF) == 0) { state = GIT_REPOSITORY_STATE_REVERT; if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE; @@ -3726,6 +3727,7 @@ int git_repository_state(git_repository *repo) state = GIT_REPOSITORY_STATE_BISECT; git_str_dispose(&repo_path); + git_reference_free(ref); return state; } @@ -3762,7 +3764,6 @@ static const char *state_files[] = { GIT_MERGE_HEAD_FILE, GIT_MERGE_MODE_FILE, GIT_MERGE_MSG_FILE, - GIT_REVERT_HEAD_FILE, GIT_CHERRYPICK_HEAD_FILE, GIT_BISECT_LOG_FILE, GIT_REBASE_MERGE_DIR, @@ -3770,11 +3771,30 @@ static const char *state_files[] = { GIT_SEQUENCER_DIR, }; +static const char *state_refs[] = { + GIT_REVERT_HEAD_REF, +}; + int git_repository_state_cleanup(git_repository *repo) { + int error; + size_t i; + GIT_ASSERT_ARG(repo); - return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); + if ((error = git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files))) < 0) + goto out; + + for (i = 0; i < ARRAY_SIZE(state_refs); i++) { + if ((error = git_reference_remove(repo, state_refs[i])) < 0) { + if (error != GIT_ENOTFOUND) + goto out; + error = 0; + } + } + +out: + return error; } int git_repository__shallow_roots( diff --git a/src/libgit2/revert.c b/src/libgit2/revert.c index 2fb53f8f541..1bf496f9ada 100644 --- a/src/libgit2/revert.c +++ b/src/libgit2/revert.c @@ -22,23 +22,10 @@ static int write_revert_head( git_repository *repo, - const char *commit_oidstr) + const git_oid *commit) { - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - int error = 0; - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_REVERT_HEAD_FILE)) >= 0 && - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_REVERT_FILE_MODE)) >= 0 && - (error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0) - error = git_filebuf_commit(&file); - - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - return error; + return git_reference_create(NULL, repo, GIT_REVERT_HEAD_REF, + commit, 1, NULL); } static int write_merge_msg( @@ -99,9 +86,20 @@ static int revert_normalize_opts( static int revert_state_cleanup(git_repository *repo) { - const char *state_files[] = { GIT_REVERT_HEAD_FILE, GIT_MERGE_MSG_FILE }; + const char *state_files[] = { GIT_MERGE_MSG_FILE }; + int error; - return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); + if ((error = git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files))) < 0) + goto out; + + if ((error = git_reference_remove(repo, GIT_REVERT_HEAD_REF)) < 0) { + if (error != GIT_ENOTFOUND) + goto out; + error = 0; + } + +out: + return error; } static int revert_seterr(git_commit *commit, const char *fmt) @@ -198,7 +196,7 @@ int git_revert( if ((error = git_str_printf(&their_label, "parent of %.7s... %s", commit_id, commit_msg)) < 0 || (error = revert_normalize_opts(repo, &opts, given_opts, git_str_cstr(&their_label))) < 0 || (error = git_indexwriter_init_for_operation(&indexwriter, repo, &opts.checkout_opts.checkout_strategy)) < 0 || - (error = write_revert_head(repo, commit_id)) < 0 || + (error = write_revert_head(repo, git_commit_id(commit))) < 0 || (error = write_merge_msg(repo, commit_id, commit_msg)) < 0 || (error = git_repository_head(&our_ref, repo)) < 0 || (error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJECT_COMMIT)) < 0 || diff --git a/tests/libgit2/repo/state.c b/tests/libgit2/repo/state.c index 92b272dcee9..eb87fffb919 100644 --- a/tests/libgit2/repo/state.c +++ b/tests/libgit2/repo/state.c @@ -17,13 +17,20 @@ void test_repo_state__cleanup(void) git_str_dispose(&_path); } -static void setup_simple_state(const char *filename) +static void setup_simple_state_file(const char *filename) { cl_git_pass(git_str_joinpath(&_path, git_repository_path(_repo), filename)); git_futils_mkpath2file(git_str_cstr(&_path), 0777); cl_git_mkfile(git_str_cstr(&_path), "dummy"); } +static void setup_simple_state_ref(const char *refname) +{ + git_oid oid; + cl_git_pass(git_reference_name_to_id(&oid, _repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_create(NULL, _repo, refname, &oid, 1, NULL)); +} + static void assert_repo_state(git_repository_state_t state) { cl_assert_equal_i(state, git_repository_state(_repo)); @@ -42,7 +49,7 @@ void test_repo_state__none_with_HEAD_detached(void) void test_repo_state__merge(void) { - setup_simple_state(GIT_MERGE_HEAD_FILE); + setup_simple_state_file(GIT_MERGE_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_MERGE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -50,7 +57,7 @@ void test_repo_state__merge(void) void test_repo_state__revert(void) { - setup_simple_state(GIT_REVERT_HEAD_FILE); + setup_simple_state_ref(GIT_REVERT_HEAD_REF); assert_repo_state(GIT_REPOSITORY_STATE_REVERT); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -58,8 +65,8 @@ void test_repo_state__revert(void) void test_repo_state__revert_sequence(void) { - setup_simple_state(GIT_REVERT_HEAD_FILE); - setup_simple_state(GIT_SEQUENCER_TODO_FILE); + setup_simple_state_ref(GIT_REVERT_HEAD_REF); + setup_simple_state_file(GIT_SEQUENCER_TODO_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REVERT_SEQUENCE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -67,7 +74,7 @@ void test_repo_state__revert_sequence(void) void test_repo_state__cherry_pick(void) { - setup_simple_state(GIT_CHERRYPICK_HEAD_FILE); + setup_simple_state_file(GIT_CHERRYPICK_HEAD_FILE); assert_repo_state(GIT_REPOSITORY_STATE_CHERRYPICK); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -75,8 +82,8 @@ void test_repo_state__cherry_pick(void) void test_repo_state__cherrypick_sequence(void) { - setup_simple_state(GIT_CHERRYPICK_HEAD_FILE); - setup_simple_state(GIT_SEQUENCER_TODO_FILE); + setup_simple_state_file(GIT_CHERRYPICK_HEAD_FILE); + setup_simple_state_file(GIT_SEQUENCER_TODO_FILE); assert_repo_state(GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -84,7 +91,7 @@ void test_repo_state__cherrypick_sequence(void) void test_repo_state__bisect(void) { - setup_simple_state(GIT_BISECT_LOG_FILE); + setup_simple_state_file(GIT_BISECT_LOG_FILE); assert_repo_state(GIT_REPOSITORY_STATE_BISECT); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -92,7 +99,7 @@ void test_repo_state__bisect(void) void test_repo_state__rebase_interactive(void) { - setup_simple_state(GIT_REBASE_MERGE_INTERACTIVE_FILE); + setup_simple_state_file(GIT_REBASE_MERGE_INTERACTIVE_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REBASE_INTERACTIVE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -100,7 +107,7 @@ void test_repo_state__rebase_interactive(void) void test_repo_state__rebase_merge(void) { - setup_simple_state(GIT_REBASE_MERGE_DIR "whatever"); + setup_simple_state_file(GIT_REBASE_MERGE_DIR "whatever"); assert_repo_state(GIT_REPOSITORY_STATE_REBASE_MERGE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -108,7 +115,7 @@ void test_repo_state__rebase_merge(void) void test_repo_state__rebase(void) { - setup_simple_state(GIT_REBASE_APPLY_REBASING_FILE); + setup_simple_state_file(GIT_REBASE_APPLY_REBASING_FILE); assert_repo_state(GIT_REPOSITORY_STATE_REBASE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -116,7 +123,7 @@ void test_repo_state__rebase(void) void test_repo_state__apply_mailbox(void) { - setup_simple_state(GIT_REBASE_APPLY_APPLYING_FILE); + setup_simple_state_file(GIT_REBASE_APPLY_APPLYING_FILE); assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -124,7 +131,7 @@ void test_repo_state__apply_mailbox(void) void test_repo_state__apply_mailbox_or_rebase(void) { - setup_simple_state(GIT_REBASE_APPLY_DIR "whatever"); + setup_simple_state_file(GIT_REBASE_APPLY_DIR "whatever"); assert_repo_state(GIT_REPOSITORY_STATE_APPLY_MAILBOX_OR_REBASE); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); From 8ffc7a9933581fb5107d69b914adf07d11cf5a4f Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 08:27:43 +0200 Subject: [PATCH 3/9] refs: handle CHERRY_PICK_HEAD via the refdb Fix handling of "CHERRY_PICK_HEAD" by exclusively reading and writing it via the reference database. --- src/libgit2/cherrypick.c | 36 +++++++++++++++++------------------- src/libgit2/refs.h | 2 +- src/libgit2/repository.c | 4 ++-- tests/libgit2/repo/state.c | 4 ++-- 4 files changed, 22 insertions(+), 24 deletions(-) diff --git a/src/libgit2/cherrypick.c b/src/libgit2/cherrypick.c index 561370169fc..9d85e1d6876 100644 --- a/src/libgit2/cherrypick.c +++ b/src/libgit2/cherrypick.c @@ -23,23 +23,9 @@ static int write_cherrypick_head( git_repository *repo, - const char *commit_oidstr) + const git_oid *commit) { - git_filebuf file = GIT_FILEBUF_INIT; - git_str file_path = GIT_STR_INIT; - int error = 0; - - if ((error = git_str_joinpath(&file_path, repo->gitdir, GIT_CHERRYPICK_HEAD_FILE)) >= 0 && - (error = git_filebuf_open(&file, file_path.ptr, GIT_FILEBUF_CREATE_LEADING_DIRS, GIT_CHERRYPICK_FILE_MODE)) >= 0 && - (error = git_filebuf_printf(&file, "%s\n", commit_oidstr)) >= 0) - error = git_filebuf_commit(&file); - - if (error < 0) - git_filebuf_cleanup(&file); - - git_str_dispose(&file_path); - - return error; + return git_reference_create(NULL, repo, GIT_CHERRYPICK_HEAD_REF, commit, 1, NULL); } static int write_merge_msg( @@ -98,9 +84,21 @@ static int cherrypick_normalize_opts( static int cherrypick_state_cleanup(git_repository *repo) { - const char *state_files[] = { GIT_CHERRYPICK_HEAD_FILE, GIT_MERGE_MSG_FILE }; + const char *state_files[] = { GIT_MERGE_MSG_FILE }; + int error; + + if ((error = git_repository__cleanup_files(repo, state_files, + ARRAY_SIZE(state_files))) < 0) + goto out; - return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files)); + if ((error = git_reference_remove(repo, GIT_CHERRYPICK_HEAD_REF)) < 0) { + if (error != GIT_ENOTFOUND) + goto out; + error = 0; + } + +out: + return error; } static int cherrypick_seterr(git_commit *commit, const char *fmt) @@ -199,7 +197,7 @@ int git_cherrypick( (error = git_str_printf(&their_label, "%.7s... %s", commit_oidstr, commit_summary)) < 0 || (error = cherrypick_normalize_opts(repo, &opts, given_opts, git_str_cstr(&their_label))) < 0 || (error = git_indexwriter_init_for_operation(&indexwriter, repo, &opts.checkout_opts.checkout_strategy)) < 0 || - (error = write_cherrypick_head(repo, commit_oidstr)) < 0 || + (error = write_cherrypick_head(repo, git_commit_id(commit))) < 0 || (error = git_repository_head(&our_ref, repo)) < 0 || (error = git_reference_peel((git_object **)&our_commit, our_ref, GIT_OBJECT_COMMIT)) < 0 || (error = git_cherrypick_commit(&index, repo, commit, our_commit, opts.mainline, &opts.merge_opts)) < 0 || diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 2bfb51308f4..505c49a6eb8 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -40,11 +40,11 @@ extern bool git_reference__enable_symbolic_ref_target_validation; */ #define GIT_ORIG_HEAD_REF "ORIG_HEAD" #define GIT_REVERT_HEAD_REF "REVERT_HEAD" +#define GIT_CHERRYPICK_HEAD_REF "CHERRY_PICK_HEAD" #define GIT_HEAD_FILE "HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD" #define GIT_MERGE_HEAD_FILE "MERGE_HEAD" -#define GIT_CHERRYPICK_HEAD_FILE "CHERRY_PICK_HEAD" #define GIT_BISECT_LOG_FILE "BISECT_LOG" #define GIT_REBASE_MERGE_DIR "rebase-merge/" #define GIT_REBASE_MERGE_INTERACTIVE_FILE GIT_REBASE_MERGE_DIR "interactive" diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 0a36ebc6876..12a909bfc0b 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -3718,7 +3718,7 @@ int git_repository_state(git_repository *repo) if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { state = GIT_REPOSITORY_STATE_REVERT_SEQUENCE; } - } else if (git_fs_path_contains_file(&repo_path, GIT_CHERRYPICK_HEAD_FILE)) { + } else if (git_reference_lookup(&ref, repo, GIT_CHERRYPICK_HEAD_REF) == 0) { state = GIT_REPOSITORY_STATE_CHERRYPICK; if (git_fs_path_contains_file(&repo_path, GIT_SEQUENCER_TODO_FILE)) { state = GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE; @@ -3764,7 +3764,6 @@ static const char *state_files[] = { GIT_MERGE_HEAD_FILE, GIT_MERGE_MODE_FILE, GIT_MERGE_MSG_FILE, - GIT_CHERRYPICK_HEAD_FILE, GIT_BISECT_LOG_FILE, GIT_REBASE_MERGE_DIR, GIT_REBASE_APPLY_DIR, @@ -3773,6 +3772,7 @@ static const char *state_files[] = { static const char *state_refs[] = { GIT_REVERT_HEAD_REF, + GIT_CHERRYPICK_HEAD_REF, }; int git_repository_state_cleanup(git_repository *repo) diff --git a/tests/libgit2/repo/state.c b/tests/libgit2/repo/state.c index eb87fffb919..ce593d4cf09 100644 --- a/tests/libgit2/repo/state.c +++ b/tests/libgit2/repo/state.c @@ -74,7 +74,7 @@ void test_repo_state__revert_sequence(void) void test_repo_state__cherry_pick(void) { - setup_simple_state_file(GIT_CHERRYPICK_HEAD_FILE); + setup_simple_state_ref(GIT_CHERRYPICK_HEAD_REF); assert_repo_state(GIT_REPOSITORY_STATE_CHERRYPICK); cl_git_pass(git_repository_state_cleanup(_repo)); assert_repo_state(GIT_REPOSITORY_STATE_NONE); @@ -82,7 +82,7 @@ void test_repo_state__cherry_pick(void) void test_repo_state__cherrypick_sequence(void) { - setup_simple_state_file(GIT_CHERRYPICK_HEAD_FILE); + setup_simple_state_ref(GIT_CHERRYPICK_HEAD_REF); setup_simple_state_file(GIT_SEQUENCER_TODO_FILE); assert_repo_state(GIT_REPOSITORY_STATE_CHERRYPICK_SEQUENCE); cl_git_pass(git_repository_state_cleanup(_repo)); From e792b62be783807c978426a3f455721613bad394 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 08:27:43 +0200 Subject: [PATCH 4/9] refs: rename GIT_STASH_FILE to indicate this is a ref The GIT_STASH_FILE define contains the path to the stash reference. While we know that this used to be a file with the "files" backend, it's not a standalone file with the "reftable" backend anymore. Rename the macro to GIT_STASH_REF to indicate that this is a proper ref. --- src/libgit2/refs.h | 4 +--- src/libgit2/stash.c | 24 ++++++++++++------------ tests/libgit2/stash/drop.c | 12 ++++++------ 3 files changed, 19 insertions(+), 21 deletions(-) diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 505c49a6eb8..65aabf1ae5b 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -41,6 +41,7 @@ extern bool git_reference__enable_symbolic_ref_target_validation; #define GIT_ORIG_HEAD_REF "ORIG_HEAD" #define GIT_REVERT_HEAD_REF "REVERT_HEAD" #define GIT_CHERRYPICK_HEAD_REF "CHERRY_PICK_HEAD" +#define GIT_STASH_REF GIT_REFS_DIR "stash" #define GIT_HEAD_FILE "HEAD" #define GIT_FETCH_HEAD_FILE "FETCH_HEAD" @@ -57,9 +58,6 @@ extern bool git_reference__enable_symbolic_ref_target_validation; #define GIT_SEQUENCER_OPTIONS_FILE GIT_SEQUENCER_DIR "options" #define GIT_SEQUENCER_TODO_FILE GIT_SEQUENCER_DIR "todo" -#define GIT_STASH_FILE "stash" -#define GIT_REFS_STASH_FILE GIT_REFS_DIR GIT_STASH_FILE - #define GIT_REFERENCE_FORMAT__PRECOMPOSE_UNICODE (1u << 16) #define GIT_REFERENCE_FORMAT__VALIDATION_DISABLE (1u << 15) diff --git a/src/libgit2/stash.c b/src/libgit2/stash.c index 23c82b408fd..3b00ab4851e 100644 --- a/src/libgit2/stash.c +++ b/src/libgit2/stash.c @@ -555,10 +555,10 @@ static int update_reflog( git_reference *stash; int error; - if ((error = git_reference_ensure_log(repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_reference_ensure_log(repo, GIT_STASH_REF)) < 0) return error; - error = git_reference_create(&stash, repo, GIT_REFS_STASH_FILE, w_commit_oid, 1, message); + error = git_reference_create(&stash, repo, GIT_STASH_REF, w_commit_oid, 1, message); git_reference_free(stash); @@ -779,10 +779,10 @@ static int retrieve_stash_commit( size_t max; const git_reflog_entry *entry; - if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_reference_lookup(&stash, repo, GIT_STASH_REF)) < 0) goto cleanup; - if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_reflog_read(&reflog, repo, GIT_STASH_REF)) < 0) goto cleanup; max = git_reflog_entrycount(reflog); @@ -1188,7 +1188,7 @@ int git_stash_foreach( size_t i, max; const git_reflog_entry *entry; - error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE); + error = git_reference_lookup(&stash, repo, GIT_STASH_REF); if (error == GIT_ENOTFOUND) { git_error_clear(); return 0; @@ -1196,7 +1196,7 @@ int git_stash_foreach( if (error < 0) goto cleanup; - if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_reflog_read(&reflog, repo, GIT_STASH_REF)) < 0) goto cleanup; max = git_reflog_entrycount(reflog); @@ -1233,13 +1233,13 @@ int git_stash_drop( if ((error = git_transaction_new(&tx, repo)) < 0) return error; - if ((error = git_transaction_lock_ref(tx, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_transaction_lock_ref(tx, GIT_STASH_REF)) < 0) goto cleanup; - if ((error = git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_reference_lookup(&stash, repo, GIT_STASH_REF)) < 0) goto cleanup; - if ((error = git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_reflog_read(&reflog, repo, GIT_STASH_REF)) < 0) goto cleanup; max = git_reflog_entrycount(reflog); @@ -1253,17 +1253,17 @@ int git_stash_drop( if ((error = git_reflog_drop(reflog, index, true)) < 0) goto cleanup; - if ((error = git_transaction_set_reflog(tx, GIT_REFS_STASH_FILE, reflog)) < 0) + if ((error = git_transaction_set_reflog(tx, GIT_STASH_REF, reflog)) < 0) goto cleanup; if (max == 1) { - if ((error = git_transaction_remove(tx, GIT_REFS_STASH_FILE)) < 0) + if ((error = git_transaction_remove(tx, GIT_STASH_REF)) < 0) goto cleanup; } else if (index == 0) { const git_reflog_entry *entry; entry = git_reflog_entry_byindex(reflog, 0); - if ((error = git_transaction_set_target(tx, GIT_REFS_STASH_FILE, &entry->oid_cur, NULL, NULL)) < 0) + if ((error = git_transaction_set_target(tx, GIT_STASH_REF, &entry->oid_cur, NULL, NULL)) < 0) goto cleanup; } diff --git a/tests/libgit2/stash/drop.c b/tests/libgit2/stash/drop.c index a5714717274..2f9ade67dd6 100644 --- a/tests/libgit2/stash/drop.c +++ b/tests/libgit2/stash/drop.c @@ -100,9 +100,9 @@ void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void) push_three_states(); - cl_git_pass(git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)); + cl_git_pass(git_reference_lookup(&stash, repo, GIT_STASH_REF)); - cl_git_pass(git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)); + cl_git_pass(git_reflog_read(&reflog, repo, GIT_STASH_REF)); entry = git_reflog_entry_byindex(reflog, 1); git_oid_cpy(&oid, git_reflog_entry_id_old(entry)); @@ -112,7 +112,7 @@ void test_stash_drop__dropping_an_entry_rewrites_reflog_history(void) cl_git_pass(git_stash_drop(repo, 1)); - cl_git_pass(git_reflog_read(&reflog, repo, GIT_REFS_STASH_FILE)); + cl_git_pass(git_reflog_read(&reflog, repo, GIT_STASH_REF)); entry = git_reflog_entry_byindex(reflog, 0); cl_assert_equal_oid(&oid, git_reflog_entry_id_old(entry)); @@ -129,7 +129,7 @@ void test_stash_drop__dropping_the_last_entry_removes_the_stash(void) push_three_states(); - cl_git_pass(git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE)); + cl_git_pass(git_reference_lookup(&stash, repo, GIT_STASH_REF)); git_reference_free(stash); cl_git_pass(git_stash_drop(repo, 0)); @@ -137,7 +137,7 @@ void test_stash_drop__dropping_the_last_entry_removes_the_stash(void) cl_git_pass(git_stash_drop(repo, 0)); cl_git_fail_with( - git_reference_lookup(&stash, repo, GIT_REFS_STASH_FILE), GIT_ENOTFOUND); + git_reference_lookup(&stash, repo, GIT_STASH_REF), GIT_ENOTFOUND); } static void retrieve_top_stash_id(git_oid *out) @@ -145,7 +145,7 @@ static void retrieve_top_stash_id(git_oid *out) git_object *top_stash; cl_git_pass(git_revparse_single(&top_stash, repo, "stash@{0}")); - cl_git_pass(git_reference_name_to_id(out, repo, GIT_REFS_STASH_FILE)); + cl_git_pass(git_reference_name_to_id(out, repo, GIT_STASH_REF)); cl_assert_equal_oid(out, git_object_id(top_stash)); From 9e21fba3ea0005e18cfe4b9925c08f252bcf76df Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 10:47:47 +0200 Subject: [PATCH 5/9] refs: introduce GIT_HEAD_REF define Introduce the GIT_HEAD_REF define so that we can clearly indicate that we're talking about the "HEAD" reference and not necessarily a file. Note that there still are a couple of places where GIT_HEAD_FILE is being used: - `git_repository_create_head()`: This function is used to create HEAD when initializing a new repository. This should get fixed eventually so that we create HEAD via the refdb, but this is a more involved refactoring that will be handled in a separate patch series. - `repo_init_head()`: Likewise. - `conditional_match_onbranch()`: This function is used to decide whether or not an `includeIf.onbranch` condition matches. This will be fixed in subsequent commits. Other than that there shouldn't be any more references to GIT_HEAD_FILE. --- src/libgit2/annotated_commit.c | 2 +- src/libgit2/branch.c | 2 +- src/libgit2/clone.c | 4 +-- src/libgit2/describe.c | 2 +- src/libgit2/fetchhead.c | 2 +- src/libgit2/merge.c | 2 +- src/libgit2/rebase.c | 8 ++--- src/libgit2/refdb.c | 4 +-- src/libgit2/refdb_fs.c | 6 ++-- src/libgit2/refs.c | 8 ++--- src/libgit2/refs.h | 1 + src/libgit2/remote.c | 4 +-- src/libgit2/repository.c | 22 ++++++------ src/libgit2/reset.c | 2 +- src/libgit2/revparse.c | 8 ++--- src/libgit2/revwalk.c | 4 +-- src/libgit2/submodule.c | 2 +- src/libgit2/transports/local.c | 4 +-- tests/libgit2/checkout/checkout_helpers.c | 2 +- tests/libgit2/merge/analysis.c | 2 +- tests/libgit2/merge/workdir/simple.c | 4 +-- tests/libgit2/online/clone.c | 8 ++--- tests/libgit2/refs/branches/delete.c | 6 ++-- tests/libgit2/refs/branches/ishead.c | 8 ++--- tests/libgit2/refs/read.c | 8 ++--- tests/libgit2/refs/reflog/messages.c | 44 +++++++++++------------ tests/libgit2/refs/update.c | 4 +-- tests/libgit2/repo/head.c | 2 +- tests/libgit2/repo/repo_helpers.c | 4 +-- tests/libgit2/repo/state.c | 2 +- tests/libgit2/worktree/refs.c | 2 +- 31 files changed, 92 insertions(+), 91 deletions(-) diff --git a/src/libgit2/annotated_commit.c b/src/libgit2/annotated_commit.c index c5c8ace789d..bb619bed31b 100644 --- a/src/libgit2/annotated_commit.c +++ b/src/libgit2/annotated_commit.c @@ -166,7 +166,7 @@ int git_annotated_commit_from_head( *out = NULL; - if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_lookup(&head, repo, GIT_HEAD_REF)) < 0) return -1; error = git_annotated_commit_from_ref(out, repo, head); diff --git a/src/libgit2/branch.c b/src/libgit2/branch.c index 9a31c9c6ffc..5d9ba961f74 100644 --- a/src/libgit2/branch.c +++ b/src/libgit2/branch.c @@ -160,7 +160,7 @@ static int branch_is_checked_out(git_repository *worktree, void *payload) if (git_repository_is_bare(worktree)) return 0; - if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) { + if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_REF)) < 0) { if (error == GIT_ENOTFOUND) error = 0; goto out; diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c index 237efc0ba7d..e4d9c134f1b 100644 --- a/src/libgit2/clone.c +++ b/src/libgit2/clone.c @@ -193,7 +193,7 @@ static int update_remote_head( "%s%s/%s", GIT_REFS_REMOTES_DIR, git_remote_name(remote), - GIT_HEAD_FILE)) < 0) + GIT_HEAD_REF)) < 0) goto cleanup; error = git_reference_symbolic_create( @@ -226,7 +226,7 @@ static int update_head_to_remote( return error; /* We cloned an empty repository or one with an unborn HEAD */ - if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_FILE)) + if (refs_len == 0 || strcmp(refs[0]->name, GIT_HEAD_REF)) return update_head_to_default(repo); /* We know we have HEAD, let's see where it points */ diff --git a/src/libgit2/describe.c b/src/libgit2/describe.c index dfbe7b4ab0b..5f9e483e16f 100644 --- a/src/libgit2/describe.c +++ b/src/libgit2/describe.c @@ -731,7 +731,7 @@ int git_describe_workdir( git_describe_result *result = NULL; git_object *commit; - if ((error = git_reference_name_to_id(¤t_id, repo, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_name_to_id(¤t_id, repo, GIT_HEAD_REF)) < 0) return error; if ((error = git_object_lookup(&commit, repo, ¤t_id, GIT_OBJECT_COMMIT)) < 0) diff --git a/src/libgit2/fetchhead.c b/src/libgit2/fetchhead.c index 08be282a521..0dab1c24303 100644 --- a/src/libgit2/fetchhead.c +++ b/src/libgit2/fetchhead.c @@ -121,7 +121,7 @@ static int fetchhead_ref_write( GIT_REFS_TAGS_DIR) == 0) { type = "tag "; name = fetchhead_ref->ref_name + strlen(GIT_REFS_TAGS_DIR); - } else if (!git__strcmp(fetchhead_ref->ref_name, GIT_HEAD_FILE)) { + } else if (!git__strcmp(fetchhead_ref->ref_name, GIT_HEAD_REF)) { head = 1; } else { type = ""; diff --git a/src/libgit2/merge.c b/src/libgit2/merge.c index eabb4bfa32c..ddf09442f6a 100644 --- a/src/libgit2/merge.c +++ b/src/libgit2/merge.c @@ -3317,7 +3317,7 @@ int git_merge_analysis( git_reference *head_ref = NULL; int error = 0; - if ((error = git_reference_lookup(&head_ref, repo, GIT_HEAD_FILE)) < 0) { + if ((error = git_reference_lookup(&head_ref, repo, GIT_HEAD_REF)) < 0) { git_error_set(GIT_ERROR_MERGE, "failed to lookup HEAD reference"); return error; } diff --git a/src/libgit2/rebase.c b/src/libgit2/rebase.c index eb8a728357c..be3180fba81 100644 --- a/src/libgit2/rebase.c +++ b/src/libgit2/rebase.c @@ -659,7 +659,7 @@ static int rebase_init_merge( &onto_commit, repo, git_annotated_commit_id(onto))) < 0 || (error = git_checkout_tree(repo, (git_object *)onto_commit, &rebase->options.checkout_options)) < 0 || - (error = git_reference_create(&head_ref, repo, GIT_HEAD_FILE, + (error = git_reference_create(&head_ref, repo, GIT_HEAD_REF, git_annotated_commit_id(onto), 1, reflog.ptr)) < 0) goto done; @@ -1191,10 +1191,10 @@ int git_rebase_abort(git_rebase *rebase) return 0; error = rebase->head_detached ? - git_reference_create(&orig_head_ref, rebase->repo, GIT_HEAD_FILE, + git_reference_create(&orig_head_ref, rebase->repo, GIT_HEAD_REF, &rebase->orig_head_id, 1, "rebase: aborting") : git_reference_symbolic_create( - &orig_head_ref, rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, + &orig_head_ref, rebase->repo, GIT_HEAD_REF, rebase->orig_head_name, 1, "rebase: aborting"); if (error < 0) @@ -1379,7 +1379,7 @@ static int return_to_orig_head(git_rebase *rebase) git_commit_id(terminal_commit), 1, &rebase->orig_head_id, branch_msg.ptr)) == 0) error = git_reference_symbolic_create(&head_ref, - rebase->repo, GIT_HEAD_FILE, rebase->orig_head_name, 1, + rebase->repo, GIT_HEAD_REF, rebase->orig_head_name, 1, head_msg.ptr); git_str_dispose(&head_msg); diff --git a/src/libgit2/refdb.c b/src/libgit2/refdb.c index ed33de92bf2..8f922c0cf75 100644 --- a/src/libgit2/refdb.c +++ b/src/libgit2/refdb.c @@ -324,7 +324,7 @@ int git_refdb_should_write_reflog(int *out, git_refdb *db, const git_reference * */ *out = git_refdb_has_log(db, ref->name) || !git__prefixcmp(ref->name, GIT_REFS_HEADS_DIR) || - !git__strcmp(ref->name, GIT_HEAD_FILE) || + !git__strcmp(ref->name, GIT_HEAD_REF) || !git__prefixcmp(ref->name, GIT_REFS_REMOTES_DIR) || !git__prefixcmp(ref->name, GIT_REFS_NOTES_DIR); break; @@ -350,7 +350,7 @@ int git_refdb_should_write_head_reflog(int *out, git_refdb *db, const git_refere goto out; } - if ((error = git_refdb_lookup(&head, db, GIT_HEAD_FILE)) < 0) + if ((error = git_refdb_lookup(&head, db, GIT_HEAD_REF)) < 0) goto out; if (git_reference_type(head) == GIT_REFERENCE_DIRECT) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 1138ebe74d3..145efc1ea43 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -95,7 +95,7 @@ GIT_INLINE(int) reflog_path( const char *base; int error; - base = (strcmp(refname, GIT_HEAD_FILE) == 0) ? repo->gitdir : + base = (strcmp(refname, GIT_HEAD_REF) == 0) ? repo->gitdir : repo->commondir; if ((error = git_str_joinpath(out, base, GIT_REFLOG_DIR)) < 0) @@ -1581,7 +1581,7 @@ static int maybe_append_head(refdb_fs_backend *backend, const git_reference *ref if (git_reference_name_to_id(&old_id, backend->repo, ref->name) < 0) memset(&old_id, 0, sizeof(old_id)); - if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_FILE)) < 0 || + if ((error = git_reference_lookup(&head, backend->repo, GIT_HEAD_REF)) < 0 || (error = reflog_append(backend, head, &old_id, git_reference_target(ref), who, message)) < 0) goto out; @@ -2298,7 +2298,7 @@ static int reflog_append( /* "normal" symbolic updates do not write */ if (is_symbolic && - strcmp(ref->name, GIT_HEAD_FILE) && + strcmp(ref->name, GIT_HEAD_REF) && !(old && new)) return 0; diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index e01278521dc..6ee08bac704 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -264,14 +264,14 @@ int git_reference_dwim(git_reference **out, git_repository *repo, const char *re GIT_REFS_TAGS_DIR "%s", GIT_REFS_HEADS_DIR "%s", GIT_REFS_REMOTES_DIR "%s", - GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_FILE, + GIT_REFS_REMOTES_DIR "%s/" GIT_HEAD_REF, NULL }; if (*refname) git_str_puts(&name, refname); else { - git_str_puts(&name, GIT_HEAD_FILE); + git_str_puts(&name, GIT_HEAD_REF); fallbackmode = false; } @@ -599,7 +599,7 @@ static int refs_update_head(git_repository *worktree, void *_payload) git_reference *head = NULL, *updated = NULL; int error; - if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_lookup(&head, worktree, GIT_HEAD_REF)) < 0) goto out; if (git_reference_type(head) != GIT_REFERENCE_SYMBOLIC || @@ -1403,7 +1403,7 @@ int git_reference__is_unborn_head(bool *unborn, const git_reference *ref, git_re if (error != 0 && error != GIT_ENOTFOUND) return error; - else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_FILE) == 0) + else if (error == GIT_ENOTFOUND && git__strcmp(ref->name, GIT_HEAD_REF) == 0) *unborn = true; else *unborn = false; diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 65aabf1ae5b..5b89a666bbf 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -38,6 +38,7 @@ extern bool git_reference__enable_symbolic_ref_target_validation; * references go through the reference database as usual for any other * reference, as well. */ +#define GIT_HEAD_REF "HEAD" #define GIT_ORIG_HEAD_REF "ORIG_HEAD" #define GIT_REVERT_HEAD_REF "REVERT_HEAD" #define GIT_CHERRYPICK_HEAD_REF "CHERRY_PICK_HEAD" diff --git a/src/libgit2/remote.c b/src/libgit2/remote.c index 0b674c5ef2c..6fe6be19628 100644 --- a/src/libgit2/remote.c +++ b/src/libgit2/remote.c @@ -1554,7 +1554,7 @@ static int git_remote_write_fetchhead(git_remote *remote, git_refspec *spec, git /* Determine what to merge: if refspec was a wildcard, just use HEAD */ if (git_refspec_is_wildcard(spec)) { - if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_FILE)) < 0 || + if ((error = git_reference_lookup(&head_ref, remote->repo, GIT_HEAD_REF)) < 0 || (error = remote_head_for_ref(&merge_remote_ref, remote, spec, update_heads, head_ref)) < 0) goto cleanup; } else { @@ -2912,7 +2912,7 @@ int git_remote__default_branch(git_str *out, git_remote *remote) if ((error = git_remote_ls(&heads, &heads_len, remote)) < 0) goto done; - if (heads_len == 0 || strcmp(heads[0]->name, GIT_HEAD_FILE)) { + if (heads_len == 0 || strcmp(heads[0]->name, GIT_HEAD_REF)) { error = GIT_ENOTFOUND; goto done; } diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c index 12a909bfc0b..32a70e0182b 100644 --- a/src/libgit2/repository.c +++ b/src/libgit2/repository.c @@ -2930,7 +2930,7 @@ int git_repository_head_detached(git_repository *repo) if (git_repository_odb__weakptr(&odb, repo) < 0) return -1; - if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) + if (git_reference_lookup(&ref, repo, GIT_HEAD_REF) < 0) return -1; if (git_reference_type(ref) == GIT_REFERENCE_SYMBOLIC) { @@ -2969,7 +2969,7 @@ int git_repository_head(git_reference **head_out, git_repository *repo) GIT_ASSERT_ARG(head_out); - if ((error = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_lookup(&head, repo, GIT_HEAD_REF)) < 0) return error; if (git_reference_type(head) == GIT_REFERENCE_DIRECT) { @@ -2998,7 +2998,7 @@ int git_repository_head_for_worktree(git_reference **out, git_repository *repo, if ((error = git_worktree_lookup(&worktree, repo, name)) < 0 || (error = git_repository_open_from_worktree(&worktree_repo, worktree)) < 0 || - (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_FILE)) < 0) + (error = git_reference_lookup(&head, worktree_repo, GIT_HEAD_REF)) < 0) goto out; if (git_reference_type(head) != GIT_REFERENCE_DIRECT) { @@ -3146,7 +3146,7 @@ int git_repository_is_empty(git_repository *repo) git_str initialbranch = GIT_STR_INIT; int result = 0; - if ((result = git_reference_lookup(&head, repo, GIT_HEAD_FILE)) < 0 || + if ((result = git_reference_lookup(&head, repo, GIT_HEAD_REF)) < 0 || (result = git_repository_initialbranch(&initialbranch, repo)) < 0) goto done; @@ -3551,7 +3551,7 @@ static int detach(git_repository *repo, const git_oid *id, const char *new) GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(id); - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_REF)) < 0) return error; if ((error = git_object_lookup(&object, repo, id, GIT_OBJECT_ANY)) < 0) @@ -3569,7 +3569,7 @@ static int detach(git_repository *repo, const git_oid *id, const char *new) if ((error = checkout_message(&log_message, current, new)) < 0) goto cleanup; - error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_object_id(peeled), true, git_str_cstr(&log_message)); + error = git_reference_create(&new_head, repo, GIT_HEAD_REF, git_object_id(peeled), true, git_str_cstr(&log_message)); cleanup: git_str_dispose(&log_message); @@ -3591,7 +3591,7 @@ int git_repository_set_head( GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(refname); - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_REF)) < 0) return error; if ((error = checkout_message(&log_message, current, refname)) < 0) @@ -3611,14 +3611,14 @@ int git_repository_set_head( if (!error) { if (git_reference_is_branch(ref)) { - error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, + error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_REF, git_reference_name(ref), true, git_str_cstr(&log_message)); } else { error = detach(repo, git_reference_target(ref), git_reference_is_tag(ref) || git_reference_is_remote(ref) ? refname : NULL); } } else if (git_reference__is_branch(refname)) { - error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_FILE, refname, + error = git_reference_symbolic_create(&new_head, repo, GIT_HEAD_REF, refname, true, git_str_cstr(&log_message)); } @@ -3657,7 +3657,7 @@ int git_repository_detach_head(git_repository *repo) GIT_ASSERT_ARG(repo); - if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_FILE)) < 0) + if ((error = git_reference_lookup(¤t, repo, GIT_HEAD_REF)) < 0) return error; if ((error = git_repository_head(&old_head, repo)) < 0) @@ -3674,7 +3674,7 @@ int git_repository_detach_head(git_repository *repo) if ((error = checkout_message(&log_message, current, idstr)) < 0) goto cleanup; - error = git_reference_create(&new_head, repo, GIT_HEAD_FILE, git_reference_target(old_head), + error = git_reference_create(&new_head, repo, GIT_HEAD_REF, git_reference_target(old_head), 1, git_str_cstr(&log_message)); cleanup: diff --git a/src/libgit2/reset.c b/src/libgit2/reset.c index 605c4afd5e2..49a723c4e34 100644 --- a/src/libgit2/reset.c +++ b/src/libgit2/reset.c @@ -156,7 +156,7 @@ static int reset( } /* move HEAD to the new target */ - if ((error = git_reference__update_terminal(repo, GIT_HEAD_FILE, + if ((error = git_reference__update_terminal(repo, GIT_HEAD_REF, git_object_id(commit), NULL, git_str_cstr(&log_message))) < 0) goto cleanup; diff --git a/src/libgit2/revparse.c b/src/libgit2/revparse.c index 2238ba5269c..e311984988c 100644 --- a/src/libgit2/revparse.c +++ b/src/libgit2/revparse.c @@ -163,10 +163,10 @@ static int retrieve_previously_checked_out_branch_or_revision(git_object **out, if (build_regex(&preg, "checkout: moving from (.*) to .*") < 0) return -1; - if (git_reference_lookup(&ref, repo, GIT_HEAD_FILE) < 0) + if (git_reference_lookup(&ref, repo, GIT_HEAD_REF) < 0) goto cleanup; - if (git_reflog_read(&reflog, repo, GIT_HEAD_FILE) < 0) + if (git_reflog_read(&reflog, repo, GIT_HEAD_REF) < 0) goto cleanup; numentries = git_reflog_entrycount(reflog); @@ -279,8 +279,8 @@ static int retrieve_revobject_from_reflog(git_object **out, git_reference **base * When HEAD@{n} is specified, do not use dwim, which would resolve the * reference (to the current branch that HEAD is pointing to). */ - if (position > 0 && strcmp(identifier, GIT_HEAD_FILE) == 0) - error = git_reference_lookup(&ref, repo, GIT_HEAD_FILE); + if (position > 0 && strcmp(identifier, GIT_HEAD_REF) == 0) + error = git_reference_lookup(&ref, repo, GIT_HEAD_REF); else error = git_reference_dwim(&ref, repo, identifier); diff --git a/src/libgit2/revwalk.c b/src/libgit2/revwalk.c index a793a8e179c..5f798f8ce2b 100644 --- a/src/libgit2/revwalk.c +++ b/src/libgit2/revwalk.c @@ -212,7 +212,7 @@ int git_revwalk_push_head(git_revwalk *walk) GIT_ASSERT_ARG(walk); - return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts); + return git_revwalk__push_ref(walk, GIT_HEAD_REF, &opts); } int git_revwalk_hide_head(git_revwalk *walk) @@ -222,7 +222,7 @@ int git_revwalk_hide_head(git_revwalk *walk) GIT_ASSERT_ARG(walk); opts.uninteresting = 1; - return git_revwalk__push_ref(walk, GIT_HEAD_FILE, &opts); + return git_revwalk__push_ref(walk, GIT_HEAD_REF, &opts); } int git_revwalk_push_ref(git_revwalk *walk, const char *refname) diff --git a/src/libgit2/submodule.c b/src/libgit2/submodule.c index 7444e8c678b..f16c4966545 100644 --- a/src/libgit2/submodule.c +++ b/src/libgit2/submodule.c @@ -1610,7 +1610,7 @@ static int git_submodule__open( sm->flags |= GIT_SUBMODULE_STATUS_IN_WD | GIT_SUBMODULE_STATUS__WD_SCANNED; - if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_FILE)) + if (!git_reference_name_to_id(&sm->wd_oid, *subrepo, GIT_HEAD_REF)) sm->flags |= GIT_SUBMODULE_STATUS__WD_OID_VALID; else git_error_clear(); diff --git a/src/libgit2/transports/local.c b/src/libgit2/transports/local.c index 854390534f2..6a46d9b6314 100644 --- a/src/libgit2/transports/local.c +++ b/src/libgit2/transports/local.c @@ -77,7 +77,7 @@ static int add_ref(transport_local *t, const char *name) error = git_reference_resolve(&resolved, ref); if (error < 0) { git_reference_free(ref); - if (!strcmp(name, GIT_HEAD_FILE) && error == GIT_ENOTFOUND) { + if (!strcmp(name, GIT_HEAD_REF) && error == GIT_ENOTFOUND) { /* This is actually okay. Empty repos often have a HEAD that * points to a nonexistent "refs/heads/master". */ git_error_clear(); @@ -169,7 +169,7 @@ static int store_refs(transport_local *t) git__tsort((void **)ref_names.strings, ref_names.count, &git__strcmp_cb); /* Add HEAD iff direction is fetch */ - if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_FILE) < 0) + if (t->direction == GIT_DIRECTION_FETCH && add_ref(t, GIT_HEAD_REF) < 0) goto on_error; for (i = 0; i < ref_names.count; ++i) { diff --git a/tests/libgit2/checkout/checkout_helpers.c b/tests/libgit2/checkout/checkout_helpers.c index 1e9c21bdc5c..2490a572160 100644 --- a/tests/libgit2/checkout/checkout_helpers.c +++ b/tests/libgit2/checkout/checkout_helpers.c @@ -9,7 +9,7 @@ void assert_on_branch(git_repository *repo, const char *branch) git_reference *head; git_str bname = GIT_STR_INIT; - cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_REF)); cl_assert_(git_reference_type(head) == GIT_REFERENCE_SYMBOLIC, branch); cl_git_pass(git_str_joinpath(&bname, "refs/heads", branch)); diff --git a/tests/libgit2/merge/analysis.c b/tests/libgit2/merge/analysis.c index 8c61303e342..0a20e53f8b5 100644 --- a/tests/libgit2/merge/analysis.c +++ b/tests/libgit2/merge/analysis.c @@ -63,7 +63,7 @@ static void analysis_from_branch( cl_git_pass(git_str_printf(&our_refname, "%s%s", GIT_REFS_HEADS_DIR, our_branchname)); cl_git_pass(git_reference_lookup(&our_ref, repo, git_str_cstr(&our_refname))); } else { - cl_git_pass(git_reference_lookup(&our_ref, repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&our_ref, repo, GIT_HEAD_REF)); } cl_git_pass(git_str_printf(&their_refname, "%s%s", GIT_REFS_HEADS_DIR, their_branchname)); diff --git a/tests/libgit2/merge/workdir/simple.c b/tests/libgit2/merge/workdir/simple.c index c92277d8599..11cc2ebc5f2 100644 --- a/tests/libgit2/merge/workdir/simple.c +++ b/tests/libgit2/merge/workdir/simple.c @@ -664,8 +664,8 @@ void test_merge_workdir_simple__directory_file(void) { 0100644, "f5504f36e6f4eb797a56fc5bac6c6c7f32969bf2", 3, "file-5/new" }, }; - cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_DIR OURS_DIRECTORY_FILE, 1, NULL)); - cl_git_pass(git_reference_name_to_id(&head_commit_id, repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_REF, GIT_REFS_HEADS_DIR OURS_DIRECTORY_FILE, 1, NULL)); + cl_git_pass(git_reference_name_to_id(&head_commit_id, repo, GIT_HEAD_REF)); cl_git_pass(git_commit_lookup(&head_commit, repo, &head_commit_id)); cl_git_pass(git_reset(repo, (git_object *)head_commit, GIT_RESET_HARD, NULL)); diff --git a/tests/libgit2/online/clone.c b/tests/libgit2/online/clone.c index 5c283ec4d01..a19ccabe480 100644 --- a/tests/libgit2/online/clone.c +++ b/tests/libgit2/online/clone.c @@ -219,7 +219,7 @@ void test_online_clone__empty_repository(void) cl_assert_equal_i(true, git_repository_is_empty(g_repo)); cl_assert_equal_i(true, git_repository_head_unborn(g_repo)); - cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_REF)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); @@ -1325,7 +1325,7 @@ void test_online_clone__namespace_bare(void) cl_git_pass(git_clone(&g_repo, _remote_url, "./namespaced.git", &options)); - cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_REF)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); @@ -1344,7 +1344,7 @@ void test_online_clone__namespace_with_specified_branch(void) cl_git_pass(git_clone(&g_repo, _remote_url, "./namespaced", &options)); - cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_REF)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); cl_assert_equal_strn("refs/heads/", git_reference_symbolic_target(head), 11); cl_assert_equal_s(_remote_branch, git_reference_symbolic_target(head) + 11); @@ -1364,7 +1364,7 @@ void test_online_clone__sha256(void) cl_skip(); cl_git_pass(git_clone(&g_repo, _remote_url, "./sha256", &options)); - cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_REF)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); git_reference_free(head); diff --git a/tests/libgit2/refs/branches/delete.c b/tests/libgit2/refs/branches/delete.c index 2c28dd294fa..d01a42fad46 100644 --- a/tests/libgit2/refs/branches/delete.c +++ b/tests/libgit2/refs/branches/delete.c @@ -33,7 +33,7 @@ void test_refs_branches_delete__can_not_delete_a_branch_pointed_at_by_HEAD(void) git_reference *branch; /* Ensure HEAD targets the local master branch */ - cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_REF)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); @@ -47,7 +47,7 @@ void test_refs_branches_delete__can_delete_a_branch_even_if_HEAD_is_missing(void git_reference *head; git_reference *branch; - cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_REF)); git_reference_delete(head); git_reference_free(head); @@ -71,7 +71,7 @@ void test_refs_branches_delete__can_delete_a_branch_pointed_at_by_detached_HEAD( { git_reference *head, *branch; - cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, repo, GIT_HEAD_REF)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); cl_assert_equal_s("refs/heads/master", git_reference_symbolic_target(head)); git_reference_free(head); diff --git a/tests/libgit2/refs/branches/ishead.c b/tests/libgit2/refs/branches/ishead.c index 1df70b78979..d206b7a23c9 100644 --- a/tests/libgit2/refs/branches/ishead.c +++ b/tests/libgit2/refs/branches/ishead.c @@ -62,17 +62,17 @@ void test_refs_branches_ishead__wont_be_fooled_by_a_non_branch(void) /* * $ git init . * Initialized empty Git repository in d:/temp/tempee/.git/ - * + * * $ touch a && git add a * $ git commit -m" boom" * [master (root-commit) b47b758] boom * 0 files changed * create mode 100644 a - * + * * $ echo "ref: refs/heads/master" > .git/refs/heads/linked * $ echo "ref: refs/heads/linked" > .git/refs/heads/super * $ echo "ref: refs/heads/super" > .git/HEAD - * + * * $ git branch * linked -> master * * master @@ -84,7 +84,7 @@ void test_refs_branches_ishead__only_direct_references_are_considered(void) cl_git_pass(git_reference_symbolic_create(&linked, repo, "refs/heads/linked", "refs/heads/master", 0, NULL)); cl_git_pass(git_reference_symbolic_create(&super, repo, "refs/heads/super", "refs/heads/linked", 0, NULL)); - cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/heads/super", 1, NULL)); + cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_REF, "refs/heads/super", 1, NULL)); cl_assert_equal_i(false, git_branch_is_head(linked)); cl_assert_equal_i(false, git_branch_is_head(super)); diff --git a/tests/libgit2/refs/read.c b/tests/libgit2/refs/read.c index 5bfe781e3aa..e5bbe0fe1a2 100644 --- a/tests/libgit2/refs/read.c +++ b/tests/libgit2/refs/read.c @@ -70,10 +70,10 @@ void test_refs_read__symbolic(void) git_object *object; git_oid id; - cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_REF)); cl_assert(git_reference_type(reference) & GIT_REFERENCE_SYMBOLIC); cl_assert(reference_is_packed(reference) == 0); - cl_assert_equal_s(reference->name, GIT_HEAD_FILE); + cl_assert_equal_s(reference->name, GIT_HEAD_REF); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_assert(git_reference_type(resolved_ref) == GIT_REFERENCE_DIRECT); @@ -128,7 +128,7 @@ void test_refs_read__head_then_master(void) cl_git_pass(git_reference_resolve(&comp_base_ref, reference)); git_reference_free(reference); - cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_REF)); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_assert_equal_oid(git_reference_target(comp_base_ref), git_reference_target(resolved_ref)); git_reference_free(reference); @@ -149,7 +149,7 @@ void test_refs_read__master_then_head(void) git_reference *reference, *master_ref, *resolved_ref; cl_git_pass(git_reference_lookup(&master_ref, g_repo, current_head_target)); - cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&reference, g_repo, GIT_HEAD_REF)); cl_git_pass(git_reference_resolve(&resolved_ref, reference)); cl_assert_equal_oid(git_reference_target(master_ref), git_reference_target(resolved_ref)); diff --git a/tests/libgit2/refs/reflog/messages.c b/tests/libgit2/refs/reflog/messages.c index b9a10f9b818..ecf5eb7eb2a 100644 --- a/tests/libgit2/refs/reflog/messages.c +++ b/tests/libgit2/refs/reflog/messages.c @@ -34,23 +34,23 @@ void test_refs_reflog_messages__setting_head_updates_reflog(void) cl_git_pass(git_repository_set_head(g_repo, "refs/tags/test")); /* 1 */ cl_git_pass(git_repository_set_head(g_repo, "refs/remotes/test/master")); /* 0 */ - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 4, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 4, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from master to haacked"); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 3, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 3, NULL, "tags/test^{commit}", "foo@example.com", "checkout: moving from unborn to e90810b8df3e80c413d903f631643c716887138d"); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 2, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 2, "tags/test^{commit}", "refs/heads/haacked", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked"); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 1, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 1, "refs/heads/haacked", "tags/test^{commit}", "foo@example.com", "checkout: moving from haacked to test"); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "tags/test^{commit}", "refs/remotes/test/master", "foo@example.com", "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to test/master"); @@ -58,7 +58,7 @@ void test_refs_reflog_messages__setting_head_updates_reflog(void) cl_git_pass(git_annotated_commit_from_revspec(&annotated, g_repo, "haacked~0")); cl_git_pass(git_repository_set_head_detached_from_annotated(g_repo, annotated)); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, NULL, "refs/heads/haacked", "foo@example.com", "checkout: moving from be3563ae3f795b2b4353bcce3a527ad0a4f7f644 to haacked~0"); @@ -71,12 +71,12 @@ void test_refs_reflog_messages__setting_head_to_same_target_ignores_reflog(void) { size_t nentries, nentries_after; - nentries = reflog_entrycount(g_repo, GIT_HEAD_FILE); + nentries = reflog_entrycount(g_repo, GIT_HEAD_REF); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); - nentries_after = reflog_entrycount(g_repo, GIT_HEAD_FILE); + nentries_after = reflog_entrycount(g_repo, GIT_HEAD_REF); cl_assert_equal_i(nentries + 1, nentries_after); } @@ -89,14 +89,14 @@ void test_refs_reflog_messages__detaching_writes_reflog(void) msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d"; git_oid_from_string(&id, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); cl_git_pass(git_repository_set_head_detached(g_repo, &id)); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "e90810b8df3e80c413d903f631643c716887138d", NULL, msg); msg = "checkout: moving from e90810b8df3e80c413d903f631643c716887138d to haacked"; cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "e90810b8df3e80c413d903f631643c716887138d", "258f0e2a959a364e40ed6603d5d44fbb24765b10", NULL, msg); @@ -111,14 +111,14 @@ void test_refs_reflog_messages__orphan_branch_does_not_count(void) msg = "checkout: moving from master to e90810b8df3e80c413d903f631643c716887138d"; git_oid_from_string(&id, "e90810b8df3e80c413d903f631643c716887138d", GIT_OID_SHA1); cl_git_pass(git_repository_set_head_detached(g_repo, &id)); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "e90810b8df3e80c413d903f631643c716887138d", NULL, msg); /* Switching to an orphan branch does not write to the reflog */ cl_git_pass(git_repository_set_head(g_repo, "refs/heads/orphan")); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "e90810b8df3e80c413d903f631643c716887138d", NULL, msg); @@ -126,7 +126,7 @@ void test_refs_reflog_messages__orphan_branch_does_not_count(void) /* And coming back, we set the source to zero */ msg = "checkout: moving from orphan to haacked"; cl_git_pass(git_repository_set_head(g_repo, "refs/heads/haacked")); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "0000000000000000000000000000000000000000", "258f0e2a959a364e40ed6603d5d44fbb24765b10", NULL, msg); @@ -141,7 +141,7 @@ void test_refs_reflog_messages__branch_birth(void) const char *msg; size_t nentries, nentries_after; - nentries = reflog_entrycount(g_repo, GIT_HEAD_FILE); + nentries = reflog_entrycount(g_repo, GIT_HEAD_REF); cl_git_pass(git_signature_now(&sig, "me", "foo@example.com")); @@ -150,7 +150,7 @@ void test_refs_reflog_messages__branch_birth(void) cl_git_pass(git_repository_set_head(g_repo, "refs/heads/orphan")); - nentries_after = reflog_entrycount(g_repo, GIT_HEAD_FILE); + nentries_after = reflog_entrycount(g_repo, GIT_HEAD_REF); cl_assert_equal_i(nentries, nentries_after); @@ -159,7 +159,7 @@ void test_refs_reflog_messages__branch_birth(void) cl_assert_equal_i(1, reflog_entrycount(g_repo, "refs/heads/orphan")); - nentries_after = reflog_entrycount(g_repo, GIT_HEAD_FILE); + nentries_after = reflog_entrycount(g_repo, GIT_HEAD_REF); cl_assert_equal_i(nentries + 1, nentries_after); @@ -177,7 +177,7 @@ void test_refs_reflog_messages__commit_on_symbolic_ref_updates_head_reflog(void) const char *msg; size_t nentries_head, nentries_master; - nentries_head = reflog_entrycount(g_repo, GIT_HEAD_FILE); + nentries_head = reflog_entrycount(g_repo, GIT_HEAD_REF); cl_git_pass(git_signature_now(&sig, "me", "foo@example.com")); @@ -190,14 +190,14 @@ void test_refs_reflog_messages__commit_on_symbolic_ref_updates_head_reflog(void) cl_git_pass(git_reference_symbolic_create(&ref2, g_repo, "refs/heads/master", "refs/heads/foo", 1, msg)); cl_assert_equal_i(0, reflog_entrycount(g_repo, "refs/heads/foo")); - cl_assert_equal_i(nentries_head, reflog_entrycount(g_repo, GIT_HEAD_FILE)); + cl_assert_equal_i(nentries_head, reflog_entrycount(g_repo, GIT_HEAD_REF)); cl_assert_equal_i(nentries_master, reflog_entrycount(g_repo, "refs/heads/master")); msg = "message 2"; cl_git_pass(git_commit_create(&id, g_repo, "HEAD", sig, sig, NULL, msg, tree, 0, NULL)); cl_assert_equal_i(1, reflog_entrycount(g_repo, "refs/heads/foo")); - cl_assert_equal_i(nentries_head + 1, reflog_entrycount(g_repo, GIT_HEAD_FILE)); + cl_assert_equal_i(nentries_head + 1, reflog_entrycount(g_repo, GIT_HEAD_REF)); cl_assert_equal_i(nentries_master, reflog_entrycount(g_repo, "refs/heads/master")); git_signature_free(sig); @@ -235,7 +235,7 @@ void test_refs_reflog_messages__show_merge_for_merge_commits(void) "Merge commit", tree, 2, (const struct git_commit **) parent_commits)); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, NULL, git_oid_tostr_s(&merge_commit_oid), NULL, "commit (merge): Merge commit"); @@ -400,7 +400,7 @@ void test_refs_reflog_messages__detaching_head_default_message(void) cl_assert_equal_i(false, git_repository_head_detached(g_repo)); cl_git_pass(git_repository_detach_head(g_repo)); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, "checkout: moving from master to a65fedf39aefe402d3bb6e24df4d4f5fe4547750"); @@ -410,7 +410,7 @@ void test_refs_reflog_messages__detaching_head_default_message(void) cl_git_pass(git_reference_symbolic_create(&ref, g_repo, "HEAD", "refs/heads/master", true, "REATTACH")); - cl_reflog_check_entry(g_repo, GIT_HEAD_FILE, 0, + cl_reflog_check_entry(g_repo, GIT_HEAD_REF, 0, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", NULL, "REATTACH"); diff --git a/tests/libgit2/refs/update.c b/tests/libgit2/refs/update.c index 1c5127d9e38..92bca8a5a22 100644 --- a/tests/libgit2/refs/update.c +++ b/tests/libgit2/refs/update.c @@ -18,9 +18,9 @@ void test_refs_update__updating_the_target_of_a_symref_with_an_invalid_name_retu { git_reference *head; - cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, g_repo, GIT_HEAD_REF)); cl_assert_equal_i(GIT_REFERENCE_SYMBOLIC, git_reference_type(head)); git_reference_free(head); - cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(&head, g_repo, GIT_HEAD_FILE, "refs/heads/inv@{id", 1, NULL)); + cl_assert_equal_i(GIT_EINVALIDSPEC, git_reference_symbolic_create(&head, g_repo, GIT_HEAD_REF, "refs/heads/inv@{id", 1, NULL)); } diff --git a/tests/libgit2/repo/head.c b/tests/libgit2/repo/head.c index 7dea91efeb7..6008aca51ef 100644 --- a/tests/libgit2/repo/head.c +++ b/tests/libgit2/repo/head.c @@ -142,7 +142,7 @@ void test_repo_head__detach_head_Fails_if_HEAD_and_point_to_a_non_commitish(void { git_reference *head; - cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, "refs/tags/point_to_blob", 1, NULL)); + cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_REF, "refs/tags/point_to_blob", 1, NULL)); cl_git_fail(git_repository_detach_head(repo)); diff --git a/tests/libgit2/repo/repo_helpers.c b/tests/libgit2/repo/repo_helpers.c index 1efde70a50d..f5c68f579c8 100644 --- a/tests/libgit2/repo/repo_helpers.c +++ b/tests/libgit2/repo/repo_helpers.c @@ -7,7 +7,7 @@ void make_head_unborn(git_repository* repo, const char *target) { git_reference *head; - cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_FILE, target, 1, NULL)); + cl_git_pass(git_reference_symbolic_create(&head, repo, GIT_HEAD_REF, target, 1, NULL)); git_reference_free(head); } @@ -15,7 +15,7 @@ void delete_head(git_repository* repo) { git_str head_path = GIT_STR_INIT; - cl_git_pass(git_str_joinpath(&head_path, git_repository_path(repo), GIT_HEAD_FILE)); + cl_git_pass(git_str_joinpath(&head_path, git_repository_path(repo), GIT_HEAD_REF)); cl_git_pass(p_unlink(git_str_cstr(&head_path))); git_str_dispose(&head_path); diff --git a/tests/libgit2/repo/state.c b/tests/libgit2/repo/state.c index ce593d4cf09..e2cadbc55d6 100644 --- a/tests/libgit2/repo/state.c +++ b/tests/libgit2/repo/state.c @@ -27,7 +27,7 @@ static void setup_simple_state_file(const char *filename) static void setup_simple_state_ref(const char *refname) { git_oid oid; - cl_git_pass(git_reference_name_to_id(&oid, _repo, GIT_HEAD_FILE)); + cl_git_pass(git_reference_name_to_id(&oid, _repo, GIT_HEAD_REF)); cl_git_pass(git_reference_create(NULL, _repo, refname, &oid, 1, NULL)); } diff --git a/tests/libgit2/worktree/refs.c b/tests/libgit2/worktree/refs.c index 51e7b2b9463..bdc0b5279e0 100644 --- a/tests/libgit2/worktree/refs.c +++ b/tests/libgit2/worktree/refs.c @@ -224,7 +224,7 @@ void test_worktree_refs__renaming_reference_updates_worktree_heads(void) "testrepo-worktree", GIT_BRANCH_LOCAL)); cl_git_pass(git_reference_rename(&renamed, branch, "refs/heads/renamed", 0, NULL)); - cl_git_pass(git_reference_lookup(&head, fixture.worktree, GIT_HEAD_FILE)); + cl_git_pass(git_reference_lookup(&head, fixture.worktree, GIT_HEAD_REF)); cl_assert_equal_i(git_reference_type(head), GIT_REFERENCE_SYMBOLIC); cl_assert_equal_s(git_reference_symbolic_target(head), "refs/heads/renamed"); From 8a54e432081ccdc8c95fc0fd87f72c9399565d5c Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 11:43:39 +0200 Subject: [PATCH 6/9] refdb_fs: defer reading the configuration When initializing the "files" refdb we read a couple of values from the Git configuration. Unfortunately, this causes a chicken-and-egg problem when reading configuration with "includeIf.onbranch" conditionals: we need to instantiate the refdb to evaluate the condition, but we need to read the configuration to initialize the refdb. We currently work around the issue by reading the "HEAD" file directly when evaluating the conditional include. But while that works with the "files" backend, any other backends that store "HEAD" anywhere else will break. Prepare for a fix by deferring reading the configuration. We really only need to be able to execute `git_refdb_lookup()`, so all we need to ensure is that we can look up a branch without triggering any config reads. --- src/libgit2/refdb_fs.c | 70 ++++++++++++++++++++++++++---------------- 1 file changed, 44 insertions(+), 26 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 145efc1ea43..133deaf4e5a 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -61,11 +61,8 @@ typedef struct refdb_fs_backend { git_oid_t oid_type; - unsigned int fsync : 1, - sorted : 1; + unsigned int sorted : 1; int peeling_mode; - git_iterator_flag_t iterator_flags; - uint32_t direach_flags; git_sortedcache *refcache; git_map packed_refs_map; git_mutex prlock; /* protect packed_refs_map */ @@ -292,6 +289,43 @@ static int loose_lookup_to_packfile(refdb_fs_backend *backend, const char *name) return error; } +static git_iterator_flag_t refdb_fs_get_iterator_flags(refdb_fs_backend *backend) +{ + git_iterator_flag_t flags = GIT_ITERATOR_DESCEND_SYMLINKS; + int t; + + if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_IGNORECASE) && t) + flags |= GIT_ITERATOR_IGNORE_CASE; + if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_PRECOMPOSE) && t) + flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE; + + return flags; +} + +static uint32_t refdb_fs_get_direach_flags(refdb_fs_backend *backend) +{ + uint32_t flags = 0; + int t; + + if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_IGNORECASE) && t) + flags |= GIT_FS_PATH_DIR_IGNORE_CASE; + if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_PRECOMPOSE) && t) + flags |= GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE; + + return flags; +} + +static bool refdb_fs_should_fsync(refdb_fs_backend *backend) +{ + int t; + + if ((!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) || + git_repository__fsync_gitdir) + return true; + + return false; +} + static int _dirent_loose_load(void *payload, git_str *full_path) { refdb_fs_backend *backend = payload; @@ -302,7 +336,7 @@ static int _dirent_loose_load(void *payload, git_str *full_path) if (git_fs_path_isdir(full_path->ptr)) { int error = git_fs_path_direach( - full_path, backend->direach_flags, _dirent_loose_load, backend); + full_path, refdb_fs_get_direach_flags(backend), _dirent_loose_load, backend); /* Race with the filesystem, ignore it */ if (error == GIT_ENOTFOUND) { git_error_clear(); @@ -337,7 +371,7 @@ static int packed_loadloose(refdb_fs_backend *backend) * updated loose versions */ error = git_fs_path_direach( - &refs_path, backend->direach_flags, _dirent_loose_load, backend); + &refs_path, refdb_fs_get_direach_flags(backend), _dirent_loose_load, backend); git_str_dispose(&refs_path); @@ -862,13 +896,11 @@ static int iter_load_paths( const git_index_entry *entry; int error = 0; - fsit_opts.flags = ctx->backend->iterator_flags; - git_str_clear(&ctx->path); git_str_puts(&ctx->path, root_path); git_str_put(&ctx->path, ctx->ref_prefix, ctx->ref_prefix_len); - fsit_opts.flags = ctx->backend->iterator_flags; + fsit_opts.flags = refdb_fs_get_iterator_flags(ctx->backend); fsit_opts.oid_type = ctx->backend->oid_type; if ((error = git_iterator_for_filesystem(&fsit, ctx->path.ptr, &fsit_opts)) < 0) { @@ -1173,7 +1205,7 @@ static int loose_lock(git_filebuf *file, refdb_fs_backend *backend, const char * return error; filebuf_flags = GIT_FILEBUF_CREATE_LEADING_DIRS; - if (backend->fsync) + if (refdb_fs_should_fsync(backend)) filebuf_flags |= GIT_FILEBUF_FSYNC; error = git_filebuf_open(file, ref_path.ptr, filebuf_flags, GIT_REFS_FILE_MODE); @@ -1429,7 +1461,7 @@ static int packed_write(refdb_fs_backend *backend) if ((error = git_sortedcache_wlock(refcache)) < 0) return error; - if (backend->fsync) + if (refdb_fs_should_fsync(backend)) open_flags = GIT_FILEBUF_FSYNC; /* Open the file! */ @@ -2362,7 +2394,7 @@ static int reflog_append( open_flags = O_WRONLY | O_CREAT | O_APPEND; - if (backend->fsync) + if (refdb_fs_should_fsync(backend)) open_flags |= O_FSYNC; error = git_futils_writebuffer(&buf, git_str_cstr(&path), open_flags, GIT_REFLOG_FILE_MODE); @@ -2492,7 +2524,6 @@ int git_refdb_backend_fs( git_refdb_backend **backend_out, git_repository *repository) { - int t = 0; git_str gitpath = GIT_STR_INIT; refdb_fs_backend *backend; @@ -2532,19 +2563,6 @@ int git_refdb_backend_fs( git_str_dispose(&gitpath); - if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_IGNORECASE) && t) { - backend->iterator_flags |= GIT_ITERATOR_IGNORE_CASE; - backend->direach_flags |= GIT_FS_PATH_DIR_IGNORE_CASE; - } - if (!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_PRECOMPOSE) && t) { - backend->iterator_flags |= GIT_ITERATOR_PRECOMPOSE_UNICODE; - backend->direach_flags |= GIT_FS_PATH_DIR_PRECOMPOSE_UNICODE; - } - if ((!git_repository__configmap_lookup(&t, backend->repo, GIT_CONFIGMAP_FSYNCOBJECTFILES) && t) || - git_repository__fsync_gitdir) - backend->fsync = 1; - backend->iterator_flags |= GIT_ITERATOR_DESCEND_SYMLINKS; - backend->parent.exists = &refdb_fs_backend__exists; backend->parent.lookup = &refdb_fs_backend__lookup; backend->parent.iterator = &refdb_fs_backend__iterator; From 7700fbfe271a91e4c7fd11574b570807624664a5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 11:57:24 +0200 Subject: [PATCH 7/9] config_file: use the refdb to evaluate "onbranch" condition With the preceding commit we have refactored the "files" backend so that it can be both instantiated and used to look up a reference without reading any configuration. With this change in place we don't cause infinite recursion anymore when using the refdb to evaluate "onbranch" conditions. Refactor the code to use the refdb to look up "HEAD". Note that we cannot use `git_reference_lookup()` here, as that function itself tries to normalize reference names, which in turn involves reading the Git configuration. So instead, we use the lower-level `git_refdb_lookup()` function, as we don't need the normalization anyway. --- src/libgit2/config_file.c | 27 +++++++++++++++++++-------- 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/src/libgit2/config_file.c b/src/libgit2/config_file.c index 510f6fd0b77..74106c134bf 100644 --- a/src/libgit2/config_file.c +++ b/src/libgit2/config_file.c @@ -16,6 +16,7 @@ #include "config_list.h" #include "config_parse.h" #include "filebuf.h" +#include "refdb.h" #include "regexp.h" #include "sysdir.h" #include "wildmatch.h" @@ -665,27 +666,34 @@ static int conditional_match_onbranch( const char *condition) { git_str reference = GIT_STR_INIT, buf = GIT_STR_INIT; + git_reference *ref = NULL; + git_refdb *refdb = NULL; int error; GIT_UNUSED(cfg_file); /* - * NOTE: you cannot use `git_repository_head` here. Looking up the - * HEAD reference will create the ODB, which causes us to read the + * NOTE: we cannot use higher-level functions like + * `git_repository_head` here, as these will cause us to read the * repo's config for keys like core.precomposeUnicode. As we're * just parsing the config right now, though, this would result in * an endless recursion. + * + * Instead, we use lower-level functionality to do so and use the refdb + * directly. This requires that the refdb does not perform any config + * lookups when initializing or when reading a single ref. */ - - if ((error = git_str_joinpath(&buf, git_repository_path(repo), GIT_HEAD_FILE)) < 0 || - (error = git_futils_readbuffer(&reference, buf.ptr)) < 0) + if ((error = git_repository_refdb(&refdb, (git_repository *) repo)) < 0 || + (error = git_refdb_lookup(&ref, refdb, GIT_HEAD_REF)) < 0) goto out; - git_str_rtrim(&reference); - if (git__strncmp(reference.ptr, GIT_SYMREF, strlen(GIT_SYMREF))) + if (git_reference_type(ref) != GIT_REFERENCE_SYMBOLIC) { + *matches = 0; goto out; - git_str_consume(&reference, reference.ptr + strlen(GIT_SYMREF)); + } + if ((error = git_str_sets(&reference, git_reference_symbolic_target(ref))) < 0) + goto out; if (git__strncmp(reference.ptr, GIT_REFS_HEADS_DIR, strlen(GIT_REFS_HEADS_DIR))) goto out; git_str_consume(&reference, reference.ptr + strlen(GIT_REFS_HEADS_DIR)); @@ -701,9 +709,12 @@ static int conditional_match_onbranch( goto out; *matches = wildmatch(buf.ptr, reference.ptr, WM_PATHNAME) == WM_MATCH; + out: git_str_dispose(&reference); git_str_dispose(&buf); + git_reference_free(ref); + git_refdb_free(refdb); return error; From a4a0d87b2caf37098437b2550bc20f1cdd3fca04 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 12:40:01 +0200 Subject: [PATCH 8/9] refdb_fs: expose function to read a loose ref Expose a function to read a loose reference. This function will be used in a subsequent commit to read pseudo-refs on the generic refdb layer. --- src/libgit2/refdb_fs.c | 43 ++++++++++++++++++++++++++---------------- src/libgit2/refs.h | 6 ++++++ 2 files changed, 33 insertions(+), 16 deletions(-) diff --git a/src/libgit2/refdb_fs.c b/src/libgit2/refdb_fs.c index 133deaf4e5a..e0a27dc9b23 100644 --- a/src/libgit2/refdb_fs.c +++ b/src/libgit2/refdb_fs.c @@ -448,46 +448,57 @@ static bool is_per_worktree_ref(const char *ref_name) git__prefixcmp(ref_name, "refs/rewritten/") == 0; } -static int loose_lookup( +int git_reference__lookup_loose( git_reference **out, - refdb_fs_backend *backend, - const char *ref_name) + const char *ref_dir, + const char *ref_name, + git_oid_t oid_type) { - git_str ref_file = GIT_STR_INIT; + git_str buf = GIT_STR_INIT; int error = 0; - const char *ref_dir; if (out) *out = NULL; - if (is_per_worktree_ref(ref_name)) - ref_dir = backend->gitpath; - else - ref_dir = backend->commonpath; - - if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0) + if ((error = git_str_joinpath(&buf, ref_dir, ref_name)) < 0 || + (error = git_futils_readbuffer(&buf, buf.ptr)) < 0) /* cannot read loose ref file - gah */; - else if (git__prefixcmp(git_str_cstr(&ref_file), GIT_SYMREF) == 0) { + else if (git__prefixcmp(git_str_cstr(&buf), GIT_SYMREF) == 0) { const char *target; - git_str_rtrim(&ref_file); + git_str_rtrim(&buf); - if (!(target = loose_parse_symbolic(&ref_file))) + if (!(target = loose_parse_symbolic(&buf))) error = -1; else if (out != NULL) *out = git_reference__alloc_symbolic(ref_name, target); } else { git_oid oid; - if (!(error = loose_parse_oid(&oid, ref_name, &ref_file, backend->oid_type)) && + if (!(error = loose_parse_oid(&oid, ref_name, &buf, oid_type)) && out != NULL) *out = git_reference__alloc(ref_name, &oid, NULL); } - git_str_dispose(&ref_file); + git_str_dispose(&buf); return error; } +static int loose_lookup( + git_reference **out, + refdb_fs_backend *backend, + const char *ref_name) +{ + const char *ref_dir; + + if (is_per_worktree_ref(ref_name)) + ref_dir = backend->gitpath; + else + ref_dir = backend->commonpath; + + return git_reference__lookup_loose(out, ref_dir, ref_name, backend->oid_type); +} + static int ref_error_notfound(const char *name) { git_error_set(GIT_ERROR_REFERENCE, "reference '%s' not found", name); diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 5b89a666bbf..0e31d9122ed 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -128,6 +128,12 @@ int git_reference_lookup_resolved( int git_reference__log_signature(git_signature **out, git_repository *repo); +int git_reference__lookup_loose( + git_reference **out, + const char *ref_dir, + const char *ref_name, + git_oid_t oid_type); + /** Update a reference after a commit. */ int git_reference__update_for_commit( git_repository *repo, From e5a72105a4f9a7937148faa885570aa8c09b64c5 Mon Sep 17 00:00:00 2001 From: Patrick Steinhardt Date: Mon, 14 Jul 2025 12:43:58 +0200 Subject: [PATCH 9/9] refs: always read pseudorefs as loose refs Regardless of which reference storage format is used, pseudorefs will always be looked up via the filesystem as loose refs. This is because pseudorefs do not strictly follow the reference format and may contain additional metadata that is not present in a normal reference. We don't honor this in `git_reference_lookup()` though but instead defer to the refdb to read such references. This obviously works just fine with the "files" backend, but any other backend would have to grow custom logic to handle reading pseudorefs. Refactor `git_reference_lookup_resolved()` so that it knows to always read pseudorefs as loose references. This allows refdb implementations to not care about pseudoref handling at all. --- src/libgit2/refs.c | 23 +++++++++++++++++++++++ src/libgit2/refs.h | 1 + 2 files changed, 24 insertions(+) diff --git a/src/libgit2/refs.c b/src/libgit2/refs.c index 6ee08bac704..3c8f2aeb576 100644 --- a/src/libgit2/refs.c +++ b/src/libgit2/refs.c @@ -231,6 +231,14 @@ int git_reference_lookup_resolved( GIT_ASSERT_ARG(repo); GIT_ASSERT_ARG(name); + /* + * Pseudorefs are not stored in the reference backend, as they may + * contain additional data that doesn't even follow the normal ref + * format. So we look these up as "loose" refs directly. + */ + if (git_reference__is_pseudoref(name)) + return git_reference__lookup_loose(ref_out, repo->gitdir, name, repo->oid_type); + if ((error = reference_normalize_for_repo(normalized, repo, name, true)) < 0 || (error = git_repository_refdb__weakptr(&refdb, repo)) < 0 || (error = git_refdb_resolve(ref_out, refdb, normalized, max_nesting)) < 0) @@ -1278,6 +1286,21 @@ int git_reference_is_note(const git_reference *ref) return git_reference__is_note(ref->name); } +int git_reference__is_pseudoref(const char *ref_name) +{ + const char * const pseudorefs[] = { + "MERGE_HEAD", + "FETCH_HEAD", + }; + size_t i; + + for (i = 0; i < ARRAY_SIZE(pseudorefs); i++) + if (git__strcmp(ref_name, pseudorefs[i]) == 0) + return 1; + + return 0; +} + static int peel_error(int error, const git_reference *ref, const char *msg) { git_error_set( diff --git a/src/libgit2/refs.h b/src/libgit2/refs.h index 0e31d9122ed..b3729ade708 100644 --- a/src/libgit2/refs.h +++ b/src/libgit2/refs.h @@ -95,6 +95,7 @@ int git_reference__is_branch(const char *ref_name); int git_reference__is_remote(const char *ref_name); int git_reference__is_tag(const char *ref_name); int git_reference__is_note(const char *ref_name); +int git_reference__is_pseudoref(const char *ref_name); const char *git_reference__shorthand(const char *name); /*