summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--builtin/fetch.c9
-rw-r--r--fetch-pack.c32
-rw-r--r--remote.h1
-rwxr-xr-xt/t5537-fetch-shallow.sh128
-rw-r--r--transport.c11
5 files changed, 176 insertions, 5 deletions
diff --git a/builtin/fetch.c b/builtin/fetch.c
index bd7a10164f..7b41a7e388 100644
--- a/builtin/fetch.c
+++ b/builtin/fetch.c
@@ -405,6 +405,8 @@ static int iterate_ref_map(void *cb_data, unsigned char sha1[20])
struct ref **rm = cb_data;
struct ref *ref = *rm;
+ while (ref && ref->status == REF_STATUS_REJECT_SHALLOW)
+ ref = ref->next;
if (!ref)
return -1; /* end of the list */
*rm = ref->next;
@@ -451,6 +453,13 @@ static int store_updated_refs(const char *raw_url, const char *remote_name,
struct ref *ref = NULL;
const char *merge_status_marker = "";
+ if (rm->status == REF_STATUS_REJECT_SHALLOW) {
+ if (want_status == FETCH_HEAD_MERGE)
+ warning(_("reject %s because shallow roots are not allowed to be updated"),
+ rm->peer_ref ? rm->peer_ref->name : rm->name);
+ continue;
+ }
+
commit = lookup_commit_reference_gently(rm->old_sha1, 1);
if (!commit)
rm->fetch_head_status = FETCH_HEAD_NOT_FOR_MERGE;
diff --git a/fetch-pack.c b/fetch-pack.c
index 6c980cd39f..34c544d0ca 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -854,7 +854,7 @@ 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)
+ else if (si->nr_ours || si->nr_theirs)
alternate_shallow_file = setup_temporary_shallow(si->shallow);
else
alternate_shallow_file = NULL;
@@ -930,8 +930,11 @@ static int remove_duplicates_in_refs(struct ref **ref, int nr)
}
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) {
@@ -978,6 +981,31 @@ static void update_shallow(struct fetch_pack_args *args,
sha1_array_clear(&extra);
return;
}
+
+ if (!si->nr_ours && !si->nr_theirs)
+ return;
+
+ remove_nonexistent_theirs_shallow(si);
+ /* XXX remove_nonexistent_ours_in_pack() */
+ 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;
+
+ /*
+ * 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,
@@ -1003,7 +1031,7 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
&si, pack_lockfile);
reprepare_packed_git();
- update_shallow(args, &si);
+ update_shallow(args, sought, nr_sought, &si);
clear_shallow_info(&si);
return ref_cpy;
}
diff --git a/remote.h b/remote.h
index 5d217d5397..3498091e9a 100644
--- a/remote.h
+++ b/remote.h
@@ -109,6 +109,7 @@ struct ref {
REF_STATUS_REJECT_FETCH_FIRST,
REF_STATUS_REJECT_NEEDS_FORCE,
REF_STATUS_REJECT_STALE,
+ REF_STATUS_REJECT_SHALLOW,
REF_STATUS_UPTODATE,
REF_STATUS_REMOTE_REJECT,
REF_STATUS_EXPECTING_REPORT
diff --git a/t/t5537-fetch-shallow.sh b/t/t5537-fetch-shallow.sh
new file mode 100755
index 0000000000..d2110527ef
--- /dev/null
+++ b/t/t5537-fetch-shallow.sh
@@ -0,0 +1,128 @@
+#!/bin/sh
+
+test_description='fetch/clone from a shallow clone'
+
+. ./test-lib.sh
+
+commit() {
+ echo "$1" >tracked &&
+ git add tracked &&
+ git commit -m "$1"
+}
+
+test_expect_success 'setup' '
+ commit 1 &&
+ commit 2 &&
+ commit 3 &&
+ commit 4 &&
+ git config --global transfer.fsckObjects true
+'
+
+test_expect_success 'setup shallow clone' '
+ git clone --no-local --depth=2 .git shallow &&
+ git --git-dir=shallow/.git log --format=%s >actual &&
+ cat <<EOF >expect &&
+4
+3
+EOF
+ test_cmp expect actual
+'
+
+test_expect_success 'clone from shallow clone' '
+ git clone --no-local shallow shallow2 &&
+ (
+ cd shallow2 &&
+ git fsck &&
+ git log --format=%s >actual &&
+ cat <<EOF >expect &&
+4
+3
+EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'fetch from shallow clone' '
+ (
+ cd shallow &&
+ commit 5
+ ) &&
+ (
+ cd shallow2 &&
+ git fetch &&
+ git fsck &&
+ git log --format=%s origin/master >actual &&
+ cat <<EOF >expect &&
+5
+4
+3
+EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'fetch --depth from shallow clone' '
+ (
+ cd shallow &&
+ commit 6
+ ) &&
+ (
+ cd shallow2 &&
+ git fetch --depth=2 &&
+ git fsck &&
+ git log --format=%s origin/master >actual &&
+ cat <<EOF >expect &&
+6
+5
+EOF
+ test_cmp expect actual
+ )
+'
+
+test_expect_success 'fetch something upstream has but hidden by clients shallow boundaries' '
+ # the blob "1" is available in .git but hidden by the
+ # shallow2/.git/shallow and it should be resent
+ ! git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` >/dev/null &&
+ echo 1 >1.t &&
+ git add 1.t &&
+ git commit -m add-1-back &&
+ (
+ cd shallow2 &&
+ git fetch ../.git +refs/heads/master:refs/remotes/top/master &&
+ git fsck &&
+ git log --format=%s top/master >actual &&
+ cat <<EOF >expect &&
+add-1-back
+4
+3
+EOF
+ test_cmp expect actual
+ ) &&
+ git --git-dir=shallow2/.git cat-file blob `echo 1|git hash-object --stdin` >/dev/null
+
+'
+
+test_expect_success 'fetch that requires changes in .git/shallow is filtered' '
+ (
+ cd shallow &&
+ git checkout --orphan no-shallow &&
+ commit no-shallow
+ ) &&
+ git init notshallow &&
+ (
+ cd notshallow &&
+ git fetch ../shallow/.git refs/heads/*:refs/remotes/shallow/*&&
+ git for-each-ref --format="%(refname)" >actual.refs &&
+ cat <<EOF >expect.refs &&
+refs/remotes/shallow/no-shallow
+EOF
+ test_cmp expect.refs actual.refs &&
+ git log --format=%s shallow/no-shallow >actual &&
+ cat <<EOF >expect &&
+no-shallow
+EOF
+ test_cmp expect actual
+ )
+'
+
+test_done
diff --git a/transport.c b/transport.c
index 91c466742e..491360be2c 100644
--- a/transport.c
+++ b/transport.c
@@ -515,7 +515,7 @@ static struct ref *get_refs_via_connect(struct transport *transport, int for_pus
get_remote_heads(data->fd[0], NULL, 0, &refs,
for_push ? REF_NORMAL : 0,
&data->extra_have,
- transport->cloning ? &data->shallow : NULL);
+ &data->shallow);
data->got_remote_heads = 1;
return refs;
@@ -547,8 +547,7 @@ static int fetch_refs_via_pack(struct transport *transport,
if (!data->got_remote_heads) {
connect_setup(transport, 0, 0);
get_remote_heads(data->fd[0], NULL, 0, &refs_tmp, 0,
- NULL,
- transport->cloning ? &data->shallow : NULL);
+ NULL, &data->shallow);
data->got_remote_heads = 1;
}
@@ -720,6 +719,10 @@ static int print_one_push_status(struct ref *ref, const char *dest, int count, i
print_ref_status('!', "[rejected]", ref, ref->peer_ref,
"stale info", porcelain);
break;
+ case REF_STATUS_REJECT_SHALLOW:
+ print_ref_status('!', "[rejected]", ref, ref->peer_ref,
+ "new shallow roots not allowed", porcelain);
+ break;
case REF_STATUS_REMOTE_REJECT:
print_ref_status('!', "[remote rejected]", ref,
ref->deletion ? NULL : ref->peer_ref,
@@ -815,6 +818,8 @@ static int git_transport_push(struct transport *transport, struct ref *remote_re
get_remote_heads(data->fd[0], NULL, 0, &tmp_refs, REF_NORMAL, NULL, NULL);
data->got_remote_heads = 1;
}
+ if (data->shallow.nr)
+ die("pushing to a shallow repository is not supported");
memset(&args, 0, sizeof(args));
args.send_mirror = !!(flags & TRANSPORT_PUSH_MIRROR);