list-objects-filter-large: add large blob filter to list-objects
Subsystems (2)
PATCH 5/13 list-objects-filter-large: add large blob filter to list-objects
From: Jeff Hostetler <[email protected]>
Create a filter for traverse_commit_list_worker() to omit blobs larger than a requested size from the result, but always include ".git*" special files.
--- Makefile | 1 + list-objects-filter-large.c | 108 ++++++++++++++++++++++++++++++++++++++++++++ list-objects-filter-large.h | 18 ++++++++ 3 files changed, 127 insertions(+) create mode 100644 list-objects-filter-large.c create mode 100644 list-objects-filter-large.h
Makefile +1 -0
@@ -799,6 +799,7 @@ LIB_OBJS += line-log.o LIB_OBJS += line-range.o LIB_OBJS += list-objects.o LIB_OBJS += list-objects-filter-all.o +LIB_OBJS += list-objects-filter-large.o LIB_OBJS += ll-merge.o LIB_OBJS += lockfile.o LIB_OBJS += log-tree.o
list-objects-filter-large.c new file +108 -0
108 lines not on this page · raw message
list-objects-filter-large.h new file +18 -0
@@ -0,0 +1,18 @@ +#ifndef LIST_OBJECTS_FILTER_LARGE_H +#define LIST_OBJECTS_FILTER_LARGE_H + +#include "oidset2.h" + +/* +* A filter for list-objects to omit large blobs, +* but always include ".git*" special files. +*/ +void traverse_commit_list_omit_large_blobs ( +struct rev_info *revs, +show_commit_fn show_commit, +show_object_fn show_object, +oidset2_foreach_cb print_omitted_object, +void *ctx_data, +int64_t large_byte_limit); + +#endif /* LIST_OBJECTS_FILTER_LARGE_H */
Signature · 1 line
2.9.3
PATCH 6/13 list-objects-filter-sparse: add sparse-checkout based filter
From: Jeff Hostetler <[email protected]>
Create a filter for traverse_commit_list_worker() to only include the blobs the would be referenced by a sparse-checkout using the given specification.
A future enhancement should be able to also omit unneeded tree objects, but that is not currently supported.
--- Makefile | 1 + list-objects-filter-sparse.c | 221 +++++++++++++++++++++++++++++++++++++++++++ list-objects-filter-sparse.h | 30 ++++++ 3 files changed, 252 insertions(+) create mode 100644 list-objects-filter-sparse.c create mode 100644 list-objects-filter-sparse.h
Makefile +1 -0
@@ -800,6 +800,7 @@ LIB_OBJS += line-range.o LIB_OBJS += list-objects.o LIB_OBJS += list-objects-filter-all.o LIB_OBJS += list-objects-filter-large.o +LIB_OBJS += list-objects-filter-sparse.o LIB_OBJS += ll-merge.o LIB_OBJS += lockfile.o LIB_OBJS += log-tree.o
list-objects-filter-sparse.c new file +221 -0
221 lines not on this page · raw message
list-objects-filter-sparse.h new file +30 -0
@@ -0,0 +1,30 @@ +#ifndef LIST_OBJECTS_FILTERS_SPARSE_H +#define LIST_OBJECTS_FILTERS_SPARSE_H + +#include "oidset2.h" + +/* +* A filter driven by a sparse-checkout specification to only +* include blobs that a sparse checkout would populate. +* +* The sparse-checkout spec can be loaded from a blob with the +* given OID, a blob with a blob-ish path, or from a local pathname. +* We allow an OID because the repo may be bare or we may be doing +* the filtering on the server. +*/ +void traverse_commit_list_use_blob ( +struct rev_info *revs, +show_commit_fn show_commit, +show_object_fn show_object, +oidset2_foreach_cb print_omitted_object, +void *ctx_data, +struct object_id *oid); +void traverse_commit_list_use_path ( +struct rev_info *revs, +show_commit_fn show_commit, +show_object_fn show_object, +oidset2_foreach_cb print_omitted_object, +void *ctx_data, +const char *path); + +#endif /* LIST_OBJECTS_FILTERS_SPARSE_H */
Signature · 1 line
2.9.3
PATCH 7/13 object-filter: common declarations for object filtering
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
Create common routines and defines for parsing object-filter-related command line arguments and pack-protocol fields.
--- Makefile | 1 + object-filter.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ object-filter.h | 173 ++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 object-filter.c create mode 100644 object-filter.h
Makefile +1 -0
@@ -818,6 +818,7 @@ LIB_OBJS += notes-cache.o LIB_OBJS += notes-merge.o LIB_OBJS += notes-utils.o LIB_OBJS += object.o +LIB_OBJS += object-filter.o LIB_OBJS += oidset.o LIB_OBJS += oidset2.o LIB_OBJS += pack-bitmap.o
object-filter.c new file +269 -0
269 lines not on this page · raw message
object-filter.h new file +173 -0
173 lines not on this page · raw message
Signature · 1 line
2.9.3
Re: [PATCH 07/13] object-filter: common declarations for object filtering
Quoted 6 lines · On Fri, 22 Sep 2017 20:30:11 +0000 Jeff Hostetler <[email protected]> wrote:
Makefile | 1 + object-filter.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ object-filter.h | 173 ++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+) create mode 100644 object-filter.c create mode 100644 object-filter.h
I think these and list-objects-filter-* are multiple levels of indirection too many. Would a single file with a few implementations of filter_object_fn be sufficient?
Re: [PATCH 07/13] object-filter: common declarations for object filtering
Quoted 10 lines · Jonathan Tan
Quoted 6 lines · On Fri, 22 Sep 2017 20:30:11 +0000 Jeff Hostetler <[email protected]> wrote:
Makefile | 1 + object-filter.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ object-filter.h | 173 ++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+)create mode 100644
object-filter.c
create mode 100644object-filter.h
Quoted 3 lines
I think these and list-objects-filter-* are multiple levels of indirection too many. Would a single file with a few implementations of
filter_object_fnbe sufficient?
I did that in my first draft and I found it confusing.
Each filter has 3 parts (some filter-specific data structures, a filter callback routine, a driver to call the traverse code). I found it easier to reason about each filter in isolation. And it makes it easier to work on each independently and keep their inclusion in separate commits.
Re: [PATCH 07/13] object-filter: common declarations for object filtering
Quoted 15 lines · On Wed, 27 Sep 2017 13:09:42 -0400 Jeff Hostetler <[email protected]> wrote:
Quoted 10 lines · Jonathan Tan
Quoted 6 lines · On Fri, 22 Sep 2017 20:30:11 +0000 Jeff Hostetler <[email protected]> wrote:
Makefile | 1 + object-filter.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ object-filter.h | 173 ++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+)create mode 100644
object-filter.c
create mode 100644object-filter.hQuoted 3 lines
I think these and list-objects-filter-* are multiple levels of indirection too many. Would a single file with a few implementations of
filter_object_fnbe sufficient?
Quoted 7 lines
I did that in my first draft and I found it confusing.
Each filter has 3 parts (some filter-specific data structures, a filter callback routine, a driver to call the traverse code). I found it easier to reason about each filter in isolation. And it makes it easier to work on each independently and keep their inclusion in separate commits.
I looked at object-filter.{c,h} a bit more. It seems that these files:
1) define a struct that contains all the options that we would want
2) supplies a way to populate this struct from code that uses parse-options
3) supplies a way to populate this struct from code that calculates options by hand
4) supplies a way to populate this struct from "protocol" ("<key>" or
"<key> <value>" strings)
And the next commit takes the struct that object-filter.{c,h} produces and actually performs the traversal.
I think this can be significantly simplified, though. Would this work:
a) Define the object_filter_options struct, but make all fields correspond to a single parameter each. Define OBJECT_FILTER_OPTIONS_INIT to initialize everything to 0 except for large_byte_limit to ULONG_MAX (so that we can detect if something else is set to it).
b) Define one single OPT_PARSE_FILTER macro containing all the parameters. We can use the non-callback macros here. That solves 2) above.
c) Define a function that takes in (int *argc, char ***argv) that can "massage" it to remove all filter-related arguments, storing them in a object_filter_options struct. That solves 3) above. As discussed in the API documentation, this means that argument lists of the form "--unknown --known" (where "--unknown" takes an argument) are processed differently, but then again, rev-list never supported them anyway (it required "--unknown=<arg>").
d) Define a function that converts "<key>" into "--<key>" and "<key> <value>" into "--<key>=<value>", and use the existing mechanism. That solves 4) above.
This removes the need to maintain the lists of one-per-argument functions, including the parse_filter_* and opt_parse_filter_* functions declared in the header file. If we were to add a feature, we wouldn't need to change anything in the caller, and wouldn't need to hand-edit object_filter_hand_parse_arg() and object_filter_hand_parse_protocol().
Re: [PATCH 07/13] object-filter: common declarations for object filtering
Quoted 57 lines · Jonathan Tan
Quoted 15 lines · On Wed, 27 Sep 2017 13:09:42 -0400 Jeff Hostetler <[email protected]> wrote:
Quoted 10 lines · Jonathan Tan
Quoted 6 lines · On Fri, 22 Sep 2017 20:30:11 +0000 Jeff Hostetler <[email protected]> wrote:
Makefile | 1 + object-filter.c | 269 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++ object-filter.h | 173 ++++++++++++++++++++++++++++++++++++ 3 files changed, 443 insertions(+)create mode 100644
object-filter.c
create mode 100644object-filter.hQuoted 3 lines
I think these and list-objects-filter-* are multiple levels of indirection too many. Would a single file with a few implementations of
filter_object_fnbe sufficient?Quoted 7 lines
I did that in my first draft and I found it confusing.
Each filter has 3 parts (some filter-specific data structures, a filter callback routine, a driver to call the traverse code). I found it easier to reason about each filter in isolation. And it makes it easier to work on each independently and keep their inclusion in separate commits.
I looked at object-filter.{c,h} a bit more. It seems that these files:
1) define a struct that contains all the options that we would want
2) supplies a way to populate this struct from code that uses parse-options
3) supplies a way to populate this struct from code that calculates options by hand
4) supplies a way to populate this struct from "protocol" ("<key>" or"<key> <value>" strings)And the next commit takes the struct that object-filter.{c,h} produces and actually performs the traversal.
I think this can be significantly simplified, though. Would this work:
a) Define theobject_filter_optionsstruct, but make all fields correspond to a single parameter each. DefineOBJECT_FILTER_OPTIONS_INITto initialize everything to 0 except forlarge_byte_limittoULONG_MAX(so that we can detect if something else is set to it).
b) Define one singleOPT_PARSE_FILTERmacro containing all the parameters. We can use the non-callback macros here. That solves 2) above.
c) Define a function that takes in (int *argc, char ***argv) that can "massage" it to remove all filter-related arguments, storing them in aobject_filter_optionsstruct. That solves 3) above. As discussed in the API documentation, this means that argument lists of the form "--unknown --known" (where "--unknown" takes an argument) are processed differently, but then again, rev-list never supported them anyway (it required "--unknown=<arg>").
d) Define a function that converts "<key>" into "--<key>" and "<key> <value>" into "--<key>=<value>", and use the existing mechanism. That solves 4) above.
Quoted 5 lines
This removes the need to maintain the lists of one-per-argument functions, including the parse_filter_* and opt_parse_filter_* functions declared in the header file. If we were to add a feature, we wouldn't need to change anything in the caller, and wouldn't need to hand-edit
object_filter_hand_parse_arg()andobject_filter_hand_parse_protocol().
Maybe. What I have here now is the result of adding these arguments to rev-list and pack-objects (in the current patch series), and also to fetch-pack, fetch, clone, upload-pack, index-pack, and the transport and protocol code (in a follow-on patch series that I've omitted for the moment). And there will probably be a few more, such as fsck, gc, and etc. I hesitate to refine the macros too much further until we've agreement on the overall approach and terms.
Thanks
Jeff
Re: [PATCH 07/13] object-filter: common declarations for object filtering
Quoted 7 lines · On Thu, 28 Sep 2017 10:33:39 -0400 Jeff Hostetler <[email protected]> wrote:
Maybe. What I have here now is the result of adding these arguments to rev-list and pack-objects (in the current patch series), and also to fetch-pack, fetch, clone, upload-pack, index-pack, and the transport and protocol code (in a follow-on patch series that I've omitted for the moment). And there will probably be a few more, such as fsck, gc, and etc. I hesitate to refine the macros too much further until we've agreement on the overall approach and terms.
Fair enough. My current opinion on the overall approach (others might differ, of course):
- Filtering based on a sparse checkout specification in rev-list and pack-objects sounds useful to me, and is worth the filtering mechanism.
- Filtering based on size (or based on type) still doesn't seem useful to me in rev-list, but if we're going to implement the filtering mechanism anyway, we might as well use the mechanism.
- Besides my comments in [1], I think the API could still be slightly better organized. For example, object-filter probably should be the one to define the traverse_ function that takes in struct object_filter_options, and optionally a set of excluded objects to populate.
PATCH 8/13 list-objects: add traverse_commit_list_filtered method
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
Add traverse_commit_list_filtered() wrapper around the various filter methods using common data in object_filter_options.
--- list-objects.c | 34 ++++++++++++++++++++++++++++++++++ list-objects.h | 11 +++++++++++ 2 files changed, 45 insertions(+)
list-objects.c +34 -0
@@ -7,6 +7,9 @@#include "tree-walk.h" #include "revision.h" #include "list-objects.h" +#include "list-objects-filter-all.h" +#include "list-objects-filter-large.h" +#include "list-objects-filter-sparse.h" static void process_blob(struct rev_info *revs, struct blob *blob,
@@ -266,3 +269,34 @@ void traverse_commit_list(struct rev_info *revs, show_commit, show_object, show_data, NULL, NULL); } + +void traverse_commit_list_filtered ( +struct object_filter_options *filter_options, +struct rev_info *revs, +show_commit_fn show_commit, +show_object_fn show_object, +oidset2_foreach_cb print_omitted_object, +void *show_data) +{ +if (filter_options->omit_all_blobs) +traverse_commit_list_omit_all_blobs ( + revs, show_commit, show_object, print_omitted_object, show_data); + +else if (filter_options->omit_large_blobs) +traverse_commit_list_omit_large_blobs ( + revs, show_commit, show_object, print_omitted_object, show_data, + (int64_t )(uint64_t )filter_options->large_byte_limit); + +else if (filter_options->use_blob) +traverse_commit_list_use_blob ( + revs, show_commit, show_object, print_omitted_object, show_data, + &filter_options->sparse_oid); + +else if (filter_options->use_path) +traverse_commit_list_use_path ( + revs, show_commit, show_object, print_omitted_object, show_data, + filter_options->sparse_value); + +else +die ("unspecified list-objects filter" ); +}
list-objects.h +11 -0
@@ -1,6 +1,9 @@#ifndef LIST_OBJECTS_H #define LIST_OBJECTS_H +#include "oidset2.h" +#include "object-filter.h" +typedef void (*show_commit_fn )(struct commit *,void *);typedef void (*show_object_fn )(struct object *,const char *,void *);void traverse_commit_list (struct rev_info *,show_commit_fn ,show_object_fn ,void *);
@@ -38,4 +41,12 @@ void traverse_commit_list_worker( show_commit_fn, show_object_fn, void *show_data, filter_object_fn filter, void *filter_data); +void traverse_commit_list_filtered ( +struct object_filter_options *filter_options, +struct rev_info *revs, +show_commit_fn show_commit, +show_object_fn show_object, +oidset2_foreach_cb print_omitted_object, +void *show_data); +#endif
Signature · 1 line
2.9.3
PATCH 9/13 rev-list: add object filtering support
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
Teach rev-list to use the filtering provided by the traverse_commit_list_filtered() interface to omit unwanted objects from the result.
This feature is only enabled when one of the "--objects*" options are used.
When the "--filter-print-manifest" option is used, the omitted objects and their sizes are printed at the end. These are marked with a "~". This can be combined with "--quiet" to get a list of just the omitted objects.
--- builtin/rev-list.c | 73 ++++++++++++++++++++++++++++++++++++++++++++++++++++-- 1 file changed, 71 insertions(+), 2 deletions(-)
builtin/rev-list.c +71 -2
@@ -53,6 +53,8 @@ static const char rev_list_usage[] =static struct progress *progress;static unsigned progress_counter; +static struct object_filter_options filter_options; +static struct oidset2 missing_objects;static void finish_commit (struct commit *commit,void *data);static void show_commit (struct commit *commit,void *data)
@@ -179,8 +181,25 @@ static void finish_commit(struct commit *commit, void *data)static void finish_object (struct object *obj,const char *name,void *cb_data) {struct rev_list_info *info = cb_data; -if (obj->type ==OBJ_BLOB && !has_object_file (&obj->oid)) +if (obj->type ==OBJ_BLOB && !has_object_file (&obj->oid)) { +if (filter_options.print_missing) { +oidset2_insert (&missing_objects, &obj->oid, obj->type, +-1 , name); +return ; + } +if (filter_options.relax) { +/* +* Relax consistency checks to not complain about +* omitted objects (presumably caused by use of +* the previous use of the 'filter-objects' feature). +* +* Note that this is independent of any filtering that +* we are doing in this run. +*/ +return ; + }die ("missing blob object '%s'" ,oid_to_hex (&obj->oid)); + }if (info->revs->verify_objects && !obj->parsed && obj->type !=OBJ_COMMIT )parse_object (&obj->oid); }
@@ -200,6 +219,25 @@ static void show_edge(struct commit *commit)printf ("-%s\n" ,oid_to_hex (&commit->object.oid)); } +static void print_omitted_object (int i,int i_limit,struct oidset2_entry *e,void *cb_data) +{ +/* struct rev_list_info *info = cb_data; */ +const char *tn =typename (e->type); + +if (e->object_length ==-1 ) +printf ("~%s %s\n" ,oid_to_hex (&e->oid), tn); +else +printf ("~%s %s %" PRIuMAX"\n" ,oid_to_hex (&e->oid), tn, e->object_length); +} + +static void print_missing_object (int i,int i_limit,struct oidset2_entry *e,void *cb_data) +{ +/* struct rev_list_info *info = cb_data; */ +const char *tn =typename (e->type); + +printf ("?%s %s\n" ,oid_to_hex (&e->oid), tn); +} +static void print_var_str (const char *var,const char *val) {printf ("%s='%s'\n" , var, val);
@@ -333,6 +371,15 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix) show_progress = arg;continue ; } +if (object_filter_hand_parse_arg ( + &filter_options, arg,1 ,1 ,1 )) { +if (!revs.blob_objects) +die (_ ("object filtering requires --objects" )); +if (filter_options.use_blob && + !oidcmp (&filter_options.sparse_oid, &null_oid)) +die (_ ("invalid sparse value" )); +continue ; + }usage (rev_list_usage); }
@@ -357,6 +404,11 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)if (revs.show_notes)die (_ ("rev-list does not support display of notes" )); +if (object_filter_enabled (&filter_options)) { +if (use_bitmap_index) +die (_ ("cannot combine --use-bitmap-index with object filtering" )); + } + save_commit_buffer = (revs.verbose_header || revs.grep_filter.pattern_list || revs.grep_filter.header_list);
@@ -401,7 +453,24 @@ int cmd_rev_list(int argc, const char **argv, const char *prefix)return show_bisect_vars (&info, reaches, all); } -traverse_commit_list (&revs, show_commit, show_object, &info); +if (filter_options.print_missing) +memset (&missing_objects,0 ,sizeof (missing_objects)); + +if (object_filter_enabled (&filter_options)) +traverse_commit_list_filtered ( + &filter_options, &revs, + show_commit, show_object, + (filter_options.print_omitted + ? print_omitted_object + :NULL ), + &info); +else +traverse_commit_list (&revs, show_commit, show_object, &info); + +if (filter_options.print_missing) { +oidset2_foreach (&missing_objects, print_missing_object, &info); +oidset2_clear (&missing_objects); + }stop_progress (&progress);
Signature · 1 line
2.9.3
Re: [PATCH 09/13] rev-list: add object filtering support
builtin/rev-list.c static void finish_commit(struct commit *commit, void *data) · line 190
Quoted 1 line · On Fri, 22 Sep 2017 20:30:13 +0000 Jeff Hostetler <[email protected]> wrote:
builtin/rev-list.c +1
-0+if (filter_options.relax) {
Add some documentation about how this differs from ignore_missing_links in struct rev_info.
Re: [PATCH 09/13] rev-list: add object filtering support
Quoted 8 lines · Jonathan Tan
builtin/rev-list.c static void finish_commit(struct commit *commit, void *data) · line 190
Quoted 1 line · On Fri, 22 Sep 2017 20:30:13 +0000 Jeff Hostetler <[email protected]> wrote:
builtin/rev-list.c +1
-0+if (filter_options.relax) {Add some documentation about how this differs from
ignore_missing_linksin structrev_info.
It's unclear what that field means. (It's not documented that I saw.) And it is explicitly turned on and off in pack-bitmap.c, so again I'm not sure how that agrees with what I'm doing.
My relax field is probably an interim thing (to allow rev-list, index-pack, and friends not complain about missing objects during my development).
I suspect that you and I will need to merge our efforts here. You have a similar variable "revs->exclude_promisor_objects". But I need to study how our usages differ.
Thanks,
Jeff
PATCH 10/13 rev-list: add filtering help text
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
--- Documentation/git-rev-list.txt | 9 ++++++++- Documentation/rev-list-options.txt | 32 ++++++++++++++++++++++++++++++++ 2 files changed, 40 insertions(+), 1 deletion(-)
Documentation/git-rev-list.txt +8 -1
@@ -47,7 +47,14 @@ SYNOPSIS [ --fixed-strings | -F ] [ --date=<format>] [ [ --objects | --objects-edge | --objects-edge-aggressive ] - [ --unpacked ] ] + [ --unpacked ] + [ [ --filter-omit-all-blobs | + --filter-omit-large-blobs=<n>[kmg] | + --filter-use-blob=<blob-ish> | + --filter-use-path=<path> ] + [ --filter-print-missing ] + [ --filter-print-omitted ] ] ] + [ --filter-relax ] [ --pretty | --header ] [ --bisect ] [ --bisect-vars ]
Documentation/rev-list-options.txt +32 -0
@@ -698,6 +698,38 @@ ifdef::git-rev-list[] --unpacked:: Only useful with `--objects`; print the object IDs that are not in packs. + +--filter-omit-all-blobs:: + Only useful with one of the `--objects*`; omits all blobs from + the printed list of objects. + +--filter-omit-large-blobs=<n>[kmg]:: + Only useful with one of the `--objects*`; omits blobs larger than + n bytes from the printed list of objects. May optionally be + followed by 'k', 'm', or 'g' units. Value may be zero. Special + files (matching ".git*") are always included, regardless of size. + +--filter-use-blob=<blob-ish>:: +--filter-use-path=<path>:: + Only useful with one of the `--objects*`; uses a sparse-checkout + specification contained in the given object or file to filter the + result to only contain blobs referenced by such a sparse-checkout. + +--filter-print-missing:: + Prints a list of the missing objects for the requested traversal. + Object IDs are prefixed with a ``?'' character. The object type + is printed after the ID. This may be used with or without any of + the above filtering options. + +--filter-print-omitted:: + Only useful with one of the above `--filter*`; prints a list + of the omitted objects. Object IDs are prefixed with a ``~'' + character. The object size is printed after the ID. + +--filter-relax:: + Relax consistency checking for missing blobs. Do not warn of + missing blobs during normal (non-filtering) object traversal + following an earlier partial/narrow clone or fetch. endif::git-rev-list[] --no-walk[=(sorted|unsorted)]::
Signature · 1 line
2.9.3
PATCH 11/13 t6112: rev-list object filtering test
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
--- t/t6112-rev-list-filters-objects.sh | 237 ++++++++++++++++++++++++++++++++++++ 1 file changed, 237 insertions(+) create mode 100755 t/t6112-rev-list-filters-objects.sh
t/t6112-rev-list-filters-objects.sh new file +237 -0
@@ -0,0 +1,237 @@ +#!/bin/sh + +test_description='git rev-list with object filtering' + +. ./test-lib.sh + +# test the omit-all filter + +test_expect_success 'setup' ' + echo "{print \$1}" >print_1.awk && + echo "{print \$2}" >print_2.awk && + + for n in 1 2 3 4 5 + do + echo $n > file.$n + git add file.$n + git commit -m "$n" + done +' + +# Verify the omitted ("~OID") lines match the predicted list of OIDs. +test_expect_success 'omit-all-blobs omitted 5 blobs' ' + git ls-files -s file.1 file.2 file.3 file.4 file.5 \ + | awk -f print_2.awk \ + | sort >expected && + git rev-list HEAD --quiet --objects --filter-print-omitted --filter-omit-all-blobs \ + | awk -f print_1.awk \ + | sed "s/~//" >observed && + test_cmp observed expected +' + +# Verify the complete OID list matches the unfiltered OIDs plus the omitted OIDs. +test_expect_success 'omit-all-blobs nothing else changed' ' + git rev-list HEAD --objects \ + | awk -f print_1.awk \ + | sort >expected && + git rev-list HEAD --objects --filter-print-omitted --filter-omit-all-blobs \ + | awk -f print_1.awk \ + | sed "s/~//" \ + | sort >observed && + test_cmp observed expected +' + +# test the size-based filtering. + +test_expect_success 'setup_large' ' + for n in 1000 10000 + do + printf "%"$n"s" X > large.$n + git add large.$n + git commit -m "$n" + done +' + +test_expect_success 'omit-large-blobs omit 2 blobs' ' + git ls-files -s large.1000 large.10000 \ + | awk -f print_2.awk \ + | sort >expected && + git rev-list HEAD --quiet --objects --filter-print-omitted --filter-omit-large-blobs=500 \ + | awk -f print_1.awk \ + | sed "s/~//" >observed && + test_cmp observed expected +' + +test_expect_success 'omit-large-blobs nothing else changed' ' + git rev-list HEAD --objects \ + | awk -f print_1.awk \ + | sort >expected && + git rev-list HEAD --objects --filter-print-omitted --filter-omit-large-blobs=500 \ + | awk -f print_1.awk \ + | sed "s/~//" \ + | sort >observed && + test_cmp observed expected +' + +# boundary test around the size parameter. +# filter is strictly less than the value, so size 500 and 1000 should have the +# same results, but 1001 should filter more. + +test_expect_success 'omit-large-blobs omit 2 blobs' ' + git ls-files -s large.1000 large.10000 \ + | awk -f print_2.awk \ + | sort >expected && + git rev-list HEAD --quiet --objects --filter-print-omitted --filter-omit-large-blobs=1000 \ + | awk -f print_1.awk \ + | sed "s/~//" >observed && + test_cmp observed expected +' + +test_expect_success 'omit-large-blobs omit 1 blob' ' + git ls-files -s large.10000 \ + | awk -f print_2.awk \ + | sort >expected && + git rev-list HEAD --quiet --objects --filter-print-omitted --filter-omit-large-blobs=1001 \ + | awk -f print_1.awk \ + | sed "s/~//" >observed && + test_cmp observed expected +' + +test_expect_success 'omit-large-blobs omit 1 blob (1k)' ' + git ls-files -s large.10000 \ + | awk -f print_2.awk \ + | sort >expected && + git rev-list HEAD --quiet --objects --filter-print-omitted --filter-omit-large-blobs=1k \ + | awk -f print_1.awk \ + | sed "s/~//" >observed && + test_cmp observed expected +' + +test_expect_success 'omit-large-blobs omit no blob (1m)' ' + cat </dev/null >expected && + git rev-list HEAD --quiet --objects --filter-print-omitted --filter-omit-large-blobs=1m \ + | awk -f print_1.awk \ + | sed "s/~//" >observed && + test_cmp observed expected +' + +# Test sparse-pattern filtering (using explicit local patterns). +# We use the same disk format as sparse-checkout to specify the +# filtering, but do not require sparse-checkout to be enabled. + +test_expect_success 'setup using sparse file' ' + mkdir dir1 && + for n in sparse1 sparse2 + do + echo $n > $n + git add $n + echo dir1/$n > dir1/$n + git add dir1/$n + done && + git commit -m "sparse" && + echo dir1/ >pattern1 && + echo sparse1 >pattern2 +' + +# pattern1 should only include the 2 dir1/* files. +# and omit the 5 file.*, 2 large.*, and 2 top-level sparse* files. +test_expect_success 'sparse using path pattern1' ' + git rev-list HEAD --objects --filter-print-omitted --filter-use-path=pattern1 >out && + + grep "^~" out >blobs.omitted && + test $(cat blobs.omitted | wc -l) = 9 && + + grep "dir1/sparse" out >blobs.included && + test $(cat blobs.included | wc -l) = 2 +' + +# pattern2 should include the sparse1 and dir1/sparse1. +# and omit the 5 file.*, 2 large.*, and the 2 sparse2 files. +test_expect_success 'sparse using path pattern2' ' + git rev-list HEAD --objects --filter-print-omitted --filter-use-path=pattern2 >out && + + grep "^~" out >blobs.omitted && + test $(cat blobs.omitted | wc -l) = 9 && + + grep "sparse1" out >blobs.included && + test $(cat blobs.included | wc -l) = 2 +' + +# Test sparse-pattern filtering (using a blob in the repo). +# This could be used to later let pack-objects do filtering. + +# pattern1 should only include the 2 dir1/* files. +# and omit the 5 file.*, 2 large.*, 2 top-level sparse*, and 1 pattern file. +test_expect_success 'sparse using OID for pattern1' ' + git add pattern1 && + git commit -m "pattern1" && + + git rev-list HEAD --objects >normal.output && + grep "pattern1" <normal.output | awk "{print \$1;}" >pattern1.oid && + + git rev-list HEAD --objects --filter-print-omitted --filter-use-blob=`cat pattern1.oid` >out && + + grep "^~" out >blobs.omitted && + test $(cat blobs.omitted | wc -l) = 10 && + + grep "dir1/sparse" out >blobs.included && + test $(cat blobs.included | wc -l) = 2 +' + +# repeat previous test but use blob-ish expression rather than OID. +test_expect_success 'sparse using blob-ish to get OID for pattern spec' ' + git rev-list HEAD --objects --filter-print-omitted --filter-use-blob=HEAD:pattern1 >out && + + grep "^~" out >blobs.omitted && + test $(cat blobs.omitted | wc -l) = 10 && + + grep "dir1/sparse" out >blobs.included && + test $(cat blobs.included | wc -l) = 2 +' + +# pattern2 should include the sparse1 and dir1/sparse1. +# and omit the 5 file.*, 2 large.*, 2 top-level sparse*, and 2 pattern files. +test_expect_success 'sparse using OID for pattern2' ' + git add pattern2 && + git commit -m "pattern2" && + + git rev-list HEAD --objects >normal.output && + grep "pattern2" <normal.output | awk "{print \$1;}" >pattern2.oid && + + git rev-list HEAD --objects --filter-print-omitted --filter-use-blob=`cat pattern2.oid` >out && + + grep "^~" out >blobs.omitted && + test $(cat blobs.omitted | wc -l) = 11 && + + grep "sparse1" out >blobs.included && + test $(cat blobs.included | wc -l) = 2 +' + +# repeat previous test but use blob-ish expression rather than OID. +test_expect_success 'sparse using blob-ish rather than OID for pattern2' ' + git rev-list HEAD --objects --filter-print-omitted --filter-use-blob=HEAD:pattern2 >out && + + grep "^~" out >blobs.omitted && + test $(cat blobs.omitted | wc -l) = 11 && + + grep "sparse1" out >blobs.included && + test $(cat blobs.included | wc -l) = 2 +' + +# delete some loose objects and test rev-list printing them as missing. +test_expect_success 'print missing objects' ' + git ls-files -s file.1 file.2 file.3 file.4 file.5 \ + | awk -f print_2.awk \ + | sort >expected && + for id in `cat expected | sed "s|..|&/|"` + do + rm .git/objects/$id + done && + git rev-list --quiet HEAD --filter-print-missing --objects \ + | awk -f print_1.awk \ + | sed "s/?//" \ + | sort >observed && + test_cmp observed expected +' + +test_done
Signature · 1 line
2.9.3
PATCH 12/13 pack-objects: add object filtering support
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
Teach pack-objects to use the filtering provided by the traverse_commit_list_filtered() interface to omit unwanted objects from the resulting packfile.
This feature is intended for partial clone/fetch.
Filtering requires the use of the "--stdout" option.
--- builtin/pack-objects.c | 24 +++++++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-)
builtin/pack-objects.c +23 -1
@@ -78,6 +78,8 @@ static unsigned long cache_max_small_delta_size = 1000;static unsigned long window_memory_limit =0 ; +static struct object_filter_options filter_options; +/* * stats */
@@ -2810,7 +2812,12 @@ static void get_object_list(int ac, const char **av)if (prepare_revision_walk (&revs))die ("revision walk setup failed" );mark_edges_uninteresting (&revs, show_edge); -traverse_commit_list (&revs, show_commit, show_object,NULL ); +if (object_filter_enabled (&filter_options)) +traverse_commit_list_filtered (&filter_options, &revs, + show_commit, show_object, +NULL ,NULL ); +else +traverse_commit_list (&revs, show_commit, show_object,NULL );if (unpack_unreachable_expiration) { revs.ignore_missing_links =1 ;
@@ -2946,6 +2953,15 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix) N_("use a bitmap index if available to speed up counting objects")),OPT_BOOL (0 ,"write-bitmap-index" , &write_bitmap_index,N_ ("write a bitmap index together with the pack index" )), + +OPT_PARSE_FILTER_OMIT_ALL_BLOBS (&filter_options), +OPT_PARSE_FILTER_OMIT_LARGE_BLOBS (&filter_options), +OPT_PARSE_FILTER_USE_BLOB (&filter_options), +OPT_PARSE_FILTER_USE_PATH (&filter_options), +/* not needed: OPT_PARSE_FILTER_PRINT_MISSING */ +/* not needed: OPT_PARSE_FILTER_PRINT_OMITTED */ +/* not needed: OPT_PARSE_FILTER_RELAX */ + OPT_END(), };
@@ -3022,6 +3038,12 @@ int cmd_pack_objects(int argc, const char **argv, const char *prefix)if (!rev_list_all || !rev_list_reflog || !rev_list_index) unpack_unreachable_expiration =0 ; +if (object_filter_enabled (&filter_options)) { +if (!pack_to_stdout) +die ("cannot use filtering with an indexable pack." ); + use_bitmap_index =0 ; + } +/* * "soft" reasons not to use bitmaps - for on-disk repack by default we want *
Signature · 1 line
2.9.3
PATCH 13/13 pack-objects: add filtering help text
In reply to Jeff HostetlerFrom: Jeff Hostetler <[email protected]>
Add help text for new object filtering options to
pack-objects documentation.
--- Documentation/git-pack-objects.txt | 17 +++++++++++++++++ 1 file changed, 17 insertions(+)
Documentation/git-pack-objects.txt +17 -0
@@ -231,6 +231,23 @@ So does `git bundle` (see linkgit:git-bundle[1]) when it creates a bundle. With this option, parents that are hidden by grafts are packed nevertheless. +--filter-omit-all-blobs:: + Requires `--stdout`. Omits all blobs from the packfile. + +--filter-omit-large-blobs=<n>[kmg]:: + Requires `--stdout`. Omits large blobs larger than n bytes from + the packfile. May optionally be followed by 'k', 'm', or 'g' units. + Value may be zero. Special files (matching ".git*") are always + included, regardless of size. + +--filter-use-blob=<blob-ish>:: +--filter-use-path=<path>:: + Requires `--stdout`. Use a sparse-checkout specification to + filter the resulting packfile to only contain the blobs that + would be referenced by such a sparse-checkout. `<path>` specifies + a local pathname. `<blob-ish>` specifies an expression that can + be evaluated to a blob. + SEE ALSO -------- linkgit:git-rev-list[1]
Signature · 1 line
2.9.3