Skip to content

Commit df11e19

Browse files
jonathantanmygitster
authored andcommitted
rev-list: support termination at promisor objects
Teach rev-list to support termination of an object traversal at any object from a promisor remote (whether one that the local repo also has, or one that the local repo knows about because it has another promisor object that references it). This will be used subsequently in gc and in the connectivity check used by fetch. For efficiency, if an object is referenced by a promisor object, and is in the local repo only as a non-promisor object, object traversal will not stop there. This is to avoid building the list of promisor object references. (In list-objects.c, the case where obj is NULL in process_blob() and process_tree() do not need to be changed because those happen only when there is a conflict between the expected type and the existing object. If the object doesn't exist, an object will be synthesized, which is fine.) Signed-off-by: Jonathan Tan <[email protected]> Signed-off-by: Jeff Hostetler <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 8b4c010 commit df11e19

File tree

7 files changed

+239
-11
lines changed

7 files changed

+239
-11
lines changed

Documentation/rev-list-options.txt

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -745,10 +745,21 @@ The form '--missing=allow-any' will allow object traversal to continue
745745
if a missing object is encountered. Missing objects will silently be
746746
omitted from the results.
747747
+
748+
The form '--missing=allow-promisor' is like 'allow-any', but will only
749+
allow object traversal to continue for EXPECTED promisor missing objects.
750+
Unexpected missing objects will raise an error.
751+
+
748752
The form '--missing=print' is like 'allow-any', but will also print a
749753
list of the missing objects. Object IDs are prefixed with a ``?'' character.
750754
endif::git-rev-list[]
751755

756+
--exclude-promisor-objects::
757+
(For internal use only.) Prefilter object traversal at
758+
promisor boundary. This is used with partial clone. This is
759+
stronger than `--missing=allow-promisor` because it limits the
760+
traversal, rather than just silencing errors about missing
761+
objects.
762+
752763
--no-walk[=(sorted|unsorted)]::
753764
Only show the given commits, but do not traverse their ancestors.
754765
This has no effect if a range is specified. If the argument

builtin/rev-list.c

Lines changed: 63 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@
1515
#include "progress.h"
1616
#include "reflog-walk.h"
1717
#include "oidset.h"
18+
#include "packfile.h"
1819

1920
static const char rev_list_usage[] =
2021
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -67,6 +68,7 @@ enum missing_action {
6768
MA_ERROR = 0, /* fail if any missing objects are encountered */
6869
MA_ALLOW_ANY, /* silently allow ALL missing objects */
6970
MA_PRINT, /* print ALL missing objects in special section */
71+
MA_ALLOW_PROMISOR, /* silently allow all missing PROMISOR objects */
7072
};
7173
static enum missing_action arg_missing_action;
7274

@@ -197,6 +199,12 @@ static void finish_commit(struct commit *commit, void *data)
197199

198200
static inline void finish_object__ma(struct object *obj)
199201
{
202+
/*
203+
* Whether or not we try to dynamically fetch missing objects
204+
* from the server, we currently DO NOT have the object. We
205+
* can either print, allow (ignore), or conditionally allow
206+
* (ignore) them.
207+
*/
200208
switch (arg_missing_action) {
201209
case MA_ERROR:
202210
die("missing blob object '%s'", oid_to_hex(&obj->oid));
@@ -209,25 +217,36 @@ static inline void finish_object__ma(struct object *obj)
209217
oidset_insert(&missing_objects, &obj->oid);
210218
return;
211219

220+
case MA_ALLOW_PROMISOR:
221+
if (is_promisor_object(&obj->oid))
222+
return;
223+
die("unexpected missing blob object '%s'",
224+
oid_to_hex(&obj->oid));
225+
return;
226+
212227
default:
213228
BUG("unhandled missing_action");
214229
return;
215230
}
216231
}
217232

218-
static void finish_object(struct object *obj, const char *name, void *cb_data)
233+
static int finish_object(struct object *obj, const char *name, void *cb_data)
219234
{
220235
struct rev_list_info *info = cb_data;
221-
if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
236+
if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid)) {
222237
finish_object__ma(obj);
238+
return 1;
239+
}
223240
if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
224241
parse_object(&obj->oid);
242+
return 0;
225243
}
226244

227245
static void show_object(struct object *obj, const char *name, void *cb_data)
228246
{
229247
struct rev_list_info *info = cb_data;
230-
finish_object(obj, name, cb_data);
248+
if (finish_object(obj, name, cb_data))
249+
return;
231250
display_progress(progress, ++progress_counter);
232251
if (info->flags & REV_LIST_QUIET)
233252
return;
@@ -315,11 +334,19 @@ static inline int parse_missing_action_value(const char *value)
315334

316335
if (!strcmp(value, "allow-any")) {
317336
arg_missing_action = MA_ALLOW_ANY;
337+
fetch_if_missing = 0;
318338
return 1;
319339
}
320340

321341
if (!strcmp(value, "print")) {
322342
arg_missing_action = MA_PRINT;
343+
fetch_if_missing = 0;
344+
return 1;
345+
}
346+
347+
if (!strcmp(value, "allow-promisor")) {
348+
arg_missing_action = MA_ALLOW_PROMISOR;
349+
fetch_if_missing = 0;
323350
return 1;
324351
}
325352

@@ -344,6 +371,35 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
344371
init_revisions(&revs, prefix);
345372
revs.abbrev = DEFAULT_ABBREV;
346373
revs.commit_format = CMIT_FMT_UNSPECIFIED;
374+
375+
/*
376+
* Scan the argument list before invoking setup_revisions(), so that we
377+
* know if fetch_if_missing needs to be set to 0.
378+
*
379+
* "--exclude-promisor-objects" acts as a pre-filter on missing objects
380+
* by not crossing the boundary from realized objects to promisor
381+
* objects.
382+
*
383+
* Let "--missing" to conditionally set fetch_if_missing.
384+
*/
385+
for (i = 1; i < argc; i++) {
386+
const char *arg = argv[i];
387+
if (!strcmp(arg, "--exclude-promisor-objects")) {
388+
fetch_if_missing = 0;
389+
revs.exclude_promisor_objects = 1;
390+
break;
391+
}
392+
}
393+
for (i = 1; i < argc; i++) {
394+
const char *arg = argv[i];
395+
if (skip_prefix(arg, "--missing=", &arg)) {
396+
if (revs.exclude_promisor_objects)
397+
die(_("cannot combine --exclude-promisor-objects and --missing"));
398+
if (parse_missing_action_value(arg))
399+
break;
400+
}
401+
}
402+
347403
argc = setup_revisions(argc, argv, &revs, NULL);
348404

349405
memset(&info, 0, sizeof(info));
@@ -412,9 +468,10 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
412468
continue;
413469
}
414470

415-
if (skip_prefix(arg, "--missing=", &arg) &&
416-
parse_missing_action_value(arg))
417-
continue;
471+
if (!strcmp(arg, "--exclude-promisor-objects"))
472+
continue; /* already handled above */
473+
if (skip_prefix(arg, "--missing=", &arg))
474+
continue; /* already handled above */
418475

419476
usage(rev_list_usage);
420477

list-objects.c

Lines changed: 28 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@
99
#include "list-objects.h"
1010
#include "list-objects-filter.h"
1111
#include "list-objects-filter-options.h"
12+
#include "packfile.h"
1213

1314
static void process_blob(struct rev_info *revs,
1415
struct blob *blob,
@@ -30,6 +31,20 @@ static void process_blob(struct rev_info *revs,
3031
if (obj->flags & (UNINTERESTING | SEEN))
3132
return;
3233

34+
/*
35+
* Pre-filter known-missing objects when explicitly requested.
36+
* Otherwise, a missing object error message may be reported
37+
* later (depending on other filtering criteria).
38+
*
39+
* Note that this "--exclude-promisor-objects" pre-filtering
40+
* may cause the actual filter to report an incomplete list
41+
* of missing objects.
42+
*/
43+
if (revs->exclude_promisor_objects &&
44+
!has_object_file(&obj->oid) &&
45+
is_promisor_object(&obj->oid))
46+
return;
47+
3348
pathlen = path->len;
3449
strbuf_addstr(path, name);
3550
if (filter_fn)
@@ -91,16 +106,28 @@ static void process_tree(struct rev_info *revs,
91106
all_entries_interesting: entry_not_interesting;
92107
int baselen = base->len;
93108
enum list_objects_filter_result r = LOFR_MARK_SEEN | LOFR_DO_SHOW;
109+
int gently = revs->ignore_missing_links ||
110+
revs->exclude_promisor_objects;
94111

95112
if (!revs->tree_objects)
96113
return;
97114
if (!obj)
98115
die("bad tree object");
99116
if (obj->flags & (UNINTERESTING | SEEN))
100117
return;
101-
if (parse_tree_gently(tree, revs->ignore_missing_links) < 0) {
118+
if (parse_tree_gently(tree, gently) < 0) {
102119
if (revs->ignore_missing_links)
103120
return;
121+
122+
/*
123+
* Pre-filter known-missing tree objects when explicitly
124+
* requested. This may cause the actual filter to report
125+
* an incomplete list of missing objects.
126+
*/
127+
if (revs->exclude_promisor_objects &&
128+
is_promisor_object(&obj->oid))
129+
return;
130+
104131
die("bad tree object %s", oid_to_hex(&obj->oid));
105132
}
106133

object.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -252,7 +252,7 @@ struct object *parse_object(const struct object_id *oid)
252252
if (obj && obj->parsed)
253253
return obj;
254254

255-
if ((obj && obj->type == OBJ_BLOB) ||
255+
if ((obj && obj->type == OBJ_BLOB && has_object_file(oid)) ||
256256
(!obj && has_object_file(oid) &&
257257
sha1_object_info(oid->hash, NULL) == OBJ_BLOB)) {
258258
if (check_sha1_signature(repl, NULL, 0, NULL) < 0) {

revision.c

Lines changed: 31 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -198,6 +198,8 @@ static struct object *get_reference(struct rev_info *revs, const char *name,
198198
if (!object) {
199199
if (revs->ignore_missing)
200200
return object;
201+
if (revs->exclude_promisor_objects && is_promisor_object(oid))
202+
return NULL;
201203
die("bad object %s", name);
202204
}
203205
object->flags |= flags;
@@ -790,9 +792,17 @@ static int add_parents_to_list(struct rev_info *revs, struct commit *commit,
790792

791793
for (parent = commit->parents; parent; parent = parent->next) {
792794
struct commit *p = parent->item;
793-
794-
if (parse_commit_gently(p, revs->ignore_missing_links) < 0)
795+
int gently = revs->ignore_missing_links ||
796+
revs->exclude_promisor_objects;
797+
if (parse_commit_gently(p, gently) < 0) {
798+
if (revs->exclude_promisor_objects &&
799+
is_promisor_object(&p->object.oid)) {
800+
if (revs->first_parent_only)
801+
break;
802+
continue;
803+
}
795804
return -1;
805+
}
796806
if (revs->show_source && !p->util)
797807
p->util = commit->util;
798808
p->object.flags |= left_flag;
@@ -2088,6 +2098,10 @@ static int handle_revision_opt(struct rev_info *revs, int argc, const char **arg
20882098
revs->limited = 1;
20892099
} else if (!strcmp(arg, "--ignore-missing")) {
20902100
revs->ignore_missing = 1;
2101+
} else if (!strcmp(arg, "--exclude-promisor-objects")) {
2102+
if (fetch_if_missing)
2103+
die("BUG: exclude_promisor_objects can only be used when fetch_if_missing is 0");
2104+
revs->exclude_promisor_objects = 1;
20912105
} else {
20922106
int opts = diff_opt_parse(&revs->diffopt, argv, argc, revs->prefix);
20932107
if (!opts)
@@ -2830,6 +2844,16 @@ void reset_revision_walk(void)
28302844
clear_object_flags(SEEN | ADDED | SHOWN);
28312845
}
28322846

2847+
static int mark_uninteresting(const struct object_id *oid,
2848+
struct packed_git *pack,
2849+
uint32_t pos,
2850+
void *unused)
2851+
{
2852+
struct object *o = parse_object(oid);
2853+
o->flags |= UNINTERESTING | SEEN;
2854+
return 0;
2855+
}
2856+
28332857
int prepare_revision_walk(struct rev_info *revs)
28342858
{
28352859
int i;
@@ -2858,6 +2882,11 @@ int prepare_revision_walk(struct rev_info *revs)
28582882
(revs->limited && limiting_can_increase_treesame(revs)))
28592883
revs->treesame.name = "treesame";
28602884

2885+
if (revs->exclude_promisor_objects) {
2886+
for_each_packed_object(mark_uninteresting, NULL,
2887+
FOR_EACH_OBJECT_PROMISOR_ONLY);
2888+
}
2889+
28612890
if (revs->no_walk != REVISION_WALK_NO_WALK_UNSORTED)
28622891
commit_list_sort_by_date(&revs->commits);
28632892
if (revs->no_walk)

revision.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -121,7 +121,10 @@ struct rev_info {
121121
bisect:1,
122122
ancestry_path:1,
123123
first_parent_only:1,
124-
line_level_traverse:1;
124+
line_level_traverse:1,
125+
126+
/* for internal use only */
127+
exclude_promisor_objects:1;
125128

126129
/* Diff flags */
127130
unsigned int diff:1,

0 commit comments

Comments
 (0)