Skip to content

Commit 61061ab

Browse files
committed
Merge branch 'jh/object-filtering'
In preparation for implementing narrow/partial clone, the object walking machinery has been taught a way to tell it to "filter" some objects from enumeration. * jh/object-filtering: rev-list: support --no-filter argument list-objects-filter-options: support --no-filter list-objects-filter-options: fix 'keword' typo in comment pack-objects: add list-objects filtering rev-list: add list-objects filtering support list-objects: filter objects in traverse_commit_list oidset: add iterator methods to oidset oidmap: add oidmap iterator methods dir: allow exclusions from blob in addition to file
2 parents 936d1b9 + f4371a8 commit 61061ab

20 files changed

+1735
-53
lines changed

Documentation/git-pack-objects.txt

Lines changed: 21 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ SYNOPSIS
1212
'git pack-objects' [-q | --progress | --all-progress] [--all-progress-implied]
1313
[--no-reuse-delta] [--delta-base-offset] [--non-empty]
1414
[--local] [--incremental] [--window=<n>] [--depth=<n>]
15-
[--revs [--unpacked | --all]] [--stdout | base-name]
15+
[--revs [--unpacked | --all]]
16+
[--stdout [--filter=<filter-spec>] | base-name]
1617
[--shallow] [--keep-true-parents] < object-list
1718

1819

@@ -236,6 +237,25 @@ So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle.
236237
With this option, parents that are hidden by grafts are packed
237238
nevertheless.
238239

240+
--filter=<filter-spec>::
241+
Requires `--stdout`. Omits certain objects (usually blobs) from
242+
the resulting packfile. See linkgit:git-rev-list[1] for valid
243+
`<filter-spec>` forms.
244+
245+
--no-filter::
246+
Turns off any previous `--filter=` argument.
247+
248+
--missing=<missing-action>::
249+
A debug option to help with future "partial clone" development.
250+
This option specifies how missing objects are handled.
251+
+
252+
The form '--missing=error' requests that pack-objects stop with an error if
253+
a missing object is encountered. This is the default action.
254+
+
255+
The form '--missing=allow-any' will allow object traversal to continue
256+
if a missing object is encountered. Missing objects will silently be
257+
omitted from the results.
258+
239259
SEE ALSO
240260
--------
241261
linkgit:git-rev-list[1]

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: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -706,6 +706,47 @@ 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. n may be zero. The suffixes k, m, and g can be used to name
719+
units in KiB, MiB, or GiB. For example, 'blob:limit=1k' is the same
720+
as 'blob:limit=1024'.
721+
+
722+
The form '--filter=sparse:oid=<blob-ish>' uses a sparse-checkout
723+
specification contained in the blob (or blob-expression) '<blob-ish>'
724+
to omit blobs that would not be not required for a sparse checkout on
725+
the requested refs.
726+
+
727+
The form '--filter=sparse:path=<path>' similarly uses a sparse-checkout
728+
specification contained in <path>.
729+
730+
--no-filter::
731+
Turn off any previous `--filter=` argument.
732+
733+
--filter-print-omitted::
734+
Only useful with `--filter=`; prints a list of the objects omitted
735+
by the filter. Object IDs are prefixed with a ``~'' character.
736+
737+
--missing=<missing-action>::
738+
A debug option to help with future "partial clone" development.
739+
This option specifies how missing objects are handled.
740+
+
741+
The form '--missing=error' requests that rev-list stop with an error if
742+
a missing object is encountered. This is the default action.
743+
+
744+
The form '--missing=allow-any' will allow object traversal to continue
745+
if a missing object is encountered. Missing objects will silently be
746+
omitted from the results.
747+
+
748+
The form '--missing=print' is like 'allow-any', but will also print a
749+
list of the missing objects. Object IDs are prefixed with a ``?'' character.
709750
endif::git-rev-list[]
710751

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

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -811,6 +811,8 @@ LIB_OBJS += levenshtein.o
811811
LIB_OBJS += line-log.o
812812
LIB_OBJS += line-range.o
813813
LIB_OBJS += list-objects.o
814+
LIB_OBJS += list-objects-filter.o
815+
LIB_OBJS += list-objects-filter-options.o
814816
LIB_OBJS += ll-merge.o
815817
LIB_OBJS += lockfile.o
816818
LIB_OBJS += log-tree.o

builtin/pack-objects.c

Lines changed: 63 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@
1515
#include "diff.h"
1616
#include "revision.h"
1717
#include "list-objects.h"
18+
#include "list-objects-filter.h"
19+
#include "list-objects-filter-options.h"
1820
#include "pack-objects.h"
1921
#include "progress.h"
2022
#include "refs.h"
@@ -79,6 +81,15 @@ static unsigned long cache_max_small_delta_size = 1000;
7981

8082
static unsigned long window_memory_limit = 0;
8183

84+
static struct list_objects_filter_options filter_options;
85+
86+
enum missing_action {
87+
MA_ERROR = 0, /* fail if any missing objects are encountered */
88+
MA_ALLOW_ANY, /* silently allow ALL missing objects */
89+
};
90+
static enum missing_action arg_missing_action;
91+
static show_object_fn fn_show_object;
92+
8293
/*
8394
* stats
8495
*/
@@ -2553,6 +2564,42 @@ static void show_object(struct object *obj, const char *name, void *data)
25532564
obj->flags |= OBJECT_ADDED;
25542565
}
25552566

2567+
static void show_object__ma_allow_any(struct object *obj, const char *name, void *data)
2568+
{
2569+
assert(arg_missing_action == MA_ALLOW_ANY);
2570+
2571+
/*
2572+
* Quietly ignore ALL missing objects. This avoids problems with
2573+
* staging them now and getting an odd error later.
2574+
*/
2575+
if (!has_object_file(&obj->oid))
2576+
return;
2577+
2578+
show_object(obj, name, data);
2579+
}
2580+
2581+
static int option_parse_missing_action(const struct option *opt,
2582+
const char *arg, int unset)
2583+
{
2584+
assert(arg);
2585+
assert(!unset);
2586+
2587+
if (!strcmp(arg, "error")) {
2588+
arg_missing_action = MA_ERROR;
2589+
fn_show_object = show_object;
2590+
return 0;
2591+
}
2592+
2593+
if (!strcmp(arg, "allow-any")) {
2594+
arg_missing_action = MA_ALLOW_ANY;
2595+
fn_show_object = show_object__ma_allow_any;
2596+
return 0;
2597+
}
2598+
2599+
die(_("invalid value for --missing"));
2600+
return 0;
2601+
}
2602+
25562603
static void show_edge(struct commit *commit)
25572604
{
25582605
add_preferred_base(&commit->object.oid);
@@ -2817,7 +2864,12 @@ static void get_object_list(int ac, const char **av)
28172864
if (prepare_revision_walk(&revs))
28182865
die("revision walk setup failed");
28192866
mark_edges_uninteresting(&revs, show_edge);
2820-
traverse_commit_list(&revs, show_commit, show_object, NULL);
2867+
2868+
if (!fn_show_object)
2869+
fn_show_object = show_object;
2870+
traverse_commit_list_filtered(&filter_options, &revs,
2871+
show_commit, fn_show_object, NULL,
2872+
NULL);
28212873

28222874
if (unpack_unreachable_expiration) {
28232875
revs.ignore_missing_links = 1;
@@ -2953,6 +3005,10 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
29533005
N_("use a bitmap index if available to speed up counting objects")),
29543006
OPT_BOOL(0, "write-bitmap-index", &write_bitmap_index,
29553007
N_("write a bitmap index together with the pack index")),
3008+
OPT_PARSE_LIST_OBJECTS_FILTER(&filter_options),
3009+
{ OPTION_CALLBACK, 0, "missing", NULL, N_("action"),
3010+
N_("handling for missing objects"), PARSE_OPT_NONEG,
3011+
option_parse_missing_action },
29563012
OPT_END(),
29573013
};
29583014

@@ -3029,6 +3085,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)
30293085
if (!rev_list_all || !rev_list_reflog || !rev_list_index)
30303086
unpack_unreachable_expiration = 0;
30313087

3088+
if (filter_options.choice) {
3089+
if (!pack_to_stdout)
3090+
die("cannot use --filter without --stdout.");
3091+
use_bitmap_index = 0;
3092+
}
3093+
30323094
/*
30333095
* "soft" reasons not to use bitmaps - for on-disk repack by default we want
30343096
*

builtin/rev-list.c

Lines changed: 110 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,30 @@ 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, ("--no-" CL_ARG__FILTER))) {
407+
list_objects_filter_release(&filter_options);
408+
continue;
409+
}
410+
if (!strcmp(arg, "--filter-print-omitted")) {
411+
arg_print_omitted = 1;
412+
continue;
413+
}
414+
415+
if (skip_prefix(arg, "--missing=", &arg) &&
416+
parse_missing_action_value(arg))
417+
continue;
418+
338419
usage(rev_list_usage);
339420

340421
}
@@ -360,6 +441,9 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
360441
if (revs.show_notes)
361442
die(_("rev-list does not support display of notes"));
362443

444+
if (filter_options.choice && use_bitmap_index)
445+
die(_("cannot combine --use-bitmap-index with object filtering"));
446+
363447
save_commit_buffer = (revs.verbose_header ||
364448
revs.grep_filter.pattern_list ||
365449
revs.grep_filter.header_list);
@@ -403,7 +487,31 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)
403487
return show_bisect_vars(&info, reaches, all);
404488
}
405489

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

408516
stop_progress(&progress);
409517

0 commit comments

Comments
 (0)