This patch just put together pieces from the previous patches:
- Before getting the new pack, we need to remove all new reachable
shallow roots. The remaining roots may or may not be added to
.git/shallow.
- After getting the pack, walk all new refs until they connect to
current refs, or hit the bottom of current repo, or hit new
shallow roots.
Those refs that hit new shallow roots are rejected because by default
we do not allow to update .git/shallow (the only exception so far is
cloning from a shallow repo, which is more like creating .git/shallow
than updating it)
Signed-off-by: Nguyễn Thái Ngọc Duy
---
builtin/fetch.c | 9 +++
fetch-pack.c | 35 ++-
remote.h | 1 +
t/t5536-fetch-shallow.sh (new +x) | 128 ++
transport.c | 11 +++-
5 files changed, 179 insertions(+), 5 deletions(-)
create mode 100755 t/t5536-fetch-shallow.sh
diff --git a/builtin/fetch.c b/builtin/fetch.c
index bd7a101..7b41a7e 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 b76581a..64fa5d2 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -855,7 +855,17 @@ static struct ref *do_fetch_pack(struct fetch_pack_args
*args,
NULL);
else if (args->cloning && shallow && shallow->nr)
alternate_shallow_file = setup_temporary_shallow(shallow);
- else
+ else if (!args->cloning && shallow && shallow->nr) {
+ struct extra_have_objects extra;
+ memset(&extra, 0, sizeof(extra));
+ remove_reachable_shallow_points(&extra, shallow);
+ if (extra.nr) {
+ alternate_shallow_file =
setup_temporary_shallow(&extra);
+ free(shallow->array);
+ *shallow = extra;
+ } else
+ alternate_shallow_file = NULL;
+ } else
alternate_shallow_file = NULL;
if (get_pack(args, fd, pack_lockfile))
die("git fetch-pack: fetch failed.");
@@ -929,8 +939,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 extra_have_objects *shallow)
{
+ struct extra_have_objects ref;
+ int *status;
int i;
if (args->depth > 0 && alternate_shallow_file) {
@@ -977,6 +990,24 @@ static void update_shallow(struct fetch_pack_args *args,
free(extra.array);
return;
}
+
+ memset(&ref, 0, sizeof(ref));
+ for (i = 0; i < nr_sought; i++)
+ add_extra_have(&ref, sought[i]->old_sha1);
+
+ status = xcalloc(nr_sought, sizeof(*status));
+
+ /*
+* remote is also shallow, check what ref is safe to update
+* without updating .git/shallow
+*/
+ if (mark_new_shallow_refs(&ref, status, NULL, shallow)) {
+ for (i = 0; i < nr_sought; i++)
+ if (status[i])
+ sought[i]->status = REF_STATUS_REJECT_SHALLOW;
+ }
+ free(status);
+ free(ref.array);
}
struct ref *fetch_pack(struct fetch_pack_args *args,
@@ -1000,6 +1031,6 @@ struct ref *fetch_pack(struct fetch_pack_args *args,
ref_cpy = do_fetch_pack(args, fd, ref, sought, nr_sought,
shallow, pack_lockfile);
reprepare_packed_git();
- update_shallow(args, shallow);
+ update_shallow(args, sought, nr_sought, shallow);
return ref_cpy;
}
diff --git a/remote.h b/remote.h
index ff604ff..e519c2