Merge branch 'maint'
authorJunio C Hamano <gitster@pobox.com>
Mon, 28 Mar 2011 21:17:17 +0000 (14:17 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 28 Mar 2011 21:17:17 +0000 (14:17 -0700)
* maint:
git tag documentation grammar fixes and readability updates
grep: Add the option '--line-number'

1  2 
Documentation/git-grep.txt
Documentation/git-tag.txt
builtin/grep.c
index d4d425ea30292d69edd6e89a78e25dbe6346ef40,791d4d4871b6a285878f8c43b3b0a76c7f63f57c..132505eb4f83fdc64778df8cf58b595ca6eadf1f
@@@ -93,6 -93,7 +93,7 @@@ OPTION
        as a regex).
  
  -n::
+ --line-number::
        Prefix the line number to matching lines.
  
  -l::
@@@ -203,6 -204,16 +204,6 @@@ git grep --all-match -e NODE -e Unexpec
        Looks for a line that has `NODE` or `Unexpected` in
        files that have lines that match both.
  
 -Author
 -------
 -Originally written by Linus Torvalds <torvalds@osdl.org>, later
 -revamped by Junio C Hamano.
 -
 -
 -Documentation
 ---------------
 -Documentation by Junio C Hamano and the git-list <git@vger.kernel.org>.
 -
  GIT
  ---
  Part of the linkgit:git[1] suite
index 61263fa3290598680207c93d23d44ac3cd1f34e1,fa7ac12a3db2aeed7d35ab5e460b1c204c3bec37..d82f62120a21059a31d9c708c39d93b2a630d590
@@@ -165,13 -165,12 +165,12 @@@ You can test which tag you have by doin
  
  which should return 0123456789abcdef.. if you have the new version.
  
- Sorry for inconvenience.
+ Sorry for the inconvenience.
  ------------
  
  Does this seem a bit complicated?  It *should* be. There is no
- way that it would be correct to just "fix" it behind peoples
- backs. People need to know that their tags might have been
- changed.
+ way that it would be correct to just "fix" it automatically.
+ People need to know that their tags might have been changed.
  
  
  On Automatic following
@@@ -189,9 -188,10 +188,10 @@@ the toplevel but not limited to them.  
  from each other do not necessarily want to automatically get
  private anchor point tags from the other person.
  
- You would notice "please pull" messages on the mailing list says
- repo URL and branch name alone.  This is designed to be easily
- cut&pasted to a 'git fetch' command line:
+ Often, "please pull" messages on the mailing list just provide
+ two pieces of information: a repo URL and a branch name; this
+ is designed to be easily cut&pasted at the end of a 'git fetch'
+ command line:
  
  ------------
  Linus, please pull from
@@@ -207,14 -207,14 +207,14 @@@ becomes
  $ git pull git://git..../proj.git master
  ------------
  
- In such a case, you do not want to automatically follow other's
- tags.
+ In such a case, you do not want to automatically follow the other
person's tags.
  
- One important aspect of git is it is distributed, and being
distributed largely means there is no inherent "upstream" or
+ One important aspect of git is its distributed nature, which
+ largely means there is no inherent "upstream" or
  "downstream" in the system.  On the face of it, the above
  example might seem to indicate that the tag namespace is owned
- by upper echelon of people and tags only flow downwards, but
+ by the upper echelon of people and that tags only flow downwards, but
  that is not the case.  It only shows that the usage pattern
  determines who are interested in whose tags.
  
@@@ -232,7 -232,7 +232,7 @@@ this case
  
  It may well be that among networking people, they may want to
  exchange the tags internal to their group, but in that workflow
- they are most likely tracking with each other's progress by
+ they are most likely tracking each other's progress by
  having remote-tracking branches.  Again, the heuristic to automatically
  follow such tags is a good thing.
  
@@@ -242,26 -242,35 +242,26 @@@ On Backdating Tag
  
  If you have imported some changes from another VCS and would like
  to add tags for major releases of your work, it is useful to be able
- to specify the date to embed inside of the tag object.  The data in
+ to specify the date to embed inside of the tag object; such data in
  the tag object affects, for example, the ordering of tags in the
  gitweb interface.
  
  To set the date used in future tag objects, set the environment
- variable GIT_COMMITTER_DATE to one or more of the date and time.  The
- date and time can be specified in a number of ways; the most common
- is "YYYY-MM-DD HH:MM".
+ variable GIT_COMMITTER_DATE (see the later discussion of possible
+ values; the most common form is "YYYY-MM-DD HH:MM").
  
- An example follows.
+ For example:
  
  ------------
  $ GIT_COMMITTER_DATE="2006-10-02 10:31" git tag -s v1.0.1
  ------------
  
+ include::date-formats.txt[]
  
  SEE ALSO
  --------
  linkgit:git-check-ref-format[1].
  
 -Author
 -------
 -Written by Linus Torvalds <torvalds@osdl.org>,
 -Junio C Hamano <gitster@pobox.com> and Chris Wright <chrisw@osdl.org>.
 -
 -Documentation
 ---------------
 -Documentation by David Greaves, Junio C Hamano and the git-list <git@vger.kernel.org>.
 -
  GIT
  ---
  Part of the linkgit:git[1] suite
diff --combined builtin/grep.c
index 0bf8c0116a6a4c178a2c368f17d4103e91486624,bb0f93208fc6c3e418f9db5bcaec4b79c57e2bec..85e9583a1335330f8e852d7937abb10c97798bc0
@@@ -328,6 -328,106 +328,6 @@@ static int grep_config(const char *var
        return 0;
  }
  
 -/*
 - * Return non-zero if max_depth is negative or path has no more then max_depth
 - * slashes.
 - */
 -static int accept_subdir(const char *path, int max_depth)
 -{
 -      if (max_depth < 0)
 -              return 1;
 -
 -      while ((path = strchr(path, '/')) != NULL) {
 -              max_depth--;
 -              if (max_depth < 0)
 -                      return 0;
 -              path++;
 -      }
 -      return 1;
 -}
 -
 -/*
 - * Return non-zero if name is a subdirectory of match and is not too deep.
 - */
 -static int is_subdir(const char *name, int namelen,
 -              const char *match, int matchlen, int max_depth)
 -{
 -      if (matchlen > namelen || strncmp(name, match, matchlen))
 -              return 0;
 -
 -      if (name[matchlen] == '\0') /* exact match */
 -              return 1;
 -
 -      if (!matchlen || match[matchlen-1] == '/' || name[matchlen] == '/')
 -              return accept_subdir(name + matchlen + 1, max_depth);
 -
 -      return 0;
 -}
 -
 -/*
 - * git grep pathspecs are somewhat different from diff-tree pathspecs;
 - * pathname wildcards are allowed.
 - */
 -static int pathspec_matches(const char **paths, const char *name, int max_depth)
 -{
 -      int namelen, i;
 -      if (!paths || !*paths)
 -              return accept_subdir(name, max_depth);
 -      namelen = strlen(name);
 -      for (i = 0; paths[i]; i++) {
 -              const char *match = paths[i];
 -              int matchlen = strlen(match);
 -              const char *cp, *meta;
 -
 -              if (is_subdir(name, namelen, match, matchlen, max_depth))
 -                      return 1;
 -              if (!fnmatch(match, name, 0))
 -                      return 1;
 -              if (name[namelen-1] != '/')
 -                      continue;
 -
 -              /* We are being asked if the directory ("name") is worth
 -               * descending into.
 -               *
 -               * Find the longest leading directory name that does
 -               * not have metacharacter in the pathspec; the name
 -               * we are looking at must overlap with that directory.
 -               */
 -              for (cp = match, meta = NULL; cp - match < matchlen; cp++) {
 -                      char ch = *cp;
 -                      if (ch == '*' || ch == '[' || ch == '?') {
 -                              meta = cp;
 -                              break;
 -                      }
 -              }
 -              if (!meta)
 -                      meta = cp; /* fully literal */
 -
 -              if (namelen <= meta - match) {
 -                      /* Looking at "Documentation/" and
 -                       * the pattern says "Documentation/howto/", or
 -                       * "Documentation/diff*.txt".  The name we
 -                       * have should match prefix.
 -                       */
 -                      if (!memcmp(match, name, namelen))
 -                              return 1;
 -                      continue;
 -              }
 -
 -              if (meta - match < namelen) {
 -                      /* Looking at "Documentation/howto/" and
 -                       * the pattern says "Documentation/h*";
 -                       * match up to "Do.../h"; this avoids descending
 -                       * into "Documentation/technical/".
 -                       */
 -                      if (!memcmp(match, name, meta - match))
 -                              return 1;
 -                      continue;
 -              }
 -      }
 -      return 0;
 -}
 -
  static void *lock_and_read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
        void *data;
@@@ -480,7 -580,7 +480,7 @@@ static void run_pager(struct grep_opt *
        free(argv);
  }
  
 -static int grep_cache(struct grep_opt *opt, const char **paths, int cached)
 +static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec, int cached)
  {
        int hit = 0;
        int nr;
                struct cache_entry *ce = active_cache[nr];
                if (!S_ISREG(ce->ce_mode))
                        continue;
 -              if (!pathspec_matches(paths, ce->name, opt->max_depth))
 +              if (!match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL))
                        continue;
                /*
                 * If CE_VALID is on, we assume worktree file and its cache entry
        return hit;
  }
  
 -static int grep_tree(struct grep_opt *opt, const char **paths,
 -                   struct tree_desc *tree,
 -                   const char *tree_name, const char *base)
 +static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
 +                   struct tree_desc *tree, struct strbuf *base, int tn_len)
  {
 -      int len;
 -      int hit = 0;
 +      int hit = 0, matched = 0;
        struct name_entry entry;
 -      char *down;
 -      int tn_len = strlen(tree_name);
 -      struct strbuf pathbuf;
 -
 -      strbuf_init(&pathbuf, PATH_MAX + tn_len);
 -
 -      if (tn_len) {
 -              strbuf_add(&pathbuf, tree_name, tn_len);
 -              strbuf_addch(&pathbuf, ':');
 -              tn_len = pathbuf.len;
 -      }
 -      strbuf_addstr(&pathbuf, base);
 -      len = pathbuf.len;
 +      int old_baselen = base->len;
  
        while (tree_entry(tree, &entry)) {
                int te_len = tree_entry_len(entry.path, entry.sha1);
 -              pathbuf.len = len;
 -              strbuf_add(&pathbuf, entry.path, te_len);
 -
 -              if (S_ISDIR(entry.mode))
 -                      /* Match "abc/" against pathspec to
 -                       * decide if we want to descend into "abc"
 -                       * directory.
 -                       */
 -                      strbuf_addch(&pathbuf, '/');
 -
 -              down = pathbuf.buf + tn_len;
 -              if (!pathspec_matches(paths, down, opt->max_depth))
 -                      ;
 -              else if (S_ISREG(entry.mode))
 -                      hit |= grep_sha1(opt, entry.sha1, pathbuf.buf, tn_len);
 +
 +              if (matched != 2) {
 +                      matched = tree_entry_interesting(&entry, base, tn_len, pathspec);
 +                      if (matched == -1)
 +                              break; /* no more matches */
 +                      if (!matched)
 +                              continue;
 +              }
 +
 +              strbuf_add(base, entry.path, te_len);
 +
 +              if (S_ISREG(entry.mode)) {
 +                      hit |= grep_sha1(opt, entry.sha1, base->buf, tn_len);
 +              }
                else if (S_ISDIR(entry.mode)) {
                        enum object_type type;
                        struct tree_desc sub;
                        if (!data)
                                die("unable to read tree (%s)",
                                    sha1_to_hex(entry.sha1));
 +
 +                      strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
 -                      hit |= grep_tree(opt, paths, &sub, tree_name, down);
 +                      hit |= grep_tree(opt, pathspec, &sub, base, tn_len);
                        free(data);
                }
 +              strbuf_setlen(base, old_baselen);
 +
                if (hit && opt->status_only)
                        break;
        }
 -      strbuf_release(&pathbuf);
        return hit;
  }
  
 -static int grep_object(struct grep_opt *opt, const char **paths,
 +static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
                       struct object *obj, const char *name)
  {
        if (obj->type == OBJ_BLOB)
                struct tree_desc tree;
                void *data;
                unsigned long size;
 -              int hit;
 +              struct strbuf base;
 +              int hit, len;
 +
                data = read_object_with_reference(obj->sha1, tree_type,
                                                  &size, NULL);
                if (!data)
                        die("unable to read tree (%s)", sha1_to_hex(obj->sha1));
 +
 +              len = name ? strlen(name) : 0;
 +              strbuf_init(&base, PATH_MAX + len + 1);
 +              if (len) {
 +                      strbuf_add(&base, name, len);
 +                      strbuf_addch(&base, ':');
 +              }
                init_tree_desc(&tree, data, size);
 -              hit = grep_tree(opt, paths, &tree, name, "");
 +              hit = grep_tree(opt, pathspec, &tree, &base, base.len);
 +              strbuf_release(&base);
                free(data);
                return hit;
        }
        die("unable to grep from object of type %s", typename(obj->type));
  }
  
 -static int grep_objects(struct grep_opt *opt, const char **paths,
 +static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
                        const struct object_array *list)
  {
        unsigned int i;
        for (i = 0; i < nr; i++) {
                struct object *real_obj;
                real_obj = deref_tag(list->objects[i].item, NULL, 0);
 -              if (grep_object(opt, paths, real_obj, list->objects[i].name)) {
 +              if (grep_object(opt, pathspec, real_obj, list->objects[i].name)) {
                        hit = 1;
                        if (opt->status_only)
                                break;
        return hit;
  }
  
 -static int grep_directory(struct grep_opt *opt, const char **paths)
 +static int grep_directory(struct grep_opt *opt, const struct pathspec *pathspec)
  {
        struct dir_struct dir;
        int i, hit = 0;
        memset(&dir, 0, sizeof(dir));
        setup_standard_excludes(&dir);
  
 -      fill_directory(&dir, paths);
 +      fill_directory(&dir, pathspec->raw);
        for (i = 0; i < dir.nr; i++) {
 +              const char *name = dir.entries[i]->name;
 +              int namelen = strlen(name);
 +              if (!match_pathspec_depth(pathspec, name, namelen, 0, NULL))
 +                      continue;
                hit |= grep_file(opt, dir.entries[i]->name);
                if (hit && opt->status_only)
                        break;
@@@ -659,12 -757,11 +659,12 @@@ static int context_callback(const struc
  static int file_callback(const struct option *opt, const char *arg, int unset)
  {
        struct grep_opt *grep_opt = opt->value;
 +      int from_stdin = !strcmp(arg, "-");
        FILE *patterns;
        int lno = 0;
        struct strbuf sb = STRBUF_INIT;
  
 -      patterns = fopen(arg, "r");
 +      patterns = from_stdin ? stdin : fopen(arg, "r");
        if (!patterns)
                die_errno("cannot open '%s'", arg);
        while (strbuf_getline(&sb, patterns, '\n') == 0) {
                s = strbuf_detach(&sb, &len);
                append_grep_pat(grep_opt, s, len, arg, ++lno, GREP_PATTERN);
        }
 -      fclose(patterns);
 +      if (!from_stdin)
 +              fclose(patterns);
        strbuf_release(&sb);
        return 0;
  }
@@@ -735,7 -831,6 +735,7 @@@ int cmd_grep(int argc, const char **arg
        struct grep_opt opt;
        struct object_array list = OBJECT_ARRAY_INIT;
        const char **paths = NULL;
 +      struct pathspec pathspec;
        struct string_list path_list = STRING_LIST_INIT_NODUP;
        int i;
        int dummy;
                OPT_BOOLEAN('F', "fixed-strings", &opt.fixed,
                        "interpret patterns as fixed strings"),
                OPT_GROUP(""),
-               OPT_BOOLEAN('n', NULL, &opt.linenum, "show line numbers"),
+               OPT_BOOLEAN('n', "line-number", &opt.linenum, "show line numbers"),
                OPT_NEGBIT('h', NULL, &opt.pathname, "don't show filenames", 1),
                OPT_BIT('H', NULL, &opt.pathname, "show filenames", 1),
                OPT_NEGBIT(0, "full-name", &opt.relative,
                paths[0] = prefix;
                paths[1] = NULL;
        }
 +      init_pathspec(&pathspec, paths);
 +      pathspec.max_depth = opt.max_depth;
 +      pathspec.recursive = 1;
  
        if (show_in_pager && (cached || list.nr))
                die("--open-files-in-pager only works on the worktree");
                        die("--cached cannot be used with --no-index.");
                if (list.nr)
                        die("--no-index cannot be used with revs.");
 -              hit = grep_directory(&opt, paths);
 +              hit = grep_directory(&opt, &pathspec);
        } else if (!list.nr) {
                if (!cached)
                        setup_work_tree();
  
 -              hit = grep_cache(&opt, paths, cached);
 +              hit = grep_cache(&opt, &pathspec, cached);
        } else {
                if (cached)
                        die("both --cached and trees are given.");
 -              hit = grep_objects(&opt, paths, &list);
 +              hit = grep_objects(&opt, &pathspec, &list);
        }
  
        if (use_threads)