From 17cbd2eae04807d12b49a73b60f2855b65c9d8ab Mon Sep 17 00:00:00 2001 From: Mike Frysinger Date: Wed, 15 Jan 2025 21:00:06 -0500 Subject: [PATCH] alternates: allow relative paths in all repositories Git does not limit relative paths in alternates to the first repository, so libgit2 shouldn't either. --- src/libgit2/odb.c | 8 ++------ tests/libgit2/odb/alternates.c | 36 ++++++++++++++++++++++++++++++++++ 2 files changed, 38 insertions(+), 6 deletions(-) diff --git a/src/libgit2/odb.c b/src/libgit2/odb.c index 6ed072b35..e58f3c942 100644 --- a/src/libgit2/odb.c +++ b/src/libgit2/odb.c @@ -788,12 +788,8 @@ static int load_alternates(git_odb *odb, const char *objects_dir, int alternate_ if (*alternate == '\0' || *alternate == '#') continue; - /* - * Relative path: build based on the current `objects` - * folder. However, relative paths are only allowed in - * the current repository. - */ - if (*alternate == '.' && !alternate_depth) { + /* Relative path: build based on the current `objects` folder. */ + if (*alternate == '.') { if ((result = git_str_joinpath(&alternates_path, objects_dir, alternate)) < 0) break; alternate = git_str_cstr(&alternates_path); diff --git a/tests/libgit2/odb/alternates.c b/tests/libgit2/odb/alternates.c index aeadcc9d2..21dcaa857 100644 --- a/tests/libgit2/odb/alternates.c +++ b/tests/libgit2/odb/alternates.c @@ -78,3 +78,39 @@ void test_odb_alternates__long_chain(void) cl_git_fail(git_commit_lookup(&commit, repo, &oid)); git_repository_free(repo); } + +void test_odb_alternates__relative(void) +{ + git_commit *commit; + git_oid oid; + + /* Set the alternate A -> testrepo.git */ + init_linked_repo(paths[0], cl_fixture("testrepo.git")); + + /* Set the alternate B -> A */ + init_linked_repo(paths[1], paths[0]); + /* Set the alternate C -> B */ + init_linked_repo(paths[2], paths[1]); + + /* Use a relative alternates path for B -> A */ + cl_git_pass(git_fs_path_prettify(&filepath, paths[1], NULL)); + cl_git_pass(git_str_joinpath(&filepath, filepath.ptr, "objects/info/alternates")); + + cl_git_pass(git_filebuf_open(&file, git_str_cstr(&filepath), 0, 0666)); + git_filebuf_printf(&file, "../../%s/objects\n", paths[0]); + cl_git_pass(git_filebuf_commit(&file)); + + /* Now load B and see if we can find an object from testrepo.git */ + cl_git_pass(git_repository_open(&repo, paths[1])); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + git_commit_free(commit); + git_repository_free(repo); + + /* Now load C and see if we can find an object from testrepo.git */ + cl_git_pass(git_repository_open(&repo, paths[2])); + git_oid_from_string(&oid, "a65fedf39aefe402d3bb6e24df4d4f5fe4547750", GIT_OID_SHA1); + cl_git_pass(git_commit_lookup(&commit, repo, &oid)); + git_commit_free(commit); + git_repository_free(repo); +}