Merge branch 'jk/alias-in-bare' into maint
authorJunio C Hamano <gitster@pobox.com>
Wed, 3 Apr 2013 16:25:41 +0000 (09:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Wed, 3 Apr 2013 16:25:41 +0000 (09:25 -0700)
An aliased command spawned from a bare repository that does not say
it is bare with "core.bare = yes" is treated as non-bare by mistake.

* jk/alias-in-bare:
setup: suppress implicit "." work-tree for bare repos
environment: add GIT_PREFIX to local_repo_env
cache.h: drop LOCAL_REPO_ENV_SIZE

1  2 
cache.h
environment.c
git.c
setup.c
diff --combined cache.h
index 898e346b0c08486c9251dd936e00008a7e44930e,c1fe67ffcfb1e792658d8d2c889e21f28ea78a94..bb71bf8a7f92bafb16699e7a53cd206042d0465a
+++ b/cache.h
@@@ -131,6 -131,7 +131,6 @@@ struct cache_entry 
        unsigned int ce_namelen;
        unsigned char sha1[20];
        struct cache_entry *next;
 -      struct cache_entry *dir_next;
        char name[FLEX_ARRAY]; /* more */
  };
  
@@@ -266,15 -267,25 +266,15 @@@ struct index_state 
        unsigned name_hash_initialized : 1,
                 initialized : 1;
        struct hash_table name_hash;
 +      struct hash_table dir_hash;
  };
  
  extern struct index_state the_index;
  
  /* Name hashing */
  extern void add_name_hash(struct index_state *istate, struct cache_entry *ce);
 -/*
 - * We don't actually *remove* it, we can just mark it invalid so that
 - * we won't find it in lookups.
 - *
 - * Not only would we have to search the lists (simple enough), but
 - * we'd also have to rehash other hash buckets in case this makes the
 - * hash bucket empty (common). So it's much better to just mark
 - * it.
 - */
 -static inline void remove_name_hash(struct cache_entry *ce)
 -{
 -      ce->ce_flags |= CE_UNHASHED;
 -}
 +extern void remove_name_hash(struct index_state *istate, struct cache_entry *ce);
 +extern void free_name_hash(struct index_state *istate);
  
  
  #ifndef NO_THE_INDEX_COMPATIBILITY_MACROS
@@@ -330,9 -341,11 +330,11 @@@ static inline enum object_type object_t
                OBJ_BLOB;
  }
  
+ /* Double-check local_repo_env below if you add to this list. */
  #define GIT_DIR_ENVIRONMENT "GIT_DIR"
  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
+ #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
  #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
  #define GIT_NOTES_REWRITE_REF_ENVIRONMENT "GIT_NOTES_REWRITE_REF"
  #define GIT_NOTES_REWRITE_MODE_ENVIRONMENT "GIT_NOTES_REWRITE_MODE"
 +#define GIT_LITERAL_PATHSPECS_ENVIRONMENT "GIT_LITERAL_PATHSPECS"
  
  /*
-  * Repository-local GIT_* environment variables
-  * The array is NULL-terminated to simplify its usage in contexts such
-  * environment creation or simple walk of the list.
-  * The number of non-NULL entries is available as a macro.
+  * This environment variable is expected to contain a boolean indicating
+  * whether we should or should not treat:
+  *
+  *   GIT_DIR=foo.git git ...
+  *
+  * as if GIT_WORK_TREE=. was given. It's not expected that users will make use
+  * of this, but we use it internally to communicate to sub-processes that we
+  * are in a bare repo. If not set, defaults to true.
+  */
+ #define GIT_IMPLICIT_WORK_TREE_ENVIRONMENT "GIT_IMPLICIT_WORK_TREE"
+ /*
+  * Repository-local GIT_* environment variables; these will be cleared
+  * when git spawns a sub-process that runs inside another repository.
+  * The array is NULL-terminated, which makes it easy to pass in the "env"
+  * parameter of a run-command invocation, or to do a simple walk.
   */
- #define LOCAL_REPO_ENV_SIZE 9
- extern const char *const local_repo_env[LOCAL_REPO_ENV_SIZE + 1];
+ extern const char * const local_repo_env[];
  
  extern int is_bare_repository_cfg;
  extern int is_bare_repository(void);
@@@ -463,8 -486,6 +476,8 @@@ extern int index_name_is_other(const st
  extern int ie_match_stat(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  extern int ie_modified(const struct index_state *, struct cache_entry *, struct stat *, unsigned int);
  
 +#define PATHSPEC_ONESTAR 1    /* the pathspec pattern sastisfies GFNM_ONESTAR */
 +
  struct pathspec {
        const char **raw; /* get_pathspec() result, not freed by free_pathspec() */
        int nr;
        struct pathspec_item {
                const char *match;
                int len;
 -              unsigned int use_wildcard:1;
 +              int nowildcard_len;
 +              int flags;
        } *items;
  };
  
@@@ -483,8 -503,6 +496,8 @@@ extern int init_pathspec(struct pathspe
  extern void free_pathspec(struct pathspec *);
  extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
  
 +extern int limit_pathspec_to_literal(void);
 +
  #define HASH_WRITE_OBJECT 1
  #define HASH_FORMAT_CHECK 2
  extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
@@@ -525,7 -543,6 +538,7 @@@ extern int delete_ref(const char *, con
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
  extern int trust_ctime;
 +extern int check_stat;
  extern int quote_path_fully;
  extern int has_symlinks;
  extern int minimum_abbrev, default_abbrev;
@@@ -552,12 -569,6 +565,12 @@@ extern int core_preload_index
  extern int core_apply_sparse_checkout;
  extern int precomposed_unicode;
  
 +/*
 + * The character that begins a commented line in user-editable file
 + * that is subject to stripspace.
 + */
 +extern char comment_line_char;
 +
  enum branch_track {
        BRANCH_TRACK_UNSPECIFIED = -1,
        BRANCH_TRACK_NEVER = 0,
@@@ -1002,19 -1013,15 +1015,19 @@@ struct ref 
        unsigned char old_sha1[20];
        unsigned char new_sha1[20];
        char *symref;
 -      unsigned int force:1,
 +      unsigned int
 +              force:1,
 +              forced_update:1,
                merge:1,
 -              nonfastforward:1,
                deletion:1;
        enum {
                REF_STATUS_NONE = 0,
                REF_STATUS_OK,
                REF_STATUS_REJECT_NONFASTFORWARD,
 +              REF_STATUS_REJECT_ALREADY_EXISTS,
                REF_STATUS_REJECT_NODELETE,
 +              REF_STATUS_REJECT_FETCH_FIRST,
 +              REF_STATUS_REJECT_NEEDS_FORCE,
                REF_STATUS_UPTODATE,
                REF_STATUS_REMOTE_REJECT,
                REF_STATUS_EXPECTING_REPORT
@@@ -1143,9 -1150,6 +1156,9 @@@ extern int check_repository_format_vers
  extern int git_env_bool(const char *, int);
  extern int git_config_system(void);
  extern int config_error_nonbool(const char *);
 +#if defined(__GNUC__) && ! defined(__clang__)
 +#define config_error_nonbool(s) (config_error_nonbool(s), -1)
 +#endif
  extern const char *get_log_output_encoding(void);
  extern const char *get_commit_output_encoding(void);
  
@@@ -1159,28 -1163,12 +1172,28 @@@ struct config_include_data 
  #define CONFIG_INCLUDE_INIT { 0 }
  extern int git_config_include(const char *name, const char *value, void *data);
  
 +/*
 + * Match and parse a config key of the form:
 + *
 + *   section.(subsection.)?key
 + *
 + * (i.e., what gets handed to a config_fn_t). The caller provides the section;
 + * we return -1 if it does not match, 0 otherwise. The subsection and key
 + * out-parameters are filled by the function (and subsection is NULL if it is
 + * missing).
 + */
 +extern int parse_config_key(const char *var,
 +                          const char *section,
 +                          const char **subsection, int *subsection_len,
 +                          const char **key);
 +
  extern int committer_ident_sufficiently_given(void);
  extern int author_ident_sufficiently_given(void);
  
  extern const char *git_commit_encoding;
  extern const char *git_log_output_encoding;
  extern const char *git_mailmap_file;
 +extern const char *git_mailmap_blob;
  
  /* IO helper functions */
  extern void maybe_flush_or_die(FILE *, const char *);
diff --combined environment.c
index 89d6c70c15a95aff82f0063e3c0dd6bdab026213,92c5dff008b591e66f47678f21ba5442fde43593..e2e75c16602d8e5841c2461defaba7b9866115d8
@@@ -13,7 -13,6 +13,7 @@@
  
  int trust_executable_bit = 1;
  int trust_ctime = 1;
 +int check_stat = 1;
  int has_symlinks = 1;
  int minimum_abbrev = 4, default_abbrev = 7;
  int ignore_case;
@@@ -63,12 -62,6 +63,12 @@@ int precomposed_unicode = -1; /* see pr
  struct startup_info *startup_info;
  unsigned long pack_size_limit_cfg;
  
 +/*
 + * The character that begins a commented line in user-editable file
 + * that is subject to stripspace.
 + */
 +char comment_line_char = '#';
 +
  /* Parallel index stat data preload? */
  int core_preload_index = 0;
  
@@@ -83,20 -76,20 +83,20 @@@ static const char *git_dir
  static char *git_object_dir, *git_index_file, *git_graft_file;
  
  /*
-  * Repository-local GIT_* environment variables
-  * Remember to update local_repo_env_size in cache.h when
-  * the size of the list changes
+  * Repository-local GIT_* environment variables; see cache.h for details.
   */
- const char * const local_repo_env[LOCAL_REPO_ENV_SIZE + 1] = {
+ const char * const local_repo_env[] = {
        ALTERNATE_DB_ENVIRONMENT,
        CONFIG_ENVIRONMENT,
        CONFIG_DATA_ENVIRONMENT,
        DB_ENVIRONMENT,
        GIT_DIR_ENVIRONMENT,
        GIT_WORK_TREE_ENVIRONMENT,
+       GIT_IMPLICIT_WORK_TREE_ENVIRONMENT,
        GRAFT_ENVIRONMENT,
        INDEX_ENVIRONMENT,
        NO_REPLACE_OBJECTS_ENVIRONMENT,
+       GIT_PREFIX_ENVIRONMENT,
        NULL
  };
  
diff --combined git.c
index 39ba6b14618389bc9312df43a376b52f9a21d881,0ffea570c71cfc4619dc42f20c5ee7f4d72c6499..850d3f5527f4100f45cb5eb1a7d8772e04ae4443
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -6,10 -6,10 +6,10 @@@
  #include "run-command.h"
  
  const char git_usage_string[] =
 -      "git [--version] [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
 +      "git [--version] [--help] [-c name=value]\n"
 +      "           [--exec-path[=<path>]] [--html-path] [--man-path] [--info-path]\n"
        "           [-p|--paginate|--no-pager] [--no-replace-objects] [--bare]\n"
        "           [--git-dir=<path>] [--work-tree=<path>] [--namespace=<name>]\n"
 -      "           [-c name=value] [--help]\n"
        "           <command> [<args>]";
  
  const char git_more_info_string[] =
@@@ -125,6 -125,7 +125,7 @@@ static int handle_options(const char **
                        static char git_dir[PATH_MAX+1];
                        is_bare_repository_cfg = 1;
                        setenv(GIT_DIR_ENVIRONMENT, getcwd(git_dir, sizeof(git_dir)), 0);
+                       setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
                        if (envchanged)
                                *envchanged = 1;
                } else if (!strcmp(cmd, "-c")) {
                        git_config_push_parameter((*argv)[1]);
                        (*argv)++;
                        (*argc)--;
 +              } else if (!strcmp(cmd, "--literal-pathspecs")) {
 +                      setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "1", 1);
 +                      if (envchanged)
 +                              *envchanged = 1;
 +              } else if (!strcmp(cmd, "--no-literal-pathspecs")) {
 +                      setenv(GIT_LITERAL_PATHSPECS_ENVIRONMENT, "0", 1);
 +                      if (envchanged)
 +                              *envchanged = 1;
                } else {
                        fprintf(stderr, "Unknown option: %s\n", cmd);
                        usage(git_usage_string);
@@@ -313,7 -306,6 +314,7 @@@ static void handle_internal_command(in
                { "bundle", cmd_bundle, RUN_SETUP_GENTLY },
                { "cat-file", cmd_cat_file, RUN_SETUP },
                { "check-attr", cmd_check_attr, RUN_SETUP },
 +              { "check-ignore", cmd_check_ignore, RUN_SETUP | NEED_WORK_TREE },
                { "check-ref-format", cmd_check_ref_format },
                { "checkout", cmd_checkout, RUN_SETUP | NEED_WORK_TREE },
                { "checkout-index", cmd_checkout_index,
@@@ -545,7 -537,7 +546,7 @@@ int main(int argc, const char **argv
                commit_pager_choice();
                printf("usage: %s\n\n", git_usage_string);
                list_common_cmds_help();
 -              printf("\n%s\n", git_more_info_string);
 +              printf("\n%s\n", _(git_more_info_string));
                exit(1);
        }
        cmd = argv[0];
diff --combined setup.c
index a2be9690ad3bd8895affe485e67bb7edac4afa9d,01c5476eb771f13df0e1ace0066a2213d3aaa290..94c1e61bda747ed5c664bbbf8431234dc8276d29
+++ b/setup.c
@@@ -66,14 -66,7 +66,14 @@@ int check_filename(const char *prefix, 
        const char *name;
        struct stat st;
  
 -      name = prefix ? prefix_filename(prefix, strlen(prefix), arg) : arg;
 +      if (!prefixcmp(arg, ":/")) {
 +              if (arg[2] == '\0') /* ":/" is root dir, always exists */
 +                      return 1;
 +              name = arg + 2;
 +      } else if (prefix)
 +              name = prefix_filename(prefix, strlen(prefix), arg);
 +      else
 +              name = arg;
        if (!lstat(name, &st))
                return 1; /* file exists */
        if (errno == ENOENT || errno == ENOTDIR)
@@@ -207,11 -200,10 +207,11 @@@ static const char *prefix_pathspec(cons
                     *copyfrom && *copyfrom != ')';
                     copyfrom = nextat) {
                        size_t len = strcspn(copyfrom, ",)");
 -                      if (copyfrom[len] == ')')
 -                              nextat = copyfrom + len;
 -                      else
 +                      if (copyfrom[len] == ',')
                                nextat = copyfrom + len + 1;
 +                      else
 +                              /* handle ')' and '\0' */
 +                              nextat = copyfrom + len;
                        if (!len)
                                continue;
                        for (i = 0; i < ARRAY_SIZE(pathspec_magic); i++)
                                die("Invalid pathspec magic '%.*s' in '%s'",
                                    (int) len, copyfrom, elt);
                }
 -              if (*copyfrom == ')')
 -                      copyfrom++;
 +              if (*copyfrom != ')')
 +                      die("Missing ')' at the end of pathspec magic in '%s'", elt);
 +              copyfrom++;
        } else {
                /* shorthand */
                for (copyfrom = elt + 1;
                return prefix_path(prefix, prefixlen, copyfrom);
  }
  
 +/*
 + * N.B. get_pathspec() is deprecated in favor of the "struct pathspec"
 + * based interface - see pathspec_magic above.
 + *
 + * Arguments:
 + *  - prefix - a path relative to the root of the working tree
 + *  - pathspec - a list of paths underneath the prefix path
 + *
 + * Iterates over pathspec, prepending each path with prefix,
 + * and return the resulting list.
 + *
 + * If pathspec is empty, return a singleton list containing prefix.
 + *
 + * If pathspec and prefix are both empty, return an empty list.
 + *
 + * This is typically used by built-in commands such as add.c, in order
 + * to normalize argv arguments provided to the built-in into a list of
 + * paths to process, all relative to the root of the working tree.
 + */
  const char **get_pathspec(const char *prefix, const char **pathspec)
  {
        const char *entry = *pathspec;
@@@ -525,6 -497,12 +525,12 @@@ static const char *setup_explicit_git_d
                        set_git_work_tree(core_worktree);
                }
        }
+       else if (!git_env_bool(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, 1)) {
+               /* #16d */
+               set_git_dir(gitdirenv);
+               free(gitfile);
+               return NULL;
+       }
        else /* #2, #10 */
                set_git_work_tree(".");
  
@@@ -603,6 -581,8 +609,8 @@@ static const char *setup_bare_git_dir(c
        if (check_repository_format_gently(".", nongit_ok))
                return NULL;
  
+       setenv(GIT_IMPLICIT_WORK_TREE_ENVIRONMENT, "0", 1);
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
                const char *gitdir;
@@@ -796,9 -776,9 +804,9 @@@ const char *setup_git_directory_gently(
  
        prefix = setup_git_directory_gently_1(nongit_ok);
        if (prefix)
-               setenv("GIT_PREFIX", prefix, 1);
+               setenv(GIT_PREFIX_ENVIRONMENT, prefix, 1);
        else
-               setenv("GIT_PREFIX", "", 1);
+               setenv(GIT_PREFIX_ENVIRONMENT, "", 1);
  
        if (startup_info) {
                startup_info->have_repository = !nongit_ok || !*nongit_ok;