Commit df5eb323 by yuangli

support fetch unshallow option on shallow repos

parent 09b3d33d
...@@ -751,6 +751,13 @@ typedef struct { ...@@ -751,6 +751,13 @@ typedef struct {
int depth; 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 * Whether to allow off-site redirects. If this is not
* specified, the `http.followRedirects` configuration setting * specified, the `http.followRedirects` configuration setting
* will be consulted. * will be consulted.
...@@ -765,7 +772,7 @@ typedef struct { ...@@ -765,7 +772,7 @@ typedef struct {
#define GIT_FETCH_OPTIONS_VERSION 1 #define GIT_FETCH_OPTIONS_VERSION 1
#define GIT_FETCH_OPTIONS_INIT { GIT_FETCH_OPTIONS_VERSION, GIT_REMOTE_CALLBACKS_INIT, GIT_FETCH_PRUNE_UNSPECIFIED, 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 * Initialize git_fetch_options structure
......
...@@ -389,11 +389,6 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c ...@@ -389,11 +389,6 @@ static int checkout_branch(git_repository *repo, git_remote *remote, const git_c
return error; 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) 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; int error;
...@@ -415,7 +410,7 @@ static int clone_into(git_repository *repo, git_remote *_remote, const git_fetch ...@@ -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)); memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
fetch_opts.update_fetchhead = 0; fetch_opts.update_fetchhead = 0;
if (!git_fetch_is_shallow(opts)) if (opts->depth <= 0)
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL; fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote)); git_str_printf(&reflog_message, "clone: from %s", git_remote_url(remote));
......
...@@ -61,7 +61,7 @@ static int mark_local(git_remote *remote) ...@@ -61,7 +61,7 @@ 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 */
if (git_odb_exists(odb, &head->oid)) if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid))
head->local = 1; head->local = 1;
else else
remote->need_pack = 1; remote->need_pack = 1;
...@@ -173,6 +173,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) ...@@ -173,6 +173,7 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
git_transport *t = remote->transport; git_transport *t = remote->transport;
remote->need_pack = 0; remote->need_pack = 0;
remote->nego.depth = opts->unshallow ? INT_MAX : opts->depth;
if (filter_wants(remote, opts) < 0) if (filter_wants(remote, opts) < 0)
return -1; return -1;
...@@ -181,13 +182,17 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts) ...@@ -181,13 +182,17 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
if (!remote->need_pack) if (!remote->need_pack)
return 0; 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 * Now we have everything set up so we can start tell the
* server what we want and what we have. * server what we want and what we have.
*/ */
remote->nego.refs = (const git_remote_head * const *)remote->refs.contents; remote->nego.refs = (const git_remote_head * const *)remote->refs.contents;
remote->nego.count = remote->refs.length; remote->nego.count = remote->refs.length;
remote->nego.depth = opts->depth;
remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray)); remote->nego.shallow_roots = git__malloc(sizeof(git_shallowarray));
git_array_init(remote->nego.shallow_roots->array); git_array_init(remote->nego.shallow_roots->array);
......
...@@ -3366,10 +3366,10 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro ...@@ -3366,10 +3366,10 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro
assert(repo); assert(repo);
if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0) 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) 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_array_foreach(roots, idx, oid) {
git_filebuf_write(&file, git_oid_tostr_s(oid), GIT_OID_HEXSZ); 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 ...@@ -3378,12 +3378,19 @@ int git_repository__shallow_roots_write(git_repository *repo, git_array_oid_t ro
git_filebuf_commit(&file); git_filebuf_commit(&file);
git_str_dispose(&path); if ((error = load_grafts(repo)) < 0) {
error = -1;
goto on_error;
}
if (load_grafts(repo) < 0) if (git_array_size(roots) == 0) {
return -1; remove(path.ptr);
}
return 0; on_error:
git_str_dispose(&path);
return error;
} }
int git_repository_shallow_roots(git_oidarray *out, git_repository *repo) int git_repository_shallow_roots(git_oidarray *out, git_repository *repo)
......
...@@ -496,17 +496,35 @@ const git_oid * git_shallowarray_get(git_shallowarray *array, size_t idx) ...@@ -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) int git_shallowarray_add(git_shallowarray *array, git_oid *oid)
{ {
size_t oid_index; size_t oid_index;
if (git_array_search(&oid_index, array->array, (git_array_compare_cb)git_oid_cmp, &oid) < 0) { 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_oid *tmp = git_array_alloc(array->array);
GIT_ERROR_CHECK_ALLOC(tmp);
git_oid_cpy(tmp, oid); git_oid_cpy(tmp, oid);
} }
return 0; return 0;
} }
int git_shallowarray_remove(git_shallowarray *array, git_oid *oid) int git_shallowarray_remove(git_shallowarray *array, git_oid *oid)
{ {
GIT_UNUSED(array); git_array_oid_t new_array = GIT_ARRAY_INIT;
GIT_UNUSED(oid); git_oid *element;
/* no git_array_remove… meh */ git_oid *tmp;
return -1; 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;
} }
...@@ -131,3 +131,44 @@ void test_clone_shallow__clone_depth_five(void) ...@@ -131,3 +131,44 @@ void test_clone_shallow__clone_depth_five(void)
git_revwalk_free(walk); git_revwalk_free(walk);
git_repository_free(repo); 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);
}
#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);
}
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