summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authoryuangli <yuangli@mathworks.com>2022-08-09 19:24:57 +0100
committeryuangli <yuangli@mathworks.com>2022-08-09 19:24:57 +0100
commitdf5eb3239b1419b3f4382d7bcca9a5d85611d7d3 (patch)
treea5d97cf1c8f6b269bae26f48a6176236e749c005
parent09b3d33d6dba7f4804b478a72dec3258405856c2 (diff)
downloadlibgit2-df5eb3239b1419b3f4382d7bcca9a5d85611d7d3.tar.gz
support fetch unshallow option on shallow repos
-rw-r--r--include/git2/remote.h9
-rw-r--r--src/libgit2/clone.c7
-rw-r--r--src/libgit2/fetch.c9
-rw-r--r--src/libgit2/repository.c19
-rw-r--r--src/libgit2/transports/smart.c26
-rw-r--r--tests/libgit2/clone/shallow.c41
-rw-r--r--tests/libgit2/transports/smart/shallowarray.c52
7 files changed, 144 insertions, 19 deletions
diff --git a/include/git2/remote.h b/include/git2/remote.h
index f3415d843..240e5aa4e 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -751,6 +751,13 @@ typedef struct {
int depth;
/**
+ * Unshallow flag of the fetch to perform.
+ *
+ * The default is 0, which means the flag is off.
+ */
+ int unshallow;
+
+ /**
* Whether to allow off-site redirects. If this is not
* specified, the `http.followRedirects` configuration setting
* will be consulted.
@@ -765,7 +772,7 @@ typedef struct {
#define GIT_FETCH_OPTIONS_VERSION 1
#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 1, \
- GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, -1 }
+ GIT_REMOTE_DOWNLOAD_TAGS_UNSPECIFIED, GIT_PROXY_OPTIONS_INIT, -1, 0 }
/**
* Initialize git_fetch_options structure
diff --git a/src/libgit2/clone.c b/src/libgit2/clone.c
index 5e07dc733..6f34cb7ca 100644
--- a/src/libgit2/clone.c
+++ b/src/libgit2/clone.c
@@ -389,11 +389,6 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
return error;
}
-static int git_fetch_is_shallow(const git_fetch_options *opts)
-{
- return opts->depth > 0;
-}
-
static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch_options *opts, const git_checkout_options *co_opts, const char *branch)
{
int error;
@@ -415,7 +410,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch
memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
fetch_opts.update_fetchhead = 0;
- if (!git_fetch_is_shallow(opts))
+ if (opts->depth <= 0)
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
diff --git a/src/libgit2/fetch.c b/src/libgit2/fetch.c
index b90ce2ee8..a015cfbd3 100644
--- a/src/libgit2/fetch.c
+++ b/src/libgit2/fetch.c
@@ -61,7 +61,7 @@ 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 */
- if (git_odb_exists(odb, &head->oid))
+ if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid))
head->local = 1;
else
remote->need_pack = 1;
@@ -173,6 +173,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
git_transport *t = remote->transport;
remote->need_pack = 0;
+ remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth;
if (filter_wants(remote, opts) < 0)
return -1;
@@ -181,13 +182,17 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
if (!remote->need_pack)
return 0;
+ if (opts->unshallow && opts->depth > 0) {
+ git_error_set(GIT_ERROR_INVALID, "options '--depth' and '--unshallow' cannot be used together");
+ return -1;
+ }
+
/*
* Now we have everything set up so we can start tell the
* server what we want and what we have.
*/
remote->nego.refs = (const git_remote_head * const *)remote->refs.contents;
remote->nego.count = remote->refs.length;
- remote->nego.depth = opts->depth;
remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray));
git_array_init(remote->nego.shallow_roots->array);
diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c
index 0d149a626..13559ef07 100644
--- a/src/libgit2/repository.c
+++ b/src/libgit2/repository.c
@@ -3366,10 +3366,10 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro
assert(repo);
if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0)
- return error;
+ goto on_error;
if ((error = git_filebuf_open(&file, git_str_cstr(&path), GIT_FILEBUF_HASH_CONTENTS, 0666)) < 0)
- return error;
+ goto on_error;
git_array_foreach(roots, idx, oid) {
git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ);
@@ -3378,12 +3378,19 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro
git_filebuf_commit(&file);
- git_str_dispose(&path);
+ if ((error = load_grafts(repo)) < 0) {
+ error = -1;
+ goto on_error;
+ }
- if (load_grafts(repo) < 0)
- return -1;
+ if (git_array_size(roots) == 0) {
+ remove(path.ptr);
+ }
- return 0;
+on_error:
+ git_str_dispose(&path);
+
+ return error;
}
int git_repository_shallow_roots(git_oidarray *out, git_repository *repo)
diff --git a/src/libgit2/transports/smart.c b/src/libgit2/transports/smart.c
index 9d1afeb05..b0925c8bb 100644
--- a/src/libgit2/transports/smart.c
+++ b/src/libgit2/transports/smart.c
@@ -496,17 +496,35 @@ const git_oid * git_shallowarray_get(git_shallowarray *array, size_t idx)
int git_shallowarray_add(git_shallowarray *array, git_oid *oid)
{
size_t oid_index;
+
if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, &oid) < 0) {
git_oid *tmp = git_array_alloc(array->array);
+ GIT_ERROR_CHECK_ALLOC(tmp);
+
git_oid_cpy(tmp, oid);
}
+
return 0;
}
int git_shallowarray_remove(git_shallowarray *array, git_oid *oid)
{
- GIT_UNUSED(array);
- GIT_UNUSED(oid);
- /* no git_array_removeā€¦ meh */
- return -1;
+ git_array_oid_t new_array = GIT_ARRAY_INIT;
+ git_oid *element;
+ git_oid *tmp;
+ size_t i;
+
+ git_array_foreach(array->array, i, element) {
+ if (git_oid_cmp(oid, element)) {
+ tmp = git_array_alloc(new_array);
+ GIT_ERROR_CHECK_ALLOC(tmp);
+
+ git_oid_cpy(tmp, element);
+ }
+ }
+
+ git_array_clear(array->array);
+ array->array = new_array;
+
+ return 0;
}
diff --git a/tests/libgit2/clone/shallow.c b/tests/libgit2/clone/shallow.c
index 7fb056f91..2a88d5d05 100644
--- a/tests/libgit2/clone/shallow.c
+++ b/tests/libgit2/clone/shallow.c
@@ -131,3 +131,44 @@ void test_clone_shallow__clone_depth_five(void)
git_revwalk_free(walk);
git_repository_free(repo);
}
+
+void test_clone_shallow__unshallow(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;
+ 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(), "unshallow");
+ 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.unshallow = 1;
+ cl_git_pass(git_remote_lookup(&origin, repo, "origin"));
+
+ cl_git_pass(git_remote_fetch(origin, NULL, &fetch_opts, NULL));
+ cl_assert_equal_b(false, git_repository_is_shallow(repo));
+
+ 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, 21);
+ cl_assert_equal_i(error, GIT_ITEROVER);
+
+ git_remote_free(origin);
+ git_str_dispose(&path);
+ git_revwalk_free(walk);
+ git_repository_free(repo);
+}
diff --git a/tests/libgit2/transports/smart/shallowarray.c b/tests/libgit2/transports/smart/shallowarray.c
new file mode 100644
index 000000000..c51e62713
--- /dev/null
+++ b/tests/libgit2/transports/smart/shallowarray.c
@@ -0,0 +1,52 @@
+#include "clar_libgit2.h"
+
+#include "git2/oid.h"
+#include "git2/transport.h"
+
+#include "common.h"
+#include "transports/smart.h"
+#include "oid.h"
+
+#include <assert.h>
+
+#define oid_0 "c070ad8c08840c8116da865b2d65593a6bb9cd2a"
+#define oid_1 "0966a434eb1a025db6b71485ab63a3bfbea520b6"
+#define oid_2 "83834a7afdaa1a1260568567f6ad90020389f664"
+
+void test_transports_smart_shallowarray__add_and_remove_oid_from_shallowarray(void)
+{
+ git_oid oid_0_obj, oid_1_obj, oid_2_obj;
+ git_shallowarray *shallow_roots = git__malloc(sizeof(git_shallowarray));
+ git_array_init(shallow_roots->array);
+
+ git_oid_fromstr(&oid_0_obj, oid_0);
+ git_oid_fromstr(&oid_1_obj, oid_1);
+ git_oid_fromstr(&oid_2_obj, oid_2);
+
+ git_shallowarray_add(shallow_roots, &oid_0_obj);
+ git_shallowarray_add(shallow_roots, &oid_1_obj);
+ git_shallowarray_add(shallow_roots, &oid_2_obj);
+
+ cl_assert_equal_i(3, shallow_roots->array.size);
+ cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0]));
+ cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1]));
+ cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&shallow_roots->array.ptr[2]));
+
+ git_shallowarray_remove(shallow_roots, &oid_2_obj);
+
+ cl_assert_equal_i(2, shallow_roots->array.size);
+ cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0]));
+ cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&shallow_roots->array.ptr[1]));
+
+ git_shallowarray_remove(shallow_roots, &oid_1_obj);
+
+ cl_assert_equal_i(1, shallow_roots->array.size);
+ cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&shallow_roots->array.ptr[0]));
+
+ git_shallowarray_remove(shallow_roots, &oid_0_obj);
+
+ cl_assert_equal_i(0, shallow_roots->array.size);
+
+ git_array_clear(shallow_roots->array);
+ git__free(shallow_roots);
+}