connected: split out promisor-based connectivity check
When performing a connectivity check in a partial clone we try to avoid doing the connectivity check by checking whether all new tips are part of a promisor pack. This makes use of the fact that we don't expect full connectivity for promised objects anyway, so it's basically fine if those objects are not fully connected. The logic that handles this promisor-based check is somewhat hard to read though as it uses nested loops and gotos. Pull it out into a standalone function, which makes it a bit easier to reason about. We'll also further simplify the function in the next commit. Suggested-by: Christian Couder <christian.couder@gmail.com> Signed-off-by: Patrick Steinhardt <ps@pks.im> Signed-off-by: Junio C Hamano <gitster@pobox.com>
Patrick Steinhardt committed
Jun 25, 2026 at 11:57 UTC
0a7f3389f4c16da05a1113ef0829a352af62dcbe
1 file changed
+51
-34
connected.c
+51
-34
@@ -11,6 +11,49 @@
11
#include "packfile.h"
12
#include "promisor-remote.h"
13
14
+/*
15
+ * For partial clones, we don't want to have to do a regular connectivity check
16
+ * because we have to enumerate and exclude all promisor objects (slow), and
17
+ * then the connectivity check itself becomes a no-op because in a partial
18
+ * clone every object is a promisor object. Instead, just make sure we
19
+ * received, in a promisor packfile, the objects pointed to by each wanted ref.
20
+ *
21
+ * Before checking for promisor packs, be sure we have the latest pack-files
22
+ * loaded into memory.
23
+ *
24
+ * Returns 1 when all object IDs have been found in promisor packs, in which
25
+ * case we're fully connected and thus done. Returns 0 when we have found
26
+ * objects in non-promisor packs, in which case we'll have to fall back to the
27
+ * rev-list-based connectivity checks. Returns a negative error code on error.
28
+ */
29
+static int check_connected_promisor(oid_iterate_fn fn,
30
+ void *cb_data,
31
+ const struct object_id **oid)
32
+{
33
+ odb_reprepare(the_repository->objects);
34
+ do {
35
+ struct packed_git *p;
36
+
37
+ repo_for_each_pack(the_repository, p) {
38
+ if (!p->pack_promisor)
39
+ continue;
40
+ if (find_pack_entry_one(*oid, p))
41
+ goto promisor_pack_found;
42
+ }
43
+
44
+ /*
45
+ * We have found an object that is not part of a promisor pack,
46
+ * and thus we cannot skip the full connectivity check.
47
+ */
48
+ return 0;
49
+
50
+promisor_pack_found:
51
+ ;
52
+ } while ((*oid = fn(cb_data)) != NULL);
53
+
54
+ return 1;
55
+}
56
+
57
/*
58
* If we feed all the commits we want to verify to this command
59
*
@@ -46,42 +89,16 @@ int check_connected(oid_iterate_fn fn, void *cb_data,
89
}
90
91
if (repo_has_promisor_remote(the_repository)) {
49
- /*
50
- * For partial clones, we don't want to have to do a regular
51
- * connectivity check because we have to enumerate and exclude
52
- * all promisor objects (slow), and then the connectivity check
53
- * itself becomes a no-op because in a partial clone every
54
- * object is a promisor object. Instead, just make sure we
55
- * received, in a promisor packfile, the objects pointed to by
56
- * each wanted ref.
57
- *
58
- * Before checking for promisor packs, be sure we have the
59
- * latest pack-files loaded into memory.
60
- */
61
- odb_reprepare(the_repository->objects);
62
- do {
63
- struct packed_git *p;
64
-
65
- repo_for_each_pack(the_repository, p) {
66
- if (!p->pack_promisor)
67
- continue;
68
- if (find_pack_entry_one(oid, p))
69
- goto promisor_pack_found;
70
- }
71
- /*
72
- * Fallback to rev-list with oid and the rest of the
73
- * object IDs provided by fn.
74
- */
75
- goto no_promisor_pack_found;
76
-promisor_pack_found:
77
- ;
78
- } while ((oid = fn(cb_data)) != NULL);
79
- if (opt->err_fd)
80
- close(opt->err_fd);
81
- return 0;
92
+ err = check_connected_promisor(fn, cb_data, &oid);
93
+ if (err) {
94
+ if (opt->err_fd)
95
+ close(opt->err_fd);
96
+ if (err > 0)
97
+ err = 0;
98
+ return err;
99
+ }
100
}
101
84
-no_promisor_pack_found:
102
if (opt->shallow_file) {
103
strvec_push(&rev_list.args, "--shallow-file");
104
strvec_push(&rev_list.args, opt->shallow_file);