Skip to content

Commit e0a6c28

Browse files
committed
refdb: introduce commondir awareness
The refdb_fs_backend is not aware of the git commondir, which stores common objects like the o bject database and packed/loose refereensces when worktrees are used. Make refdb_fs_backend aware of the common directory by introducing a new commonpath variable that points to the actual common path of the database and using it instead of the gitdir for the mentioned objects.
1 parent 71dd086 commit e0a6c28

File tree

2 files changed

+96
-6
lines changed

2 files changed

+96
-6
lines changed

src/refdb_fs.c

Lines changed: 28 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -57,6 +57,8 @@ typedef struct refdb_fs_backend {
5757
git_repository *repo;
5858
/* path to git directory */
5959
char *gitpath;
60+
/* path to common objects' directory */
61+
char *commonpath;
6062

6163
git_sortedcache *refcache;
6264
int peeling_mode;
@@ -363,18 +365,32 @@ static const char *loose_parse_symbolic(git_buf *file_content)
363365
return refname_start;
364366
}
365367

368+
static bool is_per_worktree_ref(const char *ref_name)
369+
{
370+
return strcmp("HEAD", ref_name) == 0 ||
371+
strcmp("FETCH_HEAD", ref_name) == 0 ||
372+
strcmp("MERGE_HEAD", ref_name) == 0 ||
373+
strcmp("ORIG_HEAD", ref_name) == 0;
374+
}
375+
366376
static int loose_lookup(
367377
git_reference **out,
368378
refdb_fs_backend *backend,
369379
const char *ref_name)
370380
{
371381
git_buf ref_file = GIT_BUF_INIT;
372382
int error = 0;
383+
const char *ref_dir;
373384

374385
if (out)
375386
*out = NULL;
376387

377-
if ((error = loose_readbuffer(&ref_file, backend->gitpath, ref_name)) < 0)
388+
if (is_per_worktree_ref(ref_name))
389+
ref_dir = backend->gitpath;
390+
else
391+
ref_dir = backend->commonpath;
392+
393+
if ((error = loose_readbuffer(&ref_file, ref_dir, ref_name)) < 0)
378394
/* cannot read loose ref file - gah */;
379395
else if (git__prefixcmp(git_buf_cstr(&ref_file), GIT_SYMREF) == 0) {
380396
const char *target;
@@ -485,12 +501,12 @@ static int iter_load_loose_paths(refdb_fs_backend *backend, refdb_fs_iter *iter)
485501
git_iterator_options fsit_opts = GIT_ITERATOR_OPTIONS_INIT;
486502
const git_index_entry *entry = NULL;
487503

488-
if (!backend->gitpath) /* do nothing if no gitpath for loose refs */
504+
if (!backend->commonpath) /* do nothing if no commonpath for loose refs */
489505
return 0;
490506

491507
fsit_opts.flags = backend->iterator_flags;
492508

493-
if ((error = git_buf_printf(&path, "%s/refs", backend->gitpath)) < 0 ||
509+
if ((error = git_buf_printf(&path, "%s/refs", backend->commonpath)) < 0 ||
494510
(error = git_iterator_for_filesystem(&fsit, path.ptr, &fsit_opts)) < 0) {
495511
git_buf_free(&path);
496512
return error;
@@ -1410,6 +1426,7 @@ static void refdb_fs_backend__free(git_refdb_backend *_backend)
14101426

14111427
git_sortedcache_free(backend->refcache);
14121428
git__free(backend->gitpath);
1429+
git__free(backend->commonpath);
14131430
git__free(backend);
14141431
}
14151432

@@ -1420,6 +1437,8 @@ static int setup_namespace(git_buf *gitpath, git_repository *repo)
14201437
/* Not all repositories have a gitpath */
14211438
if (repo->path_repository == NULL)
14221439
return 0;
1440+
if (repo->commondir == NULL)
1441+
return 0;
14231442

14241443
/* Load the path to the repo first */
14251444
git_buf_puts(gitpath, repo->path_repository);
@@ -1446,7 +1465,7 @@ static int setup_namespace(git_buf *gitpath, git_repository *repo)
14461465
git__free(parts);
14471466

14481467
/* Make sure that the folder with the namespace exists */
1449-
if (git_futils_mkdir_relative(git_buf_cstr(gitpath), repo->path_repository,
1468+
if (git_futils_mkdir_relative(git_buf_cstr(gitpath), repo->commondir,
14501469
0777, GIT_MKDIR_PATH, NULL) < 0)
14511470
return -1;
14521471

@@ -1960,9 +1979,11 @@ int git_refdb_backend_fs(
19601979
if (setup_namespace(&gitpath, repository) < 0)
19611980
goto fail;
19621981

1963-
backend->gitpath = git_buf_detach(&gitpath);
1982+
backend->gitpath = backend->commonpath = git_buf_detach(&gitpath);
1983+
if (repository->commondir)
1984+
backend->commonpath = git__strdup(repository->commondir);
19641985

1965-
if (git_buf_joinpath(&gitpath, backend->gitpath, GIT_PACKEDREFS_FILE) < 0 ||
1986+
if (git_buf_joinpath(&gitpath, backend->commonpath, GIT_PACKEDREFS_FILE) < 0 ||
19661987
git_sortedcache_new(
19671988
&backend->refcache, offsetof(struct packref, name),
19681989
NULL, NULL, packref_cmp, git_buf_cstr(&gitpath)) < 0)
@@ -2002,6 +2023,7 @@ int git_refdb_backend_fs(
20022023
fail:
20032024
git_buf_free(&gitpath);
20042025
git__free(backend->gitpath);
2026+
git__free(backend->commonpath);
20052027
git__free(backend);
20062028
return -1;
20072029
}

tests/worktree/refs.c

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
#include "clar_libgit2.h"
2+
#include "worktree_helpers.h"
3+
4+
#define COMMON_REPO "testrepo"
5+
#define WORKTREE_REPO "testrepo-worktree"
6+
7+
static worktree_fixture fixture =
8+
WORKTREE_FIXTURE_INIT(COMMON_REPO, WORKTREE_REPO);
9+
10+
void test_worktree_refs__initialize(void)
11+
{
12+
setup_fixture_worktree(&fixture);
13+
}
14+
15+
void test_worktree_refs__cleanup(void)
16+
{
17+
cleanup_fixture_worktree(&fixture);
18+
}
19+
20+
void test_worktree_refs__list(void)
21+
{
22+
git_strarray refs, wtrefs;
23+
unsigned i, j;
24+
int error = 0;
25+
26+
cl_git_pass(git_reference_list(&refs, fixture.repo));
27+
cl_git_pass(git_reference_list(&wtrefs, fixture.worktree));
28+
29+
if (refs.count != wtrefs.count)
30+
{
31+
error = GIT_ERROR;
32+
goto exit;
33+
}
34+
35+
for (i = 0; i < refs.count; i++)
36+
{
37+
int found = 0;
38+
39+
for (j = 0; j < wtrefs.count; j++)
40+
{
41+
if (!strcmp(refs.strings[i], wtrefs.strings[j]))
42+
{
43+
found = 1;
44+
break;
45+
}
46+
}
47+
48+
if (!found)
49+
{
50+
error = GIT_ERROR;
51+
goto exit;
52+
}
53+
}
54+
55+
exit:
56+
git_strarray_free(&refs);
57+
git_strarray_free(&wtrefs);
58+
cl_git_pass(error);
59+
}
60+
61+
void test_worktree_refs__read_head(void)
62+
{
63+
git_reference *head;
64+
65+
cl_git_pass(git_repository_head(&head, fixture.worktree));
66+
67+
git_reference_free(head);
68+
}

0 commit comments

Comments
 (0)