summaryrefslogtreecommitdiff
path: root/fetch-pack.c
diff options
context:
space:
mode:
authorJunio C Hamano <gitster@pobox.com>2014-01-17 12:21:14 -0800
committerJunio C Hamano <gitster@pobox.com>2014-01-17 12:21:20 -0800
commit92251b1b5b5e53ac9de890105e2a2bd9d15e2ecb (patch)
treeed77d1e0ceaf2142ce14583a1b60c4af204571a0 /fetch-pack.c
parentd8cf714c0edf261a2bcc126fc240b10ed04a5b8d (diff)
parent3b32a7ca90b9c63f2306feb2a66b62b94c1a640f (diff)
downloadgit-92251b1b5b5e53ac9de890105e2a2bd9d15e2ecb.tar.gz
Merge branch 'nd/shallow-clone'
Fetching from a shallow-cloned repository used to be forbidden, primarily because the codepaths involved were not carefully vetted and we did not bother supporting such usage. This attempts to allow object transfer out of a shallow-cloned repository in a controlled way (i.e. the receiver become a shallow repository with truncated history). * nd/shallow-clone: (31 commits) t5537: fix incorrect expectation in test case 10 shallow: remove unused code send-pack.c: mark a file-local function static git-clone.txt: remove shallow clone limitations prune: clean .git/shallow after pruning objects clone: use git protocol for cloning shallow repo locally send-pack: support pushing from a shallow clone via http receive-pack: support pushing to a shallow clone via http smart-http: support shallow fetch/clone remote-curl: pass ref SHA-1 to fetch-pack as well send-pack: support pushing to a shallow clone receive-pack: allow pushes that update .git/shallow connected.c: add new variant that runs with --shallow-file add GIT_SHALLOW_FILE to propagate --shallow-file to subprocesses receive/send-pack: support pushing from a shallow clone receive-pack: reorder some code in unpack() fetch: add --update-shallow to accept refs that update .git/shallow upload-pack: make sure deepening preserves shallow roots fetch: support fetching from a shallow repository clone: support remote shallow repository ...
Diffstat (limited to 'fetch-pack.c')
-rw-r--r--fetch-pack.c131
1 files changed, 119 insertions, 12 deletions
diff --git a/fetch-pack.c b/fetch-pack.c
index 760ed16e79..d52de74c4b 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;
@@ -309,7 +310,7 @@ static int find_common(struct fetch_pack_args *args,
}
if (is_repository_shallow())
- write_shallow_commits(&req_buf, 1);
+ write_shallow_commits(&req_buf, 1, NULL);
if (args->depth > 0)
packet_buf_write(&req_buf, "deepen %d", args->depth);
packet_buf_flush(&req_buf);
@@ -772,6 +773,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);
@@ -848,7 +850,10 @@ static struct ref *do_fetch_pack(struct fetch_pack_args *args,
if (args->stateless_rpc)
packet_flush(fd[1]);
if (args->depth > 0)
- setup_alternate_shallow(&shallow_lock, &alternate_shallow_file);
+ setup_alternate_shallow(&shallow_lock, &alternate_shallow_file,
+ NULL);
+ else if (si->nr_ours || si->nr_theirs)
+ alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
@@ -922,14 +927,121 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr)
return dst;
}
+static void update_shallow(struct fetch_pack_args *args,
+ struct ref **sought, int nr_sought,
+ struct shallow_info *si)
+{
+ struct sha1_array ref = SHA1_ARRAY_INIT;
+ int *status;
+ int i;
+
+ if (args->depth > 0 && alternate_shallow_file) {
+ if (*alternate_shallow_file == '\0') { /* --unshallow */
+ unlink_or_warn(git_path("shallow"));
+ rollback_lock_file(&shallow_lock);
+ } else
+ 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;
+ }
+
+ if (!si->nr_ours && !si->nr_theirs)
+ return;
+
+ remove_nonexistent_theirs_shallow(si);
+ if (!si->nr_ours && !si->nr_theirs)
+ return;
+ for (i = 0; i < nr_sought; i++)
+ sha1_array_append(&ref, sought[i]->old_sha1);
+ si->ref = &ref;
+
+ if (args->update_shallow) {
+ /*
+ * remote is also shallow, .git/shallow may be updated
+ * so all refs can be accepted. Make sure we only add
+ * shallow roots that are actually reachable from new
+ * refs.
+ */
+ struct sha1_array extra = SHA1_ARRAY_INIT;
+ unsigned char (*sha1)[20] = si->shallow->sha1;
+ assign_shallow_commits_to_refs(si, NULL, NULL);
+ if (!si->nr_ours && !si->nr_theirs) {
+ sha1_array_clear(&ref);
+ return;
+ }
+ for (i = 0; i < si->nr_ours; i++)
+ sha1_array_append(&extra, sha1[si->ours[i]]);
+ for (i = 0; i < si->nr_theirs; i++)
+ sha1_array_append(&extra, sha1[si->theirs[i]]);
+ setup_alternate_shallow(&shallow_lock,
+ &alternate_shallow_file,
+ &extra);
+ commit_lock_file(&shallow_lock);
+ sha1_array_clear(&extra);
+ sha1_array_clear(&ref);
+ return;
+ }
+
+ /*
+ * remote is also shallow, check what ref is safe to update
+ * without updating .git/shallow
+ */
+ status = xcalloc(nr_sought, sizeof(*status));
+ assign_shallow_commits_to_refs(si, NULL, status);
+ if (si->nr_ours || si->nr_theirs) {
+ for (i = 0; i < nr_sought; i++)
+ if (status[i])
+ sought[i]->status = REF_STATUS_REJECT_SHALLOW;
+ }
+ free(status);
+ sha1_array_clear(&ref);
+}
+
struct ref *fetch_pack(struct fetch_pack_args *args,
int fd[], struct child_process *conn,
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)
@@ -939,16 +1051,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);
-
- if (args->depth > 0 && alternate_shallow_file) {
- if (*alternate_shallow_file == '\0') { /* --unshallow */
- unlink_or_warn(git_path("shallow"));
- rollback_lock_file(&shallow_lock);
- } else
- commit_lock_file(&shallow_lock);
- }
-
+ 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, sought, nr_sought, &si);
+ clear_shallow_info(&si);
return ref_cpy;
}