{"thread":{"id":"26076","subject":"[PATCH 00/21] nd/struct-pathspec v2","startedAt":"2010-12-15T15:02:35Z","lastAt":"2019-02-04T21:49:40Z","messageCount":44,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Nguyen Thai Ngoc Duy","Ævar Arnfjörð Bjarmason","Duy Nguyen"],"isPatch":true,"patchVersion":1,"patchTotal":21},"messages":[{"id":"158160","messageId":"1292425376-14550-1-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":null,"subject":"[PATCH 00/21] nd/struct-pathspec v2","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:35Z","receivedAt":"2010-12-15T15:02:35Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Changes from previous version [1]\n\n - fixes depth limit and overlapping pathspecs, by checking deepest\n   pathspecs first. struct pathspec is now sorted (raw[] untouched)\n\n - match_pathspec_depth depends on new match_pathspec_item() (a\n   clone of match_one(), but takes advantage of struct pathspec)\n\n - ce_path_match uses struct pathspec\n\n - strbuf is used instead of fixed length \"base\" buffer. This\n   introduces the weird strbuf_offset() function.\n\n - never_interesting is disabled if any wildcards is present\n\n - struct pathspec * == NULL is unacceptable, callers must pass\n   non-NULL.\n\n - a bit more tests\n\n[1] http://mid.gmane.org/1292233616-27692-1-git-send-email-pclouds@gmail.com\n\nJonathan Nieder (1):\n  glossary: define pathspec\n\nNguyễn Thái Ngọc Duy (20):\n  Add struct pathspec\n  diff-no-index: use diff_tree_setup_paths()\n  Convert struct diff_options to use struct pathspec\n  tree_entry_interesting(): remove dependency on struct diff_options\n  Move tree_entry_interesting() to tree-walk.c and export it\n  diff-tree: convert base+baselen to writable strbuf\n  tree_entry_interesting(): refactor into separate smaller functions\n  tree_entry_interesting(): support depth limit\n  tree_entry_interesting(): fix depth limit with overlapping pathspecs\n  tree_entry_interesting(): support wildcard matching\n  tree_entry_interesting(): optimize wildcard matching when base is matched\n  pathspec: add match_pathspec_depth()\n  Convert ce_path_match() to use struct pathspec\n  Convert ce_path_match() to use match_pathspec_depth()\n  grep: convert to use struct pathspec\n  grep: use match_pathspec_depth() for cache/worktree grepping\n  strbuf: allow \"buf\" to point to the middle of the allocated buffer\n  grep: use writable strbuf from caller for grep_tree()\n  grep: drop pathspec_matches() in favor of tree_entry_interesting()\n  t7810: overlapping pathspecs and depth limit\n\n Documentation/glossary-content.txt |   23 +++\n builtin/diff-files.c               |    2 +-\n builtin/diff.c                     |    4 +-\n builtin/grep.c                     |  197 +++++++-------------------\n builtin/log.c                      |    2 +-\n builtin/update-index.c             |    8 +-\n cache.h                            |   17 ++-\n diff-lib.c                         |   12 ++-\n diff-no-index.c                    |   13 +-\n diff.h                             |    4 +-\n dir.c                              |  151 ++++++++++++++++++++\n dir.h                              |    4 +\n preload-index.c                    |    5 +-\n read-cache.c                       |   25 +---\n revision.c                         |   11 +-\n strbuf.c                           |   36 ++++--\n strbuf.h                           |   10 +-\n t/t4010-diff-pathspec.sh           |   32 ++++\n t/t7810-grep.sh                    |   18 +++\n tree-diff.c                        |  277 +++++++++---------------------------\n tree-walk.c                        |  180 +++++++++++++++++++++++\n tree-walk.h                        |    2 +\n wt-status.c                        |    5 +-\n 23 files changed, 615 insertions(+), 423 deletions(-)\n\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158161","messageId":"1292425376-14550-2-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 01/21] Add struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:36Z","receivedAt":"2010-12-15T15:02:36Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"The old pathspec structure remains as pathspec.raw[]. New things are\nstored in pathspec.items[]. There's no guarantee that the pathspec\norder in raw[] is exactly as in items[].\n\nraw[] is external (source) data and is untouched by pathspec\nmanipulation functions. It eases migration from old const char ** to\nthis new struct.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h |   11 +++++++++++\n dir.c   |   31 +++++++++++++++++++++++++++++++\n 2 files changed, 42 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 2ef2fa3..9eeecc2 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -493,6 +493,17 @@ extern int index_name_is_other(const struct index_state *, const char *, int);\n extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);\n extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);\n \n+struct pathspec {\n+\tconst char **raw; /* get_pathspec() result, not freed by free_pathspec() */\n+\tint nr;\n+\tstruct pathspec_item {\n+\t\tconst char *match;\n+\t\tint len;\n+\t} *items;\n+};\n+\n+extern int init_pathspec(struct pathspec *, const char **);\n+extern void free_pathspec(struct pathspec *);\n extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);\n extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);\n extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);\ndiff --git a/dir.c b/dir.c\nindex 133f472..a88f2ef 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1071,3 +1071,34 @@ int remove_path(const char *name)\n \treturn 0;\n }\n \n+int init_pathspec(struct pathspec *pathspec, const char **paths)\n+{\n+\tconst char **p = paths;\n+\tint i;\n+\n+\tmemset(pathspec, 0, sizeof(*pathspec));\n+\tif (!p)\n+\t\treturn 0;\n+\twhile (*p)\n+\t\tp++;\n+\tpathspec->raw = paths;\n+\tpathspec->nr = p - paths;\n+\tif (!pathspec->nr)\n+\t\treturn 0;\n+\n+\tpathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);\n+\tfor (i = 0; i < pathspec->nr; i++) {\n+\t\tstruct pathspec_item *item = pathspec->items+i;\n+\t\tconst char *path = paths[i];\n+\n+\t\titem->match = path;\n+\t\titem->len = strlen(path);\n+\t}\n+\treturn 0;\n+}\n+\n+void free_pathspec(struct pathspec *pathspec)\n+{\n+\tfree(pathspec->items);\n+\tpathspec->items = NULL;\n+}\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158180","messageId":"1292425376-14550-3-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 02/21] diff-no-index: use diff_tree_setup_paths()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:37Z","receivedAt":"2010-12-15T15:02:37Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"diff_options.{paths,nr_paths} will be removed later. Do not\nmodify them directly.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n diff-no-index.c |    9 +++++----\n 1 files changed, 5 insertions(+), 4 deletions(-)\n\ndiff --git a/diff-no-index.c b/diff-no-index.c\nindex ce9e783..e48ab92 100644\n--- a/diff-no-index.c\n+++ b/diff-no-index.c\n@@ -231,8 +231,9 @@ void diff_no_index(struct rev_info *revs,\n \n \tif (prefix) {\n \t\tint len = strlen(prefix);\n+\t\tconst char *paths[3];\n+\t\tmemset(paths, 0, sizeof(paths));\n \n-\t\trevs->diffopt.paths = xcalloc(2, sizeof(char *));\n \t\tfor (i = 0; i < 2; i++) {\n \t\t\tconst char *p = argv[argc - 2 + i];\n \t\t\t/*\n@@ -242,12 +243,12 @@ void diff_no_index(struct rev_info *revs,\n \t\t\tp = (strcmp(p, \"-\")\n \t\t\t     ? xstrdup(prefix_filename(prefix, len, p))\n \t\t\t     : p);\n-\t\t\trevs->diffopt.paths[i] = p;\n+\t\t\tpaths[i] = p;\n \t\t}\n+\t\tdiff_tree_setup_paths(paths, &revs->diffopt);\n \t}\n \telse\n-\t\trevs->diffopt.paths = argv + argc - 2;\n-\trevs->diffopt.nr_paths = 2;\n+\t\tdiff_tree_setup_paths(argv + argc - 2, &revs->diffopt);\n \trevs->diffopt.skip_stat_unmatch = 1;\n \tif (!revs->diffopt.output_format)\n \t\trevs->diffopt.output_format = DIFF_FORMAT_PATCH;\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158162","messageId":"1292425376-14550-4-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 03/21] Convert struct diff_options to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:38Z","receivedAt":"2010-12-15T15:02:38Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/diff-files.c |    2 +-\n builtin/diff.c       |    4 ++--\n builtin/log.c        |    2 +-\n diff-lib.c           |    2 +-\n diff-no-index.c      |    4 ++--\n diff.h               |    4 +---\n revision.c           |    6 +-----\n tree-diff.c          |   48 +++++++++++++-----------------------------------\n 8 files changed, 22 insertions(+), 50 deletions(-)\n\ndiff --git a/builtin/diff-files.c b/builtin/diff-files.c\nindex 951c7c8..46085f8 100644\n--- a/builtin/diff-files.c\n+++ b/builtin/diff-files.c\n@@ -61,7 +61,7 @@ int cmd_diff_files(int argc, const char **argv, const char *prefix)\n \t    (rev.diffopt.output_format & DIFF_FORMAT_PATCH))\n \t\trev.combine_merges = rev.dense_combined_merges = 1;\n \n-\tif (read_cache_preload(rev.diffopt.paths) < 0) {\n+\tif (read_cache_preload(rev.diffopt.pathspec.raw) < 0) {\n \t\tperror(\"read_cache_preload\");\n \t\treturn -1;\n \t}\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex a43d326..76c42d8 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -135,7 +135,7 @@ static int builtin_diff_index(struct rev_info *revs,\n \t    revs->max_count != -1 || revs->min_age != -1 ||\n \t    revs->max_age != -1)\n \t\tusage(builtin_diff_usage);\n-\tif (read_cache_preload(revs->diffopt.paths) < 0) {\n+\tif (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {\n \t\tperror(\"read_cache_preload\");\n \t\treturn -1;\n \t}\n@@ -237,7 +237,7 @@ static int builtin_diff_files(struct rev_info *revs, int argc, const char **argv\n \t\trevs->combine_merges = revs->dense_combined_merges = 1;\n \n \tsetup_work_tree();\n-\tif (read_cache_preload(revs->diffopt.paths) < 0) {\n+\tif (read_cache_preload(revs->diffopt.pathspec.raw) < 0) {\n \t\tperror(\"read_cache_preload\");\n \t\treturn -1;\n \t}\ndiff --git a/builtin/log.c b/builtin/log.c\nindex eaa1ee0..92779a5 100644\n--- a/builtin/log.c\n+++ b/builtin/log.c\n@@ -89,7 +89,7 @@ static void cmd_log_init(int argc, const char **argv, const char *prefix,\n \t\trev->always_show_header = 0;\n \tif (DIFF_OPT_TST(&rev->diffopt, FOLLOW_RENAMES)) {\n \t\trev->always_show_header = 0;\n-\t\tif (rev->diffopt.nr_paths != 1)\n+\t\tif (rev->diffopt.pathspec.nr != 1)\n \t\t\tusage(\"git logs can only follow renames on one pathname at a time\");\n \t}\n \tfor (i = 1; i < argc; i++) {\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 392ce2b..3b809f2 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)\n \tactive_nr = dst - active_cache;\n \n \tinit_revisions(&revs, NULL);\n-\trevs.prune_data = opt->paths;\n+\trevs.prune_data = opt->pathspec.raw;\n \ttree = parse_tree_indirect(tree_sha1);\n \tif (!tree)\n \t\tdie(\"bad tree object %s\", sha1_to_hex(tree_sha1));\ndiff --git a/diff-no-index.c b/diff-no-index.c\nindex e48ab92..3a36144 100644\n--- a/diff-no-index.c\n+++ b/diff-no-index.c\n@@ -260,8 +260,8 @@ void diff_no_index(struct rev_info *revs,\n \tif (diff_setup_done(&revs->diffopt) < 0)\n \t\tdie(\"diff_setup_done failed\");\n \n-\tif (queue_diff(&revs->diffopt, revs->diffopt.paths[0],\n-\t\t       revs->diffopt.paths[1]))\n+\tif (queue_diff(&revs->diffopt, revs->diffopt.pathspec.raw[0],\n+\t\t       revs->diffopt.pathspec.raw[1]))\n \t\texit(1);\n \tdiff_set_mnemonic_prefix(&revs->diffopt, \"1/\", \"2/\");\n \tdiffcore_std(&revs->diffopt);\ndiff --git a/diff.h b/diff.h\nindex bf2f44d..6497b71 100644\n--- a/diff.h\n+++ b/diff.h\n@@ -133,9 +133,7 @@ struct diff_options {\n \tFILE *file;\n \tint close_file;\n \n-\tint nr_paths;\n-\tconst char **paths;\n-\tint *pathlens;\n+\tstruct pathspec pathspec;\n \tchange_fn_t change;\n \tadd_remove_fn_t add_remove;\n \tdiff_format_fn_t format_callback;\ndiff --git a/revision.c b/revision.c\nindex b1c1890..b2a5867 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -553,11 +553,7 @@ static void cherry_pick_list(struct commit_list *list, struct rev_info *revs)\n \n \tleft_first = left_count < right_count;\n \tinit_patch_ids(&ids);\n-\tif (revs->diffopt.nr_paths) {\n-\t\tids.diffopts.nr_paths = revs->diffopt.nr_paths;\n-\t\tids.diffopts.paths = revs->diffopt.paths;\n-\t\tids.diffopts.pathlens = revs->diffopt.pathlens;\n-\t}\n+\tids.diffopts.pathspec = revs->diffopt.pathspec;\n \n \t/* Compute patch-ids for one side */\n \tfor (p = list; p; p = p->next) {\ndiff --git a/tree-diff.c b/tree-diff.c\nindex cd659c6..7a4cc4b 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -100,16 +100,17 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \tint pathlen;\n \tint never_interesting = -1;\n \n-\tif (!opt->nr_paths)\n+\tif (!opt->pathspec.nr)\n \t\treturn 1;\n \n \tsha1 = tree_entry_extract(desc, &path, &mode);\n \n \tpathlen = tree_entry_len(path, sha1);\n \n-\tfor (i = 0; i < opt->nr_paths; i++) {\n-\t\tconst char *match = opt->paths[i];\n-\t\tint matchlen = opt->pathlens[i];\n+\tfor (i = 0; i < opt->pathspec.nr; i++) {\n+\t\tconst struct pathspec_item *item = opt->pathspec.items+i;\n+\t\tconst char *match = item->match;\n+\t\tint matchlen = item->len;\n \t\tint m = -1; /* signals that we haven't called strncmp() */\n \n \t\tif (baselen >= matchlen) {\n@@ -289,7 +290,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru\n \t\tif (DIFF_OPT_TST(opt, QUICK) &&\n \t\t    DIFF_OPT_TST(opt, HAS_CHANGES))\n \t\t\tbreak;\n-\t\tif (opt->nr_paths) {\n+\t\tif (opt->pathspec.nr) {\n \t\t\tskip_uninteresting(t1, base, baselen, opt);\n \t\t\tskip_uninteresting(t2, base, baselen, opt);\n \t\t}\n@@ -348,7 +349,7 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \tDIFF_OPT_SET(&diff_opts, RECURSIVE);\n \tDIFF_OPT_SET(&diff_opts, FIND_COPIES_HARDER);\n \tdiff_opts.output_format = DIFF_FORMAT_NO_OUTPUT;\n-\tdiff_opts.single_follow = opt->paths[0];\n+\tdiff_opts.single_follow = opt->pathspec.raw[0];\n \tdiff_opts.break_opt = opt->break_opt;\n \tpaths[0] = NULL;\n \tdiff_tree_setup_paths(paths, &diff_opts);\n@@ -368,15 +369,16 @@ static void try_to_follow_renames(struct tree_desc *t1, struct tree_desc *t2, co\n \t\t * diff_queued_diff, we will also use that as the path in\n \t\t * the future!\n \t\t */\n-\t\tif ((p->status == 'R' || p->status == 'C') && !strcmp(p->two->path, opt->paths[0])) {\n+\t\tif ((p->status == 'R' || p->status == 'C') &&\n+\t\t    !strcmp(p->two->path, opt->pathspec.raw[0])) {\n \t\t\t/* Switch the file-pairs around */\n \t\t\tq->queue[i] = choice;\n \t\t\tchoice = p;\n \n \t\t\t/* Update the path we use from now on.. */\n \t\t\tdiff_tree_release_paths(opt);\n-\t\t\topt->paths[0] = xstrdup(p->one->path);\n-\t\t\tdiff_tree_setup_paths(opt->paths, opt);\n+\t\t\topt->pathspec.raw[0] = xstrdup(p->one->path);\n+\t\t\tdiff_tree_setup_paths(opt->pathspec.raw, opt);\n \n \t\t\t/*\n \t\t\t * The caller expects us to return a set of vanilla\n@@ -451,36 +453,12 @@ int diff_root_tree_sha1(const unsigned char *new, const char *base, struct diff_\n \treturn retval;\n }\n \n-static int count_paths(const char **paths)\n-{\n-\tint i = 0;\n-\twhile (*paths++)\n-\t\ti++;\n-\treturn i;\n-}\n-\n void diff_tree_release_paths(struct diff_options *opt)\n {\n-\tfree(opt->pathlens);\n+\tfree_pathspec(&opt->pathspec);\n }\n \n void diff_tree_setup_paths(const char **p, struct diff_options *opt)\n {\n-\topt->nr_paths = 0;\n-\topt->pathlens = NULL;\n-\topt->paths = NULL;\n-\n-\tif (p) {\n-\t\tint i;\n-\n-\t\topt->paths = p;\n-\t\topt->nr_paths = count_paths(p);\n-\t\tif (opt->nr_paths == 0) {\n-\t\t\topt->pathlens = NULL;\n-\t\t\treturn;\n-\t\t}\n-\t\topt->pathlens = xmalloc(opt->nr_paths * sizeof(int));\n-\t\tfor (i=0; i < opt->nr_paths; i++)\n-\t\t\topt->pathlens[i] = strlen(p[i]);\n-\t}\n+\tinit_pathspec(&opt->pathspec, p);\n }\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158179","messageId":"1292425376-14550-5-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 04/21] tree_entry_interesting(): remove dependency on struct diff_options","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:39Z","receivedAt":"2010-12-15T15:02:39Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This function can be potentially used in more places than just\ntree-diff.c. \"struct diff_options\" does not make much sense outside\ndiff_tree_sha1().\n\nWhile removing the use of diff_options, it also removes\ntree_entry_extract() call, which means S_ISDIR() uses the entry->mode\ndirectly, without being filtered by canon_mode() (called internally\ninside tree_entry_extract).\n\nThe only use of the mode information in this function is to check the\ntype of the entry by giving it to S_ISDIR() macro, and the result does\nnot change with or without canon_mode(), so it is ok to bypass\ntree_entry_extract().\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree-diff.c |   26 ++++++++++----------------\n 1 files changed, 10 insertions(+), 16 deletions(-)\n\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 7a4cc4b..57e8909 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -91,24 +91,19 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const\n  *  - zero for no\n  *  - negative for \"no, and no subsequent entries will be either\"\n  */\n-static int tree_entry_interesting(struct tree_desc *desc, const char *base, int baselen, struct diff_options *opt)\n+static int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen, const struct pathspec *ps)\n {\n-\tconst char *path;\n-\tconst unsigned char *sha1;\n-\tunsigned mode;\n \tint i;\n \tint pathlen;\n \tint never_interesting = -1;\n \n-\tif (!opt->pathspec.nr)\n+\tif (!ps || !ps->nr)\n \t\treturn 1;\n \n-\tsha1 = tree_entry_extract(desc, &path, &mode);\n-\n-\tpathlen = tree_entry_len(path, sha1);\n+\tpathlen = tree_entry_len(entry->path, entry->sha1);\n \n-\tfor (i = 0; i < opt->pathspec.nr; i++) {\n-\t\tconst struct pathspec_item *item = opt->pathspec.items+i;\n+\tfor (i = 0; i < ps->nr; i++) {\n+\t\tconst struct pathspec_item *item = ps->items+i;\n \t\tconst char *match = item->match;\n \t\tint matchlen = item->len;\n \t\tint m = -1; /* signals that we haven't called strncmp() */\n@@ -148,7 +143,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t\t * Does match sort strictly earlier than path\n \t\t\t * with their common parts?\n \t\t\t */\n-\t\t\tm = strncmp(match, path,\n+\t\t\tm = strncmp(match, entry->path,\n \t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n \t\t\tif (m < 0)\n \t\t\t\tcontinue;\n@@ -175,7 +170,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\tif (matchlen > pathlen) {\n \t\t\tif (match[pathlen] != '/')\n \t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(mode))\n+\t\t\tif (!S_ISDIR(entry->mode))\n \t\t\t\tcontinue;\n \t\t}\n \n@@ -184,7 +179,7 @@ static int tree_entry_interesting(struct tree_desc *desc, const char *base, int\n \t\t\t * we cheated and did not do strncmp(), so we do\n \t\t\t * that here.\n \t\t\t */\n-\t\t\tm = strncmp(match, path, pathlen);\n+\t\t\tm = strncmp(match, entry->path, pathlen);\n \n \t\t/*\n \t\t * If common part matched earlier then it is a hit,\n@@ -207,8 +202,7 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(desc, base, baselen,\n-\t\t\t\t\t\t      opt);\n+\t\t\tshow = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n \t\t}\n@@ -267,7 +261,7 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(t, base, baselen, opt);\n+\t\t\tshow = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n \t\t}\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158163","messageId":"1292425376-14550-6-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 05/21] Move tree_entry_interesting() to tree-walk.c and export it","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:40Z","receivedAt":"2010-12-15T15:02:40Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Signed-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree-diff.c |  110 ---------------------------------------------------------\n tree-walk.c |  112 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n tree-walk.h |    2 +\n 3 files changed, 114 insertions(+), 110 deletions(-)\n\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 57e8909..28a69dc 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -82,116 +82,6 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const\n \treturn 0;\n }\n \n-/*\n- * Is a tree entry interesting given the pathspec we have?\n- *\n- * Return:\n- *  - 2 for \"yes, and all subsequent entries will be\"\n- *  - 1 for yes\n- *  - zero for no\n- *  - negative for \"no, and no subsequent entries will be either\"\n- */\n-static int tree_entry_interesting(const struct name_entry *entry, const char *base, int baselen, const struct pathspec *ps)\n-{\n-\tint i;\n-\tint pathlen;\n-\tint never_interesting = -1;\n-\n-\tif (!ps || !ps->nr)\n-\t\treturn 1;\n-\n-\tpathlen = tree_entry_len(entry->path, entry->sha1);\n-\n-\tfor (i = 0; i < ps->nr; i++) {\n-\t\tconst struct pathspec_item *item = ps->items+i;\n-\t\tconst char *match = item->match;\n-\t\tint matchlen = item->len;\n-\t\tint m = -1; /* signals that we haven't called strncmp() */\n-\n-\t\tif (baselen >= matchlen) {\n-\t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (strncmp(base, match, matchlen))\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * If the base is a subdirectory of a path which\n-\t\t\t * was specified, all of them are interesting.\n-\t\t\t */\n-\t\t\tif (!matchlen ||\n-\t\t\t    base[matchlen] == '/' ||\n-\t\t\t    match[matchlen - 1] == '/')\n-\t\t\t\treturn 2;\n-\n-\t\t\t/* Just a random prefix match */\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\t/* Does the base match? */\n-\t\tif (strncmp(base, match, baselen))\n-\t\t\tcontinue;\n-\n-\t\tmatch += baselen;\n-\t\tmatchlen -= baselen;\n-\n-\t\tif (never_interesting) {\n-\t\t\t/*\n-\t\t\t * We have not seen any match that sorts later\n-\t\t\t * than the current path.\n-\t\t\t */\n-\n-\t\t\t/*\n-\t\t\t * Does match sort strictly earlier than path\n-\t\t\t * with their common parts?\n-\t\t\t */\n-\t\t\tm = strncmp(match, entry->path,\n-\t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n-\t\t\tif (m < 0)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * If we come here even once, that means there is at\n-\t\t\t * least one pathspec that would sort equal to or\n-\t\t\t * later than the path we are currently looking at.\n-\t\t\t * In other words, if we have never reached this point\n-\t\t\t * after iterating all pathspecs, it means all\n-\t\t\t * pathspecs are either outside of base, or inside the\n-\t\t\t * base but sorts strictly earlier than the current\n-\t\t\t * one.  In either case, they will never match the\n-\t\t\t * subsequent entries.  In such a case, we initialized\n-\t\t\t * the variable to -1 and that is what will be\n-\t\t\t * returned, allowing the caller to terminate early.\n-\t\t\t */\n-\t\t\tnever_interesting = 0;\n-\t\t}\n-\n-\t\tif (pathlen > matchlen)\n-\t\t\tcontinue;\n-\n-\t\tif (matchlen > pathlen) {\n-\t\t\tif (match[pathlen] != '/')\n-\t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(entry->mode))\n-\t\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (m == -1)\n-\t\t\t/*\n-\t\t\t * we cheated and did not do strncmp(), so we do\n-\t\t\t * that here.\n-\t\t\t */\n-\t\t\tm = strncmp(match, entry->path, pathlen);\n-\n-\t\t/*\n-\t\t * If common part matched earlier then it is a hit,\n-\t\t * because we rejected the case where path is not a\n-\t\t * leading directory and is shorter than match.\n-\t\t */\n-\t\tif (!m)\n-\t\t\treturn 1;\n-\t}\n-\treturn never_interesting; /* No matches */\n-}\n-\n /* A whole sub-tree went away or appeared */\n static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)\n {\ndiff --git a/tree-walk.c b/tree-walk.c\nindex a9bbf4e..a2e2a99 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -455,3 +455,115 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch\n \tfree(tree);\n \treturn retval;\n }\n+\n+/*\n+ * Is a tree entry interesting given the pathspec we have?\n+ *\n+ * Return:\n+ *  - 2 for \"yes, and all subsequent entries will be\"\n+ *  - 1 for yes\n+ *  - zero for no\n+ *  - negative for \"no, and no subsequent entries will be either\"\n+ */\n+int tree_entry_interesting(const struct name_entry *entry,\n+\t\t\t   const char *base, int baselen,\n+\t\t\t   const struct pathspec *ps)\n+{\n+\tint i;\n+\tint pathlen;\n+\tint never_interesting = -1;\n+\n+\tif (!ps || !ps->nr)\n+\t\treturn 1;\n+\n+\tpathlen = tree_entry_len(entry->path, entry->sha1);\n+\n+\tfor (i = 0; i < ps->nr; i++) {\n+\t\tconst struct pathspec_item *item = ps->items+i;\n+\t\tconst char *match = item->match;\n+\t\tint matchlen = item->len;\n+\t\tint m = -1; /* signals that we haven't called strncmp() */\n+\n+\t\tif (baselen >= matchlen) {\n+\t\t\t/* If it doesn't match, move along... */\n+\t\t\tif (strncmp(base, match, matchlen))\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * If the base is a subdirectory of a path which\n+\t\t\t * was specified, all of them are interesting.\n+\t\t\t */\n+\t\t\tif (!matchlen ||\n+\t\t\t    base[matchlen] == '/' ||\n+\t\t\t    match[matchlen - 1] == '/')\n+\t\t\t\treturn 2;\n+\n+\t\t\t/* Just a random prefix match */\n+\t\t\tcontinue;\n+\t\t}\n+\n+\t\t/* Does the base match? */\n+\t\tif (strncmp(base, match, baselen))\n+\t\t\tcontinue;\n+\n+\t\tmatch += baselen;\n+\t\tmatchlen -= baselen;\n+\n+\t\tif (never_interesting) {\n+\t\t\t/*\n+\t\t\t * We have not seen any match that sorts later\n+\t\t\t * than the current path.\n+\t\t\t */\n+\n+\t\t\t/*\n+\t\t\t * Does match sort strictly earlier than path\n+\t\t\t * with their common parts?\n+\t\t\t */\n+\t\t\tm = strncmp(match, entry->path,\n+\t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n+\t\t\tif (m < 0)\n+\t\t\t\tcontinue;\n+\n+\t\t\t/*\n+\t\t\t * If we come here even once, that means there is at\n+\t\t\t * least one pathspec that would sort equal to or\n+\t\t\t * later than the path we are currently looking at.\n+\t\t\t * In other words, if we have never reached this point\n+\t\t\t * after iterating all pathspecs, it means all\n+\t\t\t * pathspecs are either outside of base, or inside the\n+\t\t\t * base but sorts strictly earlier than the current\n+\t\t\t * one.  In either case, they will never match the\n+\t\t\t * subsequent entries.  In such a case, we initialized\n+\t\t\t * the variable to -1 and that is what will be\n+\t\t\t * returned, allowing the caller to terminate early.\n+\t\t\t */\n+\t\t\tnever_interesting = 0;\n+\t\t}\n+\n+\t\tif (pathlen > matchlen)\n+\t\t\tcontinue;\n+\n+\t\tif (matchlen > pathlen) {\n+\t\t\tif (match[pathlen] != '/')\n+\t\t\t\tcontinue;\n+\t\t\tif (!S_ISDIR(entry->mode))\n+\t\t\t\tcontinue;\n+\t\t}\n+\n+\t\tif (m == -1)\n+\t\t\t/*\n+\t\t\t * we cheated and did not do strncmp(), so we do\n+\t\t\t * that here.\n+\t\t\t */\n+\t\t\tm = strncmp(match, entry->path, pathlen);\n+\n+\t\t/*\n+\t\t * If common part matched earlier then it is a hit,\n+\t\t * because we rejected the case where path is not a\n+\t\t * leading directory and is shorter than match.\n+\t\t */\n+\t\tif (!m)\n+\t\t\treturn 1;\n+\t}\n+\treturn never_interesting; /* No matches */\n+}\ndiff --git a/tree-walk.h b/tree-walk.h\nindex 7e3e0b5..c12f0a2 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -60,4 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru\n \treturn info->pathlen + tree_entry_len(n->path, n->sha1);\n }\n \n+extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps);\n+\n #endif\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158164","messageId":"1292425376-14550-7-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 06/21] glossary: define pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:41Z","receivedAt":"2010-12-15T15:02:41Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"From: Jonathan Nieder <jrnieder@gmail.com>\n\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n Documentation/glossary-content.txt |   23 +++++++++++++++++++++++\n 1 files changed, 23 insertions(+), 0 deletions(-)\n\ndiff --git a/Documentation/glossary-content.txt b/Documentation/glossary-content.txt\nindex 1f029f8..4ed2a28 100644\n--- a/Documentation/glossary-content.txt\n+++ b/Documentation/glossary-content.txt\n@@ -273,6 +273,29 @@ This commit is referred to as a \"merge commit\", or sometimes just a\n \t<<def_pack,pack>>, to assist in efficiently accessing the contents of a\n \tpack.\n \n+[[def_pathspec]]pathspec::\n+       Pattern used to specify paths.\n++\n+Pathspecs are used on the command line of \"git ls-files\", \"git\n+ls-tree\", \"git grep\", \"git checkout\", and many other commands to\n+limit the scope of operations to some subset of the tree or\n+worktree.  See the documentation of each command for whether\n+paths are relative to the current directory or toplevel.  The\n+pathspec syntax is as follows:\n+\n+* any path matches itself\n+* the pathspec up to the last slash represents a\n+  directory prefix.  The scope of that pathspec is\n+  limited to that subtree.\n+* the rest of the pathspec is a pattern for the remainder\n+  of the pathname.  Paths relative to the directory\n+  prefix will be matched against that pattern using fnmatch(3);\n+  in particular, '*' and '?' _can_ match directory separators.\n++\n+For example, Documentation/*.jpg will match all .jpg files\n+in the Documentation subtree,\n+including Documentation/chapter_1/figure_1.jpg.\n+\n [[def_parent]]parent::\n \tA <<def_commit_object,commit object>> contains a (possibly empty) list\n \tof the logical predecessor(s) in the line of development, i.e. its\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158166","messageId":"1292425376-14550-8-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 07/21] diff-tree: convert base+baselen to writable strbuf","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:42Z","receivedAt":"2010-12-15T15:02:42Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"In traversing trees, a full path is splitted into two parts: base\ndirectory and entry. They are however quite often concatenated\nwhenever a full path is needed. Current code allocates a new buffer,\ndo two memcpy(), use it, then release.\n\nInstead this patch turns \"base\" to a writable, extendable buffer. When\na concatenation is needed, the callee only needs to append \"entry\" to\nbase, use it, then truncate the entry out again. \"base\" must remain\nunchanged before and after entering a function.\n\nThis avoids quite a bit of malloc() and memcpy().\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree-diff.c |  119 ++++++++++++++++++++++++++--------------------------------\n tree-walk.c |    5 +-\n tree-walk.h |    2 +-\n 3 files changed, 57 insertions(+), 69 deletions(-)\n\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 28a69dc..67fa6c4 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -6,34 +6,18 @@\n #include \"diffcore.h\"\n #include \"tree.h\"\n \n-static char *malloc_base(const char *base, int baselen, const char *path, int pathlen)\n-{\n-\tchar *newbase = xmalloc(baselen + pathlen + 2);\n-\tmemcpy(newbase, base, baselen);\n-\tmemcpy(newbase + baselen, path, pathlen);\n-\tmemcpy(newbase + baselen + pathlen, \"/\", 2);\n-\treturn newbase;\n-}\n-\n-static char *malloc_fullname(const char *base, int baselen, const char *path, int pathlen)\n-{\n-\tchar *fullname = xmalloc(baselen + pathlen + 1);\n-\tmemcpy(fullname, base, baselen);\n-\tmemcpy(fullname + baselen, path, pathlen);\n-\tfullname[baselen + pathlen] = 0;\n-\treturn fullname;\n-}\n-\n-static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,\n-\t\t       const char *base, int baselen);\n+static void show_entry(struct diff_options *opt, const char *prefix,\n+\t\t       struct tree_desc *desc, struct strbuf *base);\n \n-static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const char *base, int baselen, struct diff_options *opt)\n+static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2,\n+\t\t\t      struct strbuf *base, struct diff_options *opt)\n {\n \tunsigned mode1, mode2;\n \tconst char *path1, *path2;\n \tconst unsigned char *sha1, *sha2;\n \tint cmp, pathlen1, pathlen2;\n-\tchar *fullname;\n+\tint old_baselen = base->len;\n+\tint retval = 0;\n \n \tsha1 = tree_entry_extract(t1, &path1, &mode1);\n \tsha2 = tree_entry_extract(t2, &path2, &mode2);\n@@ -42,11 +26,11 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const\n \tpathlen2 = tree_entry_len(path2, sha2);\n \tcmp = base_name_compare(path1, pathlen1, mode1, path2, pathlen2, mode2);\n \tif (cmp < 0) {\n-\t\tshow_entry(opt, \"-\", t1, base, baselen);\n+\t\tshow_entry(opt, \"-\", t1, base);\n \t\treturn -1;\n \t}\n \tif (cmp > 0) {\n-\t\tshow_entry(opt, \"+\", t2, base, baselen);\n+\t\tshow_entry(opt, \"+\", t2, base);\n \t\treturn 1;\n \t}\n \tif (!DIFF_OPT_TST(opt, FIND_COPIES_HARDER) && !hashcmp(sha1, sha2) && mode1 == mode2)\n@@ -57,33 +41,29 @@ static int compare_tree_entry(struct tree_desc *t1, struct tree_desc *t2, const\n \t * file, we need to consider it a remove and an add.\n \t */\n \tif (S_ISDIR(mode1) != S_ISDIR(mode2)) {\n-\t\tshow_entry(opt, \"-\", t1, base, baselen);\n-\t\tshow_entry(opt, \"+\", t2, base, baselen);\n+\t\tshow_entry(opt, \"-\", t1, base);\n+\t\tshow_entry(opt, \"+\", t2, base);\n \t\treturn 0;\n \t}\n \n+\tstrbuf_add(base, path1, pathlen1);\n \tif (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode1)) {\n-\t\tint retval;\n-\t\tchar *newbase = malloc_base(base, baselen, path1, pathlen1);\n \t\tif (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {\n-\t\t\tnewbase[baselen + pathlen1] = 0;\n \t\t\topt->change(opt, mode1, mode2,\n-\t\t\t\t    sha1, sha2, newbase, 0, 0);\n-\t\t\tnewbase[baselen + pathlen1] = '/';\n+\t\t\t\t    sha1, sha2, base->buf, 0, 0);\n \t\t}\n-\t\tretval = diff_tree_sha1(sha1, sha2, newbase, opt);\n-\t\tfree(newbase);\n-\t\treturn retval;\n+\t\tstrbuf_addch(base, '/');\n+\t\tretval = diff_tree_sha1(sha1, sha2, base->buf, opt);\n \t}\n-\n-\tfullname = malloc_fullname(base, baselen, path1, pathlen1);\n-\topt->change(opt, mode1, mode2, sha1, sha2, fullname, 0, 0);\n-\tfree(fullname);\n+\telse\n+\t\topt->change(opt, mode1, mode2, sha1, sha2, base->buf, 0, 0);\n+\tstrbuf_setlen(base, old_baselen);\n \treturn 0;\n }\n \n /* A whole sub-tree went away or appeared */\n-static void show_tree(struct diff_options *opt, const char *prefix, struct tree_desc *desc, const char *base, int baselen)\n+static void show_tree(struct diff_options *opt, const char *prefix,\n+\t\t      struct tree_desc *desc, struct strbuf *base)\n {\n \tint all_interesting = 0;\n \twhile (desc->size) {\n@@ -92,30 +72,32 @@ static void show_tree(struct diff_options *opt, const char *prefix, struct tree_\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(&desc->entry, base, baselen, &opt->pathspec);\n+\t\t\tshow = tree_entry_interesting(&desc->entry, base,\n+\t\t\t\t\t\t      &opt->pathspec);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n \t\t}\n \t\tif (show < 0)\n \t\t\tbreak;\n \t\tif (show)\n-\t\t\tshow_entry(opt, prefix, desc, base, baselen);\n+\t\t\tshow_entry(opt, prefix, desc, base);\n \t\tupdate_tree_entry(desc);\n \t}\n }\n \n /* A file entry went away or appeared */\n-static void show_entry(struct diff_options *opt, const char *prefix, struct tree_desc *desc,\n-\t\t       const char *base, int baselen)\n+static void show_entry(struct diff_options *opt, const char *prefix,\n+\t\t       struct tree_desc *desc, struct strbuf *base)\n {\n \tunsigned mode;\n \tconst char *path;\n \tconst unsigned char *sha1 = tree_entry_extract(desc, &path, &mode);\n \tint pathlen = tree_entry_len(path, sha1);\n+\tint old_baselen = base->len;\n \n+\tstrbuf_add(base, path, pathlen);\n \tif (DIFF_OPT_TST(opt, RECURSIVE) && S_ISDIR(mode)) {\n \t\tenum object_type type;\n-\t\tchar *newbase = malloc_base(base, baselen, path, pathlen);\n \t\tstruct tree_desc inner;\n \t\tvoid *tree;\n \t\tunsigned long size;\n@@ -124,25 +106,22 @@ static void show_entry(struct diff_options *opt, const char *prefix, struct tree\n \t\tif (!tree || type != OBJ_TREE)\n \t\t\tdie(\"corrupt tree sha %s\", sha1_to_hex(sha1));\n \n-\t\tif (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE)) {\n-\t\t\tnewbase[baselen + pathlen] = 0;\n-\t\t\topt->add_remove(opt, *prefix, mode, sha1, newbase, 0);\n-\t\t\tnewbase[baselen + pathlen] = '/';\n-\t\t}\n+\t\tif (DIFF_OPT_TST(opt, TREE_IN_RECURSIVE))\n+\t\t\topt->add_remove(opt, *prefix, mode, sha1, base->buf, 0);\n \n-\t\tinit_tree_desc(&inner, tree, size);\n-\t\tshow_tree(opt, prefix, &inner, newbase, baselen + 1 + pathlen);\n+\t\tstrbuf_addch(base, '/');\n \n+\t\tinit_tree_desc(&inner, tree, size);\n+\t\tshow_tree(opt, prefix, &inner, base);\n \t\tfree(tree);\n-\t\tfree(newbase);\n-\t} else {\n-\t\tchar *fullname = malloc_fullname(base, baselen, path, pathlen);\n-\t\topt->add_remove(opt, prefix[0], mode, sha1, fullname, 0);\n-\t\tfree(fullname);\n-\t}\n+\t} else\n+\t\topt->add_remove(opt, prefix[0], mode, sha1, base->buf, 0);\n+\n+\tstrbuf_setlen(base, old_baselen);\n }\n \n-static void skip_uninteresting(struct tree_desc *t, const char *base, int baselen, struct diff_options *opt)\n+static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,\n+\t\t\t       struct diff_options *opt)\n {\n \tint all_interesting = 0;\n \twhile (t->size) {\n@@ -151,7 +130,8 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(&t->entry, base, baselen, &opt->pathspec);\n+\t\t\tshow = tree_entry_interesting(&t->entry, base,\n+\t\t\t\t\t\t      &opt->pathspec);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n \t\t}\n@@ -166,31 +146,36 @@ static void skip_uninteresting(struct tree_desc *t, const char *base, int basele\n \t}\n }\n \n-int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, struct diff_options *opt)\n+int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n+\t      const char *base_str, struct diff_options *opt)\n {\n-\tint baselen = strlen(base);\n+\tstruct strbuf base;\n+\tint baselen = strlen(base_str);\n+\n+\tstrbuf_init(&base, PATH_MAX);\n+\tstrbuf_add(&base, base_str, baselen);\n \n \tfor (;;) {\n \t\tif (DIFF_OPT_TST(opt, QUICK) &&\n \t\t    DIFF_OPT_TST(opt, HAS_CHANGES))\n \t\t\tbreak;\n \t\tif (opt->pathspec.nr) {\n-\t\t\tskip_uninteresting(t1, base, baselen, opt);\n-\t\t\tskip_uninteresting(t2, base, baselen, opt);\n+\t\t\tskip_uninteresting(t1, &base, opt);\n+\t\t\tskip_uninteresting(t2, &base, opt);\n \t\t}\n \t\tif (!t1->size) {\n \t\t\tif (!t2->size)\n \t\t\t\tbreak;\n-\t\t\tshow_entry(opt, \"+\", t2, base, baselen);\n+\t\t\tshow_entry(opt, \"+\", t2, &base);\n \t\t\tupdate_tree_entry(t2);\n \t\t\tcontinue;\n \t\t}\n \t\tif (!t2->size) {\n-\t\t\tshow_entry(opt, \"-\", t1, base, baselen);\n+\t\t\tshow_entry(opt, \"-\", t1, &base);\n \t\t\tupdate_tree_entry(t1);\n \t\t\tcontinue;\n \t\t}\n-\t\tswitch (compare_tree_entry(t1, t2, base, baselen, opt)) {\n+\t\tswitch (compare_tree_entry(t1, t2, &base, opt)) {\n \t\tcase -1:\n \t\t\tupdate_tree_entry(t1);\n \t\t\tcontinue;\n@@ -203,6 +188,8 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru\n \t\t}\n \t\tdie(\"git diff-tree: internal error\");\n \t}\n+\n+\tstrbuf_release(&base);\n \treturn 0;\n }\n \ndiff --git a/tree-walk.c b/tree-walk.c\nindex a2e2a99..0830676 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -466,12 +466,13 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch\n  *  - negative for \"no, and no subsequent entries will be either\"\n  */\n int tree_entry_interesting(const struct name_entry *entry,\n-\t\t\t   const char *base, int baselen,\n+\t\t\t   const struct strbuf *base_buf,\n \t\t\t   const struct pathspec *ps)\n {\n \tint i;\n-\tint pathlen;\n+\tint pathlen, baselen = base_buf->len;\n \tint never_interesting = -1;\n+\tconst char *base = base_buf->buf;\n \n \tif (!ps || !ps->nr)\n \t\treturn 1;\ndiff --git a/tree-walk.h b/tree-walk.h\nindex c12f0a2..f81c232 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru\n \treturn info->pathlen + tree_entry_len(n->path, n->sha1);\n }\n \n-extern int tree_entry_interesting(const struct name_entry *, const char *, int, const struct pathspec *ps);\n+extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps);\n \n #endif\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158165","messageId":"1292425376-14550-9-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 08/21] tree_entry_interesting(): refactor into separate smaller functions","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:43Z","receivedAt":"2010-12-15T15:02:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree-walk.c |  170 ++++++++++++++++++++++++++++++++---------------------------\n 1 files changed, 93 insertions(+), 77 deletions(-)\n\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 0830676..5012705 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -456,6 +456,90 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch\n \treturn retval;\n }\n \n+static int match_entry(const struct name_entry *entry, int pathlen,\n+\t\t       const char *match, int matchlen,\n+\t\t       int *never_interesting)\n+{\n+\tint m = -1; /* signals that we haven't called strncmp() */\n+\n+\tif (*never_interesting) {\n+\t\t/*\n+\t\t * We have not seen any match that sorts later\n+\t\t * than the current path.\n+\t\t */\n+\n+\t\t/*\n+\t\t * Does match sort strictly earlier than path\n+\t\t * with their common parts?\n+\t\t */\n+\t\tm = strncmp(match, entry->path,\n+\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n+\t\tif (m < 0)\n+\t\t\treturn 0;\n+\n+\t\t/*\n+\t\t * If we come here even once, that means there is at\n+\t\t * least one pathspec that would sort equal to or\n+\t\t * later than the path we are currently looking at.\n+\t\t * In other words, if we have never reached this point\n+\t\t * after iterating all pathspecs, it means all\n+\t\t * pathspecs are either outside of base, or inside the\n+\t\t * base but sorts strictly earlier than the current\n+\t\t * one.  In either case, they will never match the\n+\t\t * subsequent entries.  In such a case, we initialized\n+\t\t * the variable to -1 and that is what will be\n+\t\t * returned, allowing the caller to terminate early.\n+\t\t */\n+\t\t*never_interesting = 0;\n+\t}\n+\n+\tif (pathlen > matchlen)\n+\t\treturn 0;\n+\n+\tif (matchlen > pathlen) {\n+\t\tif (match[pathlen] != '/')\n+\t\t\treturn 0;\n+\t\tif (!S_ISDIR(entry->mode))\n+\t\t\treturn 0;\n+\t}\n+\n+\tif (m == -1)\n+\t\t/*\n+\t\t * we cheated and did not do strncmp(), so we do\n+\t\t * that here.\n+\t\t */\n+\t\tm = strncmp(match, entry->path, pathlen);\n+\n+\t/*\n+\t * If common part matched earlier then it is a hit,\n+\t * because we rejected the case where path is not a\n+\t * leading directory and is shorter than match.\n+\t */\n+\tif (!m)\n+\t\treturn 1;\n+\n+\treturn 0;\n+}\n+\n+static int match_dir_prefix(const char *base, int baselen,\n+\t\t\t    const char *match, int matchlen)\n+{\n+\tif (strncmp(base, match, matchlen))\n+\t\treturn 0;\n+\n+\t/*\n+\t * If the base is a subdirectory of a path which\n+\t * was specified, all of them are interesting.\n+\t */\n+\tif (!matchlen ||\n+\t    base[matchlen] == '/' ||\n+\t    match[matchlen - 1] == '/')\n+\t\treturn 1;\n+\n+\t/* Just a random prefix match */\n+\treturn 0;\n+}\n+\n /*\n  * Is a tree entry interesting given the pathspec we have?\n  *\n@@ -466,13 +550,12 @@ int get_tree_entry(const unsigned char *tree_sha1, const char *name, unsigned ch\n  *  - negative for \"no, and no subsequent entries will be either\"\n  */\n int tree_entry_interesting(const struct name_entry *entry,\n-\t\t\t   const struct strbuf *base_buf,\n+\t\t\t   const struct strbuf *base,\n \t\t\t   const struct pathspec *ps)\n {\n \tint i;\n-\tint pathlen, baselen = base_buf->len;\n+\tint pathlen, baselen = base->len;\n \tint never_interesting = -1;\n-\tconst char *base = base_buf->buf;\n \n \tif (!ps || !ps->nr)\n \t\treturn 1;\n@@ -483,88 +566,21 @@ int tree_entry_interesting(const struct name_entry *entry,\n \t\tconst struct pathspec_item *item = ps->items+i;\n \t\tconst char *match = item->match;\n \t\tint matchlen = item->len;\n-\t\tint m = -1; /* signals that we haven't called strncmp() */\n \n \t\tif (baselen >= matchlen) {\n \t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (strncmp(base, match, matchlen))\n+\t\t\tif (!match_dir_prefix(base->buf, baselen, match, matchlen))\n \t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * If the base is a subdirectory of a path which\n-\t\t\t * was specified, all of them are interesting.\n-\t\t\t */\n-\t\t\tif (!matchlen ||\n-\t\t\t    base[matchlen] == '/' ||\n-\t\t\t    match[matchlen - 1] == '/')\n-\t\t\t\treturn 2;\n-\n-\t\t\t/* Just a random prefix match */\n-\t\t\tcontinue;\n+\t\t\treturn 2;\n \t\t}\n \n \t\t/* Does the base match? */\n-\t\tif (strncmp(base, match, baselen))\n-\t\t\tcontinue;\n-\n-\t\tmatch += baselen;\n-\t\tmatchlen -= baselen;\n-\n-\t\tif (never_interesting) {\n-\t\t\t/*\n-\t\t\t * We have not seen any match that sorts later\n-\t\t\t * than the current path.\n-\t\t\t */\n-\n-\t\t\t/*\n-\t\t\t * Does match sort strictly earlier than path\n-\t\t\t * with their common parts?\n-\t\t\t */\n-\t\t\tm = strncmp(match, entry->path,\n-\t\t\t\t    (matchlen < pathlen) ? matchlen : pathlen);\n-\t\t\tif (m < 0)\n-\t\t\t\tcontinue;\n-\n-\t\t\t/*\n-\t\t\t * If we come here even once, that means there is at\n-\t\t\t * least one pathspec that would sort equal to or\n-\t\t\t * later than the path we are currently looking at.\n-\t\t\t * In other words, if we have never reached this point\n-\t\t\t * after iterating all pathspecs, it means all\n-\t\t\t * pathspecs are either outside of base, or inside the\n-\t\t\t * base but sorts strictly earlier than the current\n-\t\t\t * one.  In either case, they will never match the\n-\t\t\t * subsequent entries.  In such a case, we initialized\n-\t\t\t * the variable to -1 and that is what will be\n-\t\t\t * returned, allowing the caller to terminate early.\n-\t\t\t */\n-\t\t\tnever_interesting = 0;\n+\t\tif (!strncmp(base->buf, match, baselen)) {\n+\t\t\tif (match_entry(entry, pathlen,\n+\t\t\t\t\tmatch + baselen, matchlen - baselen,\n+\t\t\t\t\t&never_interesting))\n+\t\t\t\treturn 1;\n \t\t}\n-\n-\t\tif (pathlen > matchlen)\n-\t\t\tcontinue;\n-\n-\t\tif (matchlen > pathlen) {\n-\t\t\tif (match[pathlen] != '/')\n-\t\t\t\tcontinue;\n-\t\t\tif (!S_ISDIR(entry->mode))\n-\t\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (m == -1)\n-\t\t\t/*\n-\t\t\t * we cheated and did not do strncmp(), so we do\n-\t\t\t * that here.\n-\t\t\t */\n-\t\t\tm = strncmp(match, entry->path, pathlen);\n-\n-\t\t/*\n-\t\t * If common part matched earlier then it is a hit,\n-\t\t * because we rejected the case where path is not a\n-\t\t * leading directory and is shorter than match.\n-\t\t */\n-\t\tif (!m)\n-\t\t\treturn 1;\n \t}\n \treturn never_interesting; /* No matches */\n }\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158169","messageId":"1292425376-14550-10-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 09/21] tree_entry_interesting(): support depth limit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:44Z","receivedAt":"2010-12-15T15:02:44Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is needed to replace pathspec_matches() in builtin/grep.c.\n\nmax_depth == -1 means infinite depth. Depth limit is only effective\nwhen pathspec.recursive == 1. When pathspec.recursive == 0, the\nbehavior depends on match functions: non-recursive for\ntree_entry_interesting() and recursive for match_pathspec{,_depth}\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h     |    2 ++\n dir.c       |   15 +++++++++++++++\n dir.h       |    1 +\n tree-diff.c |    4 ++++\n tree-walk.c |   19 ++++++++++++++++---\n 5 files changed, 38 insertions(+), 3 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 9eeecc2..b110775 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -496,6 +496,8 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct\n struct pathspec {\n \tconst char **raw; /* get_pathspec() result, not freed by free_pathspec() */\n \tint nr;\n+\tint recursive:1;\n+\tint max_depth;\n \tstruct pathspec_item {\n \t\tconst char *match;\n \t\tint len;\ndiff --git a/dir.c b/dir.c\nindex a88f2ef..79e88f6 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -71,6 +71,21 @@ int fill_directory(struct dir_struct *dir, const char **pathspec)\n \treturn len;\n }\n \n+int within_depth(const char *name, int namelen,\n+\t\t\tint depth, int max_depth)\n+{\n+\tconst char *cp = name, *cpe = name + namelen;\n+\n+\twhile (cp < cpe) {\n+\t\tif (*cp++ != '/')\n+\t\t\tcontinue;\n+\t\tdepth++;\n+\t\tif (depth > max_depth)\n+\t\t\treturn 0;\n+\t}\n+\treturn 1;\n+}\n+\n /*\n  * Does 'match' match the given name?\n  * A match is found if\ndiff --git a/dir.h b/dir.h\nindex 278d84c..c71de08 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -65,6 +65,7 @@ struct dir_struct {\n #define MATCHED_FNMATCH 2\n #define MATCHED_EXACTLY 3\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n+extern int within_depth(const char *name, int namelen, int depth, int max_depth);\n \n extern int fill_directory(struct dir_struct *dir, const char **pathspec);\n extern int read_directory(struct dir_struct *, const char *path, int len, const char **pathspec);\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 67fa6c4..bde2c52 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -152,6 +152,10 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2,\n \tstruct strbuf base;\n \tint baselen = strlen(base_str);\n \n+\t/* Enable recursion indefinitely */\n+\topt->pathspec.recursive = DIFF_OPT_TST(opt, RECURSIVE);\n+\topt->pathspec.max_depth = -1;\n+\n \tstrbuf_init(&base, PATH_MAX);\n \tstrbuf_add(&base, base_str, baselen);\n \ndiff --git a/tree-walk.c b/tree-walk.c\nindex 5012705..91d7b36 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -1,6 +1,7 @@\n #include \"cache.h\"\n #include \"tree-walk.h\"\n #include \"unpack-trees.h\"\n+#include \"dir.h\"\n #include \"tree.h\"\n \n static const char *get_mode(const char *str, unsigned int *modep)\n@@ -557,8 +558,13 @@ int tree_entry_interesting(const struct name_entry *entry,\n \tint pathlen, baselen = base->len;\n \tint never_interesting = -1;\n \n-\tif (!ps || !ps->nr)\n-\t\treturn 1;\n+\tif (!ps->nr) {\n+\t\tif (!ps->recursive || ps->max_depth == -1)\n+\t\t\treturn 1;\n+\t\treturn !!within_depth(base->buf, baselen,\n+\t\t\t\t      !!S_ISDIR(entry->mode),\n+\t\t\t\t      ps->max_depth);\n+\t}\n \n \tpathlen = tree_entry_len(entry->path, entry->sha1);\n \n@@ -571,7 +577,14 @@ int tree_entry_interesting(const struct name_entry *entry,\n \t\t\t/* If it doesn't match, move along... */\n \t\t\tif (!match_dir_prefix(base->buf, baselen, match, matchlen))\n \t\t\t\tcontinue;\n-\t\t\treturn 2;\n+\n+\t\t\tif (!ps->recursive || ps->max_depth == -1)\n+\t\t\t\treturn 2;\n+\n+\t\t\treturn !!within_depth(base->buf + matchlen + 1,\n+\t\t\t\t\t      baselen - matchlen - 1,\n+\t\t\t\t\t      !!S_ISDIR(entry->mode),\n+\t\t\t\t\t      ps->max_depth);\n \t\t}\n \n \t\t/* Does the base match? */\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158181","messageId":"1292425376-14550-11-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 10/21] tree_entry_interesting(): fix depth limit with overlapping pathspecs","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:45Z","receivedAt":"2010-12-15T15:02:45Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"Suppose we have two pathspecs 'a' and 'a/b' (both are dirs) and depth\nlimit 1. In current code, pathspecs are checked in input order. When\n'a/b' is checked against pathspec 'a', it fails depth limit and\ntherefore is excluded, although it should match 'a/b' pathspec.\n\nThis patch reorders all pathspecs alphabetically, then teaches\ntree_entry_interesting() to check against the deepest pathspec first,\nso depth limit of a shallower pathspec won't affect a deeper one.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c       |   13 +++++++++++++\n tree-walk.c |    2 +-\n 2 files changed, 14 insertions(+), 1 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 79e88f6..aa0522d 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1086,6 +1086,15 @@ int remove_path(const char *name)\n \treturn 0;\n }\n \n+static int pathspec_item_cmp(const void *a_, const void *b_)\n+{\n+\tstruct pathspec_item *a, *b;\n+\n+\ta = (struct pathspec_item *)a_;\n+\tb = (struct pathspec_item *)b_;\n+\treturn strcmp(a->match, b->match);\n+}\n+\n int init_pathspec(struct pathspec *pathspec, const char **paths)\n {\n \tconst char **p = paths;\n@@ -1109,6 +1118,10 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)\n \t\titem->match = path;\n \t\titem->len = strlen(path);\n \t}\n+\n+\tqsort(pathspec->items, pathspec->nr,\n+\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n+\n \treturn 0;\n }\n \ndiff --git a/tree-walk.c b/tree-walk.c\nindex 91d7b36..93b05a7 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -568,7 +568,7 @@ int tree_entry_interesting(const struct name_entry *entry,\n \n \tpathlen = tree_entry_len(entry->path, entry->sha1);\n \n-\tfor (i = 0; i < ps->nr; i++) {\n+\tfor (i = ps->nr-1; i >= 0; i--) {\n \t\tconst struct pathspec_item *item = ps->items+i;\n \t\tconst char *match = item->match;\n \t\tint matchlen = item->len;\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158171","messageId":"1292425376-14550-12-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 11/21] tree_entry_interesting(): support wildcard matching","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:46Z","receivedAt":"2010-12-15T15:02:46Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"never_interesting optimization is disabled if there is any wildcard\npathspec, even if it only matches exactly on trees.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h                  |    2 ++\n dir.c                    |    3 +++\n t/t4010-diff-pathspec.sh |   14 ++++++++++++++\n tree-walk.c              |   30 +++++++++++++++++++++++++++---\n tree-walk.h              |    2 +-\n 5 files changed, 47 insertions(+), 4 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex b110775..dc0bfb4 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -496,11 +496,13 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct\n struct pathspec {\n \tconst char **raw; /* get_pathspec() result, not freed by free_pathspec() */\n \tint nr;\n+\tint has_wildcard:1;\n \tint recursive:1;\n \tint max_depth;\n \tstruct pathspec_item {\n \t\tconst char *match;\n \t\tint len;\n+\t\tint has_wildcard:1;\n \t} *items;\n };\n \ndiff --git a/dir.c b/dir.c\nindex aa0522d..66c163f 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1117,6 +1117,9 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)\n \n \t\titem->match = path;\n \t\titem->len = strlen(path);\n+\t\titem->has_wildcard = !no_wildcard(path);\n+\t\tif (item->has_wildcard)\n+\t\t\tpathspec->has_wildcard = 1;\n \t}\n \n \tqsort(pathspec->items, pathspec->nr,\ndiff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh\nindex 94df7ae..4b120f8 100755\n--- a/t/t4010-diff-pathspec.sh\n+++ b/t/t4010-diff-pathspec.sh\n@@ -70,4 +70,18 @@ test_expect_success 'diff-tree pathspec' '\n \ttest_cmp expected current\n '\n \n+EMPTY_TREE=4b825dc642cb6eb9a060e54bf8d69288fbee4904\n+\n+test_expect_success 'diff-tree with wildcard shows dir also matches' '\n+\tgit diff-tree --name-only $EMPTY_TREE $tree -- \"f*\" >result &&\n+\techo file0 >expected &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'diff-tree -r with wildcard' '\n+\tgit diff-tree -r --name-only $EMPTY_TREE $tree -- \"*file1\" >result &&\n+\techo path1/file1 >expected &&\n+\ttest_cmp expected result\n+'\n+\n test_done\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 93b05a7..cc5a4e1 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -551,12 +551,12 @@ static int match_dir_prefix(const char *base, int baselen,\n  *  - negative for \"no, and no subsequent entries will be either\"\n  */\n int tree_entry_interesting(const struct name_entry *entry,\n-\t\t\t   const struct strbuf *base,\n+\t\t\t   struct strbuf *base,\n \t\t\t   const struct pathspec *ps)\n {\n \tint i;\n \tint pathlen, baselen = base->len;\n-\tint never_interesting = -1;\n+\tint never_interesting = ps->has_wildcard ? 0 : -1;\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive || ps->max_depth == -1)\n@@ -576,7 +576,7 @@ int tree_entry_interesting(const struct name_entry *entry,\n \t\tif (baselen >= matchlen) {\n \t\t\t/* If it doesn't match, move along... */\n \t\t\tif (!match_dir_prefix(base->buf, baselen, match, matchlen))\n-\t\t\t\tcontinue;\n+\t\t\t\tgoto match_wildcards;\n \n \t\t\tif (!ps->recursive || ps->max_depth == -1)\n \t\t\t\treturn 2;\n@@ -594,6 +594,30 @@ int tree_entry_interesting(const struct name_entry *entry,\n \t\t\t\t\t&never_interesting))\n \t\t\t\treturn 1;\n \t\t}\n+\n+match_wildcards:\n+\t\tif (!ps->items[i].has_wildcard)\n+\t\t\tcontinue;\n+\n+\t\t/*\n+\t\t * Concatenate base and entry->path into one and do\n+\t\t * fnmatch() on it.\n+\t\t */\n+\n+\t\tstrbuf_add(base, entry->path, pathlen);\n+\n+\t\tif (!fnmatch(match, base->buf, 0)) {\n+\t\t\tstrbuf_setlen(base, baselen);\n+\t\t\treturn 1;\n+\t\t}\n+\t\tstrbuf_setlen(base, baselen);\n+\n+\t\t/*\n+\t\t * Match all directories. We'll try to match files\n+\t\t * later on.\n+\t\t */\n+\t\tif (ps->recursive && S_ISDIR(entry->mode))\n+\t\t\treturn 1;\n \t}\n \treturn never_interesting; /* No matches */\n }\ndiff --git a/tree-walk.h b/tree-walk.h\nindex f81c232..6589ee2 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru\n \treturn info->pathlen + tree_entry_len(n->path, n->sha1);\n }\n \n-extern int tree_entry_interesting(const struct name_entry *, const struct strbuf *, const struct pathspec *ps);\n+extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps);\n \n #endif\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158167","messageId":"1292425376-14550-13-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 12/21] tree_entry_interesting(): optimize wildcard matching when base is matched","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:47Z","receivedAt":"2010-12-15T15:02:47Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"If base is already matched, skip that part when calling\nfnmatch(). This happens quite often if users start a command from\nworktree's subdirectory and prefix is usually prepended to all\npathspecs.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t4010-diff-pathspec.sh |   18 ++++++++++++++++++\n tree-walk.c              |   14 ++++++++++++++\n 2 files changed, 32 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh\nindex 4b120f8..fbc8cd8 100755\n--- a/t/t4010-diff-pathspec.sh\n+++ b/t/t4010-diff-pathspec.sh\n@@ -84,4 +84,22 @@ test_expect_success 'diff-tree -r with wildcard' '\n \ttest_cmp expected result\n '\n \n+test_expect_success 'diff-tree with wildcard shows dir also matches' '\n+\tgit diff-tree --name-only $tree $tree2 -- \"path1/f*\" >result &&\n+\techo path1 >expected &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'diff-tree -r with wildcard from beginning' '\n+\tgit diff-tree -r --name-only $tree $tree2 -- \"path1/*file1\" >result &&\n+\techo path1/file1 >expected &&\n+\ttest_cmp expected result\n+'\n+\n+test_expect_success 'diff-tree -r with wildcard' '\n+\tgit diff-tree -r --name-only $tree $tree2 -- \"path1/f*\" >result &&\n+\techo path1/file1 >expected &&\n+\ttest_cmp expected result\n+'\n+\n test_done\ndiff --git a/tree-walk.c b/tree-walk.c\nindex cc5a4e1..99413b3 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -593,6 +593,20 @@ int tree_entry_interesting(const struct name_entry *entry,\n \t\t\t\t\tmatch + baselen, matchlen - baselen,\n \t\t\t\t\t&never_interesting))\n \t\t\t\treturn 1;\n+\n+\t\t\tif (ps->items[i].has_wildcard) {\n+\t\t\t\tif (!fnmatch(match + baselen, entry->path, 0))\n+\t\t\t\t\treturn 1;\n+\n+\t\t\t\t/*\n+\t\t\t\t * Match all directories. We'll try to\n+\t\t\t\t * match files later on.\n+\t\t\t\t */\n+\t\t\t\tif (ps->recursive && S_ISDIR(entry->mode))\n+\t\t\t\t\treturn 1;\n+\t\t\t}\n+\n+\t\t\tcontinue;\n \t\t}\n \n match_wildcards:\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158168","messageId":"1292425376-14550-14-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 13/21] pathspec: add match_pathspec_depth()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:48Z","receivedAt":"2010-12-15T15:02:48Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"match_pathspec_depth() is a clone of match_pathspec() except that it\ncan take depth limit. Computation is a bit lighter compared to\nmatch_pathspec() because it's usually precomputed and stored in struct\npathspec.\n\nIn long term, match_pathspec() and match_one() should be removed in\nfavor of this function.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n dir.c |   89 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++\n dir.h |    3 ++\n 2 files changed, 92 insertions(+), 0 deletions(-)\n\ndiff --git a/dir.c b/dir.c\nindex 66c163f..b1407a5 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -169,6 +169,95 @@ int match_pathspec(const char **pathspec, const char *name, int namelen,\n \treturn retval;\n }\n \n+/*\n+ * Does 'match' match the given name?\n+ * A match is found if\n+ *\n+ * (1) the 'match' string is leading directory of 'name', or\n+ * (2) the 'match' string is a wildcard and matches 'name', or\n+ * (3) the 'match' string is exactly the same as 'name'.\n+ *\n+ * and the return value tells which case it was.\n+ *\n+ * It returns 0 when there is no match.\n+ */\n+static int match_pathspec_item(const struct pathspec_item *item, int prefix,\n+\t\t\t       const char *name, int namelen)\n+{\n+\t/* name/namelen has prefix cut off by caller */\n+\tconst char *match = item->match + prefix;\n+\tint matchlen = item->len - prefix;\n+\n+\t/* If the match was just the prefix, we matched */\n+\tif (!*match)\n+\t\treturn MATCHED_RECURSIVELY;\n+\n+\tif (matchlen <= namelen && !strncmp(match, name, matchlen)) {\n+\t\tif (matchlen == namelen)\n+\t\t\treturn MATCHED_EXACTLY;\n+\n+\t\tif (match[matchlen-1] == '/' || name[matchlen] == '/')\n+\t\t\treturn MATCHED_RECURSIVELY;\n+\t}\n+\n+\tif (item->has_wildcard && !fnmatch(match, name, 0))\n+\t\treturn MATCHED_FNMATCH;\n+\n+\treturn 0;\n+}\n+\n+/*\n+ * Given a name and a list of pathspecs, see if the name matches\n+ * any of the pathspecs.  The caller is also interested in seeing\n+ * all pathspec matches some names it calls this function with\n+ * (otherwise the user could have mistyped the unmatched pathspec),\n+ * and a mark is left in seen[] array for pathspec element that\n+ * actually matched anything.\n+ */\n+int match_pathspec_depth(const struct pathspec *ps,\n+\t\t\t const char *name, int namelen,\n+\t\t\t int prefix, char *seen)\n+{\n+\tint i, retval = 0;\n+\n+\tif (!ps->nr) {\n+\t\tif (!ps->recursive || ps->max_depth == -1)\n+\t\t\treturn MATCHED_RECURSIVELY;\n+\n+\t\tif (within_depth(name, namelen, 0, ps->max_depth))\n+\t\t\treturn MATCHED_EXACTLY;\n+\t\telse\n+\t\t\treturn 0;\n+\t}\n+\n+\tname += prefix;\n+\tnamelen -= prefix;\n+\n+\tfor (i = ps->nr - 1; i >= 0; i--) {\n+\t\tint how;\n+\t\tif (seen && seen[i] == MATCHED_EXACTLY)\n+\t\t\tcontinue;\n+\t\thow = match_pathspec_item(ps->items+i, prefix, name, namelen);\n+\t\tif (ps->recursive && ps->max_depth != -1 &&\n+\t\t    how && how != MATCHED_FNMATCH) {\n+\t\t\tint len = ps->items[i].len;\n+\t\t\tif (name[len] == '/')\n+\t\t\t\tlen++;\n+\t\t\tif (within_depth(name+len, namelen-len, 0, ps->max_depth))\n+\t\t\t\thow = MATCHED_EXACTLY;\n+\t\t\telse\n+\t\t\t\thow = 0;\n+\t\t}\n+\t\tif (how) {\n+\t\t\tif (retval < how)\n+\t\t\t\tretval = how;\n+\t\t\tif (seen && seen[i] < how)\n+\t\t\t\tseen[i] = how;\n+\t\t}\n+\t}\n+\treturn retval;\n+}\n+\n static int no_wildcard(const char *string)\n {\n \treturn string[strcspn(string, \"*?[{\\\\\")] == '\\0';\ndiff --git a/dir.h b/dir.h\nindex c71de08..ddb4147 100644\n--- a/dir.h\n+++ b/dir.h\n@@ -65,6 +65,9 @@ struct dir_struct {\n #define MATCHED_FNMATCH 2\n #define MATCHED_EXACTLY 3\n extern int match_pathspec(const char **pathspec, const char *name, int namelen, int prefix, char *seen);\n+extern int match_pathspec_depth(const struct pathspec *pathspec,\n+\t\t\t\tconst char *name, int namelen,\n+\t\t\t\tint prefix, char *seen);\n extern int within_depth(const char *name, int namelen, int depth, int max_depth);\n \n extern int fill_directory(struct dir_struct *dir, const char **pathspec);\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158170","messageId":"1292425376-14550-15-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 14/21] Convert ce_path_match() to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:49Z","receivedAt":"2010-12-15T15:02:49Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/update-index.c |    8 ++++++--\n cache.h                |    2 +-\n diff-lib.c             |   10 ++++++++--\n preload-index.c        |    5 ++++-\n read-cache.c           |    7 ++++---\n revision.c             |    5 ++++-\n wt-status.c            |    5 ++++-\n 7 files changed, 31 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 3ab214d..9d1f67e 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -543,7 +543,10 @@ static int do_reupdate(int ac, const char **av,\n \t */\n \tint pos;\n \tint has_head = 1;\n-\tconst char **pathspec = get_pathspec(prefix, av + 1);\n+\tconst char **paths = get_pathspec(prefix, av + 1);\n+\tstruct pathspec pathspec;\n+\n+\tinit_pathspec(&pathspec, paths);\n \n \tif (read_ref(\"HEAD\", head_sha1))\n \t\t/* If there is no HEAD, that means it is an initial\n@@ -556,7 +559,7 @@ static int do_reupdate(int ac, const char **av,\n \t\tstruct cache_entry *old = NULL;\n \t\tint save_nr;\n \n-\t\tif (ce_stage(ce) || !ce_path_match(ce, pathspec))\n+\t\tif (ce_stage(ce) || !ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \t\tif (has_head)\n \t\t\told = read_one_ent(NULL, head_sha1,\n@@ -575,6 +578,7 @@ static int do_reupdate(int ac, const char **av,\n \t\tif (save_nr != active_nr)\n \t\t\tgoto redo;\n \t}\n+\tfree_pathspec(&pathspec);\n \treturn 0;\n }\n \ndiff --git a/cache.h b/cache.h\nindex dc0bfb4..b5cd61c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -508,7 +508,7 @@ struct pathspec {\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void free_pathspec(struct pathspec *);\n-extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);\n+extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);\n extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);\n extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);\n extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 3b809f2..63db7f4 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -89,9 +89,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \tint silent_on_removed = option & DIFF_SILENT_ON_REMOVED;\n \tunsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)\n \t\t\t      ? CE_MATCH_RACY_IS_DIRTY : 0);\n+\tstruct pathspec pathspec;\n \n \tdiff_set_mnemonic_prefix(&revs->diffopt, \"i/\", \"w/\");\n \n+\tinit_pathspec(&pathspec, revs->prune_data);\n \tif (diff_unmerged_stage < 0)\n \t\tdiff_unmerged_stage = 2;\n \tentries = active_nr;\n@@ -106,7 +108,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\tDIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))\n \t\t\tbreak;\n \n-\t\tif (!ce_path_match(ce, revs->prune_data))\n+\t\tif (!ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n@@ -218,6 +220,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\t    ce->name, 0, dirty_submodule);\n \n \t}\n+\tfree_pathspec(&pathspec);\n \tdiffcore_std(&revs->diffopt);\n \tdiff_flush(&revs->diffopt);\n \treturn 0;\n@@ -417,6 +420,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)\n \tstruct cache_entry *idx = src[0];\n \tstruct cache_entry *tree = src[1];\n \tstruct rev_info *revs = o->unpack_data;\n+\tstruct pathspec pathspec;\n \n \t/*\n \t * Unpack-trees generates a DF/conflict entry if\n@@ -427,8 +431,10 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)\n \tif (tree == o->df_conflict_entry)\n \t\ttree = NULL;\n \n-\tif (ce_path_match(idx ? idx : tree, revs->prune_data))\n+\tinit_pathspec(&pathspec, revs->prune_data);\n+\tif (ce_path_match(idx ? idx : tree, &pathspec))\n \t\tdo_oneway_diff(o, idx, tree);\n+\tfree_pathspec(&pathspec);\n \n \treturn 0;\n }\ndiff --git a/preload-index.c b/preload-index.c\nindex e3d0bda..49cb08d 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -35,7 +35,9 @@ static void *preload_thread(void *_data)\n \tstruct index_state *index = p->index;\n \tstruct cache_entry **cep = index->cache + p->offset;\n \tstruct cache_def cache;\n+\tstruct pathspec pathspec;\n \n+\tinit_pathspec(&pathspec, p->pathspec);\n \tmemset(&cache, 0, sizeof(cache));\n \tnr = p->nr;\n \tif (nr + p->offset > index->cache_nr)\n@@ -51,7 +53,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce_uptodate(ce))\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, p->pathspec))\n+\t\tif (!ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\n@@ -61,6 +63,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tce_mark_uptodate(ce);\n \t} while (--nr > 0);\n+\tfree_pathspec(&pathspec);\n \treturn NULL;\n }\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 1f42473..f1141a3 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -683,17 +683,18 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b)\n \treturn ce_namelen(b) == len && !memcmp(a->name, b->name, len);\n }\n \n-int ce_path_match(const struct cache_entry *ce, const char **pathspec)\n+int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)\n {\n \tconst char *match, *name;\n+\tconst char **ps = pathspec->raw;\n \tint len;\n \n-\tif (!pathspec)\n+\tif (!pathspec->nr)\n \t\treturn 1;\n \n \tlen = ce_namelen(ce);\n \tname = ce->name;\n-\twhile ((match = *pathspec++) != NULL) {\n+\twhile ((match = *ps++) != NULL) {\n \t\tint matchlen = strlen(match);\n \t\tif (matchlen > len)\n \t\t\tcontinue;\ndiff --git a/revision.c b/revision.c\nindex b2a5867..e77184a 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -951,6 +951,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \tunsigned char sha1[20];\n \tconst char **prune = NULL;\n \tint i, prune_num = 1; /* counting terminating NULL */\n+\tstruct pathspec pathspec;\n \n \tif (get_sha1(\"HEAD\", sha1) || !(head = lookup_commit(sha1)))\n \t\tdie(\"--merge without HEAD?\");\n@@ -965,11 +966,12 @@ static void prepare_show_merge(struct rev_info *revs)\n \n \tif (!active_nr)\n \t\tread_cache();\n+\tinit_pathspec(&pathspec, revs->prune_data);\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (ce_path_match(ce, revs->prune_data)) {\n+\t\tif (ce_path_match(ce, &pathspec)) {\n \t\t\tprune_num++;\n \t\t\tprune = xrealloc(prune, sizeof(*prune) * prune_num);\n \t\t\tprune[prune_num-2] = ce->name;\n@@ -979,6 +981,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\t       ce_same_name(ce, active_cache[i+1]))\n \t\t\ti++;\n \t}\n+\tfree_pathspec(&pathspec);\n \trevs->prune_data = prune;\n \trevs->limited = 1;\n }\ndiff --git a/wt-status.c b/wt-status.c\nindex 54b6b03..70bd378 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -350,14 +350,16 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \n static void wt_status_collect_changes_initial(struct wt_status *s)\n {\n+\tstruct pathspec pathspec;\n \tint i;\n \n+\tinit_pathspec(&pathspec, s->pathspec);\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct string_list_item *it;\n \t\tstruct wt_status_change_data *d;\n \t\tstruct cache_entry *ce = active_cache[i];\n \n-\t\tif (!ce_path_match(ce, s->pathspec))\n+\t\tif (!ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \t\tit = string_list_insert(&s->change, ce->name);\n \t\td = it->util;\n@@ -372,6 +374,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)\n \t\telse\n \t\t\td->index_status = DIFF_STATUS_ADDED;\n \t}\n+\tfree_pathspec(&pathspec);\n }\n \n static void wt_status_collect_untracked(struct wt_status *s)\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158172","messageId":"1292425376-14550-16-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 15/21] Convert ce_path_match() to use match_pathspec_depth()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:50Z","receivedAt":"2010-12-15T15:02:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n read-cache.c |   24 +-----------------------\n 1 files changed, 1 insertions(+), 23 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex f1141a3..7f51cd6 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -685,29 +685,7 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b)\n \n int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)\n {\n-\tconst char *match, *name;\n-\tconst char **ps = pathspec->raw;\n-\tint len;\n-\n-\tif (!pathspec->nr)\n-\t\treturn 1;\n-\n-\tlen = ce_namelen(ce);\n-\tname = ce->name;\n-\twhile ((match = *ps++) != NULL) {\n-\t\tint matchlen = strlen(match);\n-\t\tif (matchlen > len)\n-\t\t\tcontinue;\n-\t\tif (memcmp(name, match, matchlen))\n-\t\t\tcontinue;\n-\t\tif (matchlen && name[matchlen-1] == '/')\n-\t\t\treturn 1;\n-\t\tif (name[matchlen] == '/' || !name[matchlen])\n-\t\t\treturn 1;\n-\t\tif (!matchlen)\n-\t\t\treturn 1;\n-\t}\n-\treturn 0;\n+\treturn match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);\n }\n \n /*\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158173","messageId":"1292425376-14550-17-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 16/21] grep: convert to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:51Z","receivedAt":"2010-12-15T15:02:51Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c |   30 ++++++++++++++++--------------\n 1 files changed, 16 insertions(+), 14 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex da32f3d..4179af8 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -585,7 +585,7 @@ static void run_pager(struct grep_opt *opt, const char *prefix)\n \tfree(argv);\n }\n \n-static int grep_cache(struct grep_opt *opt, const char **paths, int cached)\n+static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)\n {\n \tint hit = 0;\n \tint nr;\n@@ -595,7 +595,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)\n \t\tstruct cache_entry *ce = active_cache[nr];\n \t\tif (!S_ISREG(ce->ce_mode))\n \t\t\tcontinue;\n-\t\tif (!pathspec_matches(paths, ce->name, opt->max_depth))\n+\t\tif (!pathspec_matches(pathspec->raw, ce->name, opt->max_depth))\n \t\t\tcontinue;\n \t\t/*\n \t\t * If CE_VALID is on, we assume worktree file and its cache entry\n@@ -622,7 +622,7 @@ static int grep_cache(struct grep_opt *opt, const char **paths, int cached)\n \treturn hit;\n }\n \n-static int grep_tree(struct grep_opt *opt, const char **paths,\n+static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t     struct tree_desc *tree,\n \t\t     const char *tree_name, const char *base)\n {\n@@ -656,7 +656,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,\n \t\t\tstrbuf_addch(&pathbuf, '/');\n \n \t\tdown = pathbuf.buf + tn_len;\n-\t\tif (!pathspec_matches(paths, down, opt->max_depth))\n+\t\tif (!pathspec_matches(pathspec->raw, down, opt->max_depth))\n \t\t\t;\n \t\telse if (S_ISREG(entry.mode))\n \t\t\thit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);\n@@ -671,7 +671,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,\n \t\t\t\tdie(\"unable to read tree (%s)\",\n \t\t\t\t    sha1_to_hex(entry.sha1));\n \t\t\tinit_tree_desc(&sub, data, size);\n-\t\t\thit |= grep_tree(opt, paths, &sub, tree_name, down);\n+\t\t\thit |= grep_tree(opt, pathspec, &sub, tree_name, down);\n \t\t\tfree(data);\n \t\t}\n \t\tif (hit && opt->status_only)\n@@ -681,7 +681,7 @@ static int grep_tree(struct grep_opt *opt, const char **paths,\n \treturn hit;\n }\n \n-static int grep_object(struct grep_opt *opt, const char **paths,\n+static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t       struct object *obj, const char *name)\n {\n \tif (obj->type == OBJ_BLOB)\n@@ -696,14 +696,14 @@ static int grep_object(struct grep_opt *opt, const char **paths,\n \t\tif (!data)\n \t\t\tdie(\"unable to read tree (%s)\", sha1_to_hex(obj->sha1));\n \t\tinit_tree_desc(&tree, data, size);\n-\t\thit = grep_tree(opt, paths, &tree, name, \"\");\n+\t\thit = grep_tree(opt, pathspec, &tree, name, \"\");\n \t\tfree(data);\n \t\treturn hit;\n \t}\n \tdie(\"unable to grep from object of type %s\", typename(obj->type));\n }\n \n-static int grep_objects(struct grep_opt *opt, const char **paths,\n+static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\tconst struct object_array *list)\n {\n \tunsigned int i;\n@@ -713,7 +713,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths,\n \tfor (i = 0; i < nr; i++) {\n \t\tstruct object *real_obj;\n \t\treal_obj = deref_tag(list->objects[i].item, NULL, 0);\n-\t\tif (grep_object(opt, paths, real_obj, list->objects[i].name)) {\n+\t\tif (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {\n \t\t\thit = 1;\n \t\t\tif (opt->status_only)\n \t\t\t\tbreak;\n@@ -722,7 +722,7 @@ static int grep_objects(struct grep_opt *opt, const char **paths,\n \treturn hit;\n }\n \n-static int grep_directory(struct grep_opt *opt, const char **paths)\n+static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec)\n {\n \tstruct dir_struct dir;\n \tint i, hit = 0;\n@@ -730,7 +730,7 @@ static int grep_directory(struct grep_opt *opt, const char **paths)\n \tmemset(&dir, 0, sizeof(dir));\n \tsetup_standard_excludes(&dir);\n \n-\tfill_directory(&dir, paths);\n+\tfill_directory(&dir, pathspec->raw);\n \tfor (i = 0; i < dir.nr; i++) {\n \t\thit |= grep_file(opt, dir.entries[i]->name);\n \t\tif (hit && opt->status_only)\n@@ -836,6 +836,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tstruct grep_opt opt;\n \tstruct object_array list = OBJECT_ARRAY_INIT;\n \tconst char **paths = NULL;\n+\tstruct pathspec pathspec;\n \tstruct string_list path_list = STRING_LIST_INIT_NODUP;\n \tint i;\n \tint dummy;\n@@ -1063,6 +1064,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\tpaths[0] = prefix;\n \t\tpaths[1] = NULL;\n \t}\n+\tinit_pathspec(&pathspec, paths);\n \n \tif (show_in_pager && (cached || list.nr))\n \t\tdie(\"--open-files-in-pager only works on the worktree\");\n@@ -1093,16 +1095,16 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\tdie(\"--cached cannot be used with --no-index.\");\n \t\tif (list.nr)\n \t\t\tdie(\"--no-index cannot be used with revs.\");\n-\t\thit = grep_directory(&opt, paths);\n+\t\thit = grep_directory(&opt, &pathspec);\n \t} else if (!list.nr) {\n \t\tif (!cached)\n \t\t\tsetup_work_tree();\n \n-\t\thit = grep_cache(&opt, paths, cached);\n+\t\thit = grep_cache(&opt, &pathspec, cached);\n \t} else {\n \t\tif (cached)\n \t\t\tdie(\"both --cached and trees are given.\");\n-\t\thit = grep_objects(&opt, paths, &list);\n+\t\thit = grep_objects(&opt, &pathspec, &list);\n \t}\n \n \tif (use_threads)\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158174","messageId":"1292425376-14550-18-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 17/21] grep: use match_pathspec_depth() for cache/worktree grepping","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:52Z","receivedAt":"2010-12-15T15:02:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 4179af8..fbc7d02 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -595,7 +595,7 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n \t\tstruct cache_entry *ce = active_cache[nr];\n \t\tif (!S_ISREG(ce->ce_mode))\n \t\t\tcontinue;\n-\t\tif (!pathspec_matches(pathspec->raw, ce->name, opt->max_depth))\n+\t\tif (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))\n \t\t\tcontinue;\n \t\t/*\n \t\t * If CE_VALID is on, we assume worktree file and its cache entry\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158175","messageId":"1292425376-14550-19-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 18/21] strbuf: allow \"buf\" to point to the middle of the allocated buffer","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:53Z","receivedAt":"2010-12-15T15:02:53Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This allows offseting buf forward by neglen bytes. This patch makes\nsure that reallocation works even when buf is not at the top of\nallocated region.\n\nMany functions are not aware that there could be data before buf. Use\nwith care.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n strbuf.c |   36 ++++++++++++++++++++++++++----------\n strbuf.h |   10 ++++++----\n 2 files changed, 32 insertions(+), 14 deletions(-)\n\ndiff --git a/strbuf.c b/strbuf.c\nindex bc3a080..12cda6f 100644\n--- a/strbuf.c\n+++ b/strbuf.c\n@@ -28,8 +28,10 @@ char strbuf_slopbuf[1];\n \n void strbuf_init(struct strbuf *sb, size_t hint)\n {\n-\tsb->alloc = sb->len = 0;\n-\tsb->buf = strbuf_slopbuf;\n+\tsb->alloc  = 0;\n+\tsb->len\t   = 0;\n+\tsb->neglen = 0;\n+\tsb->buf\t   = strbuf_slopbuf;\n \tif (hint)\n \t\tstrbuf_grow(sb, hint);\n }\n@@ -37,7 +39,7 @@ void strbuf_init(struct strbuf *sb, size_t hint)\n void strbuf_release(struct strbuf *sb)\n {\n \tif (sb->alloc) {\n-\t\tfree(sb->buf);\n+\t\tfree(sb->buf - sb->neglen);\n \t\tstrbuf_init(sb, 0);\n \t}\n }\n@@ -45,6 +47,8 @@ void strbuf_release(struct strbuf *sb)\n char *strbuf_detach(struct strbuf *sb, size_t *sz)\n {\n \tchar *res = sb->alloc ? sb->buf : NULL;\n+\tif (sb->neglen)\n+\t\tdie(\"shift buf back before detaching\");\n \tif (sz)\n \t\t*sz = sb->len;\n \tstrbuf_init(sb, 0);\n@@ -54,20 +58,23 @@ char *strbuf_detach(struct strbuf *sb, size_t *sz)\n void strbuf_attach(struct strbuf *sb, void *buf, size_t len, size_t alloc)\n {\n \tstrbuf_release(sb);\n-\tsb->buf   = buf;\n-\tsb->len   = len;\n-\tsb->alloc = alloc;\n+\tsb->buf    = buf;\n+\tsb->len    = len;\n+\tsb->neglen = 0;\n+\tsb->alloc  = alloc;\n \tstrbuf_grow(sb, 0);\n \tsb->buf[sb->len] = '\\0';\n }\n \n void strbuf_grow(struct strbuf *sb, size_t extra)\n {\n-\tif (sb->len + extra + 1 <= sb->len)\n+\tchar *buf = !sb->alloc ? NULL : sb->buf - sb->neglen;\n+\tint len = sb->neglen + sb->len;\n+\n+\tif (len + extra + 1 <= len)\n \t\tdie(\"you want to use way too much memory\");\n-\tif (!sb->alloc)\n-\t\tsb->buf = NULL;\n-\tALLOC_GROW(sb->buf, sb->len + extra + 1, sb->alloc);\n+\tALLOC_GROW(buf, len + extra + 1, sb->alloc);\n+\tsb->buf = buf + sb->neglen;\n }\n \n void strbuf_trim(struct strbuf *sb)\n@@ -402,3 +409,12 @@ int strbuf_check_branch_ref(struct strbuf *sb, const char *name)\n \tstrbuf_splice(sb, 0, 0, \"refs/heads/\", 11);\n \treturn check_ref_format(sb->buf);\n }\n+\n+void strbuf_offset(struct strbuf *sb, int offset)\n+{\n+\tif (offset > sb->len || offset < sb->neglen)\n+\t\tdie(\"you cannot offset out of allocated buffer\");\n+\tsb->buf\t   += offset;\n+\tsb->neglen += offset;\n+\tsb->len\t   -= offset;\n+}\ndiff --git a/strbuf.h b/strbuf.h\nindex fac2dbc..3c3b146 100644\n--- a/strbuf.h\n+++ b/strbuf.h\n@@ -43,11 +43,11 @@\n extern char strbuf_slopbuf[];\n struct strbuf {\n \tsize_t alloc;\n-\tsize_t len;\n+\tsize_t len, neglen;\n \tchar *buf;\n };\n \n-#define STRBUF_INIT  { 0, 0, strbuf_slopbuf }\n+#define STRBUF_INIT  { 0, 0, 0, strbuf_slopbuf }\n \n /*----- strbuf life cycle -----*/\n extern void strbuf_init(struct strbuf *, size_t);\n@@ -62,7 +62,7 @@ static inline void strbuf_swap(struct strbuf *a, struct strbuf *b) {\n \n /*----- strbuf size related -----*/\n static inline size_t strbuf_avail(const struct strbuf *sb) {\n-\treturn sb->alloc ? sb->alloc - sb->len - 1 : 0;\n+\treturn sb->alloc ? sb->alloc - sb->len - sb->neglen - 1 : 0;\n }\n \n extern void strbuf_grow(struct strbuf *, size_t);\n@@ -70,7 +70,7 @@ extern void strbuf_grow(struct strbuf *, size_t);\n static inline void strbuf_setlen(struct strbuf *sb, size_t len) {\n \tif (!sb->alloc)\n \t\tstrbuf_grow(sb, 0);\n-\tassert(len < sb->alloc);\n+\tassert(sb->neglen + len < sb->alloc);\n \tsb->len = len;\n \tsb->buf[len] = '\\0';\n }\n@@ -136,4 +136,6 @@ extern int launch_editor(const char *path, struct strbuf *buffer, const char *co\n extern int strbuf_branchname(struct strbuf *sb, const char *name);\n extern int strbuf_check_branch_ref(struct strbuf *sb, const char *name);\n \n+extern void strbuf_offset(struct strbuf *sb, int offset);\n+\n #endif /* STRBUF_H */\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158178","messageId":"1292425376-14550-20-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 19/21] grep: use writable strbuf from caller in grep_tree()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:54Z","receivedAt":"2010-12-15T15:02:54Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c |   52 +++++++++++++++++++++++++---------------------------\n 1 files changed, 25 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex fbc7d02..5ecbbf8 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -623,43 +623,29 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n }\n \n static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n-\t\t     struct tree_desc *tree,\n-\t\t     const char *tree_name, const char *base)\n+\t\t     struct tree_desc *tree, struct strbuf *base, int tn_len)\n {\n-\tint len;\n \tint hit = 0;\n \tstruct name_entry entry;\n-\tchar *down;\n-\tint tn_len = strlen(tree_name);\n-\tstruct strbuf pathbuf;\n-\n-\tstrbuf_init(&pathbuf, PATH_MAX + tn_len);\n-\n-\tif (tn_len) {\n-\t\tstrbuf_add(&pathbuf, tree_name, tn_len);\n-\t\tstrbuf_addch(&pathbuf, ':');\n-\t\ttn_len = pathbuf.len;\n-\t}\n-\tstrbuf_addstr(&pathbuf, base);\n-\tlen = pathbuf.len;\n+\tint old_baselen = base->len;\n \n \twhile (tree_entry(tree, &entry)) {\n \t\tint te_len = tree_entry_len(entry.path, entry.sha1);\n-\t\tpathbuf.len = len;\n-\t\tstrbuf_add(&pathbuf, entry.path, te_len);\n+\n+\t\tstrbuf_add(base, entry.path, te_len);\n \n \t\tif (S_ISDIR(entry.mode))\n \t\t\t/* Match \"abc/\" against pathspec to\n \t\t\t * decide if we want to descend into \"abc\"\n \t\t\t * directory.\n \t\t\t */\n-\t\t\tstrbuf_addch(&pathbuf, '/');\n+\t\t\tstrbuf_addch(base, '/');\n \n-\t\tdown = pathbuf.buf + tn_len;\n-\t\tif (!pathspec_matches(pathspec->raw, down, opt->max_depth))\n+\t\tif (!pathspec_matches(pathspec->raw, base->buf, opt->max_depth))\n \t\t\t;\n-\t\telse if (S_ISREG(entry.mode))\n-\t\t\thit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);\n+\t\telse if (S_ISREG(entry.mode)) {\n+\t\t\thit |= grep_sha1(opt, entry.sha1, base->buf - tn_len, tn_len);\n+\t\t}\n \t\telse if (S_ISDIR(entry.mode)) {\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc sub;\n@@ -671,13 +657,14 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\t\tdie(\"unable to read tree (%s)\",\n \t\t\t\t    sha1_to_hex(entry.sha1));\n \t\t\tinit_tree_desc(&sub, data, size);\n-\t\t\thit |= grep_tree(opt, pathspec, &sub, tree_name, down);\n+\t\t\thit |= grep_tree(opt, pathspec, &sub, base, tn_len);\n \t\t\tfree(data);\n \t\t}\n+\t\tstrbuf_setlen(base, old_baselen);\n+\n \t\tif (hit && opt->status_only)\n \t\t\tbreak;\n \t}\n-\tstrbuf_release(&pathbuf);\n \treturn hit;\n }\n \n@@ -690,13 +677,24 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\tstruct tree_desc tree;\n \t\tvoid *data;\n \t\tunsigned long size;\n-\t\tint hit;\n+\t\tstruct strbuf base;\n+\t\tint hit, len;\n+\n \t\tdata = read_object_with_reference(obj->sha1, tree_type,\n \t\t\t\t\t\t  &size, NULL);\n \t\tif (!data)\n \t\t\tdie(\"unable to read tree (%s)\", sha1_to_hex(obj->sha1));\n+\n+\t\tlen = name ? strlen(name) : 0;\n+\t\tstrbuf_init(&base, PATH_MAX + len + 1);\n+\t\tif (len) {\n+\t\t\tstrbuf_add(&base, name, len);\n+\t\t\tstrbuf_addch(&base, ':');\n+\t\t\tstrbuf_offset(&base, base.len);\n+\t\t}\n \t\tinit_tree_desc(&tree, data, size);\n-\t\thit = grep_tree(opt, pathspec, &tree, name, \"\");\n+\t\thit = grep_tree(opt, pathspec, &tree, &base, base.neglen);\n+\t\tstrbuf_release(&base);\n \t\tfree(data);\n \t\treturn hit;\n \t}\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158177","messageId":"1292425376-14550-21-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 20/21] grep: drop pathspec_matches() in favor of tree_entry_interesting()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:55Z","receivedAt":"2010-12-15T15:02:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n builtin/grep.c |  125 ++++++-------------------------------------------------\n 1 files changed, 14 insertions(+), 111 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 5ecbbf8..3cd66b1 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -333,106 +333,6 @@ static int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Return non-zero if max_depth is negative or path has no more then max_depth\n- * slashes.\n- */\n-static int accept_subdir(const char *path, int max_depth)\n-{\n-\tif (max_depth < 0)\n-\t\treturn 1;\n-\n-\twhile ((path = strchr(path, '/')) != NULL) {\n-\t\tmax_depth--;\n-\t\tif (max_depth < 0)\n-\t\t\treturn 0;\n-\t\tpath++;\n-\t}\n-\treturn 1;\n-}\n-\n-/*\n- * Return non-zero if name is a subdirectory of match and is not too deep.\n- */\n-static int is_subdir(const char *name, int namelen,\n-\t\tconst char *match, int matchlen, int max_depth)\n-{\n-\tif (matchlen > namelen || strncmp(name, match, matchlen))\n-\t\treturn 0;\n-\n-\tif (name[matchlen] == '\\0') /* exact match */\n-\t\treturn 1;\n-\n-\tif (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')\n-\t\treturn accept_subdir(name + matchlen + 1, max_depth);\n-\n-\treturn 0;\n-}\n-\n-/*\n- * git grep pathspecs are somewhat different from diff-tree pathspecs;\n- * pathname wildcards are allowed.\n- */\n-static int pathspec_matches(const char **paths, const char *name, int max_depth)\n-{\n-\tint namelen, i;\n-\tif (!paths || !*paths)\n-\t\treturn accept_subdir(name, max_depth);\n-\tnamelen = strlen(name);\n-\tfor (i = 0; paths[i]; i++) {\n-\t\tconst char *match = paths[i];\n-\t\tint matchlen = strlen(match);\n-\t\tconst char *cp, *meta;\n-\n-\t\tif (is_subdir(name, namelen, match, matchlen, max_depth))\n-\t\t\treturn 1;\n-\t\tif (!fnmatch(match, name, 0))\n-\t\t\treturn 1;\n-\t\tif (name[namelen-1] != '/')\n-\t\t\tcontinue;\n-\n-\t\t/* We are being asked if the directory (\"name\") is worth\n-\t\t * descending into.\n-\t\t *\n-\t\t * Find the longest leading directory name that does\n-\t\t * not have metacharacter in the pathspec; the name\n-\t\t * we are looking at must overlap with that directory.\n-\t\t */\n-\t\tfor (cp = match, meta = NULL; cp - match < matchlen; cp++) {\n-\t\t\tchar ch = *cp;\n-\t\t\tif (ch == '*' || ch == '[' || ch == '?') {\n-\t\t\t\tmeta = cp;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tif (!meta)\n-\t\t\tmeta = cp; /* fully literal */\n-\n-\t\tif (namelen <= meta - match) {\n-\t\t\t/* Looking at \"Documentation/\" and\n-\t\t\t * the pattern says \"Documentation/howto/\", or\n-\t\t\t * \"Documentation/diff*.txt\".  The name we\n-\t\t\t * have should match prefix.\n-\t\t\t */\n-\t\t\tif (!memcmp(match, name, namelen))\n-\t\t\t\treturn 1;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (meta - match < namelen) {\n-\t\t\t/* Looking at \"Documentation/howto/\" and\n-\t\t\t * the pattern says \"Documentation/h*\";\n-\t\t\t * match up to \"Do.../h\"; this avoids descending\n-\t\t\t * into \"Documentation/technical/\".\n-\t\t\t */\n-\t\t\tif (!memcmp(match, name, meta - match))\n-\t\t\t\treturn 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)\n {\n \tvoid *data;\n@@ -625,25 +525,24 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t     struct tree_desc *tree, struct strbuf *base, int tn_len)\n {\n-\tint hit = 0;\n+\tint hit = 0, matched = 0;\n \tstruct name_entry entry;\n \tint old_baselen = base->len;\n \n \twhile (tree_entry(tree, &entry)) {\n \t\tint te_len = tree_entry_len(entry.path, entry.sha1);\n \n-\t\tstrbuf_add(base, entry.path, te_len);\n+\t\tif (matched != 2) {\n+\t\t\tmatched = tree_entry_interesting(&entry, base, pathspec);\n+\t\t\tif (matched == -1)\n+\t\t\t\tbreak; /* no more matches */\n+\t\t\tif (!matched)\n+\t\t\t\tcontinue;\n+\t\t}\n \n-\t\tif (S_ISDIR(entry.mode))\n-\t\t\t/* Match \"abc/\" against pathspec to\n-\t\t\t * decide if we want to descend into \"abc\"\n-\t\t\t * directory.\n-\t\t\t */\n-\t\t\tstrbuf_addch(base, '/');\n+\t\tstrbuf_add(base, entry.path, te_len);\n \n-\t\tif (!pathspec_matches(pathspec->raw, base->buf, opt->max_depth))\n-\t\t\t;\n-\t\telse if (S_ISREG(entry.mode)) {\n+\t\tif (S_ISREG(entry.mode)) {\n \t\t\thit |= grep_sha1(opt, entry.sha1, base->buf - tn_len, tn_len);\n \t\t}\n \t\telse if (S_ISDIR(entry.mode)) {\n@@ -656,6 +555,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\tif (!data)\n \t\t\t\tdie(\"unable to read tree (%s)\",\n \t\t\t\t    sha1_to_hex(entry.sha1));\n+\n+\t\t\tstrbuf_addch(base, '/');\n \t\t\tinit_tree_desc(&sub, data, size);\n \t\t\thit |= grep_tree(opt, pathspec, &sub, base, tn_len);\n \t\t\tfree(data);\n@@ -1063,6 +964,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\tpaths[1] = NULL;\n \t}\n \tinit_pathspec(&pathspec, paths);\n+\tpathspec.max_depth = opt.max_depth;\n+\tpathspec.recursive = 1;\n \n \tif (show_in_pager && (cached || list.nr))\n \t\tdie(\"--open-files-in-pager only works on the worktree\");\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158176","messageId":"1292425376-14550-22-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 21/21] t7810: overlapping pathspecs and depth limit","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-15T15:02:56Z","receivedAt":"2010-12-15T15:02:56Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t7810-grep.sh |   18 ++++++++++++++++++\n 1 files changed, 18 insertions(+), 0 deletions(-)\n\ndiff --git a/t/t7810-grep.sh b/t/t7810-grep.sh\nindex 023f225..d89faee 100755\n--- a/t/t7810-grep.sh\n+++ b/t/t7810-grep.sh\n@@ -182,6 +182,24 @@ do\n \t\ttest_cmp expected actual\n \t'\n \n+\ttest_expect_success \"grep --max-depth 0 -- . t $L\" '\n+\t\t{\n+\t\t\techo ${HC}t/v:1:vvv\n+\t\t\techo ${HC}v:1:vvv\n+\t\t} >expected &&\n+\t\tgit grep --max-depth 0 -n -e vvv $H -- . t >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n+\ttest_expect_success \"grep --max-depth 0 -- t . $L\" '\n+\t\t{\n+\t\t\techo ${HC}t/v:1:vvv\n+\t\t\techo ${HC}v:1:vvv\n+\t\t} >expected &&\n+\t\tgit grep --max-depth 0 -n -e vvv $H -- t . >actual &&\n+\t\ttest_cmp expected actual\n+\t'\n+\n done\n \n cat >expected <<EOF\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158242","messageId":"7vmxo5l2g4.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"1292425376-14550-11-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 10/21] tree_entry_interesting(): fix depth limit with overlapping pathspecs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-12-16T23:31:39Z","receivedAt":"2010-12-16T23:31:39Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> Suppose we have two pathspecs 'a' and 'a/b' (both are dirs) and depth\n> limit 1. In current code, pathspecs are checked in input order. When\n> 'a/b' is checked against pathspec 'a', it fails depth limit and\n> therefore is excluded, although it should match 'a/b' pathspec.\n>\n> This patch reorders all pathspecs alphabetically, then teaches\n> tree_entry_interesting() to check against the deepest pathspec first,\n> so depth limit of a shallower pathspec won't affect a deeper one.\n\nI am quite happy to see where this new round of this series is going so\nfar.  I however doubt this patch is a right approach for the problem you\nare solving, especially because your longer-term (i.e. toward the rest of\nthe series to patch 21) plan is to allow wildcards [*1*].\n\nOne thing I am not clear is what it means to limit the recursion level\nwhen you have wildcards.\n\nOne possible definition of interaction between limit and wildcard may be\nto count the number of slashes in the part of the path that matches the\nwildcarded part of the pathspec, add the number of path components\nappended due to the leading directory match, and then subtract the number\nof literal slashes in the wildcarded part of the pattern from the above,\nand declare that a match is found if the difference is less than the\nlimit.\n\nE.g. a pathspec element \"a/*/x\" would match \"a/b/c/x\", \"a/b/c/d/e/x\",\n\"a/b/x/y\" and \"a/b/x/y/z\" without limit, and with the limit of 1:\n\n    a/b/c/x        matches ('*' expands to \"b/c\")\n    a/b/c/d/e/x    no ('*' has to expand to \"c/d/e\" and needs 2 levels)\n    a/b/x/y        matches ('*' expands to \"b\" costing zero, \"/y\" needs 1)\n    a/b/x/y/z      does not match\n\nAnother definition could be to count _only_ the part that is appended by\nrecursion (i.e. we do not count how many slashes has to match '*' in the\nabove examples), and as the option is called --depth, it might make more\nsense.\n\nIn either case, I am not sure if \"if it matches the longest pathspec, we\nhave the answer without looking at shorter ones\" would be a good rule to\nuse.\n\n\n[Footnote]\n\n*1* In addition, perhaps you may later want to introduce some \"negative\"\nmatch operators to pathspecs; while I am not particularly fond of that\ndirection at this moment, I would like to leave the door open for that\npossibility, in case it turns out to be a good thing to have.\n"},{"id":"158245","messageId":"7v39pxl10y.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"1292425376-14550-15-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 14/21] Convert ce_path_match() to use struct pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-12-17T00:02:21Z","receivedAt":"2010-12-17T00:02:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> diff --git a/diff-lib.c b/diff-lib.c\n> index 3b809f2..63db7f4 100644\n> --- a/diff-lib.c\n> +++ b/diff-lib.c\n> @@ -89,9 +89,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n>  \tint silent_on_removed = option & DIFF_SILENT_ON_REMOVED;\n>  \tunsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)\n>  \t\t\t      ? CE_MATCH_RACY_IS_DIRTY : 0);\n> +\tstruct pathspec pathspec;\n>  \n>  \tdiff_set_mnemonic_prefix(&revs->diffopt, \"i/\", \"w/\");\n>  \n> +\tinit_pathspec(&pathspec, revs->prune_data);\n\nI wonder if it makes more sense to change the type of revs->prune_data\nfrom an array of pointers to strings to a pointer to struct pathspec.\nIs there a downside?\n\n> diff --git a/preload-index.c b/preload-index.c\n> index e3d0bda..49cb08d 100644\n> --- a/preload-index.c\n> +++ b/preload-index.c\n> @@ -35,7 +35,9 @@ static void *preload_thread(void *_data)\n>  \tstruct index_state *index = p->index;\n>  \tstruct cache_entry **cep = index->cache + p->offset;\n>  \tstruct cache_def cache;\n> +\tstruct pathspec pathspec;\n>  \n> +\tinit_pathspec(&pathspec, p->pathspec);\n\nLikewise; would it make the API cleaner to make read_cache_preload() and\nread_index_preload() take \"const struct pathspec *\" instead of the\ntraditional \"const char **\"?\n"},{"id":"158246","messageId":"7vy67pjlvb.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"1292425376-14550-20-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 19/21] grep: use writable strbuf from caller in grep_tree()","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-12-17T00:15:04Z","receivedAt":"2010-12-17T00:15:04Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n> +\t\thit = grep_tree(opt, pathspec, &tree, &base, base.neglen);\n\nIf you are going to let the users of strbuf API to refer directly to the\nfield, I think \"neglen\" should be renamed to something more reasonable,\nsay, \"offset\".\n\nI am still debating myself if this strbuf_offset is anugly hack merely to\nallow the implementation of \"grep\" not to carry one extra offset around\nthroughout its callchain, or if it is generic enough that other/future\ncallers would benefit from.  I am leaning toward to think this is an ugly\nhack, as a new caller that wants to carry _two_ offsets into a strbuf\nwouldn't get much benefit from this new API.  But I may be missreading\nyour code.\n"},{"id":"158270","messageId":"AANLkTi=hXQqtYmhtHh+D67d9puRrDA+iScpafaYYMsAk@mail.gmail.com","threadId":"26076","inReplyTo":"7vy67pjlvb.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 19/21] grep: use writable strbuf from caller in grep_tree()","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T09:56:43Z","receivedAt":"2010-12-17T09:56:43Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/12/17 Junio C Hamano <gitster@pobox.com>:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> +             hit = grep_tree(opt, pathspec, &tree, &base, base.neglen);\n>\n> If you are going to let the users of strbuf API to refer directly to the\n> field, I think \"neglen\" should be renamed to something more reasonable,\n> say, \"offset\".\n>\n> I am still debating myself if this strbuf_offset is anugly hack merely to\n> allow the implementation of \"grep\" not to carry one extra offset around\n> throughout its callchain, or if it is generic enough that other/future\n> callers would benefit from.  I am leaning toward to think this is an ugly\n> hack, as a new caller that wants to carry _two_ offsets into a strbuf\n> wouldn't get much benefit from this new API.  But I may be missreading\n> your code.\n>\n\nI did not want to another offset to tree_entry_interesting. But an\nextra argument would be less ugly than an extra API.\n-- \nDuy\n"},{"id":"158271","messageId":"AANLkTikKCU==mS5_TdqHstETj=CQ_deHMCJ4xW0r+Sck@mail.gmail.com","threadId":"26076","inReplyTo":"7v39pxl10y.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 14/21] Convert ce_path_match() to use struct pathspec","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T09:59:52Z","receivedAt":"2010-12-17T09:59:52Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/12/17 Junio C Hamano <gitster@pobox.com>:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> diff --git a/diff-lib.c b/diff-lib.c\n>> index 3b809f2..63db7f4 100644\n>> --- a/diff-lib.c\n>> +++ b/diff-lib.c\n>> @@ -89,9 +89,11 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n>>       int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;\n>>       unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)\n>>                             ? CE_MATCH_RACY_IS_DIRTY : 0);\n>> +     struct pathspec pathspec;\n>>\n>>       diff_set_mnemonic_prefix(&revs->diffopt, \"i/\", \"w/\");\n>>\n>> +     init_pathspec(&pathspec, revs->prune_data);\n>\n> I wonder if it makes more sense to change the type of revs->prune_data\n> from an array of pointers to strings to a pointer to struct pathspec.\n> Is there a downside?\n\nConverting a pointer to another pointer means mis typecasting can\nhappen and the compiler won't help catching them. I thinking of\nchanging prune_data to simply struct pathspec. Looks like it breaks\nthing.. hm...\n-- \nDuy\n"},{"id":"158272","messageId":"AANLkTi=4vnitj-U5M+V_ALVpAk0ncMG=09aAEqA=KD41@mail.gmail.com","threadId":"26076","inReplyTo":"7vmxo5l2g4.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 10/21] tree_entry_interesting(): fix depth limit with overlapping pathspecs","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T10:05:32Z","receivedAt":"2010-12-17T10:05:32Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/12/17 Junio C Hamano <gitster@pobox.com>:\n> One thing I am not clear is what it means to limit the recursion level\n> when you have wildcards.\n\nRecursion level does not affect wildcards at all. That was original\ndesign, a91f453 (grep: Add --max-depth option. - 2009-07-22). I think\ncurrent git-grep still follows that.\n\n> [Footnote]\n>\n> *1* In addition, perhaps you may later want to introduce some \"negative\"\n> match operators to pathspecs; while I am not particularly fond of that\n> direction at this moment, I would like to leave the door open for that\n> possibility, in case it turns out to be a good thing to have.\n\nIt's a essential thing for narrow clone, otherwise I can't widen a\nnarrow clone. But narrow clone must prove it's a good thing to have\nfirst..\n-- \nDuy\n"},{"id":"158276","messageId":"1292589787-9525-1-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"AANLkTikKCU==mS5_TdqHstETj=CQ_deHMCJ4xW0r+Sck@mail.gmail.com","subject":"[PATCH 14/21] struct rev_info: convert prune_data to struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T12:43:06Z","receivedAt":"2010-12-17T12:43:06Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n New patch. rev_info->pathspec is now struct pathspec.\n\n builtin/add.c         |    2 +-\n builtin/diff.c        |   12 ++++--------\n builtin/fast-export.c |    2 +-\n diff-lib.c            |    6 +++---\n revision.c            |   15 ++++++++-------\n revision.h            |    2 +-\n wt-status.c           |    4 ++--\n 7 files changed, 20 insertions(+), 23 deletions(-)\n\ndiff --git a/builtin/add.c b/builtin/add.c\nindex 56a4e0a..3fc79a5 100644\n--- a/builtin/add.c\n+++ b/builtin/add.c\n@@ -86,7 +86,7 @@ int add_files_to_cache(const char *prefix, const char **pathspec, int flags)\n \tstruct rev_info rev;\n \tinit_revisions(&rev, prefix);\n \tsetup_revisions(0, NULL, &rev, NULL);\n-\trev.prune_data = pathspec;\n+\tinit_pathspec(&rev.prune_data, pathspec);\n \trev.diffopt.output_format = DIFF_FORMAT_CALLBACK;\n \trev.diffopt.format_callback = update_callback;\n \tdata.flags = flags;\ndiff --git a/builtin/diff.c b/builtin/diff.c\nindex 76c42d8..4ebb1b6 100644\n--- a/builtin/diff.c\n+++ b/builtin/diff.c\n@@ -371,14 +371,10 @@ int cmd_diff(int argc, const char **argv, const char *prefix)\n \t\t}\n \t\tdie(\"unhandled object '%s' given.\", name);\n \t}\n-\tif (rev.prune_data) {\n-\t\tconst char **pathspec = rev.prune_data;\n-\t\twhile (*pathspec) {\n-\t\t\tif (!path)\n-\t\t\t\tpath = *pathspec;\n-\t\t\tpaths++;\n-\t\t\tpathspec++;\n-\t\t}\n+\tif (rev.prune_data.nr) {\n+\t\tif (!path)\n+\t\t\tpath = rev.prune_data.items[0].match;\n+\t\tpaths += rev.prune_data.nr;\n \t}\n \n \t/*\ndiff --git a/builtin/fast-export.c b/builtin/fast-export.c\nindex c8fd46b..ba57457 100644\n--- a/builtin/fast-export.c\n+++ b/builtin/fast-export.c\n@@ -651,7 +651,7 @@ int cmd_fast_export(int argc, const char **argv, const char *prefix)\n \tif (import_filename)\n \t\timport_marks(import_filename);\n \n-\tif (import_filename && revs.prune_data)\n+\tif (import_filename && revs.prune_data.nr)\n \t\tfull_tree = 1;\n \n \tget_tags_and_duplicates(&revs.pending, &extra_refs);\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 3b809f2..2251f3d 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\tDIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))\n \t\t\tbreak;\n \n-\t\tif (!ce_path_match(ce, revs->prune_data))\n+\t\tif (!ce_path_match(ce, revs->prune_data.raw))\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n@@ -427,7 +427,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)\n \tif (tree == o->df_conflict_entry)\n \t\ttree = NULL;\n \n-\tif (ce_path_match(idx ? idx : tree, revs->prune_data))\n+\tif (ce_path_match(idx ? idx : tree, revs->prune_data.raw))\n \t\tdo_oneway_diff(o, idx, tree);\n \n \treturn 0;\n@@ -501,7 +501,7 @@ int do_diff_cache(const unsigned char *tree_sha1, struct diff_options *opt)\n \tactive_nr = dst - active_cache;\n \n \tinit_revisions(&revs, NULL);\n-\trevs.prune_data = opt->pathspec.raw;\n+\tinit_pathspec(&revs.prune_data, opt->pathspec.raw);\n \ttree = parse_tree_indirect(tree_sha1);\n \tif (!tree)\n \t\tdie(\"bad tree object %s\", sha1_to_hex(tree_sha1));\ndiff --git a/revision.c b/revision.c\nindex b2a5867..515e2dd 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -323,7 +323,7 @@ static int rev_compare_tree(struct rev_info *revs, struct commit *parent, struct\n \t\t * tagged commit by specifying both --simplify-by-decoration\n \t\t * and pathspec.\n \t\t */\n-\t\tif (!revs->prune_data)\n+\t\tif (!revs->prune_data.nr)\n \t\t\treturn REV_TREE_SAME;\n \t}\n \n@@ -969,7 +969,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (ce_path_match(ce, revs->prune_data)) {\n+\t\tif (ce_path_match(ce, revs->prune_data.raw)) {\n \t\t\tprune_num++;\n \t\t\tprune = xrealloc(prune, sizeof(*prune) * prune_num);\n \t\t\tprune[prune_num-2] = ce->name;\n@@ -979,7 +979,8 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\t       ce_same_name(ce, active_cache[i+1]))\n \t\t\ti++;\n \t}\n-\trevs->prune_data = prune;\n+\tfree_pathspec(&revs->prune_data);\n+\tinit_pathspec(&revs->prune_data, prune);\n \trevs->limited = 1;\n }\n \n@@ -1616,7 +1617,7 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \t}\n \n \tif (prune_data)\n-\t\trevs->prune_data = get_pathspec(revs->prefix, prune_data);\n+\t\tinit_pathspec(&revs->prune_data, get_pathspec(revs->prefix, prune_data));\n \n \tif (revs->def == NULL)\n \t\trevs->def = opt ? opt->def : NULL;\n@@ -1647,13 +1648,13 @@ int setup_revisions(int argc, const char **argv, struct rev_info *revs, struct s\n \tif (revs->topo_order)\n \t\trevs->limited = 1;\n \n-\tif (revs->prune_data) {\n-\t\tdiff_tree_setup_paths(revs->prune_data, &revs->pruning);\n+\tif (revs->prune_data.nr) {\n+\t\tdiff_tree_setup_paths(revs->prune_data.raw, &revs->pruning);\n \t\t/* Can't prune commits with rename following: the paths change.. */\n \t\tif (!DIFF_OPT_TST(&revs->diffopt, FOLLOW_RENAMES))\n \t\t\trevs->prune = 1;\n \t\tif (!revs->full_diff)\n-\t\t\tdiff_tree_setup_paths(revs->prune_data, &revs->diffopt);\n+\t\t\tdiff_tree_setup_paths(revs->prune_data.raw, &revs->diffopt);\n \t}\n \tif (revs->combine_merges)\n \t\trevs->ignore_merges = 0;\ndiff --git a/revision.h b/revision.h\nindex 05659c6..82509dd 100644\n--- a/revision.h\n+++ b/revision.h\n@@ -34,7 +34,7 @@ struct rev_info {\n \t/* Basic information */\n \tconst char *prefix;\n \tconst char *def;\n-\tvoid *prune_data;\n+\tstruct pathspec prune_data;\n \tunsigned int early_output;\n \n \t/* Traversal flags */\ndiff --git a/wt-status.c b/wt-status.c\nindex 54b6b03..5c6b118 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -319,7 +319,7 @@ static void wt_status_collect_changes_worktree(struct wt_status *s)\n     }\n \trev.diffopt.format_callback = wt_status_collect_changed_cb;\n \trev.diffopt.format_callback_data = s;\n-\trev.prune_data = s->pathspec;\n+\tinit_pathspec(&rev.prune_data, s->pathspec);\n \trun_diff_files(&rev, 0);\n }\n \n@@ -344,7 +344,7 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \trev.diffopt.detect_rename = 1;\n \trev.diffopt.rename_limit = 200;\n \trev.diffopt.break_opt = 0;\n-\trev.prune_data = s->pathspec;\n+\tinit_pathspec(&rev.prune_data, s->pathspec);\n \trun_diff_index(&rev, 1);\n }\n \n-- \n1.7.3.3.476.g10a82\n"},{"id":"158277","messageId":"1292589787-9525-2-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292589787-9525-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 15/21] Convert ce_path_match() to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T12:43:07Z","receivedAt":"2010-12-17T12:43:07Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n The old 14/21. Slightly changed because of rev_info->pathspec change.\n\n builtin/update-index.c |    8 ++++++--\n cache.h                |    2 +-\n diff-lib.c             |    4 ++--\n preload-index.c        |    5 ++++-\n read-cache.c           |    7 ++++---\n revision.c             |    2 +-\n wt-status.c            |    5 ++++-\n 7 files changed, 22 insertions(+), 11 deletions(-)\n\ndiff --git a/builtin/update-index.c b/builtin/update-index.c\nindex 3ab214d..9d1f67e 100644\n--- a/builtin/update-index.c\n+++ b/builtin/update-index.c\n@@ -543,7 +543,10 @@ static int do_reupdate(int ac, const char **av,\n \t */\n \tint pos;\n \tint has_head = 1;\n-\tconst char **pathspec = get_pathspec(prefix, av + 1);\n+\tconst char **paths = get_pathspec(prefix, av + 1);\n+\tstruct pathspec pathspec;\n+\n+\tinit_pathspec(&pathspec, paths);\n \n \tif (read_ref(\"HEAD\", head_sha1))\n \t\t/* If there is no HEAD, that means it is an initial\n@@ -556,7 +559,7 @@ static int do_reupdate(int ac, const char **av,\n \t\tstruct cache_entry *old = NULL;\n \t\tint save_nr;\n \n-\t\tif (ce_stage(ce) || !ce_path_match(ce, pathspec))\n+\t\tif (ce_stage(ce) || !ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \t\tif (has_head)\n \t\t\told = read_one_ent(NULL, head_sha1,\n@@ -575,6 +578,7 @@ static int do_reupdate(int ac, const char **av,\n \t\tif (save_nr != active_nr)\n \t\t\tgoto redo;\n \t}\n+\tfree_pathspec(&pathspec);\n \treturn 0;\n }\n \ndiff --git a/cache.h b/cache.h\nindex dc0bfb4..b5cd61c 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -508,7 +508,7 @@ struct pathspec {\n \n extern int init_pathspec(struct pathspec *, const char **);\n extern void free_pathspec(struct pathspec *);\n-extern int ce_path_match(const struct cache_entry *ce, const char **pathspec);\n+extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);\n extern int index_fd(unsigned char *sha1, int fd, struct stat *st, int write_object, enum object_type type, const char *path);\n extern int index_path(unsigned char *sha1, const char *path, struct stat *st, int write_object);\n extern void fill_stat_cache_info(struct cache_entry *ce, struct stat *st);\ndiff --git a/diff-lib.c b/diff-lib.c\nindex 2251f3d..1e22992 100644\n--- a/diff-lib.c\n+++ b/diff-lib.c\n@@ -106,7 +106,7 @@ int run_diff_files(struct rev_info *revs, unsigned int option)\n \t\t\tDIFF_OPT_TST(&revs->diffopt, HAS_CHANGES))\n \t\t\tbreak;\n \n-\t\tif (!ce_path_match(ce, revs->prune_data.raw))\n+\t\tif (!ce_path_match(ce, &revs->prune_data))\n \t\t\tcontinue;\n \n \t\tif (ce_stage(ce)) {\n@@ -427,7 +427,7 @@ static int oneway_diff(struct cache_entry **src, struct unpack_trees_options *o)\n \tif (tree == o->df_conflict_entry)\n \t\ttree = NULL;\n \n-\tif (ce_path_match(idx ? idx : tree, revs->prune_data.raw))\n+\tif (ce_path_match(idx ? idx : tree, &revs->prune_data))\n \t\tdo_oneway_diff(o, idx, tree);\n \n \treturn 0;\ndiff --git a/preload-index.c b/preload-index.c\nindex e3d0bda..49cb08d 100644\n--- a/preload-index.c\n+++ b/preload-index.c\n@@ -35,7 +35,9 @@ static void *preload_thread(void *_data)\n \tstruct index_state *index = p->index;\n \tstruct cache_entry **cep = index->cache + p->offset;\n \tstruct cache_def cache;\n+\tstruct pathspec pathspec;\n \n+\tinit_pathspec(&pathspec, p->pathspec);\n \tmemset(&cache, 0, sizeof(cache));\n \tnr = p->nr;\n \tif (nr + p->offset > index->cache_nr)\n@@ -51,7 +53,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tif (ce_uptodate(ce))\n \t\t\tcontinue;\n-\t\tif (!ce_path_match(ce, p->pathspec))\n+\t\tif (!ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \t\tif (threaded_has_symlink_leading_path(&cache, ce->name, ce_namelen(ce)))\n \t\t\tcontinue;\n@@ -61,6 +63,7 @@ static void *preload_thread(void *_data)\n \t\t\tcontinue;\n \t\tce_mark_uptodate(ce);\n \t} while (--nr > 0);\n+\tfree_pathspec(&pathspec);\n \treturn NULL;\n }\n \ndiff --git a/read-cache.c b/read-cache.c\nindex 1f42473..f1141a3 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -683,17 +683,18 @@ int ce_same_name(struct cache_entry *a, struct cache_entry *b)\n \treturn ce_namelen(b) == len && !memcmp(a->name, b->name, len);\n }\n \n-int ce_path_match(const struct cache_entry *ce, const char **pathspec)\n+int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)\n {\n \tconst char *match, *name;\n+\tconst char **ps = pathspec->raw;\n \tint len;\n \n-\tif (!pathspec)\n+\tif (!pathspec->nr)\n \t\treturn 1;\n \n \tlen = ce_namelen(ce);\n \tname = ce->name;\n-\twhile ((match = *pathspec++) != NULL) {\n+\twhile ((match = *ps++) != NULL) {\n \t\tint matchlen = strlen(match);\n \t\tif (matchlen > len)\n \t\t\tcontinue;\ndiff --git a/revision.c b/revision.c\nindex 515e2dd..a0d3816 100644\n--- a/revision.c\n+++ b/revision.c\n@@ -969,7 +969,7 @@ static void prepare_show_merge(struct rev_info *revs)\n \t\tstruct cache_entry *ce = active_cache[i];\n \t\tif (!ce_stage(ce))\n \t\t\tcontinue;\n-\t\tif (ce_path_match(ce, revs->prune_data.raw)) {\n+\t\tif (ce_path_match(ce, &revs->prune_data)) {\n \t\t\tprune_num++;\n \t\t\tprune = xrealloc(prune, sizeof(*prune) * prune_num);\n \t\t\tprune[prune_num-2] = ce->name;\ndiff --git a/wt-status.c b/wt-status.c\nindex 5c6b118..457d265 100644\n--- a/wt-status.c\n+++ b/wt-status.c\n@@ -350,14 +350,16 @@ static void wt_status_collect_changes_index(struct wt_status *s)\n \n static void wt_status_collect_changes_initial(struct wt_status *s)\n {\n+\tstruct pathspec pathspec;\n \tint i;\n \n+\tinit_pathspec(&pathspec, s->pathspec);\n \tfor (i = 0; i < active_nr; i++) {\n \t\tstruct string_list_item *it;\n \t\tstruct wt_status_change_data *d;\n \t\tstruct cache_entry *ce = active_cache[i];\n \n-\t\tif (!ce_path_match(ce, s->pathspec))\n+\t\tif (!ce_path_match(ce, &pathspec))\n \t\t\tcontinue;\n \t\tit = string_list_insert(&s->change, ce->name);\n \t\td = it->util;\n@@ -372,6 +374,7 @@ static void wt_status_collect_changes_initial(struct wt_status *s)\n \t\telse\n \t\t\td->index_status = DIFF_STATUS_ADDED;\n \t}\n+\tfree_pathspec(&pathspec);\n }\n \n static void wt_status_collect_untracked(struct wt_status *s)\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158278","messageId":"1292589865-9617-1-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"AANLkTi=hXQqtYmhtHh+D67d9puRrDA+iScpafaYYMsAk@mail.gmail.com","subject":"[PATCH 19/21] grep: use writable strbuf from caller for grep_tree()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T12:44:25Z","receivedAt":"2010-12-17T12:44:25Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n strbuf_offset and its patch are dropped.\n\n builtin/grep.c |   51 ++++++++++++++++++++++++---------------------------\n 1 files changed, 24 insertions(+), 27 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex fbc7d02..fa1ad28 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -623,43 +623,29 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n }\n \n static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n-\t\t     struct tree_desc *tree,\n-\t\t     const char *tree_name, const char *base)\n+\t\t     struct tree_desc *tree, struct strbuf *base, int tn_len)\n {\n-\tint len;\n \tint hit = 0;\n \tstruct name_entry entry;\n-\tchar *down;\n-\tint tn_len = strlen(tree_name);\n-\tstruct strbuf pathbuf;\n-\n-\tstrbuf_init(&pathbuf, PATH_MAX + tn_len);\n-\n-\tif (tn_len) {\n-\t\tstrbuf_add(&pathbuf, tree_name, tn_len);\n-\t\tstrbuf_addch(&pathbuf, ':');\n-\t\ttn_len = pathbuf.len;\n-\t}\n-\tstrbuf_addstr(&pathbuf, base);\n-\tlen = pathbuf.len;\n+\tint old_baselen = base->len;\n \n \twhile (tree_entry(tree, &entry)) {\n \t\tint te_len = tree_entry_len(entry.path, entry.sha1);\n-\t\tpathbuf.len = len;\n-\t\tstrbuf_add(&pathbuf, entry.path, te_len);\n+\n+\t\tstrbuf_add(base, entry.path, te_len);\n \n \t\tif (S_ISDIR(entry.mode))\n \t\t\t/* Match \"abc/\" against pathspec to\n \t\t\t * decide if we want to descend into \"abc\"\n \t\t\t * directory.\n \t\t\t */\n-\t\t\tstrbuf_addch(&pathbuf, '/');\n+\t\t\tstrbuf_addch(base, '/');\n \n-\t\tdown = pathbuf.buf + tn_len;\n-\t\tif (!pathspec_matches(pathspec->raw, down, opt->max_depth))\n+\t\tif (!pathspec_matches(pathspec->raw, base->buf + tn_len, opt->max_depth))\n \t\t\t;\n-\t\telse if (S_ISREG(entry.mode))\n-\t\t\thit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);\n+\t\telse if (S_ISREG(entry.mode)) {\n+\t\t\thit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);\n+\t\t}\n \t\telse if (S_ISDIR(entry.mode)) {\n \t\t\tenum object_type type;\n \t\t\tstruct tree_desc sub;\n@@ -671,13 +657,14 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\t\tdie(\"unable to read tree (%s)\",\n \t\t\t\t    sha1_to_hex(entry.sha1));\n \t\t\tinit_tree_desc(&sub, data, size);\n-\t\t\thit |= grep_tree(opt, pathspec, &sub, tree_name, down);\n+\t\t\thit |= grep_tree(opt, pathspec, &sub, base, tn_len);\n \t\t\tfree(data);\n \t\t}\n+\t\tstrbuf_setlen(base, old_baselen);\n+\n \t\tif (hit && opt->status_only)\n \t\t\tbreak;\n \t}\n-\tstrbuf_release(&pathbuf);\n \treturn hit;\n }\n \n@@ -690,13 +677,23 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\tstruct tree_desc tree;\n \t\tvoid *data;\n \t\tunsigned long size;\n-\t\tint hit;\n+\t\tstruct strbuf base;\n+\t\tint hit, len;\n+\n \t\tdata = read_object_with_reference(obj->sha1, tree_type,\n \t\t\t\t\t\t  &size, NULL);\n \t\tif (!data)\n \t\t\tdie(\"unable to read tree (%s)\", sha1_to_hex(obj->sha1));\n+\n+\t\tlen = name ? strlen(name) : 0;\n+\t\tstrbuf_init(&base, PATH_MAX + len + 1);\n+\t\tif (len) {\n+\t\t\tstrbuf_add(&base, name, len);\n+\t\t\tstrbuf_addch(&base, ':');\n+\t\t}\n \t\tinit_tree_desc(&tree, data, size);\n-\t\thit = grep_tree(opt, pathspec, &tree, name, \"\");\n+\t\thit = grep_tree(opt, pathspec, &tree, &base, base.len);\n+\t\tstrbuf_release(&base);\n \t\tfree(data);\n \t\treturn hit;\n \t}\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158279","messageId":"1292589933-9706-1-git-send-email-pclouds@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-21-git-send-email-pclouds@gmail.com","subject":"[PATCH 20/21] grep: drop pathspec_matches() in favor of tree_entry_interesting()","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T12:45:33Z","receivedAt":"2010-12-17T12:45:33Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n tree_entry_interesting now takes base_offset. The real base is\n base->buf+base_offset\n\n builtin/grep.c |  125 ++++++-------------------------------------------------\n tree-diff.c    |    4 +-\n tree-walk.c    |   19 ++++----\n tree-walk.h    |    2 +-\n 4 files changed, 27 insertions(+), 123 deletions(-)\n\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex fa1ad28..7256002 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -333,106 +333,6 @@ static int grep_config(const char *var, const char *value, void *cb)\n \treturn 0;\n }\n \n-/*\n- * Return non-zero if max_depth is negative or path has no more then max_depth\n- * slashes.\n- */\n-static int accept_subdir(const char *path, int max_depth)\n-{\n-\tif (max_depth < 0)\n-\t\treturn 1;\n-\n-\twhile ((path = strchr(path, '/')) != NULL) {\n-\t\tmax_depth--;\n-\t\tif (max_depth < 0)\n-\t\t\treturn 0;\n-\t\tpath++;\n-\t}\n-\treturn 1;\n-}\n-\n-/*\n- * Return non-zero if name is a subdirectory of match and is not too deep.\n- */\n-static int is_subdir(const char *name, int namelen,\n-\t\tconst char *match, int matchlen, int max_depth)\n-{\n-\tif (matchlen > namelen || strncmp(name, match, matchlen))\n-\t\treturn 0;\n-\n-\tif (name[matchlen] == '\\0') /* exact match */\n-\t\treturn 1;\n-\n-\tif (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')\n-\t\treturn accept_subdir(name + matchlen + 1, max_depth);\n-\n-\treturn 0;\n-}\n-\n-/*\n- * git grep pathspecs are somewhat different from diff-tree pathspecs;\n- * pathname wildcards are allowed.\n- */\n-static int pathspec_matches(const char **paths, const char *name, int max_depth)\n-{\n-\tint namelen, i;\n-\tif (!paths || !*paths)\n-\t\treturn accept_subdir(name, max_depth);\n-\tnamelen = strlen(name);\n-\tfor (i = 0; paths[i]; i++) {\n-\t\tconst char *match = paths[i];\n-\t\tint matchlen = strlen(match);\n-\t\tconst char *cp, *meta;\n-\n-\t\tif (is_subdir(name, namelen, match, matchlen, max_depth))\n-\t\t\treturn 1;\n-\t\tif (!fnmatch(match, name, 0))\n-\t\t\treturn 1;\n-\t\tif (name[namelen-1] != '/')\n-\t\t\tcontinue;\n-\n-\t\t/* We are being asked if the directory (\"name\") is worth\n-\t\t * descending into.\n-\t\t *\n-\t\t * Find the longest leading directory name that does\n-\t\t * not have metacharacter in the pathspec; the name\n-\t\t * we are looking at must overlap with that directory.\n-\t\t */\n-\t\tfor (cp = match, meta = NULL; cp - match < matchlen; cp++) {\n-\t\t\tchar ch = *cp;\n-\t\t\tif (ch == '*' || ch == '[' || ch == '?') {\n-\t\t\t\tmeta = cp;\n-\t\t\t\tbreak;\n-\t\t\t}\n-\t\t}\n-\t\tif (!meta)\n-\t\t\tmeta = cp; /* fully literal */\n-\n-\t\tif (namelen <= meta - match) {\n-\t\t\t/* Looking at \"Documentation/\" and\n-\t\t\t * the pattern says \"Documentation/howto/\", or\n-\t\t\t * \"Documentation/diff*.txt\".  The name we\n-\t\t\t * have should match prefix.\n-\t\t\t */\n-\t\t\tif (!memcmp(match, name, namelen))\n-\t\t\t\treturn 1;\n-\t\t\tcontinue;\n-\t\t}\n-\n-\t\tif (meta - match < namelen) {\n-\t\t\t/* Looking at \"Documentation/howto/\" and\n-\t\t\t * the pattern says \"Documentation/h*\";\n-\t\t\t * match up to \"Do.../h\"; this avoids descending\n-\t\t\t * into \"Documentation/technical/\".\n-\t\t\t */\n-\t\t\tif (!memcmp(match, name, meta - match))\n-\t\t\t\treturn 1;\n-\t\t\tcontinue;\n-\t\t}\n-\t}\n-\treturn 0;\n-}\n-\n static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)\n {\n \tvoid *data;\n@@ -625,25 +525,24 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t     struct tree_desc *tree, struct strbuf *base, int tn_len)\n {\n-\tint hit = 0;\n+\tint hit = 0, matched = 0;\n \tstruct name_entry entry;\n \tint old_baselen = base->len;\n \n \twhile (tree_entry(tree, &entry)) {\n \t\tint te_len = tree_entry_len(entry.path, entry.sha1);\n \n-\t\tstrbuf_add(base, entry.path, te_len);\n+\t\tif (matched != 2) {\n+\t\t\tmatched = tree_entry_interesting(&entry, base, tn_len, pathspec);\n+\t\t\tif (matched == -1)\n+\t\t\t\tbreak; /* no more matches */\n+\t\t\tif (!matched)\n+\t\t\t\tcontinue;\n+\t\t}\n \n-\t\tif (S_ISDIR(entry.mode))\n-\t\t\t/* Match \"abc/\" against pathspec to\n-\t\t\t * decide if we want to descend into \"abc\"\n-\t\t\t * directory.\n-\t\t\t */\n-\t\t\tstrbuf_addch(base, '/');\n+\t\tstrbuf_add(base, entry.path, te_len);\n \n-\t\tif (!pathspec_matches(pathspec->raw, base->buf + tn_len, opt->max_depth))\n-\t\t\t;\n-\t\telse if (S_ISREG(entry.mode)) {\n+\t\tif (S_ISREG(entry.mode)) {\n \t\t\thit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);\n \t\t}\n \t\telse if (S_ISDIR(entry.mode)) {\n@@ -656,6 +555,8 @@ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,\n \t\t\tif (!data)\n \t\t\t\tdie(\"unable to read tree (%s)\",\n \t\t\t\t    sha1_to_hex(entry.sha1));\n+\n+\t\t\tstrbuf_addch(base, '/');\n \t\t\tinit_tree_desc(&sub, data, size);\n \t\t\thit |= grep_tree(opt, pathspec, &sub, base, tn_len);\n \t\t\tfree(data);\n@@ -1062,6 +963,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\tpaths[1] = NULL;\n \t}\n \tinit_pathspec(&pathspec, paths);\n+\tpathspec.max_depth = opt.max_depth;\n+\tpathspec.recursive = 1;\n \n \tif (show_in_pager && (cached || list.nr))\n \t\tdie(\"--open-files-in-pager only works on the worktree\");\ndiff --git a/tree-diff.c b/tree-diff.c\nindex bde2c52..064233a 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -72,7 +72,7 @@ static void show_tree(struct diff_options *opt, const char *prefix,\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(&desc->entry, base,\n+\t\t\tshow = tree_entry_interesting(&desc->entry, base, 0,\n \t\t\t\t\t\t      &opt->pathspec);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\n@@ -130,7 +130,7 @@ static void skip_uninteresting(struct tree_desc *t, struct strbuf *base,\n \t\tif (all_interesting)\n \t\t\tshow = 1;\n \t\telse {\n-\t\t\tshow = tree_entry_interesting(&t->entry, base,\n+\t\t\tshow = tree_entry_interesting(&t->entry, base, 0,\n \t\t\t\t\t\t      &opt->pathspec);\n \t\t\tif (show == 2)\n \t\t\t\tall_interesting = 1;\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 99413b3..9b43ad5 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -551,17 +551,17 @@ static int match_dir_prefix(const char *base, int baselen,\n  *  - negative for \"no, and no subsequent entries will be either\"\n  */\n int tree_entry_interesting(const struct name_entry *entry,\n-\t\t\t   struct strbuf *base,\n+\t\t\t   struct strbuf *base, int base_offset,\n \t\t\t   const struct pathspec *ps)\n {\n \tint i;\n-\tint pathlen, baselen = base->len;\n+\tint pathlen, baselen = base->len - base_offset;\n \tint never_interesting = ps->has_wildcard ? 0 : -1;\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive || ps->max_depth == -1)\n \t\t\treturn 1;\n-\t\treturn !!within_depth(base->buf, baselen,\n+\t\treturn !!within_depth(base->buf + base_offset, baselen,\n \t\t\t\t      !!S_ISDIR(entry->mode),\n \t\t\t\t      ps->max_depth);\n \t}\n@@ -571,24 +571,25 @@ int tree_entry_interesting(const struct name_entry *entry,\n \tfor (i = ps->nr-1; i >= 0; i--) {\n \t\tconst struct pathspec_item *item = ps->items+i;\n \t\tconst char *match = item->match;\n+\t\tconst char *base_str = base->buf + base_offset;\n \t\tint matchlen = item->len;\n \n \t\tif (baselen >= matchlen) {\n \t\t\t/* If it doesn't match, move along... */\n-\t\t\tif (!match_dir_prefix(base->buf, baselen, match, matchlen))\n+\t\t\tif (!match_dir_prefix(base_str, baselen, match, matchlen))\n \t\t\t\tgoto match_wildcards;\n \n \t\t\tif (!ps->recursive || ps->max_depth == -1)\n \t\t\t\treturn 2;\n \n-\t\t\treturn !!within_depth(base->buf + matchlen + 1,\n+\t\t\treturn !!within_depth(base_str + matchlen + 1,\n \t\t\t\t\t      baselen - matchlen - 1,\n \t\t\t\t\t      !!S_ISDIR(entry->mode),\n \t\t\t\t\t      ps->max_depth);\n \t\t}\n \n \t\t/* Does the base match? */\n-\t\tif (!strncmp(base->buf, match, baselen)) {\n+\t\tif (!strncmp(base_str, match, baselen)) {\n \t\t\tif (match_entry(entry, pathlen,\n \t\t\t\t\tmatch + baselen, matchlen - baselen,\n \t\t\t\t\t&never_interesting))\n@@ -620,11 +621,11 @@ match_wildcards:\n \n \t\tstrbuf_add(base, entry->path, pathlen);\n \n-\t\tif (!fnmatch(match, base->buf, 0)) {\n-\t\t\tstrbuf_setlen(base, baselen);\n+\t\tif (!fnmatch(match, base->buf + base_offset, 0)) {\n+\t\t\tstrbuf_setlen(base, base_offset + baselen);\n \t\t\treturn 1;\n \t\t}\n-\t\tstrbuf_setlen(base, baselen);\n+\t\tstrbuf_setlen(base, base_offset + baselen);\n \n \t\t/*\n \t\t * Match all directories. We'll try to match files\ndiff --git a/tree-walk.h b/tree-walk.h\nindex 6589ee2..39524b7 100644\n--- a/tree-walk.h\n+++ b/tree-walk.h\n@@ -60,6 +60,6 @@ static inline int traverse_path_len(const struct traverse_info *info, const stru\n \treturn info->pathlen + tree_entry_len(n->path, n->sha1);\n }\n \n-extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, const struct pathspec *ps);\n+extern int tree_entry_interesting(const struct name_entry *, struct strbuf *, int, const struct pathspec *ps);\n \n #endif\n-- \n1.7.3.3.476.g10a82\n"},{"id":"158284","messageId":"7vfwtwjv0f.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"AANLkTikKCU==mS5_TdqHstETj=CQ_deHMCJ4xW0r+Sck@mail.gmail.com","subject":"Re: [PATCH 14/21] Convert ce_path_match() to use struct pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-12-17T15:09:52Z","receivedAt":"2010-12-17T15:09:52Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n>> I wonder if it makes more sense to change the type of revs->prune_data\n>> from an array of pointers to strings to a pointer to struct pathspec.\n>> Is there a downside?\n>\n> Converting a pointer to another pointer means mis typecasting can\n> happen and the compiler won't help catching them.\n\nYou can rename the field at the same time, and the compiler will catch\nanything you forgot to touch, no?\n"},{"id":"158285","messageId":"AANLkTinfzd8wOFTymVGeKH6cBg-6Ua6U+4N8x1TrQcHZ@mail.gmail.com","threadId":"26076","inReplyTo":"7vfwtwjv0f.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 14/21] Convert ce_path_match() to use struct pathspec","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-17T15:11:30Z","receivedAt":"2010-12-17T15:11:30Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Fri, Dec 17, 2010 at 10:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n>\n>>> I wonder if it makes more sense to change the type of revs->prune_data\n>>> from an array of pointers to strings to a pointer to struct pathspec.\n>>> Is there a downside?\n>>\n>> Converting a pointer to another pointer means mis typecasting can\n>> happen and the compiler won't help catching them.\n>\n> You can rename the field at the same time, and the compiler will catch\n> anything you forgot to touch, no?\n>\n\nYes. I didn't think of that :(\n-- \nDuy\n"},{"id":"158288","messageId":"7vsjxwi2vz.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"AANLkTi=4vnitj-U5M+V_ALVpAk0ncMG=09aAEqA=KD41@mail.gmail.com","subject":"Re: [PATCH 10/21] tree_entry_interesting(): fix depth limit with overlapping pathspecs","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-12-17T20:02:40Z","receivedAt":"2010-12-17T20:02:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n> 2010/12/17 Junio C Hamano <gitster@pobox.com>:\n>> One thing I am not clear is what it means to limit the recursion level\n>> when you have wildcards.\n>\n> Recursion level does not affect wildcards at all. That was original\n> design, a91f453 (grep: Add --max-depth option. - 2009-07-22). I think\n> current git-grep still follows that.\n\nI know what the current code does, as I remember a91f453 essentially\npunted on coming up with a sane semantics.  As this series under\ndiscussion is about coming up with a unified and sane pathspec handling\nacross board, it would be a good opportunity to think about it again, this\ntime without punting so fast.\n"},{"id":"158290","messageId":"7voc8ki1o3.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"AANLkTinfzd8wOFTymVGeKH6cBg-6Ua6U+4N8x1TrQcHZ@mail.gmail.com","subject":"Re: [PATCH 14/21] Convert ce_path_match() to use struct pathspec","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-12-17T20:29:00Z","receivedAt":"2010-12-17T20:29:00Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n> On Fri, Dec 17, 2010 at 10:09 PM, Junio C Hamano <gitster@pobox.com> wrote:\n>> Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n>>\n>>>> I wonder if it makes more sense to change the type of revs->prune_data\n>>>> from an array of pointers to strings to a pointer to struct pathspec.\n>>>> Is there a downside?\n>>>\n>>> Converting a pointer to another pointer means mis typecasting can\n>>> happen and the compiler won't help catching them.\n>>\n>> You can rename the field at the same time, and the compiler will catch\n>> anything you forgot to touch, no?\n>>\n> Yes. I didn't think of that :(\n\nAnd it would have an added benefit that it would catch new callsites\nsomebody else added while being unaware of your conversion--the merge\nresult will not compile.\n"},{"id":"158299","messageId":"AANLkTik+DaUrh99qs4T-Pm_+3Oq499L_NtP6Xcht1wfH@mail.gmail.com","threadId":"26076","inReplyTo":"7vmxo5l2g4.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 10/21] tree_entry_interesting(): fix depth limit with overlapping pathspecs","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-12-18T03:37:28Z","receivedAt":"2010-12-18T03:37:28Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/12/17 Junio C Hamano <gitster@pobox.com>:\n> One possible definition of interaction between limit and wildcard may be\n> to count the number of slashes in the part of the path that matches the\n> wildcarded part of the pathspec, add the number of path components\n> appended due to the leading directory match, and then subtract the number\n> of literal slashes in the wildcarded part of the pattern from the above,\n> and declare that a match is found if the difference is less than the\n> limit.\n>\n> E.g. a pathspec element \"a/*/x\" would match \"a/b/c/x\", \"a/b/c/d/e/x\",\n> \"a/b/x/y\" and \"a/b/x/y/z\" without limit, and with the limit of 1:\n>\n>    a/b/c/x        matches ('*' expands to \"b/c\")\n>    a/b/c/d/e/x    no ('*' has to expand to \"c/d/e\" and needs 2 levels)\n>    a/b/x/y        matches ('*' expands to \"b\" costing zero, \"/y\" needs 1)\n>    a/b/x/y/z      does not match\n>\n> Another definition could be to count _only_ the part that is appended by\n> recursion (i.e. we do not count how many slashes has to match '*' in the\n> above examples), and as the option is called --depth, it might make more\n> sense.\n\nSo with the above example, \"a/\" won't be counted. Depth limit of 0 or\n1 will result in no matches. Depth limit of 2 will result in a/b/c/x\nand a/b/x/y, correct?\n\nI prefer this definition to the former. It sounds simpler to\nunderstand and use, also less computation. But I can implement both\n:-) We can mark what matching strategy we would use in struct\npathspec.  Hmm.. I'm not much help in figuring out which one makes\nmore sense.\n\nAnother thing, I don't know if anybody would need it. Should we\nsupport depth limit per pathspec, so \"a/*/x\" can have depth limit of\n2, but \"*.c\" has depth limit of 1..For one thing, his may help keeping\ncurrent's git-grep depth limit behavior if depth limit can also be\napplied to wildcard pathspecs by setting depth limit for wildcard\npathspecs to -1. Exposing depth limit per pathspec to users is another\nmatter.\n\n> In either case, I am not sure if \"if it matches the longest pathspec, we\n> have the answer without looking at shorter ones\" would be a good rule to\n> use.\n\nAs long as the rule of matching is \"if any of these pathspecs is\nmatched, we have a match\", then pathspec order should not matter\n(without depth limit). Matching decision of one pathspec does not\naffect the others. Depth limit is the first one breaking the last\nsentence. And because pathspec order does not matter before depth\nlimit introduction, it should not cause any regression when depth\nlimit requires pathspecs in certain order. That's how I thought when I\ndecided to sort pathspecs.\n\nWildcard pathspecs are handled in a completely different path (even\nwith depth limit in either way you described). Overlapping is no issue\nto wildcard pathspecs, we always need full pathspec to call fnmatch()\n(unless you implied some early cut optmization that I don't see).\nTherefore pathspec order is no issue.\n\nEven when I introduce negative pathspec, it would be actually negative\nprefix and go the same route as current depth limit impl (it also has\nthe same overlapping pathspec issue). Negative wildcard pathspecs\nwould blow my mind.\n-- \nDuy\n"},{"id":"160007","messageId":"7vd3ngdaoa.fsf@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"1292425376-14550-10-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 09/21] tree_entry_interesting(): support depth limit","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-01-28T20:40:21Z","receivedAt":"2011-01-28T20:40:21Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n\n>  static const char *get_mode(const char *str, unsigned int *modep)\n> @@ -557,8 +558,13 @@ int tree_entry_interesting(const struct name_entry *entry,\n>  \tint pathlen, baselen = base->len;\n>  \tint never_interesting = -1;\n>  \n> -\tif (!ps || !ps->nr)\n> -\t\treturn 1;\n> +\tif (!ps->nr) {\n> +\t\tif (!ps->recursive || ps->max_depth == -1)\n> +\t\t\treturn 1;\n> +\t\treturn !!within_depth(base->buf, baselen,\n> +\t\t\t\t      !!S_ISDIR(entry->mode),\n> +\t\t\t\t      ps->max_depth);\n> +\t}\n\nBack in 1d848f6 (tree_entry_interesting(): allow it to say \"everything is\ninteresting\", 2007-03-21), a new return value \"2\" was introduced to allow\nthis function to tell the caller that all the remaining entries in the\ntree object the caller is feeding the entries to this function _will_\nmatch.  This was to optimize away expensive pathspec matching done by this\nfunction.\n\nIn that version, \"no pathspec\" case wasn't changed to return 2 but still\nreturned 1 (\"I tell you that this does not match; call me with the next\nentry\").  We could have changed it to return 2, but the overhead was only\na call to a function that checks the number of pathspecs and was not so\nbad.\n\nBut shouldn't we start returning 2 by now?  It is not that returning 1 was\na more correct thing to do to begin with.\n\nWhen depth check is in effect, the result depends on the mode of the\nentry, so we cannot short-circuit by returning 2, but at least we should\ndo so when (max_depth == -1), no?\n"},{"id":"160018","messageId":"AANLkTik_7FUuocoXa7Rk5DWSR4ie7FBfYNa0MSQzwnsZ@mail.gmail.com","threadId":"26076","inReplyTo":"7vd3ngdaoa.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 09/21] tree_entry_interesting(): support depth limit","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2011-01-29T03:13:50Z","receivedAt":"2011-01-29T03:13:50Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2011/1/29 Junio C Hamano <gitster@pobox.com>:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>>  static const char *get_mode(const char *str, unsigned int *modep)\n>> @@ -557,8 +558,13 @@ int tree_entry_interesting(const struct name_entry *entry,\n>>       int pathlen, baselen = base->len;\n>>       int never_interesting = -1;\n>>\n>> -     if (!ps || !ps->nr)\n>> -             return 1;\n>> +     if (!ps->nr) {\n>> +             if (!ps->recursive || ps->max_depth == -1)\n>> +                     return 1;\n>> +             return !!within_depth(base->buf, baselen,\n>> +                                   !!S_ISDIR(entry->mode),\n>> +                                   ps->max_depth);\n>> +     }\n>\n> Back in 1d848f6 (tree_entry_interesting(): allow it to say \"everything is\n> interesting\", 2007-03-21), a new return value \"2\" was introduced to allow\n> this function to tell the caller that all the remaining entries in the\n> tree object the caller is feeding the entries to this function _will_\n> match.  This was to optimize away expensive pathspec matching done by this\n> function.\n>\n> In that version, \"no pathspec\" case wasn't changed to return 2 but still\n> returned 1 (\"I tell you that this does not match; call me with the next\n> entry\").  We could have changed it to return 2, but the overhead was only\n> a call to a function that checks the number of pathspecs and was not so\n> bad.\n>\n> But shouldn't we start returning 2 by now?  It is not that returning 1 was\n> a more correct thing to do to begin with.\n>\n> When depth check is in effect, the result depends on the mode of the\n> entry, so we cannot short-circuit by returning 2, but at least we should\n> do so when (max_depth == -1), no?\n\nYes, should be 2.\n-- \nDuy\n"},{"id":"160110","messageId":"7v62t46cyz.fsf_-_@alter.siamese.dyndns.org","threadId":"26076","inReplyTo":"AANLkTik_7FUuocoXa7Rk5DWSR4ie7FBfYNa0MSQzwnsZ@mail.gmail.com","subject":"[PATCH] tree_entry_interesting(): with no pathspecs, everything will match","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2011-01-31T20:21:40Z","receivedAt":"2011-01-31T20:21:40Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Hence the function should return \"2\" in such a case as advertised.\n\nNote that finding a directory that busts the depth limit does not mean non\ndirectories at the same level would also bust the limit (they don't), so\nwe still need to return 1, not 2 in the within_depth() codepath.\n\nSigned-off-by: Junio C Hamano <gitster@pobox.com>\n--- \n\n  Nguyen Thai Ngoc Duy <pclouds@gmail.com> writes:\n\n  >> When depth check is in effect, the result depends on the mode of the\n  >> entry, so we cannot short-circuit by returning 2, but at least we should\n  >> do so when (max_depth == -1), no?\n  >\n  > Yes, should be 2.\n\n  Thanks.  I'll queue this.\n\n tree-walk.c |    2 +-\n 1 files changed, 1 insertions(+), 1 deletions(-)\n\ndiff --git a/tree-walk.c b/tree-walk.c\nindex 9b43ad5..ece8cc0 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -560,7 +560,7 @@ int tree_entry_interesting(const struct name_entry *entry,\n \n \tif (!ps->nr) {\n \t\tif (!ps->recursive || ps->max_depth == -1)\n-\t\t\treturn 1;\n+\t\t\treturn 2;\n \t\treturn !!within_depth(base->buf + base_offset, baselen,\n \t\t\t\t      !!S_ISDIR(entry->mode),\n \t\t\t\t      ps->max_depth);\n-- \n1.7.4.261.g705f2\n"},{"id":"368449","messageId":"20190204103618.17992-1-avarab@gmail.com","threadId":"26076","inReplyTo":"1292425376-14550-12-git-send-email-pclouds@gmail.com","subject":"[PATCH] diff-tree doc: correct & remove wrong documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-04T10:36:18Z","receivedAt":"2019-02-04T10:36:33Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"The documentation saying that diff-tree didn't support anything except\nliteral prefixes hasn't been true since\nd38f28093e (\"tree_entry_interesting(): support wildcard matching\",\n2010-12-15), but this documentation was not updated at the time.\n\nSince this command uses pathspecs like most other commands, there's no\nneed to show examples of how the various \"cmd <revs> <paths>\"\ninvocations work.\n\nFurthermore, the \"git diff-tree --abbrev 5319e4\" example shown here\nnever worked. We'd ended up with that through a combination of\n62b42d3487 (\"docs: fix some antique example output\", 2011-05-26) and\nac4e086929 (\"Adjust core-git documentation to more recent Linus GIT.\",\n2005-05-05), but \"git diff-tree <tree>\" was always invalid.\n\nSigned-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n---\n Documentation/git-diff-tree.txt | 51 +--------------------------------\n 1 file changed, 1 insertion(+), 50 deletions(-)\n\ndiff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt\nindex 2319b2b192..43daa7c046 100644\n--- a/Documentation/git-diff-tree.txt\n+++ b/Documentation/git-diff-tree.txt\n@@ -31,10 +31,7 @@ include::diff-options.txt[]\n \n <path>...::\n \tIf provided, the results are limited to a subset of files\n-\tmatching one of these prefix strings.\n-\ti.e., file matches `/^<pattern1>|<pattern2>|.../`\n-\tNote that this parameter does not provide any wildcard or regexp\n-\tfeatures.\n+\tmatching one of the provided pathspecs.\n \n -r::\n         recurse into sub-trees\n@@ -114,52 +111,6 @@ include::pretty-options.txt[]\n \n \n include::pretty-formats.txt[]\n-\n-\n-LIMITING OUTPUT\n----------------\n-If you're only interested in differences in a subset of files, for\n-example some architecture-specific files, you might do:\n-\n-\tgit diff-tree -r <tree-ish> <tree-ish> arch/ia64 include/asm-ia64\n-\n-and it will only show you what changed in those two directories.\n-\n-Or if you are searching for what changed in just `kernel/sched.c`, just do\n-\n-\tgit diff-tree -r <tree-ish> <tree-ish> kernel/sched.c\n-\n-and it will ignore all differences to other files.\n-\n-The pattern is always the prefix, and is matched exactly.  There are no\n-wildcards.  Even stricter, it has to match a complete path component.\n-I.e. \"foo\" does not pick up `foobar.h`.  \"foo\" does match `foo/bar.h`\n-so it can be used to name subdirectories.\n-\n-An example of normal usage is:\n-\n-  torvalds@ppc970:~/git> git diff-tree --abbrev 5319e4\n-  :100664 100664 ac348b... a01513...\tgit-fsck-objects.c\n-\n-which tells you that the last commit changed just one file (it's from\n-this one:\n-\n------------------------------------------------------------------------------\n-commit 3c6f7ca19ad4043e9e72fa94106f352897e651a8\n-tree 5319e4d609cdd282069cc4dce33c1db559539b03\n-parent b4e628ea30d5ab3606119d2ea5caeab141d38df7\n-author Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n-committer Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n-\n-Make \"git-fsck-objects\" print out all the root commits it finds.\n-\n-Once I do the reference tracking, I'll also make it print out all the\n-HEAD commits it finds, which is even more interesting.\n------------------------------------------------------------------------------\n-\n-in case you care).\n-\n-\n include::diff-format.txt[]\n \n GIT\n-- \n2.20.1.611.gfbb209baf1\n\n"},{"id":"368452","messageId":"CACsJy8BnwRfBZvOq9Yng_n4aqAX0DRG4csbMjVe=9CRWSTajbQ@mail.gmail.com","threadId":"26076","inReplyTo":"20190204103618.17992-1-avarab@gmail.com","subject":"Re: [PATCH] diff-tree doc: correct & remove wrong documentation","fromName":"Duy Nguyen","fromEmail":"pclouds@gmail.com","sentAt":"2019-02-04T10:42:45Z","receivedAt":"2019-02-04T11:07:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"On Mon, Feb 4, 2019 at 5:36 PM Ævar Arnfjörð Bjarmason <avarab@gmail.com> wrote:\n>\n> The documentation saying that diff-tree didn't support anything except\n> literal prefixes hasn't been true since\n> d38f28093e (\"tree_entry_interesting(): support wildcard matching\",\n> 2010-12-15), but this documentation was not updated at the time.\n>\n> Since this command uses pathspecs like most other commands, there's no\n> need to show examples of how the various \"cmd <revs> <paths>\"\n> invocations work.\n>\n> Furthermore, the \"git diff-tree --abbrev 5319e4\" example shown here\n> never worked. We'd ended up with that through a combination of\n> 62b42d3487 (\"docs: fix some antique example output\", 2011-05-26) and\n> ac4e086929 (\"Adjust core-git documentation to more recent Linus GIT.\",\n> 2005-05-05), but \"git diff-tree <tree>\" was always invalid.\n\nNice!\n\nI was going to protest \"but it does not work!\" but I was thinking\nls-tree instead of diff-tree.\n\n>\n> Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com>\n> ---\n>  Documentation/git-diff-tree.txt | 51 +--------------------------------\n>  1 file changed, 1 insertion(+), 50 deletions(-)\n>\n> diff --git a/Documentation/git-diff-tree.txt b/Documentation/git-diff-tree.txt\n> index 2319b2b192..43daa7c046 100644\n> --- a/Documentation/git-diff-tree.txt\n> +++ b/Documentation/git-diff-tree.txt\n> @@ -31,10 +31,7 @@ include::diff-options.txt[]\n>\n>  <path>...::\n>         If provided, the results are limited to a subset of files\n> -       matching one of these prefix strings.\n> -       i.e., file matches `/^<pattern1>|<pattern2>|.../`\n> -       Note that this parameter does not provide any wildcard or regexp\n> -       features.\n> +       matching one of the provided pathspecs.\n>\n>  -r::\n>          recurse into sub-trees\n> @@ -114,52 +111,6 @@ include::pretty-options.txt[]\n>\n>\n>  include::pretty-formats.txt[]\n> -\n> -\n> -LIMITING OUTPUT\n> ----------------\n> -If you're only interested in differences in a subset of files, for\n> -example some architecture-specific files, you might do:\n> -\n> -       git diff-tree -r <tree-ish> <tree-ish> arch/ia64 include/asm-ia64\n> -\n> -and it will only show you what changed in those two directories.\n> -\n> -Or if you are searching for what changed in just `kernel/sched.c`, just do\n> -\n> -       git diff-tree -r <tree-ish> <tree-ish> kernel/sched.c\n> -\n> -and it will ignore all differences to other files.\n> -\n> -The pattern is always the prefix, and is matched exactly.  There are no\n> -wildcards.  Even stricter, it has to match a complete path component.\n> -I.e. \"foo\" does not pick up `foobar.h`.  \"foo\" does match `foo/bar.h`\n> -so it can be used to name subdirectories.\n> -\n> -An example of normal usage is:\n> -\n> -  torvalds@ppc970:~/git> git diff-tree --abbrev 5319e4\n> -  :100664 100664 ac348b... a01513...   git-fsck-objects.c\n> -\n> -which tells you that the last commit changed just one file (it's from\n> -this one:\n> -\n> ------------------------------------------------------------------------------\n> -commit 3c6f7ca19ad4043e9e72fa94106f352897e651a8\n> -tree 5319e4d609cdd282069cc4dce33c1db559539b03\n> -parent b4e628ea30d5ab3606119d2ea5caeab141d38df7\n> -author Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n> -committer Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n> -\n> -Make \"git-fsck-objects\" print out all the root commits it finds.\n> -\n> -Once I do the reference tracking, I'll also make it print out all the\n> -HEAD commits it finds, which is even more interesting.\n> ------------------------------------------------------------------------------\n> -\n> -in case you care).\n> -\n> -\n>  include::diff-format.txt[]\n>\n>  GIT\n> --\n> 2.20.1.611.gfbb209baf1\n>\n\n\n-- \nDuy\n"},{"id":"368487","messageId":"xmqqpns7tg2x.fsf@gitster-ct.c.googlers.com","threadId":"26076","inReplyTo":"20190204103618.17992-1-avarab@gmail.com","subject":"Re: [PATCH] diff-tree doc: correct & remove wrong documentation","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2019-02-04T21:10:46Z","receivedAt":"2019-02-04T21:10:51Z","isPatch":true,"sender":{"key":"gitster@pobox.com","avatar":"https://avatars.githubusercontent.com/u/54884?v=4"},"body":"Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n\n>  <path>...::\n>  \tIf provided, the results are limited to a subset of files\n> -\tmatching one of these prefix strings.\n> -\ti.e., file matches `/^<pattern1>|<pattern2>|.../`\n> -\tNote that this parameter does not provide any wildcard or regexp\n> -\tfeatures.\n> +\tmatching one of the provided pathspecs.\n\nCorrect.\n\n> -\n> -\n> -LIMITING OUTPUT\n> ----------------\n> -If you're only interested in differences in a subset of files, for\n> -example some architecture-specific files, you might do:\n> -\n> -\tgit diff-tree -r <tree-ish> <tree-ish> arch/ia64 include/asm-ia64\n> -\n> -and it will only show you what changed in those two directories.\n> -\n> -Or if you are searching for what changed in just `kernel/sched.c`, just do\n> -\n> -\tgit diff-tree -r <tree-ish> <tree-ish> kernel/sched.c\n> -\n> -and it will ignore all differences to other files.\n\nAll of the above give still useful piece of information to the\nreaders.  I do not think it is a good idea to assume familiarilty\nwith pathspec limiting to all readers---a new reader must start\nsomewhere and diff-tree may just be a random place s/he started at.\n\nSo I do not think it is a good idea to drop this example or the\nsection from the page.\n\n> -The pattern is always the prefix, and is matched exactly.  There are no\n> -wildcards.  Even stricter, it has to match a complete path component.\n> -I.e. \"foo\" does not pick up `foobar.h`.  \"foo\" does match `foo/bar.h`\n> -so it can be used to name subdirectories.\n\nI agree with the patch that this paragraph should go.\n\n> -An example of normal usage is:\n> -\n> -  torvalds@ppc970:~/git> git diff-tree --abbrev 5319e4\n> -  :100664 100664 ac348b... a01513...\tgit-fsck-objects.c\n\nInteresting.  This does not work (and I do not think it has ever\nworked) for a tree object 5319e4, but it works as advertised for a\ncommit object.\n\nThe description section has this near the top\n\n       If there is only one <tree-ish> given, the commit is compared\n       with its parents (see --stdin below).\n              \nI think s/given,/& it must be a commit-ish and/ would be appropriate\nthere; please include such a fix in a reroll.\n\nI agree with this patch that it is a good idea to drop this example;\nit is more appropriate to use \"git show\" on the commit-ish in the\ncase of the given example anyway.\n\n> -\n> -which tells you that the last commit changed just one file (it's from\n> -this one:\n> -\n> ------------------------------------------------------------------------------\n> -commit 3c6f7ca19ad4043e9e72fa94106f352897e651a8\n> -tree 5319e4d609cdd282069cc4dce33c1db559539b03\n> -parent b4e628ea30d5ab3606119d2ea5caeab141d38df7\n> -author Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n> -committer Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n> -\n> -Make \"git-fsck-objects\" print out all the root commits it finds.\n> -\n> -Once I do the reference tracking, I'll also make it print out all the\n> -HEAD commits it finds, which is even more interesting.\n> ------------------------------------------------------------------------------\n> -\n> -in case you care).\n> -\n"},{"id":"368493","messageId":"87sgx3kyvm.fsf@evledraar.gmail.com","threadId":"26076","inReplyTo":"xmqqpns7tg2x.fsf@gitster-ct.c.googlers.com","subject":"Re: [PATCH] diff-tree doc: correct & remove wrong documentation","fromName":"Ævar Arnfjörð Bjarmason","fromEmail":"avarab@gmail.com","sentAt":"2019-02-04T21:49:33Z","receivedAt":"2019-02-04T21:49:40Z","isPatch":true,"sender":{"key":"avarab@gmail.com","avatar":"https://avatars.githubusercontent.com/u/45301?v=4"},"body":"\nOn Mon, Feb 04 2019, Junio C Hamano wrote:\n\n> Ævar Arnfjörð Bjarmason  <avarab@gmail.com> writes:\n>\n>>  <path>...::\n>>  \tIf provided, the results are limited to a subset of files\n>> -\tmatching one of these prefix strings.\n>> -\ti.e., file matches `/^<pattern1>|<pattern2>|.../`\n>> -\tNote that this parameter does not provide any wildcard or regexp\n>> -\tfeatures.\n>> +\tmatching one of the provided pathspecs.\n>\n> Correct.\n>\n>> -\n>> -\n>> -LIMITING OUTPUT\n>> ----------------\n>> -If you're only interested in differences in a subset of files, for\n>> -example some architecture-specific files, you might do:\n>> -\n>> -\tgit diff-tree -r <tree-ish> <tree-ish> arch/ia64 include/asm-ia64\n>> -\n>> -and it will only show you what changed in those two directories.\n>> -\n>> -Or if you are searching for what changed in just `kernel/sched.c`, just do\n>> -\n>> -\tgit diff-tree -r <tree-ish> <tree-ish> kernel/sched.c\n>> -\n>> -and it will ignore all differences to other files.\n>\n> All of the above give still useful piece of information to the\n> readers.  I do not think it is a good idea to assume familiarilty\n> with pathspec limiting to all readers---a new reader must start\n> somewhere and diff-tree may just be a random place s/he started at.\n>\n> So I do not think it is a good idea to drop this example or the\n> section from the page.\n\nI was aiming for something like what e.g. \"git-ls-files\" says, which is\njust:\n\n    Files to show. If no files are given all files which match the other\n    specified criteria are shown.\n\nBut yes, having an example is good, but with this removed isn't the\nexample we show in \"RAW OUTPUT FORMAT\" now just below sufficient to show\nwhat this remove section was trying (and failing) to do, i.e.:\n\n    git-diff-tree [-r] <tree-ish-1> <tree-ish-2> [<pattern>...]\n        compares the trees named by the two arguments.\n\nThat doesn't have --abbrev, but I think it's enough to leave that\ndiscussed in \"OPTIONS\" above.\n\n>> -The pattern is always the prefix, and is matched exactly.  There are no\n>> -wildcards.  Even stricter, it has to match a complete path component.\n>> -I.e. \"foo\" does not pick up `foobar.h`.  \"foo\" does match `foo/bar.h`\n>> -so it can be used to name subdirectories.\n>\n> I agree with the patch that this paragraph should go.\n>\n>> -An example of normal usage is:\n>> -\n>> -  torvalds@ppc970:~/git> git diff-tree --abbrev 5319e4\n>> -  :100664 100664 ac348b... a01513...\tgit-fsck-objects.c\n>\n> Interesting.  This does not work (and I do not think it has ever\n> worked) for a tree object 5319e4, but it works as advertised for a\n> commit object.\n>\n> The description section has this near the top\n>\n>        If there is only one <tree-ish> given, the commit is compared\n>        with its parents (see --stdin below).\n>\n> I think s/given,/& it must be a commit-ish and/ would be appropriate\n> there; please include such a fix in a reroll.\n>\n> I agree with this patch that it is a good idea to drop this example;\n> it is more appropriate to use \"git show\" on the commit-ish in the\n> case of the given example anyway.\n>\n>> -\n>> -which tells you that the last commit changed just one file (it's from\n>> -this one:\n>> -\n>> ------------------------------------------------------------------------------\n>> -commit 3c6f7ca19ad4043e9e72fa94106f352897e651a8\n>> -tree 5319e4d609cdd282069cc4dce33c1db559539b03\n>> -parent b4e628ea30d5ab3606119d2ea5caeab141d38df7\n>> -author Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n>> -committer Linus Torvalds <torvalds@ppc970.osdl.org> Sat Apr 9 12:02:30 2005\n>> -\n>> -Make \"git-fsck-objects\" print out all the root commits it finds.\n>> -\n>> -Once I do the reference tracking, I'll also make it print out all the\n>> -HEAD commits it finds, which is even more interesting.\n>> ------------------------------------------------------------------------------\n>> -\n>> -in case you care).\n>> -\n"}]}