Merge branch 'js/early-config'
authorJunio C Hamano <gitster@pobox.com>
Thu, 9 Nov 2017 05:31:29 +0000 (14:31 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 9 Nov 2017 05:31:29 +0000 (14:31 +0900)
Correct start-up sequence so that a repository could be placed
immediately under the root directory again (which was broken at
around Git 2.13).

* js/early-config:
  setup: avoid double slashes when looking for HEAD

1  2 
setup.c

diff --combined setup.c
+++ b/setup.c
@@@ -1,6 -1,4 +1,6 @@@
  #include "cache.h"
 +#include "repository.h"
 +#include "config.h"
  #include "dir.h"
  #include "string-list.h"
  
@@@ -136,30 -134,21 +136,30 @@@ int path_inside_repo(const char *prefix
  
  int check_filename(const char *prefix, const char *arg)
  {
 -      const char *name;
 +      char *to_free = NULL;
        struct stat st;
  
 -      if (starts_with(arg, ":/")) {
 -              if (arg[2] == '\0') /* ":/" is root dir, always exists */
 +      if (skip_prefix(arg, ":/", &arg)) {
 +              if (!*arg) /* ":/" 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))
 +              prefix = NULL;
 +      } else if (skip_prefix(arg, ":!", &arg) ||
 +                 skip_prefix(arg, ":^", &arg)) {
 +              if (!*arg) /* excluding everything is silly, but allowed */
 +                      return 1;
 +      }
 +
 +      if (prefix)
 +              arg = to_free = prefix_filename(prefix, arg);
 +
 +      if (!lstat(arg, &st)) {
 +              free(to_free);
                return 1; /* file exists */
 -      if (errno == ENOENT || errno == ENOTDIR)
 +      }
 +      if (is_missing_file_error(errno)) {
 +              free(to_free);
                return 0; /* file does not exist */
 +      }
        die_errno("failed to stat '%s'", arg);
  }
  
@@@ -187,24 -176,6 +187,24 @@@ static void NORETURN die_verify_filenam
  
  }
  
 +/*
 + * Check for arguments that don't resolve as actual files,
 + * but which look sufficiently like pathspecs that we'll consider
 + * them such for the purposes of rev/pathspec DWIM parsing.
 + */
 +static int looks_like_pathspec(const char *arg)
 +{
 +      /* anything with a wildcard character */
 +      if (!no_wildcard(arg))
 +              return 1;
 +
 +      /* long-form pathspec magic */
 +      if (starts_with(arg, ":("))
 +              return 1;
 +
 +      return 0;
 +}
 +
  /*
   * Verify a filename that we got as an argument for a pathspec
   * entry. Note that a filename that begins with "-" never verifies
@@@ -230,8 -201,8 +230,8 @@@ void verify_filename(const char *prefix
                     int diagnose_misspelt_rev)
  {
        if (*arg == '-')
 -              die("bad flag '%s' used after filename", arg);
 -      if (check_filename(prefix, arg) || !no_wildcard(arg))
 +              die("option '%s' must come before non-option arguments", arg);
 +      if (looks_like_pathspec(arg) || check_filename(prefix, arg))
                return;
        die_verify_filename(prefix, arg, diagnose_misspelt_rev);
  }
@@@ -283,7 -254,7 +283,7 @@@ int get_common_dir_noenv(struct strbuf 
                if (!is_absolute_path(data.buf))
                        strbuf_addf(&path, "%s/", gitdir);
                strbuf_addbuf(&path, &data);
 -              strbuf_addstr(sb, real_path(path.buf));
 +              strbuf_add_real_path(sb, path.buf);
                ret = 1;
        } else {
                strbuf_addstr(sb, gitdir);
@@@ -312,7 -283,9 +312,9 @@@ int is_git_directory(const char *suspec
        size_t len;
  
        /* Check worktree-related signatures */
-       strbuf_addf(&path, "%s/HEAD", suspect);
+       strbuf_addstr(&path, suspect);
+       strbuf_complete(&path, '/');
+       strbuf_addstr(&path, "HEAD");
        if (validate_headref(path.buf))
                goto done;
  
@@@ -541,8 -514,7 +543,8 @@@ void read_gitfile_error_die(int error_c
  
  /*
   * Try to read the location of the git directory from the .git file,
 - * return path to git directory if found.
 + * return path to git directory if found. The return value comes from
 + * a shared buffer.
   *
   * On failure, if return_error_code is not NULL, return_error_code
   * will be set to an error code and NULL will be returned. If
@@@ -728,16 -700,11 +730,16 @@@ static const char *setup_discovered_git
  
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
 +              char *to_free = NULL;
 +              const char *ret;
 +
                if (offset != cwd->len && !is_absolute_path(gitdir))
 -                      gitdir = real_pathdup(gitdir);
 +                      gitdir = to_free = real_pathdup(gitdir, 1);
                if (chdir(cwd->buf))
                        die_errno("Could not come back to cwd");
 -              return setup_explicit_git_dir(gitdir, cwd, nongit_ok);
 +              ret = setup_explicit_git_dir(gitdir, cwd, nongit_ok);
 +              free(to_free);
 +              return ret;
        }
  
        /* #16.2, #17.2, #20.2, #21.2, #24, #25, #28, #29 (see t1510) */
@@@ -778,7 -745,7 +780,7 @@@ static const char *setup_bare_git_dir(s
  
        /* --work-tree is set without --git-dir; use discovered one */
        if (getenv(GIT_WORK_TREE_ENVIRONMENT) || git_work_tree_cfg) {
 -              const char *gitdir;
 +              static const char *gitdir;
  
                gitdir = offset == cwd->len ? "." : xmemdupz(cwd->buf, offset);
                if (chdir(cwd->buf))
@@@ -844,7 -811,7 +846,7 @@@ static int canonicalize_ceiling_entry(s
                /* Keep entry but do not canonicalize it */
                return 1;
        } else {
 -              char *real_path = real_pathdup(ceil);
 +              char *real_path = real_pathdup(ceil, 0);
                if (!real_path) {
                        return 0;
                }
@@@ -970,21 -937,19 +972,21 @@@ static enum discovery_result setup_git_
        }
  }
  
 -const char *discover_git_directory(struct strbuf *gitdir)
 +int discover_git_directory(struct strbuf *commondir,
 +                         struct strbuf *gitdir)
  {
        struct strbuf dir = STRBUF_INIT, err = STRBUF_INIT;
        size_t gitdir_offset = gitdir->len, cwd_len;
 +      size_t commondir_offset = commondir->len;
        struct repository_format candidate;
  
        if (strbuf_getcwd(&dir))
 -              return NULL;
 +              return -1;
  
        cwd_len = dir.len;
        if (setup_git_directory_gently_1(&dir, gitdir, 0) <= 0) {
                strbuf_release(&dir);
 -              return NULL;
 +              return -1;
        }
  
        /*
                strbuf_insert(gitdir, gitdir_offset, dir.buf, dir.len);
        }
  
 +      get_common_dir(commondir, gitdir->buf + gitdir_offset);
 +
        strbuf_reset(&dir);
 -      strbuf_addf(&dir, "%s/config", gitdir->buf + gitdir_offset);
 +      strbuf_addf(&dir, "%s/config", commondir->buf + commondir_offset);
        read_repository_format(&candidate, dir.buf);
        strbuf_release(&dir);
  
                warning("ignoring git dir '%s': %s",
                        gitdir->buf + gitdir_offset, err.buf);
                strbuf_release(&err);
 -              return NULL;
 +              strbuf_setlen(commondir, commondir_offset);
 +              strbuf_setlen(gitdir, gitdir_offset);
 +              return -1;
        }
  
 -      return gitdir->buf + gitdir_offset;
 +      return 0;
  }
  
  const char *setup_git_directory_gently(int *nongit_ok)
        startup_info->have_repository = !nongit_ok || !*nongit_ok;
        startup_info->prefix = prefix;
  
 +      /*
 +       * Not all paths through the setup code will call 'set_git_dir()' (which
 +       * directly sets up the environment) so in order to guarantee that the
 +       * environment is in a consistent state after setup, explicitly setup
 +       * the environment if we have a repository.
 +       *
 +       * NEEDSWORK: currently we allow bogus GIT_DIR values to be set in some
 +       * code paths so we also need to explicitly setup the environment if
 +       * the user has set GIT_DIR.  It may be beneficial to disallow bogus
 +       * GIT_DIR values at some point in the future.
 +       */
 +      if (startup_info->have_repository || getenv(GIT_DIR_ENVIRONMENT)) {
 +              if (!the_repository->gitdir) {
 +                      const char *gitdir = getenv(GIT_DIR_ENVIRONMENT);
 +                      if (!gitdir)
 +                              gitdir = DEFAULT_GIT_DIR_ENVIRONMENT;
 +                      repo_set_gitdir(the_repository, gitdir);
 +                      setup_git_env();
 +              }
 +      }
 +
        strbuf_release(&dir);
        strbuf_release(&gitdir);