refs: extract out refs_create_refdir_stubs()

For Git to recognize a directory as a Git directory, it requires the
directory to contain:

  1. 'HEAD' file
  2. 'objects/' directory
  3. 'refs/' directory

Here, #1 and #3 are part of the reference storage mechanism,
specifically the files backend. Since then, newer backends such as the
reftable backend have moved to using their own path ('reftable/') for
storing references. But to ensure Git still recognizes the directory as
a Git directory, we create stubs.

There are two locations where we create stubs:

- In 'refs/reftable-backend.c' when creating the reftable backend.
- In 'clone.c' before spawning transport helpers.

In a following commit, we'll add another instance. So instead of
repeating the code, let's extract out this code to
`refs_create_refdir_stubs()` and use it.

Signed-off-by: Karthik Nayak <karthik.188@gmail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Karthik Nayak
2026-02-25 10:40:42 +01:00
committed by Junio C Hamano
parent 2c69ff4819
commit 4ffbb02ee4
4 changed files with 39 additions and 18 deletions

View File

@@ -1225,12 +1225,7 @@ int cmd_clone(int argc,
initialize_repository_version(GIT_HASH_UNKNOWN,
the_repository->ref_storage_format, 1);
strbuf_addf(&buf, "%s/HEAD", git_dir);
write_file(buf.buf, "ref: refs/heads/.invalid");
strbuf_reset(&buf);
strbuf_addf(&buf, "%s/refs", git_dir);
safe_create_dir(the_repository, buf.buf, 1);
refs_create_refdir_stubs(the_repository, git_dir, NULL);
/*
* additional config can be injected with -c, make sure it's included

23
refs.c
View File

@@ -2163,6 +2163,29 @@ const char *refs_resolve_ref_unsafe(struct ref_store *refs,
return NULL;
}
void refs_create_refdir_stubs(struct repository *repo, const char *refdir,
const char *refs_heads_content)
{
struct strbuf path = STRBUF_INIT;
strbuf_addf(&path, "%s/HEAD", refdir);
write_file(path.buf, "ref: refs/heads/.invalid");
adjust_shared_perm(repo, path.buf);
strbuf_reset(&path);
strbuf_addf(&path, "%s/refs", refdir);
safe_create_dir(repo, path.buf, 1);
if (refs_heads_content) {
strbuf_reset(&path);
strbuf_addf(&path, "%s/refs/heads", refdir);
write_file(path.buf, "%s", refs_heads_content);
adjust_shared_perm(repo, path.buf);
}
strbuf_release(&path);
}
/* backend functions */
int ref_store_create_on_disk(struct ref_store *refs, int flags, struct strbuf *err)
{

13
refs.h
View File

@@ -1427,4 +1427,17 @@ void ref_iterator_free(struct ref_iterator *ref_iterator);
int do_for_each_ref_iterator(struct ref_iterator *iter,
each_ref_fn fn, void *cb_data);
/*
* Git only recognizes a directory as a repository if it contains:
* - HEAD file
* - refs/ folder
* While it is necessary within the files backend, newer backends may not
* follow the same structure. To go around this, we create stubs as necessary.
*
* If provided with a 'refs_heads_content', we create the 'refs/heads/head' file
* with the provided message.
*/
void refs_create_refdir_stubs(struct repository *repo, const char *refdir,
const char *refs_heads_content);
#endif /* REFS_H */

View File

@@ -491,18 +491,8 @@ static int reftable_be_create_on_disk(struct ref_store *ref_store,
safe_create_dir(the_repository, sb.buf, 1);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/HEAD", refs->base.gitdir);
write_file(sb.buf, "ref: refs/heads/.invalid");
adjust_shared_perm(the_repository, sb.buf);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/refs", refs->base.gitdir);
safe_create_dir(the_repository, sb.buf, 1);
strbuf_reset(&sb);
strbuf_addf(&sb, "%s/refs/heads", refs->base.gitdir);
write_file(sb.buf, "this repository uses the reftable format");
adjust_shared_perm(the_repository, sb.buf);
refs_create_refdir_stubs(the_repository, refs->base.gitdir,
"this repository uses the reftable format");
strbuf_release(&sb);
return 0;