mirror of
https://github.com/git/git.git
synced 2024-05-08 22:36:10 +02:00
support fetching into a shallow repository
A shallow commit is a commit which has parents, which in turn are "grafted away", i.e. the commit appears as if it were a root. Since these shallow commits should not be edited by the user, but only by core git, they are recorded in the file $GIT_DIR/shallow. A repository containing shallow commits is called shallow. The advantage of a shallow repository is that even if the upstream contains lots of history, your local (shallow) repository needs not occupy much disk space. The disadvantage is that you might miss a merge base when pulling some remote branch. Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <junkio@cox.net>
This commit is contained in:
parent
9b8dc263e1
commit
ed09aef06f
2
Makefile
2
Makefile
|
@ -260,7 +260,7 @@ LIB_OBJS = \
|
||||||
revision.o pager.o tree-walk.o xdiff-interface.o \
|
revision.o pager.o tree-walk.o xdiff-interface.o \
|
||||||
write_or_die.o trace.o list-objects.o grep.o \
|
write_or_die.o trace.o list-objects.o grep.o \
|
||||||
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
alloc.o merge-file.o path-list.o help.o unpack-trees.o $(DIFF_OBJS) \
|
||||||
color.o wt-status.o archive-zip.o archive-tar.o
|
color.o wt-status.o archive-zip.o archive-tar.o shallow.o
|
||||||
|
|
||||||
BUILTIN_OBJS = \
|
BUILTIN_OBJS = \
|
||||||
builtin-add.o \
|
builtin-add.o \
|
||||||
|
|
21
commit.c
21
commit.c
|
@ -1,6 +1,7 @@
|
||||||
#include "cache.h"
|
#include "cache.h"
|
||||||
#include "tag.h"
|
#include "tag.h"
|
||||||
#include "commit.h"
|
#include "commit.h"
|
||||||
|
#include "pkt-line.h"
|
||||||
|
|
||||||
int save_commit_buffer = 1;
|
int save_commit_buffer = 1;
|
||||||
|
|
||||||
|
@ -221,6 +222,8 @@ static void prepare_commit_graft(void)
|
||||||
return;
|
return;
|
||||||
graft_file = get_graft_file();
|
graft_file = get_graft_file();
|
||||||
read_graft_file(graft_file);
|
read_graft_file(graft_file);
|
||||||
|
/* make sure shallows are read */
|
||||||
|
is_repository_shallow();
|
||||||
commit_graft_prepared = 1;
|
commit_graft_prepared = 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -234,6 +237,24 @@ static struct commit_graft *lookup_commit_graft(const unsigned char *sha1)
|
||||||
return commit_graft[pos];
|
return commit_graft[pos];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int write_shallow_commits(int fd, int use_pack_protocol)
|
||||||
|
{
|
||||||
|
int i, count = 0;
|
||||||
|
for (i = 0; i < commit_graft_nr; i++)
|
||||||
|
if (commit_graft[i]->nr_parent < 0) {
|
||||||
|
const char *hex =
|
||||||
|
sha1_to_hex(commit_graft[i]->sha1);
|
||||||
|
count++;
|
||||||
|
if (use_pack_protocol)
|
||||||
|
packet_write(fd, "shallow %s", hex);
|
||||||
|
else {
|
||||||
|
write(fd, hex, 40);
|
||||||
|
write(fd, "\n", 1);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
|
||||||
int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
|
int parse_commit_buffer(struct commit *item, void *buffer, unsigned long size)
|
||||||
{
|
{
|
||||||
char *tail = buffer;
|
char *tail = buffer;
|
||||||
|
|
8
commit.h
8
commit.h
|
@ -97,7 +97,7 @@ void sort_in_topological_order_fn(struct commit_list ** list, int lifo,
|
||||||
|
|
||||||
struct commit_graft {
|
struct commit_graft {
|
||||||
unsigned char sha1[20];
|
unsigned char sha1[20];
|
||||||
int nr_parent;
|
int nr_parent; /* < 0 if shallow commit */
|
||||||
unsigned char parent[FLEX_ARRAY][20]; /* more */
|
unsigned char parent[FLEX_ARRAY][20]; /* more */
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -107,4 +107,10 @@ int read_graft_file(const char *graft_file);
|
||||||
|
|
||||||
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
|
extern struct commit_list *get_merge_bases(struct commit *rev1, struct commit *rev2, int cleanup);
|
||||||
|
|
||||||
|
extern int register_shallow(const unsigned char *sha1);
|
||||||
|
extern int write_shallow_commits(int fd, int use_pack_protocol);
|
||||||
|
extern int is_repository_shallow();
|
||||||
|
extern struct commit_list *get_shallow_commits(struct object_array *heads,
|
||||||
|
int depth);
|
||||||
|
|
||||||
#endif /* COMMIT_H */
|
#endif /* COMMIT_H */
|
||||||
|
|
|
@ -180,6 +180,8 @@ static int find_common(int fd[2], unsigned char *result_sha1,
|
||||||
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
|
packet_write(fd[1], "want %s\n", sha1_to_hex(remote));
|
||||||
fetching++;
|
fetching++;
|
||||||
}
|
}
|
||||||
|
if (is_repository_shallow())
|
||||||
|
write_shallow_commits(fd[1], 1);
|
||||||
packet_flush(fd[1]);
|
packet_flush(fd[1]);
|
||||||
if (!fetching)
|
if (!fetching)
|
||||||
return 1;
|
return 1;
|
||||||
|
@ -523,6 +525,8 @@ static int fetch_pack(int fd[2], int nr_match, char **match)
|
||||||
int status;
|
int status;
|
||||||
|
|
||||||
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
get_remote_heads(fd[0], &ref, 0, NULL, 0);
|
||||||
|
if (is_repository_shallow() && !server_supports("shallow"))
|
||||||
|
die("Server does not support shallow clients");
|
||||||
if (server_supports("multi_ack")) {
|
if (server_supports("multi_ack")) {
|
||||||
if (verbose)
|
if (verbose)
|
||||||
fprintf(stderr, "Server supports multi_ack\n");
|
fprintf(stderr, "Server supports multi_ack\n");
|
||||||
|
|
|
@ -0,0 +1,97 @@
|
||||||
|
#include "cache.h"
|
||||||
|
#include "commit.h"
|
||||||
|
|
||||||
|
static int is_shallow = -1;
|
||||||
|
|
||||||
|
int register_shallow(const unsigned char *sha1)
|
||||||
|
{
|
||||||
|
struct commit_graft *graft =
|
||||||
|
xmalloc(sizeof(struct commit_graft));
|
||||||
|
struct commit *commit = lookup_commit(sha1);
|
||||||
|
|
||||||
|
hashcpy(graft->sha1, sha1);
|
||||||
|
graft->nr_parent = -1;
|
||||||
|
if (commit && commit->object.parsed)
|
||||||
|
commit->parents = NULL;
|
||||||
|
return register_commit_graft(graft, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int is_repository_shallow()
|
||||||
|
{
|
||||||
|
FILE *fp;
|
||||||
|
char buf[1024];
|
||||||
|
|
||||||
|
if (is_shallow >= 0)
|
||||||
|
return is_shallow;
|
||||||
|
|
||||||
|
fp = fopen(git_path("shallow"), "r");
|
||||||
|
if (!fp) {
|
||||||
|
is_shallow = 0;
|
||||||
|
return is_shallow;
|
||||||
|
}
|
||||||
|
is_shallow = 1;
|
||||||
|
|
||||||
|
while (fgets(buf, sizeof(buf), fp)) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
if (get_sha1_hex(buf, sha1))
|
||||||
|
die("bad shallow line: %s", buf);
|
||||||
|
register_shallow(sha1);
|
||||||
|
}
|
||||||
|
fclose(fp);
|
||||||
|
return is_shallow;
|
||||||
|
}
|
||||||
|
|
||||||
|
struct commit_list *get_shallow_commits(struct object_array *heads, int depth)
|
||||||
|
{
|
||||||
|
int i = 0, cur_depth = 0;
|
||||||
|
struct commit_list *result = NULL;
|
||||||
|
struct object_array stack = {0, 0, NULL};
|
||||||
|
struct commit *commit = NULL;
|
||||||
|
|
||||||
|
while (commit || i < heads->nr || stack.nr) {
|
||||||
|
struct commit_list *p;
|
||||||
|
if (!commit) {
|
||||||
|
if (i < heads->nr) {
|
||||||
|
commit = (struct commit *)
|
||||||
|
heads->objects[i++].item;
|
||||||
|
if (commit->object.type != OBJ_COMMIT) {
|
||||||
|
commit = NULL;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
commit->util = xcalloc(1, sizeof(int));
|
||||||
|
cur_depth = 0;
|
||||||
|
} else {
|
||||||
|
commit = (struct commit *)
|
||||||
|
stack.objects[--stack.nr].item;
|
||||||
|
cur_depth = *(int *)commit->util;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
parse_commit(commit);
|
||||||
|
cur_depth++;
|
||||||
|
for (p = commit->parents, commit = NULL; p; p = p->next) {
|
||||||
|
if (!p->item->util) {
|
||||||
|
int *pointer = xmalloc(sizeof(int));
|
||||||
|
p->item->util = pointer;
|
||||||
|
*pointer = cur_depth;
|
||||||
|
} else {
|
||||||
|
int *pointer = p->item->util;
|
||||||
|
if (cur_depth >= *pointer)
|
||||||
|
continue;
|
||||||
|
*pointer = cur_depth;
|
||||||
|
}
|
||||||
|
if (cur_depth < depth) {
|
||||||
|
if (p->next)
|
||||||
|
add_object_array(&p->item->object,
|
||||||
|
NULL, &stack);
|
||||||
|
else {
|
||||||
|
commit = p->item;
|
||||||
|
cur_depth = *(int *)commit->util;
|
||||||
|
}
|
||||||
|
} else
|
||||||
|
commit_list_insert(p->item, &result);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
|
@ -486,6 +486,7 @@ static int get_common_commits(void)
|
||||||
|
|
||||||
static void receive_needs(void)
|
static void receive_needs(void)
|
||||||
{
|
{
|
||||||
|
struct object_array shallows = {0, 0, NULL};
|
||||||
static char line[1000];
|
static char line[1000];
|
||||||
int len;
|
int len;
|
||||||
|
|
||||||
|
@ -495,8 +496,19 @@ static void receive_needs(void)
|
||||||
len = packet_read_line(0, line, sizeof(line));
|
len = packet_read_line(0, line, sizeof(line));
|
||||||
reset_timeout();
|
reset_timeout();
|
||||||
if (!len)
|
if (!len)
|
||||||
return;
|
break;
|
||||||
|
|
||||||
|
if (!strncmp("shallow ", line, 8)) {
|
||||||
|
unsigned char sha1[20];
|
||||||
|
struct object *object;
|
||||||
|
if (get_sha1(line + 8, sha1))
|
||||||
|
die("invalid shallow line: %s", line);
|
||||||
|
object = parse_object(sha1);
|
||||||
|
if (!object)
|
||||||
|
die("did not find object for %s", line);
|
||||||
|
add_object_array(object, NULL, &shallows);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
if (strncmp("want ", line, 5) ||
|
if (strncmp("want ", line, 5) ||
|
||||||
get_sha1_hex(line+5, sha1_buf))
|
get_sha1_hex(line+5, sha1_buf))
|
||||||
die("git-upload-pack: protocol error, "
|
die("git-upload-pack: protocol error, "
|
||||||
|
@ -528,11 +540,17 @@ static void receive_needs(void)
|
||||||
add_object_array(o, NULL, &want_obj);
|
add_object_array(o, NULL, &want_obj);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (shallows.nr > 0) {
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < shallows.nr; i++)
|
||||||
|
register_shallow(shallows.objects[i].item->sha1);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
static int send_ref(const char *refname, const unsigned char *sha1, int flag, void *cb_data)
|
||||||
{
|
{
|
||||||
static const char *capabilities = "multi_ack thin-pack side-band side-band-64k ofs-delta";
|
static const char *capabilities = "multi_ack thin-pack side-band"
|
||||||
|
" side-band-64k ofs-delta shallow";
|
||||||
struct object *o = parse_object(sha1);
|
struct object *o = parse_object(sha1);
|
||||||
|
|
||||||
if (!o)
|
if (!o)
|
||||||
|
|
Loading…
Reference in New Issue