{"thread":{"id":"29460","subject":"[PATCH/RFC] grep: Add the option '--exclude'","startedAt":"2012-01-28T02:06:10Z","lastAt":"2012-01-28T02:40:55Z","messageCount":2,"participants":["Albert Yale"],"isPatch":true,"patchVersion":1,"patchTotal":null},"messages":[{"id":"183213","messageId":"1327716370-40705-1-git-send-email-surfingalbert@gmail.com","threadId":"29460","inReplyTo":null,"subject":"[PATCH/RFC] grep: Add the option '--exclude'","fromName":"Albert Yale","fromEmail":"surfingalbert@gmail.com","sentAt":"2012-01-28T02:06:10Z","receivedAt":"2012-01-28T02:06:10Z","isPatch":true,"sender":{"key":"surfingalbert@gmail.com","avatar":null},"body":"grep: Add the option '--exclude'\n\nSigned-off-by: Albert Yale <surfingalbert@gmail.com>\n---\nThis is a work-in-progress. It's functional,\nbut it hasn't been thoroughly tested.\n\nI'd like some feedback. Particularly for\ninit_pathspec_string_list() in dir.c.\n\nThank you,\n\nAlbert Yale\n\n Documentation/git-grep.txt |    7 ++++++\n builtin/grep.c             |   50 ++++++++++++++++++++++++++++++++++++-------\n cache.h                    |    1 +\n dir.c                      |   32 ++++++++++++++++++++++++++++\n 4 files changed, 82 insertions(+), 8 deletions(-)\n\ndiff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\nindex 6a8b1e3..8cbb161 100644\n--- a/Documentation/git-grep.txt\n+++ b/Documentation/git-grep.txt\n@@ -22,6 +22,7 @@ SYNOPSIS\n \t   [--color[=<when>] | --no-color]\n \t   [-A <post-context>] [-B <pre-context>] [-C <context>]\n \t   [-f <file>] [-e] <pattern>\n+\t   [-x <pattern>|--exclude=<pattern>]\n \t   [--and|--or|--not|(|)|-e <pattern>...]\n \t   [ [--exclude-standard] [--cached | --no-index | --untracked] | <tree>...]\n \t   [--] [<pathspec>...]\n@@ -124,6 +125,12 @@ OPTIONS\n \tUse fixed strings for patterns (don't interpret pattern\n \tas a regex).\n \n+-x <pattern>::\n+--exclude=<pattern>::\n+\tIn addition to those found in .gitignore (per directory) and\n+\t$GIT_DIR/info/exclude, also consider these patterns to be in the\n+\tset of the ignore rules in effect.\n+\n -n::\n --line-number::\n \tPrefix the line number to matching lines.\ndiff --git a/builtin/grep.c b/builtin/grep.c\nindex 9ce064a..106810f 100644\n--- a/builtin/grep.c\n+++ b/builtin/grep.c\n@@ -518,7 +518,8 @@ 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 struct pathspec *pathspec, int cached)\n+static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,\n+\t\t\t  int cached, const struct pathspec *exclude_pathspec)\n {\n \tint hit = 0;\n \tint nr;\n@@ -530,6 +531,9 @@ static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int\n \t\t\tcontinue;\n \t\tif (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))\n \t\t\tcontinue;\n+\t\tif (exclude_pathspec->nr &&\n+\t\t\tmatch_pathspec_depth(exclude_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 \t\t * are identical, even if worktree file has been modified, so use\n@@ -639,16 +643,23 @@ static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,\n }\n \n static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,\n-\t\t\tconst struct object_array *list)\n+\t\t\tconst struct object_array *list, const struct pathspec *exclude_pathspec)\n {\n \tunsigned int i;\n \tint hit = 0;\n \tconst unsigned int nr = list->nr;\n \n \tfor (i = 0; i < nr; i++) {\n+\t\tconst char *name = list->objects[i].name;\n+\t\tint namelen = strlen(name);\n \t\tstruct object *real_obj;\n \t\treal_obj = deref_tag(list->objects[i].item, NULL, 0);\n-\t\tif (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {\n+\n+\t\tif (exclude_pathspec->nr &&\n+\t\t\tmatch_pathspec_depth(exclude_pathspec, name, namelen, 0, NULL))\n+\t\t\tcontinue;\n+\n+\t\tif (grep_object(opt, pathspec, real_obj, name)) {\n \t\t\thit = 1;\n \t\t\tif (opt->status_only)\n \t\t\t\tbreak;\n@@ -658,7 +669,7 @@ static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,\n }\n \n static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,\n-\t\t\t  int exc_std)\n+\t\t\t  int exc_std, struct string_list *exclude_list)\n {\n \tstruct dir_struct dir;\n \tint i, hit = 0;\n@@ -667,6 +678,10 @@ static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec,\n \tif (exc_std)\n \t\tsetup_standard_excludes(&dir);\n \n+\tfor (i = 0; i < exclude_list->nr; i++)\n+\t\tadd_exclude(exclude_list->items[i].string, \"\", 0,\n+\t\t\t    &dir.exclude_list[EXC_CMDL]);\n+\n \tfill_directory(&dir, pathspec->raw);\n \tfor (i = 0; i < dir.nr; i++) {\n \t\tconst char *name = dir.entries[i]->name;\n@@ -764,6 +779,14 @@ static int pattern_callback(const struct option *opt, const char *arg,\n \treturn 0;\n }\n \n+static int exclude_cb(const struct option *opt, const char *arg,\n+\t\t\t    int unset)\n+{\n+\tstruct string_list *exclude_list = opt->value;\n+\tstring_list_append(exclude_list, arg);\n+\treturn 0;\n+}\n+\n static int help_callback(const struct option *opt, const char *arg, int unset)\n {\n \treturn -1;\n@@ -780,6 +803,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tstruct object_array list = OBJECT_ARRAY_INIT;\n \tconst char **paths = NULL;\n \tstruct pathspec pathspec;\n+\tstruct pathspec exclude_pathspec;\n \tstruct string_list path_list = STRING_LIST_INIT_NODUP;\n \tint i;\n \tint dummy;\n@@ -792,7 +816,7 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\tpattern_type_pcre,\n \t};\n \tint pattern_type = pattern_type_unspecified;\n-\n+\tstruct string_list exclude_list = STRING_LIST_INIT_NODUP;\n \tstruct option options[] = {\n \t\tOPT_BOOLEAN(0, \"cached\", &cached,\n \t\t\t\"search in index instead of in the work tree\"),\n@@ -872,6 +896,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\t\t\"read patterns from file\", file_callback),\n \t\t{ OPTION_CALLBACK, 'e', NULL, &opt, \"pattern\",\n \t\t\t\"match <pattern>\", PARSE_OPT_NONEG, pattern_callback },\n+\t\t{ OPTION_CALLBACK, 'x', \"exclude\", &exclude_list, \"pattern\",\n+\t\t  \"add <pattern> to ignore rules\", PARSE_OPT_NONEG, exclude_cb },\n \t\t{ OPTION_CALLBACK, 0, \"and\", &opt, NULL,\n \t\t  \"combine patterns specified with -e\",\n \t\t  PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },\n@@ -1053,6 +1079,10 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tpathspec.max_depth = opt.max_depth;\n \tpathspec.recursive = 1;\n \n+\tinit_pathspec_string_list(&exclude_pathspec, &exclude_list);\n+\texclude_pathspec.max_depth = opt.max_depth;\n+\texclude_pathspec.recursive = 1;\n+\n \tif (show_in_pager && (cached || list.nr))\n \t\tdie(_(\"--open-files-in-pager only works on the worktree\"));\n \n@@ -1083,18 +1113,19 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \t\tint use_exclude = (opt_exclude < 0) ? use_index : !!opt_exclude;\n \t\tif (list.nr)\n \t\t\tdie(_(\"--no-index or --untracked cannot be used with revs.\"));\n-\t\thit = grep_directory(&opt, &pathspec, use_exclude);\n+\t\thit = grep_directory(&opt, &pathspec, use_exclude, &exclude_list);\n \t} else if (0 <= opt_exclude) {\n \t\tdie(_(\"--[no-]exclude-standard cannot be used for tracked contents.\"));\n \t} else if (!list.nr) {\n \t\tif (!cached)\n \t\t\tsetup_work_tree();\n \n-\t\thit = grep_cache(&opt, &pathspec, cached);\n+\t\thit = grep_cache(&opt, &pathspec, cached, &exclude_pathspec);\n \t} else {\n \t\tif (cached)\n \t\t\tdie(_(\"both --cached and trees are given.\"));\n-\t\thit = grep_objects(&opt, &pathspec, &list);\n+\n+\t\thit = grep_objects(&opt, &pathspec, &list, &exclude_pathspec);\n \t}\n \n \tif (use_threads)\n@@ -1102,5 +1133,8 @@ int cmd_grep(int argc, const char **argv, const char *prefix)\n \tif (hit && show_in_pager)\n \t\trun_pager(&opt, prefix);\n \tfree_grep_patterns(&opt);\n+\tfree_pathspec(&pathspec);\n+\tfree_pathspec(&exclude_pathspec);\n+\tstring_list_clear(&exclude_list, 0);\n \treturn !hit;\n }\ndiff --git a/cache.h b/cache.h\nindex 10afd71..5c34ccb 100644\n--- a/cache.h\n+++ b/cache.h\n@@ -536,6 +536,7 @@ struct pathspec {\n };\n \n extern int init_pathspec(struct pathspec *, const char **);\n+extern int init_pathspec_string_list(struct pathspec *, struct string_list *);\n extern void free_pathspec(struct pathspec *);\n extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);\n \ndiff --git a/dir.c b/dir.c\nindex 0a78d00..65749cc 100644\n--- a/dir.c\n+++ b/dir.c\n@@ -9,6 +9,8 @@\n #include \"dir.h\"\n #include \"refs.h\"\n \n+#include \"string-list.h\"\n+\n struct path_simplify {\n \tint len;\n \tconst char *path;\n@@ -1259,6 +1261,36 @@ static int pathspec_item_cmp(const void *a_, const void *b_)\n \treturn strcmp(a->match, b->match);\n }\n \n+int init_pathspec_string_list(struct pathspec *pathspec, struct string_list *path_list)\n+{\n+\tint i;\n+\n+\tmemset(pathspec, 0, sizeof(*pathspec));\n+\tif (!path_list)\n+\t\treturn 0;\n+\tpathspec->raw = 0; /* THIS IS PROBABLY BAD!!! */\n+\tpathspec->nr = path_list->nr;\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 = path_list->items[i].string;\n+\n+\t\titem->match = path;\n+\t\titem->len = strlen(path);\n+\t\titem->use_wildcard = !no_wildcard(path);\n+\t\tif (item->use_wildcard)\n+\t\t\tpathspec->has_wildcard = 1;\n+\t}\n+\n+\tqsort(pathspec->items, pathspec->nr,\n+\t      sizeof(struct pathspec_item), pathspec_item_cmp);\n+\n+\treturn 0;\n+}\n+\n int init_pathspec(struct pathspec *pathspec, const char **paths)\n {\n \tconst char **p = paths;\n-- \n1.7.8.3\n"},{"id":"183214","messageId":"CALEc4zGCrW1WLm9NC5N7Dsdk9qdVBOO3h2mkFwh+v-a=RM57yA@mail.gmail.com","threadId":"29460","inReplyTo":"CAPc5daW+pcO-HLoo9THLgt4Ow2BHZ-fWgXL=zPgyunvt1mf9ZQ@mail.gmail.com","subject":"Re: [PATCH/RFC] grep: Add the option '--exclude'","fromName":"Albert Yale","fromEmail":"surfingalbert@gmail.com","sentAt":"2012-01-28T02:40:55Z","receivedAt":"2012-01-28T02:40:55Z","isPatch":true,"sender":{"key":"surfingalbert@gmail.com","avatar":null},"body":"I think you're correct. That would be a better way to implement this.\n\nI'll look into it this weekend.\n\nAlbert Yale\n\nOn Fri, Jan 27, 2012 at 9:19 PM, Junio C Hamano <gitster@pobox.com> wrote:\n> I'd prefer to see this done not by introducing a separate pathspec, but\n> instead by adding exclusion-related fields to struct pathspec. That way, the\n> existing callsites to  match_pathspec() do not have to change, and only the\n> program start-up needs to learn to stuff these negative pathspecs, no?\n>\n> On Jan 27, 2012 6:06 PM, \"Albert Yale\" <surfingalbert@gmail.com> wrote:\n>>\n>> grep: Add the option '--exclude'\n>>\n>> Signed-off-by: Albert Yale <surfingalbert@gmail.com>\n>> ---\n>> This is a work-in-progress. It's functional,\n>> but it hasn't been thoroughly tested.\n>>\n>> I'd like some feedback. Particularly for\n>> init_pathspec_string_list() in dir.c.\n>>\n>> Thank you,\n>>\n>> Albert Yale\n>>\n>>  Documentation/git-grep.txt |    7 ++++++\n>>  builtin/grep.c             |   50\n>> ++++++++++++++++++++++++++++++++++++-------\n>>  cache.h                    |    1 +\n>>  dir.c                      |   32 ++++++++++++++++++++++++++++\n>>  4 files changed, 82 insertions(+), 8 deletions(-)\n>>\n>> diff --git a/Documentation/git-grep.txt b/Documentation/git-grep.txt\n>> index 6a8b1e3..8cbb161 100644\n>> --- a/Documentation/git-grep.txt\n>> +++ b/Documentation/git-grep.txt\n>> @@ -22,6 +22,7 @@ SYNOPSIS\n>>           [--color[=<when>] | --no-color]\n>>           [-A <post-context>] [-B <pre-context>] [-C <context>]\n>>           [-f <file>] [-e] <pattern>\n>> +          [-x <pattern>|--exclude=<pattern>]\n>>           [--and|--or|--not|(|)|-e <pattern>...]\n>>           [ [--exclude-standard] [--cached | --no-index | --untracked] |\n>> <tree>...]\n>>           [--] [<pathspec>...]\n>> @@ -124,6 +125,12 @@ OPTIONS\n>>        Use fixed strings for patterns (don't interpret pattern\n>>        as a regex).\n>>\n>> +-x <pattern>::\n>> +--exclude=<pattern>::\n>> +       In addition to those found in .gitignore (per directory) and\n>> +       $GIT_DIR/info/exclude, also consider these patterns to be in the\n>> +       set of the ignore rules in effect.\n>> +\n>>  -n::\n>>  --line-number::\n>>        Prefix the line number to matching lines.\n>> diff --git a/builtin/grep.c b/builtin/grep.c\n>> index 9ce064a..106810f 100644\n>> --- a/builtin/grep.c\n>> +++ b/builtin/grep.c\n>> @@ -518,7 +518,8 @@ static void run_pager(struct grep_opt *opt, const char\n>> *prefix)\n>>        free(argv);\n>>  }\n>>\n>> -static int grep_cache(struct grep_opt *opt, const struct pathspec\n>> *pathspec, int cached)\n>> +static int grep_cache(struct grep_opt *opt, const struct pathspec\n>> *pathspec,\n>> +                         int cached, const struct pathspec\n>> *exclude_pathspec)\n>>  {\n>>        int hit = 0;\n>>        int nr;\n>> @@ -530,6 +531,9 @@ static int grep_cache(struct grep_opt *opt, const\n>> struct pathspec *pathspec, int\n>>                        continue;\n>>                if (!match_pathspec_depth(pathspec, ce->name,\n>> ce_namelen(ce), 0, NULL))\n>>                        continue;\n>> +               if (exclude_pathspec->nr &&\n>> +                       match_pathspec_depth(exclude_pathspec, ce->name,\n>> ce_namelen(ce), 0, NULL))\n>> +                       continue;\n>>                /*\n>>                 * If CE_VALID is on, we assume worktree file and its cache\n>> entry\n>>                 * are identical, even if worktree file has been modified,\n>> so use\n>> @@ -639,16 +643,23 @@ static int grep_object(struct grep_opt *opt, const\n>> struct pathspec *pathspec,\n>>  }\n>>\n>>  static int grep_objects(struct grep_opt *opt, const struct pathspec\n>> *pathspec,\n>> -                       const struct object_array *list)\n>> +                       const struct object_array *list, const struct\n>> pathspec *exclude_pathspec)\n>>  {\n>>        unsigned int i;\n>>        int hit = 0;\n>>        const unsigned int nr = list->nr;\n>>\n>>        for (i = 0; i < nr; i++) {\n>> +               const char *name = list->objects[i].name;\n>> +               int namelen = strlen(name);\n>>                struct object *real_obj;\n>>                real_obj = deref_tag(list->objects[i].item, NULL, 0);\n>> -               if (grep_object(opt, pathspec, real_obj,\n>> list->objects[i].name)) {\n>> +\n>> +               if (exclude_pathspec->nr &&\n>> +                       match_pathspec_depth(exclude_pathspec, name,\n>> namelen, 0, NULL))\n>> +                       continue;\n>> +\n>> +               if (grep_object(opt, pathspec, real_obj, name)) {\n>>                        hit = 1;\n>>                        if (opt->status_only)\n>>                                break;\n>> @@ -658,7 +669,7 @@ static int grep_objects(struct grep_opt *opt, const\n>> struct pathspec *pathspec,\n>>  }\n>>\n>>  static int grep_directory(struct grep_opt *opt, const struct pathspec\n>> *pathspec,\n>> -                         int exc_std)\n>> +                         int exc_std, struct string_list *exclude_list)\n>>  {\n>>        struct dir_struct dir;\n>>        int i, hit = 0;\n>> @@ -667,6 +678,10 @@ static int grep_directory(struct grep_opt *opt, const\n>> struct pathspec *pathspec,\n>>        if (exc_std)\n>>                setup_standard_excludes(&dir);\n>>\n>> +       for (i = 0; i < exclude_list->nr; i++)\n>> +               add_exclude(exclude_list->items[i].string, \"\", 0,\n>> +                           &dir.exclude_list[EXC_CMDL]);\n>> +\n>>        fill_directory(&dir, pathspec->raw);\n>>        for (i = 0; i < dir.nr; i++) {\n>>                const char *name = dir.entries[i]->name;\n>> @@ -764,6 +779,14 @@ static int pattern_callback(const struct option *opt,\n>> const char *arg,\n>>        return 0;\n>>  }\n>>\n>> +static int exclude_cb(const struct option *opt, const char *arg,\n>> +                           int unset)\n>> +{\n>> +       struct string_list *exclude_list = opt->value;\n>> +       string_list_append(exclude_list, arg);\n>> +       return 0;\n>> +}\n>> +\n>>  static int help_callback(const struct option *opt, const char *arg, int\n>> unset)\n>>  {\n>>        return -1;\n>> @@ -780,6 +803,7 @@ int cmd_grep(int argc, const char **argv, const char\n>> *prefix)\n>>        struct object_array list = OBJECT_ARRAY_INIT;\n>>        const char **paths = NULL;\n>>        struct pathspec pathspec;\n>> +       struct pathspec exclude_pathspec;\n>>        struct string_list path_list = STRING_LIST_INIT_NODUP;\n>>        int i;\n>>        int dummy;\n>> @@ -792,7 +816,7 @@ int cmd_grep(int argc, const char **argv, const char\n>> *prefix)\n>>                pattern_type_pcre,\n>>        };\n>>        int pattern_type = pattern_type_unspecified;\n>> -\n>> +       struct string_list exclude_list = STRING_LIST_INIT_NODUP;\n>>        struct option options[] = {\n>>                OPT_BOOLEAN(0, \"cached\", &cached,\n>>                        \"search in index instead of in the work tree\"),\n>> @@ -872,6 +896,8 @@ int cmd_grep(int argc, const char **argv, const char\n>> *prefix)\n>>                        \"read patterns from file\", file_callback),\n>>                { OPTION_CALLBACK, 'e', NULL, &opt, \"pattern\",\n>>                        \"match <pattern>\", PARSE_OPT_NONEG,\n>> pattern_callback },\n>> +               { OPTION_CALLBACK, 'x', \"exclude\", &exclude_list,\n>> \"pattern\",\n>> +                 \"add <pattern> to ignore rules\", PARSE_OPT_NONEG,\n>> exclude_cb },\n>>                { OPTION_CALLBACK, 0, \"and\", &opt, NULL,\n>>                  \"combine patterns specified with -e\",\n>>                  PARSE_OPT_NOARG | PARSE_OPT_NONEG, and_callback },\n>> @@ -1053,6 +1079,10 @@ int cmd_grep(int argc, const char **argv, const\n>> char *prefix)\n>>        pathspec.max_depth = opt.max_depth;\n>>        pathspec.recursive = 1;\n>>\n>> +       init_pathspec_string_list(&exclude_pathspec, &exclude_list);\n>> +       exclude_pathspec.max_depth = opt.max_depth;\n>> +       exclude_pathspec.recursive = 1;\n>> +\n>>        if (show_in_pager && (cached || list.nr))\n>>                die(_(\"--open-files-in-pager only works on the worktree\"));\n>>\n>> @@ -1083,18 +1113,19 @@ int cmd_grep(int argc, const char **argv, const\n>> char *prefix)\n>>                int use_exclude = (opt_exclude < 0) ? use_index :\n>> !!opt_exclude;\n>>                if (list.nr)\n>>                        die(_(\"--no-index or --untracked cannot be used\n>> with revs.\"));\n>> -               hit = grep_directory(&opt, &pathspec, use_exclude);\n>> +               hit = grep_directory(&opt, &pathspec, use_exclude,\n>> &exclude_list);\n>>        } else if (0 <= opt_exclude) {\n>>                die(_(\"--[no-]exclude-standard cannot be used for tracked\n>> contents.\"));\n>>        } else if (!list.nr) {\n>>                if (!cached)\n>>                        setup_work_tree();\n>>\n>> -               hit = grep_cache(&opt, &pathspec, cached);\n>> +               hit = grep_cache(&opt, &pathspec, cached,\n>> &exclude_pathspec);\n>>        } else {\n>>                if (cached)\n>>                        die(_(\"both --cached and trees are given.\"));\n>> -               hit = grep_objects(&opt, &pathspec, &list);\n>> +\n>> +               hit = grep_objects(&opt, &pathspec, &list,\n>> &exclude_pathspec);\n>>        }\n>>\n>>        if (use_threads)\n>> @@ -1102,5 +1133,8 @@ int cmd_grep(int argc, const char **argv, const char\n>> *prefix)\n>>        if (hit && show_in_pager)\n>>                run_pager(&opt, prefix);\n>>        free_grep_patterns(&opt);\n>> +       free_pathspec(&pathspec);\n>> +       free_pathspec(&exclude_pathspec);\n>> +       string_list_clear(&exclude_list, 0);\n>>        return !hit;\n>>  }\n>> diff --git a/cache.h b/cache.h\n>> index 10afd71..5c34ccb 100644\n>> --- a/cache.h\n>> +++ b/cache.h\n>> @@ -536,6 +536,7 @@ struct pathspec {\n>>  };\n>>\n>>  extern int init_pathspec(struct pathspec *, const char **);\n>> +extern int init_pathspec_string_list(struct pathspec *, struct\n>> string_list *);\n>>  extern void free_pathspec(struct pathspec *);\n>>  extern int ce_path_match(const struct cache_entry *ce, const struct\n>> pathspec *pathspec);\n>>\n>> diff --git a/dir.c b/dir.c\n>> index 0a78d00..65749cc 100644\n>> --- a/dir.c\n>> +++ b/dir.c\n>> @@ -9,6 +9,8 @@\n>>  #include \"dir.h\"\n>>  #include \"refs.h\"\n>>\n>> +#include \"string-list.h\"\n>> +\n>>  struct path_simplify {\n>>        int len;\n>>        const char *path;\n>> @@ -1259,6 +1261,36 @@ static int pathspec_item_cmp(const void *a_, const\n>> void *b_)\n>>        return strcmp(a->match, b->match);\n>>  }\n>>\n>> +int init_pathspec_string_list(struct pathspec *pathspec, struct\n>> string_list *path_list)\n>> +{\n>> +       int i;\n>> +\n>> +       memset(pathspec, 0, sizeof(*pathspec));\n>> +       if (!path_list)\n>> +               return 0;\n>> +       pathspec->raw = 0; /* THIS IS PROBABLY BAD!!! */\n>> +       pathspec->nr = path_list->nr;\n>> +       if (!pathspec->nr)\n>> +               return 0;\n>> +\n>> +       pathspec->items = xmalloc(sizeof(struct\n>> pathspec_item)*pathspec->nr);\n>> +       for (i = 0; i < pathspec->nr; i++) {\n>> +               struct pathspec_item *item = pathspec->items+i;\n>> +               const char *path = path_list->items[i].string;\n>> +\n>> +               item->match = path;\n>> +               item->len = strlen(path);\n>> +               item->use_wildcard = !no_wildcard(path);\n>> +               if (item->use_wildcard)\n>> +                       pathspec->has_wildcard = 1;\n>> +       }\n>> +\n>> +       qsort(pathspec->items, pathspec->nr,\n>> +             sizeof(struct pathspec_item), pathspec_item_cmp);\n>> +\n>> +       return 0;\n>> +}\n>> +\n>>  int init_pathspec(struct pathspec *pathspec, const char **paths)\n>>  {\n>>        const char **p = paths;\n>> --\n>> 1.7.8.3\n>>\n>> --\n>> To unsubscribe from this list: send the line \"unsubscribe git\" in\n>> the body of a message to majordomo@vger.kernel.org\n>> More majordomo info at  http://vger.kernel.org/majordomo-info.html\n"}]}