summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
authorYuang Li <yuangli88@hotmail.com>2022-07-29 09:36:14 +0100
committerGitHub <noreply@github.com>2022-07-29 09:36:14 +0100
commita491917f8e37108b6180590736d833095626b1ec (patch)
tree2802cfbafd3e7d94e6a3153848ed0edf3ac1aebc /src
parent7f46bfac14f0502711f8441348fd361175953fd5 (diff)
parent09acf6986513381316c8797c4529323bff8525a5 (diff)
downloadlibgit2-a491917f8e37108b6180590736d833095626b1ec.tar.gz
Merge pull request #5 from mathworks/shallow-clone-local
Shallow clone local
Diffstat (limited to 'src')
-rw-r--r--src/libgit2/commit.c43
-rw-r--r--src/libgit2/grafts.c246
-rw-r--r--src/libgit2/grafts.h37
-rw-r--r--src/libgit2/libgit2.c5
-rw-r--r--src/libgit2/repository.c41
-rw-r--r--src/libgit2/repository.h6
6 files changed, 370 insertions, 8 deletions
diff --git a/src/libgit2/commit.c b/src/libgit2/commit.c
index 114ae6fc9..75cc8837c 100644
--- a/src/libgit2/commit.c
+++ b/src/libgit2/commit.c
@@ -22,6 +22,7 @@
#include "object.h"
#include "array.h"
#include "oidarray.h"
+#include "grafts.h"
void git_commit__free(void *_commit)
{
@@ -421,13 +422,7 @@ static int commit_parse(git_commit *commit, const char *data, size_t size, unsig
buffer += tree_len;
}
- /*
- * TODO: commit grafts!
- */
-
- while (git_object__parse_oid_header(&parent_id,
- &buffer, buffer_end, "parent ",
- GIT_OID_SHA1) == 0) {
+ while (git_oid__parse(&parent_id, &buffer, buffer_end, "parent ") == 0) {
git_oid *new_id = git_array_alloc(commit->parent_ids);
GIT_ERROR_CHECK_ALLOC(new_id);
@@ -508,9 +503,41 @@ int git_commit__parse_raw(void *commit, const char *data, size_t size)
return commit_parse(commit, data, size, 0);
}
+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, unsigned int flags)
{
- return commit_parse(commit, git_odb_object_data(odb_obj), git_odb_object_size(odb_obj), flags);
+ 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), flags)) < 0)
+ return error;
+
+ if (!git_shallow__enabled)
+ return 0;
+
+ /* 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);
}
int git_commit__parse(void *_commit, git_odb_object *odb_obj)
diff --git a/src/libgit2/grafts.c b/src/libgit2/grafts.c
new file mode 100644
index 000000000..82be2a680
--- /dev/null
+++ b/src/libgit2/grafts.c
@@ -0,0 +1,246 @@
+/*
+ * 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 "oidarray.h"
+#include "parse.h"
+
+bool git_shallow__enabled = false;
+
+struct git_grafts {
+ /* Map of `git_commit_graft`s */
+ git_oidmap *commits;
+
+ /* File backing the graft. NULL if it's an in-memory graft */
+ char *path;
+ git_oid path_checksum;
+};
+
+int git_grafts_new(git_grafts **out)
+{
+ git_grafts *grafts;
+
+ grafts = git__calloc(1, sizeof(*grafts));
+ GIT_ERROR_CHECK_ALLOC(grafts);
+
+ if ((git_oidmap_new(&grafts->commits)) < 0) {
+ git__free(grafts);
+ return -1;
+ }
+
+ *out = grafts;
+ return 0;
+}
+
+int git_grafts_from_file(git_grafts **out, const char *path)
+{
+ git_grafts *grafts = NULL;
+ int error;
+
+ if ((error = git_grafts_new(&grafts)) < 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;
+}
+
+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;
+
+ assert(grafts);
+
+ 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;
+
+ assert(grafts);
+
+ if (!grafts->path)
+ return 0;
+
+ if ((error = git_futils_readbuffer_updated(&contents, grafts->path,
+ (grafts->path_checksum).id, &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 *content, size_t contentlen)
+{
+ 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, content, contentlen)) < 0)
+ goto error;
+
+ for (; parser.remain_len; git_parse_advance_line(&parser)) {
+ const char *line_start = parser.line, *line_end = parser.line + parser.line_len;
+ git_oid graft_oid;
+
+ if ((error = git_oid_fromstrn(&graft_oid, line_start, GIT_OID_HEXSZ)) < 0) {
+ git_error_set(GIT_ERROR_GRAFTS, "invalid graft OID at line %" PRIuZ, parser.line_num);
+ goto error;
+ }
+ line_start += GIT_OID_HEXSZ;
+
+ while (line_start < line_end && *line_start == ' ') {
+ git_oid *id = git_array_alloc(parents);
+ GIT_ERROR_CHECK_ALLOC(id);
+
+ if ((error = git_oid_fromstrn(id, ++line_start, GIT_OID_HEXSZ)) < 0) {
+ git_error_set(GIT_ERROR_GRAFTS, "invalid parent OID at line %" PRIuZ, parser.line_num);
+ goto error;
+ }
+
+ line_start += GIT_OID_HEXSZ;
+ }
+
+ 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;
+
+ assert(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;
+
+ assert(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)
+{
+ assert(out && grafts && oid);
+ if ((*out = git_oidmap_get(grafts->commits, oid)) == NULL)
+ return GIT_ENOTFOUND;
+ return 0;
+}
+
+int git_grafts_get_oids(git_oidarray *out, git_grafts *grafts)
+{
+ git_array_oid_t oids = GIT_ARRAY_INIT;
+ const git_oid *oid;
+ size_t i = 0;
+ int error;
+
+ assert(out && grafts);
+
+ while ((error = git_oidmap_iterate(NULL, grafts->commits, &i, &oid)) == 0) {
+ git_oid *cpy = git_array_alloc(oids);
+ GIT_ERROR_CHECK_ALLOC(cpy);
+ git_oid_cpy(cpy, oid);
+ }
+
+ git_oidarray__from_array(out, &oids);
+
+ return 0;
+}
+
+size_t git_grafts_size(git_grafts *grafts)
+{
+ return git_oidmap_size(grafts->commits);
+}
diff --git a/src/libgit2/grafts.h b/src/libgit2/grafts.h
new file mode 100644
index 000000000..fd9ef6736
--- /dev/null
+++ b/src/libgit2/grafts.h
@@ -0,0 +1,37 @@
+/*
+ * 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;
+
+extern bool git_shallow__enabled;
+
+int git_grafts_new(git_grafts **out);
+int git_grafts_from_file(git_grafts **out, const char *path);
+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 *content, size_t contentlen);
+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_get_oids(git_oidarray *out, git_grafts *grafts);
+size_t git_grafts_size(git_grafts *grafts);
+
+#endif
diff --git a/src/libgit2/libgit2.c b/src/libgit2/libgit2.c
index 2fda0722e..2537730cf 100644
--- a/src/libgit2/libgit2.c
+++ b/src/libgit2/libgit2.c
@@ -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"
@@ -414,6 +415,10 @@ int git_libgit2_opts(int key, ...)
git_repository__validate_ownership = (va_arg(ap, int) != 0);
break;
+ case GIT_OPT_ENABLE_SHALLOW:
+ git_shallow__enabled = (va_arg(ap, int) != 0);
+ break;
+
default:
git_error_set(GIT_ERROR_INVALID, "invalid option key");
error = -1;
diff --git a/src/libgit2/repository.c b/src/libgit2/repository.c
index 90ac91db9..761772d55 100644
--- a/src/libgit2/repository.c
+++ b/src/libgit2/repository.c
@@ -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"
@@ -150,6 +151,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);
@@ -727,6 +730,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_from_file(&repo->grafts, path.ptr)) < 0)
+ goto error;
+
+ git_str_clear(&path);
+
+ if ((error = git_str_joinpath(&path, repo->gitdir, "shallow")) < 0 ||
+ (error = git_grafts_from_file(&repo->shallow_grafts, path.ptr)) < 0)
+ goto error;
+
+error:
+ git_str_dispose(&path);
+ return error;
+}
+
int git_repository_open_bare(
git_repository **repo_ptr,
const char *bare_path)
@@ -1016,6 +1040,9 @@ int git_repository_open_ext(
if ((error = check_extensions(config, version)) < 0)
goto cleanup;
+ if (git_shallow__enabled && (error = load_grafts(repo)) < 0)
+ goto cleanup;
+
if ((flags & GIT_REPOSITORY_OPEN_BARE) != 0) {
repo->is_bare = 1;
} else {
@@ -1402,6 +1429,20 @@ int git_repository_set_index(git_repository *repo, git_index *index)
return 0;
}
+int git_repository_grafts__weakptr(git_grafts **out, git_repository *repo)
+{
+ assert(out && repo && repo->grafts);
+ *out = repo->grafts;
+ return 0;
+}
+
+int git_repository_shallow_grafts__weakptr(git_grafts **out, git_repository *repo)
+{
+ assert(out && repo && repo->shallow_grafts);
+ *out = repo->shallow_grafts;
+ return 0;
+}
+
int git_repository_set_namespace(git_repository *repo, const char *namespace)
{
git__free(repo->namespace);
diff --git a/src/libgit2/repository.h b/src/libgit2/repository.h
index a488f2bf2..3cca53b3e 100644
--- a/src/libgit2/repository.h
+++ b/src/libgit2/repository.h
@@ -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 "/"
@@ -156,6 +157,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];
@@ -187,6 +191,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);
/*
* Configuration map cache