Merge branch 'mm/config-xdg'
authorJunio C Hamano <gitster@pobox.com>
Mon, 9 Jul 2012 16:00:35 +0000 (09:00 -0700)
committerJunio C Hamano <gitster@pobox.com>
Mon, 9 Jul 2012 16:00:36 +0000 (09:00 -0700)
Teach git to read various information from $XDG_CONFIG_HOME/git/ to allow
the user to avoid cluttering $HOME.

* mm/config-xdg:
config: write to $XDG_CONFIG_HOME/git/config file when appropriate
Let core.attributesfile default to $XDG_CONFIG_HOME/git/attributes
Let core.excludesfile default to $XDG_CONFIG_HOME/git/ignore
config: read (but not write) from $XDG_CONFIG_HOME/git/config file

1  2 
Documentation/config.txt
cache.h
dir.c
diff --combined Documentation/config.txt
index 0bcea8a949e96d53ebc7aa956d70ef7873551320,db07459bbb3380fb0af1b403227a95ec67f4d6f6..c6ff15e59413eb731e983ac2c1de010e12336001
@@@ -159,10 -159,9 +159,10 @@@ advice.*:
                specified a refspec that isn't your current branch) and
                it resulted in a non-fast-forward error.
        statusHints::
 -              Directions on how to stage/unstage/add shown in the
 -              output of linkgit:git-status[1] and the template shown
 -              when writing commit messages.
 +              Show directions on how to proceed from the current
 +              state in the output of linkgit:git-status[1] and in
 +              the template shown when writing commit messages in
 +              linkgit:git-commit[1].
        commitBeforeMerge::
                Advice shown when linkgit:git-merge[1] refuses to
                merge to avoid overwriting local changes.
@@@ -484,7 -483,9 +484,9 @@@ core.excludesfile:
        '.git/info/exclude', git looks into this file for patterns
        of files which are not meant to be tracked.  "`~/`" is expanded
        to the value of `$HOME` and "`~user/`" to the specified user's
-       home directory.  See linkgit:gitignore[5].
+       home directory. Its default value is $XDG_CONFIG_HOME/git/ignore.
+       If $XDG_CONFIG_HOME is either not set or empty, $HOME/.config/git/ignore
+       is used instead. See linkgit:gitignore[5].
  
  core.askpass::
        Some commands (e.g. svn and http interfaces) that interactively
@@@ -499,7 -500,9 +501,9 @@@ core.attributesfile:
        In addition to '.gitattributes' (per-directory) and
        '.git/info/attributes', git looks into this file for attributes
        (see linkgit:gitattributes[5]). Path expansions are made the same
-       way as for `core.excludesfile`.
+       way as for `core.excludesfile`. Its default value is
+       $XDG_CONFIG_HOME/git/attributes. If $XDG_CONFIG_HOME is either not
+       set or empty, $HOME/.config/git/attributes is used instead.
  
  core.editor::
        Commands such as `commit` and `tag` that lets you edit
@@@ -881,7 -884,7 +885,7 @@@ column.ui:
        make equal size columns
  --
  +
 -      This option defaults to 'never'.
 +This option defaults to 'never'.
  
  column.branch::
        Specify whether to output branch listing in `git branch` in columns.
@@@ -1721,7 -1724,6 +1725,7 @@@ push.default:
        no refspec is implied by any of the options given on the command
        line. Possible values are:
  +
 +--
  * `nothing` - do not push anything.
  * `matching` - push all branches having the same name in both ends.
    This is for those who prepare all the branches into a publishable
    option and is well-suited for beginners. It will become the default
    in Git 2.0.
  * `current` - push the current branch to a branch of the same name.
 -  +
 -  The `simple`, `current` and `upstream` modes are for those who want to
 -  push out a single branch after finishing work, even when the other
 -  branches are not yet ready to be pushed out. If you are working with
 -  other people to push into the same shared repository, you would want
 -  to use one of these.
 +--
 ++
 +The `simple`, `current` and `upstream` modes are for those who want to
 +push out a single branch after finishing work, even when the other
 +branches are not yet ready to be pushed out. If you are working with
 +other people to push into the same shared repository, you would want
 +to use one of these.
  
  rebase.stat::
        Whether to show a diffstat of what changed upstream since the last
diff --combined cache.h
index 89581041ce82603ae82866f8f8a5c01b4f7f6d0d,fbba2d687a3869db9e4ed2e15e0a4679d5188fe1..c22b9289808f708c68c94ff4a331466250e9b7e5
+++ b/cache.h
@@@ -409,11 -409,8 +409,11 @@@ extern const char *setup_git_directory(
  extern char *prefix_path(const char *prefix, int len, const char *path);
  extern const char *prefix_filename(const char *prefix, int len, const char *path);
  extern int check_filename(const char *prefix, const char *name);
 -extern void verify_filename(const char *prefix, const char *name);
 +extern void verify_filename(const char *prefix,
 +                          const char *name,
 +                          int diagnose_misspelt_rev);
  extern void verify_non_filename(const char *prefix, const char *name);
 +extern int path_inside_repo(const char *prefix, const char *path);
  
  #define INIT_DB_QUIET 0x0001
  
@@@ -622,6 -619,8 +622,8 @@@ extern char *git_snpath(char *buf, size
        __attribute__((format (printf, 3, 4)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
+ extern char *mkpathdup(const char *fmt, ...)
+       __attribute__((format (printf, 1, 2)));
  
  /* Return a statically allocated filename matching the sha1 signature */
  extern char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
@@@ -711,6 -710,7 +713,7 @@@ int set_shared_perm(const char *path, i
  int safe_create_leading_directories(char *path);
  int safe_create_leading_directories_const(const char *path);
  int mkdir_in_gitdir(const char *path);
+ extern void home_config_paths(char **global, char **xdg, char *file);
  extern char *expand_user_path(const char *path);
  const char *enter_repo(const char *path, int strict);
  static inline int is_absolute_path(const char *path)
diff --combined dir.c
index 0015cc54f455cf48e6e2d66c23ecebfa017fcf00,390367fa6703624e4566006f647b875f96764ba8..a772c6dc6c2bf4dc40f46f0bb5d0899312f3ffd4
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -288,24 -288,9 +288,24 @@@ int match_pathspec_depth(const struct p
        return retval;
  }
  
 +/*
 + * Return the length of the "simple" part of a path match limiter.
 + */
 +static int simple_length(const char *match)
 +{
 +      int len = -1;
 +
 +      for (;;) {
 +              unsigned char c = *match++;
 +              len++;
 +              if (c == '\0' || is_glob_special(c))
 +                      return len;
 +      }
 +}
 +
  static int no_wildcard(const char *string)
  {
 -      return string[strcspn(string, "*?[{\\")] == '\0';
 +      return string[simple_length(string)] == '\0';
  }
  
  void add_exclude(const char *string, const char *base,
        x->flags = flags;
        if (!strchr(string, '/'))
                x->flags |= EXC_FLAG_NODIR;
 -      if (no_wildcard(string))
 -              x->flags |= EXC_FLAG_NOWILDCARD;
 +      x->nowildcardlen = simple_length(string);
        if (*string == '*' && no_wildcard(string+1))
                x->flags |= EXC_FLAG_ENDSWITH;
        ALLOC_GROW(which->excludes, which->nr + 1, which->alloc);
@@@ -512,69 -498,57 +512,69 @@@ int excluded_from_list(const char *path
  {
        int i;
  
 -      if (el->nr) {
 -              for (i = el->nr - 1; 0 <= i; i--) {
 -                      struct exclude *x = el->excludes[i];
 -                      const char *exclude = x->pattern;
 -                      int to_exclude = x->to_exclude;
 -
 -                      if (x->flags & EXC_FLAG_MUSTBEDIR) {
 -                              if (*dtype == DT_UNKNOWN)
 -                                      *dtype = get_dtype(NULL, pathname, pathlen);
 -                              if (*dtype != DT_DIR)
 -                                      continue;
 -                      }
 +      if (!el->nr)
 +              return -1;      /* undefined */
  
 -                      if (x->flags & EXC_FLAG_NODIR) {
 -                              /* match basename */
 -                              if (x->flags & EXC_FLAG_NOWILDCARD) {
 -                                      if (!strcmp_icase(exclude, basename))
 -                                              return to_exclude;
 -                              } else if (x->flags & EXC_FLAG_ENDSWITH) {
 -                                      if (x->patternlen - 1 <= pathlen &&
 -                                          !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
 -                                              return to_exclude;
 -                              } else {
 -                                      if (fnmatch_icase(exclude, basename, 0) == 0)
 -                                              return to_exclude;
 -                              }
 -                      }
 -                      else {
 -                              /* match with FNM_PATHNAME:
 -                               * exclude has base (baselen long) implicitly
 -                               * in front of it.
 -                               */
 -                              int baselen = x->baselen;
 -                              if (*exclude == '/')
 -                                      exclude++;
 -
 -                              if (pathlen < baselen ||
 -                                  (baselen && pathname[baselen-1] != '/') ||
 -                                  strncmp_icase(pathname, x->base, baselen))
 -                                  continue;
 -
 -                              if (x->flags & EXC_FLAG_NOWILDCARD) {
 -                                      if (!strcmp_icase(exclude, pathname + baselen))
 -                                              return to_exclude;
 -                              } else {
 -                                      if (fnmatch_icase(exclude, pathname+baselen,
 -                                                  FNM_PATHNAME) == 0)
 -                                          return to_exclude;
 -                              }
 +      for (i = el->nr - 1; 0 <= i; i--) {
 +              struct exclude *x = el->excludes[i];
 +              const char *name, *exclude = x->pattern;
 +              int to_exclude = x->to_exclude;
 +              int namelen, prefix = x->nowildcardlen;
 +
 +              if (x->flags & EXC_FLAG_MUSTBEDIR) {
 +                      if (*dtype == DT_UNKNOWN)
 +                              *dtype = get_dtype(NULL, pathname, pathlen);
 +                      if (*dtype != DT_DIR)
 +                              continue;
 +              }
 +
 +              if (x->flags & EXC_FLAG_NODIR) {
 +                      /* match basename */
 +                      if (prefix == x->patternlen) {
 +                              if (!strcmp_icase(exclude, basename))
 +                                      return to_exclude;
 +                      } else if (x->flags & EXC_FLAG_ENDSWITH) {
 +                              if (x->patternlen - 1 <= pathlen &&
 +                                  !strcmp_icase(exclude + 1, pathname + pathlen - x->patternlen + 1))
 +                                      return to_exclude;
 +                      } else {
 +                              if (fnmatch_icase(exclude, basename, 0) == 0)
 +                                      return to_exclude;
                        }
 +                      continue;
 +              }
 +
 +              /* match with FNM_PATHNAME:
 +               * exclude has base (baselen long) implicitly in front of it.
 +               */
 +              if (*exclude == '/') {
 +                      exclude++;
 +                      prefix--;
                }
 +
 +              if (pathlen < x->baselen ||
 +                  (x->baselen && pathname[x->baselen-1] != '/') ||
 +                  strncmp_icase(pathname, x->base, x->baselen))
 +                      continue;
 +
 +              namelen = x->baselen ? pathlen - x->baselen : pathlen;
 +              name = pathname + pathlen  - namelen;
 +
 +              /* if the non-wildcard part is longer than the
 +                 remaining pathname, surely it cannot match */
 +              if (prefix > namelen)
 +                      continue;
 +
 +              if (prefix) {
 +                      if (strncmp_icase(exclude, name, prefix))
 +                              continue;
 +                      exclude += prefix;
 +                      name    += prefix;
 +                      namelen -= prefix;
 +              }
 +
 +              if (!namelen || !fnmatch_icase(exclude, name, FNM_PATHNAME))
 +                      return to_exclude;
        }
        return -1; /* undecided */
  }
@@@ -1081,6 -1055,21 +1081,6 @@@ static int cmp_name(const void *p1, con
                                  e2->name, e2->len);
  }
  
 -/*
 - * Return the length of the "simple" part of a path match limiter.
 - */
 -static int simple_length(const char *match)
 -{
 -      int len = -1;
 -
 -      for (;;) {
 -              unsigned char c = *match++;
 -              len++;
 -              if (c == '\0' || is_glob_special(c))
 -                      return len;
 -      }
 -}
 -
  static struct path_simplify *create_simplify(const char **pathspec)
  {
        int nr, alloc = 0;
@@@ -1303,12 -1292,17 +1303,17 @@@ int remove_dir_recursively(struct strbu
  void setup_standard_excludes(struct dir_struct *dir)
  {
        const char *path;
+       char *xdg_path;
  
        dir->exclude_per_dir = ".gitignore";
        path = git_path("info/exclude");
+       if (!excludes_file) {
+               home_config_paths(NULL, &xdg_path, "ignore");
+               excludes_file = xdg_path;
+       }
        if (!access(path, R_OK))
                add_excludes_from_file(dir, path);
-       if (excludes_file && !access(excludes_file, R_OK))
+       if (!access(excludes_file, R_OK))
                add_excludes_from_file(dir, excludes_file);
  }