Commit 4ed1bd15 by Michał Kępień

fetch: enable deepening/shortening shallow clones

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).
parent d9475611
...@@ -60,9 +60,11 @@ static int mark_local(git_remote *remote) ...@@ -60,9 +60,11 @@ static int mark_local(git_remote *remote)
git_vector_foreach(&remote->refs, i, head) { git_vector_foreach(&remote->refs, i, head) {
/* If we have the object, mark it so we don't ask for it. /* 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 However if we are unshallowing or changing history
even though the head exists locally. */ depth, we need to ask for it even though the head
if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid)) exists locally. */
if (remote->nego.depth == GIT_FETCH_DEPTH_FULL &&
git_odb_exists(odb, &head->oid))
head->local = 1; head->local = 1;
else else
remote->need_pack = 1; remote->need_pack = 1;
......
...@@ -164,3 +164,102 @@ void test_online_shallow__unshallow(void) ...@@ -164,3 +164,102 @@ void test_online_shallow__unshallow(void)
git_revwalk_free(walk); git_revwalk_free(walk);
git_repository_free(repo); 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);
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment