Merge branch 'jk/submodule-name-verify-fix' into jk/submodule-name-verify-fsck
authorJeff King <peff@peff.net>
Tue, 15 May 2018 14:15:18 +0000 (10:15 -0400)
committerJeff King <peff@peff.net>
Tue, 22 May 2018 03:54:28 +0000 (23:54 -0400)
* jk/submodule-name-verify-fix:
verify_path: disallow symlinks in .gitmodules
update-index: stat updated files earlier
verify_path: drop clever fallthrough
skip_prefix: add icase-insensitive variant
is_{hfs,ntfs}_dotgitmodules: add tests
path: match NTFS short names for more .git files
is_hfs_dotgit: match other .git files
is_ntfs_dotgit: use a size_t for traversing string
submodule-config: verify submodule names as paths

Note that this includes two bits of evil-merge:

- there's a new call to verify_path() that doesn't actually
have a mode available. It should be OK to pass "0" here,
since we're just manipulating the untracked cache, not an
actual index entry.

- the lstat() in builtin/update-index.c:update_one() needs
to be updated to handle the fsmonitor case (without this
it still behaves correctly, but does an unnecessary
lstat).

13 files changed:
1  2 
apply.c
builtin/submodule--helper.c
builtin/update-index.c
cache.h
dir.c
git-compat-util.h
git-submodule.sh
path.c
read-cache.c
submodule-config.c
submodule-config.h
t/helper/test-path-utils.c
utf8.c
diff --combined apply.c
index 134dc7ba78cddd99406b78a97898bd8a32393b4c,b96d3755950f09e3c1661b59a3247060388868aa..2d1cfe4dbb563e4601f5fec16d6ae2fe88fee80c
+++ b/apply.c
@@@ -8,7 -8,6 +8,7 @@@
   */
  
  #include "cache.h"
 +#include "config.h"
  #include "blob.h"
  #include "delta.h"
  #include "diff.h"
@@@ -75,10 -74,14 +75,10 @@@ static int parse_ignorewhitespace_optio
  }
  
  int init_apply_state(struct apply_state *state,
 -                   const char *prefix,
 -                   struct lock_file *lock_file)
 +                   const char *prefix)
  {
        memset(state, 0, sizeof(*state));
        state->prefix = prefix;
 -      state->prefix_length = state->prefix ? strlen(state->prefix) : 0;
 -      state->lock_file = lock_file;
 -      state->newfd = -1;
        state->apply = 1;
        state->line_termination = '\n';
        state->p_value = 1;
@@@ -143,6 -146,8 +143,6 @@@ int check_apply_state(struct apply_stat
        }
        if (state->check_index)
                state->unsafe_paths = 0;
 -      if (!state->lock_file)
 -              return error("BUG: state->lock_file should not be NULL");
  
        if (state->apply_verbosity <= verbosity_silent) {
                state->saved_error_routine = get_error_routine();
@@@ -214,7 -219,6 +214,7 @@@ struct patch 
        unsigned int recount:1;
        unsigned int conflicted_threeway:1;
        unsigned int direct_to_threeway:1;
 +      unsigned int crlf_in_old:1;
        struct fragment *fragments;
        char *result;
        size_t resultsize;
@@@ -300,33 -304,52 +300,33 @@@ static uint32_t hash_line(const char *c
  static int fuzzy_matchlines(const char *s1, size_t n1,
                            const char *s2, size_t n2)
  {
 -      const char *last1 = s1 + n1 - 1;
 -      const char *last2 = s2 + n2 - 1;
 -      int result = 0;
 +      const char *end1 = s1 + n1;
 +      const char *end2 = s2 + n2;
  
        /* ignore line endings */
 -      while ((*last1 == '\r') || (*last1 == '\n'))
 -              last1--;
 -      while ((*last2 == '\r') || (*last2 == '\n'))
 -              last2--;
 -
 -      /* skip leading whitespaces, if both begin with whitespace */
 -      if (s1 <= last1 && s2 <= last2 && isspace(*s1) && isspace(*s2)) {
 -              while (isspace(*s1) && (s1 <= last1))
 -                      s1++;
 -              while (isspace(*s2) && (s2 <= last2))
 -                      s2++;
 -      }
 -      /* early return if both lines are empty */
 -      if ((s1 > last1) && (s2 > last2))
 -              return 1;
 -      while (!result) {
 -              result = *s1++ - *s2++;
 -              /*
 -               * Skip whitespace inside. We check for whitespace on
 -               * both buffers because we don't want "a b" to match
 -               * "ab"
 -               */
 -              if (isspace(*s1) && isspace(*s2)) {
 -                      while (isspace(*s1) && s1 <= last1)
 +      while (s1 < end1 && (end1[-1] == '\r' || end1[-1] == '\n'))
 +              end1--;
 +      while (s2 < end2 && (end2[-1] == '\r' || end2[-1] == '\n'))
 +              end2--;
 +
 +      while (s1 < end1 && s2 < end2) {
 +              if (isspace(*s1)) {
 +                      /*
 +                       * Skip whitespace. We check on both buffers
 +                       * because we don't want "a b" to match "ab".
 +                       */
 +                      if (!isspace(*s2))
 +                              return 0;
 +                      while (s1 < end1 && isspace(*s1))
                                s1++;
 -                      while (isspace(*s2) && s2 <= last2)
 +                      while (s2 < end2 && isspace(*s2))
                                s2++;
 -              }
 -              /*
 -               * If we reached the end on one side only,
 -               * lines don't match
 -               */
 -              if (
 -                  ((s2 > last2) && (s1 <= last1)) ||
 -                  ((s1 > last1) && (s2 <= last2)))
 +              } else if (*s1++ != *s2++)
                        return 0;
 -              if ((s1 > last1) && (s2 > last2))
 -                      break;
        }
  
 -      return !result;
 +      /* If we reached the end on one side only, lines don't match. */
 +      return s1 == end1 && s2 == end2;
  }
  
  static void add_line_info(struct image *img, const char *bol, size_t len, unsigned flag)
@@@ -740,6 -763,17 +740,6 @@@ static char *find_name_traditional(stru
        return find_name_common(state, line, def, p_value, line + len, 0);
  }
  
 -static int count_slashes(const char *cp)
 -{
 -      int cnt = 0;
 -      char ch;
 -
 -      while ((ch = *cp++))
 -              if (ch == '/')
 -                      cnt++;
 -      return cnt;
 -}
 -
  /*
   * Given the string after "--- " or "+++ ", guess the appropriate
   * p_value for the given patch.
@@@ -762,11 -796,11 +762,11 @@@ static int guess_p_value(struct apply_s
                 * Does it begin with "a/$our-prefix" and such?  Then this is
                 * very likely to apply to our directory.
                 */
 -              if (!strncmp(name, state->prefix, state->prefix_length))
 +              if (starts_with(name, state->prefix))
                        val = count_slashes(state->prefix);
                else {
                        cp++;
 -                      if (!strncmp(cp, state->prefix, state->prefix_length))
 +                      if (starts_with(cp, state->prefix))
                                val = count_slashes(state->prefix) + 1;
                }
        }
@@@ -788,13 -822,16 +788,13 @@@ static int has_epoch_timestamp(const ch
         * 1970-01-01, and the seconds part must be "00".
         */
        const char stamp_regexp[] =
 -              "^(1969-12-31|1970-01-01)"
 -              " "
 -              "[0-2][0-9]:[0-5][0-9]:00(\\.0+)?"
 +              "^[0-2][0-9]:([0-5][0-9]):00(\\.0+)?"
                " "
                "([-+][0-2][0-9]:?[0-5][0-9])\n";
        const char *timestamp = NULL, *cp, *colon;
        static regex_t *stamp;
        regmatch_t m[10];
 -      int zoneoffset;
 -      int hourminute;
 +      int zoneoffset, epoch_hour, hour, minute;
        int status;
  
        for (cp = nameline; *cp != '\n'; cp++) {
        }
        if (!timestamp)
                return 0;
 +
 +      /*
 +       * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
 +       * (west of GMT) or 1970-01-01 (east of GMT)
 +       */
 +      if (skip_prefix(timestamp, "1969-12-31 ", &timestamp))
 +              epoch_hour = 24;
 +      else if (skip_prefix(timestamp, "1970-01-01 ", &timestamp))
 +              epoch_hour = 0;
 +      else
 +              return 0;
 +
        if (!stamp) {
                stamp = xmalloc(sizeof(*stamp));
                if (regcomp(stamp, stamp_regexp, REG_EXTENDED)) {
                return 0;
        }
  
 +      hour = strtol(timestamp, NULL, 10);
 +      minute = strtol(timestamp + m[1].rm_so, NULL, 10);
 +
        zoneoffset = strtol(timestamp + m[3].rm_so + 1, (char **) &colon, 10);
        if (*colon == ':')
                zoneoffset = zoneoffset * 60 + strtol(colon + 1, NULL, 10);
        if (timestamp[m[3].rm_so] == '-')
                zoneoffset = -zoneoffset;
  
 -      /*
 -       * YYYY-MM-DD hh:mm:ss must be from either 1969-12-31
 -       * (west of GMT) or 1970-01-01 (east of GMT)
 -       */
 -      if ((zoneoffset < 0 && memcmp(timestamp, "1969-12-31", 10)) ||
 -          (0 <= zoneoffset && memcmp(timestamp, "1970-01-01", 10)))
 -              return 0;
 -
 -      hourminute = (strtol(timestamp + 11, NULL, 10) * 60 +
 -                    strtol(timestamp + 14, NULL, 10) -
 -                    zoneoffset);
 -
 -      return ((zoneoffset < 0 && hourminute == 1440) ||
 -              (0 <= zoneoffset && !hourminute));
 +      return hour * 60 + minute - zoneoffset == epoch_hour * 60;
  }
  
  /*
@@@ -950,7 -985,7 +950,7 @@@ static int gitdiff_verify_name(struct a
                }
                free(another);
        } else {
 -              if (!starts_with(line, "/dev/null\n"))
 +              if (!is_dev_null(line))
                        return error(_("git apply: bad git-diff - expected /dev/null on line %d"), state->linenr);
        }
  
@@@ -1637,19 -1672,6 +1637,19 @@@ static void check_whitespace(struct app
        record_ws_error(state, result, line + 1, len - 2, state->linenr);
  }
  
 +/*
 + * Check if the patch has context lines with CRLF or
 + * the patch wants to remove lines with CRLF.
 + */
 +static void check_old_for_crlf(struct patch *patch, const char *line, int len)
 +{
 +      if (len >= 2 && line[len-1] == '\n' && line[len-2] == '\r') {
 +              patch->ws_rule |= WS_CR_AT_EOL;
 +              patch->crlf_in_old = 1;
 +      }
 +}
 +
 +
  /*
   * Parse a unified diff. Note that this really needs to parse each
   * fragment separately, since the only way to know the difference
@@@ -1700,14 -1722,11 +1700,14 @@@ static int parse_fragment(struct apply_
                        if (!deleted && !added)
                                leading++;
                        trailing++;
 +                      check_old_for_crlf(patch, line, len);
                        if (!state->apply_in_reverse &&
                            state->ws_error_action == correct_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
                        break;
                case '-':
 +                      if (!state->apply_in_reverse)
 +                              check_old_for_crlf(patch, line, len);
                        if (state->apply_in_reverse &&
                            state->ws_error_action != nowarn_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
                        trailing = 0;
                        break;
                case '+':
 +                      if (state->apply_in_reverse)
 +                              check_old_for_crlf(patch, line, len);
                        if (!state->apply_in_reverse &&
                            state->ws_error_action != nowarn_ws_error)
                                check_whitespace(state, line, len, patch->ws_rule);
@@@ -2082,16 -2099,17 +2082,16 @@@ static int use_patch(struct apply_stat
        int i;
  
        /* Paths outside are not touched regardless of "--include" */
 -      if (0 < state->prefix_length) {
 -              int pathlen = strlen(pathname);
 -              if (pathlen <= state->prefix_length ||
 -                  memcmp(state->prefix, pathname, state->prefix_length))
 +      if (state->prefix && *state->prefix) {
 +              const char *rest;
 +              if (!skip_prefix(pathname, state->prefix, &rest) || !*rest)
                        return 0;
        }
  
        /* See if it matches any of exclude/include rule */
        for (i = 0; i < state->limit_by_name.nr; i++) {
                struct string_list_item *it = &state->limit_by_name.items[i];
 -              if (!wildmatch(it->string, pathname, 0, NULL))
 +              if (!wildmatch(it->string, pathname, 0))
                        return (it->util != NULL);
        }
  
@@@ -2260,11 -2278,8 +2260,11 @@@ static void show_stats(struct apply_sta
                add, pluses, del, minuses);
  }
  
 -static int read_old_data(struct stat *st, const char *path, struct strbuf *buf)
 +static int read_old_data(struct stat *st, struct patch *patch,
 +                       const char *path, struct strbuf *buf)
  {
 +      int conv_flags = patch->crlf_in_old ?
 +              CONV_EOL_KEEP_CRLF : CONV_EOL_RENORMALIZE;
        switch (st->st_mode & S_IFMT) {
        case S_IFLNK:
                if (strbuf_readlink(buf, path, st->st_size) < 0)
        case S_IFREG:
                if (strbuf_read_file(buf, path, st->st_size) != st->st_size)
                        return error(_("unable to open or read %s"), path);
 -              convert_to_git(path, buf->buf, buf->len, buf, 0);
 +              /*
 +               * "git apply" without "--index/--cached" should never look
 +               * at the index; the target file may not have been added to
 +               * the index yet, and we may not even be in any Git repository.
 +               * Pass NULL to convert_to_git() to stress this; the function
 +               * should never look at the index when explicit crlf option
 +               * is given.
 +               */
 +              convert_to_git(NULL, path, buf->buf, buf->len, buf, conv_flags);
                return 0;
        default:
                return -1;
@@@ -2301,7 -2308,7 +2301,7 @@@ static void update_pre_post_images(stru
                                   size_t len, size_t postlen)
  {
        int i, ctx, reduced;
 -      char *new, *old, *fixed;
 +      char *new_buf, *old_buf, *fixed;
        struct image fixed_preimage;
  
        /*
         * We trust the caller to tell us if the update can be done
         * in place (postlen==0) or not.
         */
 -      old = postimage->buf;
 +      old_buf = postimage->buf;
        if (postlen)
 -              new = postimage->buf = xmalloc(postlen);
 +              new_buf = postimage->buf = xmalloc(postlen);
        else
 -              new = old;
 +              new_buf = old_buf;
        fixed = preimage->buf;
  
        for (i = reduced = ctx = 0; i < postimage->nr; i++) {
                size_t l_len = postimage->line[i].len;
                if (!(postimage->line[i].flag & LINE_COMMON)) {
                        /* an added line -- no counterparts in preimage */
 -                      memmove(new, old, l_len);
 -                      old += l_len;
 -                      new += l_len;
 +                      memmove(new_buf, old_buf, l_len);
 +                      old_buf += l_len;
 +                      new_buf += l_len;
                        continue;
                }
  
                /* a common context -- skip it in the original postimage */
 -              old += l_len;
 +              old_buf += l_len;
  
                /* and find the corresponding one in the fixed preimage */
                while (ctx < preimage->nr &&
  
                /* and copy it in, while fixing the line length */
                l_len = preimage->line[ctx].len;
 -              memcpy(new, fixed, l_len);
 -              new += l_len;
 +              memcpy(new_buf, fixed, l_len);
 +              new_buf += l_len;
                fixed += l_len;
                postimage->line[i].len = l_len;
                ctx++;
        }
  
        if (postlen
 -          ? postlen < new - postimage->buf
 -          : postimage->len < new - postimage->buf)
 +          ? postlen < new_buf - postimage->buf
 +          : postimage->len < new_buf - postimage->buf)
                die("BUG: caller miscounted postlen: asked %d, orig = %d, used = %d",
 -                  (int)postlen, (int) postimage->len, (int)(new - postimage->buf));
 +                  (int)postlen, (int) postimage->len, (int)(new_buf - postimage->buf));
  
        /* Fix the length of the whole thing */
 -      postimage->len = new - postimage->buf;
 +      postimage->len = new_buf - postimage->buf;
        postimage->nr -= reduced;
  }
  
  static int line_by_line_fuzzy_match(struct image *img,
                                    struct image *preimage,
                                    struct image *postimage,
 -                                  unsigned long try,
 -                                  int try_lno,
 +                                  unsigned long current,
 +                                  int current_lno,
                                    int preimage_limit)
  {
        int i;
  
        for (i = 0; i < preimage_limit; i++) {
                size_t prelen = preimage->line[i].len;
 -              size_t imglen = img->line[try_lno+i].len;
 +              size_t imglen = img->line[current_lno+i].len;
  
 -              if (!fuzzy_matchlines(img->buf + try + imgoff, imglen,
 +              if (!fuzzy_matchlines(img->buf + current + imgoff, imglen,
                                      preimage->buf + preoff, prelen))
                        return 0;
                if (preimage->line[i].flag & LINE_COMMON)
         */
        extra_chars = preimage_end - preimage_eof;
        strbuf_init(&fixed, imgoff + extra_chars);
 -      strbuf_add(&fixed, img->buf + try, imgoff);
 +      strbuf_add(&fixed, img->buf + current, imgoff);
        strbuf_add(&fixed, preimage_eof, extra_chars);
        fixed_buf = strbuf_detach(&fixed, &fixed_len);
        update_pre_post_images(preimage, postimage,
@@@ -2455,8 -2462,8 +2455,8 @@@ static int match_fragment(struct apply_
                          struct image *img,
                          struct image *preimage,
                          struct image *postimage,
 -                        unsigned long try,
 -                        int try_lno,
 +                        unsigned long current,
 +                        int current_lno,
                          unsigned ws_rule,
                          int match_beginning, int match_end)
  {
        size_t fixed_len, postlen;
        int preimage_limit;
  
 -      if (preimage->nr + try_lno <= img->nr) {
 +      if (preimage->nr + current_lno <= img->nr) {
                /*
                 * The hunk falls within the boundaries of img.
                 */
                preimage_limit = preimage->nr;
 -              if (match_end && (preimage->nr + try_lno != img->nr))
 +              if (match_end && (preimage->nr + current_lno != img->nr))
                        return 0;
        } else if (state->ws_error_action == correct_ws_error &&
                   (ws_rule & WS_BLANK_AT_EOF)) {
                 * match with img, and the remainder of the preimage
                 * must be blank.
                 */
 -              preimage_limit = img->nr - try_lno;
 +              preimage_limit = img->nr - current_lno;
        } else {
                /*
                 * The hunk extends beyond the end of the img and
                return 0;
        }
  
 -      if (match_beginning && try_lno)
 +      if (match_beginning && current_lno)
                return 0;
  
        /* Quick hash check */
        for (i = 0; i < preimage_limit; i++)
 -              if ((img->line[try_lno + i].flag & LINE_PATCHED) ||
 -                  (preimage->line[i].hash != img->line[try_lno + i].hash))
 +              if ((img->line[current_lno + i].flag & LINE_PATCHED) ||
 +                  (preimage->line[i].hash != img->line[current_lno + i].hash))
                        return 0;
  
        if (preimage_limit == preimage->nr) {
                /*
                 * Do we have an exact match?  If we were told to match
 -               * at the end, size must be exactly at try+fragsize,
 -               * otherwise try+fragsize must be still within the preimage,
 +               * at the end, size must be exactly at current+fragsize,
 +               * otherwise current+fragsize must be still within the preimage,
                 * and either case, the old piece should match the preimage
                 * exactly.
                 */
                if ((match_end
 -                   ? (try + preimage->len == img->len)
 -                   : (try + preimage->len <= img->len)) &&
 -                  !memcmp(img->buf + try, preimage->buf, preimage->len))
 +                   ? (current + preimage->len == img->len)
 +                   : (current + preimage->len <= img->len)) &&
 +                  !memcmp(img->buf + current, preimage->buf, preimage->len))
                        return 1;
        } else {
                /*
         */
        if (state->ws_ignore_action == ignore_ws_change)
                return line_by_line_fuzzy_match(img, preimage, postimage,
 -                                              try, try_lno, preimage_limit);
 +                                              current, current_lno, preimage_limit);
  
        if (state->ws_error_action != correct_ws_error)
                return 0;
         */
        strbuf_init(&fixed, preimage->len + 1);
        orig = preimage->buf;
 -      target = img->buf + try;
 +      target = img->buf + current;
        for (i = 0; i < preimage_limit; i++) {
                size_t oldlen = preimage->line[i].len;
 -              size_t tgtlen = img->line[try_lno + i].len;
 +              size_t tgtlen = img->line[current_lno + i].len;
                size_t fixstart = fixed.len;
                struct strbuf tgtfix;
                int match;
@@@ -2666,8 -2673,8 +2666,8 @@@ static int find_pos(struct apply_state 
                    int match_beginning, int match_end)
  {
        int i;
 -      unsigned long backwards, forwards, try;
 -      int backwards_lno, forwards_lno, try_lno;
 +      unsigned long backwards, forwards, current;
 +      int backwards_lno, forwards_lno, current_lno;
  
        /*
         * If match_beginning or match_end is specified, there is no
        if ((size_t) line > img->nr)
                line = img->nr;
  
 -      try = 0;
 +      current = 0;
        for (i = 0; i < line; i++)
 -              try += img->line[i].len;
 +              current += img->line[i].len;
  
        /*
         * There's probably some smart way to do this, but I'll leave
         * that to the smart and beautiful people. I'm simple and stupid.
         */
 -      backwards = try;
 +      backwards = current;
        backwards_lno = line;
 -      forwards = try;
 +      forwards = current;
        forwards_lno = line;
 -      try_lno = line;
 +      current_lno = line;
  
        for (i = 0; ; i++) {
                if (match_fragment(state, img, preimage, postimage,
 -                                 try, try_lno, ws_rule,
 +                                 current, current_lno, ws_rule,
                                   match_beginning, match_end))
 -                      return try_lno;
 +                      return current_lno;
  
        again:
                if (backwards_lno == 0 && forwards_lno == img->nr)
                        }
                        backwards_lno--;
                        backwards -= img->line[backwards_lno].len;
 -                      try = backwards;
 -                      try_lno = backwards_lno;
 +                      current = backwards;
 +                      current_lno = backwards_lno;
                } else {
                        if (forwards_lno == img->nr) {
                                i++;
                        }
                        forwards += img->line[forwards_lno].len;
                        forwards_lno++;
 -                      try = forwards;
 -                      try_lno = forwards_lno;
 +                      current = forwards;
 +                      current_lno = forwards_lno;
                }
  
        }
@@@ -2812,10 -2819,13 +2812,10 @@@ static void update_image(struct apply_s
                img->line_allocated = img->line;
        }
        if (preimage_limit != postimage->nr)
 -              memmove(img->line + applied_pos + postimage->nr,
 -                      img->line + applied_pos + preimage_limit,
 -                      (img->nr - (applied_pos + preimage_limit)) *
 -                      sizeof(*img->line));
 -      memcpy(img->line + applied_pos,
 -             postimage->line,
 -             postimage->nr * sizeof(*img->line));
 +              MOVE_ARRAY(img->line + applied_pos + postimage->nr,
 +                         img->line + applied_pos + preimage_limit,
 +                         img->nr - (applied_pos + preimage_limit));
 +      COPY_ARRAY(img->line + applied_pos, postimage->line, postimage->nr);
        if (!state->allow_overlap)
                for (i = 0; i < postimage->nr; i++)
                        img->line[applied_pos + i].flag |= LINE_PATCHED;
@@@ -2896,7 -2906,6 +2896,7 @@@ static int apply_one_fragment(struct ap
                        if (plen && (ws_rule & WS_BLANK_AT_EOF) &&
                            ws_blank_line(patch + 1, plen, ws_rule))
                                is_blank_context = 1;
 +                      /* fallthrough */
                case '-':
                        memcpy(old, patch + 1, plen);
                        add_line_info(&preimage, old, plen,
                        old += plen;
                        if (first == '-')
                                break;
 -              /* Fall-through for ' ' */
 +                      /* fallthrough */
                case '+':
                        /* --no-add does not add new lines */
                        if (first == '+' && state->no_add)
            newlines.len > 0 && newlines.buf[newlines.len - 1] == '\n') {
                old--;
                strbuf_setlen(&newlines, newlines.len - 1);
 +              preimage.line_allocated[preimage.nr - 1].len--;
 +              postimage.line_allocated[postimage.nr - 1].len--;
        }
  
        leading = frag->leading;
@@@ -3154,7 -3161,7 +3154,7 @@@ static int apply_binary(struct apply_st
                 * See if the old one matches what the patch
                 * applies to.
                 */
 -              hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
 +              hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->old_sha1_prefix))
                        return error(_("the patch applies to '%s' (%s), "
                                       "which does not match the "
                                     name);
  
                /* verify that the result matches */
 -              hash_sha1_file(img->buf, img->len, blob_type, oid.hash);
 +              hash_object_file(img->buf, img->len, blob_type, &oid);
                if (strcmp(oid_to_hex(&oid), patch->new_sha1_prefix))
                        return error(_("binary patch to '%s' creates incorrect result (expecting %s, got %s)"),
                                name, patch->new_sha1_prefix, oid_to_hex(&oid));
@@@ -3387,7 -3394,6 +3387,7 @@@ static int load_patch_target(struct app
                             struct strbuf *buf,
                             const struct cache_entry *ce,
                             struct stat *st,
 +                           struct patch *patch,
                             const char *name,
                             unsigned expected_mode)
  {
                } else if (has_symlink_leading_path(name, strlen(name))) {
                        return error(_("reading from '%s' beyond a symbolic link"), name);
                } else {
 -                      if (read_old_data(st, name, buf))
 +                      if (read_old_data(st, patch, name, buf))
                                return error(_("failed to read %s"), name);
                }
        }
@@@ -3436,7 -3442,7 +3436,7 @@@ static int load_preimage(struct apply_s
                /* We have a patched copy in memory; use that. */
                strbuf_add(&buf, previous->result, previous->resultsize);
        } else {
 -              status = load_patch_target(state, &buf, ce, st,
 +              status = load_patch_target(state, &buf, ce, st, patch,
                                           patch->old_name, patch->old_mode);
                if (status < 0)
                        return status;
@@@ -3524,7 -3530,7 +3524,7 @@@ static int load_current(struct apply_st
        if (verify_index_match(ce, &st))
                return error(_("%s: does not match index"), name);
  
 -      status = load_patch_target(state, &buf, ce, &st, name, mode);
 +      status = load_patch_target(state, &buf, ce, &st, patch, name, mode);
        if (status < 0)
                return status;
        else if (status)
@@@ -3554,8 -3560,8 +3554,8 @@@ static int try_threeway(struct apply_st
  
        /* Preimage the patch was prepared for */
        if (patch->is_new)
 -              write_sha1_file("", 0, blob_type, pre_oid.hash);
 -      else if (get_sha1(patch->old_sha1_prefix, pre_oid.hash) ||
 +              write_object_file("", 0, blob_type, &pre_oid);
 +      else if (get_oid(patch->old_sha1_prefix, &pre_oid) ||
                 read_blob_object(&buf, &pre_oid, patch->old_mode))
                return error(_("repository lacks the necessary blob to fall back on 3-way merge."));
  
                return -1;
        }
        /* post_oid is theirs */
 -      write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, post_oid.hash);
 +      write_object_file(tmp_image.buf, tmp_image.len, blob_type, &post_oid);
        clear_image(&tmp_image);
  
        /* our_oid is ours */
                        return error(_("cannot read the current contents of '%s'"),
                                     patch->old_name);
        }
 -      write_sha1_file(tmp_image.buf, tmp_image.len, blob_type, our_oid.hash);
 +      write_object_file(tmp_image.buf, tmp_image.len, blob_type, &our_oid);
        clear_image(&tmp_image);
  
        /* in-core three-way merge between post and our using pre as base */
@@@ -3720,7 -3726,8 +3720,7 @@@ static int check_preimage(struct apply_
   is_new:
        patch->is_new = 1;
        patch->is_delete = 0;
 -      free(patch->old_name);
 -      patch->old_name = NULL;
 +      FREE_AND_NULL(patch->old_name);
        return 0;
  }
  
@@@ -3755,7 -3762,7 +3755,7 @@@ static int check_to_create(struct apply
                        return 0;
  
                return EXISTS_IN_WORKTREE;
 -      } else if ((errno != ENOENT) && (errno != ENOTDIR)) {
 +      } else if (!is_missing_file_error(errno)) {
                return error_errno("%s", new_name);
        }
        return 0;
@@@ -3860,9 -3867,9 +3860,9 @@@ static int check_unsafe_path(struct pat
        if (!patch->is_delete)
                new_name = patch->new_name;
  
-       if (old_name && !verify_path(old_name))
+       if (old_name && !verify_path(old_name, patch->old_mode))
                return error(_("invalid path '%s'"), old_name);
-       if (new_name && !verify_path(new_name))
+       if (new_name && !verify_path(new_name, patch->new_mode))
                return error(_("invalid path '%s'"), new_name);
        return 0;
  }
@@@ -4079,7 -4086,7 +4079,7 @@@ static int build_fake_ancestor(struct a
                        else
                                return error(_("sha1 information is lacking or "
                                               "useless for submodule %s"), name);
 -              } else if (!get_sha1_blob(patch->old_sha1_prefix, oid.hash)) {
 +              } else if (!get_oid_blob(patch->old_sha1_prefix, &oid)) {
                        ; /* ok */
                } else if (!patch->lines_added && !patch->lines_deleted) {
                        /* mode-only change: update the current */
@@@ -4163,30 -4170,30 +4163,30 @@@ static void show_mode_change(struct pat
  static void show_rename_copy(struct patch *p)
  {
        const char *renamecopy = p->is_rename ? "rename" : "copy";
 -      const char *old, *new;
 +      const char *old_name, *new_name;
  
        /* Find common prefix */
 -      old = p->old_name;
 -      new = p->new_name;
 +      old_name = p->old_name;
 +      new_name = p->new_name;
        while (1) {
                const char *slash_old, *slash_new;
 -              slash_old = strchr(old, '/');
 -              slash_new = strchr(new, '/');
 +              slash_old = strchr(old_name, '/');
 +              slash_new = strchr(new_name, '/');
                if (!slash_old ||
                    !slash_new ||
 -                  slash_old - old != slash_new - new ||
 -                  memcmp(old, new, slash_new - new))
 +                  slash_old - old_name != slash_new - new_name ||
 +                  memcmp(old_name, new_name, slash_new - new_name))
                        break;
 -              old = slash_old + 1;
 -              new = slash_new + 1;
 +              old_name = slash_old + 1;
 +              new_name = slash_new + 1;
        }
 -      /* p->old_name thru old is the common prefix, and old and new
 +      /* p->old_name thru old_name is the common prefix, and old_name and new_name
         * through the end of names are renames
         */
 -      if (old != p->old_name)
 +      if (old_name != p->old_name)
                printf(" %s %.*s{%s => %s} (%d%%)\n", renamecopy,
 -                     (int)(old - p->old_name), p->old_name,
 -                     old, new, p->score);
 +                     (int)(old_name - p->old_name), p->old_name,
 +                     old_name, new_name, p->score);
        else
                printf(" %s %s => %s (%d%%)\n", renamecopy,
                       p->old_name, p->new_name, p->score);
@@@ -4291,7 -4298,7 +4291,7 @@@ static int add_index_file(struct apply_
                        }
                        fill_stat_cache_info(ce, &st);
                }
 -              if (write_sha1_file(buf, size, blob_type, ce->oid.hash) < 0) {
 +              if (write_object_file(buf, size, blob_type, &ce->oid) < 0) {
                        free(ce);
                        return error(_("unable to create backing store "
                                       "for newly created file %s"), path);
@@@ -4687,13 -4694,13 +4687,13 @@@ static int apply_patch(struct apply_sta
                state->apply = 0;
  
        state->update_index = state->check_index && state->apply;
 -      if (state->update_index && state->newfd < 0) {
 +      if (state->update_index && !is_lock_file_locked(&state->lock_file)) {
                if (state->index_file)
 -                      state->newfd = hold_lock_file_for_update(state->lock_file,
 -                                                               state->index_file,
 -                                                               LOCK_DIE_ON_ERROR);
 +                      hold_lock_file_for_update(&state->lock_file,
 +                                                state->index_file,
 +                                                LOCK_DIE_ON_ERROR);
                else
 -                      state->newfd = hold_locked_index(state->lock_file, LOCK_DIE_ON_ERROR);
 +                      hold_locked_index(&state->lock_file, LOCK_DIE_ON_ERROR);
        }
  
        if (state->check_index && read_apply_cache(state) < 0) {
@@@ -4889,18 -4896,22 +4889,18 @@@ int apply_all_patches(struct apply_stat
        }
  
        if (state->update_index) {
 -              res = write_locked_index(&the_index, state->lock_file, COMMIT_LOCK);
 +              res = write_locked_index(&the_index, &state->lock_file, COMMIT_LOCK);
                if (res) {
                        error(_("Unable to write new index file"));
                        res = -128;
                        goto end;
                }
 -              state->newfd = -1;
        }
  
        res = !!errs;
  
  end:
 -      if (state->newfd >= 0) {
 -              rollback_lock_file(state->lock_file);
 -              state->newfd = -1;
 -      }
 +      rollback_lock_file(&state->lock_file);
  
        if (state->apply_verbosity <= verbosity_silent) {
                set_error_routine(state->saved_error_routine);
@@@ -4943,9 -4954,8 +4943,9 @@@ int apply_parse_options(int argc, cons
                        N_("make sure the patch is applicable to the current index")),
                OPT_BOOL(0, "cached", &state->cached,
                        N_("apply a patch without touching the working tree")),
 -              OPT_BOOL(0, "unsafe-paths", &state->unsafe_paths,
 -                      N_("accept a patch that touches outside the working area")),
 +              OPT_BOOL_F(0, "unsafe-paths", &state->unsafe_paths,
 +                         N_("accept a patch that touches outside the working area"),
 +                         PARSE_OPT_NOCOMPLETE),
                OPT_BOOL(0, "apply", force_apply,
                        N_("also apply the patch (use with --stat/--summary/--check)")),
                OPT_BOOL('3', "3way", &state->threeway,
index 6ba8587b6d3b7b8b1bc7a96451916c60210b093b,b4b4d29d82896e706be44f8509cb39a6e34037fa..4f35c98bb970328bca5135bd66fdaf3a9fce0d16
@@@ -1,7 -1,5 +1,7 @@@
  #include "builtin.h"
 +#include "repository.h"
  #include "cache.h"
 +#include "config.h"
  #include "parse-options.h"
  #include "quote.h"
  #include "pathspec.h"
  #include "remote.h"
  #include "refs.h"
  #include "connect.h"
 +#include "revision.h"
 +#include "diffcore.h"
 +#include "diff.h"
 +
 +#define OPT_QUIET (1 << 0)
 +#define OPT_CACHED (1 << 1)
 +#define OPT_RECURSIVE (1 << 2)
 +#define OPT_FORCE (1 << 3)
 +
 +typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 +                                void *cb_data);
  
  static char *get_default_remote(void)
  {
        char *dest = NULL, *ret;
 -      unsigned char sha1[20];
        struct strbuf sb = STRBUF_INIT;
 -      const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 +      const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
  
        if (!refname)
                die(_("No such ref: %s"), "HEAD");
        return ret;
  }
  
 +static int print_default_remote(int argc, const char **argv, const char *prefix)
 +{
 +      const char *remote;
 +
 +      if (argc != 1)
 +              die(_("submodule--helper print-default-remote takes no arguments"));
 +
 +      remote = get_default_remote();
 +      if (remote)
 +              printf("%s\n", remote);
 +
 +      return 0;
 +}
 +
  static int starts_with_dot_slash(const char *str)
  {
        return str[0] == '.' && is_dir_sep(str[1]);
@@@ -244,64 -218,6 +244,64 @@@ static int resolve_relative_url_test(in
        return 0;
  }
  
 +/* the result should be freed by the caller. */
 +static char *get_submodule_displaypath(const char *path, const char *prefix)
 +{
 +      const char *super_prefix = get_super_prefix();
 +
 +      if (prefix && super_prefix) {
 +              BUG("cannot have prefix '%s' and superprefix '%s'",
 +                  prefix, super_prefix);
 +      } else if (prefix) {
 +              struct strbuf sb = STRBUF_INIT;
 +              char *displaypath = xstrdup(relative_path(path, prefix, &sb));
 +              strbuf_release(&sb);
 +              return displaypath;
 +      } else if (super_prefix) {
 +              return xstrfmt("%s%s", super_prefix, path);
 +      } else {
 +              return xstrdup(path);
 +      }
 +}
 +
 +static char *compute_rev_name(const char *sub_path, const char* object_id)
 +{
 +      struct strbuf sb = STRBUF_INIT;
 +      const char ***d;
 +
 +      static const char *describe_bare[] = { NULL };
 +
 +      static const char *describe_tags[] = { "--tags", NULL };
 +
 +      static const char *describe_contains[] = { "--contains", NULL };
 +
 +      static const char *describe_all_always[] = { "--all", "--always", NULL };
 +
 +      static const char **describe_argv[] = { describe_bare, describe_tags,
 +                                              describe_contains,
 +                                              describe_all_always, NULL };
 +
 +      for (d = describe_argv; *d; d++) {
 +              struct child_process cp = CHILD_PROCESS_INIT;
 +              prepare_submodule_repo_env(&cp.env_array);
 +              cp.dir = sub_path;
 +              cp.git_cmd = 1;
 +              cp.no_stderr = 1;
 +
 +              argv_array_push(&cp.args, "describe");
 +              argv_array_pushv(&cp.args, *d);
 +              argv_array_push(&cp.args, object_id);
 +
 +              if (!capture_command(&cp, &sb, 0)) {
 +                      strbuf_strip_suffix(&sb, "\n");
 +                      return strbuf_detach(&sb, NULL);
 +              }
 +      }
 +
 +      strbuf_release(&sb);
 +      return NULL;
 +}
 +
  struct module_list {
        const struct cache_entry **entries;
        int alloc, nr;
@@@ -316,7 -232,8 +316,7 @@@ static int module_list_compute(int argc
        int i, result = 0;
        char *ps_matched = NULL;
        parse_pathspec(pathspec, 0,
 -                     PATHSPEC_PREFER_FULL |
 -                     PATHSPEC_STRIP_SUBMODULE_SLASH_CHEAP,
 +                     PATHSPEC_PREFER_FULL,
                       prefix, argv);
  
        if (pathspec->nr)
@@@ -357,10 -274,12 +357,10 @@@ static void module_list_active(struct m
        int i;
        struct module_list active_modules = MODULE_LIST_INIT;
  
 -      gitmodules_config();
 -
        for (i = 0; i < list->nr; i++) {
                const struct cache_entry *ce = list->entries[i];
  
 -              if (!is_submodule_initialized(ce->name))
 +              if (!is_submodule_active(the_repository, ce->name))
                        continue;
  
                ALLOC_GROW(active_modules.entries,
        *list = active_modules;
  }
  
 +static char *get_up_path(const char *path)
 +{
 +      int i;
 +      struct strbuf sb = STRBUF_INIT;
 +
 +      for (i = count_slashes(path); i; i--)
 +              strbuf_addstr(&sb, "../");
 +
 +      /*
 +       * Check if 'path' ends with slash or not
 +       * for having the same output for dir/sub_dir
 +       * and dir/sub_dir/
 +       */
 +      if (!is_dir_sep(path[strlen(path) - 1]))
 +              strbuf_addstr(&sb, "../");
 +
 +      return strbuf_detach(&sb, NULL);
 +}
 +
  static int module_list(int argc, const char **argv, const char *prefix)
  {
        int i;
        return 0;
  }
  
 -static void init_submodule(const char *path, const char *prefix, int quiet)
 +static void for_each_listed_submodule(const struct module_list *list,
 +                                    each_submodule_fn fn, void *cb_data)
 +{
 +      int i;
 +      for (i = 0; i < list->nr; i++)
 +              fn(list->entries[i], cb_data);
 +}
 +
 +struct init_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define INIT_CB_INIT { NULL, 0 }
 +
 +static void init_submodule(const char *path, const char *prefix,
 +                         unsigned int flags)
  {
        const struct submodule *sub;
        struct strbuf sb = STRBUF_INIT;
        char *upd = NULL, *url = NULL, *displaypath;
  
 -      /* Only loads from .gitmodules, no overlay with .git/config */
 -      gitmodules_config();
 -
 -      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);
 +      displaypath = get_submodule_displaypath(path, prefix);
  
 -      sub = submodule_from_path(null_sha1, path);
 +      sub = submodule_from_path(&null_oid, path);
  
        if (!sub)
                die(_("No url found for submodule path '%s' in .gitmodules"),
         *
         * Set active flag for the submodule being initialized
         */
 -      if (!is_submodule_initialized(path)) {
 -              strbuf_reset(&sb);
 +      if (!is_submodule_active(the_repository, path)) {
                strbuf_addf(&sb, "submodule.%s.active", sub->name);
                git_config_set_gently(sb.buf, "true");
 +              strbuf_reset(&sb);
        }
  
        /*
         * To look up the url in .git/config, we must not fall back to
         * .gitmodules, so look it up directly.
         */
 -      strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
        if (git_config_get_string(sb.buf, &url)) {
                if (!sub->url)
                if (git_config_set_gently(sb.buf, url))
                        die(_("Failed to register url for submodule path '%s'"),
                            displaypath);
 -              if (!quiet)
 +              if (!(flags & OPT_QUIET))
                        fprintf(stderr,
                                _("Submodule '%s' (%s) registered for path '%s'\n"),
                                sub->name, url, displaypath);
        }
 +      strbuf_reset(&sb);
  
        /* Copy "update" setting when it is not set yet */
 -      strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.update", sub->name);
        if (git_config_get_string(sb.buf, &upd) &&
            sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
        free(upd);
  }
  
 +static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 +{
 +      struct init_cb *info = cb_data;
 +      init_submodule(list_item->name, info->prefix, info->flags);
 +}
 +
  static int module_init(int argc, const char **argv, const char *prefix)
  {
 +      struct init_cb info = INIT_CB_INIT;
        struct pathspec pathspec;
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
 -      int i;
  
        struct option module_init_options[] = {
                OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
        if (!argc && git_config_get_value_multi("submodule.active"))
                module_list_active(&list);
  
 -      for (i = 0; i < list.nr; i++)
 -              init_submodule(list.entries[i]->name, prefix, quiet);
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +
 +      for_each_listed_submodule(&list, init_submodule_cb, &info);
 +
 +      return 0;
 +}
 +
 +struct status_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define STATUS_CB_INIT { NULL, 0 }
 +
 +static void print_status(unsigned int flags, char state, const char *path,
 +                       const struct object_id *oid, const char *displaypath)
 +{
 +      if (flags & OPT_QUIET)
 +              return;
 +
 +      printf("%c%s %s", state, oid_to_hex(oid), displaypath);
 +
 +      if (state == ' ' || state == '+')
 +              printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
 +
 +      printf("\n");
 +}
 +
 +static int handle_submodule_head_ref(const char *refname,
 +                                   const struct object_id *oid, int flags,
 +                                   void *cb_data)
 +{
 +      struct object_id *output = cb_data;
 +      if (oid)
 +              oidcpy(output, oid);
 +
 +      return 0;
 +}
 +
 +static void status_submodule(const char *path, const struct object_id *ce_oid,
 +                           unsigned int ce_flags, const char *prefix,
 +                           unsigned int flags)
 +{
 +      char *displaypath;
 +      struct argv_array diff_files_args = ARGV_ARRAY_INIT;
 +      struct rev_info rev;
 +      int diff_files_result;
 +
 +      if (!submodule_from_path(&null_oid, path))
 +              die(_("no submodule mapping found in .gitmodules for path '%s'"),
 +                    path);
 +
 +      displaypath = get_submodule_displaypath(path, prefix);
 +
 +      if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 +              print_status(flags, 'U', path, &null_oid, displaypath);
 +              goto cleanup;
 +      }
 +
 +      if (!is_submodule_active(the_repository, path)) {
 +              print_status(flags, '-', path, ce_oid, displaypath);
 +              goto cleanup;
 +      }
 +
 +      argv_array_pushl(&diff_files_args, "diff-files",
 +                       "--ignore-submodules=dirty", "--quiet", "--",
 +                       path, NULL);
 +
 +      git_config(git_diff_basic_config, NULL);
 +      init_revisions(&rev, prefix);
 +      rev.abbrev = 0;
 +      diff_files_args.argc = setup_revisions(diff_files_args.argc,
 +                                             diff_files_args.argv,
 +                                             &rev, NULL);
 +      diff_files_result = run_diff_files(&rev, 0);
 +
 +      if (!diff_result_code(&rev.diffopt, diff_files_result)) {
 +              print_status(flags, ' ', path, ce_oid,
 +                           displaypath);
 +      } else if (!(flags & OPT_CACHED)) {
 +              struct object_id oid;
 +
 +              if (refs_head_ref(get_submodule_ref_store(path),
 +                                handle_submodule_head_ref, &oid))
 +                      die(_("could not resolve HEAD ref inside the "
 +                            "submodule '%s'"), path);
 +
 +              print_status(flags, '+', path, &oid, displaypath);
 +      } else {
 +              print_status(flags, '+', path, ce_oid, displaypath);
 +      }
 +
 +      if (flags & OPT_RECURSIVE) {
 +              struct child_process cpr = CHILD_PROCESS_INIT;
 +
 +              cpr.git_cmd = 1;
 +              cpr.dir = path;
 +              prepare_submodule_repo_env(&cpr.env_array);
 +
 +              argv_array_push(&cpr.args, "--super-prefix");
 +              argv_array_pushf(&cpr.args, "%s/", displaypath);
 +              argv_array_pushl(&cpr.args, "submodule--helper", "status",
 +                               "--recursive", NULL);
 +
 +              if (flags & OPT_CACHED)
 +                      argv_array_push(&cpr.args, "--cached");
 +
 +              if (flags & OPT_QUIET)
 +                      argv_array_push(&cpr.args, "--quiet");
 +
 +              if (run_command(&cpr))
 +                      die(_("failed to recurse into submodule '%s'"), path);
 +      }
 +
 +cleanup:
 +      argv_array_clear(&diff_files_args);
 +      free(displaypath);
 +}
 +
 +static void status_submodule_cb(const struct cache_entry *list_item,
 +                              void *cb_data)
 +{
 +      struct status_cb *info = cb_data;
 +      status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
 +                       info->prefix, info->flags);
 +}
 +
 +static int module_status(int argc, const char **argv, const char *prefix)
 +{
 +      struct status_cb info = STATUS_CB_INIT;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +      int quiet = 0;
 +
 +      struct option module_status_options[] = {
 +              OPT__QUIET(&quiet, N_("Suppress submodule status output")),
 +              OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 +              OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, module_status_options,
 +                           git_submodule_helper_usage, 0);
 +
 +      if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +
 +      for_each_listed_submodule(&list, status_submodule_cb, &info);
  
        return 0;
  }
@@@ -741,7 -474,8 +741,7 @@@ static int module_name(int argc, const 
        if (argc != 2)
                usage(_("git submodule--helper name <path>"));
  
 -      gitmodules_config();
 -      sub = submodule_from_path(null_sha1, argv[1]);
 +      sub = submodule_from_path(&null_oid, argv[1]);
  
        if (!sub)
                die(_("no submodule mapping found in .gitmodules for path '%s'"),
        return 0;
  }
  
 +struct sync_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define SYNC_CB_INIT { NULL, 0 }
 +
 +static void sync_submodule(const char *path, const char *prefix,
 +                         unsigned int flags)
 +{
 +      const struct submodule *sub;
 +      char *remote_key = NULL;
 +      char *sub_origin_url, *super_config_url, *displaypath;
 +      struct strbuf sb = STRBUF_INIT;
 +      struct child_process cp = CHILD_PROCESS_INIT;
 +      char *sub_config_path = NULL;
 +
 +      if (!is_submodule_active(the_repository, path))
 +              return;
 +
 +      sub = submodule_from_path(&null_oid, path);
 +
 +      if (sub && sub->url) {
 +              if (starts_with_dot_dot_slash(sub->url) ||
 +                  starts_with_dot_slash(sub->url)) {
 +                      char *remote_url, *up_path;
 +                      char *remote = get_default_remote();
 +                      strbuf_addf(&sb, "remote.%s.url", remote);
 +
 +                      if (git_config_get_string(sb.buf, &remote_url))
 +                              remote_url = xgetcwd();
 +
 +                      up_path = get_up_path(path);
 +                      sub_origin_url = relative_url(remote_url, sub->url, up_path);
 +                      super_config_url = relative_url(remote_url, sub->url, NULL);
 +
 +                      free(remote);
 +                      free(up_path);
 +                      free(remote_url);
 +              } else {
 +                      sub_origin_url = xstrdup(sub->url);
 +                      super_config_url = xstrdup(sub->url);
 +              }
 +      } else {
 +              sub_origin_url = xstrdup("");
 +              super_config_url = xstrdup("");
 +      }
 +
 +      displaypath = get_submodule_displaypath(path, prefix);
 +
 +      if (!(flags & OPT_QUIET))
 +              printf(_("Synchronizing submodule url for '%s'\n"),
 +                       displaypath);
 +
 +      strbuf_reset(&sb);
 +      strbuf_addf(&sb, "submodule.%s.url", sub->name);
 +      if (git_config_set_gently(sb.buf, super_config_url))
 +              die(_("failed to register url for submodule path '%s'"),
 +                    displaypath);
 +
 +      if (!is_submodule_populated_gently(path, NULL))
 +              goto cleanup;
 +
 +      prepare_submodule_repo_env(&cp.env_array);
 +      cp.git_cmd = 1;
 +      cp.dir = path;
 +      argv_array_pushl(&cp.args, "submodule--helper",
 +                       "print-default-remote", NULL);
 +
 +      strbuf_reset(&sb);
 +      if (capture_command(&cp, &sb, 0))
 +              die(_("failed to get the default remote for submodule '%s'"),
 +                    path);
 +
 +      strbuf_strip_suffix(&sb, "\n");
 +      remote_key = xstrfmt("remote.%s.url", sb.buf);
 +
 +      strbuf_reset(&sb);
 +      submodule_to_gitdir(&sb, path);
 +      strbuf_addstr(&sb, "/config");
 +
 +      if (git_config_set_in_file_gently(sb.buf, remote_key, sub_origin_url))
 +              die(_("failed to update remote for submodule '%s'"),
 +                    path);
 +
 +      if (flags & OPT_RECURSIVE) {
 +              struct child_process cpr = CHILD_PROCESS_INIT;
 +
 +              cpr.git_cmd = 1;
 +              cpr.dir = path;
 +              prepare_submodule_repo_env(&cpr.env_array);
 +
 +              argv_array_push(&cpr.args, "--super-prefix");
 +              argv_array_pushf(&cpr.args, "%s/", displaypath);
 +              argv_array_pushl(&cpr.args, "submodule--helper", "sync",
 +                               "--recursive", NULL);
 +
 +              if (flags & OPT_QUIET)
 +                      argv_array_push(&cpr.args, "--quiet");
 +
 +              if (run_command(&cpr))
 +                      die(_("failed to recurse into submodule '%s'"),
 +                            path);
 +      }
 +
 +cleanup:
 +      free(super_config_url);
 +      free(sub_origin_url);
 +      strbuf_release(&sb);
 +      free(remote_key);
 +      free(displaypath);
 +      free(sub_config_path);
 +}
 +
 +static void sync_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 +{
 +      struct sync_cb *info = cb_data;
 +      sync_submodule(list_item->name, info->prefix, info->flags);
 +
 +}
 +
 +static int module_sync(int argc, const char **argv, const char *prefix)
 +{
 +      struct sync_cb info = SYNC_CB_INIT;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +      int quiet = 0;
 +      int recursive = 0;
 +
 +      struct option module_sync_options[] = {
 +              OPT__QUIET(&quiet, N_("Suppress output of synchronizing submodule url")),
 +              OPT_BOOL(0, "recursive", &recursive,
 +                      N_("Recurse into nested submodules")),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule--helper sync [--quiet] [--recursive] [<path>]"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, module_sync_options,
 +                           git_submodule_helper_usage, 0);
 +
 +      if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +      if (recursive)
 +              info.flags |= OPT_RECURSIVE;
 +
 +      for_each_listed_submodule(&list, sync_submodule_cb, &info);
 +
 +      return 0;
 +}
 +
 +struct deinit_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +#define DEINIT_CB_INIT { NULL, 0 }
 +
 +static void deinit_submodule(const char *path, const char *prefix,
 +                           unsigned int flags)
 +{
 +      const struct submodule *sub;
 +      char *displaypath = NULL;
 +      struct child_process cp_config = CHILD_PROCESS_INIT;
 +      struct strbuf sb_config = STRBUF_INIT;
 +      char *sub_git_dir = xstrfmt("%s/.git", path);
 +
 +      sub = submodule_from_path(&null_oid, path);
 +
 +      if (!sub || !sub->name)
 +              goto cleanup;
 +
 +      displaypath = get_submodule_displaypath(path, prefix);
 +
 +      /* remove the submodule work tree (unless the user already did it) */
 +      if (is_directory(path)) {
 +              struct strbuf sb_rm = STRBUF_INIT;
 +              const char *format;
 +
 +              /*
 +               * protect submodules containing a .git directory
 +               * NEEDSWORK: instead of dying, automatically call
 +               * absorbgitdirs and (possibly) warn.
 +               */
 +              if (is_directory(sub_git_dir))
 +                      die(_("Submodule work tree '%s' contains a .git "
 +                            "directory (use 'rm -rf' if you really want "
 +                            "to remove it including all of its history)"),
 +                          displaypath);
 +
 +              if (!(flags & OPT_FORCE)) {
 +                      struct child_process cp_rm = CHILD_PROCESS_INIT;
 +                      cp_rm.git_cmd = 1;
 +                      argv_array_pushl(&cp_rm.args, "rm", "-qn",
 +                                       path, NULL);
 +
 +                      if (run_command(&cp_rm))
 +                              die(_("Submodule work tree '%s' contains local "
 +                                    "modifications; use '-f' to discard them"),
 +                                    displaypath);
 +              }
 +
 +              strbuf_addstr(&sb_rm, path);
 +
 +              if (!remove_dir_recursively(&sb_rm, 0))
 +                      format = _("Cleared directory '%s'\n");
 +              else
 +                      format = _("Could not remove submodule work tree '%s'\n");
 +
 +              if (!(flags & OPT_QUIET))
 +                      printf(format, displaypath);
 +
 +              strbuf_release(&sb_rm);
 +      }
 +
 +      if (mkdir(path, 0777))
 +              printf(_("could not create empty submodule directory %s"),
 +                    displaypath);
 +
 +      cp_config.git_cmd = 1;
 +      argv_array_pushl(&cp_config.args, "config", "--get-regexp", NULL);
 +      argv_array_pushf(&cp_config.args, "submodule.%s\\.", sub->name);
 +
 +      /* remove the .git/config entries (unless the user already did it) */
 +      if (!capture_command(&cp_config, &sb_config, 0) && sb_config.len) {
 +              char *sub_key = xstrfmt("submodule.%s", sub->name);
 +              /*
 +               * remove the whole section so we have a clean state when
 +               * the user later decides to init this submodule again
 +               */
 +              git_config_rename_section_in_file(NULL, sub_key, NULL);
 +              if (!(flags & OPT_QUIET))
 +                      printf(_("Submodule '%s' (%s) unregistered for path '%s'\n"),
 +                               sub->name, sub->url, displaypath);
 +              free(sub_key);
 +      }
 +
 +cleanup:
 +      free(displaypath);
 +      free(sub_git_dir);
 +      strbuf_release(&sb_config);
 +}
 +
 +static void deinit_submodule_cb(const struct cache_entry *list_item,
 +                              void *cb_data)
 +{
 +      struct deinit_cb *info = cb_data;
 +      deinit_submodule(list_item->name, info->prefix, info->flags);
 +}
 +
 +static int module_deinit(int argc, const char **argv, const char *prefix)
 +{
 +      struct deinit_cb info = DEINIT_CB_INIT;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +      int quiet = 0;
 +      int force = 0;
 +      int all = 0;
 +
 +      struct option module_deinit_options[] = {
 +              OPT__QUIET(&quiet, N_("Suppress submodule status output")),
 +              OPT__FORCE(&force, N_("Remove submodule working trees even if they contain local changes"), 0),
 +              OPT_BOOL(0, "all", &all, N_("Unregister all submodules")),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule deinit [--quiet] [-f | --force] [--all | [--] [<path>...]]"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, module_deinit_options,
 +                           git_submodule_helper_usage, 0);
 +
 +      if (all && argc) {
 +              error("pathspec and --all are incompatible");
 +              usage_with_options(git_submodule_helper_usage,
 +                                 module_deinit_options);
 +      }
 +
 +      if (!argc && !all)
 +              die(_("Use '--all' if you really want to deinitialize all submodules"));
 +
 +      if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +      if (force)
 +              info.flags |= OPT_FORCE;
 +
 +      for_each_listed_submodule(&list, deinit_submodule_cb, &info);
 +
 +      return 0;
 +}
 +
  static int clone_submodule(const char *path, const char *gitdir, const char *url,
                           const char *depth, struct string_list *reference,
                           int quiet, int progress)
@@@ -1348,10 -779,6 +1348,10 @@@ static int prepare_to_clone_next_submod
                                           struct strbuf *out)
  {
        const struct submodule *sub = NULL;
 +      const char *url = NULL;
 +      const char *update_string;
 +      enum submodule_update_type update_type;
 +      char *key;
        struct strbuf displaypath_sb = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        const char *displaypath = NULL;
                goto cleanup;
        }
  
 -      sub = submodule_from_path(null_sha1, ce->name);
 +      sub = submodule_from_path(&null_oid, ce->name);
  
        if (suc->recursive_prefix)
                displaypath = relative_path(suc->recursive_prefix,
                goto cleanup;
        }
  
 +      key = xstrfmt("submodule.%s.update", sub->name);
 +      if (!repo_config_get_string_const(the_repository, key, &update_string)) {
 +              update_type = parse_submodule_update_type(update_string);
 +      } else {
 +              update_type = sub->update_strategy.type;
 +      }
 +      free(key);
 +
        if (suc->update.type == SM_UPDATE_NONE
            || (suc->update.type == SM_UPDATE_UNSPECIFIED
 -              && sub->update_strategy.type == SM_UPDATE_NONE)) {
 +              && update_type == SM_UPDATE_NONE)) {
                strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
                strbuf_addch(out, '\n');
                goto cleanup;
        }
  
        /* Check if the submodule has been initialized. */
 -      if (!is_submodule_initialized(ce->name)) {
 +      if (!is_submodule_active(the_repository, ce->name)) {
                next_submodule_warn_missing(suc, out, displaypath);
                goto cleanup;
        }
  
 +      strbuf_reset(&sb);
 +      strbuf_addf(&sb, "submodule.%s.url", sub->name);
 +      if (repo_config_get_string_const(the_repository, sb.buf, &url))
 +              url = sub->url;
 +
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/.git", ce->name);
        needs_cloning = !file_exists(sb.buf);
                argv_array_push(&child->args, "--depth=1");
        argv_array_pushl(&child->args, "--path", sub->path, NULL);
        argv_array_pushl(&child->args, "--name", sub->name, NULL);
 -      argv_array_pushl(&child->args, "--url", sub->url, NULL);
 +      argv_array_pushl(&child->args, "--url", url, NULL);
        if (suc->references.nr) {
                struct string_list_item *item;
                for_each_string_list_item(item, &suc->references)
@@@ -1515,7 -929,7 +1515,7 @@@ static int update_clone_task_finished(i
        const struct cache_entry *ce;
        struct submodule_update_clone *suc = suc_cb;
  
 -      int *idxP = *(int**)idx_task_cb;
 +      int *idxP = idx_task_cb;
        int idx = *idxP;
        free(idxP);
  
        return 0;
  }
  
 +static int gitmodules_update_clone_config(const char *var, const char *value,
 +                                        void *cb)
 +{
 +      int *max_jobs = cb;
 +      if (!strcmp(var, "submodule.fetchjobs"))
 +              *max_jobs = parse_submodule_fetchjobs(var, value);
 +      return 0;
 +}
 +
  static int update_clone(int argc, const char **argv, const char *prefix)
  {
        const char *update = NULL;
 -      int max_jobs = -1;
 +      int max_jobs = 1;
        struct string_list_item *item;
        struct pathspec pathspec;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
        };
        suc.prefix = prefix;
  
 +      config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
 +      git_config(gitmodules_update_clone_config, &max_jobs);
 +
        argc = parse_options(argc, argv, prefix, module_update_clone_options,
                             git_submodule_helper_usage, 0);
  
        if (pathspec.nr)
                suc.warn_if_uninitialized = 1;
  
 -      /* Overlay the parsed .gitmodules file with .git/config */
 -      gitmodules_config();
 -      git_config(submodule_config, NULL);
 -
 -      if (max_jobs < 0)
 -              max_jobs = parallel_submodules();
 -
        run_processes_parallel(max_jobs,
                               update_clone_get_next_task,
                               update_clone_start_failure,
@@@ -1647,23 -1056,19 +1647,23 @@@ static int resolve_relative_path(int ar
  static const char *remote_submodule_branch(const char *path)
  {
        const struct submodule *sub;
 -      gitmodules_config();
 -      git_config(submodule_config, NULL);
 +      const char *branch = NULL;
 +      char *key;
  
 -      sub = submodule_from_path(null_sha1, path);
 +      sub = submodule_from_path(&null_oid, path);
        if (!sub)
                return NULL;
  
 -      if (!sub->branch)
 +      key = xstrfmt("submodule.%s.branch", sub->name);
 +      if (repo_config_get_string_const(the_repository, key, &branch))
 +              branch = sub->branch;
 +      free(key);
 +
 +      if (!branch)
                return "master";
  
 -      if (!strcmp(sub->branch, ".")) {
 -              unsigned char sha1[20];
 -              const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 +      if (!strcmp(branch, ".")) {
 +              const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
  
                if (!refname)
                        die(_("No such ref: %s"), "HEAD");
                return refname;
        }
  
 -      return sub->branch;
 +      return branch;
  }
  
  static int resolve_remote_submodule_branch(int argc, const char **argv,
  static int push_check(int argc, const char **argv, const char *prefix)
  {
        struct remote *remote;
 +      const char *superproject_head;
 +      char *head;
 +      int detached_head = 0;
 +      struct object_id head_oid;
  
 -      if (argc < 2)
 -              die("submodule--helper push-check requires at least 1 argument");
 +      if (argc < 3)
 +              die("submodule--helper push-check requires at least 2 arguments");
 +
 +      /*
 +       * superproject's resolved head ref.
 +       * if HEAD then the superproject is in a detached head state, otherwise
 +       * it will be the resolved head ref.
 +       */
 +      superproject_head = argv[1];
 +      argv++;
 +      argc--;
 +      /* Get the submodule's head ref and determine if it is detached */
 +      head = resolve_refdup("HEAD", 0, &head_oid, NULL);
 +      if (!head)
 +              die(_("Failed to resolve HEAD as a valid ref."));
 +      if (!strcmp(head, "HEAD"))
 +              detached_head = 1;
  
        /*
         * The remote must be configured.
                        if (rs->pattern || rs->matching)
                                continue;
  
 -                      /*
 -                       * LHS must match a single ref
 -                       * NEEDSWORK: add logic to special case 'HEAD' once
 -                       * working with submodules in a detached head state
 -                       * ceases to be the norm.
 -                       */
 -                      if (count_refspec_match(rs->src, local_refs, NULL) != 1)
 +                      /* LHS must match a single ref */
 +                      switch (count_refspec_match(rs->src, local_refs, NULL)) {
 +                      case 1:
 +                              break;
 +                      case 0:
 +                              /*
 +                               * If LHS matches 'HEAD' then we need to ensure
 +                               * that it matches the same named branch
 +                               * checked out in the superproject.
 +                               */
 +                              if (!strcmp(rs->src, "HEAD")) {
 +                                      if (!detached_head &&
 +                                          !strcmp(head, superproject_head))
 +                                              break;
 +                                      die("HEAD does not match the named branch in the superproject");
 +                              }
 +                              /* fallthrough */
 +                      default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
 +                      }
                }
                free_refspec(refspec_nr, refspec);
        }
 +      free(head);
  
        return 0;
  }
@@@ -1799,6 -1172,9 +1799,6 @@@ static int absorb_git_dirs(int argc, co
        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;
  
@@@ -1814,9 -1190,34 +1814,32 @@@ static int is_active(int argc, const ch
        if (argc != 2)
                die("submodule--helper is-active takes exactly 1 argument");
  
 -      gitmodules_config();
 -
 -      return !is_submodule_initialized(argv[1]);
 +      return !is_submodule_active(the_repository, argv[1]);
  }
  
+ /*
+  * Exit non-zero if any of the submodule names given on the command line is
+  * invalid. If no names are given, filter stdin to print only valid names
+  * (which is primarily intended for testing).
+  */
+ static int check_name(int argc, const char **argv, const char *prefix)
+ {
+       if (argc > 1) {
+               while (*++argv) {
+                       if (check_submodule_name(*argv) < 0)
+                               return 1;
+               }
+       } else {
+               struct strbuf buf = STRBUF_INIT;
+               while (strbuf_getline(&buf, stdin) != EOF) {
+                       if (!check_submodule_name(buf.buf))
+                               printf("%s\n", buf.buf);
+               }
+               strbuf_release(&buf);
+       }
+       return 0;
+ }
  #define SUPPORT_SUPER_PREFIX (1<<0)
  
  struct cmd_struct {
@@@ -1834,21 -1235,19 +1857,22 @@@ static struct cmd_struct commands[] = 
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
 +      {"status", module_status, SUPPORT_SUPER_PREFIX},
 +      {"print-default-remote", print_default_remote, 0},
 +      {"sync", module_sync, SUPPORT_SUPER_PREFIX},
 +      {"deinit", module_deinit, 0},
        {"remote-branch", resolve_remote_submodule_branch, 0},
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
        {"is-active", is_active, 0},
+       {"check-name", check_name, 0},
  };
  
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
  {
        int i;
 -      if (argc < 2)
 -              die(_("submodule--helper subcommand must be "
 -                    "called with a subcommand"));
 +      if (argc < 2 || !strcmp(argv[1], "-h"))
 +              usage("git submodule--helper <command>");
  
        for (i = 0; i < ARRAY_SIZE(commands); i++) {
                if (!strcmp(argv[1], commands[i].cmd)) {
diff --combined builtin/update-index.c
index 58d1c2d2827d61899d73f1ea7632c5ee219f3ace,19216595fbb917d06d51a42a85d0975d903948a9..1af8a00b889c968634389bf61138200d97eb32f9
@@@ -4,7 -4,6 +4,7 @@@
   * Copyright (C) Linus Torvalds, 2005
   */
  #include "cache.h"
 +#include "config.h"
  #include "lockfile.h"
  #include "quote.h"
  #include "cache-tree.h"
@@@ -16,7 -15,6 +16,7 @@@
  #include "pathspec.h"
  #include "dir.h"
  #include "split-index.h"
 +#include "fsmonitor.h"
  
  /*
   * Default to not allowing changes to the list of files. The
@@@ -33,7 -31,6 +33,7 @@@ static int force_remove
  static int verbose;
  static int mark_valid_only;
  static int mark_skip_worktree_only;
 +static int mark_fsmonitor_only;
  #define MARK_FLAG 1
  #define UNMARK_FLAG 2
  static struct strbuf mtime_dir = STRBUF_INIT;
@@@ -230,7 -227,6 +230,7 @@@ static int mark_ce_flags(const char *pa
        int namelen = strlen(path);
        int pos = cache_name_pos(path, namelen);
        if (0 <= pos) {
 +              mark_fsmonitor_invalid(&the_index, active_cache[pos]);
                if (mark)
                        active_cache[pos]->ce_flags |= flag;
                else
@@@ -261,7 -257,7 +261,7 @@@ static int remove_one_path(const char *
   */
  static int process_lstat_error(const char *path, int err)
  {
 -      if (err == ENOENT || err == ENOTDIR)
 +      if (is_missing_file_error(err))
                return remove_one_path(path);
        return error("lstat(\"%s\"): %s", path, strerror(err));
  }
@@@ -283,17 -279,15 +283,17 @@@ static int add_one_path(const struct ca
        fill_stat_cache_info(ce, st);
        ce->ce_mode = ce_mode_from_stat(old, st->st_mode);
  
 -      if (index_path(ce->oid.hash, path, st,
 +      if (index_path(&ce->oid, path, st,
                       info_only ? 0 : HASH_WRITE_OBJECT)) {
                free(ce);
                return -1;
        }
        option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
        option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
 -      if (add_cache_entry(ce, option))
 +      if (add_cache_entry(ce, option)) {
 +              free(ce);
                return error("%s: cannot add to the index - missing --add option?", path);
 +      }
        return 0;
  }
  
@@@ -331,7 -325,7 +331,7 @@@ static int process_directory(const cha
                if (S_ISGITLINK(ce->ce_mode)) {
  
                        /* Do nothing to the index if there is no HEAD! */
 -                      if (resolve_gitlink_ref(path, "HEAD", oid.hash) < 0)
 +                      if (resolve_gitlink_ref(path, "HEAD", &oid) < 0)
                                return 0;
  
                        return add_one_path(ce, path, len, st);
        }
  
        /* No match - should we add it as a gitlink? */
 -      if (!resolve_gitlink_ref(path, "HEAD", oid.hash))
 +      if (!resolve_gitlink_ref(path, "HEAD", &oid))
                return add_one_path(NULL, path, len, st);
  
        /* Error out. */
        return error("%s: is a directory - add files inside instead", path);
  }
  
- static int process_path(const char *path)
+ static int process_path(const char *path, struct stat *st, int stat_errno)
  {
        int pos, len;
-       struct stat st;
        const struct cache_entry *ce;
  
        len = strlen(path);
         * First things first: get the stat information, to decide
         * what to do about the pathname!
         */
-       if (lstat(path, &st) < 0)
-               return process_lstat_error(path, errno);
+       if (stat_errno)
+               return process_lstat_error(path, stat_errno);
  
-       if (S_ISDIR(st.st_mode))
-               return process_directory(path, len, &st);
+       if (S_ISDIR(st->st_mode))
+               return process_directory(path, len, st);
  
-       return add_one_path(ce, path, len, &st);
+       return add_one_path(ce, path, len, st);
  }
  
  static int add_cacheinfo(unsigned int mode, const struct object_id *oid,
        int size, len, option;
        struct cache_entry *ce;
  
-       if (!verify_path(path))
+       if (!verify_path(path, mode))
                return error("Invalid path '%s'", path);
  
        len = strlen(path);
@@@ -449,7 -442,17 +448,18 @@@ static void chmod_path(char flip, cons
  
  static void update_one(const char *path)
  {
-       if (!verify_path(path)) {
+       int stat_errno = 0;
+       struct stat st;
 -      if (mark_valid_only || mark_skip_worktree_only || force_remove)
++      if (mark_valid_only || mark_skip_worktree_only || force_remove ||
++          mark_fsmonitor_only)
+               st.st_mode = 0;
+       else if (lstat(path, &st) < 0) {
+               st.st_mode = 0;
+               stat_errno = errno;
+       } /* else stat is valid */
+       if (!verify_path(path, st.st_mode)) {
                fprintf(stderr, "Ignoring path %s\n", path);
                return;
        }
                        die("Unable to mark file %s", path);
                return;
        }
 +      if (mark_fsmonitor_only) {
 +              if (mark_ce_flags(path, CE_FSMONITOR_VALID, mark_fsmonitor_only == MARK_FLAG))
 +                      die("Unable to mark file %s", path);
 +              return;
 +      }
  
        if (force_remove) {
                if (remove_file_from_cache(path))
                report("remove '%s'", path);
                return;
        }
-       if (process_path(path))
+       if (process_path(path, &st, stat_errno))
                die("Unable to process path %s", path);
        report("add '%s'", path);
  }
@@@ -545,7 -543,7 +555,7 @@@ static void read_index_info(int nul_ter
                        path_name = uq.buf;
                }
  
-               if (!verify_path(path_name)) {
+               if (!verify_path(path_name, mode)) {
                        fprintf(stderr, "Ignoring path %s\n", path_name);
                        continue;
                }
@@@ -687,9 -685,9 +697,9 @@@ static int unresolve_one(const char *pa
  
  static void read_head_pointers(void)
  {
 -      if (read_ref("HEAD", head_oid.hash))
 +      if (read_ref("HEAD", &head_oid))
                die("No HEAD -- no initial commit yet?");
 -      if (read_ref("MERGE_HEAD", merge_head_oid.hash)) {
 +      if (read_ref("MERGE_HEAD", &merge_head_oid)) {
                fprintf(stderr, "Not in the middle of a merge.\n");
                exit(0);
        }
@@@ -729,7 -727,7 +739,7 @@@ static int do_reupdate(int ac, const ch
                       PATHSPEC_PREFER_CWD,
                       prefix, av + 1);
  
 -      if (read_ref("HEAD", head_oid.hash))
 +      if (read_ref("HEAD", &head_oid))
                /* If there is no HEAD, that means it is an initial
                 * commit.  Update everything in the index.
                 */
@@@ -925,9 -923,7 +935,9 @@@ int cmd_update_index(int argc, const ch
        struct refresh_params refresh_args = {0, &has_errors};
        int lock_error = 0;
        int split_index = -1;
 -      struct lock_file *lock_file;
 +      int force_write = 0;
 +      int fsmonitor = -1;
 +      struct lock_file lock_file = LOCK_INIT;
        struct parse_opt_ctx_t ctx;
        strbuf_getline_fn getline_fn;
        int parseopt_state = PARSE_OPT_UNKNOWN;
                            N_("test if the filesystem supports untracked cache"), UC_TEST),
                OPT_SET_INT(0, "force-untracked-cache", &untracked_cache,
                            N_("enable untracked cache without testing the filesystem"), UC_FORCE),
 +              OPT_SET_INT(0, "force-write-index", &force_write,
 +                      N_("write out the index even if is not flagged as changed"), 1),
 +              OPT_BOOL(0, "fsmonitor", &fsmonitor,
 +                      N_("enable or disable file system monitor")),
 +              {OPTION_SET_INT, 0, "fsmonitor-valid", &mark_fsmonitor_only, NULL,
 +                      N_("mark files as fsmonitor valid"),
 +                      PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, MARK_FLAG},
 +              {OPTION_SET_INT, 0, "no-fsmonitor-valid", &mark_fsmonitor_only, NULL,
 +                      N_("clear fsmonitor valid bit"),
 +                      PARSE_OPT_NOARG | PARSE_OPT_NONEG, NULL, UNMARK_FLAG},
                OPT_END()
        };
  
  
        git_config(git_default_config, NULL);
  
 -      /* We can't free this memory, it becomes part of a linked list parsed atexit() */
 -      lock_file = xcalloc(1, sizeof(struct lock_file));
 -
        /* we will diagnose later if it turns out that we need to update it */
 -      newfd = hold_locked_index(lock_file, 0);
 +      newfd = hold_locked_index(&lock_file, 0);
        if (newfd < 0)
                lock_error = errno;
  
                die("BUG: bad untracked_cache value: %d", untracked_cache);
        }
  
 -      if (active_cache_changed) {
 +      if (fsmonitor > 0) {
 +              if (git_config_get_fsmonitor() == 0)
 +                      warning(_("core.fsmonitor is unset; "
 +                              "set it if you really want to "
 +                              "enable fsmonitor"));
 +              add_fsmonitor(&the_index);
 +              report(_("fsmonitor enabled"));
 +      } else if (!fsmonitor) {
 +              if (git_config_get_fsmonitor() == 1)
 +                      warning(_("core.fsmonitor is set; "
 +                              "remove it if you really want to "
 +                              "disable fsmonitor"));
 +              remove_fsmonitor(&the_index);
 +              report(_("fsmonitor disabled"));
 +      }
 +
 +      if (active_cache_changed || force_write) {
                if (newfd < 0) {
                        if (refresh_args.flags & REFRESH_QUIET)
                                exit(128);
                        unable_to_lock_die(get_index_file(), lock_error);
                }
 -              if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
 +              if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                        die("Unable to write new index file");
        }
  
 -      rollback_lock_file(lock_file);
 +      rollback_lock_file(&lock_file);
  
        return has_errors ? 1 : 0;
  }
diff --combined cache.h
index a61b2d3f0d79b0f56992e0343803811f5265d716,5a44f79e263b650472b650b72de3b5430243f273..0323853c99e75a1edc2e4415db9490ae36bd2c0f
+++ b/cache.h
@@@ -4,7 -4,6 +4,7 @@@
  #include "git-compat-util.h"
  #include "strbuf.h"
  #include "hashmap.h"
 +#include "list.h"
  #include "advice.h"
  #include "gettext.h"
  #include "convert.h"
  #include "string-list.h"
  #include "pack-revindex.h"
  #include "hash.h"
 -
 -#ifndef platform_SHA_CTX
 -/*
 - * platform's underlying implementation of SHA-1; could be OpenSSL,
 - * blk_SHA, Apple CommonCrypto, etc...  Note that including
 - * SHA1_HEADER may have already defined platform_SHA_CTX for our
 - * own implementations like block-sha1 and ppc-sha1, so we list
 - * the default for OpenSSL compatible SHA-1 implementations here.
 - */
 -#define platform_SHA_CTX      SHA_CTX
 -#define platform_SHA1_Init    SHA1_Init
 -#define platform_SHA1_Update  SHA1_Update
 -#define platform_SHA1_Final           SHA1_Final
 -#endif
 -
 -#define git_SHA_CTX           platform_SHA_CTX
 -#define git_SHA1_Init         platform_SHA1_Init
 -#define git_SHA1_Update               platform_SHA1_Update
 -#define git_SHA1_Final                platform_SHA1_Final
 -
 -#ifdef SHA1_MAX_BLOCK_SIZE
 -#include "compat/sha1-chunked.h"
 -#undef git_SHA1_Update
 -#define git_SHA1_Update               git_SHA1_Update_Chunked
 -#endif
 +#include "path.h"
 +#include "sha1-array.h"
 +#include "repository.h"
  
  #include <zlib.h>
  typedef struct git_zstream {
@@@ -53,8 -74,6 +53,8 @@@ struct object_id 
        unsigned char hash[GIT_MAX_RAWSZ];
  };
  
 +#define the_hash_algo the_repository->hash_algo
 +
  #if defined(DT_UNKNOWN) && !defined(NO_D_TYPE_IN_DIRENT)
  #define DTYPE(de)     ((de)->d_type)
  #else
@@@ -182,7 -201,6 +182,7 @@@ struct cache_entry 
  #define CE_ADDED             (1 << 19)
  
  #define CE_HASHED            (1 << 20)
 +#define CE_FSMONITOR_VALID   (1 << 21)
  #define CE_WT_REMOVE         (1 << 22) /* remove in work directory */
  #define CE_CONFLICTED        (1 << 23)
  
@@@ -306,7 -324,6 +306,7 @@@ static inline unsigned int canon_mode(u
  #define CACHE_TREE_CHANGED    (1 << 5)
  #define SPLIT_INDEX_ORDERED   (1 << 6)
  #define UNTRACKED_CHANGED     (1 << 7)
 +#define FSMONITOR_CHANGED     (1 << 8)
  
  struct split_index;
  struct untracked_cache;
@@@ -320,14 -337,11 +320,14 @@@ struct index_state 
        struct split_index *split_index;
        struct cache_time timestamp;
        unsigned name_hash_initialized : 1,
 -               initialized : 1;
 +               initialized : 1,
 +               drop_cache_tree : 1;
        struct hashmap name_hash;
        struct hashmap dir_hash;
        unsigned char sha1[20];
        struct untracked_cache *untracked;
 +      uint64_t fsmonitor_last_update;
 +      struct ewah_bitmap *fsmonitor_dirty;
  };
  
  extern struct index_state the_index;
@@@ -347,7 -361,7 +347,7 @@@ extern void free_name_hash(struct index
  #define active_cache_tree (the_index.cache_tree)
  
  #define read_cache() read_index(&the_index)
 -#define read_cache_from(path) read_index_from(&the_index, (path))
 +#define read_cache_from(path) read_index_from(&the_index, (path), (get_git_dir()))
  #define read_cache_preload(pathspec) read_index_preload(&the_index, (pathspec))
  #define is_cache_unborn() is_index_unborn(&the_index)
  #define read_cache_unmerged() read_index_unmerged(&the_index)
@@@ -401,6 -415,7 +401,6 @@@ static inline enum object_type object_t
  #define GIT_WORK_TREE_ENVIRONMENT "GIT_WORK_TREE"
  #define GIT_PREFIX_ENVIRONMENT "GIT_PREFIX"
  #define GIT_SUPER_PREFIX_ENVIRONMENT "GIT_INTERNAL_SUPER_PREFIX"
 -#define GIT_TOPLEVEL_PREFIX_ENVIRONMENT "GIT_INTERNAL_TOPLEVEL_PREFIX"
  #define DEFAULT_GIT_DIR_ENVIRONMENT ".git"
  #define DB_ENVIRONMENT "GIT_OBJECT_DIRECTORY"
  #define INDEX_ENVIRONMENT "GIT_INDEX_FILE"
  #define GITATTRIBUTES_FILE ".gitattributes"
  #define INFOATTRIBUTES_FILE "info/attributes"
  #define ATTRIBUTE_MACRO_PREFIX "[attr]"
 +#define GITMODULES_FILE ".gitmodules"
  #define GIT_NOTES_REF_ENVIRONMENT "GIT_NOTES_REF"
  #define GIT_NOTES_DEFAULT_REF "refs/notes/commits"
  #define GIT_NOTES_DISPLAY_REF_ENVIRONMENT "GIT_NOTES_DISPLAY_REF"
  #define GIT_NOGLOB_PATHSPECS_ENVIRONMENT "GIT_NOGLOB_PATHSPECS"
  #define GIT_ICASE_PATHSPECS_ENVIRONMENT "GIT_ICASE_PATHSPECS"
  #define GIT_QUARANTINE_ENVIRONMENT "GIT_QUARANTINE_PATH"
 +#define GIT_OPTIONAL_LOCKS_ENVIRONMENT "GIT_OPTIONAL_LOCKS"
 +
 +/*
 + * Environment variable used in handshaking the wire protocol.
 + * Contains a colon ':' separated list of keys with optional values
 + * 'key[=value]'.  Presence of unknown keys and values must be
 + * ignored.
 + */
 +#define GIT_PROTOCOL_ENVIRONMENT "GIT_PROTOCOL"
 +/* HTTP header used to handshake the wire protocol */
 +#define GIT_PROTOCOL_HEADER "Git-Protocol"
  
  /*
   * This environment variable is expected to contain a boolean indicating
   */
  extern const char * const local_repo_env[];
  
 +extern void setup_git_env(void);
 +
  /*
   * Returns true iff we have a configured git repository (either via
   * setup_git_directory, or in the environment via $GIT_DIR).
@@@ -524,15 -525,12 +524,15 @@@ extern void set_git_work_tree(const cha
  
  extern void setup_work_tree(void);
  /*
 - * Find GIT_DIR of the repository that contains the current working directory,
 - * without changing the working directory or other global state. The result is
 - * appended to gitdir. The return value is either NULL if no repository was
 - * found, or pointing to the path inside gitdir's buffer.
 + * Find the commondir and gitdir of the repository that contains the current
 + * working directory, without changing the working directory or other global
 + * state. The result is appended to commondir and gitdir.  If the discovered
 + * gitdir does not correspond to a worktree, then 'commondir' and 'gitdir' will
 + * both have the same result appended to the buffer.  The return value is
 + * either 0 upon success and non-zero if no repository was found.
   */
 -extern const char *discover_git_directory(struct strbuf *gitdir);
 +extern int discover_git_directory(struct strbuf *commondir,
 +                                struct strbuf *gitdir);
  extern const char *setup_git_directory_gently(int *);
  extern const char *setup_git_directory(void);
  extern char *prefix_path(const char *prefix, int len, const char *path);
@@@ -592,49 -590,15 +592,49 @@@ extern int read_index(struct index_stat
  extern int read_index_preload(struct index_state *, const struct pathspec *pathspec);
  extern int do_read_index(struct index_state *istate, const char *path,
                         int must_exist); /* for testting only! */
 -extern int read_index_from(struct index_state *, const char *path);
 +extern int read_index_from(struct index_state *, const char *path,
 +                         const char *gitdir);
  extern int is_index_unborn(struct index_state *);
  extern int read_index_unmerged(struct index_state *);
 +
 +/* For use with `write_locked_index()`. */
  #define COMMIT_LOCK           (1 << 0)
 -#define CLOSE_LOCK            (1 << 1)
 +#define SKIP_IF_UNCHANGED     (1 << 1)
 +
 +/*
 + * Write the index while holding an already-taken lock. Close the lock,
 + * and if `COMMIT_LOCK` is given, commit it.
 + *
 + * Unless a split index is in use, write the index into the lockfile.
 + *
 + * With a split index, write the shared index to a temporary file,
 + * adjust its permissions and rename it into place, then write the
 + * split index to the lockfile. If the temporary file for the shared
 + * index cannot be created, fall back to the behavior described in
 + * the previous paragraph.
 + *
 + * With `COMMIT_LOCK`, the lock is always committed or rolled back.
 + * Without it, the lock is closed, but neither committed nor rolled
 + * back.
 + *
 + * If `SKIP_IF_UNCHANGED` is given and the index is unchanged, nothing
 + * is written (and the lock is rolled back if `COMMIT_LOCK` is given).
 + */
  extern int write_locked_index(struct index_state *, struct lock_file *lock, unsigned flags);
 +
  extern int discard_index(struct index_state *);
 +extern void move_index_extensions(struct index_state *dst, struct index_state *src);
  extern int unmerged_index(const struct index_state *);
- extern int verify_path(const char *path);
 +
 +/**
 + * Returns 1 if the index differs from HEAD, 0 otherwise. When on an unborn
 + * branch, returns 1 if there are entries in the index, 0 otherwise. If an
 + * strbuf is provided, the space-separated list of files that differ will be
 + * appended to it.
 + */
 +extern int index_has_changes(struct strbuf *sb);
 +
+ extern int verify_path(const char *path, unsigned mode);
  extern int strcmp_offset(const char *s1, const char *s2, size_t *first_change);
  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);
@@@ -707,16 -671,13 +707,16 @@@ extern void *read_blob_data_from_index(
  #define CE_MATCH_IGNORE_MISSING               0x08
  /* enable stat refresh */
  #define CE_MATCH_REFRESH              0x10
 -extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 -extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 +/* don't refresh_fsmonitor state or do stat comparison even if CE_FSMONITOR_VALID is true */
 +#define CE_MATCH_IGNORE_FSMONITOR 0X20
 +extern int ie_match_stat(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
 +extern int ie_modified(struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
  
  #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);
 -extern int index_path(unsigned char *sha1, const char *path, struct stat *st, unsigned flags);
 +#define HASH_RENORMALIZE  4
 +extern int index_fd(struct object_id *oid, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
 +extern int index_path(struct object_id *oid, const char *path, struct stat *st, unsigned flags);
  
  /*
   * Record to sd the data from st that we use to check whether a file
@@@ -745,17 -706,12 +745,17 @@@ extern void fill_stat_cache_info(struc
  extern int refresh_index(struct index_state *, unsigned int flags, const struct pathspec *pathspec, char *seen, const char *header_msg);
  extern struct cache_entry *refresh_cache_entry(struct cache_entry *, unsigned int);
  
 +/*
 + * Opportunistically update the index but do not complain if we can't.
 + * The lockfile is always committed or rolled back.
 + */
  extern void update_index_if_able(struct index_state *, struct lock_file *);
  
  extern int hold_locked_index(struct lock_file *, int);
  extern void set_alternate_index_output(const char *);
  
  extern int verify_index_checksum;
 +extern int verify_ce_order;
  
  /* Environment bits from configuration mechanism */
  extern int trust_executable_bit;
@@@ -809,7 -765,7 +809,7 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 -extern int git_db_env, git_index_env, git_graft_env, git_common_dir_env;
 +extern const char *core_fsmonitor;
  
  /*
   * Include broken refs in all ref iterations, which will
   */
  extern int ref_paranoia;
  
 +/*
 + * Returns the boolean value of $GIT_OPTIONAL_LOCKS (or the default value).
 + */
 +int use_optional_locks(void);
 +
  /*
   * The character that begins a commented line in user-editable file
   * that is subject to stripspace.
@@@ -895,15 -846,11 +895,15 @@@ extern int grafts_replace_parents
  #define GIT_REPO_VERSION 0
  #define GIT_REPO_VERSION_READ 1
  extern int repository_format_precious_objects;
 +extern char *repository_format_partial_clone;
 +extern const char *core_partial_clone_filter_default;
  
  struct repository_format {
        int version;
        int precious_objects;
 +      char *partial_clone; /* value of extensions.partialclone */
        int is_bare;
 +      int hash_algo;
        char *work_tree;
        struct string_list unknown_extensions;
  };
@@@ -941,10 -888,84 +941,10 @@@ extern void check_repository_format(voi
  #define TYPE_CHANGED    0x0040
  
  /*
 - * Return a statically allocated filename, either generically (mkpath), in
 - * the repository directory (git_path), or in a submodule's repository
 - * directory (git_path_submodule). In all cases, note that the result
 - * may be overwritten by another call to _any_ of the functions. Consider
 - * using the safer "dup" or "strbuf" formats below (in some cases, the
 - * unsafe versions have already been removed).
 - */
 -extern const char *mkpath(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -extern const char *git_common_path(const char *fmt, ...) __attribute__((format (printf, 1, 2)));
 -
 -extern char *mksnpath(char *buf, size_t n, const char *fmt, ...)
 -      __attribute__((format (printf, 3, 4)));
 -extern void strbuf_git_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -extern char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -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)));
 -extern char *mkpathdup(const char *fmt, ...)
 -      __attribute__((format (printf, 1, 2)));
 -extern char *git_pathdup_submodule(const char *path, const char *fmt, ...)
 -      __attribute__((format (printf, 2, 3)));
 -
 -extern void report_linked_checkout_garbage(void);
 -
 -/*
 - * You can define a static memoized git path like:
 - *
 - *    static GIT_PATH_FUNC(git_path_foo, "FOO");
 - *
 - * or use one of the global ones below.
 - */
 -#define GIT_PATH_FUNC(func, filename) \
 -      const char *func(void) \
 -      { \
 -              static char *ret; \
 -              if (!ret) \
 -                      ret = git_pathdup(filename); \
 -              return ret; \
 -      }
 -
 -const char *git_path_cherry_pick_head(void);
 -const char *git_path_revert_head(void);
 -const char *git_path_squash_msg(void);
 -const char *git_path_merge_msg(void);
 -const char *git_path_merge_rr(void);
 -const char *git_path_merge_mode(void);
 -const char *git_path_merge_head(void);
 -const char *git_path_fetch_head(void);
 -const char *git_path_shallow(void);
 -
 -/*
 - * Return the name of the file in the local object database that would
 - * be used to store a loose object with the specified sha1.  The
 - * return value is a pointer to a statically allocated buffer that is
 - * overwritten each time the function is called.
 - */
 -extern const char *sha1_file_name(const unsigned char *sha1);
 -
 -/*
 - * Return the name of the (local) packfile with the specified sha1 in
 - * its name.  The return value is a pointer to memory that is
 - * overwritten each time this function is called.
 + * Put in `buf` the name of the file in the local object database that
 + * would be used to store a loose object with the specified sha1.
   */
 -extern char *sha1_pack_name(const unsigned char *sha1);
 -
 -/*
 - * Return the name of the (local) pack index file with the specified
 - * sha1 in its name.  The return value is a pointer to memory that is
 - * overwritten each time this function is called.
 - */
 -extern char *sha1_pack_index_name(const unsigned char *sha1);
 +extern void sha1_file_name(struct strbuf *buf, const unsigned char *sha1);
  
  /*
   * Return an abbreviated sha1 unique within this repository's object database.
@@@ -969,7 -990,14 +969,7 @@@ extern const struct object_id null_oid
  
  static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2)
  {
 -      int i;
 -
 -      for (i = 0; i < GIT_SHA1_RAWSZ; i++, sha1++, sha2++) {
 -              if (*sha1 != *sha2)
 -                      return *sha1 - *sha2;
 -      }
 -
 -      return 0;
 +      return memcmp(sha1, sha2, GIT_SHA1_RAWSZ);
  }
  
  static inline int oidcmp(const struct object_id *oid1, const struct object_id *oid2)
@@@ -997,13 -1025,6 +997,13 @@@ static inline void oidcpy(struct object
        hashcpy(dst->hash, src->hash);
  }
  
 +static inline struct object_id *oiddup(const struct object_id *src)
 +{
 +      struct object_id *dst = xmalloc(sizeof(struct object_id));
 +      oidcpy(dst, src);
 +      return dst;
 +}
 +
  static inline void hashclr(unsigned char *hash)
  {
        memset(hash, 0, GIT_SHA1_RAWSZ);
  
  static inline void oidclr(struct object_id *oid)
  {
 -      hashclr(oid->hash);
 +      memset(oid->hash, 0, GIT_MAX_RAWSZ);
  }
  
  
@@@ -1029,25 -1050,27 +1029,25 @@@ extern const struct object_id empty_tre
        "\xe6\x9d\xe2\x9b\xb2\xd1\xd6\x43\x4b\x8b" \
        "\x29\xae\x77\x5a\xd8\xc2\xe4\x8c\x53\x91"
  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);
 +      return !hashcmp(sha1, the_hash_algo->empty_blob->hash);
  }
  
  static inline int is_empty_blob_oid(const struct object_id *oid)
  {
 -      return !hashcmp(oid->hash, EMPTY_BLOB_SHA1_BIN);
 +      return !oidcmp(oid, the_hash_algo->empty_blob);
  }
  
  static inline int is_empty_tree_sha1(const unsigned char *sha1)
  {
 -      return !hashcmp(sha1, EMPTY_TREE_SHA1_BIN);
 +      return !hashcmp(sha1, the_hash_algo->empty_tree->hash);
  }
  
  static inline int is_empty_tree_oid(const struct object_id *oid)
  {
 -      return !hashcmp(oid->hash, EMPTY_TREE_SHA1_BIN);
 +      return !oidcmp(oid, the_hash_algo->empty_tree);
  }
  
  /* set default permissions by passing mode arguments to open(2) */
@@@ -1165,7 -1188,15 +1165,15 @@@ int normalize_path_copy(char *dst, cons
  int longest_ancestor_length(const char *path, struct string_list *prefixes);
  char *strip_path_suffix(const char *path, const char *suffix);
  int daemon_avoid_alias(const char *path);
- extern int is_ntfs_dotgit(const char *name);
+ /*
+  * These functions match their is_hfs_dotgit() counterparts; see utf8.h for
+  * details.
+  */
+ int is_ntfs_dotgit(const char *name);
+ int is_ntfs_dotgitmodules(const char *name);
+ int is_ntfs_dotgitignore(const char *name);
+ int is_ntfs_dotgitattributes(const char *name);
  
  /*
   * Returns true iff "str" could be confused as a command-line option when
@@@ -1189,12 -1220,13 +1197,12 @@@ extern char *xdg_config_home(const cha
   */
  extern char *xdg_cache_home(const char *filename);
  
 -/* object replacement */
 -#define LOOKUP_REPLACE_OBJECT 1
 -#define LOOKUP_UNKNOWN_OBJECT 2
 -extern void *read_sha1_file_extended(const unsigned char *sha1, enum object_type *type, unsigned long *size, unsigned flag);
 +extern void *read_sha1_file_extended(const unsigned char *sha1,
 +                                   enum object_type *type,
 +                                   unsigned long *size, int lookup_replace);
  static inline void *read_sha1_file(const unsigned char *sha1, enum object_type *type, unsigned long *size)
  {
 -      return read_sha1_file_extended(sha1, type, size, LOOKUP_REPLACE_OBJECT);
 +      return read_sha1_file_extended(sha1, type, size, 1);
  }
  
  /*
@@@ -1216,34 -1248,35 +1224,34 @@@ static inline const unsigned char *look
        return do_lookup_replace_object(sha1);
  }
  
 -static inline const unsigned char *lookup_replace_object_extended(const unsigned char *sha1, unsigned flag)
 -{
 -      if (!(flag & LOOKUP_REPLACE_OBJECT))
 -              return sha1;
 -      return lookup_replace_object(sha1);
 -}
 -
  /* Read and unpack a sha1 file into memory, write memory to a sha1 file */
  extern int sha1_object_info(const unsigned char *, unsigned long *);
 -extern int hash_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *sha1);
 -extern int write_sha1_file(const void *buf, unsigned long len, const char *type, unsigned char *return_sha1);
 -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 hash_object_file(const void *buf, unsigned long len,
 +                          const char *type, struct object_id *oid);
 +
 +extern int write_object_file(const void *buf, unsigned long len,
 +                           const char *type, struct object_id *oid);
 +
 +extern int hash_object_file_literally(const void *buf, unsigned long len,
 +                                    const char *type, struct object_id *oid,
 +                                    unsigned flags);
 +
 +extern int pretend_object_file(void *, unsigned long, enum object_type,
 +                             struct object_id *oid);
 +
 +extern int force_object_loose(const struct object_id *oid, time_t mtime);
 +
  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);
  
 -/* global flag to enable extra checks when accessing packed objects */
 -extern int do_check_packed_object_crc;
 -
  extern int check_sha1_signature(const unsigned char *sha1, void *buf, unsigned long size, const char *type);
  
  extern int finalize_object_file(const char *tmpfile, const char *filename);
  
 -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,
@@@ -1258,10 -1291,15 +1266,10 @@@ int read_loose_object(const char *path
                      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
 - * function does not respect replace references.
 - *
 - * If the QUICK flag is set, do not re-check the pack directory
 - * when we cannot find the object (this means we may give a false
 - * negative answer if another process is simultaneously repacking).
 + * Convenience for sha1_object_info_extended() with a NULL struct
 + * object_info. OBJECT_INFO_SKIP_CACHED is automatically set; pass
 + * nonzero flags to also set other flags.
   */
 -#define HAS_SHA1_QUICK 0x1
  extern int has_sha1_file_with_flags(const unsigned char *sha1, int flags);
  static inline int has_sha1_file(const unsigned char *sha1)
  {
@@@ -1279,6 -1317,8 +1287,6 @@@ extern int has_object_file_with_flags(c
   */
  extern int has_loose_object_nonlocal(const unsigned char *sha1);
  
 -extern int has_pack_index(const unsigned char *sha1);
 -
  extern void assert_sha1_type(const unsigned char *sha1, enum object_type expect);
  
  /* Helper to check and "touch" a file */
@@@ -1296,8 -1336,8 +1304,8 @@@ static inline unsigned int hexval(unsig
   */
  static inline int hex2chr(const char *s)
  {
 -      int val = hexval(s[0]);
 -      return (val < 0) ? val : (val << 4) | hexval(s[1]);
 +      unsigned int val = hexval(s[0]);
 +      return (val & ~0xf) ? val : (val << 4) | hexval(s[1]);
  }
  
  /* Convert to/from hex/sha1 representation */
@@@ -1316,37 -1356,38 +1324,37 @@@ struct object_context 
         */
        struct strbuf symlink_path;
        /*
 -       * If GET_SHA1_RECORD_PATH is set, this will record path (if any)
 +       * If GET_OID_RECORD_PATH is set, this will record path (if any)
         * found when resolving the name. The caller is responsible for
         * releasing the memory.
         */
        char *path;
  };
  
 -#define GET_SHA1_QUIETLY           01
 -#define GET_SHA1_COMMIT            02
 -#define GET_SHA1_COMMITTISH        04
 -#define GET_SHA1_TREE             010
 -#define GET_SHA1_TREEISH          020
 -#define GET_SHA1_BLOB             040
 -#define GET_SHA1_FOLLOW_SYMLINKS 0100
 -#define GET_SHA1_RECORD_PATH     0200
 -#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);
 -extern int get_sha1_tree(const char *str, unsigned char *sha1);
 -extern int get_sha1_treeish(const char *str, unsigned char *sha1);
 -extern int get_sha1_blob(const char *str, unsigned char *sha1);
 -extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 -extern int get_sha1_with_context(const char *str, unsigned flags, unsigned char *sha1, struct object_context *oc);
 +#define GET_OID_QUIETLY           01
 +#define GET_OID_COMMIT            02
 +#define GET_OID_COMMITTISH        04
 +#define GET_OID_TREE             010
 +#define GET_OID_TREEISH          020
 +#define GET_OID_BLOB             040
 +#define GET_OID_FOLLOW_SYMLINKS 0100
 +#define GET_OID_RECORD_PATH     0200
 +#define GET_OID_ONLY_TO_DIE    04000
 +
 +#define GET_OID_DISAMBIGUATORS \
 +      (GET_OID_COMMIT | GET_OID_COMMITTISH | \
 +      GET_OID_TREE | GET_OID_TREEISH | \
 +      GET_OID_BLOB)
  
  extern int get_oid(const char *str, struct object_id *oid);
 +extern int get_oid_commit(const char *str, struct object_id *oid);
 +extern int get_oid_committish(const char *str, struct object_id *oid);
 +extern int get_oid_tree(const char *str, struct object_id *oid);
 +extern int get_oid_treeish(const char *str, struct object_id *oid);
 +extern int get_oid_blob(const char *str, struct object_id *oid);
 +extern void maybe_die_on_misspelt_object_name(const char *name, const char *prefix);
 +extern int get_oid_with_context(const char *str, unsigned flags, struct object_id *oid, struct object_context *oc);
 +
  
  typedef int each_abbrev_fn(const struct object_id *oid, void *);
  extern int for_each_abbrev(const char *prefix, each_abbrev_fn, void *);
@@@ -1363,13 -1404,6 +1371,13 @@@ extern int set_disambiguate_hint_config
  extern int get_sha1_hex(const char *hex, unsigned char *sha1);
  extern int get_oid_hex(const char *hex, struct object_id *sha1);
  
 +/*
 + * Read `len` pairs of hexadecimal digits from `hex` and write the
 + * values to `binary` as `len` bytes. Return 0 on success, or -1 if
 + * the input does not consist of hex digits).
 + */
 +extern int hex_to_bytes(unsigned char *binary, const char *hex, size_t len);
 +
  /*
   * Convert a binary sha1 to its hex equivalent. The `_r` variant is reentrant,
   * and writes the NUL-terminated output to the buffer `out`, which must be at
@@@ -1467,18 -1501,18 +1475,18 @@@ struct date_mode 
  #define DATE_MODE(t) date_mode_from_type(DATE_##t)
  struct date_mode *date_mode_from_type(enum date_mode_type type);
  
 -const char *show_date(unsigned long time, int timezone, const struct date_mode *mode);
 -void show_date_relative(unsigned long time, int tz, const struct timeval *now,
 +const char *show_date(timestamp_t time, int timezone, const struct date_mode *mode);
 +void show_date_relative(timestamp_t time, int tz, const struct timeval *now,
                        struct strbuf *timebuf);
  int parse_date(const char *date, struct strbuf *out);
 -int parse_date_basic(const char *date, unsigned long *timestamp, int *offset);
 -int parse_expiry_date(const char *date, unsigned long *timestamp);
 +int parse_date_basic(const char *date, timestamp_t *timestamp, int *offset);
 +int parse_expiry_date(const char *date, timestamp_t *timestamp);
  void datestamp(struct strbuf *out);
  #define approxidate(s) approxidate_careful((s), NULL)
 -unsigned long approxidate_careful(const char *, int *);
 -unsigned long approxidate_relative(const char *date, const struct timeval *now);
 +timestamp_t approxidate_careful(const char *, int *);
 +timestamp_t approxidate_relative(const char *date, const struct timeval *now);
  void parse_date_format(const char *format, struct date_mode *mode);
 -int date_overflows(unsigned long date);
 +int date_overflows(timestamp_t date);
  
  #define IDENT_STRICT         1
  #define IDENT_NO_DATE        2
@@@ -1491,7 -1525,6 +1499,7 @@@ extern const char *ident_default_name(v
  extern const char *ident_default_email(void);
  extern const char *git_editor(void);
  extern const char *git_pager(int stdout_is_tty);
 +extern int is_terminal_dumb(void);
  extern int git_ident_config(const char *, const char *, void *);
  extern void reset_ident_date(void);
  
@@@ -1532,7 -1565,6 +1540,7 @@@ struct checkout 
        struct index_state *istate;
        const char *base_dir;
        int base_dir_len;
 +      struct delayed_checkout *delayed_checkout;
        unsigned force:1,
                 quiet:1,
                 not_new:1,
  
  #define TEMPORARY_FILENAME_LENGTH 25
  extern int checkout_entry(struct cache_entry *ce, const struct checkout *state, char *topath);
 +extern void enable_delayed_checkout(struct checkout *state);
 +extern int finish_delayed_checkout(struct checkout *state);
  
  struct cache_def {
        struct strbuf path;
@@@ -1571,19 -1601,10 +1579,19 @@@ extern struct alternate_object_databas
        struct strbuf scratch;
        size_t base_len;
  
 +      /*
 +       * Used to store the results of readdir(3) calls when searching
 +       * for unique abbreviated hashes.  This cache is never
 +       * invalidated, thus it's racy and not necessarily accurate.
 +       * That's fine for its purpose; don't use it for tasks requiring
 +       * greater accuracy!
 +       */
 +      char loose_objects_subdir_seen[256];
 +      struct oid_array loose_objects_cache;
 +
        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 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*);
@@@ -1626,7 -1647,6 +1634,7 @@@ struct pack_window 
  
  extern struct packed_git {
        struct packed_git *next;
 +      struct list_head mru;
        struct pack_window *windows;
        off_t pack_size;
        const void *index_data;
        unsigned pack_local:1,
                 pack_keep:1,
                 freshened:1,
 -               do_not_close:1;
 +               do_not_close:1,
 +               pack_promisor:1;
        unsigned char sha1[20];
        struct revindex_entry *revindex;
        /* something like ".git/objects/pack/xxxxx.pack" */
  } *packed_git;
  
  /*
 - * A most-recently-used ordered version of the packed_git list, which can
 - * be iterated instead of packed_git (and marked via mru_mark).
 + * A most-recently-used ordered version of the packed_git list.
   */
 -struct mru;
 -extern struct mru *packed_git_mru;
 +extern struct list_head packed_git_mru;
  
  struct pack_entry {
        off_t offset;
        struct packed_git *p;
  };
  
 -extern struct packed_git *parse_pack_index(unsigned char *sha1, const char *idx_path);
 -
 -/* A hook to report invalid files in pack directory */
 -#define PACKDIR_FILE_PACK 1
 -#define PACKDIR_FILE_IDX 2
 -#define PACKDIR_FILE_GARBAGE 4
 -extern void (*report_garbage)(unsigned seen_bits, const char *path);
 -
 -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);
 -
 -extern void pack_report(void);
 -
  /*
   * Create a temporary file rooted in the object database directory, or
   * die on failure. The filename is taken from "pattern", which should have the
   * usual "XXXXXX" trailer, and the resulting filename is written into the
   * "template" buffer. Returns the open descriptor.
   */
 -extern int odb_mkstemp(struct strbuf *template, const char *pattern);
 -
 -/*
 - * Generate the filename to be used for a pack file with checksum "sha1" and
 - * extension "ext". The result is written into the strbuf "buf", overwriting
 - * any existing contents. A pointer to buf->buf is returned as a convenience.
 - *
 - * Example: odb_pack_name(out, sha1, "idx") => ".git/objects/pack/pack-1234..idx"
 - */
 -extern char *odb_pack_name(struct strbuf *buf, const unsigned char *sha1, const char *ext);
 +extern int odb_mkstemp(struct strbuf *temp_filename, const char *pattern);
  
  /*
   * Create a pack .keep file named "name" (which should generally be the output
   */
  extern int odb_pack_keep(const char *name);
  
 -/*
 - * mmap the index file for the specified packfile (if it is not
 - * already mmapped).  Return 0 on success.
 - */
 -extern int open_pack_index(struct packed_git *);
 -
 -/*
 - * munmap the index file for the specified packfile (if it is
 - * currently mmapped).
 - */
 -extern void close_pack_index(struct packed_git *);
 -
 -extern unsigned char *use_pack(struct packed_git *, struct pack_window **, off_t, unsigned long *);
 -extern void close_pack_windows(struct packed_git *);
 -extern void close_all_packs(void);
 -extern void unuse_pack(struct pack_window **);
 -extern void clear_delta_base_cache(void);
 -extern struct packed_git *add_packed_git(const char *path, size_t path_len, int local);
 -
 -/*
 - * Make sure that a pointer access into an mmap'd index file is within bounds,
 - * and can provide at least 8 bytes of data.
 - *
 - * Note that this is only necessary for variable-length segments of the file
 - * (like the 64-bit extended offset table), as we compare the size to the
 - * fixed-length parts when we open the file.
 - */
 -extern void check_pack_index_ptr(const struct packed_git *p, const void *ptr);
 -
 -/*
 - * Return the SHA-1 of the nth object within the specified packfile.
 - * Open the index if it is not already open.  The return value points
 - * at the SHA-1 within the mmapped index.  Return NULL if there is an
 - * error.
 - */
 -extern const unsigned char *nth_packed_object_sha1(struct packed_git *, uint32_t n);
 -/*
 - * Like nth_packed_object_sha1, but write the data into the object specified by
 - * the the first argument.  Returns the first argument on success, and NULL on
 - * error.
 - */
 -extern const struct object_id *nth_packed_object_oid(struct object_id *, struct packed_git *, uint32_t n);
 -
 -/*
 - * Return the offset of the nth object within the specified packfile.
 - * The index must already be opened.
 - */
 -extern off_t nth_packed_object_offset(const struct packed_git *, uint32_t n);
 -
 -/*
 - * If the object named sha1 is present in the specified packfile,
 - * return its offset within the packfile; otherwise, return 0.
 - */
 -extern off_t find_pack_entry_one(const unsigned char *sha1, struct packed_git *);
 -
 -extern int is_pack_valid(struct packed_git *);
 -extern void *unpack_entry(struct packed_git *, off_t, enum object_type *, unsigned long *);
 -extern unsigned long unpack_object_header_buffer(const unsigned char *buf, unsigned long len, enum object_type *type, unsigned long *sizep);
 -extern unsigned long get_size_from_delta(struct packed_git *, struct pack_window **, off_t);
 -extern int unpack_object_header(struct packed_git *, struct pack_window **, off_t *, unsigned long *);
 -
  /*
   * Iterate over the files in the loose-object parts of the object
   * directory "path", triggering the following callbacks:
@@@ -1702,15 -1816,9 +1710,15 @@@ typedef int each_loose_object_fn(const 
  typedef int each_loose_cruft_fn(const char *basename,
                                const char *path,
                                void *data);
 -typedef int each_loose_subdir_fn(int nr,
 +typedef int each_loose_subdir_fn(unsigned int nr,
                                 const char *path,
                                 void *data);
 +int for_each_file_in_obj_subdir(unsigned int subdir_nr,
 +                              struct strbuf *path,
 +                              each_loose_object_fn obj_cb,
 +                              each_loose_cruft_fn cruft_cb,
 +                              each_loose_subdir_fn subdir_cb,
 +                              void *data);
  int for_each_loose_file_in_objdir(const char *path,
                                  each_loose_object_fn obj_cb,
                                  each_loose_cruft_fn cruft_cb,
@@@ -1723,12 -1831,17 +1731,12 @@@ int for_each_loose_file_in_objdir_buf(s
                                      void *data);
  
  /*
 - * Iterate over loose and packed objects in both the local
 + * Iterate over loose objects in both the local
   * repository and any alternates repositories (unless the
   * LOCAL_ONLY flag is set).
   */
  #define FOR_EACH_OBJECT_LOCAL_ONLY 0x1
 -typedef int each_packed_object_fn(const struct object_id *oid,
 -                                struct packed_git *pack,
 -                                uint32_t pos,
 -                                void *data);
  extern int for_each_loose_object(each_loose_object_fn, void *, unsigned flags);
 -extern int for_each_packed_object(each_packed_object_fn, void *, unsigned flags);
  
  struct object_info {
        /* Request */
        unsigned long *sizep;
        off_t *disk_sizep;
        unsigned char *delta_base_sha1;
 -      struct strbuf *typename;
 +      struct strbuf *type_name;
 +      void **contentp;
  
        /* Response */
        enum {
   */
  #define OBJECT_INFO_INIT {NULL}
  
 +/* Invoke lookup_replace_object() on the given hash */
 +#define OBJECT_INFO_LOOKUP_REPLACE 1
 +/* Allow reading from a loose object file of unknown/bogus type */
 +#define OBJECT_INFO_ALLOW_UNKNOWN_TYPE 2
 +/* Do not check cached storage */
 +#define OBJECT_INFO_SKIP_CACHED 4
 +/* Do not retry packed storage after checking packed and loose storage */
 +#define OBJECT_INFO_QUICK 8
  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);
 -
 -/* git_config_parse_key() returns these negated: */
 -#define CONFIG_INVALID_KEY 1
 -#define CONFIG_NO_SECTION_OR_NAME 2
 -/* git_config_set_gently(), git_config_set_multivar_gently() return the above or these: */
 -#define CONFIG_NO_LOCK -1
 -#define CONFIG_INVALID_FILE 3
 -#define CONFIG_NO_WRITE 4
 -#define CONFIG_NOTHING_SET 5
 -#define CONFIG_INVALID_PATTERN 6
 -#define CONFIG_GENERIC_ERROR 7
 -
 -#define CONFIG_REGEX_NONE ((void *)1)
 -
 -struct git_config_source {
 -      unsigned int use_stdin:1;
 -      const char *file;
 -      const char *blob;
 -};
 -
 -enum config_origin_type {
 -      CONFIG_ORIGIN_BLOB,
 -      CONFIG_ORIGIN_FILE,
 -      CONFIG_ORIGIN_STDIN,
 -      CONFIG_ORIGIN_SUBMODULE_BLOB,
 -      CONFIG_ORIGIN_CMDLINE
 -};
 -
 -struct config_options {
 -      unsigned int respect_includes : 1;
 -      const char *git_dir;
 -};
 -
 -typedef int (*config_fn_t)(const char *, const char *, void *);
 -extern int git_default_config(const char *, const char *, void *);
 -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 read_early_config(config_fn_t cb, void *data);
 -extern void git_config(config_fn_t fn, void *);
 -extern int git_config_with_options(config_fn_t fn, void *,
 -                                 struct git_config_source *config_source,
 -                                 const struct config_options *opts);
 -extern int git_parse_ulong(const char *, unsigned long *);
 -extern int git_parse_maybe_bool(const char *);
 -extern int git_config_int(const char *, const char *);
 -extern int64_t git_config_int64(const char *, const char *);
 -extern unsigned long git_config_ulong(const char *, const char *);
 -extern ssize_t git_config_ssize_t(const char *, const char *);
 -extern int git_config_bool_or_int(const char *, const char *, int *);
 -extern int git_config_bool(const char *, const char *);
 -extern int git_config_maybe_bool(const char *, const char *);
 -extern int git_config_string(const char **, const char *, const char *);
 -extern int git_config_pathname(const char **, const char *, const char *);
 -extern int git_config_set_in_file_gently(const char *, const char *, const char *);
 -extern void git_config_set_in_file(const char *, const char *, const char *);
 -extern int git_config_set_gently(const char *, const char *);
 -extern void git_config_set(const char *, const char *);
 -extern int git_config_parse_key(const char *, char **, int *);
 -extern int git_config_key_is_valid(const char *key);
 -extern int git_config_set_multivar_gently(const char *, const char *, const char *, int);
 -extern void git_config_set_multivar(const char *, const char *, const char *, int);
 -extern int git_config_set_multivar_in_file_gently(const char *, const char *, const char *, const char *, int);
 -extern void git_config_set_multivar_in_file(const char *, const char *, const char *, const char *, int);
 -extern int git_config_rename_section(const char *, const char *);
 -extern int git_config_rename_section_in_file(const char *, const char *, const char *);
 -extern const char *git_etc_gitconfig(void);
 -extern int git_env_bool(const char *, int);
 -extern unsigned long git_env_ulong(const char *, unsigned long);
 -extern int git_config_system(void);
 -extern int config_error_nonbool(const char *);
 -#if defined(__GNUC__)
 -#define config_error_nonbool(s) (config_error_nonbool(s), const_error())
 -#endif
 -extern const char *get_log_output_encoding(void);
 -extern const char *get_commit_output_encoding(void);
 -
 -extern int git_config_parse_parameter(const char *, config_fn_t fn, void *data);
 -
 -enum config_scope {
 -      CONFIG_SCOPE_UNKNOWN = 0,
 -      CONFIG_SCOPE_SYSTEM,
 -      CONFIG_SCOPE_GLOBAL,
 -      CONFIG_SCOPE_REPO,
 -      CONFIG_SCOPE_CMDLINE,
 -};
 -
 -extern enum config_scope current_config_scope(void);
 -extern const char *current_config_origin_type(void);
 -extern const char *current_config_name(void);
 -
 -struct config_include_data {
 -      int depth;
 -      config_fn_t fn;
 -      void *data;
 -      const struct config_options *opts;
 -};
 -#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
 + * Set this to 0 to prevent sha1_object_info_extended() from fetching missing
 + * blobs. This has a difference only if extensions.partialClone is set.
   *
 - * (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).
 - *
 - * If the subsection pointer-to-pointer passed in is NULL, returns 0 only if
 - * there is no subsection at all.
 - */
 -extern int parse_config_key(const char *var,
 -                          const char *section,
 -                          const char **subsection, int *subsection_len,
 -                          const char **key);
 -
 -struct config_set_element {
 -      struct hashmap_entry ent;
 -      char *key;
 -      struct string_list value_list;
 -};
 -
 -struct configset_list_item {
 -      struct config_set_element *e;
 -      int value_index;
 -};
 -
 -/*
 - * the contents of the list are ordered according to their
 - * position in the config files and order of parsing the files.
 - * (i.e. key-value pair at the last position of .git/config will
 - * be at the last item of the list)
 + * Its default value is 1.
   */
 -struct configset_list {
 -      struct configset_list_item *items;
 -      unsigned int nr, alloc;
 -};
 +extern int fetch_if_missing;
  
 -struct config_set {
 -      struct hashmap config_hash;
 -      int hash_initialized;
 -      struct configset_list list;
 -};
 +/* Dumb servers support */
 +extern int update_server_info(int);
  
 -extern void git_configset_init(struct config_set *cs);
 -extern int git_configset_add_file(struct config_set *cs, const char *filename);
 -extern int git_configset_get_value(struct config_set *cs, const char *key, const char **value);
 -extern const struct string_list *git_configset_get_value_multi(struct config_set *cs, const char *key);
 -extern void git_configset_clear(struct config_set *cs);
 -extern int git_configset_get_string_const(struct config_set *cs, const char *key, const char **dest);
 -extern int git_configset_get_string(struct config_set *cs, const char *key, char **dest);
 -extern int git_configset_get_int(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_ulong(struct config_set *cs, const char *key, unsigned long *dest);
 -extern int git_configset_get_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_bool_or_int(struct config_set *cs, const char *key, int *is_bool, int *dest);
 -extern int git_configset_get_maybe_bool(struct config_set *cs, const char *key, int *dest);
 -extern int git_configset_get_pathname(struct config_set *cs, const char *key, const char **dest);
 -
 -extern int git_config_get_value(const char *key, const char **value);
 -extern const struct string_list *git_config_get_value_multi(const char *key);
 -extern void git_config_clear(void);
 -extern void git_config_iter(config_fn_t fn, void *data);
 -extern int git_config_get_string_const(const char *key, const char **dest);
 -extern int git_config_get_string(const char *key, char **dest);
 -extern int git_config_get_int(const char *key, int *dest);
 -extern int git_config_get_ulong(const char *key, unsigned long *dest);
 -extern int git_config_get_bool(const char *key, int *dest);
 -extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest);
 -extern int git_config_get_maybe_bool(const char *key, int *dest);
 -extern int git_config_get_pathname(const char *key, const char **dest);
 -extern int git_config_get_untracked_cache(void);
 -extern int git_config_get_split_index(void);
 -extern int git_config_get_max_percent_split_change(void);
 -
 -/* This dies if the configured or default date is in the future */
 -extern int git_config_get_expiry(const char *key, const char **output);
 +extern const char *get_log_output_encoding(void);
 +extern const char *get_commit_output_encoding(void);
  
  /*
   * This is a hack for test programs like test-dump-untracked-cache to
   */
  extern int ignore_untracked_cache_config;
  
 -struct key_value_info {
 -      const char *filename;
 -      int linenr;
 -      enum config_origin_type origin_type;
 -      enum config_scope scope;
 -};
 -
 -extern NORETURN void git_die_config(const char *key, const char *err, ...) __attribute__((format(printf, 2, 3)));
 -extern NORETURN void git_die_config_linenr(const char *key, const char *filename, int linenr);
 -
  extern int committer_ident_sufficiently_given(void);
  extern int author_ident_sufficiently_given(void);
  
@@@ -1904,8 -2190,6 +1912,8 @@@ void shift_tree_by(const struct object_
  #define WS_TRAILING_SPACE      (WS_BLANK_AT_EOL|WS_BLANK_AT_EOF)
  #define WS_DEFAULT_RULE (WS_TRAILING_SPACE|WS_SPACE_BEFORE_TAB|8)
  #define WS_TAB_WIDTH_MASK        077
 +/* All WS_* -- when extended, adapt diff.c emit_symbol */
 +#define WS_RULE_MASK           07777
  extern unsigned whitespace_rule_cfg;
  extern unsigned whitespace_rule(const char *);
  extern unsigned parse_whitespace_rule(const char *);
@@@ -1917,8 -2201,7 +1925,8 @@@ extern int ws_blank_line(const char *li
  #define ws_tab_width(rule)     ((rule) & WS_TAB_WIDTH_MASK)
  
  /* ls-files */
 -void overlay_tree_on_cache(const char *tree_name, const char *prefix);
 +void overlay_tree_on_index(struct index_state *istate,
 +                         const char *tree_name, const char *prefix);
  
  char *alias_lookup(const char *alias);
  int split_cmdline(char *cmdline, const char ***argv);
@@@ -1937,8 -2220,8 +1945,8 @@@ struct commit_list
  int try_merge_command(const char *strategy, size_t xopts_nr,
                const char **xopts, struct commit_list *common,
                const char *head_arg, struct commit_list *remotes);
 -int checkout_fast_forward(const unsigned char *from,
 -                        const unsigned char *to,
 +int checkout_fast_forward(const struct object_id *from,
 +                        const struct object_id *to,
                          int overwrite_ignore);
  
  
@@@ -1982,10 -2265,4 +1990,10 @@@ void sleep_millisec(int millisec)
   */
  void safe_create_dir(const char *dir, int share);
  
 +/*
 + * Should we print an ellipsis after an abbreviated SHA-1 value
 + * when doing diff-raw output or indicating a detached HEAD?
 + */
 +extern int print_sha1_ellipsis(void);
 +
  #endif /* CACHE_H */
diff --combined dir.c
index dedbf5d476f207e39c1b7853ec8c97553181e5fb,31f9343f9fcf57a89cab519f284cf2e0a767744d..41aac3b7b38e76bb790da4c21c362d7d0f1d1a07
--- 1/dir.c
--- 2/dir.c
+++ b/dir.c
@@@ -7,9 -7,7 +7,9 @@@
   * Copyright (C) Linus Torvalds, 2005-2006
   *             Junio Hamano, 2005-2006
   */
 +#define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
 +#include "config.h"
  #include "dir.h"
  #include "attr.h"
  #include "refs.h"
@@@ -18,7 -16,6 +18,7 @@@
  #include "utf8.h"
  #include "varint.h"
  #include "ewah/ewok.h"
 +#include "fsmonitor.h"
  
  /*
   * Tells read_directory_recursive how a file or directory should be treated.
@@@ -48,20 -45,9 +48,20 @@@ struct cached_dir 
  };
  
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 -      const char *path, int len, struct untracked_cache_dir *untracked,
 -      int check_only, const struct pathspec *pathspec);
 -static int get_dtype(struct dirent *de, const char *path, int len);
 +      struct index_state *istate, const char *path, int len,
 +      struct untracked_cache_dir *untracked,
 +      int check_only, int stop_at_first_file, const struct pathspec *pathspec);
 +static int get_dtype(struct dirent *de, struct index_state *istate,
 +                   const char *path, int len);
 +
 +int count_slashes(const char *s)
 +{
 +      int cnt = 0;
 +      while (*s)
 +              if (*s++ == '/')
 +                      cnt++;
 +      return cnt;
 +}
  
  int fspathcmp(const char *a, const char *b)
  {
@@@ -93,11 -79,13 +93,11 @@@ int git_fnmatch(const struct pathspec_i
        if (item->magic & PATHSPEC_GLOB)
                return wildmatch(pattern, string,
                                 WM_PATHNAME |
 -                               (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0),
 -                               NULL);
 +                               (item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0));
        else
                /* wildmatch has not learned no FNM_PATHNAME mode yet */
                return wildmatch(pattern, string,
 -                               item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0,
 -                               NULL);
 +                               item->magic & PATHSPEC_ICASE ? WM_CASEFOLD : 0);
  }
  
  static int fnmatch_icase_mem(const char *pattern, int patternlen,
  
        if (ignore_case)
                flags |= WM_CASEFOLD;
 -      match_status = wildmatch(use_pat, use_str, flags, NULL);
 +      match_status = wildmatch(use_pat, use_str, flags);
  
        strbuf_release(&pat_buf);
        strbuf_release(&str_buf);
@@@ -186,9 -174,7 +186,9 @@@ char *common_prefix(const struct pathsp
        return len ? xmemdupz(pathspec->items[0].match, len) : NULL;
  }
  
 -int fill_directory(struct dir_struct *dir, const struct pathspec *pathspec)
 +int fill_directory(struct dir_struct *dir,
 +                 struct index_state *istate,
 +                 const struct pathspec *pathspec)
  {
        const char *prefix;
        size_t prefix_len;
        prefix = prefix_len ? pathspec->items[0].match : "";
  
        /* Read the directory and prune it */
 -      read_directory(dir, prefix, prefix_len, pathspec);
 +      read_directory(dir, istate, prefix, prefix_len, pathspec);
  
        return prefix_len;
  }
@@@ -221,55 -207,6 +221,55 @@@ int within_depth(const char *name, int 
        return 1;
  }
  
 +/*
 + * Read the contents of the blob with the given OID into a buffer.
 + * Append a trailing LF to the end if the last line doesn't have one.
 + *
 + * Returns:
 + *    -1 when the OID is invalid or unknown or does not refer to a blob.
 + *     0 when the blob is empty.
 + *     1 along with { data, size } of the (possibly augmented) buffer
 + *       when successful.
 + *
 + * Optionally updates the given oid_stat with the given OID (when valid).
 + */
 +static int do_read_blob(const struct object_id *oid, struct oid_stat *oid_stat,
 +                      size_t *size_out, char **data_out)
 +{
 +      enum object_type type;
 +      unsigned long sz;
 +      char *data;
 +
 +      *size_out = 0;
 +      *data_out = NULL;
 +
 +      data = read_sha1_file(oid->hash, &type, &sz);
 +      if (!data || type != OBJ_BLOB) {
 +              free(data);
 +              return -1;
 +      }
 +
 +      if (oid_stat) {
 +              memset(&oid_stat->stat, 0, sizeof(oid_stat->stat));
 +              oidcpy(&oid_stat->oid, oid);
 +      }
 +
 +      if (sz == 0) {
 +              free(data);
 +              return 0;
 +      }
 +
 +      if (data[sz - 1] != '\n') {
 +              data = xrealloc(data, st_add(sz, 1));
 +              data[sz++] = '\n';
 +      }
 +
 +      *size_out = xsize_t(sz);
 +      *data_out = data;
 +
 +      return 1;
 +}
 +
  #define DO_MATCH_EXCLUDE   (1<<0)
  #define DO_MATCH_DIRECTORY (1<<1)
  #define DO_MATCH_SUBMODULE (1<<2)
@@@ -650,21 -587,31 +650,21 @@@ void add_exclude(const char *string, co
        x->el = el;
  }
  
 -static void *read_skip_worktree_file_from_index(const char *path, size_t *size,
 -                                              struct sha1_stat *sha1_stat)
 +static int read_skip_worktree_file_from_index(const struct index_state *istate,
 +                                            const char *path,
 +                                            size_t *size_out, char **data_out,
 +                                            struct oid_stat *oid_stat)
  {
        int pos, len;
 -      unsigned long sz;
 -      enum object_type type;
 -      void *data;
  
        len = strlen(path);
 -      pos = cache_name_pos(path, len);
 +      pos = index_name_pos(istate, path, len);
        if (pos < 0)
 -              return NULL;
 -      if (!ce_skip_worktree(active_cache[pos]))
 -              return NULL;
 -      data = read_sha1_file(active_cache[pos]->oid.hash, &type, &sz);
 -      if (!data || type != OBJ_BLOB) {
 -              free(data);
 -              return NULL;
 -      }
 -      *size = xsize_t(sz);
 -      if (sha1_stat) {
 -              memset(&sha1_stat->stat, 0, sizeof(sha1_stat->stat));
 -              hashcpy(sha1_stat->sha1, active_cache[pos]->oid.hash);
 -      }
 -      return data;
 +              return -1;
 +      if (!ce_skip_worktree(istate->cache[pos]))
 +              return -1;
 +
 +      return do_read_blob(&istate->cache[pos]->oid, oid_stat, size_out, data_out);
  }
  
  /*
@@@ -744,8 -691,8 +744,8 @@@ static struct untracked_cache_dir *look
        FLEX_ALLOC_MEM(d, name, name, len);
  
        ALLOC_GROW(dir->dirs, dir->dirs_nr + 1, dir->dirs_alloc);
 -      memmove(dir->dirs + first + 1, dir->dirs + first,
 -              (dir->dirs_nr - first) * sizeof(*dir->dirs));
 +      MOVE_ARRAY(dir->dirs + first + 1, dir->dirs + first,
 +                 dir->dirs_nr - first);
        dir->dirs_nr++;
        dir->dirs[first] = d;
        return d;
@@@ -771,29 -718,16 +771,29 @@@ static void invalidate_directory(struc
                                 struct untracked_cache_dir *dir)
  {
        int i;
 -      uc->dir_invalidated++;
 +
 +      /*
 +       * Invalidation increment here is just roughly correct. If
 +       * untracked_nr or any of dirs[].recurse is non-zero, we
 +       * should increment dir_invalidated too. But that's more
 +       * expensive to do.
 +       */
 +      if (dir->valid)
 +              uc->dir_invalidated++;
 +
        dir->valid = 0;
        dir->untracked_nr = 0;
        for (i = 0; i < dir->dirs_nr; i++)
                dir->dirs[i]->recurse = 0;
  }
  
 +static int add_excludes_from_buffer(char *buf, size_t size,
 +                                  const char *base, int baselen,
 +                                  struct exclude_list *el);
 +
  /*
   * Given a file with name "fname", read it (either from disk, or from
 - * the index if "check_index" is non-zero), parse it and store the
 + * an index if 'istate' is non-null), parse it and store the
   * exclude rules in "el".
   *
   * If "ss" is not NULL, compute SHA-1 of the exclude file and fill
   * ss_valid is non-zero, "ss" must contain good value as input.
   */
  static int add_excludes(const char *fname, const char *base, int baselen,
 -                      struct exclude_list *el, int check_index,
 -                      struct sha1_stat *sha1_stat)
 +                      struct exclude_list *el, struct index_state *istate,
 +                      struct oid_stat *oid_stat)
  {
        struct stat st;
 -      int fd, i, lineno = 1;
 +      int r;
 +      int fd;
        size_t size = 0;
 -      char *buf, *entry;
 +      char *buf;
  
        fd = open(fname, O_RDONLY);
        if (fd < 0 || fstat(fd, &st) < 0) {
 -              if (errno != ENOENT)
 -                      warn_on_inaccessible(fname);
 -              if (0 <= fd)
 +              if (fd < 0)
 +                      warn_on_fopen_errors(fname);
 +              else
                        close(fd);
 -              if (!check_index ||
 -                  (buf = read_skip_worktree_file_from_index(fname, &size, sha1_stat)) == NULL)
 +              if (!istate)
                        return -1;
 -              if (size == 0) {
 -                      free(buf);
 -                      return 0;
 -              }
 -              if (buf[size-1] != '\n') {
 -                      buf = xrealloc(buf, st_add(size, 1));
 -                      buf[size++] = '\n';
 -              }
 +              r = read_skip_worktree_file_from_index(istate, fname,
 +                                                     &size, &buf,
 +                                                     oid_stat);
 +              if (r != 1)
 +                      return r;
        } else {
                size = xsize_t(st.st_size);
                if (size == 0) {
 -                      if (sha1_stat) {
 -                              fill_stat_data(&sha1_stat->stat, &st);
 -                              hashcpy(sha1_stat->sha1, EMPTY_BLOB_SHA1_BIN);
 -                              sha1_stat->valid = 1;
 +                      if (oid_stat) {
 +                              fill_stat_data(&oid_stat->stat, &st);
 +                              oidcpy(&oid_stat->oid, &empty_blob_oid);
 +                              oid_stat->valid = 1;
                        }
                        close(fd);
                        return 0;
                }
                buf[size++] = '\n';
                close(fd);
 -              if (sha1_stat) {
 +              if (oid_stat) {
                        int pos;
 -                      if (sha1_stat->valid &&
 -                          !match_stat_data_racy(&the_index, &sha1_stat->stat, &st))
 +                      if (oid_stat->valid &&
 +                          !match_stat_data_racy(istate, &oid_stat->stat, &st))
                                ; /* no content change, ss->sha1 still good */
 -                      else if (check_index &&
 -                               (pos = cache_name_pos(fname, strlen(fname))) >= 0 &&
 -                               !ce_stage(active_cache[pos]) &&
 -                               ce_uptodate(active_cache[pos]) &&
 -                               !would_convert_to_git(fname))
 -                              hashcpy(sha1_stat->sha1,
 -                                      active_cache[pos]->oid.hash);
 +                      else if (istate &&
 +                               (pos = index_name_pos(istate, fname, strlen(fname))) >= 0 &&
 +                               !ce_stage(istate->cache[pos]) &&
 +                               ce_uptodate(istate->cache[pos]) &&
 +                               !would_convert_to_git(istate, fname))
 +                              oidcpy(&oid_stat->oid,
 +                                     &istate->cache[pos]->oid);
                        else
 -                              hash_sha1_file(buf, size, "blob", sha1_stat->sha1);
 -                      fill_stat_data(&sha1_stat->stat, &st);
 -                      sha1_stat->valid = 1;
 +                              hash_object_file(buf, size, "blob",
 +                                               &oid_stat->oid);
 +                      fill_stat_data(&oid_stat->stat, &st);
 +                      oid_stat->valid = 1;
                }
        }
  
 +      add_excludes_from_buffer(buf, size, base, baselen, el);
 +      return 0;
 +}
 +
 +static int add_excludes_from_buffer(char *buf, size_t size,
 +                                  const char *base, int baselen,
 +                                  struct exclude_list *el)
 +{
 +      int i, lineno = 1;
 +      char *entry;
 +
        el->filebuf = buf;
  
        if (skip_utf8_bom(&buf, size))
  
  int add_excludes_from_file_to_list(const char *fname, const char *base,
                                   int baselen, struct exclude_list *el,
 -                                 int check_index)
 +                                 struct index_state *istate)
  {
 -      return add_excludes(fname, base, baselen, el, check_index, NULL);
 +      return add_excludes(fname, base, baselen, el, istate, NULL);
 +}
 +
 +int add_excludes_from_blob_to_list(
 +      struct object_id *oid,
 +      const char *base, int baselen,
 +      struct exclude_list *el)
 +{
 +      char *buf;
 +      size_t size;
 +      int r;
 +
 +      r = do_read_blob(oid, NULL, &size, &buf);
 +      if (r != 1)
 +              return r;
 +
 +      add_excludes_from_buffer(buf, size, base, baselen, el);
 +      return 0;
  }
  
  struct exclude_list *add_exclude_list(struct dir_struct *dir,
   * Used to set up core.excludesfile and .git/info/exclude lists.
   */
  static void add_excludes_from_file_1(struct dir_struct *dir, const char *fname,
 -                                   struct sha1_stat *sha1_stat)
 +                                   struct oid_stat *oid_stat)
  {
        struct exclude_list *el;
        /*
        if (!dir->untracked)
                dir->unmanaged_exclude_files++;
        el = add_exclude_list(dir, EXC_FILE, fname);
 -      if (add_excludes(fname, "", 0, el, 0, sha1_stat) < 0)
 +      if (add_excludes(fname, "", 0, el, NULL, oid_stat) < 0)
                die("cannot use %s as an exclude file", fname);
  }
  
@@@ -1050,8 -958,7 +1050,8 @@@ static struct exclude *last_exclude_mat
                                                       int pathlen,
                                                       const char *basename,
                                                       int *dtype,
 -                                                     struct exclude_list *el)
 +                                                     struct exclude_list *el,
 +                                                     struct index_state *istate)
  {
        struct exclude *exc = NULL; /* undecided */
        int i;
  
                if (x->flags & EXC_FLAG_MUSTBEDIR) {
                        if (*dtype == DT_UNKNOWN)
 -                              *dtype = get_dtype(NULL, pathname, pathlen);
 +                              *dtype = get_dtype(NULL, istate, pathname, pathlen);
                        if (*dtype != DT_DIR)
                                continue;
                }
   */
  int is_excluded_from_list(const char *pathname,
                          int pathlen, const char *basename, int *dtype,
 -                        struct exclude_list *el)
 +                        struct exclude_list *el, struct index_state *istate)
  {
        struct exclude *exclude;
 -      exclude = last_exclude_matching_from_list(pathname, pathlen, basename, dtype, el);
 +      exclude = last_exclude_matching_from_list(pathname, pathlen, basename,
 +                                                dtype, el, istate);
        if (exclude)
                return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return -1; /* undecided */
  }
  
  static struct exclude *last_exclude_matching_from_lists(struct dir_struct *dir,
 +                                                      struct index_state *istate,
                const char *pathname, int pathlen, const char *basename,
                int *dtype_p)
  {
                for (j = group->nr - 1; j >= 0; j--) {
                        exclude = last_exclude_matching_from_list(
                                pathname, pathlen, basename, dtype_p,
 -                              &group->el[j]);
 +                              &group->el[j], istate);
                        if (exclude)
                                return exclude;
                }
   * Loads the per-directory exclude list for the substring of base
   * which has a char length of baselen.
   */
 -static void prep_exclude(struct dir_struct *dir, const char *base, int baselen)
 +static void prep_exclude(struct dir_struct *dir,
 +                       struct index_state *istate,
 +                       const char *base, int baselen)
  {
        struct exclude_list_group *group;
        struct exclude_list *el;
  
        while (current < baselen) {
                const char *cp;
 -              struct sha1_stat sha1_stat;
 +              struct oid_stat oid_stat;
  
                stk = xcalloc(1, sizeof(*stk));
                if (current < 0) {
                        int dt = DT_DIR;
                        dir->basebuf.buf[stk->baselen - 1] = 0;
                        dir->exclude = last_exclude_matching_from_lists(dir,
 +                                                                      istate,
                                dir->basebuf.buf, stk->baselen - 1,
                                dir->basebuf.buf + current, &dt);
                        dir->basebuf.buf[stk->baselen - 1] = '/';
                }
  
                /* Try to read per-directory file */
 -              hashclr(sha1_stat.sha1);
 -              sha1_stat.valid = 0;
 +              oidclr(&oid_stat.oid);
 +              oid_stat.valid = 0;
                if (dir->exclude_per_dir &&
                    /*
                     * If we know that no files have been added in
                        strbuf_addbuf(&sb, &dir->basebuf);
                        strbuf_addstr(&sb, dir->exclude_per_dir);
                        el->src = strbuf_detach(&sb, NULL);
 -                      add_excludes(el->src, el->src, stk->baselen, el, 1,
 -                                   untracked ? &sha1_stat : NULL);
 +                      add_excludes(el->src, el->src, stk->baselen, el, istate,
 +                                   untracked ? &oid_stat : NULL);
                }
                /*
                 * NEEDSWORK: when untracked cache is enabled, prep_exclude()
                 * order, though, if you do that.
                 */
                if (untracked &&
 -                  hashcmp(sha1_stat.sha1, untracked->exclude_sha1)) {
 +                  hashcmp(oid_stat.oid.hash, untracked->exclude_sha1)) {
                        invalidate_gitignore(dir->untracked, untracked);
 -                      hashcpy(untracked->exclude_sha1, sha1_stat.sha1);
 +                      hashcpy(untracked->exclude_sha1, oid_stat.oid.hash);
                }
                dir->exclude_stack = stk;
                current = stk->baselen;
   * undecided.
   */
  struct exclude *last_exclude_matching(struct dir_struct *dir,
 -                                           const char *pathname,
 -                                           int *dtype_p)
 +                                    struct index_state *istate,
 +                                    const char *pathname,
 +                                    int *dtype_p)
  {
        int pathlen = strlen(pathname);
        const char *basename = strrchr(pathname, '/');
        basename = (basename) ? basename+1 : pathname;
  
 -      prep_exclude(dir, pathname, basename-pathname);
 +      prep_exclude(dir, istate, pathname, basename-pathname);
  
        if (dir->exclude)
                return dir->exclude;
  
 -      return last_exclude_matching_from_lists(dir, pathname, pathlen,
 +      return last_exclude_matching_from_lists(dir, istate, pathname, pathlen,
                        basename, dtype_p);
  }
  
   * scans all exclude lists to determine whether pathname is excluded.
   * Returns 1 if true, otherwise 0.
   */
 -int is_excluded(struct dir_struct *dir, const char *pathname, int *dtype_p)
 +int is_excluded(struct dir_struct *dir, struct index_state *istate,
 +              const char *pathname, int *dtype_p)
  {
        struct exclude *exclude =
 -              last_exclude_matching(dir, pathname, dtype_p);
 +              last_exclude_matching(dir, istate, pathname, dtype_p);
        if (exclude)
                return exclude->flags & EXC_FLAG_NEGATIVE ? 0 : 1;
        return 0;
@@@ -1333,22 -1233,18 +1333,22 @@@ static struct dir_entry *dir_entry_new(
        return ent;
  }
  
 -static struct dir_entry *dir_add_name(struct dir_struct *dir, const char *pathname, int len)
 +static struct dir_entry *dir_add_name(struct dir_struct *dir,
 +                                    struct index_state *istate,
 +                                    const char *pathname, int len)
  {
 -      if (cache_file_exists(pathname, len, ignore_case))
 +      if (index_file_exists(istate, pathname, len, ignore_case))
                return NULL;
  
        ALLOC_GROW(dir->entries, dir->nr+1, dir->alloc);
        return dir->entries[dir->nr++] = dir_entry_new(pathname, len);
  }
  
 -struct dir_entry *dir_add_ignored(struct dir_struct *dir, const char *pathname, int len)
 +struct dir_entry *dir_add_ignored(struct dir_struct *dir,
 +                                struct index_state *istate,
 +                                const char *pathname, int len)
  {
 -      if (!cache_name_is_other(pathname, len))
 +      if (!index_name_is_other(istate, pathname, len))
                return NULL;
  
        ALLOC_GROW(dir->ignored, dir->ignored_nr+1, dir->ignored_alloc);
@@@ -1366,15 -1262,14 +1366,15 @@@ enum exist_status 
   * the directory name; instead, use the case insensitive
   * directory hash.
   */
 -static enum exist_status directory_exists_in_index_icase(const char *dirname, int len)
 +static enum exist_status directory_exists_in_index_icase(struct index_state *istate,
 +                                                       const char *dirname, int len)
  {
        struct cache_entry *ce;
  
 -      if (cache_dir_exists(dirname, len))
 +      if (index_dir_exists(istate, dirname, len))
                return index_directory;
  
 -      ce = cache_file_exists(dirname, len, ignore_case);
 +      ce = index_file_exists(istate, dirname, len, ignore_case);
        if (ce && S_ISGITLINK(ce->ce_mode))
                return index_gitdir;
  
   * the files it contains) will sort with the '/' at the
   * end.
   */
 -static enum exist_status directory_exists_in_index(const char *dirname, int len)
 +static enum exist_status directory_exists_in_index(struct index_state *istate,
 +                                                 const char *dirname, int len)
  {
        int pos;
  
        if (ignore_case)
 -              return directory_exists_in_index_icase(dirname, len);
 +              return directory_exists_in_index_icase(istate, dirname, len);
  
 -      pos = cache_name_pos(dirname, len);
 +      pos = index_name_pos(istate, dirname, len);
        if (pos < 0)
                pos = -pos-1;
 -      while (pos < active_nr) {
 -              const struct cache_entry *ce = active_cache[pos++];
 +      while (pos < istate->cache_nr) {
 +              const struct cache_entry *ce = istate->cache[pos++];
                unsigned char endchar;
  
                if (strncmp(ce->name, dirname, len))
   *  (c) otherwise, we recurse into it.
   */
  static enum path_treatment treat_directory(struct dir_struct *dir,
 +      struct index_state *istate,
        struct untracked_cache_dir *untracked,
        const char *dirname, int len, int baselen, int exclude,
        const struct pathspec *pathspec)
  {
        /* The "len-1" is to strip the final '/' */
 -      switch (directory_exists_in_index(dirname, len-1)) {
 +      switch (directory_exists_in_index(istate, dirname, len-1)) {
        case index_directory:
                return path_recurse;
  
        case index_nonexistent:
                if (dir->flags & DIR_SHOW_OTHER_DIRECTORIES)
                        break;
 +              if (exclude &&
 +                      (dir->flags & DIR_SHOW_IGNORED_TOO) &&
 +                      (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) {
 +
 +                      /*
 +                       * This is an excluded directory and we are
 +                       * showing ignored paths that match an exclude
 +                       * pattern.  (e.g. show directory as ignored
 +                       * only if it matches an exclude pattern).
 +                       * This path will either be 'path_excluded`
 +                       * (if we are showing empty directories or if
 +                       * the directory is not empty), or will be
 +                       * 'path_none' (empty directory, and we are
 +                       * not showing empty directories).
 +                       */
 +                      if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES))
 +                              return path_excluded;
 +
 +                      if (read_directory_recursive(dir, istate, dirname, len,
 +                                                   untracked, 1, 1, pathspec) == path_excluded)
 +                              return path_excluded;
 +
 +                      return path_none;
 +              }
                if (!(dir->flags & DIR_NO_GITLINKS)) {
 -                      unsigned char sha1[20];
 -                      if (resolve_gitlink_ref(dirname, "HEAD", sha1) == 0)
 -                              return path_untracked;
 +                      struct object_id oid;
 +                      if (resolve_gitlink_ref(dirname, "HEAD", &oid) == 0)
 +                              return exclude ? path_excluded : path_untracked;
                }
                return path_recurse;
        }
  
        untracked = lookup_untracked(dir->untracked, untracked,
                                     dirname + baselen, len - baselen);
 -      return read_directory_recursive(dir, dirname, len,
 -                                      untracked, 1, pathspec);
 +
 +      /*
 +       * If this is an excluded directory, then we only need to check if
 +       * the directory contains any files.
 +       */
 +      return read_directory_recursive(dir, istate, dirname, len,
 +                                      untracked, 1, exclude, pathspec);
  }
  
  /*
@@@ -1591,13 -1455,12 +1591,13 @@@ static int exclude_matches_pathspec(con
        return 0;
  }
  
 -static int get_index_dtype(const char *path, int len)
 +static int get_index_dtype(struct index_state *istate,
 +                         const char *path, int len)
  {
        int pos;
        const struct cache_entry *ce;
  
 -      ce = cache_file_exists(path, len, 0);
 +      ce = index_file_exists(istate, path, len, 0);
        if (ce) {
                if (!ce_uptodate(ce))
                        return DT_UNKNOWN;
        }
  
        /* Try to look it up as a directory */
 -      pos = cache_name_pos(path, len);
 +      pos = index_name_pos(istate, path, len);
        if (pos >= 0)
                return DT_UNKNOWN;
        pos = -pos-1;
 -      while (pos < active_nr) {
 -              ce = active_cache[pos++];
 +      while (pos < istate->cache_nr) {
 +              ce = istate->cache[pos++];
                if (strncmp(ce->name, path, len))
                        break;
                if (ce->name[len] > '/')
        return DT_UNKNOWN;
  }
  
 -static int get_dtype(struct dirent *de, const char *path, int len)
 +static int get_dtype(struct dirent *de, struct index_state *istate,
 +                   const char *path, int len)
  {
        int dtype = de ? DTYPE(de) : DT_UNKNOWN;
        struct stat st;
  
        if (dtype != DT_UNKNOWN)
                return dtype;
 -      dtype = get_index_dtype(path, len);
 +      dtype = get_index_dtype(istate, path, len);
        if (dtype != DT_UNKNOWN)
                return dtype;
        if (lstat(path, &st))
  
  static enum path_treatment treat_one_path(struct dir_struct *dir,
                                          struct untracked_cache_dir *untracked,
 +                                        struct index_state *istate,
                                          struct strbuf *path,
                                          int baselen,
                                          const struct pathspec *pathspec,
                                          int dtype, struct dirent *de)
  {
        int exclude;
 -      int has_path_in_index = !!cache_file_exists(path->buf, path->len, ignore_case);
 +      int has_path_in_index = !!index_file_exists(istate, path->buf, path->len, ignore_case);
 +      enum path_treatment path_treatment;
  
        if (dtype == DT_UNKNOWN)
 -              dtype = get_dtype(de, path->buf, path->len);
 +              dtype = get_dtype(de, istate, path->buf, path->len);
  
        /* Always exclude indexed files */
        if (dtype != DT_DIR && has_path_in_index)
        if ((dir->flags & DIR_COLLECT_KILLED_ONLY) &&
            (dtype == DT_DIR) &&
            !has_path_in_index &&
 -          (directory_exists_in_index(path->buf, path->len) == index_nonexistent))
 +          (directory_exists_in_index(istate, path->buf, path->len) == index_nonexistent))
                return path_none;
  
 -      exclude = is_excluded(dir, path->buf, &dtype);
 +      exclude = is_excluded(dir, istate, path->buf, &dtype);
  
        /*
         * Excluded? If we don't explicitly want to show
                return path_none;
        case DT_DIR:
                strbuf_addch(path, '/');
 -              return treat_directory(dir, untracked, path->buf, path->len,
 -                                     baselen, exclude, pathspec);
 +              path_treatment = treat_directory(dir, istate, untracked,
 +                                               path->buf, path->len,
 +                                               baselen, exclude, pathspec);
 +              /*
 +               * If 1) we only want to return directories that
 +               * match an exclude pattern and 2) this directory does
 +               * not match an exclude pattern but all of its
 +               * contents are excluded, then indicate that we should
 +               * recurse into this directory (instead of marking the
 +               * directory itself as an ignored path).
 +               */
 +              if (!exclude &&
 +                  path_treatment == path_excluded &&
 +                  (dir->flags & DIR_SHOW_IGNORED_TOO) &&
 +                  (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING))
 +                      return path_recurse;
 +              return path_treatment;
        case DT_REG:
        case DT_LNK:
                return exclude ? path_excluded : path_untracked;
  static enum path_treatment treat_path_fast(struct dir_struct *dir,
                                           struct untracked_cache_dir *untracked,
                                           struct cached_dir *cdir,
 +                                         struct index_state *istate,
                                           struct strbuf *path,
                                           int baselen,
                                           const struct pathspec *pathspec)
                 * to its bottom. Verify again the same set of directories
                 * with check_only set.
                 */
 -              return read_directory_recursive(dir, path->buf, path->len,
 -                                              cdir->ucd, 1, pathspec);
 +              return read_directory_recursive(dir, istate, path->buf, path->len,
 +                                              cdir->ucd, 1, 0, pathspec);
        /*
         * We get path_recurse in the first run when
         * directory_exists_in_index() returns index_nonexistent. We
  static enum path_treatment treat_path(struct dir_struct *dir,
                                      struct untracked_cache_dir *untracked,
                                      struct cached_dir *cdir,
 +                                    struct index_state *istate,
                                      struct strbuf *path,
                                      int baselen,
                                      const struct pathspec *pathspec)
        struct dirent *de = cdir->de;
  
        if (!de)
 -              return treat_path_fast(dir, untracked, cdir, path,
 +              return treat_path_fast(dir, untracked, cdir, istate, path,
                                       baselen, pathspec);
 -      if (is_dot_or_dotdot(de->d_name) || !strcmp(de->d_name, ".git"))
 +      if (is_dot_or_dotdot(de->d_name) || !fspathcmp(de->d_name, ".git"))
                return path_none;
        strbuf_setlen(path, baselen);
        strbuf_addstr(path, de->d_name);
                return path_none;
  
        dtype = DTYPE(de);
 -      return treat_one_path(dir, untracked, path, baselen, pathspec, dtype, de);
 +      return treat_one_path(dir, untracked, istate, path, baselen, pathspec, dtype, de);
  }
  
  static void add_untracked(struct untracked_cache_dir *dir, const char *name)
  
  static int valid_cached_dir(struct dir_struct *dir,
                            struct untracked_cache_dir *untracked,
 +                          struct index_state *istate,
                            struct strbuf *path,
                            int check_only)
  {
        if (!untracked)
                return 0;
  
 -      if (stat(path->len ? path->buf : ".", &st)) {
 -              invalidate_directory(dir->untracked, untracked);
 -              memset(&untracked->stat_data, 0, sizeof(untracked->stat_data));
 -              return 0;
 -      }
 -      if (!untracked->valid ||
 -          match_stat_data_racy(&the_index, &untracked->stat_data, &st)) {
 -              if (untracked->valid)
 -                      invalidate_directory(dir->untracked, untracked);
 -              fill_stat_data(&untracked->stat_data, &st);
 -              return 0;
 +      /*
 +       * With fsmonitor, we can trust the untracked cache's valid field.
 +       */
 +      refresh_fsmonitor(istate);
 +      if (!(dir->untracked->use_fsmonitor && untracked->valid)) {
 +              if (lstat(path->len ? path->buf : ".", &st)) {
 +                      memset(&untracked->stat_data, 0, sizeof(untracked->stat_data));
 +                      return 0;
 +              }
 +              if (!untracked->valid ||
 +                      match_stat_data_racy(istate, &untracked->stat_data, &st)) {
 +                      fill_stat_data(&untracked->stat_data, &st);
 +                      return 0;
 +              }
        }
  
 -      if (untracked->check_only != !!check_only) {
 -              invalidate_directory(dir->untracked, untracked);
 +      if (untracked->check_only != !!check_only)
                return 0;
 -      }
  
        /*
         * prep_exclude will be called eventually on this directory,
         */
        if (path->len && path->buf[path->len - 1] != '/') {
                strbuf_addch(path, '/');
 -              prep_exclude(dir, path->buf, path->len);
 +              prep_exclude(dir, istate, path->buf, path->len);
                strbuf_setlen(path, path->len - 1);
        } else
 -              prep_exclude(dir, path->buf, path->len);
 +              prep_exclude(dir, istate, path->buf, path->len);
  
        /* hopefully prep_exclude() haven't invalidated this entry... */
        return untracked->valid;
  static int open_cached_dir(struct cached_dir *cdir,
                           struct dir_struct *dir,
                           struct untracked_cache_dir *untracked,
 +                         struct index_state *istate,
                           struct strbuf *path,
                           int check_only)
  {
 +      const char *c_path;
 +
        memset(cdir, 0, sizeof(*cdir));
        cdir->untracked = untracked;
 -      if (valid_cached_dir(dir, untracked, path, check_only))
 +      if (valid_cached_dir(dir, untracked, istate, path, check_only))
                return 0;
 -      cdir->fdir = opendir(path->len ? path->buf : ".");
 -      if (dir->untracked)
 +      c_path = path->len ? path->buf : ".";
 +      cdir->fdir = opendir(c_path);
 +      if (!cdir->fdir)
 +              warning_errno(_("could not open directory '%s'"), c_path);
 +      if (dir->untracked) {
 +              invalidate_directory(dir->untracked, untracked);
                dir->untracked->dir_opened++;
 +      }
        if (!cdir->fdir)
                return -1;
        return 0;
@@@ -1923,20 -1756,12 +1923,20 @@@ static void close_cached_dir(struct cac
   * Also, we ignore the name ".git" (even if it is not a directory).
   * That likely will not change.
   *
 + * If 'stop_at_first_file' is specified, 'path_excluded' is returned
 + * to signal that a file was found. This is the least significant value that
 + * indicates that a file was encountered that does not depend on the order of
 + * whether an untracked or exluded path was encountered first.
 + *
   * Returns the most significant path_treatment value encountered in the scan.
 + * If 'stop_at_first_file' is specified, `path_excluded` is the most
 + * significant path_treatment value that will be returned.
   */
 +
  static enum path_treatment read_directory_recursive(struct dir_struct *dir,
 -                                  const char *base, int baselen,
 -                                  struct untracked_cache_dir *untracked, int check_only,
 -                                  const struct pathspec *pathspec)
 +      struct index_state *istate, const char *base, int baselen,
 +      struct untracked_cache_dir *untracked, int check_only,
 +      int stop_at_first_file, const struct pathspec *pathspec)
  {
        struct cached_dir cdir;
        enum path_treatment state, subdir_state, dir_state = path_none;
  
        strbuf_add(&path, base, baselen);
  
 -      if (open_cached_dir(&cdir, dir, untracked, &path, check_only))
 +      if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only))
                goto out;
  
        if (untracked)
  
        while (!read_cached_dir(&cdir)) {
                /* check how the file or directory should be treated */
 -              state = treat_path(dir, untracked, &cdir, &path,
 +              state = treat_path(dir, untracked, &cdir, istate, &path,
                                   baselen, pathspec);
  
                if (state > dir_state)
                if ((state == path_recurse) ||
                        ((state == path_untracked) &&
                         (dir->flags & DIR_SHOW_IGNORED_TOO) &&
 -                       (get_dtype(cdir.de, path.buf, path.len) == DT_DIR))) {
 +                       (get_dtype(cdir.de, istate, path.buf, path.len) == DT_DIR))) {
                        struct untracked_cache_dir *ud;
                        ud = lookup_untracked(dir->untracked, untracked,
                                              path.buf + baselen,
                                              path.len - baselen);
                        subdir_state =
 -                              read_directory_recursive(dir, path.buf,
 +                              read_directory_recursive(dir, istate, path.buf,
                                                         path.len, ud,
 -                                                       check_only, pathspec);
 +                                                       check_only, stop_at_first_file, pathspec);
                        if (subdir_state > dir_state)
                                dir_state = subdir_state;
                }
  
                if (check_only) {
 +                      if (stop_at_first_file) {
 +                              /*
 +                               * If stopping at first file, then
 +                               * signal that a file was found by
 +                               * returning `path_excluded`. This is
 +                               * to return a consistent value
 +                               * regardless of whether an ignored or
 +                               * excluded file happened to be
 +                               * encountered 1st.
 +                               *
 +                               * In current usage, the
 +                               * `stop_at_first_file` is passed when
 +                               * an ancestor directory has matched
 +                               * an exclude pattern, so any found
 +                               * files will be excluded.
 +                               */
 +                              if (dir_state >= path_excluded) {
 +                                      dir_state = path_excluded;
 +                                      break;
 +                              }
 +                      }
 +
                        /* abort early if maximum state has been reached */
                        if (dir_state == path_untracked) {
                                if (cdir.fdir)
                switch (state) {
                case path_excluded:
                        if (dir->flags & DIR_SHOW_IGNORED)
 -                              dir_add_name(dir, path.buf, path.len);
 +                              dir_add_name(dir, istate, path.buf, path.len);
                        else if ((dir->flags & DIR_SHOW_IGNORED_TOO) ||
                                ((dir->flags & DIR_COLLECT_IGNORED) &&
                                exclude_matches_pathspec(path.buf, path.len,
                                                         pathspec)))
 -                              dir_add_ignored(dir, path.buf, path.len);
 +                              dir_add_ignored(dir, istate, path.buf, path.len);
                        break;
  
                case path_untracked:
                        if (dir->flags & DIR_SHOW_IGNORED)
                                break;
 -                      dir_add_name(dir, path.buf, path.len);
 +                      dir_add_name(dir, istate, path.buf, path.len);
                        if (cdir.fdir)
                                add_untracked(untracked, path.buf + baselen);
                        break;
@@@ -2056,7 -1859,6 +2056,7 @@@ int check_dir_entry_contains(const stru
  }
  
  static int treat_leading_path(struct dir_struct *dir,
 +                            struct index_state *istate,
                              const char *path, int len,
                              const struct pathspec *pathspec)
  {
                        break;
                if (simplify_away(sb.buf, sb.len, pathspec))
                        break;
 -              if (treat_one_path(dir, NULL, &sb, baselen, pathspec,
 +              if (treat_one_path(dir, NULL, istate, &sb, baselen, pathspec,
                                   DT_DIR, NULL) == path_none)
                        break; /* do not recurse into it */
                if (len <= baselen) {
@@@ -2172,13 -1974,8 +2172,13 @@@ static struct untracked_cache_dir *vali
                                                      const struct pathspec *pathspec)
  {
        struct untracked_cache_dir *root;
 +      static int untracked_cache_disabled = -1;
  
 -      if (!dir->untracked || getenv("GIT_DISABLE_UNTRACKED_CACHE"))
 +      if (!dir->untracked)
 +              return NULL;
 +      if (untracked_cache_disabled < 0)
 +              untracked_cache_disabled = git_env_bool("GIT_DISABLE_UNTRACKED_CACHE", 0);
 +      if (untracked_cache_disabled)
                return NULL;
  
        /*
  
        /* Validate $GIT_DIR/info/exclude and core.excludesfile */
        root = dir->untracked->root;
 -      if (hashcmp(dir->ss_info_exclude.sha1,
 -                  dir->untracked->ss_info_exclude.sha1)) {
 +      if (oidcmp(&dir->ss_info_exclude.oid,
 +                 &dir->untracked->ss_info_exclude.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_info_exclude = dir->ss_info_exclude;
        }
 -      if (hashcmp(dir->ss_excludes_file.sha1,
 -                  dir->untracked->ss_excludes_file.sha1)) {
 +      if (oidcmp(&dir->ss_excludes_file.oid,
 +                 &dir->untracked->ss_excludes_file.oid)) {
                invalidate_gitignore(dir->untracked, root);
                dir->untracked->ss_excludes_file = dir->ss_excludes_file;
        }
        return root;
  }
  
 -int read_directory(struct dir_struct *dir, const char *path,
 -                 int len, const struct pathspec *pathspec)
 +int read_directory(struct dir_struct *dir, struct index_state *istate,
 +                 const char *path, int len, const struct pathspec *pathspec)
  {
        struct untracked_cache_dir *untracked;
 +      uint64_t start = getnanotime();
  
        if (has_symlink_leading_path(path, len))
                return dir->nr;
                 * e.g. prep_exclude()
                 */
                dir->untracked = NULL;
 -      if (!len || treat_leading_path(dir, path, len, pathspec))
 -              read_directory_recursive(dir, path, len, untracked, 0, pathspec);
 +      if (!len || treat_leading_path(dir, istate, path, len, pathspec))
 +              read_directory_recursive(dir, istate, path, len, untracked, 0, 0, pathspec);
        QSORT(dir->entries, dir->nr, cmp_dir_entry);
        QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry);
  
                for (i = j = 0; j < dir->nr; j++) {
                        if (i &&
                            check_dir_entry_contains(dir->entries[i - 1], dir->entries[j])) {
 -                              free(dir->entries[j]);
 -                              dir->entries[j] = NULL;
 +                              FREE_AND_NULL(dir->entries[j]);
                        } else {
                                dir->entries[i++] = dir->entries[j];
                        }
                dir->nr = i;
        }
  
 +      trace_performance_since(start, "read directory %.*s", len, path);
        if (dir->untracked) {
 +              static int force_untracked_cache = -1;
                static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS);
 +
 +              if (force_untracked_cache < 0)
 +                      force_untracked_cache =
 +                              git_env_bool("GIT_FORCE_UNTRACKED_CACHE", 0);
                trace_printf_key(&trace_untracked_stats,
                                 "node creation: %u\n"
                                 "gitignore invalidation: %u\n"
                                 dir->untracked->gitignore_invalidated,
                                 dir->untracked->dir_invalidated,
                                 dir->untracked->dir_opened);
 -              if (dir->untracked == the_index.untracked &&
 +              if (force_untracked_cache &&
 +                      dir->untracked == istate->untracked &&
                    (dir->untracked->dir_opened ||
                     dir->untracked->gitignore_invalidated ||
                     dir->untracked->dir_invalidated))
 -                      the_index.cache_changed |= UNTRACKED_CHANGED;
 -              if (dir->untracked != the_index.untracked) {
 -                      free(dir->untracked);
 -                      dir->untracked = NULL;
 +                      istate->cache_changed |= UNTRACKED_CHANGED;
 +              if (dir->untracked != istate->untracked) {
 +                      FREE_AND_NULL(dir->untracked);
                }
        }
        return dir->nr;
@@@ -2417,10 -2208,10 +2417,10 @@@ static int remove_dir_recurse(struct st
        int ret = 0, original_len = path->len, len, kept_down = 0;
        int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY);
        int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL);
 -      unsigned char submodule_head[20];
 +      struct object_id submodule_head;
  
        if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) &&
 -          !resolve_gitlink_ref(path->buf, "HEAD", submodule_head)) {
 +          !resolve_gitlink_ref(path->buf, "HEAD", &submodule_head)) {
                /* Do not descend and nuke a nested git work tree. */
                if (kept_up)
                        *kept_up = 1;
@@@ -2516,7 -2307,7 +2516,7 @@@ int remove_path(const char *name
  {
        char *slash;
  
 -      if (unlink(name) && errno != ENOENT && errno != ENOTDIR)
 +      if (unlink(name) && !is_missing_file_error(errno))
                return -1;
  
        slash = strrchr(name, '/');
@@@ -2571,8 -2362,7 +2571,8 @@@ struct ondisk_untracked_cache 
        char exclude_per_dir[FLEX_ARRAY];
  };
  
 -#define ouc_size(len) (offsetof(struct ondisk_untracked_cache, exclude_per_dir) + len + 1)
 +#define ouc_offset(x) offsetof(struct ondisk_untracked_cache, x)
 +#define ouc_size(len) (ouc_offset(exclude_per_dir) + len + 1)
  
  struct write_data {
        int index;         /* number of written untracked_cache_dir */
@@@ -2659,8 -2449,8 +2659,8 @@@ void write_untracked_extension(struct s
        FLEX_ALLOC_MEM(ouc, exclude_per_dir, untracked->exclude_per_dir, len);
        stat_data_to_disk(&ouc->info_exclude_stat, &untracked->ss_info_exclude.stat);
        stat_data_to_disk(&ouc->excludes_file_stat, &untracked->ss_excludes_file.stat);
 -      hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.sha1);
 -      hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.sha1);
 +      hashcpy(ouc->info_exclude_sha1, untracked->ss_info_exclude.oid.hash);
 +      hashcpy(ouc->excludes_file_sha1, untracked->ss_excludes_file.oid.hash);
        ouc->dir_flags = htonl(untracked->dir_flags);
  
        varint_len = encode_varint(untracked->ident.len, varbuf);
        strbuf_addbuf(out, &untracked->ident);
  
        strbuf_add(out, ouc, ouc_size(len));
 -      free(ouc);
 -      ouc = NULL;
 +      FREE_AND_NULL(ouc);
  
        if (!untracked->root) {
                varint_len = encode_varint(0, varbuf);
@@@ -2734,18 -2525,17 +2734,18 @@@ struct read_data 
        const unsigned char *end;
  };
  
 -static void stat_data_from_disk(struct stat_data *to, const struct stat_data *from)
 +static void stat_data_from_disk(struct stat_data *to, const unsigned char *data)
  {
 -      to->sd_ctime.sec  = get_be32(&from->sd_ctime.sec);
 -      to->sd_ctime.nsec = get_be32(&from->sd_ctime.nsec);
 -      to->sd_mtime.sec  = get_be32(&from->sd_mtime.sec);
 -      to->sd_mtime.nsec = get_be32(&from->sd_mtime.nsec);
 -      to->sd_dev        = get_be32(&from->sd_dev);
 -      to->sd_ino        = get_be32(&from->sd_ino);
 -      to->sd_uid        = get_be32(&from->sd_uid);
 -      to->sd_gid        = get_be32(&from->sd_gid);
 -      to->sd_size       = get_be32(&from->sd_size);
 +      memcpy(to, data, sizeof(*to));
 +      to->sd_ctime.sec  = ntohl(to->sd_ctime.sec);
 +      to->sd_ctime.nsec = ntohl(to->sd_ctime.nsec);
 +      to->sd_mtime.sec  = ntohl(to->sd_mtime.sec);
 +      to->sd_mtime.nsec = ntohl(to->sd_mtime.nsec);
 +      to->sd_dev        = ntohl(to->sd_dev);
 +      to->sd_ino        = ntohl(to->sd_ino);
 +      to->sd_uid        = ntohl(to->sd_uid);
 +      to->sd_gid        = ntohl(to->sd_gid);
 +      to->sd_size       = ntohl(to->sd_size);
  }
  
  static int read_one_dir(struct untracked_cache_dir **untracked_,
@@@ -2820,7 -2610,7 +2820,7 @@@ static void read_stat(size_t pos, void 
                rd->data = rd->end + 1;
                return;
        }
 -      stat_data_from_disk(&ud->stat_data, (struct stat_data *)rd->data);
 +      stat_data_from_disk(&ud->stat_data, rd->data);
        rd->data += sizeof(struct stat_data);
        ud->valid = 1;
  }
@@@ -2837,22 -2627,23 +2837,22 @@@ static void read_sha1(size_t pos, void 
        rd->data += 20;
  }
  
 -static void load_sha1_stat(struct sha1_stat *sha1_stat,
 -                         const struct stat_data *stat,
 -                         const unsigned char *sha1)
 +static void load_oid_stat(struct oid_stat *oid_stat, const unsigned char *data,
 +                        const unsigned char *sha1)
  {
 -      stat_data_from_disk(&sha1_stat->stat, stat);
 -      hashcpy(sha1_stat->sha1, sha1);
 -      sha1_stat->valid = 1;
 +      stat_data_from_disk(&oid_stat->stat, data);
 +      hashcpy(oid_stat->oid.hash, sha1);
 +      oid_stat->valid = 1;
  }
  
  struct untracked_cache *read_untracked_extension(const void *data, unsigned long sz)
  {
 -      const struct ondisk_untracked_cache *ouc;
        struct untracked_cache *uc;
        struct read_data rd;
        const unsigned char *next = data, *end = (const unsigned char *)data + sz;
        const char *ident;
        int ident_len, len;
 +      const char *exclude_per_dir;
  
        if (sz <= 1 || end[-1] != '\0')
                return NULL;
        ident = (const char *)next;
        next += ident_len;
  
 -      ouc = (const struct ondisk_untracked_cache *)next;
        if (next + ouc_size(0) > end)
                return NULL;
  
        uc = xcalloc(1, sizeof(*uc));
        strbuf_init(&uc->ident, ident_len);
        strbuf_add(&uc->ident, ident, ident_len);
 -      load_sha1_stat(&uc->ss_info_exclude, &ouc->info_exclude_stat,
 -                     ouc->info_exclude_sha1);
 -      load_sha1_stat(&uc->ss_excludes_file, &ouc->excludes_file_stat,
 -                     ouc->excludes_file_sha1);
 -      uc->dir_flags = get_be32(&ouc->dir_flags);
 -      uc->exclude_per_dir = xstrdup(ouc->exclude_per_dir);
 +      load_oid_stat(&uc->ss_info_exclude,
 +                    next + ouc_offset(info_exclude_stat),
 +                    next + ouc_offset(info_exclude_sha1));
 +      load_oid_stat(&uc->ss_excludes_file,
 +                    next + ouc_offset(excludes_file_stat),
 +                    next + ouc_offset(excludes_file_sha1));
 +      uc->dir_flags = get_be32(next + ouc_offset(dir_flags));
 +      exclude_per_dir = (const char *)next + ouc_offset(exclude_per_dir);
 +      uc->exclude_per_dir = xstrdup(exclude_per_dir);
        /* NUL after exclude_per_dir is covered by sizeof(*ouc) */
 -      next += ouc_size(strlen(ouc->exclude_per_dir));
 +      next += ouc_size(strlen(exclude_per_dir));
        if (next >= end)
                goto done2;
  
@@@ -2988,12 -2777,10 +2988,12 @@@ static int invalidate_one_component(str
  }
  
  void untracked_cache_invalidate_path(struct index_state *istate,
 -                                   const char *path)
 +                                   const char *path, int safe_path)
  {
        if (!istate->untracked || !istate->untracked->root)
                return;
-       if (!safe_path && !verify_path(path))
++      if (!safe_path && !verify_path(path, 0))
 +              return;
        invalidate_one_component(istate->untracked, istate->untracked->root,
                                 path, strlen(path));
  }
  void untracked_cache_remove_from_index(struct index_state *istate,
                                       const char *path)
  {
 -      untracked_cache_invalidate_path(istate, path);
 +      untracked_cache_invalidate_path(istate, path, 1);
  }
  
  void untracked_cache_add_to_index(struct index_state *istate,
                                  const char *path)
  {
 -      untracked_cache_invalidate_path(istate, path);
 +      untracked_cache_invalidate_path(istate, path, 1);
  }
  
  /* Update gitfile and core.worktree setting to connect work tree and git dir */
diff --combined git-compat-util.h
index 07e383257b4985f7400f167d683a5fb692237d93,4be15e5eb233ffdfbce17826c20e841e56f14630..76cd42bd637224f4ac95a8164bac9c58f0064301
@@@ -322,11 -322,6 +322,11 @@@ extern char *gitdirname(char *)
  #define PRIo32 "o"
  #endif
  
 +typedef uintmax_t timestamp_t;
 +#define PRItime PRIuMAX
 +#define parse_timestamp strtoumax
 +#define TIME_MAX UINTMAX_MAX
 +
  #ifndef PATH_SEP
  #define PATH_SEP ':'
  #endif
@@@ -484,29 -479,6 +484,29 @@@ static inline int skip_prefix(const cha
        return 0;
  }
  
 +/*
 + * If the string "str" is the same as the string in "prefix", then the "arg"
 + * parameter is set to the "def" parameter and 1 is returned.
 + * If the string "str" begins with the string found in "prefix" and then a
 + * "=" sign, then the "arg" parameter is set to "str + strlen(prefix) + 1"
 + * (i.e., to the point in the string right after the prefix and the "=" sign),
 + * and 1 is returned.
 + *
 + * Otherwise, return 0 and leave "arg" untouched.
 + *
 + * When we accept both a "--key" and a "--key=<val>" option, this function
 + * can be used instead of !strcmp(arg, "--key") and then
 + * skip_prefix(arg, "--key=", &arg) to parse such an option.
 + */
 +int skip_to_optional_arg_default(const char *str, const char *prefix,
 +                               const char **arg, const char *def);
 +
 +static inline int skip_to_optional_arg(const char *str, const char *prefix,
 +                                     const char **arg)
 +{
 +      return skip_to_optional_arg_default(str, prefix, arg, "");
 +}
 +
  /*
   * Like skip_prefix, but promises never to read past "len" bytes of the input
   * buffer, and returns the remaining number of bytes in "out" via "outlen".
@@@ -646,7 -618,7 +646,7 @@@ extern int git_lstat(const char *, stru
  #endif
  
  #define DEFAULT_PACKED_GIT_LIMIT \
 -      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? 8192 : 256))
 +      ((1024L * 1024L) * (size_t)(sizeof(void*) >= 8 ? (32 * 1024L * 1024L) : 256))
  
  #ifdef NO_PREAD
  #define pread git_pread
@@@ -719,12 -691,10 +719,12 @@@ char *gitstrdup(const char *s)
  #endif
  
  #ifdef FREAD_READS_DIRECTORIES
 -#ifdef fopen
 -#undef fopen
 -#endif
 -#define fopen(a,b) git_fopen(a,b)
 +# if !defined(SUPPRESS_FOPEN_REDEFINITION)
 +#  ifdef fopen
 +#   undef fopen
 +#  endif
 +#  define fopen(a,b) git_fopen(a,b)
 +# endif
  extern FILE *git_fopen(const char*, const char*);
  #endif
  
@@@ -772,6 -742,8 +772,6 @@@ const char *inet_ntop(int af, const voi
  extern int git_atexit(void (*handler)(void));
  #endif
  
 -extern void release_pack_memory(size_t);
 -
  typedef void (*try_to_free_t)(size_t);
  extern try_to_free_t set_try_to_free_routine(try_to_free_t);
  
@@@ -826,17 -798,10 +826,17 @@@ extern ssize_t xpread(int fd, void *buf
  extern int xdup(int fd);
  extern FILE *xfopen(const char *path, const char *mode);
  extern FILE *xfdopen(int fd, const char *mode);
 -extern int xmkstemp(char *template);
 -extern int xmkstemp_mode(char *template, int mode);
 +extern int xmkstemp(char *temp_filename);
 +extern int xmkstemp_mode(char *temp_filename, int mode);
  extern char *xgetcwd(void);
  extern FILE *fopen_for_writing(const char *path);
 +extern FILE *fopen_or_warn(const char *path, const char *mode);
 +
 +/*
 + * FREE_AND_NULL(ptr) is like free(ptr) followed by ptr = NULL. Note
 + * that ptr is used twice, so don't pass e.g. ptr++.
 + */
 +#define FREE_AND_NULL(p) do { free(p); (p) = NULL; } while (0)
  
  #define ALLOC_ARRAY(x, alloc) (x) = xmalloc(st_mult(sizeof(*(x)), (alloc)))
  #define REALLOC_ARRAY(x, alloc) (x) = xrealloc((x), st_mult(sizeof(*(x)), (alloc)))
@@@ -849,14 -814,6 +849,14 @@@ static inline void copy_array(void *dst
                memcpy(dst, src, st_mult(size, n));
  }
  
 +#define MOVE_ARRAY(dst, src, n) move_array((dst), (src), (n), sizeof(*(dst)) + \
 +      BUILD_ASSERT_OR_ZERO(sizeof(*(dst)) == sizeof(*(src))))
 +static inline void move_array(void *dst, const void *src, size_t n, size_t size)
 +{
 +      if (n)
 +              memmove(dst, src, st_mult(size, n));
 +}
 +
  /*
   * These functions help you allocate structs with flex arrays, and copy
   * the data directly into the array. For example, if you had:
@@@ -921,11 -878,9 +921,11 @@@ static inline char *xstrdup_or_null(con
  
  static inline size_t xsize_t(off_t len)
  {
 -      if (len > (size_t) len)
 +      size_t size = (size_t) len;
 +
 +      if (len != (off_t) size)
                die("Cannot handle files this big");
 -      return (size_t)len;
 +      return size;
  }
  
  __attribute__((format (printf, 3, 4)))
@@@ -1001,6 -956,23 +1001,23 @@@ static inline int sane_iscase(int x, in
                return (x & 0x20) == 0;
  }
  
+ /*
+  * Like skip_prefix, but compare case-insensitively. Note that the comparison
+  * is done via tolower(), so it is strictly ASCII (no multi-byte characters or
+  * locale-specific conversions).
+  */
+ static inline int skip_iprefix(const char *str, const char *prefix,
+                              const char **out)
+ {
+       do {
+               if (!*prefix) {
+                       *out = str;
+                       return 1;
+               }
+       } while (tolower(*str++) == tolower(*prefix++));
+       return 0;
+ }
  static inline int strtoul_ui(char const *s, int base, unsigned int *result)
  {
        unsigned long ul;
@@@ -1153,8 -1125,8 +1170,8 @@@ int remove_or_warn(unsigned int mode, c
  int access_or_warn(const char *path, int mode, unsigned flag);
  int access_or_die(const char *path, int mode, unsigned flag);
  
 -/* Warn on an inaccessible file that ought to be accessible */
 -void warn_on_inaccessible(const char *path);
 +/* Warn on an inaccessible file if errno indicates this is an error */
 +int warn_on_fopen_errors(const char *path);
  
  #ifdef GMTIME_UNRELIABLE_ERRORS
  struct tm *git_gmtime(const time_t *);
@@@ -1177,41 -1149,6 +1194,41 @@@ struct tm *git_gmtime_r(const time_t *
  #define getc_unlocked(fh) getc(fh)
  #endif
  
 +/*
 + * Our code often opens a path to an optional file, to work on its
 + * contents when we can successfully open it.  We can ignore a failure
 + * to open if such an optional file does not exist, but we do want to
 + * report a failure in opening for other reasons (e.g. we got an I/O
 + * error, or the file is there, but we lack the permission to open).
 + *
 + * Call this function after seeing an error from open() or fopen() to
 + * see if the errno indicates a missing file that we can safely ignore.
 + */
 +static inline int is_missing_file_error(int errno_)
 +{
 +      return (errno_ == ENOENT || errno_ == ENOTDIR);
 +}
 +
  extern int cmd_main(int, const char **);
  
 +/*
 + * You can mark a stack variable with UNLEAK(var) to avoid it being
 + * reported as a leak by tools like LSAN or valgrind. The argument
 + * should generally be the variable itself (not its address and not what
 + * it points to). It's safe to use this on pointers which may already
 + * have been freed, or on pointers which may still be in use.
 + *
 + * Use this _only_ for a variable that leaks by going out of scope at
 + * program exit (so only from cmd_* functions or their direct helpers).
 + * Normal functions, especially those which may be called multiple
 + * times, should actually free their memory. This is only meant as
 + * an annotation, and does nothing in non-leak-checking builds.
 + */
 +#ifdef SUPPRESS_ANNOTATED_LEAKS
 +extern void unleak_memory(const void *ptr, size_t len);
 +#define UNLEAK(var) unleak_memory(&(var), sizeof(var))
 +#else
 +#define UNLEAK(var) do {} while (0)
 +#endif
 +
  #endif
diff --combined git-submodule.sh
index 24914963ca23c837e0cc46ca2dc0fa46bf9886a6,92750b9e2fc54a451f7fe9dad42737861e47dbb7..7e27d0a0da4d130f9ccb92612848da8e219427a0
@@@ -213,8 -213,7 +213,8 @@@ cmd_add(
                die "$(eval_gettext "'\$sm_path' already exists in the index and is not a submodule")"
        fi
  
 -      if test -z "$force" && ! git add --dry-run --ignore-missing "$sm_path" > /dev/null 2>&1
 +      if test -z "$force" &&
 +              ! git add --dry-run --ignore-missing --no-warn-embedded-repo "$sm_path" > /dev/null 2>&1
        then
                eval_gettextln "The following path is ignored by one of your .gitignore files:
  \$sm_path
@@@ -229,6 -228,11 +229,11 @@@ Use -f if you really want to add it." >
                sm_name="$sm_path"
        fi
  
+       if ! git submodule--helper check-name "$sm_name"
+       then
+               die "$(eval_gettext "'$sm_name' is not a valid submodule name")"
+       fi
        # perhaps the path exists and is already a git repo, else clone it
        if test -e "$sm_path"
        then
@@@ -268,7 -272,7 +273,7 @@@ or you are unsure what this means choos
        fi
        git config submodule."$sm_name".url "$realrepo"
  
 -      git add $force "$sm_path" ||
 +      git add --no-warn-embedded-repo $force "$sm_path" ||
        die "$(eval_gettext "Failed to add submodule '\$sm_path'")"
  
        git config -f .gitmodules submodule."$sm_name".path "$sm_path" &&
@@@ -428,7 -432,60 +433,7 @@@ cmd_deinit(
                shift
        done
  
 -      if test -n "$deinit_all" && test "$#" -ne 0
 -      then
 -              echo >&2 "$(eval_gettext "pathspec and --all are incompatible")"
 -              usage
 -      fi
 -      if test $# = 0 && test -z "$deinit_all"
 -      then
 -              die "$(eval_gettext "Use '--all' if you really want to deinitialize all submodules")"
 -      fi
 -
 -      {
 -              git submodule--helper list --prefix "$wt_prefix" "$@" ||
 -              echo "#unmatched" $?
 -      } |
 -      while read -r mode sha1 stage sm_path
 -      do
 -              die_if_unmatched "$mode" "$sha1"
 -              name=$(git submodule--helper name "$sm_path") || exit
 -
 -              displaypath=$(git submodule--helper relative-path "$sm_path" "$wt_prefix")
 -
 -              # Remove the submodule work tree (unless the user already did it)
 -              if test -d "$sm_path"
 -              then
 -                      # Protect submodules containing a .git directory
 -                      if test -d "$sm_path/.git"
 -                      then
 -                              die "$(eval_gettext "\
 -Submodule work tree '\$displaypath' contains a .git directory
 -(use 'rm -rf' if you really want to remove it including all of its history)")"
 -                      fi
 -
 -                      if test -z "$force"
 -                      then
 -                              git rm -qn "$sm_path" ||
 -                              die "$(eval_gettext "Submodule work tree '\$displaypath' contains local modifications; use '-f' to discard them")"
 -                      fi
 -                      rm -rf "$sm_path" &&
 -                      say "$(eval_gettext "Cleared directory '\$displaypath'")" ||
 -                      say "$(eval_gettext "Could not remove submodule work tree '\$displaypath'")"
 -              fi
 -
 -              mkdir "$sm_path" || say "$(eval_gettext "Could not create empty submodule directory '\$displaypath'")"
 -
 -              # Remove the .git/config entries (unless the user already did it)
 -              if test -n "$(git config --get-regexp submodule."$name\.")"
 -              then
 -                      # Remove the whole section so we have a clean state when
 -                      # the user later decides to init this submodule again
 -                      url=$(git config submodule."$name".url)
 -                      git config --remove-section submodule."$name" 2>/dev/null &&
 -                      say "$(eval_gettext "Submodule '\$name' (\$url) unregistered for path '\$displaypath'")"
 -              fi
 -      done
 +      git ${wt_prefix:+-C "$wt_prefix"} submodule--helper deinit ${GIT_QUIET:+--quiet} ${prefix:+--prefix "$prefix"} ${force:+--force} ${deinit_all:+--all} "$@"
  }
  
  is_tip_reachable () (
@@@ -558,6 -615,7 +563,6 @@@ cmd_update(
                die_if_unmatched "$mode" "$sha1"
  
                name=$(git submodule--helper name "$sm_path") || exit
 -              url=$(git config submodule."$name".url)
                if ! test -z "$update"
                then
                        update_module=$update
        }
  }
  
 -set_name_rev () {
 -      revname=$( (
 -              sanitize_submodule_env
 -              cd "$1" && {
 -                      git describe "$2" 2>/dev/null ||
 -                      git describe --tags "$2" 2>/dev/null ||
 -                      git describe --contains "$2" 2>/dev/null ||
 -                      git describe --all --always "$2"
 -              }
 -      ) )
 -      test -z "$revname" || revname=" ($revname)"
 -}
  #
  # Show commit summary for submodules in index or working tree
  #
@@@ -798,7 -868,7 +803,7 @@@ cmd_summary() 
                                test $status != A && test $ignore_config = all && continue
                        fi
                        # Also show added or modified modules which are checked out
 -                      GIT_DIR="$sm_path/.git" git-rev-parse --git-dir >/dev/null 2>&1 &&
 +                      GIT_DIR="$sm_path/.git" git rev-parse --git-dir >/dev/null 2>&1 &&
                        printf '%s\n' "$sm_path"
                done
        )
                missing_dst=
  
                test $mod_src = 160000 &&
 -              ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_src^0 >/dev/null &&
 +              ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_src^0 >/dev/null &&
                missing_src=t
  
                test $mod_dst = 160000 &&
 -              ! GIT_DIR="$name/.git" git-rev-parse -q --verify $sha1_dst^0 >/dev/null &&
 +              ! GIT_DIR="$name/.git" git rev-parse -q --verify $sha1_dst^0 >/dev/null &&
                missing_dst=t
  
                display_name=$(git submodule--helper relative-path "$name" "$wt_prefix")
@@@ -951,7 -1021,54 +956,7 @@@ cmd_status(
                shift
        done
  
 -      {
 -              git submodule--helper list --prefix "$wt_prefix" "$@" ||
 -              echo "#unmatched" $?
 -      } |
 -      while read -r mode sha1 stage sm_path
 -      do
 -              die_if_unmatched "$mode" "$sha1"
 -              name=$(git submodule--helper name "$sm_path") || exit
 -              displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
 -              if test "$stage" = U
 -              then
 -                      say "U$sha1 $displaypath"
 -                      continue
 -              fi
 -              if ! git submodule--helper is-active "$sm_path" ||
 -              {
 -                      ! test -d "$sm_path"/.git &&
 -                      ! test -f "$sm_path"/.git
 -              }
 -              then
 -                      say "-$sha1 $displaypath"
 -                      continue;
 -              fi
 -              if git diff-files --ignore-submodules=dirty --quiet -- "$sm_path"
 -              then
 -                      set_name_rev "$sm_path" "$sha1"
 -                      say " $sha1 $displaypath$revname"
 -              else
 -                      if test -z "$cached"
 -                      then
 -                              sha1=$(sanitize_submodule_env; cd "$sm_path" && git rev-parse --verify HEAD)
 -                      fi
 -                      set_name_rev "$sm_path" "$sha1"
 -                      say "+$sha1 $displaypath$revname"
 -              fi
 -
 -              if test -n "$recursive"
 -              then
 -                      (
 -                              prefix="$displaypath/"
 -                              sanitize_submodule_env
 -                              wt_prefix=
 -                              cd "$sm_path" &&
 -                              eval cmd_status
 -                      ) ||
 -                      die "$(eval_gettext "Failed to recurse into submodule path '\$sm_path'")"
 -              fi
 -      done
 +      git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper status ${GIT_QUIET:+--quiet} ${cached:+--cached} ${recursive:+--recursive} "$@"
  }
  #
  # Sync remote urls for submodules
@@@ -983,8 -1100,63 +988,8 @@@ cmd_sync(
                        ;;
                esac
        done
 -      cd_to_toplevel
 -      {
 -              git submodule--helper list --prefix "$wt_prefix" "$@" ||
 -              echo "#unmatched" $?
 -      } |
 -      while read -r mode sha1 stage sm_path
 -      do
 -              die_if_unmatched "$mode" "$sha1"
  
 -              # skip inactive submodules
 -              if ! git submodule--helper is-active "$sm_path"
 -              then
 -                      continue
 -              fi
 -
 -              name=$(git submodule--helper name "$sm_path")
 -              url=$(git config -f .gitmodules --get submodule."$name".url)
 -
 -              # Possibly a url relative to parent
 -              case "$url" in
 -              ./*|../*)
 -                      # rewrite foo/bar as ../.. to find path from
 -                      # submodule work tree to superproject work tree
 -                      up_path="$(printf '%s\n' "$sm_path" | sed "s/[^/][^/]*/../g")" &&
 -                      # guarantee a trailing /
 -                      up_path=${up_path%/}/ &&
 -                      # path from submodule work tree to submodule origin repo
 -                      sub_origin_url=$(git submodule--helper resolve-relative-url "$url" "$up_path") &&
 -                      # path from superproject work tree to submodule origin repo
 -                      super_config_url=$(git submodule--helper resolve-relative-url "$url") || exit
 -                      ;;
 -              *)
 -                      sub_origin_url="$url"
 -                      super_config_url="$url"
 -                      ;;
 -              esac
 -
 -              displaypath=$(git submodule--helper relative-path "$prefix$sm_path" "$wt_prefix")
 -              say "$(eval_gettext "Synchronizing submodule url for '\$displaypath'")"
 -              git config submodule."$name".url "$super_config_url"
 -
 -              if test -e "$sm_path"/.git
 -              then
 -              (
 -                      sanitize_submodule_env
 -                      cd "$sm_path"
 -                      remote=$(get_default_remote)
 -                      git config remote."$remote".url "$sub_origin_url"
 -
 -                      if test -n "$recursive"
 -                      then
 -                              prefix="$prefix$sm_path/"
 -                              eval cmd_sync
 -                      fi
 -              )
 -              fi
 -      done
 +      git ${wt_prefix:+-C "$wt_prefix"} ${prefix:+--super-prefix "$prefix"} submodule--helper sync ${GIT_QUIET:+--quiet} ${recursive:+--recursive} "$@"
  }
  
  cmd_absorbgitdirs()
diff --combined path.c
index da8b655730d363dda5010bdf2d53bd76abb82931,c72062574599f7bc312b404a817f9603384fd49c..4c4a751539aa30d134da09dd6ad1f00988818e88
--- 1/path.c
--- 2/path.c
+++ b/path.c
@@@ -2,14 -2,11 +2,14 @@@
   * Utilities for paths and pathnames
   */
  #include "cache.h"
 +#include "repository.h"
  #include "strbuf.h"
  #include "string-list.h"
  #include "dir.h"
  #include "worktree.h"
  #include "submodule-config.h"
 +#include "path.h"
 +#include "packfile.h"
  
  static int get_st_mode_bits(const char *path, int *mode)
  {
@@@ -34,10 -31,11 +34,10 @@@ static struct strbuf *get_pathname(void
        return sb;
  }
  
 -static char *cleanup_path(char *path)
 +static const char *cleanup_path(const char *path)
  {
        /* Clean it up */
 -      if (!memcmp(path, "./", 2)) {
 -              path += 2;
 +      if (skip_prefix(path, "./", &path)) {
                while (*path == '/')
                        path++;
        }
@@@ -46,7 -44,7 +46,7 @@@
  
  static void strbuf_cleanup_path(struct strbuf *sb)
  {
 -      char *path = cleanup_path(sb->buf);
 +      const char *path = cleanup_path(sb->buf);
        if (path > sb->buf)
                strbuf_remove(sb, 0, path - sb->buf);
  }
@@@ -63,7 -61,7 +63,7 @@@ char *mksnpath(char *buf, size_t n, con
                strlcpy(buf, bad_path, n);
                return buf;
        }
 -      return cleanup_path(buf);
 +      return (char *)cleanup_path(buf);
  }
  
  static int dir_prefix(const char *buf, const char *dir)
@@@ -192,7 -190,7 +192,7 @@@ static void *add_to_trie(struct trie *r
                 * Split this node: child will contain this node's
                 * existing children.
                 */
 -              child = malloc(sizeof(*child));
 +              child = xmalloc(sizeof(*child));
                memcpy(child->children, root->children, sizeof(root->children));
  
                child->len = root->len - i - 1;
@@@ -345,6 -343,8 +345,6 @@@ static void update_common_dir(struct st
  {
        char *base = buf->buf + git_dir_len;
        init_common_trie();
 -      if (!common_dir)
 -              common_dir = get_git_common_dir();
        if (trie_find(&common_trie, base, check_common, NULL) > 0)
                replace_dir(buf, git_dir_len, common_dir);
  }
@@@ -355,7 -355,7 +355,7 @@@ void report_linked_checkout_garbage(voi
        const struct common_dir *p;
        int len;
  
 -      if (!git_common_dir_env)
 +      if (!the_repository->different_commondir)
                return;
        strbuf_addf(&sb, "%s/", get_git_dir());
        len = sb.len;
        strbuf_release(&sb);
  }
  
 -static void adjust_git_path(struct strbuf *buf, int git_dir_len)
 +static void adjust_git_path(const struct repository *repo,
 +                          struct strbuf *buf, int git_dir_len)
  {
        const char *base = buf->buf + git_dir_len;
 -      if (git_graft_env && is_dir_file(base, "info", "grafts"))
 +      if (is_dir_file(base, "info", "grafts"))
                strbuf_splice(buf, 0, buf->len,
 -                            get_graft_file(), strlen(get_graft_file()));
 -      else if (git_index_env && !strcmp(base, "index"))
 +                            repo->graft_file, strlen(repo->graft_file));
 +      else if (!strcmp(base, "index"))
                strbuf_splice(buf, 0, buf->len,
 -                            get_index_file(), strlen(get_index_file()));
 -      else if (git_db_env && dir_prefix(base, "objects"))
 -              replace_dir(buf, git_dir_len + 7, get_object_directory());
 +                            repo->index_file, strlen(repo->index_file));
 +      else if (dir_prefix(base, "objects"))
 +              replace_dir(buf, git_dir_len + 7, repo->objectdir);
        else if (git_hooks_path && dir_prefix(base, "hooks"))
                replace_dir(buf, git_dir_len + 5, git_hooks_path);
 -      else if (git_common_dir_env)
 -              update_common_dir(buf, git_dir_len, NULL);
 +      else if (repo->different_commondir)
 +              update_common_dir(buf, git_dir_len, repo->commondir);
  }
  
 -static void do_git_path(const struct worktree *wt, struct strbuf *buf,
 +static void strbuf_worktree_gitdir(struct strbuf *buf,
 +                                 const struct repository *repo,
 +                                 const struct worktree *wt)
 +{
 +      if (!wt)
 +              strbuf_addstr(buf, repo->gitdir);
 +      else if (!wt->id)
 +              strbuf_addstr(buf, repo->commondir);
 +      else
 +              strbuf_git_common_path(buf, repo, "worktrees/%s", wt->id);
 +}
 +
 +static void do_git_path(const struct repository *repo,
 +                      const struct worktree *wt, struct strbuf *buf,
                        const char *fmt, va_list args)
  {
        int gitdir_len;
 -      strbuf_addstr(buf, get_worktree_git_dir(wt));
 +      strbuf_worktree_gitdir(buf, repo, wt);
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        gitdir_len = buf->len;
        strbuf_vaddf(buf, fmt, args);
 -      adjust_git_path(buf, gitdir_len);
 +      if (!wt)
 +              adjust_git_path(repo, buf, gitdir_len);
        strbuf_cleanup_path(buf);
  }
  
 +char *repo_git_path(const struct repository *repo,
 +                  const char *fmt, ...)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(repo, NULL, &path, fmt, args);
 +      va_end(args);
 +      return strbuf_detach(&path, NULL);
 +}
 +
 +void strbuf_repo_git_path(struct strbuf *sb,
 +                        const struct repository *repo,
 +                        const char *fmt, ...)
 +{
 +      va_list args;
 +      va_start(args, fmt);
 +      do_git_path(repo, NULL, sb, fmt, args);
 +      va_end(args);
 +}
 +
  char *git_path_buf(struct strbuf *buf, const char *fmt, ...)
  {
        va_list args;
        strbuf_reset(buf);
        va_start(args, fmt);
 -      do_git_path(NULL, buf, fmt, args);
 +      do_git_path(the_repository, NULL, buf, fmt, args);
        va_end(args);
        return buf->buf;
  }
@@@ -451,7 -415,7 +451,7 @@@ void strbuf_git_path(struct strbuf *sb
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, sb, fmt, args);
 +      do_git_path(the_repository, NULL, sb, fmt, args);
        va_end(args);
  }
  
@@@ -460,7 -424,7 +460,7 @@@ const char *git_path(const char *fmt, .
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, pathname, fmt, args);
 +      do_git_path(the_repository, NULL, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
@@@ -470,7 -434,7 +470,7 @@@ char *git_pathdup(const char *fmt, ...
        struct strbuf path = STRBUF_INIT;
        va_list args;
        va_start(args, fmt);
 -      do_git_path(NULL, &path, fmt, args);
 +      do_git_path(the_repository, NULL, &path, fmt, args);
        va_end(args);
        return strbuf_detach(&path, NULL);
  }
@@@ -501,52 -465,11 +501,52 @@@ const char *worktree_git_path(const str
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_path(wt, pathname, fmt, args);
 +      do_git_path(the_repository, wt, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
  
 +static void do_worktree_path(const struct repository *repo,
 +                           struct strbuf *buf,
 +                           const char *fmt, va_list args)
 +{
 +      strbuf_addstr(buf, repo->worktree);
 +      if(buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
 +              strbuf_addch(buf, '/');
 +
 +      strbuf_vaddf(buf, fmt, args);
 +      strbuf_cleanup_path(buf);
 +}
 +
 +char *repo_worktree_path(const struct repository *repo, const char *fmt, ...)
 +{
 +      struct strbuf path = STRBUF_INIT;
 +      va_list args;
 +
 +      if (!repo->worktree)
 +              return NULL;
 +
 +      va_start(args, fmt);
 +      do_worktree_path(repo, &path, fmt, args);
 +      va_end(args);
 +
 +      return strbuf_detach(&path, NULL);
 +}
 +
 +void strbuf_repo_worktree_path(struct strbuf *sb,
 +                             const struct repository *repo,
 +                             const char *fmt, ...)
 +{
 +      va_list args;
 +
 +      if (!repo->worktree)
 +              return;
 +
 +      va_start(args, fmt);
 +      do_worktree_path(repo, sb, fmt, args);
 +      va_end(args);
 +}
 +
  /* Returns 0 on success, negative on failure. */
  static int do_submodule_path(struct strbuf *buf, const char *path,
                             const char *fmt, va_list args)
@@@ -601,12 -524,11 +601,12 @@@ int strbuf_git_path_submodule(struct st
        return err;
  }
  
 -static void do_git_common_path(struct strbuf *buf,
 +static void do_git_common_path(const struct repository *repo,
 +                             struct strbuf *buf,
                               const char *fmt,
                               va_list args)
  {
 -      strbuf_addstr(buf, get_git_common_dir());
 +      strbuf_addstr(buf, repo->commondir);
        if (buf->len && !is_dir_sep(buf->buf[buf->len - 1]))
                strbuf_addch(buf, '/');
        strbuf_vaddf(buf, fmt, args);
@@@ -618,27 -540,24 +618,27 @@@ const char *git_common_path(const char 
        struct strbuf *pathname = get_pathname();
        va_list args;
        va_start(args, fmt);
 -      do_git_common_path(pathname, fmt, args);
 +      do_git_common_path(the_repository, pathname, fmt, args);
        va_end(args);
        return pathname->buf;
  }
  
 -void strbuf_git_common_path(struct strbuf *sb, const char *fmt, ...)
 +void strbuf_git_common_path(struct strbuf *sb,
 +                          const struct repository *repo,
 +                          const char *fmt, ...)
  {
        va_list args;
        va_start(args, fmt);
 -      do_git_common_path(sb, fmt, args);
 +      do_git_common_path(repo, sb, fmt, args);
        va_end(args);
  }
  
  int validate_headref(const char *path)
  {
        struct stat st;
 -      char *buf, buffer[256];
 -      unsigned char sha1[20];
 +      char buffer[256];
 +      const char *refname;
 +      struct object_id oid;
        int fd;
        ssize_t len;
  
        len = read_in_full(fd, buffer, sizeof(buffer)-1);
        close(fd);
  
 +      if (len < 0)
 +              return -1;
 +      buffer[len] = '\0';
 +
        /*
         * Is it a symbolic ref?
         */
 -      if (len < 4)
 -              return -1;
 -      if (!memcmp("ref:", buffer, 4)) {
 -              buf = buffer + 4;
 -              len -= 4;
 -              while (len && isspace(*buf))
 -                      buf++, len--;
 -              if (len >= 5 && !memcmp("refs/", buf, 5))
 +      if (skip_prefix(buffer, "ref:", &refname)) {
 +              while (isspace(*refname))
 +                      refname++;
 +              if (starts_with(refname, "refs/"))
                        return 0;
        }
  
        /*
         * Is this a detached HEAD?
         */
 -      if (!get_sha1_hex(buffer, sha1))
 +      if (!get_oid_hex(buffer, &oid))
                return 0;
  
        return -1;
@@@ -717,7 -636,7 +717,7 @@@ char *expand_user_path(const char *path
                        if (!home)
                                goto return_null;
                        if (real_home)
 -                              strbuf_addstr(&user_path, real_path(home));
 +                              strbuf_add_real_path(&user_path, home);
                        else
                                strbuf_addstr(&user_path, home);
  #ifdef GIT_WINDOWS_NATIVE
@@@ -1305,7 -1224,7 +1305,7 @@@ static int only_spaces_and_periods(cons
  
  int is_ntfs_dotgit(const char *name)
  {
-       int len;
+       size_t len;
  
        for (len = 0; ; len++)
                if (!name[len] || name[len] == '\\' || is_dir_sep(name[len])) {
                }
  }
  
+ static int is_ntfs_dot_generic(const char *name,
+                              const char *dotgit_name,
+                              size_t len,
+                              const char *dotgit_ntfs_shortname_prefix)
+ {
+       int saw_tilde;
+       size_t i;
+       if ((name[0] == '.' && !strncasecmp(name + 1, dotgit_name, len))) {
+               i = len + 1;
+ only_spaces_and_periods:
+               for (;;) {
+                       char c = name[i++];
+                       if (!c)
+                               return 1;
+                       if (c != ' ' && c != '.')
+                               return 0;
+               }
+       }
+       /*
+        * Is it a regular NTFS short name, i.e. shortened to 6 characters,
+        * followed by ~1, ... ~4?
+        */
+       if (!strncasecmp(name, dotgit_name, 6) && name[6] == '~' &&
+           name[7] >= '1' && name[7] <= '4') {
+               i = 8;
+               goto only_spaces_and_periods;
+       }
+       /*
+        * Is it a fall-back NTFS short name (for details, see
+        * https://en.wikipedia.org/wiki/8.3_filename?
+        */
+       for (i = 0, saw_tilde = 0; i < 8; i++)
+               if (name[i] == '\0')
+                       return 0;
+               else if (saw_tilde) {
+                       if (name[i] < '0' || name[i] > '9')
+                               return 0;
+               } else if (name[i] == '~') {
+                       if (name[++i] < '1' || name[i] > '9')
+                               return 0;
+                       saw_tilde = 1;
+               } else if (i >= 6)
+                       return 0;
+               else if (name[i] < 0) {
+                       /*
+                        * We know our needles contain only ASCII, so we clamp
+                        * here to make the results of tolower() sane.
+                        */
+                       return 0;
+               } else if (tolower(name[i]) != dotgit_ntfs_shortname_prefix[i])
+                       return 0;
+       goto only_spaces_and_periods;
+ }
+ /*
+  * Inline helper to make sure compiler resolves strlen() on literals at
+  * compile time.
+  */
+ static inline int is_ntfs_dot_str(const char *name, const char *dotgit_name,
+                                 const char *dotgit_ntfs_shortname_prefix)
+ {
+       return is_ntfs_dot_generic(name, dotgit_name, strlen(dotgit_name),
+                                  dotgit_ntfs_shortname_prefix);
+ }
+ int is_ntfs_dotgitmodules(const char *name)
+ {
+       return is_ntfs_dot_str(name, "gitmodules", "gi7eba");
+ }
+ int is_ntfs_dotgitignore(const char *name)
+ {
+       return is_ntfs_dot_str(name, "gitignore", "gi250a");
+ }
+ int is_ntfs_dotgitattributes(const char *name)
+ {
+       return is_ntfs_dot_str(name, "gitattributes", "gi7d29");
+ }
  int looks_like_command_line_option(const char *str)
  {
        return str && str[0] == '-';
diff --combined read-cache.c
index 59a73f4a81d76a19b8a2280e9643f7c1e715a5d4,aa99f1f797985d4128af3716b8e4257e4ba2d37c..4b35e87847f0c346f4968765fa8dc64a863a8047
@@@ -5,7 -5,6 +5,7 @@@
   */
  #define NO_THE_INDEX_COMPATIBILITY_MACROS
  #include "cache.h"
 +#include "config.h"
  #include "tempfile.h"
  #include "lockfile.h"
  #include "cache-tree.h"
@@@ -19,7 -18,6 +19,7 @@@
  #include "varint.h"
  #include "split-index.h"
  #include "utf8.h"
 +#include "fsmonitor.h"
  
  /* Mask for the name length in ce_flags in the on-disk index */
  
  #define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUC" */
  #define CACHE_EXT_LINK 0x6c696e6b       /* "link" */
  #define CACHE_EXT_UNTRACKED 0x554E5452          /* "UNTR" */
 +#define CACHE_EXT_FSMONITOR 0x46534D4E          /* "FSMN" */
  
  /* changes that can be kept in $GIT_DIR/index (basically all extensions) */
  #define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
                 CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \
 -               SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED)
 +               SPLIT_INDEX_ORDERED | UNTRACKED_CHANGED | FSMONITOR_CHANGED)
  
  struct index_state the_index;
  static const char *alternate_index_output;
@@@ -62,29 -59,27 +62,29 @@@ static void replace_index_entry(struct 
        replace_index_entry_in_base(istate, old, ce);
        remove_name_hash(istate, old);
        free(old);
 +      ce->ce_flags &= ~CE_HASHED;
        set_index_entry(istate, nr, ce);
        ce->ce_flags |= CE_UPDATE_IN_BASE;
 +      mark_fsmonitor_invalid(istate, ce);
        istate->cache_changed |= CE_ENTRY_CHANGED;
  }
  
  void rename_index_entry_at(struct index_state *istate, int nr, const char *new_name)
  {
 -      struct cache_entry *old = istate->cache[nr], *new;
 +      struct cache_entry *old_entry = istate->cache[nr], *new_entry;
        int namelen = strlen(new_name);
  
 -      new = xmalloc(cache_entry_size(namelen));
 -      copy_cache_entry(new, old);
 -      new->ce_flags &= ~CE_HASHED;
 -      new->ce_namelen = namelen;
 -      new->index = 0;
 -      memcpy(new->name, new_name, namelen + 1);
 +      new_entry = xmalloc(cache_entry_size(namelen));
 +      copy_cache_entry(new_entry, old_entry);
 +      new_entry->ce_flags &= ~CE_HASHED;
 +      new_entry->ce_namelen = namelen;
 +      new_entry->index = 0;
 +      memcpy(new_entry->name, new_name, namelen + 1);
  
 -      cache_tree_invalidate_path(istate, old->name);
 -      untracked_cache_remove_from_index(istate, old->name);
 +      cache_tree_invalidate_path(istate, old_entry->name);
 +      untracked_cache_remove_from_index(istate, old_entry->name);
        remove_index_entry_at(istate, nr);
 -      add_index_entry(istate, new, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
 +      add_index_entry(istate, new_entry, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE);
  }
  
  void fill_stat_data(struct stat_data *sd, struct stat *st)
@@@ -154,10 -149,8 +154,10 @@@ void fill_stat_cache_info(struct cache_
        if (assume_unchanged)
                ce->ce_flags |= CE_VALID;
  
 -      if (S_ISREG(st->st_mode))
 +      if (S_ISREG(st->st_mode)) {
                ce_mark_uptodate(ce);
 +              mark_fsmonitor_valid(ce);
 +      }
  }
  
  static int ce_compare_data(const struct cache_entry *ce, struct stat *st)
        int fd = git_open_cloexec(ce->name, O_RDONLY);
  
        if (fd >= 0) {
 -              unsigned char sha1[20];
 -              if (!index_fd(sha1, fd, st, OBJ_BLOB, ce->name, 0))
 -                      match = hashcmp(sha1, ce->oid.hash);
 +              struct object_id oid;
 +              if (!index_fd(&oid, fd, st, OBJ_BLOB, ce->name, 0))
 +                      match = oidcmp(&oid, &ce->oid);
                /* index_fd() closed the file descriptor already */
        }
        return match;
@@@ -197,7 -190,7 +197,7 @@@ static int ce_compare_link(const struc
  
  static int ce_compare_gitlink(const struct cache_entry *ce)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
        /*
         * We don't actually require that the .git directory
         *
         * If so, we consider it always to match.
         */
 -      if (resolve_gitlink_ref(ce->name, "HEAD", sha1) < 0)
 +      if (resolve_gitlink_ref(ce->name, "HEAD", &oid) < 0)
                return 0;
 -      return hashcmp(sha1, ce->oid.hash);
 +      return oidcmp(&oid, &ce->oid);
  }
  
  static int ce_modified_check_fs(const struct cache_entry *ce, struct stat *st)
        case S_IFDIR:
                if (S_ISGITLINK(ce->ce_mode))
                        return ce_compare_gitlink(ce) ? DATA_CHANGED : 0;
 +              /* else fallthrough */
        default:
                return TYPE_CHANGED;
        }
@@@ -307,7 -299,7 +307,7 @@@ int match_stat_data_racy(const struct i
        return match_stat_data(sd, st);
  }
  
 -int ie_match_stat(const struct index_state *istate,
 +int ie_match_stat(struct index_state *istate,
                  const struct cache_entry *ce, struct stat *st,
                  unsigned int options)
  {
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
        int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
        int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
 +      int ignore_fsmonitor = options & CE_MATCH_IGNORE_FSMONITOR;
  
 +      if (!ignore_fsmonitor)
 +              refresh_fsmonitor(istate);
        /*
         * If it's marked as always valid in the index, it's
         * valid whatever the checked-out copy says.
                return 0;
        if (!ignore_valid && (ce->ce_flags & CE_VALID))
                return 0;
 +      if (!ignore_fsmonitor && (ce->ce_flags & CE_FSMONITOR_VALID))
 +              return 0;
  
        /*
         * Intent-to-add entries have not been added, so the index entry
        return changed;
  }
  
 -int ie_modified(const struct index_state *istate,
 +int ie_modified(struct index_state *istate,
                const struct cache_entry *ce,
                struct stat *st, unsigned int options)
  {
@@@ -527,8 -514,9 +527,8 @@@ int remove_index_entry_at(struct index_
        istate->cache_nr--;
        if (pos >= istate->cache_nr)
                return 0;
 -      memmove(istate->cache + pos,
 -              istate->cache + pos + 1,
 -              (istate->cache_nr - pos) * sizeof(struct cache_entry *));
 +      MOVE_ARRAY(istate->cache + pos, istate->cache + pos + 1,
 +                 istate->cache_nr - pos);
        return 1;
  }
  
@@@ -616,43 -604,39 +616,43 @@@ static struct cache_entry *create_alias
                                           struct cache_entry *alias)
  {
        int len;
 -      struct cache_entry *new;
 +      struct cache_entry *new_entry;
  
        if (alias->ce_flags & CE_ADDED)
                die("Will not add file alias '%s' ('%s' already exists in index)", ce->name, alias->name);
  
        /* Ok, create the new entry using the name of the existing alias */
        len = ce_namelen(alias);
 -      new = xcalloc(1, cache_entry_size(len));
 -      memcpy(new->name, alias->name, len);
 -      copy_cache_entry(new, ce);
 +      new_entry = xcalloc(1, cache_entry_size(len));
 +      memcpy(new_entry->name, alias->name, len);
 +      copy_cache_entry(new_entry, ce);
        save_or_free_index_entry(istate, ce);
 -      return new;
 +      return new_entry;
  }
  
  void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
  {
 -      unsigned char sha1[20];
 -      if (write_sha1_file("", 0, blob_type, sha1))
 +      struct object_id oid;
 +      if (write_object_file("", 0, blob_type, &oid))
                die("cannot create an empty blob in the object database");
 -      hashcpy(ce->oid.hash, sha1);
 +      oidcpy(&ce->oid, &oid);
  }
  
  int add_to_index(struct index_state *istate, const char *path, struct stat *st, int flags)
  {
        int size, namelen, was_same;
        mode_t st_mode = st->st_mode;
 -      struct cache_entry *ce, *alias;
 +      struct cache_entry *ce, *alias = NULL;
        unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;
        int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
        int pretend = flags & ADD_CACHE_PRETEND;
        int intent_only = flags & ADD_CACHE_INTENT;
        int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
                          (intent_only ? ADD_CACHE_NEW_ONLY : 0));
 +      int newflags = HASH_WRITE_OBJECT;
 +
 +      if (flags & HASH_RENORMALIZE)
 +              newflags |= HASH_RENORMALIZE;
  
        if (!S_ISREG(st_mode) && !S_ISLNK(st_mode) && !S_ISDIR(st_mode))
                return error("%s: can only add regular files, symbolic links or git-directories", path);
        if (ignore_case) {
                adjust_dirname_case(istate, ce->name);
        }
 +      if (!(flags & HASH_RENORMALIZE)) {
 +              alias = index_file_exists(istate, ce->name,
 +                                        ce_namelen(ce), ignore_case);
 +              if (alias &&
 +                  !ce_stage(alias) &&
 +                  !ie_match_stat(istate, alias, st, ce_option)) {
 +                      /* Nothing changed, really */
 +                      if (!S_ISGITLINK(alias->ce_mode))
 +                              ce_mark_uptodate(alias);
 +                      alias->ce_flags |= CE_ADDED;
  
 -      alias = index_file_exists(istate, ce->name, ce_namelen(ce), ignore_case);
 -      if (alias && !ce_stage(alias) && !ie_match_stat(istate, alias, st, ce_option)) {
 -              /* Nothing changed, really */
 -              if (!S_ISGITLINK(alias->ce_mode))
 -                      ce_mark_uptodate(alias);
 -              alias->ce_flags |= CE_ADDED;
 -
 -              free(ce);
 -              return 0;
 +                      free(ce);
 +                      return 0;
 +              }
        }
        if (!intent_only) {
 -              if (index_path(ce->oid.hash, path, st, HASH_WRITE_OBJECT)) {
 +              if (index_path(&ce->oid, path, st, newflags)) {
                        free(ce);
                        return error("unable to index file %s", path);
                }
@@@ -752,7 -732,7 +752,7 @@@ struct cache_entry *make_cache_entry(un
        int size, len;
        struct cache_entry *ce, *ret;
  
-       if (!verify_path(path)) {
+       if (!verify_path(path, mode)) {
                error("Invalid path '%s'", path);
                return NULL;
        }
@@@ -797,7 -777,6 +797,7 @@@ int chmod_index_entry(struct index_stat
        }
        cache_tree_invalidate_path(istate, ce->name);
        ce->ce_flags |= CE_UPDATE_IN_BASE;
 +      mark_fsmonitor_invalid(istate, ce);
        istate->cache_changed |= CE_ENTRY_CHANGED;
  
        return 0;
@@@ -817,7 -796,7 +817,7 @@@ int ce_same_name(const struct cache_ent
   * Also, we don't want double slashes or slashes at the
   * end that can make pathnames ambiguous.
   */
- static int verify_dotfile(const char *rest)
+ static int verify_dotfile(const char *rest, unsigned mode)
  {
        /*
         * The first character was '.', but that
  
        switch (*rest) {
        /*
-        * ".git" followed by  NUL or slash is bad. This
-        * shares the path end test with the ".." case.
+        * ".git" followed by NUL or slash is bad. Note that we match
+        * case-insensitively here, even if ignore_case is not set.
+        * This outlaws ".GIT" everywhere out of an abundance of caution,
+        * since there's really no good reason to allow it.
+        *
+        * Once we've seen ".git", we can also find ".gitmodules", etc (also
+        * case-insensitively).
         */
        case 'g':
        case 'G':
                        break;
                if (rest[2] != 't' && rest[2] != 'T')
                        break;
-               rest += 2;
-       /* fallthrough */
+               if (rest[3] == '\0' || is_dir_sep(rest[3]))
+                       return 0;
+               if (S_ISLNK(mode)) {
+                       rest += 3;
+                       if (skip_iprefix(rest, "modules", &rest) &&
+                           (*rest == '\0' || is_dir_sep(*rest)))
+                               return 0;
+               }
+               break;
        case '.':
                if (rest[1] == '\0' || is_dir_sep(rest[1]))
                        return 0;
        return 1;
  }
  
- int verify_path(const char *path)
+ int verify_path(const char *path, unsigned mode)
  {
        char c;
  
                        return 1;
                if (is_dir_sep(c)) {
  inside:
-                       if (protect_hfs && is_hfs_dotgit(path))
-                               return 0;
-                       if (protect_ntfs && is_ntfs_dotgit(path))
-                               return 0;
+                       if (protect_hfs) {
+                               if (is_hfs_dotgit(path))
+                                       return 0;
+                               if (S_ISLNK(mode)) {
+                                       if (is_hfs_dotgitmodules(path))
+                                               return 0;
+                               }
+                       }
+                       if (protect_ntfs) {
+                               if (is_ntfs_dotgit(path))
+                                       return 0;
+                               if (S_ISLNK(mode)) {
+                                       if (is_ntfs_dotgitmodules(path))
+                                               return 0;
+                               }
+                       }
                        c = *path++;
-                       if ((c == '.' && !verify_dotfile(path)) ||
+                       if ((c == '.' && !verify_dotfile(path, mode)) ||
                            is_dir_sep(c) || c == '\0')
                                return 0;
                }
@@@ -1184,7 -1188,7 +1209,7 @@@ static int add_index_entry_with_check(s
  
        if (!ok_to_add)
                return -1;
-       if (!verify_path(ce->name))
+       if (!verify_path(ce->name, ce->ce_mode))
                return error("Invalid path '%s'", ce->name);
  
        if (!skip_df_check &&
@@@ -1218,8 -1222,9 +1243,8 @@@ int add_index_entry(struct index_state 
        /* Add it in.. */
        istate->cache_nr++;
        if (istate->cache_nr > pos + 1)
 -              memmove(istate->cache + pos + 1,
 -                      istate->cache + pos,
 -                      (istate->cache_nr - pos - 1) * sizeof(ce));
 +              MOVE_ARRAY(istate->cache + pos + 1, istate->cache + pos,
 +                         istate->cache_nr - pos - 1);
        set_index_entry(istate, pos, ce);
        istate->cache_changed |= CE_ENTRY_ADDED;
        return 0;
@@@ -1248,13 -1253,10 +1273,13 @@@ static struct cache_entry *refresh_cach
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
        int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
        int ignore_missing = options & CE_MATCH_IGNORE_MISSING;
 +      int ignore_fsmonitor = options & CE_MATCH_IGNORE_FSMONITOR;
  
        if (!refresh || ce_uptodate(ce))
                return ce;
  
 +      if (!ignore_fsmonitor)
 +              refresh_fsmonitor(istate);
        /*
         * CE_VALID or CE_SKIP_WORKTREE means the user promised us
         * that the change to the work tree does not matter and told
                ce_mark_uptodate(ce);
                return ce;
        }
 +      if (!ignore_fsmonitor && (ce->ce_flags & CE_FSMONITOR_VALID)) {
 +              ce_mark_uptodate(ce);
 +              return ce;
 +      }
  
        if (has_symlink_leading_path(ce->name, ce_namelen(ce))) {
                if (ignore_missing)
                         * because CE_UPTODATE flag is in-core only;
                         * we are not going to write this change out.
                         */
 -                      if (!S_ISGITLINK(ce->ce_mode))
 +                      if (!S_ISGITLINK(ce->ce_mode)) {
                                ce_mark_uptodate(ce);
 +                              mark_fsmonitor_valid(ce);
 +                      }
                        return ce;
                }
        }
  
        size = ce_size(ce);
        updated = xmalloc(size);
 -      memcpy(updated, ce, size);
 +      copy_cache_entry(updated, ce);
 +      memcpy(updated->name, ce->name, ce->ce_namelen + 1);
        fill_stat_cache_info(updated, &st);
        /*
         * If ignore_valid is not set, we should leave CE_VALID bit
@@@ -1373,7 -1368,6 +1398,7 @@@ int refresh_index(struct index_state *i
        const char *typechange_fmt;
        const char *added_fmt;
        const char *unmerged_fmt;
 +      uint64_t start = getnanotime();
  
        modified_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
        deleted_fmt = (in_porcelain ? "D\t%s\n" : "%s: needs update\n");
        added_fmt = (in_porcelain ? "A\t%s\n" : "%s needs update\n");
        unmerged_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
        for (i = 0; i < istate->cache_nr; i++) {
 -              struct cache_entry *ce, *new;
 +              struct cache_entry *ce, *new_entry;
                int cache_errno = 0;
                int changed = 0;
                int filtered = 0;
                if (filtered)
                        continue;
  
 -              new = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
 -              if (new == ce)
 +              new_entry = refresh_cache_ent(istate, ce, options, &cache_errno, &changed);
 +              if (new_entry == ce)
                        continue;
 -              if (!new) {
 +              if (!new_entry) {
                        const char *fmt;
  
                        if (really && cache_errno == EINVAL) {
                                 */
                                ce->ce_flags &= ~CE_VALID;
                                ce->ce_flags |= CE_UPDATE_IN_BASE;
 +                              mark_fsmonitor_invalid(istate, ce);
                                istate->cache_changed |= CE_ENTRY_CHANGED;
                        }
                        if (quiet)
                        continue;
                }
  
 -              replace_index_entry(istate, i, new);
 +              replace_index_entry(istate, i, new_entry);
        }
 +      trace_performance_since(start, "refresh index");
        return has_errors;
  }
  
@@@ -1532,7 -1524,6 +1557,7 @@@ struct ondisk_cache_entry_extended 
  };
  
  /* These are only used for v3 or lower */
 +#define align_padding_size(size, len) ((size + (len) + 8) & ~7) - (size + len)
  #define align_flex_name(STRUCT,len) ((offsetof(struct STRUCT,name) + (len) + 8) & ~7)
  #define ondisk_cache_entry_size(len) align_flex_name(ondisk_cache_entry,len)
  #define ondisk_cache_entry_extended_size(len) align_flex_name(ondisk_cache_entry_extended,len)
  /* Allow fsck to force verification of the index checksum. */
  int verify_index_checksum;
  
 +/* Allow fsck to force verification of the cache entry order. */
 +int verify_ce_order;
 +
  static int verify_hdr(struct cache_header *hdr, unsigned long size)
  {
 -      git_SHA_CTX c;
 -      unsigned char sha1[20];
 +      git_hash_ctx c;
 +      unsigned char hash[GIT_MAX_RAWSZ];
        int hdr_version;
  
        if (hdr->hdr_signature != htonl(CACHE_SIGNATURE))
        if (!verify_index_checksum)
                return 0;
  
 -      git_SHA1_Init(&c);
 -      git_SHA1_Update(&c, hdr, size - 20);
 -      git_SHA1_Final(sha1, &c);
 -      if (hashcmp(sha1, (unsigned char *)hdr + size - 20))
 +      the_hash_algo->init_fn(&c);
 +      the_hash_algo->update_fn(&c, hdr, size - the_hash_algo->rawsz);
 +      the_hash_algo->final_fn(hash, &c);
 +      if (hashcmp(hash, (unsigned char *)hdr + size - the_hash_algo->rawsz))
                return error("bad index file sha1 signature");
        return 0;
  }
@@@ -1586,9 -1574,6 +1611,9 @@@ static int read_index_extension(struct 
        case CACHE_EXT_UNTRACKED:
                istate->untracked = read_untracked_extension(data, sz);
                break;
 +      case CACHE_EXT_FSMONITOR:
 +              read_fsmonitor_extension(istate, data, sz);
 +              break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
                        return error("index uses %.4s extension, which we do not understand",
@@@ -1606,7 -1591,7 +1631,7 @@@ int hold_locked_index(struct lock_file 
  
  int read_index(struct index_state *istate)
  {
 -      return read_index_from(istate, get_index_file());
 +      return read_index_from(istate, get_index_file(), get_git_dir());
  }
  
  static struct cache_entry *cache_entry_from_ondisk(struct ondisk_cache_entry *ondisk,
@@@ -1706,9 -1691,6 +1731,9 @@@ static void check_ce_order(struct index
  {
        unsigned int i;
  
 +      if (!verify_ce_order)
 +              return;
 +
        for (i = 1; i < istate->cache_nr; i++) {
                struct cache_entry *ce = istate->cache[i - 1];
                struct cache_entry *next_ce = istate->cache[i];
@@@ -1764,7 -1746,6 +1789,7 @@@ static void post_read_index_from(struc
        check_ce_order(istate);
        tweak_untracked_cache(istate);
        tweak_split_index(istate);
 +      tweak_fsmonitor(istate);
  }
  
  /* remember to discard_cache() before reading a different cache! */
@@@ -1794,7 -1775,7 +1819,7 @@@ int do_read_index(struct index_state *i
                die_errno("cannot stat the open index");
  
        mmap_size = xsize_t(st.st_size);
 -      if (mmap_size < sizeof(struct cache_header) + 20)
 +      if (mmap_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                die("index file smaller than expected");
  
        mmap = xmmap(NULL, mmap_size, PROT_READ, MAP_PRIVATE, fd, 0);
        if (verify_hdr(hdr, mmap_size) < 0)
                goto unmap;
  
 -      hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - 20);
 +      hashcpy(istate->sha1, (const unsigned char *)hdr + mmap_size - the_hash_algo->rawsz);
        istate->version = ntohl(hdr->hdr_version);
        istate->cache_nr = ntohl(hdr->hdr_entries);
        istate->cache_alloc = alloc_nr(istate->cache_nr);
        istate->timestamp.sec = st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
  
 -      while (src_offset <= mmap_size - 20 - 8) {
 +      while (src_offset <= mmap_size - the_hash_algo->rawsz - 8) {
                /* After an array of active_nr index entries,
                 * there can be arbitrary number of extended
                 * sections, each of which is prefixed with
@@@ -1866,27 -1847,26 +1891,27 @@@ unmap
   * This way, shared index can be removed if they have not been used
   * for some time.
   */
 -static void freshen_shared_index(char *base_sha1_hex, int warn)
 +static void freshen_shared_index(const char *shared_index, int warn)
  {
 -      char *shared_index = git_pathdup("sharedindex.%s", base_sha1_hex);
        if (!check_and_freshen_file(shared_index, 1) && warn)
                warning("could not freshen shared index '%s'", shared_index);
 -      free(shared_index);
  }
  
 -int read_index_from(struct index_state *istate, const char *path)
 +int read_index_from(struct index_state *istate, const char *path,
 +                  const char *gitdir)
  {
 +      uint64_t start = getnanotime();
        struct split_index *split_index;
        int ret;
        char *base_sha1_hex;
 -      const char *base_path;
 +      char *base_path;
  
        /* istate->initialized covers both .git/index and .git/sharedindex.xxx */
        if (istate->initialized)
                return istate->cache_nr;
  
        ret = do_read_index(istate, path, 0);
 +      trace_performance_since(start, "read cache %s", path);
  
        split_index = istate->split_index;
        if (!split_index || is_null_sha1(split_index->base_sha1)) {
                split_index->base = xcalloc(1, sizeof(*split_index->base));
  
        base_sha1_hex = sha1_to_hex(split_index->base_sha1);
 -      base_path = git_path("sharedindex.%s", base_sha1_hex);
 +      base_path = xstrfmt("%s/sharedindex.%s", gitdir, base_sha1_hex);
        ret = do_read_index(split_index->base, base_path, 1);
        if (hashcmp(split_index->base_sha1, split_index->base->sha1))
                die("broken index, expect %s in %s, got %s",
                    base_sha1_hex, base_path,
                    sha1_to_hex(split_index->base->sha1));
  
 -      freshen_shared_index(base_sha1_hex, 0);
 +      freshen_shared_index(base_path, 0);
        merge_base_index(istate);
        post_read_index_from(istate);
 +      trace_performance_since(start, "read cache %s", base_path);
 +      free(base_path);
        return ret;
  }
  
@@@ -1941,7 -1919,8 +1966,7 @@@ int discard_index(struct index_state *i
        free_name_hash(istate);
        cache_tree_free(&(istate->cache_tree));
        istate->initialized = 0;
 -      free(istate->cache);
 -      istate->cache = NULL;
 +      FREE_AND_NULL(istate->cache);
        istate->cache_alloc = 0;
        discard_split_index(istate);
        free_untracked_cache(istate->untracked);
@@@ -1963,19 -1942,19 +1988,19 @@@ int unmerged_index(const struct index_s
  static unsigned char write_buffer[WRITE_BUFFER_SIZE];
  static unsigned long write_buffer_len;
  
 -static int ce_write_flush(git_SHA_CTX *context, int fd)
 +static int ce_write_flush(git_hash_ctx *context, int fd)
  {
        unsigned int buffered = write_buffer_len;
        if (buffered) {
 -              git_SHA1_Update(context, write_buffer, buffered);
 -              if (write_in_full(fd, write_buffer, buffered) != buffered)
 +              the_hash_algo->update_fn(context, write_buffer, buffered);
 +              if (write_in_full(fd, write_buffer, buffered) < 0)
                        return -1;
                write_buffer_len = 0;
        }
        return 0;
  }
  
 -static int ce_write(git_SHA_CTX *context, int fd, void *data, unsigned int len)
 +static int ce_write(git_hash_ctx *context, int fd, void *data, unsigned int len)
  {
        while (len) {
                unsigned int buffered = write_buffer_len;
        return 0;
  }
  
 -static int write_index_ext_header(git_SHA_CTX *context, int fd,
 +static int write_index_ext_header(git_hash_ctx *context, int fd,
                                  unsigned int ext, unsigned int sz)
  {
        ext = htonl(ext);
                (ce_write(context, fd, &sz, 4) < 0)) ? -1 : 0;
  }
  
 -static int ce_flush(git_SHA_CTX *context, int fd, unsigned char *sha1)
 +static int ce_flush(git_hash_ctx *context, int fd, unsigned char *hash)
  {
        unsigned int left = write_buffer_len;
  
        if (left) {
                write_buffer_len = 0;
 -              git_SHA1_Update(context, write_buffer, left);
 +              the_hash_algo->update_fn(context, write_buffer, left);
        }
  
 -      /* Flush first if not enough space for SHA1 signature */
 -      if (left + 20 > WRITE_BUFFER_SIZE) {
 -              if (write_in_full(fd, write_buffer, left) != left)
 +      /* Flush first if not enough space for hash signature */
 +      if (left + the_hash_algo->rawsz > WRITE_BUFFER_SIZE) {
 +              if (write_in_full(fd, write_buffer, left) < 0)
                        return -1;
                left = 0;
        }
  
 -      /* Append the SHA1 signature at the end */
 -      git_SHA1_Final(write_buffer + left, context);
 -      hashcpy(sha1, write_buffer + left);
 -      left += 20;
 -      return (write_in_full(fd, write_buffer, left) != left) ? -1 : 0;
 +      /* Append the hash signature at the end */
 +      the_hash_algo->final_fn(write_buffer + left, context);
 +      hashcpy(hash, write_buffer + left);
 +      left += the_hash_algo->rawsz;
 +      return (write_in_full(fd, write_buffer, left) < 0) ? -1 : 0;
  }
  
  static void ce_smudge_racily_clean_entry(struct cache_entry *ce)
  }
  
  /* Copy miscellaneous fields but not the name */
 -static char *copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
 +static void copy_cache_entry_to_ondisk(struct ondisk_cache_entry *ondisk,
                                       struct cache_entry *ce)
  {
        short flags;
                struct ondisk_cache_entry_extended *ondisk2;
                ondisk2 = (struct ondisk_cache_entry_extended *)ondisk;
                ondisk2->flags2 = htons((ce->ce_flags & CE_EXTENDED_FLAGS) >> 16);
 -              return ondisk2->name;
 -      }
 -      else {
 -              return ondisk->name;
        }
  }
  
 -static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce,
 -                        struct strbuf *previous_name)
 +static int ce_write_entry(git_hash_ctx *c, int fd, struct cache_entry *ce,
 +                        struct strbuf *previous_name, struct ondisk_cache_entry *ondisk)
  {
        int size;
 -      struct ondisk_cache_entry *ondisk;
 -      int saved_namelen = saved_namelen; /* compiler workaround */
 -      char *name;
        int result;
 +      unsigned int saved_namelen;
 +      int stripped_name = 0;
 +      static unsigned char padding[8] = { 0x00 };
  
        if (ce->ce_flags & CE_STRIP_NAME) {
                saved_namelen = ce_namelen(ce);
                ce->ce_namelen = 0;
 +              stripped_name = 1;
        }
  
 +      if (ce->ce_flags & CE_EXTENDED)
 +              size = offsetof(struct ondisk_cache_entry_extended, name);
 +      else
 +              size = offsetof(struct ondisk_cache_entry, name);
 +
        if (!previous_name) {
 -              size = ondisk_ce_size(ce);
 -              ondisk = xcalloc(1, size);
 -              name = copy_cache_entry_to_ondisk(ondisk, ce);
 -              memcpy(name, ce->name, ce_namelen(ce));
 +              int len = ce_namelen(ce);
 +              copy_cache_entry_to_ondisk(ondisk, ce);
 +              result = ce_write(c, fd, ondisk, size);
 +              if (!result)
 +                      result = ce_write(c, fd, ce->name, len);
 +              if (!result)
 +                      result = ce_write(c, fd, padding, align_padding_size(size, len));
        } else {
                int common, to_remove, prefix_size;
                unsigned char to_remove_vi[16];
                to_remove = previous_name->len - common;
                prefix_size = encode_varint(to_remove, to_remove_vi);
  
 -              if (ce->ce_flags & CE_EXTENDED)
 -                      size = offsetof(struct ondisk_cache_entry_extended, name);
 -              else
 -                      size = offsetof(struct ondisk_cache_entry, name);
 -              size += prefix_size + (ce_namelen(ce) - common + 1);
 -
 -              ondisk = xcalloc(1, size);
 -              name = copy_cache_entry_to_ondisk(ondisk, ce);
 -              memcpy(name, to_remove_vi, prefix_size);
 -              memcpy(name + prefix_size, ce->name + common, ce_namelen(ce) - common);
 +              copy_cache_entry_to_ondisk(ondisk, ce);
 +              result = ce_write(c, fd, ondisk, size);
 +              if (!result)
 +                      result = ce_write(c, fd, to_remove_vi, prefix_size);
 +              if (!result)
 +                      result = ce_write(c, fd, ce->name + common, ce_namelen(ce) - common);
 +              if (!result)
 +                      result = ce_write(c, fd, padding, 1);
  
                strbuf_splice(previous_name, common, to_remove,
                              ce->name + common, ce_namelen(ce) - common);
        }
 -      if (ce->ce_flags & CE_STRIP_NAME) {
 +      if (stripped_name) {
                ce->ce_namelen = saved_namelen;
                ce->ce_flags &= ~CE_STRIP_NAME;
        }
  
 -      result = ce_write(c, fd, ondisk, size);
 -      free(ondisk);
        return result;
  }
  
@@@ -2175,7 -2153,7 +2200,7 @@@ static int verify_index_from(const stru
        int fd;
        ssize_t n;
        struct stat st;
 -      unsigned char sha1[20];
 +      unsigned char hash[GIT_MAX_RAWSZ];
  
        if (!istate->initialized)
                return 0;
        if (fstat(fd, &st))
                goto out;
  
 -      if (st.st_size < sizeof(struct cache_header) + 20)
 +      if (st.st_size < sizeof(struct cache_header) + the_hash_algo->rawsz)
                goto out;
  
 -      n = pread_in_full(fd, sha1, 20, st.st_size - 20);
 -      if (n != 20)
 +      n = pread_in_full(fd, hash, the_hash_algo->rawsz, st.st_size - the_hash_algo->rawsz);
 +      if (n != the_hash_algo->rawsz)
                goto out;
  
 -      if (hashcmp(istate->sha1, sha1))
 +      if (hashcmp(istate->sha1, hash))
                goto out;
  
        close(fd);
@@@ -2223,36 -2201,28 +2248,36 @@@ static int has_racy_timestamp(struct in
        return 0;
  }
  
 -/*
 - * Opportunistically update the index but do not complain if we can't
 - */
  void update_index_if_able(struct index_state *istate, struct lock_file *lockfile)
  {
        if ((istate->cache_changed || has_racy_timestamp(istate)) &&
 -          verify_index(istate) &&
 -          write_locked_index(istate, lockfile, COMMIT_LOCK))
 +          verify_index(istate))
 +              write_locked_index(istate, lockfile, COMMIT_LOCK);
 +      else
                rollback_lock_file(lockfile);
  }
  
 +/*
 + * On success, `tempfile` is closed. If it is the temporary file
 + * of a `struct lock_file`, we will therefore effectively perform
 + * a 'close_lock_file_gently()`. Since that is an implementation
 + * detail of lockfiles, callers of `do_write_index()` should not
 + * rely on it.
 + */
  static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
                          int strip_extensions)
  {
 +      uint64_t start = getnanotime();
        int newfd = tempfile->fd;
 -      git_SHA_CTX c;
 +      git_hash_ctx c;
        struct cache_header hdr;
 -      int i, err, removed, extended, hdr_version;
 +      int i, err = 0, removed, extended, hdr_version;
        struct cache_entry **cache = istate->cache;
        int entries = istate->cache_nr;
        struct stat st;
 +      struct ondisk_cache_entry_extended ondisk;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 +      int drop_cache_tree = istate->drop_cache_tree;
  
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
        hdr.hdr_version = htonl(hdr_version);
        hdr.hdr_entries = htonl(entries - removed);
  
 -      git_SHA1_Init(&c);
 +      the_hash_algo->init_fn(&c);
        if (ce_write(&c, newfd, &hdr, sizeof(hdr)) < 0)
                return -1;
  
        previous_name = (hdr_version == 4) ? &previous_name_buf : NULL;
 +
        for (i = 0; i < entries; i++) {
                struct cache_entry *ce = cache[i];
                if (ce->ce_flags & CE_REMOVE)
                        if (allow)
                                warning(msg, ce->name);
                        else
 -                              return error(msg, ce->name);
 +                              err = error(msg, ce->name);
 +
 +                      drop_cache_tree = 1;
                }
 -              if (ce_write_entry(&c, newfd, ce, previous_name) < 0)
 -                      return -1;
 +              if (ce_write_entry(&c, newfd, ce, previous_name, (struct ondisk_cache_entry *)&ondisk) < 0)
 +                      err = -1;
 +
 +              if (err)
 +                      break;
        }
        strbuf_release(&previous_name_buf);
  
 +      if (err)
 +              return err;
 +
        /* Write extension data here */
        if (!strip_extensions && istate->split_index) {
                struct strbuf sb = STRBUF_INIT;
                if (err)
                        return -1;
        }
 -      if (!strip_extensions && istate->cache_tree) {
 +      if (!strip_extensions && !drop_cache_tree && istate->cache_tree) {
                struct strbuf sb = STRBUF_INIT;
  
                cache_tree_write(&sb, istate->cache_tree);
                if (err)
                        return -1;
        }
 +      if (!strip_extensions && istate->fsmonitor_last_update) {
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              write_fsmonitor_extension(&sb, istate);
 +              err = write_index_ext_header(&c, newfd, CACHE_EXT_FSMONITOR, sb.len) < 0
 +                      || ce_write(&c, newfd, sb.buf, sb.len) < 0;
 +              strbuf_release(&sb);
 +              if (err)
 +                      return -1;
 +      }
  
        if (ce_flush(&c, newfd, istate->sha1))
                return -1;
 -      if (close_tempfile(tempfile))
 -              return error(_("could not close '%s'"), tempfile->filename.buf);
 +      if (close_tempfile_gently(tempfile)) {
 +              error(_("could not close '%s'"), tempfile->filename.buf);
 +              return -1;
 +      }
        if (stat(tempfile->filename.buf, &st))
                return -1;
        istate->timestamp.sec = (unsigned int)st.st_mtime;
        istate->timestamp.nsec = ST_MTIME_NSEC(st);
 +      trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
        return 0;
  }
  
@@@ -2403,12 -2351,17 +2428,12 @@@ static int commit_locked_index(struct l
  static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
                                 unsigned flags)
  {
 -      int ret = do_write_index(istate, &lock->tempfile, 0);
 +      int ret = do_write_index(istate, lock->tempfile, 0);
        if (ret)
                return ret;
 -      assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
 -             (COMMIT_LOCK | CLOSE_LOCK));
        if (flags & COMMIT_LOCK)
                return commit_locked_index(lock);
 -      else if (flags & CLOSE_LOCK)
 -              return close_lock_file(lock);
 -      else
 -              return ret;
 +      return close_lock_file_gently(lock);
  }
  
  static int write_split_index(struct index_state *istate,
@@@ -2481,22 -2434,34 +2506,22 @@@ static int clean_shared_index_files(con
        return 0;
  }
  
 -static struct tempfile temporary_sharedindex;
 -
  static int write_shared_index(struct index_state *istate,
 -                            struct lock_file *lock, unsigned flags)
 +                            struct tempfile **temp)
  {
        struct split_index *si = istate->split_index;
 -      int fd, ret;
 +      int ret;
  
 -      fd = mks_tempfile(&temporary_sharedindex, git_path("sharedindex_XXXXXX"));
 -      if (fd < 0) {
 -              hashclr(si->base_sha1);
 -              return do_write_locked_index(istate, lock, flags);
 -      }
        move_cache_to_base_index(istate);
 -      ret = do_write_index(si->base, &temporary_sharedindex, 1);
 -      if (ret) {
 -              delete_tempfile(&temporary_sharedindex);
 +      ret = do_write_index(si->base, *temp, 1);
 +      if (ret)
                return ret;
 -      }
 -      ret = adjust_shared_perm(get_tempfile_path(&temporary_sharedindex));
 +      ret = adjust_shared_perm(get_tempfile_path(*temp));
        if (ret) {
 -              int save_errno = errno;
 -              error("cannot fix permission bits on %s", get_tempfile_path(&temporary_sharedindex));
 -              delete_tempfile(&temporary_sharedindex);
 -              errno = save_errno;
 +              error("cannot fix permission bits on %s", get_tempfile_path(*temp));
                return ret;
        }
 -      ret = rename_tempfile(&temporary_sharedindex,
 +      ret = rename_tempfile(temp,
                              git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret) {
                hashcpy(si->base_sha1, si->base->sha1);
@@@ -2542,21 -2507,11 +2567,21 @@@ int write_locked_index(struct index_sta
        int new_shared_index, ret;
        struct split_index *si = istate->split_index;
  
 +      if ((flags & SKIP_IF_UNCHANGED) && !istate->cache_changed) {
 +              if (flags & COMMIT_LOCK)
 +                      rollback_lock_file(lock);
 +              return 0;
 +      }
 +
 +      if (istate->fsmonitor_last_update)
 +              fill_fsmonitor_bitmap(istate);
 +
        if (!si || alternate_index_output ||
            (istate->cache_changed & ~EXTMASK)) {
                if (si)
                        hashclr(si->base_sha1);
 -              return do_write_locked_index(istate, lock, flags);
 +              ret = do_write_locked_index(istate, lock, flags);
 +              goto out;
        }
  
        if (getenv("GIT_TEST_SPLIT_INDEX")) {
        new_shared_index = istate->cache_changed & SPLIT_INDEX_ORDERED;
  
        if (new_shared_index) {
 -              ret = write_shared_index(istate, lock, flags);
 +              struct tempfile *temp;
 +              int saved_errno;
 +
 +              temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
 +              if (!temp) {
 +                      hashclr(si->base_sha1);
 +                      ret = do_write_locked_index(istate, lock, flags);
 +                      goto out;
 +              }
 +              ret = write_shared_index(istate, &temp);
 +
 +              saved_errno = errno;
 +              if (is_tempfile_active(temp))
 +                      delete_tempfile(&temp);
 +              errno = saved_errno;
 +
                if (ret)
 -                      return ret;
 +                      goto out;
        }
  
        ret = write_split_index(istate, lock, flags);
  
        /* Freshen the shared index only if the split-index was written */
 -      if (!ret && !new_shared_index)
 -              freshen_shared_index(sha1_to_hex(si->base_sha1), 1);
 +      if (!ret && !new_shared_index) {
 +              const char *shared_index = git_path("sharedindex.%s",
 +                                                  sha1_to_hex(si->base_sha1));
 +              freshen_shared_index(shared_index, 1);
 +      }
  
 +out:
 +      if (flags & COMMIT_LOCK)
 +              rollback_lock_file(lock);
        return ret;
  }
  
@@@ -2705,7 -2639,8 +2730,7 @@@ void *read_blob_data_from_index(const s
  
  void stat_validity_clear(struct stat_validity *sv)
  {
 -      free(sv->sd);
 -      sv->sd = NULL;
 +      FREE_AND_NULL(sv->sd);
  }
  
  int stat_validity_check(struct stat_validity *sv, const char *path)
@@@ -2731,9 -2666,3 +2756,9 @@@ void stat_validity_update(struct stat_v
                fill_stat_data(sv->sd, &st);
        }
  }
 +
 +void move_index_extensions(struct index_state *dst, struct index_state *src)
 +{
 +      dst->untracked = src->untracked;
 +      src->untracked = NULL;
 +}
diff --combined submodule-config.c
index 602ba8ca8b8455df9b34e2990397c838d542569f,de54351c6f26bc7db4a3f4c6fa8304da6bc9d0c7..e5f4901212db4a3d46f0265e463ca2eb790266e3
@@@ -1,15 -1,12 +1,15 @@@
  #include "cache.h"
 +#include "repository.h"
 +#include "config.h"
  #include "submodule-config.h"
  #include "submodule.h"
  #include "strbuf.h"
 +#include "parse-options.h"
  
  /*
   * submodule cache lookup structure
   * There is one shared set of 'struct submodule' entries which can be
 - * looked up by their sha1 blob id of the .gitmodule file and either
 + * looked up by their sha1 blob id of the .gitmodules file and either
   * using path or name as key.
   * for_path stores submodule entries with path as key
   * for_name stores submodule entries with name as key
@@@ -17,8 -14,6 +17,8 @@@
  struct submodule_cache {
        struct hashmap for_path;
        struct hashmap for_name;
 +      unsigned initialized:1;
 +      unsigned gitmodules_read:1;
  };
  
  /*
@@@ -35,40 -30,29 +35,40 @@@ enum lookup_type 
        lookup_path
  };
  
 -static struct submodule_cache the_submodule_cache;
 -static int is_cache_init;
 -
 -static int config_path_cmp(const struct submodule_entry *a,
 -                         const struct submodule_entry *b,
 -                         const void *unused)
 +static int config_path_cmp(const void *unused_cmp_data,
 +                         const void *entry,
 +                         const void *entry_or_key,
 +                         const void *unused_keydata)
  {
 +      const struct submodule_entry *a = entry;
 +      const struct submodule_entry *b = entry_or_key;
 +
        return strcmp(a->config->path, b->config->path) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
  }
  
 -static int config_name_cmp(const struct submodule_entry *a,
 -                         const struct submodule_entry *b,
 -                         const void *unused)
 +static int config_name_cmp(const void *unused_cmp_data,
 +                         const void *entry,
 +                         const void *entry_or_key,
 +                         const void *unused_keydata)
  {
 +      const struct submodule_entry *a = entry;
 +      const struct submodule_entry *b = entry_or_key;
 +
        return strcmp(a->config->name, b->config->name) ||
               hashcmp(a->config->gitmodules_sha1, b->config->gitmodules_sha1);
  }
  
 -static void cache_init(struct submodule_cache *cache)
 +static struct submodule_cache *submodule_cache_alloc(void)
  {
 -      hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, 0);
 -      hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, 0);
 +      return xcalloc(1, sizeof(struct submodule_cache));
 +}
 +
 +static void submodule_cache_init(struct submodule_cache *cache)
 +{
 +      hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
 +      hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
 +      cache->initialized = 1;
  }
  
  static void free_one_config(struct submodule_entry *entry)
        free(entry->config);
  }
  
 -static void cache_free(struct submodule_cache *cache)
 +static void submodule_cache_clear(struct submodule_cache *cache)
  {
        struct hashmap_iter iter;
        struct submodule_entry *entry;
  
 +      if (!cache->initialized)
 +              return;
 +
        /*
         * We iterate over the name hash here to be symmetric with the
         * allocation of struct submodule entries. Each is allocated by
 -       * their .gitmodule blob sha1 and submodule name.
 +       * their .gitmodules blob sha1 and submodule name.
         */
        hashmap_iter_init(&cache->for_name, &iter);
        while ((entry = hashmap_iter_next(&iter)))
  
        hashmap_free(&cache->for_path, 1);
        hashmap_free(&cache->for_name, 1);
 +      cache->initialized = 0;
 +      cache->gitmodules_read = 0;
 +}
 +
 +void submodule_cache_free(struct submodule_cache *cache)
 +{
 +      submodule_cache_clear(cache);
 +      free(cache);
  }
  
  static unsigned int hash_sha1_string(const unsigned char *sha1,
@@@ -190,6 -163,31 +190,31 @@@ static struct submodule *cache_lookup_n
        return NULL;
  }
  
+ int check_submodule_name(const char *name)
+ {
+       /* Disallow empty names */
+       if (!*name)
+               return -1;
+       /*
+        * Look for '..' as a path component. Check both '/' and '\\' as
+        * separators rather than is_dir_sep(), because we want the name rules
+        * to be consistent across platforms.
+        */
+       goto in_component; /* always start inside component */
+       while (*name) {
+               char c = *name++;
+               if (c == '/' || c == '\\') {
+ in_component:
+                       if (name[0] == '.' && name[1] == '.' &&
+                           (!name[2] || name[2] == '/' || name[2] == '\\'))
+                               return -1;
+               }
+       }
+       return 0;
+ }
  static int name_and_item_from_var(const char *var, struct strbuf *name,
                                  struct strbuf *item)
  {
                return 0;
  
        strbuf_add(name, subsection, subsection_len);
+       if (check_submodule_name(name->buf) < 0) {
+               warning(_("ignoring suspicious submodule name: %s"), name->buf);
+               strbuf_release(name);
+               return 0;
+       }
        strbuf_addstr(item, key);
  
        return 1;
@@@ -240,7 -244,7 +271,7 @@@ static struct submodule *lookup_or_crea
  static int parse_fetch_recurse(const char *opt, const char *arg,
                               int die_on_error)
  {
 -      switch (git_config_maybe_bool(opt, arg)) {
 +      switch (git_parse_maybe_bool(arg)) {
        case 1:
                return RECURSE_SUBMODULES_ON;
        case 0:
        }
  }
  
 +int parse_submodule_fetchjobs(const char *var, const char *value)
 +{
 +      int fetchjobs = git_config_int(var, value);
 +      if (fetchjobs < 0)
 +              die(_("negative values not allowed for submodule.fetchjobs"));
 +      return fetchjobs;
 +}
 +
  int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
  {
        return parse_fetch_recurse(opt, arg, 1);
  }
  
 +int option_fetch_parse_recurse_submodules(const struct option *opt,
 +                                        const char *arg, int unset)
 +{
 +      int *v;
 +
 +      if (!opt->value)
 +              return -1;
 +
 +      v = opt->value;
 +
 +      if (unset) {
 +              *v = RECURSE_SUBMODULES_OFF;
 +      } else {
 +              if (arg)
 +                      *v = parse_fetch_recurse_submodules_arg(opt->long_name, arg);
 +              else
 +                      *v = RECURSE_SUBMODULES_ON;
 +      }
 +      return 0;
 +}
 +
  static int parse_update_recurse(const char *opt, const char *arg,
                                int die_on_error)
  {
 -      switch (git_config_maybe_bool(opt, arg)) {
 +      switch (git_parse_maybe_bool(arg)) {
        case 1:
                return RECURSE_SUBMODULES_ON;
        case 0:
@@@ -313,7 -288,7 +344,7 @@@ int parse_update_recurse_submodules_arg
  static int parse_push_recurse(const char *opt, const char *arg,
                               int die_on_error)
  {
 -      switch (git_config_maybe_bool(opt, arg)) {
 +      switch (git_parse_maybe_bool(arg)) {
        case 1:
                /* There's no simple "on" value when pushing */
                if (die_on_error)
@@@ -457,19 -432,19 +488,19 @@@ static int parse_config(const char *var
        return ret;
  }
  
 -int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
 -                                    unsigned char *gitmodules_sha1,
 -                                    struct strbuf *rev)
 +static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
 +                                   struct object_id *gitmodules_oid,
 +                                   struct strbuf *rev)
  {
        int ret = 0;
  
 -      if (is_null_sha1(treeish_name)) {
 -              hashclr(gitmodules_sha1);
 +      if (is_null_oid(treeish_name)) {
 +              oidclr(gitmodules_oid);
                return 1;
        }
  
 -      strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
 -      if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
 +      strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
 +      if (get_oid(rev->buf, gitmodules_oid) >= 0)
                ret = 1;
  
        return ret;
   * revisions.
   */
  static const struct submodule *config_from(struct submodule_cache *cache,
 -              const unsigned char *treeish_name, const char *key,
 +              const struct object_id *treeish_name, const char *key,
                enum lookup_type lookup_type)
  {
        struct strbuf rev = STRBUF_INIT;
        unsigned long config_size;
        char *config = NULL;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        enum object_type type;
        const struct submodule *submodule = NULL;
        struct parse_config_parameter parameter;
                return entry->config;
        }
  
 -      if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
 +      if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
                goto out;
  
        switch (lookup_type) {
        case lookup_name:
 -              submodule = cache_lookup_name(cache, sha1, key);
 +              submodule = cache_lookup_name(cache, oid.hash, key);
                break;
        case lookup_path:
 -              submodule = cache_lookup_path(cache, sha1, key);
 +              submodule = cache_lookup_path(cache, oid.hash, key);
                break;
        }
        if (submodule)
                goto out;
  
 -      config = read_sha1_file(sha1, &type, &config_size);
 +      config = read_sha1_file(oid.hash, &type, &config_size);
        if (!config || type != OBJ_BLOB)
                goto out;
  
        /* fill the submodule config into the cache */
        parameter.cache = cache;
 -      parameter.treeish_name = treeish_name;
 -      parameter.gitmodules_sha1 = sha1;
 +      parameter.treeish_name = treeish_name->hash;
 +      parameter.gitmodules_sha1 = oid.hash;
        parameter.overwrite = 0;
        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
                        config, config_size, &parameter);
  
        switch (lookup_type) {
        case lookup_name:
 -              return cache_lookup_name(cache, sha1, key);
 +              return cache_lookup_name(cache, oid.hash, key);
        case lookup_path:
 -              return cache_lookup_path(cache, sha1, key);
 +              return cache_lookup_path(cache, oid.hash, key);
        default:
                return NULL;
        }
        return submodule;
  }
  
 -static void ensure_cache_init(void)
 +static void submodule_cache_check_init(struct repository *repo)
  {
 -      if (is_cache_init)
 +      if (repo->submodule_cache && repo->submodule_cache->initialized)
                return;
  
 -      cache_init(&the_submodule_cache);
 -      is_cache_init = 1;
 +      if (!repo->submodule_cache)
 +              repo->submodule_cache = submodule_cache_alloc();
 +
 +      submodule_cache_init(repo->submodule_cache);
  }
  
 -int parse_submodule_config_option(const char *var, const char *value)
 +static int gitmodules_cb(const char *var, const char *value, void *data)
  {
 +      struct repository *repo = data;
        struct parse_config_parameter parameter;
 -      parameter.cache = &the_submodule_cache;
 +
 +      parameter.cache = repo->submodule_cache;
        parameter.treeish_name = NULL;
        parameter.gitmodules_sha1 = null_sha1;
        parameter.overwrite = 1;
  
 -      ensure_cache_init();
        return parse_config(var, value, &parameter);
  }
  
 -const struct submodule *submodule_from_name(const unsigned char *treeish_name,
 +void repo_read_gitmodules(struct repository *repo)
 +{
 +      submodule_cache_check_init(repo);
 +
 +      if (repo->worktree) {
 +              char *gitmodules;
 +
 +              if (repo_read_index(repo) < 0)
 +                      return;
 +
 +              gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
 +
 +              if (!is_gitmodules_unmerged(repo->index))
 +                      git_config_from_file(gitmodules_cb, gitmodules, repo);
 +
 +              free(gitmodules);
 +      }
 +
 +      repo->submodule_cache->gitmodules_read = 1;
 +}
 +
 +void gitmodules_config_oid(const struct object_id *commit_oid)
 +{
 +      struct strbuf rev = STRBUF_INIT;
 +      struct object_id oid;
 +
 +      submodule_cache_check_init(the_repository);
 +
 +      if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
 +              git_config_from_blob_oid(gitmodules_cb, rev.buf,
 +                                       &oid, the_repository);
 +      }
 +      strbuf_release(&rev);
 +
 +      the_repository->submodule_cache->gitmodules_read = 1;
 +}
 +
 +static void gitmodules_read_check(struct repository *repo)
 +{
 +      submodule_cache_check_init(repo);
 +
 +      /* read the repo's .gitmodules file if it hasn't been already */
 +      if (!repo->submodule_cache->gitmodules_read)
 +              repo_read_gitmodules(repo);
 +}
 +
 +const struct submodule *submodule_from_name(const struct object_id *treeish_name,
                const char *name)
  {
 -      ensure_cache_init();
 -      return config_from(&the_submodule_cache, treeish_name, name, lookup_name);
 +      gitmodules_read_check(the_repository);
 +      return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
  }
  
 -const struct submodule *submodule_from_path(const unsigned char *treeish_name,
 +const struct submodule *submodule_from_path(const struct object_id *treeish_name,
                const char *path)
  {
 -      ensure_cache_init();
 -      return config_from(&the_submodule_cache, treeish_name, path, lookup_path);
 +      gitmodules_read_check(the_repository);
 +      return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);
 +}
 +
 +const struct submodule *submodule_from_cache(struct repository *repo,
 +                                           const struct object_id *treeish_name,
 +                                           const char *key)
 +{
 +      gitmodules_read_check(repo);
 +      return config_from(repo->submodule_cache, treeish_name,
 +                         key, lookup_path);
  }
  
  void submodule_free(void)
  {
 -      cache_free(&the_submodule_cache);
 -      is_cache_init = 0;
 +      if (the_repository->submodule_cache)
 +              submodule_cache_clear(the_repository->submodule_cache);
  }
diff --combined submodule-config.h
index a5503a5d177e90e009be9240bfddd68c9ead475b,103cc79dd8aa4e0052b1efe9a9a83db48143d4dc..17e297022396d2b2b837187d6deaf8a42d45a0d6
@@@ -22,30 -22,24 +22,37 @@@ struct submodule 
        int recommend_shallow;
  };
  
 +#define SUBMODULE_INIT { NULL, NULL, NULL, RECURSE_SUBMODULES_NONE, \
 +      NULL, NULL, SUBMODULE_UPDATE_STRATEGY_INIT, {0}, -1 };
 +
 +struct submodule_cache;
 +struct repository;
 +
 +extern void submodule_cache_free(struct submodule_cache *cache);
 +
 +extern int parse_submodule_fetchjobs(const char *var, const char *value);
  extern int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg);
 +struct option;
 +extern int option_fetch_parse_recurse_submodules(const struct option *opt,
 +                                               const char *arg, int unset);
  extern int parse_update_recurse_submodules_arg(const char *opt, const char *arg);
  extern int parse_push_recurse_submodules_arg(const char *opt, const char *arg);
 -extern int parse_submodule_config_option(const char *var, const char *value);
 +extern void repo_read_gitmodules(struct repository *repo);
 +extern void gitmodules_config_oid(const struct object_id *commit_oid);
  extern const struct submodule *submodule_from_name(
 -              const unsigned char *commit_or_tree, const char *name);
 +              const struct object_id *commit_or_tree, const char *name);
  extern const struct submodule *submodule_from_path(
 -              const unsigned char *commit_or_tree, const char *path);
 -extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
 -                                    unsigned char *gitmodules_sha1,
 -                                    struct strbuf *rev);
 +              const struct object_id *commit_or_tree, const char *path);
 +extern const struct submodule *submodule_from_cache(struct repository *repo,
 +                                                  const struct object_id *treeish_name,
 +                                                  const char *key);
  extern void submodule_free(void);
  
+ /*
+  * Returns 0 if the name is syntactically acceptable as a submodule "name"
+  * (e.g., that may be found in the subsection of a .gitmodules file) and -1
+  * otherwise.
+  */
+ int check_submodule_name(const char *name);
  #endif /* SUBMODULE_CONFIG_H */
index 2b3c5092a199835ea2e84339b473a9e29778178d,77517a43edf6cd1549a0267352a27b226e1ea6a5..94846550f74a843f979de14116ab2df5dd15f6e3
@@@ -1,5 -1,6 +1,6 @@@
  #include "cache.h"
  #include "string-list.h"
+ #include "utf8.h"
  
  /*
   * A "string_list_each_func_t" function that normalizes an entry from
@@@ -38,20 -39,6 +39,20 @@@ struct test_data 
        const char *alternative; /* output: ... or this.      */
  };
  
 +/*
 + * Compatibility wrappers for OpenBSD, whose basename(3) and dirname(3)
 + * have const parameters.
 + */
 +static char *posix_basename(char *path)
 +{
 +      return basename(path);
 +}
 +
 +static char *posix_dirname(char *path)
 +{
 +      return dirname(path);
 +}
 +
  static int test_function(struct test_data *data, char *(*func)(char *input),
        const char *funcname)
  {
@@@ -170,6 -157,11 +171,11 @@@ static struct test_data dirname_data[] 
        { NULL,              NULL     }
  };
  
+ static int is_dotgitmodules(const char *path)
+ {
+       return is_hfs_dotgitmodules(path) || is_ntfs_dotgitmodules(path);
+ }
  int cmd_main(int argc, const char **argv)
  {
        if (argc == 3 && !strcmp(argv[1], "normalize_path_copy")) {
        }
  
        if (argc == 2 && !strcmp(argv[1], "basename"))
 -              return test_function(basename_data, basename, argv[1]);
 +              return test_function(basename_data, posix_basename, argv[1]);
  
        if (argc == 2 && !strcmp(argv[1], "dirname"))
 -              return test_function(dirname_data, dirname, argv[1]);
 +              return test_function(dirname_data, posix_dirname, argv[1]);
  
+       if (argc > 2 && !strcmp(argv[1], "is_dotgitmodules")) {
+               int res = 0, expect = 1, i;
+               for (i = 2; i < argc; i++)
+                       if (!strcmp("--not", argv[i]))
+                               expect = !expect;
+                       else if (expect != is_dotgitmodules(argv[i]))
+                               res = error("'%s' is %s.gitmodules", argv[i],
+                                           expect ? "not " : "");
+                       else
+                               fprintf(stderr, "ok: '%s' is %s.gitmodules\n",
+                                       argv[i], expect ? "" : "not ");
+               return !!res;
+       }
        fprintf(stderr, "%s: unknown function name: %s\n", argv[0],
                argv[1] ? argv[1] : "(there was none)");
        return 1;
diff --combined utf8.c
index 2c27ce0137f8a60ca2fadf855f2c67738931e2f8,cbf22a71d74beccc3912526e9bb61ca296e07759..f04c24409b4e95d69ccd08473ef4c43d408d6d86
--- 1/utf8.c
--- 2/utf8.c
+++ b/utf8.c
@@@ -32,7 -32,7 +32,7 @@@ static int bisearch(ucs_char_t ucs, con
        if (ucs < table[0].first || ucs > table[max].last)
                return 0;
        while (max >= min) {
 -              mid = (min + max) / 2;
 +              mid = min + (max - min) / 2;
                if (ucs > table[mid].last)
                        min = mid + 1;
                else if (ucs < table[mid].first)
@@@ -381,7 -381,7 +381,7 @@@ void strbuf_utf8_replace(struct strbuf 
                old = src;
                n = utf8_width((const char**)&src, NULL);
                if (!src)       /* broken utf-8, do nothing */
 -                      return;
 +                      goto out;
                if (n && w >= pos && w < pos + width) {
                        if (subst) {
                                memcpy(dst, subst, subst_len);
        }
        strbuf_setlen(&sb_dst, dst - sb_dst.buf);
        strbuf_swap(sb_src, &sb_dst);
 +out:
        strbuf_release(&sb_dst);
  }
  
@@@ -620,28 -619,33 +620,33 @@@ static ucs_char_t next_hfs_char(const c
        }
  }
  
- int is_hfs_dotgit(const char *path)
+ static int is_hfs_dot_generic(const char *path,
+                             const char *needle, size_t needle_len)
  {
        ucs_char_t c;
  
        c = next_hfs_char(&path);
        if (c != '.')
                return 0;
-       c = next_hfs_char(&path);
  
        /*
         * there's a great deal of other case-folding that occurs
-        * in HFS+, but this is enough to catch anything that will
-        * convert to ".git"
+        * in HFS+, but this is enough to catch our fairly vanilla
+        * hard-coded needles.
         */
-       if (c != 'g' && c != 'G')
-               return 0;
-       c = next_hfs_char(&path);
-       if (c != 'i' && c != 'I')
-               return 0;
-       c = next_hfs_char(&path);
-       if (c != 't' && c != 'T')
-               return 0;
+       for (; needle_len > 0; needle++, needle_len--) {
+               c = next_hfs_char(&path);
+               /*
+                * We know our needles contain only ASCII, so we clamp here to
+                * make the results of tolower() sane.
+                */
+               if (c > 127)
+                       return 0;
+               if (tolower(c) != *needle)
+                       return 0;
+       }
        c = next_hfs_char(&path);
        if (c && !is_dir_sep(c))
                return 0;
        return 1;
  }
  
+ /*
+  * Inline wrapper to make sure the compiler resolves strlen() on literals at
+  * compile time.
+  */
+ static inline int is_hfs_dot_str(const char *path, const char *needle)
+ {
+       return is_hfs_dot_generic(path, needle, strlen(needle));
+ }
+ int is_hfs_dotgit(const char *path)
+ {
+       return is_hfs_dot_str(path, "git");
+ }
+ int is_hfs_dotgitmodules(const char *path)
+ {
+       return is_hfs_dot_str(path, "gitmodules");
+ }
+ int is_hfs_dotgitignore(const char *path)
+ {
+       return is_hfs_dot_str(path, "gitignore");
+ }
+ int is_hfs_dotgitattributes(const char *path)
+ {
+       return is_hfs_dot_str(path, "gitattributes");
+ }
  const char utf8_bom[] = "\357\273\277";
  
  int skip_utf8_bom(char **text, size_t len)