зеркало из https://github.com/microsoft/git.git
fetch: support fetching from a shallow repository
This patch just put together pieces from the 8 steps patch. We stop at step 7 and reject refs that require new shallow commits. Note that, by rejecting refs that require new shallow commits, we leave dangling objects in the repo, which become "object islands" by the next "git fetch" of the same source. If the first fetch our "ours" set is zero and we do practically nothing at step 7, "ours" is full at the next fetch and we may need to walk through commits for reachability test. Room for improvement. Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
This commit is contained in:
Родитель
beea4152d9
Коммит
4820a33baa
|
@ -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;
|
||||
|
|
32
fetch-pack.c
32
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;
|
||||
}
|
||||
|
|
1
remote.h
1
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
|
||||
|
|
|
@ -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
|
11
transport.c
11
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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче