summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--cache.h2
-rw-r--r--fetch-pack.c45
-rw-r--r--sha1_file.c3
3 files changed, 47 insertions, 3 deletions
diff --git a/cache.h b/cache.h
index d06932ed0b..6a72f54d79 100644
--- a/cache.h
+++ b/cache.h
@@ -1773,6 +1773,8 @@ struct object_info {
#define OBJECT_INFO_SKIP_CACHED 4
/* Do not retry packed storage after checking packed and loose storage */
#define OBJECT_INFO_QUICK 8
+/* Do not check loose object */
+#define OBJECT_INFO_IGNORE_LOOSE 16
extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
/*
diff --git a/fetch-pack.c b/fetch-pack.c
index d97461296d..2ea358861d 100644
--- a/fetch-pack.c
+++ b/fetch-pack.c
@@ -711,6 +711,28 @@ static void mark_alternate_complete(struct object *obj)
mark_complete(&obj->oid);
}
+struct loose_object_iter {
+ struct oidset *loose_object_set;
+ struct ref *refs;
+};
+
+/*
+ * If the number of refs is not larger than the number of loose objects,
+ * this function stops inserting.
+ */
+static int add_loose_objects_to_set(const struct object_id *oid,
+ const char *path,
+ void *data)
+{
+ struct loose_object_iter *iter = data;
+ oidset_insert(iter->loose_object_set, oid);
+ if (iter->refs == NULL)
+ return 1;
+
+ iter->refs = iter->refs->next;
+ return 0;
+}
+
static int everything_local(struct fetch_pack_args *args,
struct ref **refs,
struct ref **sought, int nr_sought)
@@ -719,16 +741,31 @@ static int everything_local(struct fetch_pack_args *args,
int retval;
int old_save_commit_buffer = save_commit_buffer;
timestamp_t cutoff = 0;
+ struct oidset loose_oid_set = OIDSET_INIT;
+ int use_oidset = 0;
+ struct loose_object_iter iter = {&loose_oid_set, *refs};
+
+ /* Enumerate all loose objects or know refs are not so many. */
+ use_oidset = !for_each_loose_object(add_loose_objects_to_set,
+ &iter, 0);
save_commit_buffer = 0;
for (ref = *refs; ref; ref = ref->next) {
struct object *o;
+ unsigned int flags = OBJECT_INFO_QUICK;
- if (!has_object_file_with_flags(&ref->old_oid,
- OBJECT_INFO_QUICK))
- continue;
+ if (use_oidset &&
+ !oidset_contains(&loose_oid_set, &ref->old_oid)) {
+ /*
+ * I know this does not exist in the loose form,
+ * so check if it exists in a non-loose form.
+ */
+ flags |= OBJECT_INFO_IGNORE_LOOSE;
+ }
+ if (!has_object_file_with_flags(&ref->old_oid, flags))
+ continue;
o = parse_object(&ref->old_oid);
if (!o)
continue;
@@ -744,6 +781,8 @@ static int everything_local(struct fetch_pack_args *args,
}
}
+ oidset_clear(&loose_oid_set);
+
if (!args->no_dependents) {
if (!args->deepen) {
for_each_ref(mark_complete_oid, NULL);
diff --git a/sha1_file.c b/sha1_file.c
index 1b94f39c4c..c0a1979479 100644
--- a/sha1_file.c
+++ b/sha1_file.c
@@ -1262,6 +1262,9 @@ int sha1_object_info_extended(const unsigned char *sha1, struct object_info *oi,
if (find_pack_entry(real, &e))
break;
+ if (flags & OBJECT_INFO_IGNORE_LOOSE)
+ return -1;
+
/* Most likely it's a loose object. */
if (!sha1_loose_object_info(real, oi, flags))
return 0;