From 9e40c1390c2a66b85b5778c515562faeac3d0c6a Mon Sep 17 00:00:00 2001 From: Kevin Saul Date: Sun, 7 Jul 2024 11:07:45 +1200 Subject: [PATCH] smart: fix shallow roots setup --- src/libgit2/transports/smart_protocol.c | 1 + tests/libgit2/online/shallow.c | 148 +++++++++++++++++++++++- 2 files changed, 146 insertions(+), 3 deletions(-) diff --git a/src/libgit2/transports/smart_protocol.c b/src/libgit2/transports/smart_protocol.c index df1c190c3..fb2dd7cf2 100644 --- a/src/libgit2/transports/smart_protocol.c +++ b/src/libgit2/transports/smart_protocol.c @@ -394,6 +394,7 @@ static int setup_shallow_roots( memcpy(out->ptr, wants->shallow_roots, sizeof(git_oid) * wants->shallow_roots_len); + out->size = wants->shallow_roots_len; } return 0; diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c index ee4aaf37e..d7038cdd2 100644 --- a/tests/libgit2/online/shallow.c +++ b/tests/libgit2/online/shallow.c @@ -242,10 +242,15 @@ void test_online_shallow__shorten_four(void) cl_assert_equal_b(true, git_repository_is_shallow(repo)); cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); - cl_assert_equal_i(3, roots_len); - cl_assert_equal_s("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", git_oid_tostr_s(&roots[0])); - cl_assert_equal_s("59706a11bde2b9899a278838ef20a97e8f8795d2", git_oid_tostr_s(&roots[1])); + cl_assert_equal_i(6, roots_len); + /* roots added during initial clone, not removed as not encountered during fetch */ + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&roots[1])); + cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&roots[3])); + /* roots added during fetch */ cl_assert_equal_s("bab66b48f836ed950c99134ef666436fb07a09a0", git_oid_tostr_s(&roots[2])); + cl_assert_equal_s("59706a11bde2b9899a278838ef20a97e8f8795d2", git_oid_tostr_s(&roots[4])); + cl_assert_equal_s("d86a2aada2f5e7ccf6f11880bfb9ab404e8a8864", git_oid_tostr_s(&roots[5])); git_revwalk_new(&walk, repo); git_revwalk_push_head(walk); @@ -263,3 +268,140 @@ void test_online_shallow__shorten_four(void) git_revwalk_free(walk); git_repository_free(repo); } + +void test_online_shallow__preserve_unrelated_roots(void) +{ + git_str path = GIT_STR_INIT; + git_repository *repo; + git_revwalk *walk; + git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT; + git_remote *origin = NULL; + git_strarray refspecs; + git_oid oid; + git_oid *roots; + size_t roots_len; + size_t num_commits = 0; + int error = 0; + git_oid first_oid; + git_oid second_oid; + git_oid third_oid; + char *first_commit = "c070ad8c08840c8116da865b2d65593a6bb9cd2a"; + char *second_commit = "6e1475206e57110fcef4b92320436c1e9872a322"; + char *third_commit = "7f822839a2fe9760f386cbbbcb3f92c5fe81def7"; + +#ifdef GIT_EXPERIMENTAL_SHA256 + cl_git_pass(git_oid_fromstr(&first_oid, first_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_fromstr(&second_oid, second_commit, GIT_OID_SHA1)); + cl_git_pass(git_oid_fromstr(&third_oid, third_commit, GIT_OID_SHA1)); +#else + cl_git_pass(git_oid_fromstr(&first_oid, first_commit)); + cl_git_pass(git_oid_fromstr(&second_oid, second_commit)); + cl_git_pass(git_oid_fromstr(&third_oid, third_commit)); +#endif + + /* setup empty repository without cloning */ + git_str_joinpath(&path, clar_sandbox_path(), "preserve_unrelated_roots"); + cl_git_pass(git_repository_init(&repo, git_str_cstr(&path), true)); + cl_git_pass(git_remote_create(&origin, repo, "origin", "https://github.com/libgit2/TestGitRepository")); + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + /* shallow fetch for first commit */ + fetch_opts.depth = 1; + refspecs.strings = &first_commit; + refspecs.count = 1; + cl_git_pass(git_remote_fetch(origin, &refspecs, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(1, roots_len); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &first_oid)); + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(num_commits, 1); + cl_assert_equal_i(error, GIT_ITEROVER); + + /* shallow fetch for second commit */ + fetch_opts.depth = 1; + refspecs.strings = &second_commit; + refspecs.count = 1; + cl_git_pass(git_remote_fetch(origin, &refspecs, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + git__free(roots); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(2, roots_len); + cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&roots[0])); + cl_assert_equal_s("6e1475206e57110fcef4b92320436c1e9872a322", git_oid_tostr_s(&roots[1])); + + git_revwalk_free(walk); + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &second_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 1); + + /* fetch full history for third commit, includes first commit which should be removed from shallow roots */ + fetch_opts.depth = 100; + refspecs.strings = &third_commit; + refspecs.count = 1; + cl_git_pass(git_remote_fetch(origin, &refspecs, &fetch_opts, NULL)); + cl_assert_equal_b(true, git_repository_is_shallow(repo)); + + git__free(roots); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(1, roots_len); + cl_assert_equal_s("6e1475206e57110fcef4b92320436c1e9872a322", git_oid_tostr_s(&roots[0])); + + git_revwalk_free(walk); + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &third_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 12); + + cl_git_pass(git_revwalk_reset(walk)); + cl_git_pass(git_revwalk_push(walk, &second_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 1); + + /* unshallow repository without specifying any refspec */ + fetch_opts.depth = GIT_FETCH_DEPTH_UNSHALLOW; + cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL)); + cl_assert_equal_b(false, git_repository_is_shallow(repo)); + + git__free(roots); + cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo)); + cl_assert_equal_i(0, roots_len); + + git_revwalk_free(walk); + cl_git_pass(git_revwalk_new(&walk, repo)); + cl_git_pass(git_revwalk_push(walk, &first_oid)); + cl_git_pass(git_revwalk_push(walk, &second_oid)); + cl_git_pass(git_revwalk_push(walk, &third_oid)); + num_commits = 0; + while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) { + num_commits++; + } + cl_assert_equal_i(error, GIT_ITEROVER); + cl_assert_equal_i(num_commits, 18); + + git__free(roots); + git_remote_free(origin); + git_str_dispose(&path); + git_revwalk_free(walk); + git_repository_free(repo); +}