Merge branch 'rs/absolute-pathdup'
authorJunio C Hamano <gitster@pobox.com>
Thu, 2 Feb 2017 21:36:55 +0000 (13:36 -0800)
committerJunio C Hamano <gitster@pobox.com>
Thu, 2 Feb 2017 21:36:55 +0000 (13:36 -0800)
Code cleanup.

* rs/absolute-pathdup:
use absolute_pathdup()
abspath: add absolute_pathdup()

1  2 
abspath.c
builtin/clone.c
builtin/submodule--helper.c
cache.h
worktree.c
diff --combined abspath.c
index fce40fddcc3b68a644fb93a698da8164a1d9b9cf,af82abd033ae8361adf825a01567ab5c1d472468..2f0c26e0e2cbee88aa671f3960d21720e4307aba
+++ b/abspath.c
@@@ -11,83 -11,46 +11,83 @@@ int is_directory(const char *path
        return (!stat(path, &st) && S_ISDIR(st.st_mode));
  }
  
 +/* removes the last path component from 'path' except if 'path' is root */
 +static void strip_last_component(struct strbuf *path)
 +{
 +      size_t offset = offset_1st_component(path->buf);
 +      size_t len = path->len;
 +
 +      /* Find start of the last component */
 +      while (offset < len && !is_dir_sep(path->buf[len - 1]))
 +              len--;
 +      /* Skip sequences of multiple path-separators */
 +      while (offset < len && is_dir_sep(path->buf[len - 1]))
 +              len--;
 +
 +      strbuf_setlen(path, len);
 +}
 +
 +/* get (and remove) the next component in 'remaining' and place it in 'next' */
 +static void get_next_component(struct strbuf *next, struct strbuf *remaining)
 +{
 +      char *start = NULL;
 +      char *end = NULL;
 +
 +      strbuf_reset(next);
 +
 +      /* look for the next component */
 +      /* Skip sequences of multiple path-separators */
 +      for (start = remaining->buf; is_dir_sep(*start); start++)
 +              ; /* nothing */
 +      /* Find end of the path component */
 +      for (end = start; *end && !is_dir_sep(*end); end++)
 +              ; /* nothing */
 +
 +      strbuf_add(next, start, end - start);
 +      /* remove the component from 'remaining' */
 +      strbuf_remove(remaining, 0, end - remaining->buf);
 +}
 +
 +/* copies root part from remaining to resolved, canonicalizing it on the way */
 +static void get_root_part(struct strbuf *resolved, struct strbuf *remaining)
 +{
 +      int offset = offset_1st_component(remaining->buf);
 +
 +      strbuf_reset(resolved);
 +      strbuf_add(resolved, remaining->buf, offset);
 +#ifdef GIT_WINDOWS_NATIVE
 +      convert_slashes(resolved->buf);
 +#endif
 +      strbuf_remove(remaining, 0, offset);
 +}
 +
  /* We allow "recursive" symbolic links. Only within reason, though. */
 -#define MAXDEPTH 5
 +#ifndef MAXSYMLINKS
 +#define MAXSYMLINKS 32
 +#endif
  
  /*
   * Return the real path (i.e., absolute path, with symlinks resolved
   * and extra slashes removed) equivalent to the specified path.  (If
   * you want an absolute path but don't mind links, use
 - * absolute_path().)  The return value is a pointer to a static
 - * buffer.
 + * absolute_path().)  Places the resolved realpath in the provided strbuf.
   *
 - * The input and all intermediate paths must be shorter than MAX_PATH.
   * The directory part of path (i.e., everything up to the last
   * dir_sep) must denote a valid, existing directory, but the last
   * component need not exist.  If die_on_error is set, then die with an
   * informative error message if there is a problem.  Otherwise, return
   * NULL on errors (without generating any output).
 - *
 - * If path is our buffer, then return path, as it's already what the
 - * user wants.
   */
 -static const char *real_path_internal(const char *path, int die_on_error)
 +char *strbuf_realpath(struct strbuf *resolved, const char *path,
 +                    int die_on_error)
  {
 -      static struct strbuf sb = STRBUF_INIT;
 +      struct strbuf remaining = STRBUF_INIT;
 +      struct strbuf next = STRBUF_INIT;
 +      struct strbuf symlink = STRBUF_INIT;
        char *retval = NULL;
 -
 -      /*
 -       * If we have to temporarily chdir(), store the original CWD
 -       * here so that we can chdir() back to it at the end of the
 -       * function:
 -       */
 -      struct strbuf cwd = STRBUF_INIT;
 -
 -      int depth = MAXDEPTH;
 -      char *last_elem = NULL;
 +      int num_symlinks = 0;
        struct stat st;
  
 -      /* We've already done it */
 -      if (path == sb.buf)
 -              return path;
 -
        if (!*path) {
                if (die_on_error)
                        die("The empty string is not a valid path");
                        goto error_out;
        }
  
 -      strbuf_reset(&sb);
 -      strbuf_addstr(&sb, path);
 +      strbuf_addstr(&remaining, path);
 +      get_root_part(resolved, &remaining);
  
 -      while (depth--) {
 -              if (!is_directory(sb.buf)) {
 -                      char *last_slash = find_last_dir_sep(sb.buf);
 -                      if (last_slash) {
 -                              last_elem = xstrdup(last_slash + 1);
 -                              strbuf_setlen(&sb, last_slash - sb.buf + 1);
 -                      } else {
 -                              last_elem = xmemdupz(sb.buf, sb.len);
 -                              strbuf_reset(&sb);
 -                      }
 +      if (!resolved->len) {
 +              /* relative path; can use CWD as the initial resolved path */
 +              if (strbuf_getcwd(resolved)) {
 +                      if (die_on_error)
 +                              die_errno("unable to get current working directory");
 +                      else
 +                              goto error_out;
 +              }
 +      }
 +
 +      /* Iterate over the remaining path components */
 +      while (remaining.len > 0) {
 +              get_next_component(&next, &remaining);
 +
 +              if (next.len == 0) {
 +                      continue; /* empty component */
 +              } else if (next.len == 1 && !strcmp(next.buf, ".")) {
 +                      continue; /* '.' component */
 +              } else if (next.len == 2 && !strcmp(next.buf, "..")) {
 +                      /* '..' component; strip the last path component */
 +                      strip_last_component(resolved);
 +                      continue;
                }
  
 -              if (sb.len) {
 -                      if (!cwd.len && strbuf_getcwd(&cwd)) {
 +              /* append the next component and resolve resultant path */
 +              if (!is_dir_sep(resolved->buf[resolved->len - 1]))
 +                      strbuf_addch(resolved, '/');
 +              strbuf_addbuf(resolved, &next);
 +
 +              if (lstat(resolved->buf, &st)) {
 +                      /* error out unless this was the last component */
 +                      if (errno != ENOENT || remaining.len) {
                                if (die_on_error)
 -                                      die_errno("Could not get current working directory");
 +                                      die_errno("Invalid path '%s'",
 +                                                resolved->buf);
                                else
                                        goto error_out;
                        }
 +              } else if (S_ISLNK(st.st_mode)) {
 +                      ssize_t len;
 +                      strbuf_reset(&symlink);
 +
 +                      if (num_symlinks++ > MAXSYMLINKS) {
 +                              errno = ELOOP;
  
 -                      if (chdir(sb.buf)) {
                                if (die_on_error)
 -                                      die_errno("Could not switch to '%s'",
 -                                                sb.buf);
 +                                      die("More than %d nested symlinks "
 +                                          "on path '%s'", MAXSYMLINKS, path);
                                else
                                        goto error_out;
                        }
 -              }
 -              if (strbuf_getcwd(&sb)) {
 -                      if (die_on_error)
 -                              die_errno("Could not get current working directory");
 -                      else
 -                              goto error_out;
 -              }
 -
 -              if (last_elem) {
 -                      if (sb.len && !is_dir_sep(sb.buf[sb.len - 1]))
 -                              strbuf_addch(&sb, '/');
 -                      strbuf_addstr(&sb, last_elem);
 -                      free(last_elem);
 -                      last_elem = NULL;
 -              }
  
 -              if (!lstat(sb.buf, &st) && S_ISLNK(st.st_mode)) {
 -                      struct strbuf next_sb = STRBUF_INIT;
 -                      ssize_t len = strbuf_readlink(&next_sb, sb.buf, 0);
 +                      len = strbuf_readlink(&symlink, resolved->buf,
 +                                            st.st_size);
                        if (len < 0) {
                                if (die_on_error)
                                        die_errno("Invalid symlink '%s'",
 -                                                sb.buf);
 +                                                resolved->buf);
                                else
                                        goto error_out;
                        }
 -                      strbuf_swap(&sb, &next_sb);
 -                      strbuf_release(&next_sb);
 -              } else
 -                      break;
 +
 +                      if (is_absolute_path(symlink.buf)) {
 +                              /* absolute symlink; set resolved to root */
 +                              get_root_part(resolved, &symlink);
 +                      } else {
 +                              /*
 +                               * relative symlink
 +                               * strip off the last component since it will
 +                               * be replaced with the contents of the symlink
 +                               */
 +                              strip_last_component(resolved);
 +                      }
 +
 +                      /*
 +                       * if there are still remaining components to resolve
 +                       * then append them to symlink
 +                       */
 +                      if (remaining.len) {
 +                              strbuf_addch(&symlink, '/');
 +                              strbuf_addbuf(&symlink, &remaining);
 +                      }
 +
 +                      /*
 +                       * use the symlink as the remaining components that
 +                       * need to be resloved
 +                       */
 +                      strbuf_swap(&symlink, &remaining);
 +              }
        }
  
 -      retval = sb.buf;
 +      retval = resolved->buf;
 +
  error_out:
 -      free(last_elem);
 -      if (cwd.len && chdir(cwd.buf))
 -              die_errno("Could not change back to '%s'", cwd.buf);
 -      strbuf_release(&cwd);
 +      strbuf_release(&remaining);
 +      strbuf_release(&next);
 +      strbuf_release(&symlink);
 +
 +      if (!retval)
 +              strbuf_reset(resolved);
  
        return retval;
  }
  
  const char *real_path(const char *path)
  {
 -      return real_path_internal(path, 1);
 +      static struct strbuf realpath = STRBUF_INIT;
 +      return strbuf_realpath(&realpath, path, 1);
  }
  
  const char *real_path_if_valid(const char *path)
  {
 -      return real_path_internal(path, 0);
 +      static struct strbuf realpath = STRBUF_INIT;
 +      return strbuf_realpath(&realpath, path, 0);
 +}
 +
 +char *real_pathdup(const char *path)
 +{
 +      struct strbuf realpath = STRBUF_INIT;
 +      char *retval = NULL;
 +
 +      if (strbuf_realpath(&realpath, path, 0))
 +              retval = strbuf_detach(&realpath, NULL);
 +
 +      strbuf_release(&realpath);
 +
 +      return retval;
  }
  
  /*
@@@ -239,6 -152,13 +239,13 @@@ const char *absolute_path(const char *p
        return sb.buf;
  }
  
+ char *absolute_pathdup(const char *path)
+ {
+       struct strbuf sb = STRBUF_INIT;
+       strbuf_add_absolute_path(&sb, path);
+       return strbuf_detach(&sb, NULL);
+ }
  /*
   * Unlike prefix_path, this should be used if the named file does
   * not have to interact with index entry; i.e. name of a random file
diff --combined builtin/clone.c
index 5ef81927a629985aa4f0de6acba326f79747e7aa,e4c1b325741050eeb99c241cb60cba8e653631b2..3f63edbbf94fdf83307621ed822722e5c9f89321
@@@ -41,19 -41,16 +41,19 @@@ static const char * const builtin_clone
  static int option_no_checkout, option_bare, option_mirror, option_single_branch = -1;
  static int option_local = -1, option_no_hardlinks, option_shared, option_recursive;
  static int option_shallow_submodules;
 -static char *option_template, *option_depth;
 +static int deepen;
 +static char *option_template, *option_depth, *option_since;
  static char *option_origin = NULL;
  static char *option_branch = NULL;
 +static struct string_list option_not = STRING_LIST_INIT_NODUP;
  static const char *real_git_dir;
  static char *option_upload_pack = "git-upload-pack";
  static int option_verbosity;
  static int option_progress = -1;
  static enum transport_family family;
  static struct string_list option_config = STRING_LIST_INIT_NODUP;
 -static struct string_list option_reference = STRING_LIST_INIT_NODUP;
 +static struct string_list option_required_reference = STRING_LIST_INIT_NODUP;
 +static struct string_list option_optional_reference = STRING_LIST_INIT_NODUP;
  static int option_dissociate;
  static int max_jobs = -1;
  
@@@ -82,10 -79,8 +82,10 @@@ static struct option builtin_clone_opti
                    N_("number of submodules cloned in parallel")),
        OPT_STRING(0, "template", &option_template, N_("template-directory"),
                   N_("directory from which templates will be used")),
 -      OPT_STRING_LIST(0, "reference", &option_reference, N_("repo"),
 +      OPT_STRING_LIST(0, "reference", &option_required_reference, N_("repo"),
                        N_("reference repository")),
 +      OPT_STRING_LIST(0, "reference-if-able", &option_optional_reference,
 +                      N_("repo"), N_("reference repository")),
        OPT_BOOL(0, "dissociate", &option_dissociate,
                 N_("use --reference only while cloning")),
        OPT_STRING('o', "origin", &option_origin, N_("name"),
                   N_("path to git-upload-pack on the remote")),
        OPT_STRING(0, "depth", &option_depth, N_("depth"),
                    N_("create a shallow clone of that depth")),
 +      OPT_STRING(0, "shallow-since", &option_since, N_("time"),
 +                  N_("create a shallow clone since a specific time")),
 +      OPT_STRING_LIST(0, "shallow-exclude", &option_not, N_("revision"),
 +                      N_("deepen history of shallow clone, excluding rev")),
        OPT_BOOL(0, "single-branch", &option_single_branch,
                    N_("clone only one branch, HEAD or --branch")),
        OPT_BOOL(0, "shallow-submodules", &option_shallow_submodules,
@@@ -170,7 -161,7 +170,7 @@@ static char *get_repo_path(const char *
  
        strbuf_addstr(&path, repo);
        raw = get_repo_path_1(&path, is_bundle);
-       canon = raw ? xstrdup(absolute_path(raw)) : NULL;
+       canon = raw ? absolute_pathdup(raw) : NULL;
        strbuf_release(&path);
        return canon;
  }
@@@ -291,37 -282,50 +291,37 @@@ static void strip_trailing_slashes(cha
  
  static int add_one_reference(struct string_list_item *item, void *cb_data)
  {
 -      char *ref_git;
 -      const char *repo;
 -      struct strbuf alternate = STRBUF_INIT;
 -
 -      /* Beware: read_gitfile(), real_path() and mkpath() return static buffer */
 -      ref_git = xstrdup(real_path(item->string));
 -
 -      repo = read_gitfile(ref_git);
 -      if (!repo)
 -              repo = read_gitfile(mkpath("%s/.git", ref_git));
 -      if (repo) {
 -              free(ref_git);
 -              ref_git = xstrdup(repo);
 -      }
 +      struct strbuf err = STRBUF_INIT;
 +      int *required = cb_data;
 +      char *ref_git = compute_alternate_path(item->string, &err);
  
 -      if (!repo && is_directory(mkpath("%s/.git/objects", ref_git))) {
 -              char *ref_git_git = mkpathdup("%s/.git", ref_git);
 -              free(ref_git);
 -              ref_git = ref_git_git;
 -      } else if (!is_directory(mkpath("%s/objects", ref_git))) {
 +      if (!ref_git) {
 +              if (*required)
 +                      die("%s", err.buf);
 +              else
 +                      fprintf(stderr,
 +                              _("info: Could not add alternate for '%s': %s\n"),
 +                              item->string, err.buf);
 +      } else {
                struct strbuf sb = STRBUF_INIT;
 -              if (get_common_dir(&sb, ref_git))
 -                      die(_("reference repository '%s' as a linked checkout is not supported yet."),
 -                          item->string);
 -              die(_("reference repository '%s' is not a local repository."),
 -                  item->string);
 +              strbuf_addf(&sb, "%s/objects", ref_git);
 +              add_to_alternates_file(sb.buf);
 +              strbuf_release(&sb);
        }
  
 -      if (!access(mkpath("%s/shallow", ref_git), F_OK))
 -              die(_("reference repository '%s' is shallow"), item->string);
 -
 -      if (!access(mkpath("%s/info/grafts", ref_git), F_OK))
 -              die(_("reference repository '%s' is grafted"), item->string);
 -
 -      strbuf_addf(&alternate, "%s/objects", ref_git);
 -      add_to_alternates_file(alternate.buf);
 -      strbuf_release(&alternate);
 +      strbuf_release(&err);
        free(ref_git);
        return 0;
  }
  
  static void setup_reference(void)
  {
 -      for_each_string_list(&option_reference, add_one_reference, NULL);
 +      int required = 1;
 +      for_each_string_list(&option_required_reference,
 +                           add_one_reference, &required);
 +      required = 0;
 +      for_each_string_list(&option_optional_reference,
 +                           add_one_reference, &required);
  }
  
  static void copy_alternates(struct strbuf *src, struct strbuf *dst,
@@@ -679,7 -683,7 +679,7 @@@ static void update_head(const struct re
        }
  }
  
 -static int checkout(void)
 +static int checkout(int submodule_progress)
  {
        unsigned char sha1[20];
        char *head;
        setup_work_tree();
  
        lock_file = xcalloc(1, sizeof(struct lock_file));
 -      hold_locked_index(lock_file, 1);
 +      hold_locked_index(lock_file, LOCK_DIE_ON_ERROR);
  
        memset(&opts, 0, sizeof opts);
        opts.update = 1;
                if (max_jobs != -1)
                        argv_array_pushf(&args, "--jobs=%d", max_jobs);
  
 +              if (submodule_progress)
 +                      argv_array_push(&args, "--progress");
 +
                err = run_command_v_opt(args.argv, RUN_GIT_CMD);
                argv_array_clear(&args);
        }
@@@ -853,7 -854,6 +853,7 @@@ int cmd_clone(int argc, const char **ar
        const char *src_ref_prefix = "refs/heads/";
        struct remote *remote;
        int err = 0, complete_refs_before_fetch = 1;
 +      int submodule_progress;
  
        struct refspec *refspec;
        const char *fetch_pattern;
                usage_msg_opt(_("You must specify a repository to clone."),
                        builtin_clone_usage, builtin_clone_options);
  
 +      if (option_depth || option_since || option_not.nr)
 +              deepen = 1;
        if (option_single_branch == -1)
 -              option_single_branch = option_depth ? 1 : 0;
 +              option_single_branch = deepen ? 1 : 0;
  
        if (option_mirror)
                option_bare = 1;
  
        path = get_repo_path(repo_name, &is_bundle);
        if (path)
-               repo = xstrdup(absolute_path(repo_name));
+               repo = absolute_pathdup(repo_name);
        else if (!strchr(repo_name, ':'))
                die(_("repository '%s' does not exist"), repo_name);
        else
                set_git_work_tree(work_tree);
        }
  
 -      junk_git_dir = git_dir;
 +      junk_git_dir = real_git_dir ? real_git_dir : git_dir;
        if (safe_create_leading_directories_const(git_dir) < 0)
                die(_("could not create leading directories of '%s'"), git_dir);
  
 -      set_git_dir_init(git_dir, real_git_dir, 0);
 -      if (real_git_dir) {
 -              git_dir = real_git_dir;
 -              junk_git_dir = real_git_dir;
 -      }
 -
        if (0 <= option_verbosity) {
                if (option_bare)
                        fprintf(stderr, _("Cloning into bare repository '%s'...\n"), dir);
                else
                        fprintf(stderr, _("Cloning into '%s'...\n"), dir);
        }
 -      init_db(option_template, INIT_DB_QUIET);
 +
 +      if (option_recursive) {
 +              if (option_required_reference.nr &&
 +                  option_optional_reference.nr)
 +                      die(_("clone --recursive is not compatible with "
 +                            "both --reference and --reference-if-able"));
 +              else if (option_required_reference.nr) {
 +                      string_list_append(&option_config,
 +                              "submodule.alternateLocation=superproject");
 +                      string_list_append(&option_config,
 +                              "submodule.alternateErrorStrategy=die");
 +              } else if (option_optional_reference.nr) {
 +                      string_list_append(&option_config,
 +                              "submodule.alternateLocation=superproject");
 +                      string_list_append(&option_config,
 +                              "submodule.alternateErrorStrategy=info");
 +              }
 +      }
 +
 +      init_db(git_dir, real_git_dir, option_template, INIT_DB_QUIET);
 +
 +      if (real_git_dir)
 +              git_dir = real_git_dir;
 +
        write_config(&option_config);
  
        git_config(git_default_config, NULL);
        git_config_set(key.buf, repo);
        strbuf_reset(&key);
  
 -      if (option_reference.nr)
 +      if (option_required_reference.nr || option_optional_reference.nr)
                setup_reference();
  
        fetch_pattern = value.buf;
        if (is_local) {
                if (option_depth)
                        warning(_("--depth is ignored in local clones; use file:// instead."));
 +              if (option_since)
 +                      warning(_("--shallow-since is ignored in local clones; use file:// instead."));
 +              if (option_not.nr)
 +                      warning(_("--shallow-exclude is ignored in local clones; use file:// instead."));
                if (!access(mkpath("%s/shallow", path), F_OK)) {
                        if (option_local > 0)
                                warning(_("source repository is shallow, ignoring --local"));
        if (option_depth)
                transport_set_option(transport, TRANS_OPT_DEPTH,
                                     option_depth);
 +      if (option_since)
 +              transport_set_option(transport, TRANS_OPT_DEEPEN_SINCE,
 +                                   option_since);
 +      if (option_not.nr)
 +              transport_set_option(transport, TRANS_OPT_DEEPEN_NOT,
 +                                   (const char *)&option_not);
        if (option_single_branch)
                transport_set_option(transport, TRANS_OPT_FOLLOWTAGS, "1");
  
                transport_set_option(transport, TRANS_OPT_UPLOADPACK,
                                     option_upload_pack);
  
 -      if (transport->smart_options && !option_depth)
 +      if (transport->smart_options && !deepen)
                transport->smart_options->check_self_contained_and_connected = 1;
  
        refs = transport_get_remote_refs(transport);
  
        update_head(our_head_points_at, remote_head, reflog_msg.buf);
  
 +      /*
 +       * We want to show progress for recursive submodule clones iff
 +       * we did so for the main clone. But only the transport knows
 +       * the final decision for this flag, so we need to rescue the value
 +       * before we free the transport.
 +       */
 +      submodule_progress = transport->progress;
 +
        transport_unlock_pack(transport);
        transport_disconnect(transport);
  
        }
  
        junk_mode = JUNK_LEAVE_REPO;
 -      err = checkout();
 +      err = checkout(submodule_progress);
  
        strbuf_release(&reflog_msg);
        strbuf_release(&branch_top);
index 74614a951e8bb8aef4ed0ef07665f8ec0e43cc78,c80f113521ca078e869dbe8f2f975aef95559992..899dc334e323a53f3e8a2981a1f8140f55f136a9
@@@ -95,8 -95,6 +95,8 @@@ static int chop_last_dir(char **remoteu
   * NEEDSWORK: This works incorrectly on the domain and protocol part.
   * remote_url      url              outcome          expectation
   * http://a.com/b  ../c             http://a.com/c   as is
 + * http://a.com/b/ ../c             http://a.com/c   same as previous line, but
 + *                                                   ignore trailing slash in url
   * http://a.com/b  ../../c          http://c         error out
   * http://a.com/b  ../../../c       http:/c          error out
   * http://a.com/b  ../../../../c    http:c           error out
@@@ -115,8 -113,8 +115,8 @@@ static char *relative_url(const char *r
        struct strbuf sb = STRBUF_INIT;
        size_t len = strlen(remoteurl);
  
 -      if (is_dir_sep(remoteurl[len]))
 -              remoteurl[len] = '\0';
 +      if (is_dir_sep(remoteurl[len-1]))
 +              remoteurl[len-1] = '\0';
  
        if (!url_is_local_not_ssh(remoteurl) || is_absolute_path(remoteurl))
                is_relative = 0;
        }
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s%s%s", remoteurl, colonsep ? ":" : "/", url);
 +      if (ends_with(url, "/"))
 +              strbuf_setlen(&sb, sb.len - 1);
        free(remoteurl);
  
        if (starts_with_dot_slash(sb.buf))
@@@ -300,8 -296,7 +300,8 @@@ static int module_list(int argc, const 
                if (ce_stage(ce))
                        printf("%06o %s U\t", ce->ce_mode, sha1_to_hex(null_sha1));
                else
 -                      printf("%06o %s %d\t", ce->ce_mode, sha1_to_hex(ce->sha1), ce_stage(ce));
 +                      printf("%06o %s %d\t", ce->ce_mode,
 +                             oid_to_hex(&ce->oid), ce_stage(ce));
  
                utf8_fprintf(stdout, "%s\n", ce->name);
        }
@@@ -317,12 -312,8 +317,12 @@@ static void init_submodule(const char *
        /* Only loads from .gitmodules, no overlay with .git/config */
        gitmodules_config();
  
 -      if (prefix) {
 -              strbuf_addf(&sb, "%s%s", prefix, path);
 +      if (prefix && get_super_prefix())
 +              die("BUG: cannot have prefix and superprefix");
 +      else if (prefix)
 +              displaypath = xstrdup(relative_path(path, prefix, &sb));
 +      else if (get_super_prefix()) {
 +              strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
                displaypath = strbuf_detach(&sb, NULL);
        } else
                displaypath = xstrdup(path);
@@@ -407,6 -398,9 +407,6 @@@ static int module_init(int argc, const 
        int i;
  
        struct option module_init_options[] = {
 -              OPT_STRING(0, "prefix", &prefix,
 -                         N_("path"),
 -                         N_("alternative anchor for relative paths")),
                OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
                OPT_END()
        };
@@@ -448,8 -442,7 +448,8 @@@ static int module_name(int argc, const 
  }
  
  static int clone_submodule(const char *path, const char *gitdir, const char *url,
 -                         const char *depth, const char *reference, int quiet)
 +                         const char *depth, struct string_list *reference,
 +                         int quiet, int progress)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
  
        argv_array_push(&cp.args, "--no-checkout");
        if (quiet)
                argv_array_push(&cp.args, "--quiet");
 +      if (progress)
 +              argv_array_push(&cp.args, "--progress");
        if (depth && *depth)
                argv_array_pushl(&cp.args, "--depth", depth, NULL);
 -      if (reference && *reference)
 -              argv_array_pushl(&cp.args, "--reference", reference, NULL);
 +      if (reference->nr) {
 +              struct string_list_item *item;
 +              for_each_string_list_item(item, reference)
 +                      argv_array_pushl(&cp.args, "--reference",
 +                                       item->string, NULL);
 +      }
        if (gitdir && *gitdir)
                argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
  
        return run_command(&cp);
  }
  
 +struct submodule_alternate_setup {
 +      const char *submodule_name;
 +      enum SUBMODULE_ALTERNATE_ERROR_MODE {
 +              SUBMODULE_ALTERNATE_ERROR_DIE,
 +              SUBMODULE_ALTERNATE_ERROR_INFO,
 +              SUBMODULE_ALTERNATE_ERROR_IGNORE
 +      } error_mode;
 +      struct string_list *reference;
 +};
 +#define SUBMODULE_ALTERNATE_SETUP_INIT { NULL, \
 +      SUBMODULE_ALTERNATE_ERROR_IGNORE, NULL }
 +
 +static int add_possible_reference_from_superproject(
 +              struct alternate_object_database *alt, void *sas_cb)
 +{
 +      struct submodule_alternate_setup *sas = sas_cb;
 +
 +      /*
 +       * If the alternate object store is another repository, try the
 +       * standard layout with .git/(modules/<name>)+/objects
 +       */
 +      if (ends_with(alt->path, "/objects")) {
 +              char *sm_alternate;
 +              struct strbuf sb = STRBUF_INIT;
 +              struct strbuf err = STRBUF_INIT;
 +              strbuf_add(&sb, alt->path, strlen(alt->path) - strlen("objects"));
 +
 +              /*
 +               * We need to end the new path with '/' to mark it as a dir,
 +               * otherwise a submodule name containing '/' will be broken
 +               * as the last part of a missing submodule reference would
 +               * be taken as a file name.
 +               */
 +              strbuf_addf(&sb, "modules/%s/", sas->submodule_name);
 +
 +              sm_alternate = compute_alternate_path(sb.buf, &err);
 +              if (sm_alternate) {
 +                      string_list_append(sas->reference, xstrdup(sb.buf));
 +                      free(sm_alternate);
 +              } else {
 +                      switch (sas->error_mode) {
 +                      case SUBMODULE_ALTERNATE_ERROR_DIE:
 +                              die(_("submodule '%s' cannot add alternate: %s"),
 +                                  sas->submodule_name, err.buf);
 +                      case SUBMODULE_ALTERNATE_ERROR_INFO:
 +                              fprintf(stderr, _("submodule '%s' cannot add alternate: %s"),
 +                                      sas->submodule_name, err.buf);
 +                      case SUBMODULE_ALTERNATE_ERROR_IGNORE:
 +                              ; /* nothing */
 +                      }
 +              }
 +              strbuf_release(&sb);
 +      }
 +
 +      return 0;
 +}
 +
 +static void prepare_possible_alternates(const char *sm_name,
 +              struct string_list *reference)
 +{
 +      char *sm_alternate = NULL, *error_strategy = NULL;
 +      struct submodule_alternate_setup sas = SUBMODULE_ALTERNATE_SETUP_INIT;
 +
 +      git_config_get_string("submodule.alternateLocation", &sm_alternate);
 +      if (!sm_alternate)
 +              return;
 +
 +      git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
 +
 +      if (!error_strategy)
 +              error_strategy = xstrdup("die");
 +
 +      sas.submodule_name = sm_name;
 +      sas.reference = reference;
 +      if (!strcmp(error_strategy, "die"))
 +              sas.error_mode = SUBMODULE_ALTERNATE_ERROR_DIE;
 +      else if (!strcmp(error_strategy, "info"))
 +              sas.error_mode = SUBMODULE_ALTERNATE_ERROR_INFO;
 +      else if (!strcmp(error_strategy, "ignore"))
 +              sas.error_mode = SUBMODULE_ALTERNATE_ERROR_IGNORE;
 +      else
 +              die(_("Value '%s' for submodule.alternateErrorStrategy is not recognized"), error_strategy);
 +
 +      if (!strcmp(sm_alternate, "superproject"))
 +              foreach_alt_odb(add_possible_reference_from_superproject, &sas);
 +      else if (!strcmp(sm_alternate, "no"))
 +              ; /* do nothing */
 +      else
 +              die(_("Value '%s' for submodule.alternateLocation is not recognized"), sm_alternate);
 +
 +      free(sm_alternate);
 +      free(error_strategy);
 +}
 +
  static int module_clone(int argc, const char **argv, const char *prefix)
  {
 -      const char *name = NULL, *url = NULL;
 -      const char *reference = NULL, *depth = NULL;
 +      const char *name = NULL, *url = NULL, *depth = NULL;
        int quiet = 0;
 +      int progress = 0;
        FILE *submodule_dot_git;
        char *p, *path = NULL, *sm_gitdir;
        struct strbuf rel_path = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
 +      struct string_list reference = STRING_LIST_INIT_NODUP;
 +      char *sm_alternate = NULL, *error_strategy = NULL;
  
        struct option module_clone_options[] = {
                OPT_STRING(0, "prefix", &prefix,
                OPT_STRING(0, "url", &url,
                           N_("string"),
                           N_("url where to clone the submodule from")),
 -              OPT_STRING(0, "reference", &reference,
 -                         N_("string"),
 +              OPT_STRING_LIST(0, "reference", &reference,
 +                         N_("repo"),
                           N_("reference repository")),
                OPT_STRING(0, "depth", &depth,
                           N_("string"),
                           N_("depth for shallow clones")),
                OPT__QUIET(&quiet, "Suppress output for cloning a submodule"),
 +              OPT_BOOL(0, "progress", &progress,
 +                         N_("force cloning progress")),
                OPT_END()
        };
  
                                   module_clone_options);
  
        strbuf_addf(&sb, "%s/modules/%s", get_git_dir(), name);
-       sm_gitdir = xstrdup(absolute_path(sb.buf));
+       sm_gitdir = absolute_pathdup(sb.buf);
        strbuf_reset(&sb);
  
        if (!is_absolute_path(path)) {
        if (!file_exists(sm_gitdir)) {
                if (safe_create_leading_directories_const(sm_gitdir) < 0)
                        die(_("could not create directory '%s'"), sm_gitdir);
 -              if (clone_submodule(path, sm_gitdir, url, depth, reference, quiet))
 +
 +              prepare_possible_alternates(name, &reference);
 +
 +              if (clone_submodule(path, sm_gitdir, url, depth, &reference,
 +                                  quiet, progress))
                        die(_("clone of '%s' into submodule path '%s' failed"),
                            url, path);
        } else {
                die(_("could not get submodule directory for '%s'"), path);
        git_config_set_in_file(p, "core.worktree",
                               relative_path(path, sm_gitdir, &rel_path));
 +
 +      /* setup alternateLocation and alternateErrorStrategy in the cloned submodule if needed */
 +      git_config_get_string("submodule.alternateLocation", &sm_alternate);
 +      if (sm_alternate)
 +              git_config_set_in_file(p, "submodule.alternateLocation",
 +                                         sm_alternate);
 +      git_config_get_string("submodule.alternateErrorStrategy", &error_strategy);
 +      if (error_strategy)
 +              git_config_set_in_file(p, "submodule.alternateErrorStrategy",
 +                                         error_strategy);
 +
 +      free(sm_alternate);
 +      free(error_strategy);
 +
        strbuf_release(&sb);
        strbuf_release(&rel_path);
        free(sm_gitdir);
@@@ -706,10 -577,9 +706,10 @@@ struct submodule_update_clone 
        struct submodule_update_strategy update;
  
        /* configuration parameters which are passed on to the children */
 +      int progress;
        int quiet;
        int recommend_shallow;
 -      const char *reference;
 +      struct string_list references;
        const char *depth;
        const char *recursive_prefix;
        const char *prefix;
        int failed_clones_nr, failed_clones_alloc;
  };
  #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
 -      SUBMODULE_UPDATE_STRATEGY_INIT, 0, -1, NULL, NULL, NULL, NULL, \
 +      SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, \
 +      NULL, NULL, NULL, \
        STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
  
  
@@@ -814,7 -683,7 +814,7 @@@ static int prepare_to_clone_next_submod
  
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
 -                      sha1_to_hex(ce->sha1), ce_stage(ce),
 +                      oid_to_hex(&ce->oid), ce_stage(ce),
                        needs_cloning, ce->name);
        string_list_append(&suc->projectlines, sb.buf);
  
        child->err = -1;
        argv_array_push(&child->args, "submodule--helper");
        argv_array_push(&child->args, "clone");
 +      if (suc->progress)
 +              argv_array_push(&child->args, "--progress");
        if (suc->quiet)
                argv_array_push(&child->args, "--quiet");
        if (suc->prefix)
        argv_array_pushl(&child->args, "--path", sub->path, NULL);
        argv_array_pushl(&child->args, "--name", sub->name, NULL);
        argv_array_pushl(&child->args, "--url", url, NULL);
 -      if (suc->reference)
 -              argv_array_push(&child->args, suc->reference);
 +      if (suc->references.nr) {
 +              struct string_list_item *item;
 +              for_each_string_list_item(item, &suc->references)
 +                      argv_array_pushl(&child->args, "--reference", item->string, NULL);
 +      }
        if (suc->depth)
                argv_array_push(&child->args, suc->depth);
  
@@@ -966,7 -830,7 +966,7 @@@ static int update_clone(int argc, cons
                OPT_STRING(0, "update", &update,
                           N_("string"),
                           N_("rebase, merge, checkout or none")),
 -              OPT_STRING(0, "reference", &suc.reference, N_("repo"),
 +              OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
                           N_("reference repository")),
                OPT_STRING(0, "depth", &suc.depth, "<depth>",
                           N_("Create a shallow clone truncated to the "
                OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
                            N_("whether the initial clone should follow the shallow recommendation")),
                OPT__QUIET(&suc.quiet, N_("don't print cloning progress")),
 +              OPT_BOOL(0, "progress", &suc.progress,
 +                          N_("force cloning progress")),
                OPT_END()
        };
  
@@@ -1092,62 -954,21 +1092,62 @@@ static int resolve_remote_submodule_bra
        return 0;
  }
  
 +static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
 +{
 +      int i;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +      unsigned flags = ABSORB_GITDIR_RECURSE_SUBMODULES;
 +
 +      struct option embed_gitdir_options[] = {
 +              OPT_STRING(0, "prefix", &prefix,
 +                         N_("path"),
 +                         N_("path into the working tree")),
 +              OPT_BIT(0, "--recursive", &flags, N_("recurse into submodules"),
 +                      ABSORB_GITDIR_RECURSE_SUBMODULES),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule--helper embed-git-dir [<path>...]"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, embed_gitdir_options,
 +                           git_submodule_helper_usage, 0);
 +
 +      gitmodules_config();
 +      git_config(submodule_config, NULL);
 +
 +      if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      for (i = 0; i < list.nr; i++)
 +              absorb_git_dir_into_superproject(prefix,
 +                              list.entries[i]->name, flags);
 +
 +      return 0;
 +}
 +
 +#define SUPPORT_SUPER_PREFIX (1<<0)
 +
  struct cmd_struct {
        const char *cmd;
        int (*fn)(int, const char **, const char *);
 +      unsigned option;
  };
  
  static struct cmd_struct commands[] = {
 -      {"list", module_list},
 -      {"name", module_name},
 -      {"clone", module_clone},
 -      {"update-clone", update_clone},
 -      {"relative-path", resolve_relative_path},
 -      {"resolve-relative-url", resolve_relative_url},
 -      {"resolve-relative-url-test", resolve_relative_url_test},
 -      {"init", module_init},
 -      {"remote-branch", resolve_remote_submodule_branch}
 +      {"list", module_list, 0},
 +      {"name", module_name, 0},
 +      {"clone", module_clone, 0},
 +      {"update-clone", update_clone, 0},
 +      {"relative-path", resolve_relative_path, 0},
 +      {"resolve-relative-url", resolve_relative_url, 0},
 +      {"resolve-relative-url-test", resolve_relative_url_test, 0},
 +      {"init", module_init, SUPPORT_SUPER_PREFIX},
 +      {"remote-branch", resolve_remote_submodule_branch, 0},
 +      {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
  };
  
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
                die(_("submodule--helper subcommand must be "
                      "called with a subcommand"));
  
 -      for (i = 0; i < ARRAY_SIZE(commands); i++)
 -              if (!strcmp(argv[1], commands[i].cmd))
 +      for (i = 0; i < ARRAY_SIZE(commands); i++) {
 +              if (!strcmp(argv[1], commands[i].cmd)) {
 +                      if (get_super_prefix() &&
 +                          !(commands[i].option & SUPPORT_SUPER_PREFIX))
 +                              die(_("%s doesn't support --super-prefix"),
 +                                  commands[i].cmd);
                        return commands[i].fn(argc - 1, argv + 1, prefix);
 +              }
 +      }
  
        die(_("'%s' is not a valid submodule--helper "
              "subcommand"), argv[1]);
diff --combined cache.h
index 674ae7e662a5dc79054d8f5b3eb3e83da198dcf6,f481e61f66870d9574bc8a1e82dbc1ec2240384a..8c77b8c543269a3f2c0b3e4149830f79176fccde
+++ b/cache.h
@@@ -173,7 -173,7 +173,7 @@@ struct cache_entry 
        unsigned int ce_flags;
        unsigned int ce_namelen;
        unsigned int index;     /* for link extension */
 -      unsigned char sha1[20];
 +      struct object_id oid;
        char name[FLEX_ARRAY]; /* more */
  };
  
@@@ -409,7 -409,6 +409,7 @@@ static inline enum object_type object_t
  #define GIT_NAMESPACE_ENVIRONMENT "GIT_NAMESPACE"
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
 +#define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
  #define GIT_GLOB_PATHSPECS_ENVIRONMENT "GIT_GLOB_PATHSPECS"
  #define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
  #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
 +#define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
  
  /*
   * This environment variable is expected to contain a boolean indicating
   */
  extern const char * const local_repo_env[];
  
 +/*
 + * Returns true iff we have a configured git repository (either via
 + * setup_git_directory, or in the environment via $GIT_DIR).
 + */
 +int have_git_dir(void);
 +
  extern int is_bare_repository_cfg;
  extern int is_bare_repository(void);
  extern int is_inside_git_dir(void);
@@@ -477,7 -469,6 +477,7 @@@ extern int get_common_dir_noenv(struct 
  extern int get_common_dir(struct strbuf *sb, const char *gitdir);
  extern const char *get_git_namespace(void);
  extern const char *strip_namespace(const char *namespaced_ref);
 +extern const char *get_super_prefix(void);
  extern const char *get_git_work_tree(void);
  
  /*
@@@ -514,6 -505,7 +514,6 @@@ extern void set_git_work_tree(const cha
  
  #define ALTERNATE_DB_ENVIRONMENT "GIT_ALTERNATE_OBJECT_DIRECTORIES"
  
 -extern const char **get_pathspec(const char *prefix, const char **pathspec);
  extern void setup_work_tree(void);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
@@@ -528,10 -520,9 +528,10 @@@ extern void verify_non_filename(const c
  extern int path_inside_repo(const char *prefix, const char *path);
  
  #define INIT_DB_QUIET 0x0001
 +#define INIT_DB_EXIST_OK 0x0002
  
 -extern int set_git_dir_init(const char *git_dir, const char *real_git_dir, int);
 -extern int init_db(const char *template_dir, unsigned int flags);
 +extern int init_db(const char *git_dir, const char *real_git_dir,
 +                 const char *template_dir, unsigned int flags);
  
  extern void sanitize_stdfds(void);
  extern int daemonize(void);
@@@ -574,26 -565,7 +574,26 @@@ extern int verify_path(const char *path
  extern int index_dir_exists(struct index_state *istate, const char *name, int namelen);
  extern void adjust_dirname_case(struct index_state *istate, char *name);
  extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
 +
 +/*
 + * Searches for an entry defined by name and namelen in the given index.
 + * If the return value is positive (including 0) it is the position of an
 + * exact match. If the return value is negative, the negated value minus 1
 + * is the position where the entry would be inserted.
 + * Example: The current index consists of these files and its stages:
 + *
 + *   b#0, d#0, f#1, f#3
 + *
 + * index_name_pos(&index, "a", 1) -> -1
 + * index_name_pos(&index, "b", 1) ->  0
 + * index_name_pos(&index, "c", 1) -> -2
 + * index_name_pos(&index, "d", 1) ->  1
 + * index_name_pos(&index, "e", 1) -> -3
 + * index_name_pos(&index, "f", 1) -> -3
 + * index_name_pos(&index, "g", 1) -> -5
 + */
  extern int index_name_pos(const struct index_state *, const char *name, int namelen);
 +
  #define ADD_CACHE_OK_TO_ADD 1         /* Ok to add */
  #define ADD_CACHE_OK_TO_REPLACE 2     /* Ok to replace file/directory */
  #define ADD_CACHE_SKIP_DFCHECK 4      /* Ok to skip DF conflict checks */
  #define ADD_CACHE_KEEP_CACHE_TREE 32  /* Do not invalidate cache-tree */
  extern int add_index_entry(struct index_state *, struct cache_entry *ce, int option);
  extern void rename_index_entry_at(struct index_state *, int pos, const char *new_name);
 +
 +/* Remove entry, return true if there are more entries to go. */
  extern int remove_index_entry_at(struct index_state *, int pos);
 +
  extern void remove_marked_cache_entries(struct index_state *istate);
  extern int remove_file_from_index(struct index_state *, const char *path);
  #define ADD_CACHE_VERBOSE 1
  #define ADD_CACHE_IGNORE_ERRORS       4
  #define ADD_CACHE_IGNORE_REMOVAL 8
  #define ADD_CACHE_INTENT 16
 +/*
 + * These two are used to add the contents of the file at path
 + * to the index, marking the working tree up-to-date by storing
 + * the cached stat info in the resulting cache entry.  A caller
 + * that has already run lstat(2) on the path can call
 + * add_to_index(), and all others can call add_file_to_index();
 + * the latter will do necessary lstat(2) internally before
 + * calling the former.
 + */
  extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
  extern int add_file_to_index(struct index_state *, const char *path, int flags);
 +
  extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
  extern int chmod_index_entry(struct index_state *, struct cache_entry *ce, char flip);
  extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
  extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
  extern int index_name_is_other(const struct index_state *, const char *, int);
 -extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
 +extern void *read_blob_data_from_index(const struct index_state *, const char *, unsigned long *);
  
  /* do stat comparison even if CE_VALID is true */
  #define CE_MATCH_IGNORE_VALID         01
@@@ -701,22 -660,15 +701,22 @@@ extern const char *git_attributes_file
  extern const char *git_hooks_path;
  extern int zlib_compression_level;
  extern int core_compression_level;
 -extern int core_compression_seen;
 +extern int pack_compression_level;
  extern size_t packed_git_window_size;
  extern size_t packed_git_limit;
  extern size_t delta_base_cache_limit;
  extern unsigned long big_file_threshold;
  extern unsigned long pack_size_limit_cfg;
  
 +/*
 + * Accessors for the core.sharedrepository config which lazy-load the value
 + * from the config (if not already set). The "reset" function can be
 + * used to unset "set" or cached value, meaning that the value will be loaded
 + * fresh from the config file on the next call to get_shared_repository().
 + */
  void set_shared_repository(int value);
  int get_shared_repository(void);
 +void reset_shared_repository(void);
  
  /*
   * Do replace refs need to be checked this run?  This variable is
@@@ -869,8 -821,8 +869,8 @@@ extern void strbuf_git_common_path(stru
        __attribute__((format (printf, 2, 3)));
  extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
        __attribute__((format (printf, 2, 3)));
 -extern void strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 -                                    const char *fmt, ...)
 +extern int strbuf_git_path_submodule(struct strbuf *sb, const char *path,
 +                                   const char *fmt, ...)
        __attribute__((format (printf, 3, 4)));
  extern char *git_pathdup(const char *fmt, ...)
        __attribute__((format (printf, 1, 2)));
@@@ -934,8 -886,8 +934,8 @@@ extern char *sha1_pack_index_name(cons
   * The result will be at least `len` characters long, and will be NUL
   * terminated.
   *
 - * The non-`_r` version returns a static buffer which will be overwritten by
 - * subsequent calls.
 + * The non-`_r` version returns a static buffer which remains valid until 4
 + * more calls to find_unique_abbrev are made.
   *
   * The `_r` variant writes to a buffer supplied by the caller, which must be at
   * least `GIT_SHA1_HEXSZ + 1` bytes. The return value is the number of bytes
@@@ -1003,39 -955,22 +1003,39 @@@ static inline void oidclr(struct object
  #define EMPTY_TREE_SHA1_BIN_LITERAL \
         "\x4b\x82\x5d\xc6\x42\xcb\x6e\xb9\xa0\x60" \
         "\xe5\x4b\xf8\xd6\x92\x88\xfb\xee\x49\x04"
 -#define EMPTY_TREE_SHA1_BIN \
 -       ((const unsigned char *) EMPTY_TREE_SHA1_BIN_LITERAL)
 +extern const struct object_id empty_tree_oid;
 +#define EMPTY_TREE_SHA1_BIN (empty_tree_oid.hash)
  
  #define EMPTY_BLOB_SHA1_HEX \
        "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391"
  #define EMPTY_BLOB_SHA1_BIN_LITERAL \
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
 -#define EMPTY_BLOB_SHA1_BIN \
 -      ((const unsigned char *) EMPTY_BLOB_SHA1_BIN_LITERAL)
 +extern const struct object_id empty_blob_oid;
 +#define EMPTY_BLOB_SHA1_BIN (empty_blob_oid.hash)
 +
  
  static inline int is_empty_blob_sha1(const unsigned char *sha1)
  {
        return !hashcmp(sha1, EMPTY_BLOB_SHA1_BIN);
  }
  
 +static inline int is_empty_blob_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
 +}
 +
 +static inline int is_empty_tree_sha1(const unsigned char *sha1)
 +{
 +      return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
 +}
 +
 +static inline int is_empty_tree_oid(const struct object_id *oid)
 +{
 +      return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
 +}
 +
 +
  int git_mkstemp(char *path, size_t n, const char *template);
  
  /* set default permissions by passing mode arguments to open(2) */
@@@ -1095,12 -1030,10 +1095,13 @@@ static inline int is_absolute_path(cons
        return is_dir_sep(path[0]) || has_dos_drive_prefix(path);
  }
  int is_directory(const char *);
 +char *strbuf_realpath(struct strbuf *resolved, const char *path,
 +                    int die_on_error);
  const char *real_path(const char *path);
  const char *real_path_if_valid(const char *path);
 +char *real_pathdup(const char *path);
  const char *absolute_path(const char *path);
+ char *absolute_pathdup(const char *path);
  const char *remove_leading_path(const char *in, const char *prefix);
  const char *relative_path(const char *in, const char *prefix, struct strbuf *sb);
  int normalize_path_copy_len(char *dst, const char *src, int *prefix_len);
@@@ -1159,8 -1092,7 +1160,8 @@@ extern int write_sha1_file(const void *
  extern int hash_sha1_file_literally(const void *buf, unsigned long len, const char *type, unsigned char *sha1, unsigned flags);
  extern int pretend_sha1_file(void *, unsigned long, enum object_type, unsigned char *);
  extern int force_object_loose(const unsigned char *sha1, time_t mtime);
 -extern int git_open_noatime(const char *name);
 +extern int git_open_cloexec(const char *name, int flags);
 +#define git_open(name) git_open_cloexec(name, O_RDONLY)
  extern void *map_sha1_file(const unsigned char *sha1, unsigned long *size);
  extern int unpack_sha1_header(git_zstream *stream, unsigned char *map, unsigned long mapsize, void *buffer, unsigned long bufsiz);
  extern int parse_sha1_header(const char *hdr, unsigned long *sizep);
@@@ -1174,19 -1106,6 +1175,19 @@@ extern int finalize_object_file(const c
  
  extern int has_sha1_pack(const unsigned char *sha1);
  
 +/*
 + * Open the loose object at path, check its sha1, and return the contents,
 + * type, and size. If the object is a blob, then "contents" may return NULL,
 + * to allow streaming of large blobs.
 + *
 + * Returns 0 on success, negative on error (details may be written to stderr).
 + */
 +int read_loose_object(const char *path,
 +                    const unsigned char *expected_sha1,
 +                    enum object_type *type,
 +                    unsigned long *size,
 +                    void **contents);
 +
  /*
   * Return true iff we have an object named sha1, whether local or in
   * an alternate object database, and whether packed or loose.  This
@@@ -1238,9 -1157,6 +1239,9 @@@ static inline int hex2chr(const char *s
  #define MINIMUM_ABBREV minimum_abbrev
  #define DEFAULT_ABBREV default_abbrev
  
 +/* used when the code does not know or care what the default abbrev is */
 +#define FALLBACK_DEFAULT_ABBREV 7
 +
  struct object_context {
        unsigned char tree[20];
        char path[PATH_MAX];
  #define GET_SHA1_FOLLOW_SYMLINKS 0100
  #define GET_SHA1_ONLY_TO_DIE    04000
  
 +#define GET_SHA1_DISAMBIGUATORS \
 +      (GET_SHA1_COMMIT | GET_SHA1_COMMITTISH | \
 +      GET_SHA1_TREE | GET_SHA1_TREEISH | \
 +      GET_SHA1_BLOB)
 +
  extern int get_sha1(const char *str, unsigned char *sha1);
  extern int get_sha1_commit(const char *str, unsigned char *sha1);
  extern int get_sha1_committish(const char *str, unsigned char *sha1);
@@@ -1280,8 -1191,6 +1281,8 @@@ extern int get_oid(const char *str, str
  typedef int each_abbrev_fn(const unsigned char *sha1, void *);
  extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
  
 +extern int set_disambiguate_hint_config(const char *var, const char *value);
 +
  /*
   * Try to read a SHA1 in hexadecimal format from the 40 characters
   * starting at hex.  Write the 20-byte result to sha1 in binary form.
@@@ -1309,7 -1218,7 +1310,7 @@@ extern char *sha1_to_hex(const unsigne
  extern char *oid_to_hex(const struct object_id *oid); /* same static buffer as sha1_to_hex */
  
  extern int interpret_branch_name(const char *str, int len, struct strbuf *);
 -extern int get_sha1_mb(const char *str, unsigned char *sha1);
 +extern int get_oid_mb(const char *str, struct object_id *oid);
  
  extern int validate_headref(const char *ref);
  
@@@ -1419,7 -1328,6 +1420,7 @@@ struct checkout 
                 not_new:1,
                 refresh_cache:1;
  };
 +#define CHECKOUT_INIT { NULL, "" }
  
  #define TEMPORARY_FILENAME_LENGTH 25
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
@@@ -1445,46 -1353,15 +1446,46 @@@ extern void remove_scheduled_dirs(void)
  
  extern struct alternate_object_database {
        struct alternate_object_database *next;
 -      char *name;
 -      char base[FLEX_ARRAY]; /* more */
 +
 +      /* see alt_scratch_buf() */
 +      struct strbuf scratch;
 +      size_t base_len;
 +
 +      char path[FLEX_ARRAY];
  } *alt_odb_list;
  extern void prepare_alt_odb(void);
  extern void read_info_alternates(const char * relative_base, int depth);
 -extern void add_to_alternates_file(const char *reference);
 +extern char *compute_alternate_path(const char *path, struct strbuf *err);
  typedef int alt_odb_fn(struct alternate_object_database *, void *);
  extern int foreach_alt_odb(alt_odb_fn, void*);
  
 +/*
 + * Allocate a "struct alternate_object_database" but do _not_ actually
 + * add it to the list of alternates.
 + */
 +struct alternate_object_database *alloc_alt_odb(const char *dir);
 +
 +/*
 + * Add the directory to the on-disk alternates file; the new entry will also
 + * take effect in the current process.
 + */
 +extern void add_to_alternates_file(const char *dir);
 +
 +/*
 + * Add the directory to the in-memory list of alternates (along with any
 + * recursive alternates it points to), but do not modify the on-disk alternates
 + * file.
 + */
 +extern void add_to_alternates_memory(const char *dir);
 +
 +/*
 + * Returns a scratch strbuf pre-filled with the alternate object directory,
 + * including a trailing slash, which can be used to access paths in the
 + * alternate. Always use this over direct access to alt->scratch, as it
 + * cleans up any previous use of the scratch buffer.
 + */
 +extern struct strbuf *alt_scratch_buf(struct alternate_object_database *alt);
 +
  struct pack_window {
        struct pack_window *next;
        unsigned char *base;
@@@ -1541,12 -1418,6 +1542,12 @@@ extern void prepare_packed_git(void)
  extern void reprepare_packed_git(void);
  extern void install_packed_git(struct packed_git *pack);
  
 +/*
 + * Give a rough count of objects in the repository. This sacrifices accuracy
 + * for speed.
 + */
 +unsigned long approximate_object_count(void);
 +
  extern struct packed_git *find_sha1_pack(const unsigned char *sha1,
                                         struct packed_git *packs);
  
@@@ -1693,15 -1564,7 +1694,15 @@@ struct object_info 
                } packed;
        } u;
  };
 +
 +/*
 + * Initializer for a "struct object_info" that wants no items. You may
 + * also memset() the memory to all-zeroes.
 + */
 +#define OBJECT_INFO_INIT {NULL}
 +
  extern int sha1_object_info_extended(const unsigned char *, struct object_info *, unsigned flags);
 +extern int packed_object_info(struct packed_git *pack, off_t offset, struct object_info *);
  
  /* Dumb servers support */
  extern int update_server_info(int);
@@@ -1738,8 -1601,6 +1739,8 @@@ extern int git_default_config(const cha
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
  extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
 +extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
 +                                   const unsigned char *sha1, void *data);
  extern void git_config_push_parameter(const char *text);
  extern int git_config_from_parameters(config_fn_t fn, void *data);
  extern void git_config(config_fn_t fn, void *);
@@@ -1938,6 -1799,7 +1939,6 @@@ extern void write_file(const char *path
  
  /* pager.c */
  extern void setup_pager(void);
 -extern const char *pager_program;
  extern int pager_in_use(void);
  extern int pager_use_color;
  extern int term_columns(void);
diff --combined worktree.c
index 53b4771c04a2b9de15379fdd213f20f213b1be60,8b8097a363ff9a90bc14f7b62079322982f6ba15..d633761575bff4811fa4f3f3822807b1f77f5ecb
@@@ -88,13 -88,21 +88,13 @@@ static struct worktree *get_main_worktr
  
        strbuf_addf(&path, "%s/HEAD", get_git_common_dir());
  
 -      if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
 -              goto done;
 -
 -      worktree = xmalloc(sizeof(struct worktree));
 +      worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
 -      worktree->id = NULL;
        worktree->is_bare = is_bare;
 -      worktree->head_ref = NULL;
        worktree->is_detached = is_detached;
 -      worktree->is_current = 0;
 -      add_head_info(&head_ref, worktree);
 -      worktree->lock_reason = NULL;
 -      worktree->lock_reason_valid = 0;
 +      if (!parse_ref(path.buf, &head_ref, &is_detached))
 +              add_head_info(&head_ref, worktree);
  
 -done:
        strbuf_release(&path);
        strbuf_release(&worktree_path);
        strbuf_release(&head_ref);
@@@ -130,11 -138,16 +130,11 @@@ static struct worktree *get_linked_work
        if (parse_ref(path.buf, &head_ref, &is_detached) < 0)
                goto done;
  
 -      worktree = xmalloc(sizeof(struct worktree));
 +      worktree = xcalloc(1, sizeof(*worktree));
        worktree->path = strbuf_detach(&worktree_path, NULL);
        worktree->id = xstrdup(id);
 -      worktree->is_bare = 0;
 -      worktree->head_ref = NULL;
        worktree->is_detached = is_detached;
 -      worktree->is_current = 0;
        add_head_info(&head_ref, worktree);
 -      worktree->lock_reason = NULL;
 -      worktree->lock_reason_valid = 0;
  
  done:
        strbuf_release(&path);
  
  static void mark_current_worktree(struct worktree **worktrees)
  {
-       char *git_dir = xstrdup(absolute_path(get_git_dir()));
+       char *git_dir = absolute_pathdup(get_git_dir());
        int i;
  
        for (i = 0; worktrees[i]; i++) {
        free(git_dir);
  }
  
 -struct worktree **get_worktrees(void)
 +static int compare_worktree(const void *a_, const void *b_)
 +{
 +      const struct worktree *const *a = a_;
 +      const struct worktree *const *b = b_;
 +      return fspathcmp((*a)->path, (*b)->path);
 +}
 +
 +struct worktree **get_worktrees(unsigned flags)
  {
        struct worktree **list = NULL;
        struct strbuf path = STRBUF_INIT;
  
        list = xmalloc(alloc * sizeof(struct worktree *));
  
 -      if ((list[counter] = get_main_worktree()))
 -              counter++;
 +      list[counter++] = get_main_worktree();
  
        strbuf_addf(&path, "%s/worktrees", get_git_common_dir());
        dir = opendir(path.buf);
        ALLOC_GROW(list, counter + 1, alloc);
        list[counter] = NULL;
  
 +      if (flags & GWT_SORT_LINKED)
 +              /*
 +               * don't sort the first item (main worktree), which will
 +               * always be the first
 +               */
 +              QSORT(list + 1, counter - 1, compare_worktree);
 +
        mark_current_worktree(list);
        return list;
  }
@@@ -255,7 -255,7 +255,7 @@@ struct worktree *find_worktree(struct w
                return wt;
  
        arg = prefix_filename(prefix, strlen(prefix), arg);
 -      path = xstrdup(real_path(arg));
 +      path = real_pathdup(arg);
        for (; *list; list++)
                if (!fspathcmp(path, real_path((*list)->path)))
                        break;
@@@ -341,7 -341,7 +341,7 @@@ const struct worktree *find_shared_symr
  
        if (worktrees)
                free_worktrees(worktrees);
 -      worktrees = get_worktrees();
 +      worktrees = get_worktrees(0);
  
        for (i = 0; worktrees[i]; i++) {
                struct worktree *wt = worktrees[i];
  
        return existing;
  }
 +
 +int submodule_uses_worktrees(const char *path)
 +{
 +      char *submodule_gitdir;
 +      struct strbuf sb = STRBUF_INIT;
 +      DIR *dir;
 +      struct dirent *d;
 +      int ret = 0;
 +      struct repository_format format;
 +
 +      submodule_gitdir = git_pathdup_submodule(path, "%s", "");
 +      if (!submodule_gitdir)
 +              return 0;
 +
 +      /* The env would be set for the superproject. */
 +      get_common_dir_noenv(&sb, submodule_gitdir);
 +
 +      /*
 +       * The check below is only known to be good for repository format
 +       * version 0 at the time of writing this code.
 +       */
 +      strbuf_addstr(&sb, "/config");
 +      read_repository_format(&format, sb.buf);
 +      if (format.version != 0) {
 +              strbuf_release(&sb);
 +              return 1;
 +      }
 +
 +      /* Replace config by worktrees. */
 +      strbuf_setlen(&sb, sb.len - strlen("config"));
 +      strbuf_addstr(&sb, "worktrees");
 +
 +      /* See if there is any file inside the worktrees directory. */
 +      dir = opendir(sb.buf);
 +      strbuf_release(&sb);
 +      free(submodule_gitdir);
 +
 +      if (!dir)
 +              return 0;
 +
 +      while ((d = readdir(dir)) != NULL) {
 +              if (is_dot_or_dotdot(d->d_name))
 +                      continue;
 +
 +              ret = 1;
 +              break;
 +      }
 +      closedir(dir);
 +      return ret;
 +}