10000 Merge pull request #6557 from libgit2/ethomson/shallow · libgit2/libgit2@2bbcdee · GitHub
[go: up one dir, main page]

Skip to content

Commit 2bbcdee

Browse files
authored
Merge pull request #6557 from libgit2/ethomson/shallow
Shallow (#6396) with some fixes from review
2 parents 251408c + 437c5f5 commit 2bbcdee

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

60 files changed

+1628
-76
lines changed

include/git2/errors.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -109,7 +109,8 @@ typedef enum {
109109
GIT_ERROR_WORKTREE,
110110
GIT_ERROR_SHA,
111111
GIT_ERROR_HTTP,
112-
GIT_ERROR_INTERNAL
112+
GIT_ERROR_INTERNAL,
113+
GIT_ERROR_GRAFTS
113114
} git_error_t;
114115

115116
/**

include/git2/remote.h

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -702,6 +702,15 @@ typedef enum {
702702
GIT_REMOTE_DOWNLOAD_TAGS_ALL
703703
} git_remote_autotag_option_t;
704704

705+
/** Constants for fetch depth (shallowness of fetch). */
706+
typedef enum {
707+
/** The fetch is "full" (not shallow). This is the default. */
708+
GIT_FETCH_DEPTH_FULL = 0,
709+
710+
/** The fetch should "unshallow" and fetch missing data. */
711+
GIT_FETCH_DEPTH_UNSHALLOW = 2147483647
712+
} git_fetch_depth_t;
713+
705714
/**
706715
* Fetch options structure.
707716
*
@@ -743,6 +752,15 @@ typedef struct {
743752
*/
744753
git_proxy_options proxy_opts;
745754

755+
/**
756+
* Depth of the fetch to perform, or `GIT_FETCH_DEPTH_FULL`
757+
* (or `0`) for full history, or `GIT_FETCH_DEPTH_UNSHALLOW`
758+
* to "unshallow" a shallow repository.
759+
*
760+
* The default is full (`GIT_FETCH_DEPTH_FULL` or `0`).
761+
*/
762+
int depth;
763+
746764
/**
747765
* Whether to allow off-site redirects. If this is not
748766
* specified, the `http.followRedirects` configuration setting

include/git2/sys/transport.h

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,14 @@
2525

2626
GIT_BEGIN_DECL
2727

28+
typedef struct {
29+
const git_remote_head * const *refs;
30+
size_t refs_len;
31+
git_oid *shallow_roots;
32+
size_t shallow_roots_len;
33+
int depth;
34+
} git_fetch_negotiation;
35+
2836
struct git_transport {
2937
unsigned int version; /**< The struct version */
3038

@@ -96,8 +104,17 @@ struct git_transport {
96104
int GIT_CALLBACK(negotiate_fetch)(
97105
git_transport *transport,
98106
git_repository *repo,
99-
const git_remote_head * const *refs,
100-
size_t count);
107+
const git_fetch_negotiation *fetch_data);
108+
109+
/**
110+
* Return the shallow roots of the remote.
111+
*
112+
* This function may be called after a successful call to
113+
* `negotiate_fetch`.
114+
*/
115+
int GIT_CALLBACK(shallow_roots)(
116+
git_oidarray *out,
117+
git_transport *transport);
101118

102119
/**
103120
* Start downloading the packfile from the remote repository.

src/cli/cmd_clone.c

Lines changed: 22 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,7 @@
1818

1919
#define COMMAND_NAME "clone"
2020

21-
static char *branch, *remote_path, *local_path;
21+
static char *branch, *remote_path, *local_path, *depth;
2222
static int show_help, quiet, checkout = 1, bare;
2323
static bool local_path_exists;
2424
static cli_progress progress = CLI_PROGRESS_INIT;
@@ -36,6 +36,8 @@ static const cli_opt_spec opts[] = {
3636
CLI_OPT_USAGE_DEFAULT, NULL, "don't create a working directory" },
3737
{ CLI_OPT_TYPE_VALUE, "branch", 'b', &branch, 0,
3838
CLI_OPT_USAGE_DEFAULT, "name", "branch to check out" },
39+
{ CLI_OPT_TYPE_VALUE, "depth", 0, &depth, 0,
40+
CLI_OPT_USAGE_DEFAULT, "depth", "commit depth to check out " },
3941
{ CLI_OPT_TYPE_LITERAL },
4042
{ CLI_OPT_TYPE_ARG, "repository", 0, &remote_path, 0,
4143
CLI_OPT_USAGE_REQUIRED, "repository", "repository path" },
@@ -71,6 +73,22 @@ static char *compute_local_path(const char *orig_path)
7173
return local_path;
7274
}
7375

76+
static int compute_depth(const char *depth)
77+
{
78+
int64_t i;
79+
const char *endptr;
80+
81+
if (!depth)
82+
return 0;
83+
84+
if (git__strntol64(&i, depth, strlen(depth), &endptr, 10) < 0 || i < 0 || i > INT_MAX || *endptr) {
85+
fprintf(stderr, "fatal: depth '%s' is not valid.\n", depth);
86+
exit(128);
87+
}
88+
89+
return (int)i;
90+
}
91+
7492
static bool validate_local_path(const char *path)
7593
{
7694
if (!git_fs_path_exists(path))
@@ -127,11 +145,9 @@ int cmd_clone(int argc, char **argv)
127145
goto done;
128146
}
129147

130-
if (bare)
131-
clone_opts.bare = 1;
132-
133-
if (branch)
134-
clone_opts.checkout_branch = branch;
148+
clone_opts.bare = !!bare;
149+
clone_opts.checkout_branch = branch;
150+
clone_opts.fetch_opts.depth = compute_depth(depth);
135151

136152
if (!checkout)
137153
clone_opts.checkout_opts.checkout_strategy = GIT_CHECKOUT_NONE;

src/libgit2/clone.c

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -420,7 +420,9 @@ static int clone_into(
420420

421421
memcpy(&fetch_opts, opts, sizeof(git_fetch_options));
422422
fetch_opts.update_fetchhead = 0;
423-
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
423+
424+
if (!opts->depth)
425+
fetch_opts.download_tags = GIT_REMOTE_DOWNLOAD_TAGS_ALL;
424426

425427
if ((error = git_remote_connect_options__from_fetch_opts(&connect_opts, remote, &fetch_opts)) < 0)
426428
goto cleanup;

src/libgit2/commit.c

Lines changed: 31 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -22,6 +22,7 @@
2222
#include "object.h"
2323
#include "array.h"
2424
#include "oidarray.h"
25+
#include "grafts.h"
2526

2627
void git_commit__free(void *_commit)
2728
{
@@ -427,10 +428,6 @@ static int commit_parse(
427428
buffer += tree_len;
428429
}
429430

430-
/*
431-
* TODO: commit grafts!
432-
*/
433-
434431
while (git_object__parse_oid_header(&parent_id,
435432
&buffer, buffer_end, "parent ",
436433
opts->oid_type) == 0) {
@@ -532,16 +529,41 @@ int git_commit__parse_raw(
532529
return commit_parse(commit, data, size, &parse_options);
533530
}
534531

532+
static int assign_commit_parents_from_graft(git_commit *commit, git_commit_graft *graft) {
533+
size_t idx;
534+
git_oid *oid;
535+
536+
git_array_clear(commit->parent_ids);
537+
git_array_init_to_size(commit->parent_ids, git_array_size(graft->parents));
538+
git_array_foreach(graft->parents, idx, oid) {
539+
git_oid *id = git_array_alloc(commit->parent_ids);
540+
GIT_ERROR_CHECK_ALLOC(id);
541+
542+
git_oid_cpy(id, oid);
543+
}
544+
545+
return 0;
546+
}
547+
535548
int git_commit__parse_ext(
536549
git_commit *commit,
537550
git_odb_object *odb_obj,
538551
git_commit__parse_options *parse_opts)
539552
{
540-
return commit_parse(
541-
commit,
542-
git_odb_object_data(odb_obj),
543-
git_odb_object_size(odb_obj),
544-
parse_opts);
553+
git_repository *repo = git_object_owner((git_object *)commit);
554+
git_commit_graft *graft;
555+
int error;
556+
557+
if ((error = commit_parse(commit, git_odb_object_data(odb_obj),
558+
git_odb_object_size(odb_obj), parse_opts)) < 0)
559+
return error;
560+
561+
/* Perform necessary grafts */
562+
if (git_grafts_get(&graft, repo->grafts, git_odb_object_id(odb_obj)) != 0 &&
563+
git_grafts_get(&graft, repo->shallow_grafts, git_odb_object_id(odb_obj)) != 0)
564+
return 0;
565+
566+
return assign_commit_parents_from_graft(commit, graft);
545567
}
546568

547569
#define GIT_COMMIT_GETTER(_rvalue, _name, _return, _invalid) \

src/libgit2/fetch.c

Lines changed: 35 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@
2020
#include "netops.h"
2121
#include "repository.h"
2222
#include "refs.h"
23+
#include "transports/smart.h"
2324

2425
static int maybe_want(git_remote *remote, git_remote_head *head, git_refspec *tagspec, git_remote_autotag_option_t tagopt)
2526
{
@@ -59,8 +60,10 @@ static int mark_local(git_remote *remote)
5960
return -1;
6061

6162
git_vector_foreach(&remote->refs, i, head) {
62-
/* If we have the object, mark it so we don't ask for it */
63-
if (git_odb_exists(odb, &head->oid))
63+
/* If we have the object, mark it so we don't ask for it.
64+
However if we are unshallowing, we need to ask for it
65+
even though the head exists locally. */
66+
if (remote->nego.depth != INT_MAX && git_odb_exists(odb, &head->oid))
6467
head->local = 1;
6568
else
6669
remote->need_pack = 1;
@@ -166,9 +169,15 @@ static int filter_wants(git_remote *remote, const git_fetch_options *opts)
166169
int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
167170
{
168171
git_transport *t = remote->transport;
172+
int error;
169173

170174
remote->need_pack = 0;
171175

176+
if (opts) {
177+
GIT_ASSERT_ARG(opts->depth >= 0);
178+
remote->nego.depth = opts->depth;
179+
}
180+
172181
if (filter_wants(remote, opts) < 0)
173182
return -1;
174183

@@ -180,20 +189,40 @@ int git_fetch_negotiate(git_remote *remote, const git_fetch_options *opts)
180189
* Now we have everything set up so we can start tell the
181190
* server what we want and what we have.
182191
*/
183-
return t->negotiate_fetch(t,
192+
remote->nego.refs = (const git_remote_head * const *)remote->refs.contents;
193+
remote->nego.refs_len = remote->refs.length;
194+
195+
if (git_repository__shallow_roots(&remote->nego.shallow_roots,
196+
&remote->nego.shallow_roots_len,
197+
remote->repo) < 0)
198+
return -1;
199+
200+
error = t->negotiate_fetch(t,
184201
remote->repo,
185-
(const git_remote_head * const *)remote->refs.contents,
186-
remote->refs.length);
202+
&remote->nego);
203+
204+
git__free(remote->nego.shallow_roots);
205+
206+
return error;
187207
}
188208

189209
int git_fetch_download_pack(git_remote *remote)
190210
{
211+
git_oidarray shallow_roots = { NULL };
191212
git_transport *t = remote->transport;
213+
int error;
192214

193215
if (!remote->need_pack)
194216
return 0;
195217

196-
return t->download_pack(t, remote->repo, &remote->stats);
218+
if ((error = t->download_pack(t, remote->repo, &remote->stats)) != 0 ||
219+
(error = t->shallow_roots(&shallow_roots, t)) != 0)
220+
return error;
221+
222+
error = git_repository__shallow_roots_write(remote->repo, &shallow_roots);
223+
224+
git_oidarray_dispose(&shallow_roots);
225+
return error;
197226
}
198227

199228
int git_fetch_options_init(git_fetch_options *opts, unsigned int version)

0 commit comments

Comments
 (0)
0