Unverified Commit 2bbcdee6 by Edward Thomson Committed by GitHub

Merge pull request #6557 from libgit2/ethomson/shallow

Shallow (#6396) with some fixes from review
parents 251408cf 437c5f5a
......@@ -109,7 +109,8 @@ typedef enum {
GIT_ERROR_WORKTREE,
GIT_ERROR_SHA,
GIT_ERROR_HTTP,
GIT_ERROR_INTERNAL
GIT_ERROR_INTERNAL,
GIT_ERROR_GRAFTS
} git_error_t;
/**
......
......@@ -702,6 +702,15 @@ typedef enum {
GIT_REMOTE_DOWNLOAD_TAGS_ALL
} git_remote_autotag_option_t;
/** Constants for fetch depth (shallowness of fetch). */
typedef enum {
/** The fetch is "full" (not shallow). This is the default. */
GIT_FETCH_DEPTH_FULL = 0,
/** The fetch should "unshallow" and fetch missing data. */
GIT_FETCH_DEPTH_UNSHALLOW = 2147483647
} git_fetch_depth_t;
/**
* Fetch options structure.
*
......@@ -744,6 +753,15 @@ typedef struct {
git_proxy_options proxy_opts;
/**
* Depth of the fetch to perform, or `GIT_FETCH_DEPTH_FULL`
* (or `0`) for full history, or `GIT_FETCH_DEPTH_UNSHALLOW`
* to "unshallow" a shallow repository.
*
* The default is full (`GIT_FETCH_DEPTH_FULL` or `0`).
*/
int depth;
/**
* Whether to allow off-site redirects. If this is not
* specified, the `http.followRedirects` configuration setting
* will be consulted.
......
......@@ -25,6 +25,14 @@
GIT_BEGIN_DECL
typedef struct {
const git_remote_head * const *refs;
size_t refs_len;
git_oid *shallow_roots;
size_t shallow_roots_len;
int depth;
} git_fetch_negotiation;
struct git_transport {
unsigned int version; /**< The struct version */
......@@ -96,8 +104,17 @@ struct git_transport {
int GIT_CALLBACK(negotiate_fetch)(
git_transport *transport,
git_repository *repo,
const git_remote_head * const *refs,
size_t count);
const git_fetch_negotiation *fetch_data);
/**
* Return the shallow roots of the remote.
*
* This function may be called after a successful call to
* `negotiate_fetch`.
*/
int GIT_CALLBACK(shallow_roots)(
git_oidarray *out,
git_transport *transport);
/**
* Start downloading the packfile from the remote repository.
......
......@@ -18,7 +18,7 @@
#define COMMAND_NAME "clone"
static char *branch, *remote_path, *local_path;
static char *branch, *remote_path, *local_path, *depth;
static int show_help, quiet, checkout = 1, bare;
static bool local_path_exists;
static cli_progress progress = CLI_PROGRESS_INIT;
......@@ -36,6 +36,8 @@ static const cli_opt_spec opts[] = {
CLI_OPT_USAGE_DEFAULT, NULL, "don't create a working directory" },
{ CLI_OPT_TYPE_VALUE, "branch", 'b', &branch, 0,
CLI_OPT_USAGE_DEFAULT, "name", "branch to check out" },
{ CLI_OPT_TYPE_VALUE, "depth", 0, &depth, 0,
CLI_OPT_USAGE_DEFAULT, "depth", "commit depth to check out " },
{ CLI_OPT_TYPE_LITERAL },
{ CLI_OPT_TYPE_ARG, "repository", 0, &remote_path, 0,
CLI_OPT_USAGE_REQUIRED, "repository", "repository path" },
......@@ -71,6 +73,22 @@ static char *compute_local_path(const char *orig_path)
return local_path;
}
static int compute_depth(const char *depth)
{
int64_t i;
const char *endptr;
if (!depth)
return 0;
if (git__strntol64(&i, depth, strlen(depth), &endptr, 10) < 0 || i < 0 || i > INT_MAX || *endptr) {
fprintf(stderr, "fatal: depth '%s' is not valid.\n", depth);
exit(128);
}
return (int)i;
}
static bool validate_local_path(const char *path)
{
if (!git_fs_path_exists(path))
......@@ -127,11 +145,9 @@ int cmd_clone(int argc, char **argv)
goto done;
}
if (bare)
clone_opts.bare = 1;
if (branch)
clone_opts.checkout_branch = branch;
clone_opts.bare = !!bare;
clone_opts.checkout_branch = branch;
clone_opts.fetch_opts.depth = compute_depth(depth);
if (!checkout)
clone_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;
......
......@@ -420,7 +420,9 @@ static int clone_into(
memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
fetch_opts.update_fetchhead = 0;
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
if (!opts->depth)
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0)
goto cleanup;
......
......@@ -22,6 +22,7 @@
#include "object.h"
#include "array.h"
#include "oidarray.h"
#include "grafts.h"
void git_commit__free(void *_commit)
{
......@@ -427,10 +428,6 @@ static int commit_parse(
buffer += tree_len;
}
/*
* TODO: commit grafts!
*/
while (git_object__parse_oid_header(&parent_id,
&buffer, buffer_end, "parent ",
opts->oid_type) == 0) {
......@@ -532,16 +529,41 @@ int git_commit__parse_raw(
return commit_parse(commit, data, size, &parse_options);
}
static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft *graft) {
size_t idx;
git_oid *oid;
git_array_clear(commit->parent_ids);
git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents));
git_array_foreach(graft->parents, idx, oid) {
git_oid *id = git_array_alloc(commit->parent_ids);
GIT_ERROR_CHECK_ALLOC(id);
git_oid_cpy(id, oid);
}
return 0;
}
int git_commit__parse_ext(
git_commit *commit,
git_odb_object *odb_obj,
git_commit__parse_options *parse_opts)
{
return commit_parse(
commit,
git_odb_object_data(odb_obj),
git_odb_object_size(odb_obj),
parse_opts);
git_repository *repo = git_object_owner((git_object *)commit);
git_commit_graft *graft;
int error;
if ((error = commit_parse(commit, git_odb_object_data(odb_obj),
git_odb_object_size(odb_obj), parse_opts)) < 0)
return error;
/* Perform necessary grafts */
if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != 0 &&
git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0)
return 0;
return assign_commit_parents_from_graft(commit, graft);
}
#define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \
......
......@@ -20,6 +20,7 @@
#include "netops.h"
#include "repository.h"
#include "refs.h"
#include "transports/smart.h"
static int maybe_want(git_remote *remote, git_remote_head *head, git_refspec *tagspec, git_remote_autotag_option_t tagopt)
{
......@@ -59,8 +60,10 @@ static int mark_local(git_remote *remote)
return -1;
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 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))
head->local = 1;
else
remote->need_pack = 1;
......@@ -166,9 +169,15 @@ cleanup:
int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
{
git_transport *t = remote->transport;
int error;
remote->need_pack = 0;
if (opts) {
GIT_ASSERT_ARG(opts->depth >= 0);
remote->nego.depth = opts->depth;
}
if (filter_wants(remote, opts) < 0)
return -1;
......@@ -180,20 +189,40 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
* Now we have everything set up so we can start tell the
* server what we want and what we have.
*/
return t->negotiate_fetch(t,
remote->nego.refs = (const git_remote_head * const *)remote->refs.contents;
remote->nego.refs_len = remote->refs.length;
if (git_repository__shallow_roots(&remote->nego.shallow_roots,
&remote->nego.shallow_roots_len,
remote->repo) < 0)
return -1;
error = t->negotiate_fetch(t,
remote->repo,
(const git_remote_head * const *)remote->refs.contents,
remote->refs.length);
&remote->nego);
git__free(remote->nego.shallow_roots);
return error;
}
int git_fetch_download_pack(git_remote *remote)
{
git_oidarray shallow_roots = { NULL };
git_transport *t = remote->transport;
int error;
if (!remote->need_pack)
return 0;
return t->download_pack(t, remote->repo, &remote->stats);
if ((error = t->download_pack(t, remote->repo, &remote->stats)) != 0 ||
(error = t->shallow_roots(&shallow_roots, t)) != 0)
return error;
error = git_repository__shallow_roots_write(remote->repo, &shallow_roots);
git_oidarray_dispose(&shallow_roots);
return error;
}
int git_fetch_options_init(git_fetch_options *opts, unsigned int version)
......
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#include "grafts.h"
#include "futils.h"
#include "oid.h"
#include "oidarray.h"
#include "parse.h"
struct git_grafts {
/* Map of `git_commit_graft`s */
git_oidmap *commits;
/* Type of object IDs */
git_oid_t oid_type;
/* File backing the graft. NULL if it's an in-memory graft */
char *path;
unsigned char path_checksum[GIT_HASH_SHA256_SIZE];
};
int git_grafts_new(git_grafts **out, git_oid_t oid_type)
{
git_grafts *grafts;
GIT_ASSERT_ARG(out && oid_type);
grafts = git__calloc(1, sizeof(*grafts));
GIT_ERROR_CHECK_ALLOC(grafts);
if ((git_oidmap_new(&grafts->commits)) < 0) {
git__free(grafts);
return -1;
}
grafts->oid_type = oid_type;
*out = grafts;
return 0;
}
int git_grafts_open(
git_grafts **out,
const char *path,
git_oid_t oid_type)
{
git_grafts *grafts = NULL;
int error;
GIT_ASSERT_ARG(out && path && oid_type);
if ((error = git_grafts_new(&grafts, oid_type)) < 0)
goto error;
grafts->path = git__strdup(path);
GIT_ERROR_CHECK_ALLOC(grafts->path);
if ((error = git_grafts_refresh(grafts)) < 0)
goto error;
*out = grafts;
error:
if (error < 0)
git_grafts_free(grafts);
return error;
}
int git_grafts_open_or_refresh(
git_grafts **out,
const char *path,
git_oid_t oid_type)
{
GIT_ASSERT_ARG(out && path && oid_type);
return *out ? git_grafts_refresh(*out) : git_grafts_open(out, path, oid_type);
}
void git_grafts_free(git_grafts *grafts)
{
if (!grafts)
return;
git__free(grafts->path);
git_grafts_clear(grafts);
git_oidmap_free(grafts->commits);
git__free(grafts);
}
void git_grafts_clear(git_grafts *grafts)
{
git_commit_graft *graft;
if (!grafts)
return;
git_oidmap_foreach_value(grafts->commits, graft, {
git__free(graft->parents.ptr);
git__free(graft);
});
git_oidmap_clear(grafts->commits);
}
int git_grafts_refresh(git_grafts *grafts)
{
git_str contents = GIT_STR_INIT;
int error, updated = 0;
GIT_ASSERT_ARG(grafts);
if (!grafts->path)
return 0;
if ((error = git_futils_readbuffer_updated(&contents, grafts->path,
grafts->path_checksum, &updated)) < 0) {
if (error == GIT_ENOTFOUND) {
git_grafts_clear(grafts);
error = 0;
}
goto cleanup;
}
if (!updated) {
goto cleanup;
}
if ((error = git_grafts_parse(grafts, contents.ptr, contents.size)) < 0)
goto cleanup;
cleanup:
git_str_dispose(&contents);
return error;
}
int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len)
{
git_array_oid_t parents = GIT_ARRAY_INIT;
git_parse_ctx parser;
int error;
git_grafts_clear(grafts);
if ((error = git_parse_ctx_init(&parser, buf, len)) < 0)
goto error;
for (; parser.remain_len; git_parse_advance_line(&parser)) {
git_oid graft_oid;
if ((error = git_parse_advance_oid(&graft_oid, &parser, grafts->oid_type)) < 0) {
git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num);
goto error;
}
while (parser.line_len && git_parse_advance_expected(&parser, "\n", 1) != 0) {
git_oid *id = git_array_alloc(parents);
GIT_ERROR_CHECK_ALLOC(id);
if ((error = git_parse_advance_expected(&parser, " ", 1)) < 0 ||
(error = git_parse_advance_oid(id, &parser, grafts->oid_type)) < 0) {
git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num);
goto error;
}
}
if ((error = git_grafts_add(grafts, &graft_oid, parents)) < 0)
goto error;
git_array_clear(parents);
}
error:
git_array_clear(parents);
return error;
}
int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents)
{
git_commit_graft *graft;
git_oid *parent_oid;
int error;
size_t i;
GIT_ASSERT_ARG(grafts && oid);
graft = git__calloc(1, sizeof(*graft));
GIT_ERROR_CHECK_ALLOC(graft);
git_array_init_to_size(graft->parents, git_array_size(parents));
git_array_foreach(parents, i, parent_oid) {
git_oid *id = git_array_alloc(graft->parents);
GIT_ERROR_CHECK_ALLOC(id);
git_oid_cpy(id, parent_oid);
}
git_oid_cpy(&graft->oid, oid);
if ((error = git_grafts_remove(grafts, &graft->oid)) < 0 && error != GIT_ENOTFOUND)
goto cleanup;
if ((error = git_oidmap_set(grafts->commits, &graft->oid, graft)) < 0)
goto cleanup;
return 0;
cleanup:
git_array_clear(graft->parents);
git__free(graft);
return error;
}
int git_grafts_remove(git_grafts *grafts, const git_oid *oid)
{
git_commit_graft *graft;
int error;
GIT_ASSERT_ARG(grafts && oid);
if ((graft = git_oidmap_get(grafts->commits, oid)) == NULL)
return GIT_ENOTFOUND;
if ((error = git_oidmap_delete(grafts->commits, oid)) < 0)
return error;
git__free(graft->parents.ptr);
git__free(graft);
return 0;
}
int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid)
{
GIT_ASSERT_ARG(out && grafts && oid);
if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL)
return GIT_ENOTFOUND;
return 0;
}
int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts)
{
git_array_oid_t array = GIT_ARRAY_INIT;
const git_oid *oid;
size_t existing, i = 0;
GIT_ASSERT_ARG(out && grafts);
if ((existing = git_oidmap_size(grafts->commits)) > 0)
git_array_init_to_size(array, existing);
while (git_oidmap_iterate(NULL, grafts->commits, &i, &oid) == 0) {
git_oid *cpy = git_array_alloc(array);
GIT_ERROR_CHECK_ALLOC(cpy);
git_oid_cpy(cpy, oid);
}
*out = array.ptr;
*out_len = array.size;
return 0;
}
size_t git_grafts_size(git_grafts *grafts)
{
return git_oidmap_size(grafts->commits);
}
/*
* Copyright (C) the libgit2 contributors. All rights reserved.
*
* This file is part of libgit2, distributed under the GNU GPL v2 with
* a Linking Exception. For full terms see the included COPYING file.
*/
#ifndef INCLUDE_graft_h__
#define INCLUDE_graft_h__
#include "common.h"
#include "oidarray.h"
#include "oidmap.h"
/** graft commit */
typedef struct {
git_oid oid;
git_array_oid_t parents;
} git_commit_graft;
typedef struct git_grafts git_grafts;
int git_grafts_new(git_grafts **out, git_oid_t oid_type);
int git_grafts_open(git_grafts **out, const char *path, git_oid_t oid_type);
int git_grafts_open_or_refresh(git_grafts **out, const char *path, git_oid_t oid_type);
void git_grafts_free(git_grafts *grafts);
void git_grafts_clear(git_grafts *grafts);
int git_grafts_refresh(git_grafts *grafts);
int git_grafts_parse(git_grafts *grafts, const char *buf, size_t len);
int git_grafts_add(git_grafts *grafts, const git_oid *oid, git_array_oid_t parents);
int git_grafts_remove(git_grafts *grafts, const git_oid *oid);
int git_grafts_get(git_commit_graft **out, git_grafts *grafts, const git_oid *oid);
int git_grafts_oids(git_oid **out, size_t *out_len, git_grafts *grafts);
size_t git_grafts_size(git_grafts *grafts);
#endif
......@@ -13,6 +13,7 @@
#include "cache.h"
#include "common.h"
#include "filter.h"
#include "grafts.h"
#include "hash.h"
#include "index.h"
#include "merge_driver.h"
......
......@@ -108,15 +108,13 @@ int git_object__from_raw(
return 0;
}
int git_object__from_odb_object(
int git_object__init_from_odb_object(
git_object **object_out,
git_repository *repo,
git_odb_object *odb_obj,
git_object_t type)
{
int error;
size_t object_size;
git_object_def *def;
git_object *object = NULL;
GIT_ASSERT_ARG(object_out);
......@@ -143,6 +141,23 @@ int git_object__from_odb_object(
object->cached.size = odb_obj->cached.size;
object->repo = repo;
*object_out = object;
return 0;
}
int git_object__from_odb_object(
git_object **object_out,
git_repository *repo,
git_odb_object *odb_obj,
git_object_t type)
{
int error;
git_object_def *def;
git_object *object = NULL;
if ((error = git_object__init_from_odb_object(&object, repo, odb_obj, type)) < 0)
return error;
/* Parse raw object data */
def = &git_objects_table[odb_obj->cached.type];
GIT_ASSERT(def->free && def->parse);
......
......@@ -36,6 +36,12 @@ int git_object__from_raw(
git_object_t object_type,
git_oid_t oid_type);
int git_object__init_from_odb_object(
git_object **object_out,
git_repository *repo,
git_odb_object *odb_obj,
git_object_t type);
int git_object__from_odb_object(
git_object **object_out,
git_repository *repo,
......
......@@ -15,10 +15,17 @@ void git_oidarray_dispose(git_oidarray *arr)
git__free(arr->ids);
}
void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array)
void git_oidarray__from_array(git_oidarray *out, const git_array_oid_t *array)
{
arr->count = array->size;
arr->ids = array->ptr;
out->count = array->size;
out->ids = array->ptr;
}
void git_oidarray__to_array(git_array_oid_t *out, const git_oidarray *array)
{
out->ptr = array->ids;
out->size = array->count;
out->asize = array->count;
}
void git_oidarray__reverse(git_oidarray *arr)
......@@ -33,6 +40,45 @@ void git_oidarray__reverse(git_oidarray *arr)
}
}
int git_oidarray__add(git_array_oid_t *arr, git_oid *id)
{
git_oid *add, *iter;
size_t i;
git_array_foreach(*arr, i, iter) {
if (git_oid_cmp(iter, id) == 0)
return 0;
}
if ((add = git_array_alloc(*arr)) == NULL)
return -1;
git_oid_cpy(add, id);
return 0;
}
bool git_oidarray__remove(git_array_oid_t *arr, git_oid *id)
{
bool found = false;
size_t remain, i;
git_oid *iter;
git_array_foreach(*arr, i, iter) {
if (git_oid_cmp(iter, id) == 0) {
arr->size--;
remain = arr->size - i;
if (remain > 0)
memmove(&arr->ptr[i], &arr->ptr[i+1], remain * sizeof(git_oid));
found = true;
break;
}
}
return found;
}
#ifndef GIT_DEPRECATE_HARD
void git_oidarray_free(git_oidarray *arr)
......
......@@ -15,6 +15,10 @@
typedef git_array_t(git_oid) git_array_oid_t;
extern void git_oidarray__reverse(git_oidarray *arr);
extern void git_oidarray__from_array(git_oidarray *arr, git_array_oid_t *array);
extern void git_oidarray__from_array(git_oidarray *out, const git_array_oid_t *array);
extern void git_oidarray__to_array(git_array_oid_t *out, const git_oidarray *array);
int git_oidarray__add(git_array_oid_t *arr, git_oid *id);
bool git_oidarray__remove(git_array_oid_t *arr, git_oid *id);
#endif
......@@ -23,6 +23,7 @@
#include "git2/types.h"
#include "git2/oid.h"
#include "git2/net.h"
#include "transports/smart.h"
#define CONFIG_URL_FMT "remote.%s.url"
#define CONFIG_PUSHURL_FMT "remote.%s.pushurl"
......
......@@ -38,6 +38,7 @@ struct git_remote {
git_remote_autotag_option_t download_tags;
int prune_refs;
int passed_refspecs;
git_fetch_negotiation nego;
};
int git_remote__urlfordirection(git_str *url_out, struct git_remote *remote, int direction, const git_remote_callbacks *callbacks);
......
......@@ -15,6 +15,7 @@
#include "buf.h"
#include "common.h"
#include "commit.h"
#include "grafts.h"
#include "tag.h"
#include "blob.h"
#include "futils.h"
......@@ -151,6 +152,8 @@ int git_repository__cleanup(git_repository *repo)
git_repository_submodule_cache_clear(repo);
git_cache_clear(&repo->objects);
git_attr_cache_flush(repo);
git_grafts_free(repo->grafts);
git_grafts_free(repo->shallow_grafts);
set_config(repo, NULL);
set_index(repo, NULL);
......@@ -842,6 +845,27 @@ out:
return error;
}
static int load_grafts(git_repository *repo)
{
git_str path = GIT_STR_INIT;
int error;
if ((error = git_repository__item_path(&path, repo, GIT_REPOSITORY_ITEM_INFO)) < 0 ||
(error = git_str_joinpath(&path, path.ptr, "grafts")) < 0 ||
(error = git_grafts_open_or_refresh(&repo->grafts, path.ptr, repo->oid_type)) < 0)
goto error;
git_str_clear(&path);
if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 ||
(error = git_grafts_open_or_refresh(&repo->shallow_grafts, path.ptr, repo->oid_type)) < 0)
goto error;
error:
git_str_dispose(&path);
return error;
}
static int find_repo(
struct repo_paths *out,
const char *start_path,
......@@ -1075,6 +1099,9 @@ int git_repository_open_ext(
if (error < 0)
goto cleanup;
if ((error = load_grafts(repo)) < 0)
goto cleanup;
if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) {
repo->is_bare = 1;
} else {
......@@ -1604,6 +1631,22 @@ int git_repository_set_index(git_repository *repo, git_index *index)
return 0;
}
int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo)
{
GIT_ASSERT_ARG(out && repo);
GIT_ASSERT(repo->grafts);
*out = repo->grafts;
return 0;
}
int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo)
{
GIT_ASSERT_ARG(out && repo);
GIT_ASSERT(repo->shallow_grafts);
*out = repo->shallow_grafts;
return 0;
}
int git_repository_set_namespace(git_repository *repo, const char *namespace)
{
git__free(repo->namespace);
......@@ -3628,6 +3671,66 @@ int git_repository_state_cleanup(git_repository *repo)
return git_repository__cleanup_files(repo, state_files, ARRAY_SIZE(state_files));
}
int git_repository__shallow_roots(
git_oid **out,
size_t *out_len,
git_repository *repo)
{
int error = 0;
if (!repo->shallow_grafts && (error = load_grafts(repo)) < 0)
return error;
if ((error = git_grafts_refresh(repo->shallow_grafts)) < 0)
return error;
if ((error = git_grafts_oids(out, out_len, repo->shallow_grafts)) < 0)
return error;
return 0;
}
int git_repository__shallow_roots_write(git_repository *repo, git_oidarray *roots)
{
git_filebuf file = GIT_FILEBUF_INIT;
git_str path = GIT_STR_INIT;
char oid_str[GIT_OID_MAX_HEXSIZE + 1];
size_t i;
int filebuf_hash, error = 0;
GIT_ASSERT_ARG(repo);
filebuf_hash = git_filebuf_hash_flags(git_oid_algorithm(repo->oid_type));
GIT_ASSERT(filebuf_hash);
if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0)
goto on_error;
if ((error = git_filebuf_open(&file, git_str_cstr(&path), filebuf_hash, 0666)) < 0)
goto on_error;
for (i = 0; i < roots->count; i++) {
git_oid_tostr(oid_str, sizeof(oid_str), &roots->ids[i]);
git_filebuf_write(&file, oid_str, git_oid_hexsize(repo->oid_type));
git_filebuf_write(&file, "\n", 1);
}
git_filebuf_commit(&file);
if ((error = load_grafts(repo)) < 0) {
error = -1;
goto on_error;
}
if (!roots->count)
remove(path.ptr);
on_error:
git_str_dispose(&path);
return error;
}
int git_repository_is_shallow(git_repository *repo)
{
git_str path = GIT_STR_INIT;
......@@ -3647,6 +3750,7 @@ int git_repository_is_shallow(git_repository *repo)
if (error < 0)
return error;
return st.st_size == 0 ? 0 : 1;
}
......
......@@ -24,6 +24,7 @@
#include "attrcache.h"
#include "submodule.h"
#include "diff_driver.h"
#include "grafts.h"
#define DOT_GIT ".git"
#define GIT_DIR DOT_GIT "/"
......@@ -158,6 +159,9 @@ struct git_repository {
unsigned int lru_counter;
git_grafts *grafts;
git_grafts *shallow_grafts;
git_atomic32 attr_session_key;
intptr_t configmap_cache[GIT_CONFIGMAP_CACHE_MAX];
......@@ -189,6 +193,8 @@ int git_repository_config__weakptr(git_config **out, git_repository *repo);
int git_repository_odb__weakptr(git_odb **out, git_repository *repo);
int git_repository_refdb__weakptr(git_refdb **out, git_repository *repo);
int git_repository_index__weakptr(git_index **out, git_repository *repo);
int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo);
int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo);
int git_repository__wrap_odb(
git_repository **out,
......@@ -245,6 +251,9 @@ extern size_t git_repository__reserved_names_posix_len;
bool git_repository__reserved_names(
git_str **out, size_t *outlen, git_repository *repo, bool include_ntfs);
int git_repository__shallow_roots(git_oid **out, size_t *out_len, git_repository *repo);
int git_repository__shallow_roots_write(git_repository *repo, git_oidarray *roots);
/*
* The default branch for the repository; the `init.defaultBranch`
* configuration option, if set, or `master` if it is not.
......
......@@ -295,15 +295,13 @@ static int local_ls(const git_remote_head ***out, size_t *size, git_transport *t
static int local_negotiate_fetch(
git_transport *transport,
git_repository *repo,
const git_remote_head * const *refs,
size_t count)
const git_fetch_negotiation *wants)
{
transport_local *t = (transport_local*)transport;
git_remote_head *rhead;
unsigned int i;
GIT_UNUSED(refs);
GIT_UNUSED(count);
GIT_UNUSED(wants);
/* Fill in the loids */
git_vector_foreach(&t->refs, i, rhead) {
......@@ -322,6 +320,16 @@ static int local_negotiate_fetch(
return 0;
}
static int local_shallow_roots(
git_oidarray *out,
git_transport *transport)
{
GIT_UNUSED(out);
GIT_UNUSED(transport);
return 0;
}
static int local_push_update_remote_ref(
git_repository *remote_repo,
const char *lref,
......@@ -747,6 +755,7 @@ int git_transport_local(git_transport **out, git_remote *owner, void *param)
t->parent.oid_type = local_oid_type;
#endif
t->parent.negotiate_fetch = local_negotiate_fetch;
t->parent.shallow_roots = local_shallow_roots;
t->parent.download_pack = local_download_pack;
t->parent.push = local_push;
t->parent.close = local_close;
......
......@@ -416,6 +416,8 @@ static void git_smart__free(git_transport *transport)
git_remote_connect_options_dispose(&t->connect_opts);
git_array_dispose(t->shallow_roots);
git__free(t->caps.object_format);
git__free(t->caps.agent);
git__free(t);
......@@ -490,6 +492,7 @@ int git_transport_smart(git_transport **out, git_remote *owner, void *param)
t->parent.close = git_smart__close;
t->parent.free = git_smart__free;
t->parent.negotiate_fetch = git_smart__negotiate_fetch;
t->parent.shallow_roots = git_smart__shallow_roots;
t->parent.download_pack = git_smart__download_pack;
t->parent.push = git_smart__push;
t->parent.ls = git_smart__ls;
......
......@@ -14,6 +14,7 @@
#include "netops.h"
#include "push.h"
#include "str.h"
#include "oidarray.h"
#include "git2/sys/transport.h"
#define GIT_SIDE_BAND_DATA 1
......@@ -32,6 +33,7 @@
#define GIT_CAP_SYMREF "symref"
#define GIT_CAP_WANT_TIP_SHA1 "allow-tip-sha1-in-want"
#define GIT_CAP_WANT_REACHABLE_SHA1 "allow-reachable-sha1-in-want"
#define GIT_CAP_SHALLOW "shallow"
#define GIT_CAP_OBJECT_FORMAT "object-format="
#define GIT_CAP_AGENT "agent="
......@@ -50,7 +52,9 @@ typedef enum {
GIT_PKT_PROGRESS,
GIT_PKT_OK,
GIT_PKT_NG,
GIT_PKT_UNPACK
GIT_PKT_UNPACK,
GIT_PKT_SHALLOW,
GIT_PKT_UNSHALLOW
} git_pkt_type;
/* Used for multi_ack and multi_ack_detailed */
......@@ -122,6 +126,11 @@ typedef struct {
int unpack_ok;
} git_pkt_unpack;
typedef struct {
git_pkt_type type;
git_oid oid;
} git_pkt_shallow;
typedef struct transport_smart_caps {
unsigned int common:1,
ofs_delta:1,
......@@ -134,7 +143,8 @@ typedef struct transport_smart_caps {
report_status:1,
thin_pack:1,
want_tip_sha1:1,
want_reachable_sha1:1;
want_reachable_sha1:1,
shallow:1;
char *object_format;
char *agent;
} transport_smart_caps;
......@@ -153,6 +163,7 @@ typedef struct {
git_vector refs;
git_vector heads;
git_vector common;
git_array_oid_t shallow_roots;
git_atomic32 cancelled;
packetsize_cb packetsize_cb;
void *packetsize_payload;
......@@ -171,8 +182,9 @@ int git_smart__push(git_transport *transport, git_push *push);
int git_smart__negotiate_fetch(
git_transport *transport,
git_repository *repo,
const git_remote_head * const *refs,
size_t count);
const git_fetch_negotiation *wants);
int git_smart__shallow_roots(git_oidarray *out, git_transport *transport);
int git_smart__download_pack(
git_transport *transport,
......@@ -195,7 +207,7 @@ int git_pkt_parse_line(git_pkt **head, const char **endptr, const char *line, si
int git_pkt_buffer_flush(git_str *buf);
int git_pkt_send_flush(GIT_SOCKET s);
int git_pkt_buffer_done(git_str *buf);
int git_pkt_buffer_wants(const git_remote_head * const *refs, size_t count, transport_smart_caps *caps, git_str *buf);
int git_pkt_buffer_wants(const git_fetch_negotiation *wants, transport_smart_caps *caps, git_str *buf);
int git_pkt_buffer_have(git_oid *oid, git_str *buf);
void git_pkt_free(git_pkt *pkt);
......
......@@ -44,9 +44,16 @@ static int flush_pkt(git_pkt **out)
}
/* the rest of the line will be useful for multi_ack and multi_ack_detailed */
static int ack_pkt(git_pkt **out, const char *line, size_t len)
static int ack_pkt(
git_pkt **out,
const char *line,
size_t len,
git_pkt_parse_data *data)
{
git_pkt_ack *pkt;
size_t oid_hexsize = git_oid_hexsize(data->oid_type);
GIT_ASSERT(data && data->oid_type);
pkt = git__calloc(1, sizeof(git_pkt_ack));
GIT_ERROR_CHECK_ALLOC(pkt);
......@@ -57,11 +64,11 @@ static int ack_pkt(git_pkt **out, const char *line, size_t len)
line += 4;
len -= 4;
if (len < GIT_OID_SHA1_HEXSIZE ||
git_oid__fromstr(&pkt->oid, line, GIT_OID_SHA1) < 0)
if (len < oid_hexsize ||
git_oid__fromstr(&pkt->oid, line, data->oid_type) < 0)
goto out_err;
line += GIT_OID_SHA1_HEXSIZE;
len -= GIT_OID_SHA1_HEXSIZE;
line += oid_hexsize;
len -= oid_hexsize;
if (len && line[0] == ' ') {
line++;
......@@ -436,6 +443,84 @@ static int unpack_pkt(git_pkt **out, const char *line, size_t len)
return 0;
}
static int shallow_pkt(
git_pkt **out,
const char *line,
size_t len,
git_pkt_parse_data *data)
{
git_pkt_shallow *pkt;
size_t oid_hexsize = git_oid_hexsize(data->oid_type);
GIT_ASSERT(data && data->oid_type);
pkt = git__calloc(1, sizeof(git_pkt_shallow));
GIT_ERROR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_SHALLOW;
if (git__prefixncmp(line, len, "shallow "))
goto out_err;
line += 8;
len -= 8;
if (len != oid_hexsize)
goto out_err;
git_oid__fromstr(&pkt->oid, line, data->oid_type);
line += oid_hexsize + 1;
len -= oid_hexsize + 1;
*out = (git_pkt *)pkt;
return 0;
out_err:
git_error_set(GIT_ERROR_NET, "invalid packet line");
git__free(pkt);
return -1;
}
static int unshallow_pkt(
git_pkt **out,
const char *line,
size_t len,
git_pkt_parse_data *data)
{
git_pkt_shallow *pkt;
size_t oid_hexsize = git_oid_hexsize(data->oid_type);
GIT_ASSERT(data && data->oid_type);
pkt = git__calloc(1, sizeof(git_pkt_shallow));
GIT_ERROR_CHECK_ALLOC(pkt);
pkt->type = GIT_PKT_UNSHALLOW;
if (git__prefixncmp(line, len, "unshallow "))
goto out_err;
line += 10;
len -= 10;
if (len != oid_hexsize)
goto out_err;
git_oid__fromstr(&pkt->oid, line, data->oid_type);
line += oid_hexsize + 1;
len -= oid_hexsize + 1;
*out = (git_pkt *) pkt;
return 0;
out_err:
git_error_set(GIT_ERROR_NET, "invalid packet line");
git__free(pkt);
return -1;
}
static int parse_len(size_t *out, const char *line, size_t linelen)
{
char num[PKT_LEN_SIZE + 1];
......@@ -553,7 +638,7 @@ int git_pkt_parse_line(
else if (*line == GIT_SIDE_BAND_ERROR)
error = sideband_error_pkt(pkt, line, len);
else if (!git__prefixncmp(line, len, "ACK"))
error = ack_pkt(pkt, line, len);
error = ack_pkt(pkt, line, len, data);
else if (!git__prefixncmp(line, len, "NAK"))
error = nak_pkt(pkt);
else if (!git__prefixncmp(line, len, "ERR"))
......@@ -566,6 +651,10 @@ int git_pkt_parse_line(
error = ng_pkt(pkt, line, len);
else if (!git__prefixncmp(line, len, "unpack"))
error = unpack_pkt(pkt, line, len);
else if (!git__prefixcmp(line, "shallow"))
error = shallow_pkt(pkt, line, len, data);
else if (!git__prefixcmp(line, "unshallow"))
error = unshallow_pkt(pkt, line, len, data);
else
error = ref_pkt(pkt, line, len, data);
......@@ -638,6 +727,9 @@ static int buffer_want_with_caps(
if (caps->ofs_delta)
git_str_puts(&str, GIT_CAP_OFS_DELTA " ");
if (caps->shallow)
git_str_puts(&str, GIT_CAP_SHALLOW " ");
if (git_str_oom(&str))
return -1;
......@@ -668,8 +760,7 @@ static int buffer_want_with_caps(
*/
int git_pkt_buffer_wants(
const git_remote_head * const *refs,
size_t count,
const git_fetch_negotiation *wants,
transport_smart_caps *caps,
git_str *buf)
{
......@@ -679,7 +770,7 @@ int git_pkt_buffer_wants(
size_t oid_hexsize, want_len, i = 0;
#ifdef GIT_EXPERIMENTAL_SHA256
oid_type = count > 0 ? refs[0]->oid.type : GIT_OID_SHA1;
oid_type = wants->refs_len > 0 ? wants->refs[0]->oid.type : GIT_OID_SHA1;
#else
oid_type = GIT_OID_SHA1;
#endif
......@@ -690,20 +781,20 @@ int git_pkt_buffer_wants(
oid_hexsize + 1 /* LF */;
if (caps->common) {
for (; i < count; ++i) {
head = refs[i];
for (; i < wants->refs_len; ++i) {
head = wants->refs[i];
if (!head->local)
break;
}
if (buffer_want_with_caps(refs[i], caps, oid_type, buf) < 0)
if (buffer_want_with_caps(wants->refs[i], caps, oid_type, buf) < 0)
return -1;
i++;
}
for (; i < count; ++i) {
head = refs[i];
for (; i < wants->refs_len; ++i) {
head = wants->refs[i];
if (head->local)
continue;
......@@ -718,6 +809,36 @@ int git_pkt_buffer_wants(
return -1;
}
/* Tell the server about our shallow objects */
for (i = 0; i < wants->shallow_roots_len; i++) {
char oid[GIT_OID_MAX_HEXSIZE + 1];
git_str shallow_buf = GIT_STR_INIT;
git_oid_tostr(oid, GIT_OID_MAX_HEXSIZE + 1, &wants->shallow_roots[i]);
git_str_puts(&shallow_buf, "shallow ");
git_str_puts(&shallow_buf, oid);
git_str_putc(&shallow_buf, '\n');
git_str_printf(buf, "%04x%s", (unsigned int)git_str_len(&shallow_buf) + 4, git_str_cstr(&shallow_buf));
git_str_dispose(&shallow_buf);
if (git_str_oom(buf))
return -1;
}
if (wants->depth > 0) {
git_str deepen_buf = GIT_STR_INIT;
git_str_printf(&deepen_buf, "deepen %d\n", wants->depth);
git_str_printf(buf,"%04x%s", (unsigned int)git_str_len(&deepen_buf) + 4, git_str_cstr(&deepen_buf));
git_str_dispose(&deepen_buf);
if (git_str_oom(buf))
return -1;
}
return git_pkt_buffer_flush(buf);
}
......
......@@ -243,6 +243,12 @@ int git_smart__detect_caps(
continue;
}
if (!git__prefixcmp(ptr, GIT_CAP_SHALLOW)) {
caps->common = caps->shallow = 1;
ptr += strlen(GIT_CAP_SHALLOW);
continue;
}
/* We don't know this capability, so skip it */
ptr = strchr(ptr, ' ');
}
......@@ -250,13 +256,20 @@ int git_smart__detect_caps(
return 0;
}
static int recv_pkt(git_pkt **out_pkt, git_pkt_type *out_type, gitno_buffer *buf)
static int recv_pkt(
git_pkt **out_pkt,
git_pkt_type *out_type,
transport_smart *t,
gitno_buffer *buf)
{
const char *ptr = buf->data, *line_end = ptr;
git_pkt *pkt = NULL;
git_pkt_parse_data pkt_parse_data = { 0 };
int error = 0, ret;
pkt_parse_data.oid_type = t->owner->repo->oid_type;
pkt_parse_data.seen_capabilities = 1;
do {
if (buf->offset > 0)
error = git_pkt_parse_line(&pkt, &line_end, ptr, buf->offset, &pkt_parse_data);
......@@ -297,7 +310,7 @@ static int store_common(transport_smart *t)
int error;
do {
if ((error = recv_pkt(&pkt, NULL, buf)) < 0)
if ((error = recv_pkt(&pkt, NULL, t, buf)) < 0)
return error;
if (pkt->type != GIT_PKT_ACK) {
......@@ -314,7 +327,7 @@ static int store_common(transport_smart *t)
return 0;
}
static int wait_while_ack(gitno_buffer *buf)
static int wait_while_ack(transport_smart *t, gitno_buffer *buf)
{
int error;
git_pkt *pkt = NULL;
......@@ -323,7 +336,7 @@ static int wait_while_ack(gitno_buffer *buf)
while (1) {
git_pkt_free(pkt);
if ((error = recv_pkt(&pkt, NULL, buf)) < 0)
if ((error = recv_pkt(&pkt, NULL, t, buf)) < 0)
return error;
if (pkt->type == GIT_PKT_NAK)
......@@ -344,7 +357,48 @@ static int wait_while_ack(gitno_buffer *buf)
return 0;
}
int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, const git_remote_head * const *wants, size_t count)
static int cap_not_sup_err(const char *cap_name)
{
git_error_set(GIT_ERROR_NET, "server doesn't support %s", cap_name);
return GIT_EINVALID;
}
/* Disables server capabilities we're not interested in */
static int setup_caps(
transport_smart_caps *caps,
const git_fetch_negotiation *wants)
{
if (wants->depth > 0) {
if (!caps->shallow)
return cap_not_sup_err(GIT_CAP_SHALLOW);
} else {
caps->shallow = 0;
}
return 0;
}
static int setup_shallow_roots(
git_array_oid_t *out,
const git_fetch_negotiation *wants)
{
git_array_clear(*out);
if (wants->shallow_roots_len > 0) {
git_array_init_to_size(*out, wants->shallow_roots_len);
GIT_ERROR_CHECK_ALLOC(out->ptr);
memcpy(out->ptr, wants->shallow_roots,
sizeof(git_oid) * wants->shallow_roots_len);
}
return 0;
}
int git_smart__negotiate_fetch(
git_transport *transport,
git_repository *repo,
const git_fetch_negotiation *wants)
{
transport_smart *t = (transport_smart *)transport;
git_revwalk__push_options opts = GIT_REVWALK__PUSH_OPTIONS_INIT;
......@@ -356,7 +410,11 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
unsigned int i;
git_oid oid;
if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
if ((error = setup_caps(&t->caps, wants)) < 0 ||
(error = setup_shallow_roots(&t->shallow_roots, wants)) < 0)
return error;
if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
return error;
if ((error = git_revwalk_new(&walk, repo)) < 0)
......@@ -366,6 +424,37 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
if ((error = git_revwalk__push_glob(walk, "refs/*", &opts)) < 0)
goto on_error;
if (wants->depth > 0) {
git_pkt_shallow *pkt;
if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
goto on_error;
while ((error = recv_pkt((git_pkt **)&pkt, NULL, t, buf)) == 0) {
bool complete = false;
if (pkt->type == GIT_PKT_SHALLOW) {
error = git_oidarray__add(&t->shallow_roots, &pkt->oid);
} else if (pkt->type == GIT_PKT_UNSHALLOW) {
git_oidarray__remove(&t->shallow_roots, &pkt->oid);
} else if (pkt->type == GIT_PKT_FLUSH) {
/* Server is done, stop processing shallow oids */
complete = true;
} else {
git_error_set(GIT_ERROR_NET, "unexpected packet type");
error = -1;
}
git_pkt_free((git_pkt *) pkt);
if (complete || error < 0)
break;
}
if (error < 0)
goto on_error;
}
/*
* Our support for ACK extensions is simply to parse them. On
* the first ACK we will accept that as enough common
......@@ -406,7 +495,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
if ((error = store_common(t)) < 0)
goto on_error;
} else {
if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0)
if ((error = recv_pkt(NULL, &pkt_type, t, buf)) < 0)
goto on_error;
if (pkt_type == GIT_PKT_ACK) {
......@@ -428,7 +517,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_pkt_ack *pkt;
unsigned int j;
if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
goto on_error;
git_vector_foreach(&t->common, j, pkt) {
......@@ -448,7 +537,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
git_pkt_ack *pkt;
unsigned int j;
if ((error = git_pkt_buffer_wants(wants, count, &t->caps, &data)) < 0)
if ((error = git_pkt_buffer_wants(wants, &t->caps, &data)) < 0)
goto on_error;
git_vector_foreach(&t->common, j, pkt) {
......@@ -466,10 +555,11 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
goto on_error;
if (t->cancelled.val) {
git_error_set(GIT_ERROR_NET, "The fetch was cancelled by the user");
git_error_set(GIT_ERROR_NET, "the fetch was cancelled");
error = GIT_EUSER;
goto on_error;
}
if ((error = git_smart__negotiation_step(&t->parent, data.ptr, data.size)) < 0)
goto on_error;
......@@ -478,7 +568,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
/* Now let's eat up whatever the server gives us */
if (!t->caps.multi_ack && !t->caps.multi_ack_detailed) {
if ((error = recv_pkt(NULL, &pkt_type, buf)) < 0)
if ((error = recv_pkt(NULL, &pkt_type, t, buf)) < 0)
return error;
if (pkt_type != GIT_PKT_ACK && pkt_type != GIT_PKT_NAK) {
......@@ -486,7 +576,7 @@ int git_smart__negotiate_fetch(git_transport *transport, git_repository *repo, c
return -1;
}
} else {
error = wait_while_ack(buf);
error = wait_while_ack(t, buf);
}
return error;
......@@ -497,6 +587,25 @@ on_error:
return error;
}
int git_smart__shallow_roots(git_oidarray *out, git_transport *transport)
{
transport_smart *t = (transport_smart *)transport;
size_t len;
GIT_ERROR_CHECK_ALLOC_MULTIPLY(&len, t->shallow_roots.size, sizeof(git_oid));
out->count = t->shallow_roots.size;
if (len) {
out->ids = git__malloc(len);
memcpy(out->ids, t->shallow_roots.ptr, len);
} else {
out->ids = NULL;
}
return 0;
}
static int no_sideband(transport_smart *t, struct git_odb_writepack *writepack, gitno_buffer *buf, git_indexer_progress *stats)
{
int recvd;
......@@ -602,7 +711,7 @@ int git_smart__download_pack(
goto done;
}
if ((error = recv_pkt(&pkt, NULL, buf)) >= 0) {
if ((error = recv_pkt(&pkt, NULL, t, buf)) >= 0) {
/* Check cancellation after network call */
if (t->cancelled.val) {
git_error_clear();
......
......@@ -33,6 +33,9 @@
#define git_array_init_to_size(a, desired) \
do { (a).size = 0; (a).asize = desired; (a).ptr = git__calloc(desired, sizeof(*(a).ptr)); } while (0)
#define git_array_dispose(a) \
do { git__free((a).ptr); } while (0)
#define git_array_clear(a) \
do { git__free((a).ptr); git_array_init(a); } while (0)
......@@ -85,12 +88,14 @@ on_oom:
#define git_array_foreach(a, i, element) \
for ((i) = 0; (i) < (a).size && ((element) = &(a).ptr[(i)]); (i)++)
typedef int (*git_array_compare_cb)(const void *, const void *);
GIT_INLINE(int) git_array__search(
size_t *out,
void *array_ptr,
size_t item_size,
size_t array_len,
int (*compare)(const void *, const void *),
git_array_compare_cb compare,
const void *key)
{
size_t lim;
......
......@@ -221,14 +221,14 @@ int git_futils_readbuffer_fd_full(git_str *buf, git_file fd)
int git_futils_readbuffer_updated(
git_str *out,
const char *path,
unsigned char checksum[GIT_HASH_SHA1_SIZE],
unsigned char checksum[GIT_HASH_SHA256_SIZE],
int *updated)
{
int error;
git_file fd;
struct stat st;
git_str buf = GIT_STR_INIT;
unsigned char checksum_new[GIT_HASH_SHA1_SIZE];
unsigned char checksum_new[GIT_HASH_SHA256_SIZE];
GIT_ASSERT_ARG(out);
GIT_ASSERT_ARG(path && *path);
......@@ -261,7 +261,10 @@ int git_futils_readbuffer_updated(
p_close(fd);
if (checksum) {
if ((error = git_hash_buf(checksum_new, buf.ptr, buf.size, GIT_HASH_ALGORITHM_SHA1)) < 0) {
error = git_hash_buf(checksum_new, buf.ptr,
buf.size, GIT_HASH_ALGORITHM_SHA256);
if (error < 0) {
git_str_dispose(&buf);
return error;
}
......@@ -269,7 +272,7 @@ int git_futils_readbuffer_updated(
/*
* If we were given a checksum, we only want to use it if it's different
*/
if (!memcmp(checksum, checksum_new, GIT_HASH_SHA1_SIZE)) {
if (!memcmp(checksum, checksum_new, GIT_HASH_SHA256_SIZE)) {
git_str_dispose(&buf);
if (updated)
*updated = 0;
......@@ -277,7 +280,7 @@ int git_futils_readbuffer_updated(
return 0;
}
memcpy(checksum, checksum_new, GIT_HASH_SHA1_SIZE);
memcpy(checksum, checksum_new, GIT_HASH_SHA256_SIZE);
}
/*
......
#include "clar_libgit2.h"
#include "git2/oid.h"
#include "git2/transport.h"
#include "common.h"
#include "transports/smart.h"
#include "oid.h"
#include "oidarray.h"
#include <assert.h>
#define oid_0 "c070ad8c08840c8116da865b2d65593a6bb9cd2a"
#define oid_1 "0966a434eb1a025db6b71485ab63a3bfbea520b6"
#define oid_2 "83834a7afdaa1a1260568567f6ad90020389f664"
#define oid_3 "746fb4c91a7b6190bc4761adf7410afc4b59812c"
void test_core_oidarray__add_and_remove_oid_from_shallowarray(void)
{
git_oid oid_0_obj, oid_1_obj, oid_2_obj, oid_3_obj;
git_array_oid_t array = GIT_ARRAY_INIT;
git_oid__fromstr(&oid_0_obj, oid_0, GIT_OID_SHA1);
git_oid__fromstr(&oid_1_obj, oid_1, GIT_OID_SHA1);
git_oid__fromstr(&oid_2_obj, oid_2, GIT_OID_SHA1);
git_oid__fromstr(&oid_3_obj, oid_3, GIT_OID_SHA1);
/* add some initial ids */
git_oidarray__add(&array, &oid_0_obj);
git_oidarray__add(&array, &oid_1_obj);
git_oidarray__add(&array, &oid_2_obj);
cl_assert_equal_i(3, array.size);
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1]));
cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&array.ptr[2]));
/* don't duplicate existing ids */
git_oidarray__add(&array, &oid_1_obj);
cl_assert_equal_i(3, array.size);
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1]));
cl_assert_equal_s("83834a7afdaa1a1260568567f6ad90020389f664", git_oid_tostr_s(&array.ptr[2]));
/* remove the last id */
cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_2_obj));
cl_assert_equal_i(2, array.size);
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1]));
/* add another id */
git_oidarray__add(&array, &oid_3_obj);
cl_assert_equal_i(3, array.size);
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[1]));
cl_assert_equal_s("746fb4c91a7b6190bc4761adf7410afc4b59812c", git_oid_tostr_s(&array.ptr[2]));
/* remove the first id */
cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_0_obj));
cl_assert_equal_i(2, array.size);
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("746fb4c91a7b6190bc4761adf7410afc4b59812c", git_oid_tostr_s(&array.ptr[1]));
/* removing a nonexistent oid does nothing */
cl_assert_equal_i(0, git_oidarray__remove(&array, &oid_2_obj));
/* add another id */
git_oidarray__add(&array, &oid_0_obj);
cl_assert_equal_i(3, array.size);
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("746fb4c91a7b6190bc4761adf7410afc4b59812c", git_oid_tostr_s(&array.ptr[1]));
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[2]));
/* remove another id */
cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_3_obj));
cl_assert_equal_i(2, array.size);
cl_assert_equal_s("0966a434eb1a025db6b71485ab63a3bfbea520b6", git_oid_tostr_s(&array.ptr[0]));
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[1]));
/* remove another id */
cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_1_obj));
cl_assert_equal_i(1, array.size);
cl_assert_equal_s("c070ad8c08840c8116da865b2d65593a6bb9cd2a", git_oid_tostr_s(&array.ptr[0]));
/* remove the final id */
cl_assert_equal_i(1, git_oidarray__remove(&array, &oid_0_obj));
cl_assert_equal_i(0, array.size);
git_array_clear(array);
}
#include "clar_libgit2.h"
#include "futils.h"
#include "grafts.h"
static git_repository *g_repo;
void test_grafts_basic__initialize(void)
{
g_repo = cl_git_sandbox_init("grafted.git");
}
void test_grafts_basic__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_grafts_basic__graft_add(void)
{
git_array_oid_t parents = GIT_ARRAY_INIT;
git_oid oid_src, *oid1;
git_commit_graft *graft;
git_grafts *grafts;
cl_git_pass(git_grafts_new(&grafts, GIT_OID_SHA1));
cl_assert(oid1 = git_array_alloc(parents));
cl_git_pass(git_oid__fromstr(&oid_src, "2f3053cbff8a4ca2f0666de364ddb734a28a31a9", GIT_OID_SHA1));
git_oid_cpy(oid1, &oid_src);
git_oid__fromstr(&oid_src, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1);
cl_git_pass(git_grafts_add(grafts, &oid_src, parents));
git_array_clear(parents);
cl_assert_equal_i(1, git_grafts_size(grafts));
cl_git_pass(git_grafts_get(&graft, grafts, &oid_src));
cl_assert_equal_s("f503807ffa920e407a600cfaee96b7152259acc7", git_oid_tostr_s(&graft->oid));
cl_assert_equal_i(1, git_array_size(graft->parents));
cl_assert_equal_s("2f3053cbff8a4ca2f0666de364ddb734a28a31a9", git_oid_tostr_s(git_array_get(graft->parents, 0)));
git_grafts_free(grafts);
}
void test_grafts_basic__grafted_revwalk(void)
{
git_revwalk *w;
git_oid oids[10];
size_t i = 0;
git_commit *commit;
cl_git_pass(git_revwalk_new(&w, g_repo));
cl_git_pass(git_revwalk_push_ref(w, "refs/heads/branch"));
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[0]), "8a00e91619098618be97c0d2ceabb05a2c58edd9");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[1]), "f503807ffa920e407a600cfaee96b7152259acc7");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[2]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9");
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oids[0]));
cl_assert_equal_i(1, git_commit_parentcount(commit));
git_commit_free(commit);
git_revwalk_free(w);
}
void test_grafts_basic__grafted_objects(void)
{
git_oid oid;
git_commit *commit;
cl_git_pass(git_oid__fromstr(&oid, "f503807ffa920e407a600cfaee96b7152259acc7", GIT_OID_SHA1));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_assert_equal_i(1, git_commit_parentcount(commit));
git_commit_free(commit);
cl_git_pass(git_oid__fromstr(&oid, "0512adebd3782157f0d5c9b22b043f87b4aaff9e", GIT_OID_SHA1));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_assert_equal_i(1, git_commit_parentcount(commit));
git_commit_free(commit);
cl_git_pass(git_oid__fromstr(&oid, "66cc22a015f6ca75b34c82d28f78ba663876bade", GIT_OID_SHA1));
cl_git_pass(git_commit_lookup(&commit, g_repo, &oid));
cl_assert_equal_i(4, git_commit_parentcount(commit));
git_commit_free(commit);
}
void test_grafts_basic__grafted_merge_revwalk(void)
{
git_revwalk *w;
git_oid oids[10];
size_t i = 0;
cl_git_pass(git_revwalk_new(&w, g_repo));
cl_git_pass(git_revwalk_push_ref(w, "refs/heads/bottom"));
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "66cc22a015f6ca75b34c82d28f78ba663876bade");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "e414f42f4e6bc6934563a2349a8600f0ab68618e");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "8a00e91619098618be97c0d2ceabb05a2c58edd9");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "1c18e80a276611bb9b146590616bbc5aebdf2945");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "d7224d49d6d5aff6ade596ed74f4bcd4f77b29e2");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "0512adebd3782157f0d5c9b22b043f87b4aaff9e");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "f503807ffa920e407a600cfaee96b7152259acc7");
cl_git_pass(git_revwalk_next(&oids[i++], w));
cl_assert_equal_s(git_oid_tostr_s(&oids[i - 1]), "2f3053cbff8a4ca2f0666de364ddb734a28a31a9");
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oids[i++], w));
git_revwalk_free(w);
}
#include "clar_libgit2.h"
#include "grafts.h"
#define OID0 "c0368f9f9743e950e6cfe1f45a649f8a9dfcd97e"
#define OID1 "cfc50a0db87ce908fb8a8c5b8f7b4ab96eee8643"
#define OID2 "6914d97cd08b9edf5e855fca211c750fa82fd80a"
#define OID3 "516521937d0e9ce9d0d836149a0702671f326b4a"
#define OID4 "e2c29d67ef2f217650196f94c796f0532b8caad6"
#define OID5 "79bcb936596cb50353fe7be28b7444e66e4a2842"
#define OID6 "b9c54107d57c17dbcaf646c4d52f66eb9e69d23d"
#define OID7 "9f8a746e9ad7b58cc840016bc3944d5ad262acb5"
#define OID8 "392f4beef7d0d15b2bc5b1abe1a754eba0ec36da"
#define OID_TRUNCATED "392f4beef7d0d15b2bc5b1abe1a754eba0ec36d"
#define OID_NONHEX "9f8a746e9ax7b58cc840016bc3944d5ad262acb5"
static git_grafts *grafts;
void test_grafts_parse__initialize(void)
{
cl_git_pass(git_grafts_new(&grafts, GIT_OID_SHA1));
}
void test_grafts_parse__cleanup(void)
{
git_grafts_free(grafts);
grafts = NULL;
}
static void assert_parse_succeeds(git_grafts *grafts, const char *string, size_t n)
{
cl_git_pass(git_grafts_parse(grafts, string, strlen(string)));
cl_assert_equal_i(git_grafts_size(grafts), n);
}
static void assert_parse_fails(git_grafts *grafts, const char *string)
{
cl_git_fail(git_grafts_parse(grafts, string, strlen(string)));
}
static void assert_graft_contains(git_grafts *grafts, const char *graft, size_t n, ...)
{
git_commit_graft *commit;
git_oid oid;
va_list ap;
size_t i = 0;
cl_git_pass(git_oid__fromstr(&oid, graft, GIT_OID_SHA1));
cl_git_pass(git_grafts_get(&commit, grafts, &oid));
cl_assert_equal_oid(&commit->oid, &oid);
cl_assert_equal_i(commit->parents.size, n);
va_start(ap, n);
while (i < n) {
cl_git_pass(git_oid__fromstr(&oid, va_arg(ap, const char *), GIT_OID_SHA1));
cl_assert_equal_oid(&commit->parents.ptr[i], &oid);
i++;
}
va_end(ap);
}
void test_grafts_parse__single_oid(void)
{
assert_parse_succeeds(grafts, OID1, 1);
assert_graft_contains(grafts, OID1, 0);
}
void test_grafts_parse__single_oid_with_newline(void)
{
assert_parse_succeeds(grafts, OID1 "\n", 1);
assert_graft_contains(grafts, OID1, 0);
}
void test_grafts_parse__multiple_oids(void)
{
assert_parse_succeeds(grafts, OID1 "\n" OID2 "\n" OID3, 3);
assert_graft_contains(grafts, OID1, 0);
assert_graft_contains(grafts, OID2, 0);
assert_graft_contains(grafts, OID3, 0);
}
void test_grafts_parse__same_oid(void)
{
assert_parse_succeeds(grafts, OID1 "\n" OID1, 1);
assert_graft_contains(grafts, OID1, 0);
}
void test_grafts_parse__oid_with_parent(void)
{
assert_parse_succeeds(grafts, OID1 " " OID2, 1);
assert_graft_contains(grafts, OID1, 1, OID2);
}
void test_grafts_parse__oid_with_parent_and_newline(void)
{
assert_parse_succeeds(grafts, OID1 " " OID2 "\n", 1);
assert_graft_contains(grafts, OID1, 1, OID2);
}
void test_grafts_parse__oid_with_multiple_parents(void)
{
assert_parse_succeeds(grafts, OID1 " " OID2 " " OID3 " " OID4 " " OID5, 1);
assert_graft_contains(grafts, OID1, 4, OID2, OID3, OID4, OID5);
}
void test_grafts_parse__multiple_oids_with_multiple_parents(void)
{
assert_parse_succeeds(grafts,
OID1 " " OID2 " " OID3 " " OID4 " " OID5 "\n"
OID6 " " OID7 " " OID8 "\n" , 2);
assert_graft_contains(grafts, OID1, 4, OID2, OID3, OID4, OID5);
assert_graft_contains(grafts, OID6, 2, OID7, OID8);
}
void test_grafts_parse__multiple_spaces_fails(void)
{
assert_parse_fails(grafts, OID1 " " OID2);
}
void test_grafts_parse__trailing_space_fails(void)
{
assert_parse_fails(grafts, OID1 " " OID2 " ");
}
void test_grafts_parse__invalid_character_inbetween_fails(void)
{
assert_parse_fails(grafts, OID1 " x " OID2);
}
void test_grafts_parse__truncated_oid_fails(void)
{
assert_parse_fails(grafts, OID_TRUNCATED);
}
void test_grafts_parse__truncated_parent_fails(void)
{
assert_parse_fails(grafts, OID1 " " OID_TRUNCATED);
}
void test_grafts_parse__invalid_oid_fails(void)
{
assert_parse_fails(grafts, OID_NONHEX);
}
void test_grafts_parse__invalid_parent_fails(void)
{
assert_parse_fails(grafts, OID1 " " OID_NONHEX);
}
#include "clar_libgit2.h"
#include "futils.h"
#include "grafts.h"
#include "repository.h"
static git_repository *g_repo;
static git_oid g_shallow_oid;
void test_grafts_shallow__initialize(void)
{
cl_git_pass(git_oid__fromstr(&g_shallow_oid, "be3563ae3f795b2b4353bcce3a527ad0a4f7f644", GIT_OID_SHA1));
}
void test_grafts_shallow__cleanup(void)
{
cl_git_sandbox_cleanup();
}
void test_grafts_shallow__no_shallow_file(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
}
void test_grafts_shallow__empty_shallow_file(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_git_mkfile("testrepo.git/shallow", "");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
}
void test_grafts_shallow__shallow_repo(void)
{
g_repo = cl_git_sandbox_init("shallow.git");
cl_assert_equal_i(1, git_repository_is_shallow(g_repo));
}
void test_grafts_shallow__clears_errors(void)
{
g_repo = cl_git_sandbox_init("testrepo.git");
cl_assert_equal_i(0, git_repository_is_shallow(g_repo));
cl_assert_equal_p(NULL, git_error_last());
}
void test_grafts_shallow__shallow_oids(void)
{
git_commit_graft *graft;
git_grafts *grafts;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo));
cl_assert_equal_i(1, git_grafts_size(grafts));
cl_git_pass(git_grafts_get(&graft, grafts, &g_shallow_oid));
}
void test_grafts_shallow__cache_clearing(void)
{
git_commit_graft *graft;
git_grafts *grafts;
git_oid tmp_oid;
cl_git_pass(git_oid__fromstr(&tmp_oid, "0000000000000000000000000000000000000000", GIT_OID_SHA1));
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo));
cl_assert_equal_i(1, git_grafts_size(grafts));
cl_git_pass(git_grafts_get(&graft, grafts, &g_shallow_oid));
cl_git_mkfile("shallow.git/shallow",
"be3563ae3f795b2b4353bcce3a527ad0a4f7f644\n"
"0000000000000000000000000000000000000000\n"
);
cl_git_pass(git_grafts_refresh(grafts));
cl_assert_equal_i(2, git_grafts_size(grafts));
cl_git_pass(git_grafts_get(&graft, grafts, &g_shallow_oid));
cl_git_pass(git_grafts_get(&graft, grafts, &tmp_oid));
cl_git_pass(p_unlink("shallow.git/shallow"));
cl_git_pass(git_grafts_refresh(grafts));
cl_assert_equal_i(0, git_grafts_size(grafts));
}
void test_grafts_shallow__errors_on_borked(void)
{
git_grafts *grafts;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_mkfile("shallow.git/shallow", "lolno");
cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo));
cl_git_fail(git_grafts_refresh(grafts));
cl_assert_equal_i(0, git_grafts_size(grafts));
cl_git_mkfile("shallow.git/shallow", "lolno\n");
cl_git_pass(git_repository_shallow_grafts__weakptr(&grafts, g_repo));
cl_git_fail(git_grafts_refresh(grafts));
cl_assert_equal_i(0, git_grafts_size(grafts));
}
void test_grafts_shallow__revwalk_behavior(void)
{
git_revwalk *w;
git_oid oid_1, oid_2, oid_3;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_revwalk_new(&w, g_repo));
cl_git_pass(git_revwalk_push_head(w));
cl_git_pass(git_revwalk_next(&oid_1, w)); // a65fedf39aefe402d3bb6e24df4d4f5fe4547750
cl_git_pass(git_revwalk_next(&oid_2, w)); // be3563ae3f795b2b4353bcce3a527ad0a4f7f644
cl_git_fail_with(GIT_ITEROVER, git_revwalk_next(&oid_3, w));
cl_assert_equal_s(git_oid_tostr_s(&oid_1), "a65fedf39aefe402d3bb6e24df4d4f5fe4547750");
cl_assert_equal_s(git_oid_tostr_s(&oid_2), "be3563ae3f795b2b4353bcce3a527ad0a4f7f644");
git_revwalk_free(w);
}
void test_grafts_shallow__grafted_object(void)
{
git_commit *commit;
g_repo = cl_git_sandbox_init("shallow.git");
cl_git_pass(git_commit_lookup(&commit, g_repo, &g_shallow_oid));
cl_assert_equal_i(0, git_commit_parentcount(commit));
git_commit_free(commit);
}
#include "clar_libgit2.h"
#include "futils.h"
#include "repository.h"
static int remote_single_branch(git_remote **out, git_repository *repo, const char *name, const char *url, void *payload)
{
GIT_UNUSED(payload);
cl_git_pass(git_remote_create_with_fetchspec(out, repo, name, url, "+refs/heads/master:refs/remotes/origin/master"));
return 0;
}
void test_online_shallow__clone_depth_zero(void)
{
git_str path = GIT_STR_INIT;
git_repository *repo;
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
git_oid *roots;
size_t roots_len;
clone_opts.fetch_opts.depth = 0;
clone_opts.remote_cb = remote_single_branch;
git_str_joinpath(&path, clar_sandbox_path(), "shallowclone_0");
cl_git_pass(git_clone(&repo, "https://github.com/libgit2/TestGitRepository", git_str_cstr(&path), &clone_opts));
/* cloning with depth 0 results in a full clone. */
cl_assert_equal_b(false, git_repository_is_shallow(repo));
/* full clones do not have shallow roots. */
cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo));
cl_assert_equal_i(0, roots_len);
git__free(roots);
git_str_dispose(&path);
git_repository_free(repo);
}
void test_online_shallow__clone_depth_one(void)
{
git_str path = GIT_STR_INIT;
git_repository *repo;
git_revwalk *walk;
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
git_oid oid;
git_oid *roots;
size_t roots_len;
size_t num_commits = 0;
int error = 0;
clone_opts.fetch_opts.depth = 1;
clone_opts.remote_cb = remote_single_branch;
git_str_joinpath(&path, clar_sandbox_path(), "shallowclone_1");
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));
cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo));
cl_assert_equal_i(1, roots_len);
cl_assert_equal_s("49322bb17d3acc9146f98c97d078513228bbf3c0", git_oid_tostr_s(&roots[0]));
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, 1);
cl_assert_equal_i(error, GIT_ITEROVER);
git__free(roots);
git_str_dispose(&path);
git_revwalk_free(walk);
git_repository_free(repo);
}
void test_online_shallow__clone_depth_five(void)
{
git_str path = GIT_STR_INIT;
git_repository *repo;
git_revwalk *walk;
git_clone_options clone_opts = GIT_CLONE_OPTIONS_INIT;
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(), "shallowclone_5");
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));
cl_git_pass(git_repository__shallow_roots(&roots, &roots_len, repo));
cl_assert_equal_i(3, roots_len);
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[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, 13);
cl_assert_equal_i(error, GIT_ITEROVER);
git__free(roots);
git_str_dispose(&path);
git_revwalk_free(walk);
git_repository_free(repo);
}
void test_online_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.depth = GIT_FETCH_DEPTH_UNSHALLOW;
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);
}
......@@ -25,7 +25,7 @@ static void assert_data_pkt_parses(const char *line, const char *expected_data,
size_t linelen = strlen(line) + 1;
const char *endptr;
git_pkt_data *pkt;
git_pkt_parse_data pkt_parse_data = { 0 };
git_pkt_parse_data pkt_parse_data = { 1, GIT_OID_SHA1 };
cl_git_pass(git_pkt_parse_line((git_pkt **) &pkt, &endptr, line, linelen, &pkt_parse_data));
cl_assert_equal_i(pkt->type, GIT_PKT_DATA);
......@@ -71,7 +71,7 @@ static void assert_ack_parses(const char *line, const char *expected_oid, enum g
const char *endptr;
git_pkt_ack *pkt;
git_oid oid;
git_pkt_parse_data pkt_parse_data = { 0 };
git_pkt_parse_data pkt_parse_data = { 1, GIT_OID_SHA1 };
cl_git_pass(git_oid__fromstr(&oid, expected_oid, GIT_OID_SHA1));
......
[core]
repositoryformatversion = 0
filemode = true
bare = true
ignorecase = true
precomposeunicode = true
f503807ffa920e407a600cfaee96b7152259acc7 2f3053cbff8a4ca2f0666de364ddb734a28a31a9
0512adebd3782157f0d5c9b22b043f87b4aaff9e 2f3053cbff8a4ca2f0666de364ddb734a28a31a9
66cc22a015f6ca75b34c82d28f78ba663876bade e414f42f4e6bc6934563a2349a8600f0ab68618e 8a00e91619098618be97c0d2ceabb05a2c58edd9 1c18e80a276611bb9b146590616bbc5aebdf2945 2f3053cbff8a4ca2f0666de364ddb734a28a31a9
66cc22a015f6ca75b34c82d28f78ba663876bade
8a00e91619098618be97c0d2ceabb05a2c58edd9
2f3053cbff8a4ca2f0666de364ddb734a28a31a9
1c18e80a276611bb9b146590616bbc5aebdf2945
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