{"thread":{"id":"25157","subject":"[PATCH 0/5] Globbing support in diff family","startedAt":"2010-09-19T23:29:55Z","lastAt":"2010-09-28T05:28:25Z","messageCount":9,"participants":["Nguyễn Thái Ngọc Duy","Junio C Hamano","Nguyen Thai Ngoc Duy"],"isPatch":true,"patchVersion":1,"patchTotal":5},"messages":[{"id":"151025","messageId":"1284939000-16907-1-git-send-email-pclouds@gmail.com","threadId":"25157","inReplyTo":null,"subject":"[PATCH 0/5] Globbing support in diff family","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-19T23:29:55Z","receivedAt":"2010-09-19T23:29:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"This is on top of the pathspec struct series\n\nhttp://mid.gmane.org/1284938514-16663-1-git-send-email-pclouds@gmail.com\n\nOne question to document experts: where to document \"pathspec\", git.txt?\n\nNguyễn Thái Ngọc Duy (5):\n  pathspec: mark wildcard pathspecs from the beginning\n  pathspec: add tree_recursive_diff parameter\n  tree_entry_interesting: turn to match_pathspec if wildcard is present\n  Convert ce_path_match() to use struct pathspec\n  ce_path_match: drop prefix matching in favor of match_pathspec\n\n builtin/update-index.c   |    8 ++++++--\n cache.h                  |    5 ++++-\n diff-lib.c               |   10 ++++++++--\n dir.c                    |    7 ++++++-\n preload-index.c          |    5 ++++-\n read-cache.c             |   25 ++-----------------------\n revision.c               |    5 ++++-\n t/t4010-diff-pathspec.sh |   23 +++++++++++++++++++++++\n tree-diff.c              |    1 +\n tree-walk.c              |   18 ++++++++++++++++++\n wt-status.c              |    5 ++++-\n 11 files changed, 80 insertions(+), 32 deletions(-)\n"},{"id":"151026","messageId":"1284939000-16907-2-git-send-email-pclouds@gmail.com","threadId":"25157","inReplyTo":"1284939000-16907-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 1/5] pathspec: mark wildcard pathspecs from the beginning","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-19T23:29:56Z","receivedAt":"2010-09-19T23:29:56Z","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 match_pathspec() should be converted to use this as well. Not now\n though.\n\n cache.h |    2 ++\n dir.c   |    7 ++++++-\n 2 files changed, 8 insertions(+), 1 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 045c9fc..7a3e0a0 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -495,8 +495,10 @@ extern int ie_modified(const struct index_state *, struct cache_entry *, struct\n struct pathspec {\n \tconst char **raw;\n \tint nr;\n+\tint has_wildcard:1;\n \tstruct pathspec_item {\n \t\tint len;\n+\t\tint has_wildcard:1;\n \t} *items;\n };\n \ndiff --git a/dir.c b/dir.c\nindex 80b2df2..a44c7b3 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -1088,7 +1088,12 @@ int init_pathspec(struct pathspec *pathspec, const char **paths)\n \n \tpathspec->items = xmalloc(sizeof(struct pathspec_item)*pathspec->nr);\n \tfor (i = 0; i < pathspec->nr; i++) {\n-\t\tpathspec->items[i].len = strlen(paths[i]);\n+\t\tstruct pathspec_item *item = pathspec->items+i;\n+\n+\t\titem->len = strlen(paths[i]);\n+\t\titem->has_wildcard = !no_wildcard(paths[i]);\n+\t\tif (item->has_wildcard)\n+\t\t\tpathspec->has_wildcard = 1;\n \t}\n \treturn 0;\n }\n-- \n1.7.1.rc1.70.g788ca\n"},{"id":"151029","messageId":"1284939000-16907-3-git-send-email-pclouds@gmail.com","threadId":"25157","inReplyTo":"1284939000-16907-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 2/5] pathspec: add tree_recursive_diff parameter","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-19T23:29:57Z","receivedAt":"2010-09-19T23:29:57Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"When wildcard match is implemented, a full path is needed to do final\nmatch. What type of diff_tree is performed determines how to treat\ndirectories:\n\n - If it's recursive diff, directories are just an intermediate step.\n   All path must end with a file name. Thus, directories will be\n   unconditionally matched.\n\n - If it's non-recursive, directories are treated like files and is\n   matched against pathspect as full path.\n\nStrictly speaking, this should be a new parameter to\ntree_entry_interesting(). But I don't feel like chaning\ntree_entry_interesting() too often.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n cache.h     |    1 +\n tree-diff.c |    1 +\n 2 files changed, 2 insertions(+), 0 deletions(-)\n\ndiff --git a/cache.h b/cache.h\nindex 7a3e0a0..dc54d16 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -496,6 +496,7 @@ struct pathspec {\n \tconst char **raw;\n \tint nr;\n \tint has_wildcard:1;\n+\tint tree_recursive_diff:1;\n \tstruct pathspec_item {\n \t\tint len;\n \t\tint has_wildcard:1;\ndiff --git a/tree-diff.c b/tree-diff.c\nindex 50d7e6d..7e58f54 100644\n--- a/tree-diff.c\n+++ b/tree-diff.c\n@@ -170,6 +170,7 @@ int diff_tree(struct tree_desc *t1, struct tree_desc *t2, const char *base, stru\n {\n \tint baselen = strlen(base);\n \n+\topt->pathspec.tree_recursive_diff = DIFF_OPT_TST(opt, RECURSIVE);\n \tfor (;;) {\n \t\tif (DIFF_OPT_TST(opt, QUICK) &&\n \t\t    DIFF_OPT_TST(opt, HAS_CHANGES))\n-- \n1.7.1.rc1.70.g788ca\n"},{"id":"151027","messageId":"1284939000-16907-4-git-send-email-pclouds@gmail.com","threadId":"25157","inReplyTo":"1284939000-16907-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 3/5] tree_entry_interesting: turn to match_pathspec if wildcard is present","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-19T23:29:58Z","receivedAt":"2010-09-19T23:29:58Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"A pathspec with wildcard usually requires full path to do\nmatching. When full path is found, match_pathspec() can do the job\npretty well (actually it can utilize pathspec_item.has_wildcard, but\nthat's another matter).\n\nSo if tree_entry_interesting() finds that there is wildcard in any\npathspec, it just skips all of its optimizations, tries to make full\npath and pass to match_pathspec().\n\nThe implementation is pretty naive. Maybe with some pattern analysis,\nwe can do some early tree cutting.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n t/t4010-diff-pathspec.sh |   14 ++++++++++++++\n tree-walk.c              |   18 ++++++++++++++++++\n 2 files changed, 32 insertions(+), 0 deletions(-)\n\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 01168ea..bc8c9bd 100644\n--- a/tree-walk.c\n+++ b/tree-walk.c\n@@ -2,6 +2,7 @@\n #include \"tree-walk.h\"\n #include \"unpack-trees.h\"\n #include \"tree.h\"\n+#include \"dir.h\"\n \n static const char *get_mode(const char *str, unsigned int *modep)\n {\n@@ -478,6 +479,23 @@ int tree_entry_interesting(const struct name_entry *entry,\n \n \tpathlen = tree_entry_len(entry->path, entry->sha1);\n \n+\tif (ps->has_wildcard) {\n+\t\tstatic char full_path[PATH_MAX];\n+\n+\t\t/*\n+\t\t * If it's recursive diff, directories are\n+\t\t * intermediate step before ending up to a file.\n+\t\t * Let it pass and we can match the files within\n+\t\t * later.\n+\t\t */\n+\t\tif (ps->tree_recursive_diff && S_ISDIR(entry->mode))\n+\t\t\treturn 1;\n+\n+\t\tmemcpy(full_path, base, baselen);\n+\t\tmemcpy(full_path+baselen, entry->path, pathlen+1);\n+\t\treturn match_pathspec(ps->raw, full_path, baselen+pathlen, 0, NULL) > 0;\n+\t}\n+\n \tfor (i = 0; i < ps->nr; i++) {\n \t\tconst char *match = ps->raw[i];\n \t\tint matchlen = ps->items[i].len;\n-- \n1.7.1.rc1.70.g788ca\n"},{"id":"151028","messageId":"1284939000-16907-5-git-send-email-pclouds@gmail.com","threadId":"25157","inReplyTo":"1284939000-16907-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 4/5] Convert ce_path_match() to use struct pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-19T23:29:59Z","receivedAt":"2010-09-19T23:29:59Z","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/update-index.c |    8 ++++++--\n cache.h                |    2 +-\n diff-lib.c             |   10 ++++++++--\n preload-index.c        |    5 ++++-\n read-cache.c           |    8 +++++---\n revision.c             |    5 ++++-\n wt-status.c            |    5 ++++-\n 7 files changed, 32 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 dc54d16..bf50603 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -505,7 +505,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..918a90c 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -683,17 +683,19 @@ 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 **p;\n \tint len;\n \n-\tif (!pathspec)\n+\tif (!pathspec || !pathspec->nr)\n \t\treturn 1;\n \n \tlen = ce_namelen(ce);\n \tname = ce->name;\n-\twhile ((match = *pathspec++) != NULL) {\n+\tp = pathspec->raw;\n+\twhile ((match = *p++) != 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.1.rc1.70.g788ca\n"},{"id":"151030","messageId":"1284939000-16907-6-git-send-email-pclouds@gmail.com","threadId":"25157","inReplyTo":"1284939000-16907-1-git-send-email-pclouds@gmail.com","subject":"[PATCH 5/5] ce_path_match: drop prefix matching in favor of match_pathspec","fromName":"Nguyễn Thái Ngọc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-19T23:30:00Z","receivedAt":"2010-09-19T23:30:00Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"ce_path_match() and tree_entry_interesting() are two functions that do\nentry filtering when traversing trees. Now that\ntree_entry_interesting() understands wildcard, ce_path_match() can\njust use match_pathspec() to also understand wildcard.\n\nSigned-off-by: Nguyễn Thái Ngọc Duy <pclouds@gmail.com>\n---\n read-cache.c             |   25 +------------------------\n t/t4010-diff-pathspec.sh |    9 +++++++++\n 2 files changed, 10 insertions(+), 24 deletions(-)\n\ndiff --git a/read-cache.c b/read-cache.c\nindex 918a90c..c67d9e0 100644\n--- a/read-cache.c\n+++ b/read-cache.c\n@@ -685,30 +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 **p;\n-\tint len;\n-\n-\tif (!pathspec || !pathspec->nr)\n-\t\treturn 1;\n-\n-\tlen = ce_namelen(ce);\n-\tname = ce->name;\n-\tp = pathspec->raw;\n-\twhile ((match = *p++) != 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(pathspec->raw, ce->name, ce_namelen(ce), 0, NULL) > 0;\n }\n \n /*\ndiff --git a/t/t4010-diff-pathspec.sh b/t/t4010-diff-pathspec.sh\nindex 4b120f8..d50fd2d 100755\n--- a/t/t4010-diff-pathspec.sh\n+++ b/t/t4010-diff-pathspec.sh\n@@ -55,6 +55,15 @@ test_expect_success \\\n     'git diff-index --cached $tree -- file0 >current &&\n      compare_diff_raw current expected'\n \n+cat >expected.template <<\\EOF\n+:100644 100644 766498d93a4b06057a8e49d23f4068f1170ff38f 0a41e115ab61be0328a19b29f18cdcb49338d516 M\tpath1/file1\n+EOF\n+test_expect_success 'diff-index with wildcard' '\n+\tgit diff-index --cached $tree -- \"*1\" >current &&\n+\tcp expected.template expected &&\n+\tcompare_diff_raw current expected\n+'\n+\n cat >expected <<\\EOF\n EOF\n test_expect_success \\\n-- \n1.7.1.rc1.70.g788ca\n"},{"id":"151863","messageId":"7vocbivnfs.fsf@alter.siamese.dyndns.org","threadId":"25157","inReplyTo":"1284939000-16907-3-git-send-email-pclouds@gmail.com","subject":"Re: [PATCH 2/5] pathspec: add tree_recursive_diff parameter","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-09-27T22:20:07Z","receivedAt":"2010-09-27T22:20:07Z","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> When wildcard match is implemented, a full path is needed to do final\n> match. What type of diff_tree is performed determines how to treat\n> directories:\n>\n>  - If it's recursive diff, directories are just an intermediate step.\n>    All path must end with a file name. Thus, directories will be\n>    unconditionally matched.\n\nHmm, I am not sure what you mean by this.  If the pathspec says a/b*/c,\nyou are in \"a\" and are deciding if you should descend to its subdirectory,\nthen you would surely want to be able to say:\n\n (1) Ah, the subdirectory I am looking at is \"bar\" and it does match \"b*\".\n     It might contain \"c\"; I should descend into it.\n\n (2) Nope, the subdirectory I am looking at is \"frotz\" and it can never\n     match \"b*\", so there is no point recursing into it.\n"},{"id":"151873","messageId":"AANLkTinZt8kish9L2F-ad_boXByZTUj-BnYTp-vtePk0@mail.gmail.com","threadId":"25157","inReplyTo":"7vocbivnfs.fsf@alter.siamese.dyndns.org","subject":"Re: [PATCH 2/5] pathspec: add tree_recursive_diff parameter","fromName":"Nguyen Thai Ngoc Duy","fromEmail":"pclouds@gmail.com","sentAt":"2010-09-28T02:38:55Z","receivedAt":"2010-09-28T02:38:55Z","isPatch":true,"sender":{"key":"pclouds@gmail.com","avatar":"https://avatars.githubusercontent.com/u/720?v=4"},"body":"2010/9/28 Junio C Hamano <gitster@pobox.com>:\n> Nguyễn Thái Ngọc Duy  <pclouds@gmail.com> writes:\n>\n>> When wildcard match is implemented, a full path is needed to do final\n>> match. What type of diff_tree is performed determines how to treat\n>> directories:\n>>\n>>  - If it's recursive diff, directories are just an intermediate step.\n>>    All path must end with a file name. Thus, directories will be\n>>    unconditionally matched.\n>\n> Hmm, I am not sure what you mean by this.  If the pathspec says a/b*/c,\n> you are in \"a\" and are deciding if you should descend to its subdirectory,\n> then you would surely want to be able to say:\n>\n>  (1) Ah, the subdirectory I am looking at is \"bar\" and it does match \"b*\".\n>     It might contain \"c\"; I should descend into it.\n>\n>  (2) Nope, the subdirectory I am looking at is \"frotz\" and it can never\n>     match \"b*\", so there is no point recursing into it.\n>\n\nI did not go that far, trying to analyse the pattern. When I wrote\n\"immediate step\" I was thinking of \"*foo\" pattern, which effectively\nmeans descending to any reachable directories because '*' matches\nslashes too. I think that's the worst case.\n\nAnyway I did not know that I could borrow some optimizations from\npathspec_matches() in builtin/grep.c.\n-- \nDuy\n"},{"id":"151876","messageId":"7vk4m6v3ly.fsf@alter.siamese.dyndns.org","threadId":"25157","inReplyTo":"AANLkTinZt8kish9L2F-ad_boXByZTUj-BnYTp-vtePk0@mail.gmail.com","subject":"Re: [PATCH 2/5] pathspec: add tree_recursive_diff parameter","fromName":"Junio C Hamano","fromEmail":"gitster@pobox.com","sentAt":"2010-09-28T05:28:25Z","receivedAt":"2010-09-28T05:28:25Z","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/9/28 Junio C Hamano <gitster@pobox.com>:\n>> Nguyễn Thái Ngọc Duy <pclouds@gmail.com> writes:\n>> ...\n>>>  - If it's recursive diff, directories are just an intermediate step.\n>>>    All path must end with a file name. Thus, directories will be\n>>>    unconditionally matched.\n>>\n>> Hmm, I am not sure what you mean by this.  If the pathspec says a/b*/c,\n>> you are in \"a\" and are deciding if you should descend to its subdirectory,\n>> then you would surely want to be able to say:\n>>\n>>  (1) Ah, the subdirectory I am looking at is \"bar\" and it does match \"b*\".\n>>      It might contain \"c\"; I should descend into it.\n>>\n>>  (2) Nope, the subdirectory I am looking at is \"frotz\" and it can never\n>>      match \"b*\", so there is no point recursing into it.\n>\n> I did not go that far, trying to analyse the pattern. When I wrote\n> \"immediate step\" I was thinking of \"*foo\" pattern, which effectively\n> means descending to any reachable directories because '*' matches\n> slashes too. I think that's the worst case.\n>\n> Anyway I did not know that I could borrow some optimizations from\n> pathspec_matches() in builtin/grep.c.\n\nAs you noticed, over time we have polished our re-implementations of the\npathspec logic to avoid needlessly descending into subdirectories, and the\none in the grep may be the latest incarnation of it.  The logic that uses\nthe path_simplify structure in dir.c may also offer you some inspirations.\n\nNote that the worst case will fall out as a natural consequence of doing\nthe fallback in the dumb and simple way, so you do not have to worry too\nmuch about it ;-)  I would prefer to see the new, consolidated logic to at\nleast know the easy optimizations we already have.\n\nThanks.\n"}]}