summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/clone.c1
-rw-r--r--builtin/fetch-pack.c2
-rw-r--r--fetch-pack.c54
-rw-r--r--fetch-pack.h4
-rw-r--r--transport.c11
-rw-r--r--transport.h6
6 files changed, 71 insertions, 7 deletions
diff --git a/builtin/clone.c b/builtin/clone.c
index 900f56476a..0b182cefc2 100644
--- a/builtin/clone.c
+++ b/builtin/clone.c
@@ -889,6 +889,7 @@ int cmd_clone(int argc, const char **argv, const char *prefix)
remote = remote_get(option_origin);
transport = transport_get(remote, remote->url[0]);
+ transport->cloning = 1;
if (!transport->get_refs_list || (!is_local && !transport->fetch))
die(_("Don't know how to clone %s"), transport->url);
diff --git a/builtin/fetch-pack.c b/builtin/fetch-pack.c
index c1d918fe1b..927424b6b8 100644
--- a/builtin/fetch-pack.c
+++ b/builtin/fetch-pack.c
@@ -153,7 +153,7 @@ int cmd_fetch_pack(int argc, const char **argv, const char *prefix)
get_remote_heads(fd[0], NULL, 0, &ref, 0, NULL, NULL);
ref = fetch_pack(&args, fd, conn, ref, dest,
- sought, nr_sought, pack_lockfile_ptr);
+ sought, nr_sought, NULL, pack_lockfile_ptr);
if (pack_lockfile) {
printf("lock %s\n", pack_lockfile);
fflush(stdout);
diff --git a/fetch-pack.c b/fetch-pack.c
index 35d097e1b1..6c980cd39f 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -13,6 +13,7 @@
#include "transport.h"
#include "version.h"
#include "prio-queue.h"
+#include "sha1-array.h"
static int transfer_unpack_limit = -1;
static int fetch_unpack_limit = -1;
@@ -774,6 +775,7 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
int fd[2],
const struct ref *orig_ref,
struct ref **sought, int nr_sought,
+ struct shallow_info *si,
char **pack_lockfile)
{
struct ref *ref = copy_ref_list(orig_ref);
@@ -852,6 +854,8 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (args->depth > 0)
setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
NULL);
+ else if (args->cloning && si->shallow && si->shallow->nr)
+ alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
@@ -925,8 +929,11 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr)
return dst;
}
-static void update_shallow(struct fetch_pack_args *args)
+static void update_shallow(struct fetch_pack_args *args,
+ struct shallow_info *si)
{
+ int i;
+
if (args->depth > 0 && alternate_shallow_file) {
if (*alternate_shallow_file == '\0') { /* --unshallow */
unlink_or_warn(git_path("shallow"));
@@ -935,6 +942,42 @@ static void update_shallow(struct fetch_pack_args *args)
commit_lock_file(&shallow_lock);
return;
}
+
+ if (!si->shallow || !si->shallow->nr)
+ return;
+
+ if (alternate_shallow_file) {
+ /*
+ * The temporary shallow file is only useful for
+ * index-pack and unpack-objects because it may
+ * contain more roots than we want. Delete it.
+ */
+ if (*alternate_shallow_file)
+ unlink(alternate_shallow_file);
+ free((char *)alternate_shallow_file);
+ }
+
+ if (args->cloning) {
+ /*
+ * remote is shallow, but this is a clone, there are
+ * no objects in repo to worry about. Accept any
+ * shallow points that exist in the pack (iow in repo
+ * after get_pack() and reprepare_packed_git())
+ */
+ struct sha1_array extra = SHA1_ARRAY_INIT;
+ unsigned char (*sha1)[20] = si->shallow->sha1;
+ for (i = 0; i < si->shallow->nr; i++)
+ if (has_sha1_file(sha1[i]))
+ sha1_array_append(&extra, sha1[i]);
+ if (extra.nr) {
+ setup_alternate_shallow(&shallow_lock,
+ &alternate_shallow_file,
+ &extra);
+ commit_lock_file(&shallow_lock);
+ }
+ sha1_array_clear(&extra);
+ return;
+ }
}
struct ref *fetch_pack(struct fetch_pack_args *args,
@@ -942,9 +985,11 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
const struct ref *ref,
const char *dest,
struct ref **sought, int nr_sought,
+ struct sha1_array *shallow,
char **pack_lockfile)
{
struct ref *ref_cpy;
+ struct shallow_info si;
fetch_pack_setup();
if (nr_sought)
@@ -954,8 +999,11 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
packet_flush(fd[1]);
die("no matching remote head");
}
- ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought, pack_lockfile);
- update_shallow(args);
+ prepare_shallow_info(&si, shallow);
+ ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
+ &si, pack_lockfile);
reprepare_packed_git();
+ update_shallow(args, &si);
+ clear_shallow_info(&si);
return ref_cpy;
}
diff --git a/fetch-pack.h b/fetch-pack.h
index 9b08388edf..ce595376b7 100644
--- a/fetch-pack.h
+++ b/fetch-pack.h
@@ -4,6 +4,8 @@
#include "string-list.h"
#include "run-command.h"
+struct sha1_array;
+
struct fetch_pack_args {
const char *uploadpack;
int unpacklimit;
@@ -20,6 +22,7 @@ struct fetch_pack_args {
unsigned stateless_rpc:1;
unsigned check_self_contained_and_connected:1;
unsigned self_contained_and_connected:1;
+ unsigned cloning:1;
};
/*
@@ -33,6 +36,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
const char *dest,
struct ref **sought,
int nr_sought,
+ struct sha1_array *shallow,
char **pack_lockfile);
#endif
diff --git a/transport.c b/transport.c
index 90453df9c6..91c466742e 100644
--- a/transport.c
+++ b/transport.c
@@ -456,6 +456,7 @@ struct git_transport_data {
int fd[2];
unsigned got_remote_heads : 1;
struct sha1_array extra_have;
+ struct sha1_array shallow;
};
static int set_git_option(struct git_transport_options *opts,
@@ -512,7 +513,9 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
connect_setup(transport, for_push, 0);
get_remote_heads(data->fd[0], NULL, 0, &refs,
- for_push ? REF_NORMAL : 0, &data->extra_have, NULL);
+ for_push ? REF_NORMAL : 0,
+ &data->extra_have,
+ transport->cloning ? &data->shallow : NULL);
data->got_remote_heads = 1;
return refs;
@@ -539,17 +542,19 @@ static int fetch_refs_via_pack(struct transport *transport,
args.depth = data->options.depth;
args.check_self_contained_and_connected =
data->options.check_self_contained_and_connected;
+ args.cloning = transport->cloning;
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0,
- NULL, NULL);
+ NULL,
+ transport->cloning ? &data->shallow : NULL);
data->got_remote_heads = 1;
}
refs = fetch_pack(&args, data->fd, data->conn,
refs_tmp ? refs_tmp : transport->remote_refs,
- dest, to_fetch, nr_heads,
+ dest, to_fetch, nr_heads, &data->shallow,
&transport->pack_lockfile);
close(data->fd[0]);
close(data->fd[1]);
diff --git a/transport.h b/transport.h
index b3679bbdc7..59842d4994 100644
--- a/transport.h
+++ b/transport.h
@@ -35,6 +35,12 @@ struct transport {
*/
unsigned cannot_reuse : 1;
+ /*
+ * A hint from caller that it will be performing a clone, not
+ * normal fetch. IOW the repository is guaranteed empty.
+ */
+ unsigned cloning : 1;
+
/**
* Returns 0 if successful, positive if the option is not
* recognized or is inapplicable, and negative if the option