Skip to content

Commit caf3827

Browse files
jeffhostetlergitster
authored andcommitted
rev-list: add list-objects filtering support
Teach rev-list to use the filtering provided by the traverse_commit_list_filtered() interface to omit unwanted objects from the result. Object filtering is only allowed when one of the "--objects*" options are used. When the "--filter-print-omitted" option is used, the omitted objects are printed at the end. These are marked with a "~". This option can be combined with "--quiet" to get a list of just the omitted objects. Add t6112 test. In the future, we will introduce a "partial clone" mechanism wherein an object in a repo, obtained from a remote, may reference a missing object that can be dynamically fetched from that remote once needed. This "partial clone" mechanism will have a way, sometimes slow, of determining if a missing link is one of the links expected to be produced by this mechanism. This patch introduces handling of missing objects to help debugging and development of the "partial clone" mechanism, and once the mechanism is implemented, for a power user to perform operations that are missing-object aware without incurring the cost of checking if a missing link is expected. Signed-off-by: Jeff Hostetler <[email protected]> Reviewed-by: Jonathan Tan <[email protected]> Signed-off-by: Junio C Hamano <[email protected]>
1 parent 25ec7bc commit caf3827

File tree

4 files changed

+370
-3
lines changed

4 files changed

+370
-3
lines changed

Documentation/git-rev-list.txt

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,9 @@ SYNOPSIS
4747
[ --fixed-strings | -F ]
4848
[ --date=<format>]
4949
[ [ --objects | --objects-edge | --objects-edge-aggressive ]
50-
[ --unpacked ] ]
50+
[ --unpacked ]
51+
[ --filter=<filter-spec> [ --filter-print-omitted ] ] ]
52+
[ --missing=<missing-action> ]
5153
[ --pretty | --header ]
5254
[ --bisect ]
5355
[ --bisect-vars ]

Documentation/rev-list-options.txt

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,42 @@ ifdef::git-rev-list[]
706706
--unpacked::
707707
Only useful with `--objects`; print the object IDs that are not
708708
in packs.
709+
710+
--filter=<filter-spec>::
711+
Only useful with one of the `--objects*`; omits objects (usually
712+
blobs) from the list of printed objects. The '<filter-spec>'
713+
may be one of the following:
714+
+
715+
The form '--filter=blob:none' omits all blobs.
716+
+
717+
The form '--filter=blob:limit=<n>[kmg]' omits blobs larger than n bytes
718+
or units. The value may be zero.
719+
+
720+
The form '--filter=sparse:oid=<oid-ish>' uses a sparse-checkout
721+
specification contained in the object (or the object that the expression
722+
evaluates to) to omit blobs that would not be not required for a
723+
sparse checkout on the requested refs.
724+
+
725+
The form '--filter=sparse:path=<path>' similarly uses a sparse-checkout
726+
specification contained in <path>.
727+
728+
--filter-print-omitted::
729+
Only useful with `--filter=`; prints a list of the objects omitted
730+
by the filter. Object IDs are prefixed with a ``~'' character.
731+
732+
--missing=<missing-action>::
733+
A debug option to help with future "partial clone" development.
734+
This option specifies how missing objects are handled.
735+
+
736+
The form '--missing=error' requests that rev-list stop with an error if
737+
a missing object is encountered. This is the default action.
738+
+
739+
The form '--missing=allow-any' will allow object traversal to continue
740+
if a missing object is encountered. Missing objects will silently be
741+
omitted from the results.
742+
+
743+
The form '--missing=print' is like 'allow-any', but will also print a
744+
list of the missing objects. Object IDs are prefixed with a ``?'' character.
709745
endif::git-rev-list[]
710746

711747
--no-walk[=(sorted|unsorted)]::

builtin/rev-list.c

Lines changed: 106 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,8 @@
44
#include "diff.h"
55
#include "revision.h"
66
#include "list-objects.h"
7+
#include "list-objects-filter.h"
8+
#include "list-objects-filter-options.h"
79
#include "pack.h"
810
#include "pack-bitmap.h"
911
#include "builtin.h"
@@ -12,6 +14,7 @@
1214
#include "bisect.h"
1315
#include "progress.h"
1416
#include "reflog-walk.h"
17+
#include "oidset.h"
1518

1619
static const char rev_list_usage[] =
1720
"git rev-list [OPTION] <commit-id>... [ -- paths... ]\n"
@@ -55,6 +58,20 @@ static const char rev_list_usage[] =
5558
static struct progress *progress;
5659
static unsigned progress_counter;
5760

61+
static struct list_objects_filter_options filter_options;
62+
static struct oidset omitted_objects;
63+
static int arg_print_omitted; /* print objects omitted by filter */
64+
65+
static struct oidset missing_objects;
66+
enum missing_action {
67+
MA_ERROR = 0, /* fail if any missing objects are encountered */
68+
MA_ALLOW_ANY, /* silently allow ALL missing objects */
69+
MA_PRINT, /* print ALL missing objects in special section */
70+
};
71+
static enum missing_action arg_missing_action;
72+
73+
#define DEFAULT_OIDSET_SIZE (16*1024)
74+
5875
static void finish_commit(struct commit *commit, void *data);
5976
static void show_commit(struct commit *commit, void *data)
6077
{
@@ -178,11 +195,31 @@ static void finish_commit(struct commit *commit, void *data)
178195
free_commit_buffer(commit);
179196
}
180197

198+
static inline void finish_object__ma(struct object *obj)
199+
{
200+
switch (arg_missing_action) {
201+
case MA_ERROR:
202+
die("missing blob object '%s'", oid_to_hex(&obj->oid));
203+
return;
204+
205+
case MA_ALLOW_ANY:
206+
return;
207+
208+
case MA_PRINT:
209+
oidset_insert(&missing_objects, &obj->oid);
210+
return;
211+
212+
default:
213+
BUG("unhandled missing_action");
214+
return;
215+
}
216+
}
217+
181218
static void finish_object(struct object *obj, const char *name, void *cb_data)
182219
{
183220
struct rev_list_info *info = cb_data;
184221
if (obj->type == OBJ_BLOB && !has_object_file(&obj->oid))
185-
die("missing blob object '%s'", oid_to_hex(&obj->oid));
222+
finish_object__ma(obj);
186223
if (info->revs->verify_objects && !obj->parsed && obj->type != OBJ_COMMIT)
187224
parse_object(&obj->oid);
188225
}
@@ -269,6 +306,26 @@ static int show_object_fast(
269306
return 1;
270307
}
271308

309+
static inline int parse_missing_action_value(const char *value)
310+
{
311+
if (!strcmp(value, "error")) {
312+
arg_missing_action = MA_ERROR;
313+
return 1;
314+
}
315+
316+
if (!strcmp(value, "allow-any")) {
317+
arg_missing_action = MA_ALLOW_ANY;
318+
return 1;
319+
}
320+
321+
if (!strcmp(value, "print")) {
322+
arg_missing_action = MA_PRINT;
323+
return 1;
324+
}
325+
326+
return 0;
327+
}
328+
272329
int cmd_rev_list(int argc, const char **argv, const char *prefix)
273330
{
274331
struct rev_info revs;
@@ -335,6 +392,26 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
335392
show_progress = arg;
336393
continue;
337394
}
395+
396+
if (skip_prefix(arg, ("--" CL_ARG__FILTER "="), &arg)) {
397+
parse_list_objects_filter(&filter_options, arg);
398+
if (filter_options.choice && !revs.blob_objects)
399+
die(_("object filtering requires --objects"));
400+
if (filter_options.choice == LOFC_SPARSE_OID &&
401+
!filter_options.sparse_oid_value)
402+
die(_("invalid sparse value '%s'"),
403+
filter_options.filter_spec);
404+
continue;
405+
}
406+
if (!strcmp(arg, "--filter-print-omitted")) {
407+
arg_print_omitted = 1;
408+
continue;
409+
}
410+
411+
if (skip_prefix(arg, "--missing=", &arg) &&
412+
parse_missing_action_value(arg))
413+
continue;
414+
338415
usage(rev_list_usage);
339416

340417
}
@@ -360,6 +437,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
360437
if (revs.show_notes)
361438
die(_("rev-list does not support display of notes"));
362439

440+
if (filter_options.choice && use_bitmap_index)
441+
die(_("cannot combine --use-bitmap-index with object filtering"));
442+
363443
save_commit_buffer = (revs.verbose_header ||
364444
revs.grep_filter.pattern_list ||
365445
revs.grep_filter.header_list);
@@ -404,7 +484,31 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
404484
return show_bisect_vars(&info, reaches, all);
405485
}
406486

407-
traverse_commit_list(&revs, show_commit, show_object, &info);
487+
if (arg_print_omitted)
488+
oidset_init(&omitted_objects, DEFAULT_OIDSET_SIZE);
489+
if (arg_missing_action == MA_PRINT)
490+
oidset_init(&missing_objects, DEFAULT_OIDSET_SIZE);
491+
492+
traverse_commit_list_filtered(
493+
&filter_options, &revs, show_commit, show_object, &info,
494+
(arg_print_omitted ? &omitted_objects : NULL));
495+
496+
if (arg_print_omitted) {
497+
struct oidset_iter iter;
498+
struct object_id *oid;
499+
oidset_iter_init(&omitted_objects, &iter);
500+
while ((oid = oidset_iter_next(&iter)))
501+
printf("~%s\n", oid_to_hex(oid));
502+
oidset_clear(&omitted_objects);
503+
}
504+
if (arg_missing_action == MA_PRINT) {
505+
struct oidset_iter iter;
506+
struct object_id *oid;
507+
oidset_iter_init(&missing_objects, &iter);
508+
while ((oid = oidset_iter_next(&iter)))
509+
printf("?%s\n", oid_to_hex(oid));
510+
oidset_clear(&missing_objects);
511+
}
408512

409513
stop_progress(&progress);
410514

0 commit comments

Comments
 (0)