git@vger.kernel.org list mirror (unofficial, one of many)
 help / color / Atom feed
From: Elijah Newren <newren@gmail.com>
To: Derrick Stolee via GitGitGadget <gitgitgadget@gmail.com>
Cc: Git Mailing List <git@vger.kernel.org>,
	Junio C Hamano <gitster@pobox.com>,
	Derrick Stolee <dstolee@microsoft.com>
Subject: Re: [PATCH 8/9] sparse-checkout: use hashmaps for cone patterns
Date: Fri, 23 Aug 2019 21:56:52 -0700
Message-ID: <CABPp-BFMtO=7UGVZPbqh3tthSetvz5F=W3S=RsryPSuchmZeZw@mail.gmail.com> (raw)
In-Reply-To: <b99acea4a09a6ed5302e5e622a6b6eb35d2d01b1.1566313865.git.gitgitgadget@gmail.com>

On Tue, Aug 20, 2019 at 8:12 AM Derrick Stolee via GitGitGadget
<gitgitgadget@gmail.com> wrote:
>
> From: Derrick Stolee <dstolee@microsoft.com>
>
> The parent and recursive patterns allowed by the "cone mode"
> option in sparse-checkout are restrictive enough that we
> can avoid using the regex parsing. Everything is based on
> prefix matches, so we can use hashsets to store the prefixes
> from the sparse-checkout file. When checking a path, we can
> strip path entries from the path and check the hashset for
> an exact match.
>
> As a test, I created a cone-mode sparse-checkout file for the
> Linux repository that actually includes every file. This was
> constructed by taking every folder in the Linux repo and creating
> the pattern pairs here:
>
>         /$folder/*
>         !/$folder/*/*
>
> This resulted in a sparse-checkout file sith 8,296 patterns.
> Running 'git read-tree -mu HEAD' on this file had the following
> performance:
>
>         core.sparseCheckout=false: 0.21 s (0.00 s)
>          core.sparseCheckout=true: 3.75 s (3.50 s)
>          core.sparseCheckout=cone: 0.23 s (0.01 s)

Nice!

> The times in parentheses above correspond to the time spent
> in the first clear_ce_flags() call, according to the trace2
> performance traces.
>
> While this example is contrived, it demonstrates how these
> patterns can slow the sparse-checkout feature.
>
> Signed-off-by: Derrick Stolee <dstolee@microsoft.com>
> ---
>  Documentation/git-sparse-checkout.txt |   1 -
>  dir.c                                 | 154 +++++++++++++++++++++++++-
>  dir.h                                 |  27 +++++
>  t/t1091-sparse-checkout-builtin.sh    |   8 ++
>  4 files changed, 183 insertions(+), 7 deletions(-)
>
> diff --git a/Documentation/git-sparse-checkout.txt b/Documentation/git-sparse-checkout.txt
> index 463319055b..7ade827370 100644
> --- a/Documentation/git-sparse-checkout.txt
> +++ b/Documentation/git-sparse-checkout.txt
> @@ -85,7 +85,6 @@ negate patterns. For example, to remove the file `unwanted`:
>  !unwanted
>  ----------------
>
> -
>  ## CONE PATTERN SET
>
>  The full pattern set allows for arbitrary pattern matches and complicated
> diff --git a/dir.c b/dir.c
> index d021c908e5..2c5ff89a72 100644
> --- a/dir.c
> +++ b/dir.c
> @@ -599,6 +599,99 @@ void parse_exclude_pattern(const char **pattern,
>         *patternlen = len;
>  }
>
> +static int el_hashmap_cmp(const void *unused_cmp_data,
> +                         const void *a, const void *b, const void *key)
> +{
> +       const struct exclude_entry *ee1 = a;
> +       const struct exclude_entry *ee2 = b;
> +
> +       return strncmp(ee1->pattern, ee2->pattern, ee1->patternlen);
> +}
> +
> +static void add_exclude_to_hashsets(struct exclude_list *el, struct exclude *x)

Is this for something that is logically an "include" or an "exclude"?
The earlier use of "exclude" for "include"s now how me totally confused
and makes me know I'll have to read the code really carefully and may
still get messed up.

I don't know if there's a better way, but re-using .gitignore internals
for sparse-checkout stuff leads to this inverted switcheroo and makes
things hard to follow.  Is it too late or too hard to easily rename the
"exclude" stuff used by gitignore to something else more neutral?
Sigh...

> +{
> +       struct exclude_entry *e;
> +       char *truncated;
> +       char *data = NULL;
> +
> +       if (!el->use_cone_patterns)
> +               return;
> +
> +       if (x->patternlen >= 4 &&
> +           !strcmp(x->pattern + x->patternlen - 4, "/*/*")) {
> +               if (!(x->flags & EXC_FLAG_NEGATIVE)) {
> +                       /* Not a cone pattern. */
> +                       el->use_cone_patterns = 0;
> +                       warning(_("unrecognized pattern: '%s'"), x->pattern);
> +                       goto clear_hashmaps;
> +               }
> +
> +               truncated = xstrdup(x->pattern);
> +               truncated[x->patternlen - 4] = 0;
> +
> +               e = xmalloc(sizeof(struct exclude_entry));
> +               e->pattern = truncated;
> +               e->patternlen = x->patternlen - 4;
> +               hashmap_entry_init(e, memhash(e->pattern, e->patternlen));
> +
> +               if (!hashmap_get(&el->recursive_hashmap, e, NULL)) {
> +                       /* We did not see the "parent" included */
> +                       warning(_("unrecognized negative pattern: '%s'"), x->pattern);
> +                       free(truncated);
> +                       goto clear_hashmaps;
> +               }
> +
> +               hashmap_add(&el->parent_hashmap, e);
> +               hashmap_remove(&el->recursive_hashmap, e, &data);
> +               free(data);
> +               return;
> +       }
> +
> +       if (x->patternlen >= 2 &&
> +           !strcmp(x->pattern + x->patternlen - 2, "/*")) {
> +               if (x->flags & EXC_FLAG_NEGATIVE) {
> +                       warning(_("unrecognized negative pattern: '%s'"), x->pattern);
> +                       goto clear_hashmaps;
> +               }
> +
> +               e = xmalloc(sizeof(struct exclude_entry));
> +
> +               truncated = xstrdup(x->pattern);
> +               truncated[x->patternlen - 2] = 0;
> +               e->pattern = truncated;
> +               e->patternlen = x->patternlen - 2;
> +               hashmap_entry_init(e, memhash(e->pattern, e->patternlen));
> +
> +               hashmap_add(&el->recursive_hashmap, e);
> +
> +               if (hashmap_get(&el->parent_hashmap, e, NULL)) {
> +                       /* we already included this at the parent level */
> +                       warning(_("your sparse-checkout file may have issues: pattern '%s' is repeated"),
> +                               x->pattern);
> +                       hashmap_remove(&el->parent_hashmap, e, &data);
> +                       free(data);
> +               }
> +               return;
> +       }
> +
> +clear_hashmaps:
> +       hashmap_free(&el->parent_hashmap, 1);
> +       hashmap_free(&el->recursive_hashmap, 1);
> +       el->use_cone_patterns = 0;
> +}
> +
> +static int hashmap_contains_path(struct hashmap *map,
> +                                struct strbuf *pattern)
> +{
> +       struct exclude_entry e;
> +
> +       /* Check straight mapping */
> +       e.pattern = pattern->buf;
> +       e.patternlen = pattern->len;
> +       hashmap_entry_init(&e, memhash(e.pattern, e.patternlen));
> +       return !!hashmap_get(map, &e, NULL);
> +}
> +
>  void add_exclude(const char *string, const char *base,
>                  int baselen, struct exclude_list *el, int srcpos)
>  {
> @@ -623,6 +716,8 @@ void add_exclude(const char *string, const char *base,
>         ALLOC_GROW(el->excludes, el->nr + 1, el->alloc);
>         el->excludes[el->nr++] = x;
>         x->el = el;
> +
> +       add_exclude_to_hashsets(el, x);
>  }
>
>  static int read_skip_worktree_file_from_index(const struct index_state *istate,
> @@ -848,6 +943,10 @@ static int add_excludes_from_buffer(char *buf, size_t size,
>         int i, lineno = 1;
>         char *entry;
>
> +       el->use_cone_patterns = core_sparse_checkout == SPARSE_CHECKOUT_CONE ? 1 : 0;
> +       hashmap_init(&el->recursive_hashmap, el_hashmap_cmp, NULL, 0);
> +       hashmap_init(&el->parent_hashmap, el_hashmap_cmp, NULL, 0);
> +
>         el->filebuf = buf;
>
>         if (skip_utf8_bom(&buf, size))
> @@ -1070,18 +1169,61 @@ static struct exclude *last_exclude_matching_from_list(const char *pathname,
>
>  /*
>   * Scan the list and let the last match determine the fate.
> - * Return 1 for exclude, 0 for include and -1 for undecided.
> + * Return 0 for exclude, 1 for include and -1 for undecided.

Um...this doesn't make me feel any better about whether we're going to
run into bugs about "include" vs. "exclude".

>   */
>  int is_excluded_from_list(const char *pathname,
>                           int pathlen, const char *basename, int *dtype,
>                           struct exclude_list *el, struct index_state *istate)
>  {
>         struct exclude *exclude;
> -       exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
> -                                                 dtype, el, istate);
> -       if (exclude)
> -               return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
> -       return -1; /* undecided */
> +       struct strbuf parent_pathname = STRBUF_INIT;
> +       int result = 0;
> +       const char *slash_pos;
> +
> +       if (!el->use_cone_patterns) {
> +               exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
> +                                                               dtype, el, istate);
> +
> +               if (exclude)
> +                       return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
> +
> +               return -1; /* undecided */
> +       }
> +
> +       strbuf_addch(&parent_pathname, '/');
> +       strbuf_add(&parent_pathname, pathname, pathlen);
> +       slash_pos = strrchr(parent_pathname.buf, '/');
> +
> +       if (slash_pos == parent_pathname.buf) {
> +               /* include every file in root */
> +               result = 1;
> +               goto done;
> +       }
> +
> +       strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf);
> +
> +       if (hashmap_contains_path(&el->parent_hashmap, &parent_pathname)) {
> +               result = 1;
> +               goto done;
> +       }
> +
> +       while (parent_pathname.len) {
> +               if (hashmap_contains_path(&el->recursive_hashmap,
> +                                         &parent_pathname)) {
> +                       result = -1;
> +                       goto done;
> +               }
> +
> +               slash_pos = strrchr(parent_pathname.buf, '/');
> +               if (slash_pos == parent_pathname.buf)
> +                       break;
> +
> +               strbuf_setlen(&parent_pathname, slash_pos - parent_pathname.buf);
> +       }
> +
> +done:
> +       strbuf_release(&parent_pathname);
> +       return result;
>  }
>
>  static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
> diff --git a/dir.h b/dir.h
> index 680079bbe3..2d3356d1c0 100644
> --- a/dir.h
> +++ b/dir.h
> @@ -4,6 +4,7 @@
>  /* See Documentation/technical/api-directory-listing.txt */
>
>  #include "cache.h"
> +#include "hashmap.h"
>  #include "strbuf.h"
>
>  struct dir_entry {
> @@ -37,6 +38,13 @@ struct exclude {
>         int srcpos;
>  };
>
> +/* used for hashmaps for cone patterns */
> +struct exclude_entry {
> +       struct hashmap_entry ent;
> +       char *pattern;
> +       size_t patternlen;
> +};
> +
>  /*
>   * Each excludes file will be parsed into a fresh exclude_list which
>   * is appended to the relevant exclude_list_group (either EXC_DIRS or
> @@ -55,6 +63,25 @@ struct exclude_list {
>         const char *src;
>
>         struct exclude **excludes;
> +
> +       /*
> +        * While scanning the excludes, we attempt to match the patterns
> +        * with a more restricted set that allows us to use hashsets for
> +        * matching logic, which is faster than the linear lookup in the
> +        * excludes array above. If non-zero, that check succeeded.
> +        */
> +       unsigned use_cone_patterns;
> +
> +       /*
> +        * Stores paths where everything starting with those paths
> +        * is included.
> +        */
> +       struct hashmap recursive_hashmap;
> +
> +       /*
> +        * Used to check single-level parents of blobs.
> +        */
> +       struct hashmap parent_hashmap;
>  };
>
>  /*
> diff --git a/t/t1091-sparse-checkout-builtin.sh b/t/t1091-sparse-checkout-builtin.sh
> index 8cc377b839..60f10864a1 100755
> --- a/t/t1091-sparse-checkout-builtin.sh
> +++ b/t/t1091-sparse-checkout-builtin.sh
> @@ -134,6 +134,14 @@ test_expect_success 'cone mode: match patterns' '
>         test_cmp expect dir
>  '
>
> +test_expect_success 'cone mode: warn on bad pattern' '
> +       test_when_finished mv sparse-checkout repo/.git/info &&
> +       cp repo/.git/info/sparse-checkout . &&
> +       echo "!/deep/deeper/*" >>repo/.git/info/sparse-checkout &&
> +       git -C repo read-tree -mu HEAD 2>err &&
> +       test_i18ngrep "unrecognized negative pattern" err
> +'
> +
>  test_expect_success 'sparse-checkout disable' '
>         git -C repo sparse-checkout disable &&
>         test_path_is_missing repo/.git/info/sparse-checkout &&
> --
> gitgitgadget

So, uh, I saw the exclude vs. include thing, started scanning to see
if it was going to get better, saw the next include/exclude thing that
triggered a bell, and I more or less just scrolled quickly to the
bottom checking if anything might catch my eye.  So I didn't look at
this patch very closely at all.  I decided to just start playing with
the series instead...and as far as that goes, this patch is probably
fine because my testing seemed to work.

  reply index

Thread overview: 154+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2019-08-20 15:11 [PATCH 0/9] [RFC] New sparse-checkout builtin and "cone" mode Derrick Stolee via GitGitGadget
2019-08-20 15:11 ` [PATCH 1/9] sparse-checkout: create builtin with 'list' subcommand Derrick Stolee via GitGitGadget
2019-08-23 22:30   ` Elijah Newren
2019-08-20 15:11 ` [PATCH 2/9] sparse-checkout: create 'init' subcommand Derrick Stolee via GitGitGadget
2019-08-23 23:02   ` Elijah Newren
2019-09-11 14:27     ` Derrick Stolee
2019-09-11 20:28     ` Derrick Stolee
2019-08-20 15:11 ` [PATCH 3/9] clone: add --sparse mode Derrick Stolee via GitGitGadget
2019-08-23 23:17   ` Elijah Newren
2019-09-18 13:51     ` Derrick Stolee
2019-08-20 15:11 ` [PATCH 4/9] sparse-checkout: 'add' subcommand Derrick Stolee via GitGitGadget
2019-08-23 23:30   ` Elijah Newren
2019-09-18 13:55     ` Derrick Stolee
2019-09-18 14:56       ` Elijah Newren
2019-09-18 17:23         ` Derrick Stolee
2019-08-20 15:11 ` [PATCH 5/9] sparse-checkout: create 'disable' subcommand Derrick Stolee via GitGitGadget
2019-08-23 23:50   ` Elijah Newren
2019-08-20 15:11 ` [PATCH 6/9] trace2:experiment: clear_ce_flags_1 Jeff Hostetler via GitGitGadget
2019-08-24  0:08   ` Elijah Newren
2019-08-20 15:11 ` [PATCH 7/9] sparse-checkout: add 'cone' mode Derrick Stolee via GitGitGadget
2019-08-24  0:31   ` Elijah Newren
2019-08-20 15:11 ` [PATCH 8/9] sparse-checkout: use hashmaps for cone patterns Derrick Stolee via GitGitGadget
2019-08-24  4:56   ` Elijah Newren [this message]
2019-08-20 15:11 ` [PATCH 9/9] sparse-checkout: init and add in cone mode Derrick Stolee via GitGitGadget
2019-08-24  5:07   ` Elijah Newren
2019-08-21 21:52 ` [PATCH 0/9] [RFC] New sparse-checkout builtin and "cone" mode Elijah Newren
2019-08-22 13:10   ` Derrick Stolee
2019-08-22 14:25     ` Derrick Stolee
2019-08-24  5:40     ` Elijah Newren
2019-08-26 13:29       ` Derrick Stolee
2019-08-26 18:16         ` Elijah Newren
2019-08-26 19:16           ` Derrick Stolee
2019-09-02 17:55       ` Eric Sunshine
2019-09-19 14:43 ` [PATCH v2 00/11] " Derrick Stolee via GitGitGadget
2019-09-19 14:43   ` [PATCH v2 01/11] sparse-checkout: create builtin with 'list' subcommand Derrick Stolee via GitGitGadget
2019-10-05 19:22     ` Elijah Newren
2019-09-19 14:43   ` [PATCH v2 02/11] sparse-checkout: create 'init' subcommand Derrick Stolee via GitGitGadget
2019-10-05 19:34     ` Elijah Newren
2019-09-19 14:43   ` [PATCH v2 03/11] clone: add --sparse mode Derrick Stolee via GitGitGadget
2019-10-05 19:40     ` Elijah Newren
2019-10-07 13:56       ` Derrick Stolee
2019-09-19 14:43   ` [PATCH v2 05/11] sparse-checkout: add '--stdin' option to set subcommand Derrick Stolee via GitGitGadget
2019-09-19 14:43   ` [PATCH v2 04/11] sparse-checkout: 'set' subcommand Derrick Stolee via GitGitGadget
2019-10-05 22:44     ` Elijah Newren
2019-10-06  0:30       ` Elijah Newren
2019-10-07 18:26         ` Derrick Stolee
2019-10-11 22:24           ` Elijah Newren
2019-09-19 14:43   ` [PATCH v2 06/11] sparse-checkout: create 'disable' subcommand Derrick Stolee via GitGitGadget
2019-10-06  4:10     ` Elijah Newren
2019-10-07 19:12       ` Derrick Stolee
2019-09-19 14:43   ` [PATCH v2 07/11] trace2: add region in clear_ce_flags Jeff Hostetler via GitGitGadget
2019-10-06  4:13     ` Elijah Newren
2019-09-19 14:43   ` [PATCH v2 08/11] sparse-checkout: add 'cone' mode Derrick Stolee via GitGitGadget
2019-10-06  4:22     ` Elijah Newren
2019-10-07 19:15       ` Derrick Stolee
2019-09-19 14:43   ` [PATCH v2 09/11] sparse-checkout: use hashmaps for cone patterns Derrick Stolee via GitGitGadget
2019-09-19 20:59     ` Derrick Stolee
2019-09-20 14:37       ` Derrick Stolee
2019-09-19 14:43   ` [PATCH v2 10/11] sparse-checkout: init and set in cone mode Derrick Stolee via GitGitGadget
2019-09-19 14:43   ` [PATCH v2 11/11] unpack-trees: hash less " Derrick Stolee via GitGitGadget
2019-10-01 13:40   ` [PATCH v2 00/11] New sparse-checkout builtin and "cone" mode Derrick Stolee
2019-10-01 16:54     ` Elijah Newren
2019-10-01 18:15       ` Derrick Stolee
2019-10-03 22:28     ` Junio C Hamano
2019-10-07 20:08   ` [PATCH v3 00/17] " Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 01/17] sparse-checkout: create builtin with 'list' subcommand Derrick Stolee via GitGitGadget
2019-10-11 22:01       ` Elijah Newren
2019-10-07 20:08     ` [PATCH v3 02/17] sparse-checkout: create 'init' subcommand Derrick Stolee via GitGitGadget
2019-10-11 22:14       ` Elijah Newren
2019-10-14 20:22         ` Derrick Stolee
2019-10-07 20:08     ` [PATCH v3 03/17] clone: add --sparse mode Derrick Stolee via GitGitGadget
2019-10-11 22:20       ` Elijah Newren
2019-10-07 20:08     ` [PATCH v3 04/17] sparse-checkout: 'set' subcommand Derrick Stolee via GitGitGadget
2019-10-11 22:26       ` Elijah Newren
2019-10-11 22:30         ` Elijah Newren
2019-10-07 20:08     ` [PATCH v3 05/17] sparse-checkout: add '--stdin' option to set subcommand Derrick Stolee via GitGitGadget
2019-10-11 22:27       ` Elijah Newren
2019-10-14 20:28         ` Derrick Stolee
2019-10-07 20:08     ` [PATCH v3 06/17] sparse-checkout: create 'disable' subcommand Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 07/17] trace2: add region in clear_ce_flags Jeff Hostetler via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 08/17] sparse-checkout: add 'cone' mode Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 09/17] sparse-checkout: use hashmaps for cone patterns Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 10/17] sparse-checkout: init and set in cone mode Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 11/17] unpack-trees: hash less " Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 12/17] unpack-trees: add progress to clear_ce_flags() Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 13/17] read-tree: show progress by default Derrick Stolee via GitGitGadget
2019-10-12 22:16       ` Elijah Newren
2019-10-14 20:31         ` Derrick Stolee
2019-10-07 20:08     ` [PATCH v3 14/17] sparse-checkout: sanitize for nested folders Derrick Stolee via GitGitGadget
2019-10-07 20:08     ` [PATCH v3 15/17] sparse-checkout: update working directory in-process Derrick Stolee via GitGitGadget
2019-10-12 22:57       ` Elijah Newren
2019-10-14 20:39         ` Derrick Stolee
2019-10-07 20:08     ` [PATCH v3 16/17] sparse-checkout: write using lockfile Derrick Stolee via GitGitGadget
2019-10-12 22:59       ` Elijah Newren
2019-10-14 20:41         ` Derrick Stolee
2019-10-07 20:08     ` [PATCH v3 17/17] sparse-checkout: cone mode should not interact with .gitignore Derrick Stolee via GitGitGadget
2019-10-12 23:00       ` Elijah Newren
2019-10-12 23:22     ` [PATCH v3 00/17] New sparse-checkout builtin and "cone" mode Elijah Newren
2019-10-15 13:55     ` [PATCH v4 " Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 01/17] sparse-checkout: create builtin with 'list' subcommand Derrick Stolee via GitGitGadget
2019-10-16 19:00         ` Elijah Newren
2019-10-21 12:10           ` Derrick Stolee
2019-10-18 16:07         ` SZEDER Gábor
2019-10-21 11:42           ` Derrick Stolee
2019-10-15 13:55       ` [PATCH v4 02/17] sparse-checkout: create 'init' subcommand Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 03/17] clone: add --sparse mode Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 04/17] sparse-checkout: 'set' subcommand Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 05/17] sparse-checkout: add '--stdin' option to set subcommand Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 06/17] sparse-checkout: create 'disable' subcommand Derrick Stolee via GitGitGadget
2019-10-18 16:31         ` SZEDER Gábor
2019-10-15 13:55       ` [PATCH v4 07/17] trace2: add region in clear_ce_flags Jeff Hostetler via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 08/17] sparse-checkout: add 'cone' mode Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 09/17] sparse-checkout: use hashmaps for cone patterns Derrick Stolee via GitGitGadget
2019-10-18 15:31         ` SZEDER Gábor
2019-10-21 11:44           ` Derrick Stolee
2019-10-15 13:55       ` [PATCH v4 10/17] sparse-checkout: init and set in cone mode Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 11/17] unpack-trees: hash less " Derrick Stolee via GitGitGadget
2019-10-15 13:55       ` [PATCH v4 12/17] unpack-trees: add progress to clear_ce_flags() Derrick Stolee via GitGitGadget
2019-10-15 13:56       ` [PATCH v4 13/17] read-tree: show progress by default Derrick Stolee via GitGitGadget
2019-10-15 13:56       ` [PATCH v4 14/17] sparse-checkout: sanitize for nested folders Derrick Stolee via GitGitGadget
2019-10-15 13:56       ` [PATCH v4 15/17] sparse-checkout: update working directory in-process Derrick Stolee via GitGitGadget
2019-10-18 20:24         ` SZEDER Gábor
2019-10-18 20:40           ` SZEDER Gábor
2019-10-21 11:59             ` Derrick Stolee
2019-10-15 13:56       ` [PATCH v4 16/17] sparse-checkout: write using lockfile Derrick Stolee via GitGitGadget
2019-10-15 13:56       ` [PATCH v4 17/17] sparse-checkout: cone mode should not interact with .gitignore Derrick Stolee via GitGitGadget
2019-10-16 20:07       ` [PATCH v4 00/17] New sparse-checkout builtin and "cone" mode Elijah Newren
2019-10-17 23:53       ` Jon Simons
2019-10-21 12:08         ` Derrick Stolee
2019-10-21 13:56       ` [PATCH v5 " Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 01/17] sparse-checkout: create builtin with 'list' subcommand Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 02/17] sparse-checkout: create 'init' subcommand Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 03/17] clone: add --sparse mode Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 04/17] sparse-checkout: 'set' subcommand Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 05/17] sparse-checkout: add '--stdin' option to set subcommand Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 06/17] sparse-checkout: create 'disable' subcommand Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 07/17] trace2: add region in clear_ce_flags Jeff Hostetler via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 08/17] sparse-checkout: add 'cone' mode Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 09/17] sparse-checkout: use hashmaps for cone patterns Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 10/17] sparse-checkout: init and set in cone mode Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 11/17] unpack-trees: hash less " Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 12/17] unpack-trees: add progress to clear_ce_flags() Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 13/17] read-tree: show progress by default Derrick Stolee via GitGitGadget
2019-10-21 15:04           ` Phillip Wood
2019-10-21 15:14             ` Derrick Stolee
2019-10-23  3:48               ` Junio C Hamano
2019-10-23 12:50                 ` Derrick Stolee
2019-10-24 10:18                   ` Phillip Wood
2019-10-24 10:18                 ` Phillip Wood
2019-10-21 13:56         ` [PATCH v5 14/17] sparse-checkout: sanitize for nested folders Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 15/17] sparse-checkout: update working directory in-process Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 16/17] sparse-checkout: write using lockfile Derrick Stolee via GitGitGadget
2019-10-21 13:56         ` [PATCH v5 17/17] sparse-checkout: cone mode should not interact with .gitignore Derrick Stolee via GitGitGadget
2019-10-23  3:52         ` [PATCH v5 00/17] New sparse-checkout builtin and "cone" mode Junio C Hamano

Reply instructions:

You may reply publically to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

  List information: http://vger.kernel.org/majordomo-info.html

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to='CABPp-BFMtO=7UGVZPbqh3tthSetvz5F=W3S=RsryPSuchmZeZw@mail.gmail.com' \
    --to=newren@gmail.com \
    --cc=dstolee@microsoft.com \
    --cc=git@vger.kernel.org \
    --cc=gitgitgadget@gmail.com \
    --cc=gitster@pobox.com \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link

git@vger.kernel.org list mirror (unofficial, one of many)

Archives are clonable:
	git clone --mirror https://public-inbox.org/git
	git clone --mirror http://ou63pmih66umazou.onion/git
	git clone --mirror http://czquwvybam4bgbro.onion/git
	git clone --mirror http://hjrcffqmbrq6wope.onion/git

Example config snippet for mirrors

Newsgroups are available over NNTP:
	nntp://news.public-inbox.org/inbox.comp.version-control.git
	nntp://ou63pmih66umazou.onion/inbox.comp.version-control.git
	nntp://czquwvybam4bgbro.onion/inbox.comp.version-control.git
	nntp://hjrcffqmbrq6wope.onion/inbox.comp.version-control.git
	nntp://news.gmane.org/gmane.comp.version-control.git

 note: .onion URLs require Tor: https://www.torproject.org/

AGPL code for this site: git clone https://public-inbox.org/public-inbox.git