File 0001-fetch-enable-deepening-shortening-shallow-clones.patch of Package libgit2
From: =?UTF-8?q?Micha=C5=82=20K=C4=99pie=C5=84?= <michal@isc.org>
Date: Wed, 6 Dec 2023 11:50:29 +0100
Subject: fetch: enable deepening/shortening shallow clones
References: shallow-fix
Patch-mainline: no
A shallow repository can currently only be completely unshallowed, which
is caused by mark_local() only marking locally-existing objects as
wanted if the fetch depth is set to INT_MAX (GIT_FETCH_DEPTH_UNSHALLOW).
This prevents deepening the history of a shallow clone to an arbitrary
number of commits, which may be preferable over full unshallowing for
large repositories.
Enable deepening and shortening shallow clones by marking
locally-existing objects as wanted whenever the fetch depth is set to
any non-default value (either GIT_FETCH_DEPTH_UNSHALLOW or an arbitrary
positive integer).
Signed-off-by: Jiri Slaby <jslaby@suse.cz>
---
src/libgit2/fetch.c | 8 +--
tests/libgit2/online/shallow.c | 99 ++++++++++++++++++++++++++++++++++
2 files changed, 104 insertions(+), 3 deletions(-)
diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c
index d74abb4a8473..8e2660f2172a 100644
--- a/src/libgit2/fetch.c
+++ b/src/libgit2/fetch.c
@@ -60,9 +60,11 @@ static int mark_local(git_remote *remote)
git_vector_foreach(&remote->refs, i, head) {
/* If we have the object, mark it so we don't ask for it.
- However if we are unshallowing, we need to ask for it
- even though the head exists locally. */
- if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid))
+ However if we are unshallowing or changing history
+ depth, we need to ask for it even though the head
+ exists locally. */
+ if (remote->nego.depth == GIT_FETCH_DEPTH_FULL &&
+ git_odb_exists(odb, &head->oid))
head->local = 1;
else
remote->need_pack = 1;
diff --git a/tests/libgit2/online/shallow.c b/tests/libgit2/online/shallow.c
index 5c0e6565b039..ee4aaf37ed4f 100644
--- a/tests/libgit2/online/shallow.c
+++ b/tests/libgit2/online/shallow.c
@@ -164,3 +164,102 @@ void test_online_shallow__unshallow(void)
git_revwalk_free(walk);
git_repository_free(repo);
}
+
+void test_online_shallow__deepen_six(void)
+{
+ git_str path = GIT_STR_INIT;
+ git_repository *repo;
+ git_revwalk *walk;
+ git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
+ git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
+ git_remote *origin = NULL;
+ git_oid oid;
+ git_oid *roots;
+ size_t roots_len;
+ size_t num_commits = 0;
+ int error = 0;
+
+ clone_opts.fetch_opts.depth = 5;
+ clone_opts.remote_cb = remote_single_branch;
+
+ git_str_joinpath(&path, clar_sandbox_path(), "deepen_6");
+ cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts));
+ cl_assert_equal_b(true, git_repository_is_shallow(repo));
+
+ fetch_opts.depth = 6;
+ cl_git_pass(git_remote_lookup(&origin, repo, "origin"));
+ cl_git_pass(git_remote_fetch(origin, NULL, &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(4, roots_len);
+ cl_assert_equal_s("58be4659bb571194ed4562d04b359d26216f526e", git_oid_tostr_s(&roots[0]));
+ cl_assert_equal_s("d31f5a60d406e831d056b8ac2538d515100c2df2", git_oid_tostr_s(&roots[1]));
+ cl_assert_equal_s("6462e7d8024396b14d7651e2ec11e2bbf07a05c4", git_oid_tostr_s(&roots[2]));
+ cl_assert_equal_s("2c349335b7f797072cf729c4f3bb0914ecb6dec9", git_oid_tostr_s(&roots[3]));
+
+ git_revwalk_new(&walk, repo);
+ git_revwalk_push_head(walk);
+
+ while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) {
+ num_commits++;
+ }
+
+ cl_assert_equal_i(num_commits, 17);
+ cl_assert_equal_i(error, GIT_ITEROVER);
+
+ git__free(roots);
+ git_remote_free(origin);
+ git_str_dispose(&path);
+ git_revwalk_free(walk);
+ git_repository_free(repo);
+}
+
+void test_online_shallow__shorten_four(void)
+{
+ git_str path = GIT_STR_INIT;
+ git_repository *repo;
+ git_revwalk *walk;
+ git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
+ git_fetch_options fetch_opts = GIT_FETCH_OPTIONS_INIT;
+ git_remote *origin = NULL;
+ git_oid oid;
+ git_oid *roots;
+ size_t roots_len;
+ size_t num_commits = 0;
+ int error = 0;
+
+ clone_opts.fetch_opts.depth = 5;
+ clone_opts.remote_cb = remote_single_branch;
+
+ git_str_joinpath(&path, clar_sandbox_path(), "shorten_4");
+ cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts));
+ cl_assert_equal_b(true, git_repository_is_shallow(repo));
+
+ fetch_opts.depth = 4;
+ cl_git_pass(git_remote_lookup(&origin, repo, "origin"));
+ cl_git_pass(git_remote_fetch(origin, NULL, &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(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_s("bab66b48f836ed950c99134ef666436fb07a09a0", git_oid_tostr_s(&roots[2]));
+
+ git_revwalk_new(&walk, repo);
+ git_revwalk_push_head(walk);
+
+ while ((error = git_revwalk_next(&oid, walk)) == GIT_OK) {
+ num_commits++;
+ }
+
+ cl_assert_equal_i(num_commits, 10);
+ cl_assert_equal_i(error, GIT_ITEROVER);
+
+ git__free(roots);
+ git_remote_free(origin);
+ git_str_dispose(&path);
+ git_revwalk_free(walk);
+ git_repository_free(repo);
+}
--
2.50.1