Sync with Git 2.15.2
authorJunio C Hamano <gitster@pobox.com>
Tue, 22 May 2018 05:18:06 +0000 (14:18 +0900)
committerJunio C Hamano <gitster@pobox.com>
Tue, 22 May 2018 05:18:06 +0000 (14:18 +0900)
* maint-2.15:
  Git 2.15.2
  Git 2.14.4
  Git 2.13.7
  verify_path: disallow symlinks in .gitmodules
  update-index: stat updated files earlier
  verify_dotfile: mention case-insensitivity in comment
  verify_path: drop clever fallthrough
  skip_prefix: add case-insensitive variant
  is_{hfs,ntfs}_dotgitmodules: add tests
  is_ntfs_dotgit: match other .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

1  2 
apply.c
builtin/submodule--helper.c
builtin/update-index.c
cache.h
git-compat-util.h
git-submodule.sh
read-cache.c
submodule-config.c
submodule-config.h

diff --combined apply.c
+++ b/apply.c
@@@ -75,10 -75,13 +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->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();
@@@ -3860,9 -3865,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;
  }
@@@ -4687,13 -4692,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 -4894,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);
  #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)
 +
 +typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 +                                void *cb_data);
  
  static char *get_default_remote(void)
  {
@@@ -229,64 -219,6 +229,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;
@@@ -396,29 -328,21 +396,29 @@@ static int module_list(int argc, const 
        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;
  
 -      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_oid, path);
  
         * Set active flag for the submodule being initialized
         */
        if (!is_submodule_active(the_repository, path)) {
 -              strbuf_reset(&sb);
                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;
  }
@@@ -1382,7 -1144,7 +1382,7 @@@ static int push_check(int argc, const c
        argv++;
        argc--;
        /* Get the submodule's head ref and determine if it is detached */
 -      head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
 +      head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
        if (!strcmp(head, "HEAD"))
@@@ -1480,6 -1242,29 +1480,29 @@@ static int is_active(int argc, const ch
        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 {
@@@ -1497,11 -1282,11 +1520,12 @@@ 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},
        {"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)
diff --combined builtin/update-index.c
@@@ -16,7 -16,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 -32,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 -228,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
@@@ -331,7 -328,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 -445,17 +448,17 @@@ 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)
+               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 -546,7 +554,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 -688,9 +696,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 -730,7 +738,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,8 -926,6 +934,8 @@@ int cmd_update_index(int argc, const ch
        struct refresh_params refresh_args = {0, &has_errors};
        int lock_error = 0;
        int split_index = -1;
 +      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;
                            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()
        };
  
                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);
diff --combined cache.h
+++ b/cache.h
@@@ -14,7 -14,6 +14,7 @@@
  #include "hash.h"
  #include "path.h"
  #include "sha1-array.h"
 +#include "repository.h"
  
  #ifndef platform_SHA_CTX
  /*
@@@ -78,8 -77,6 +78,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
@@@ -207,7 -204,6 +207,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)
  
@@@ -331,7 -327,6 +331,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;
@@@ -345,14 -340,11 +345,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;
@@@ -372,7 -364,7 +372,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)
@@@ -454,16 -446,6 +454,16 @@@ static inline enum object_type object_t
  #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
   * whether we should or should not treat:
@@@ -617,45 -599,16 +617,45 @@@ 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)
 +
 +/*
 + * 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.
 + */
  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);
@@@ -728,14 -681,11 +728,14 @@@ 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
 +#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);
  
@@@ -766,17 -716,12 +766,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;
@@@ -830,7 -775,6 +830,7 @@@ extern int core_apply_sparse_checkout
  extern int precomposed_unicode;
  extern int protect_hfs;
  extern int protect_ntfs;
 +extern const char *core_fsmonitor;
  
  /*
   * Include broken refs in all ref iterations, which will
@@@ -921,7 -865,6 +921,7 @@@ struct repository_format 
        int version;
        int precious_objects;
        int is_bare;
 +      int hash_algo;
        char *work_tree;
        struct string_list unknown_extensions;
  };
@@@ -1054,22 -997,22 +1054,22 @@@ extern const struct object_id empty_blo
  
  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) */
@@@ -1187,7 -1130,15 +1187,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
@@@ -1374,13 -1325,6 +1382,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
@@@ -1502,7 -1446,6 +1510,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);
  
@@@ -1984,10 -1927,4 +1992,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 git-compat-util.h
@@@ -484,29 -484,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".
@@@ -1001,6 -978,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;
diff --combined git-submodule.sh
@@@ -229,6 -229,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
@@@ -758,6 -763,18 +763,6 @@@ cmd_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
  #
@@@ -1004,7 -1021,54 +1009,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
diff --combined read-cache.c
@@@ -19,7 -19,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;
@@@ -64,7 -62,6 +64,7 @@@ static void replace_index_entry(struct 
        free(old);
        set_index_entry(istate, nr, ce);
        ce->ce_flags |= CE_UPDATE_IN_BASE;
 +      mark_fsmonitor_invalid(istate, ce);
        istate->cache_changed |= CE_ENTRY_CHANGED;
  }
  
@@@ -153,10 -150,8 +153,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)
@@@ -196,7 -191,7 +196,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)
@@@ -306,7 -301,7 +306,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)
  {
@@@ -641,17 -631,13 +641,17 @@@ int add_to_index(struct index_state *is
  {
        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, path, st, HASH_WRITE_OBJECT)) {
 +              if (index_path(&ce->oid, path, st, newflags)) {
                        free(ce);
                        return error("unable to index file %s", path);
                }
@@@ -751,7 -733,7 +751,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;
        }
@@@ -796,7 -778,6 +796,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;
@@@ -816,7 -797,7 +816,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;
                }
@@@ -1183,7 -1189,7 +1208,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 &&
@@@ -1248,13 -1254,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;
                }
        }
@@@ -1420,7 -1417,6 +1445,7 @@@ int refresh_index(struct index_state *i
                                 */
                                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)
@@@ -1540,9 -1536,6 +1565,9 @@@ struct ondisk_cache_entry_extended 
  /* 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;
@@@ -1583,9 -1576,6 +1608,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",
@@@ -1603,7 -1593,7 +1628,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,
@@@ -1703,9 -1693,6 +1728,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];
@@@ -1761,7 -1748,6 +1786,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! */
@@@ -1863,19 -1849,20 +1888,19 @@@ 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)
  {
        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)
                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);
 +      free(base_path);
        return ret;
  }
  
@@@ -2215,22 -2201,17 +2240,22 @@@ 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)
  {
        struct stat st;
        struct ondisk_cache_entry_extended ondisk;
        struct strbuf previous_name_buf = STRBUF_INIT, *previous_name;
 -      int drop_cache_tree = 0;
 +      int drop_cache_tree = istate->drop_cache_tree;
  
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
                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_gently(tempfile)) {
                error(_("could not close '%s'"), tempfile->filename.buf);
 -              delete_tempfile(&tempfile);
                return -1;
        }
        if (stat(tempfile->filename.buf, &st))
@@@ -2396,9 -2368,14 +2421,9 @@@ static int do_write_locked_index(struc
        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_gently(lock);
 -      else
 -              return ret;
 +      return close_lock_file_gently(lock);
  }
  
  static int write_split_index(struct index_state *istate,
@@@ -2472,21 -2449,32 +2497,21 @@@ static int clean_shared_index_files(con
  }
  
  static int write_shared_index(struct index_state *istate,
 -                            struct lock_file *lock, unsigned flags)
 +                            struct tempfile **temp)
  {
 -      struct tempfile *temp;
        struct split_index *si = istate->split_index;
        int ret;
  
 -      temp = mks_tempfile(git_path("sharedindex_XXXXXX"));
 -      if (!temp) {
 -              hashclr(si->base_sha1);
 -              return do_write_locked_index(istate, lock, flags);
 -      }
        move_cache_to_base_index(istate);
 -      ret = do_write_index(si->base, temp, 1);
 -      if (ret) {
 -              delete_tempfile(&temp);
 +      ret = do_write_index(si->base, *temp, 1);
 +      if (ret)
                return ret;
 -      }
 -      ret = adjust_shared_perm(get_tempfile_path(temp));
 +      ret = adjust_shared_perm(get_tempfile_path(*temp));
        if (ret) {
 -              int save_errno = errno;
 -              error("cannot fix permission bits on %s", get_tempfile_path(temp));
 -              delete_tempfile(&temp);
 -              errno = save_errno;
 +              error("cannot fix permission bits on %s", get_tempfile_path(*temp));
                return ret;
        }
 -      ret = rename_tempfile(&temp,
 +      ret = rename_tempfile(temp,
                              git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
        if (!ret) {
                hashcpy(si->base_sha1, si->base->sha1);
@@@ -2532,15 -2520,11 +2557,15 @@@ int write_locked_index(struct index_sta
        int new_shared_index, ret;
        struct split_index *si = istate->split_index;
  
 +      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;
  }
  
diff --combined submodule-config.c
@@@ -9,7 -9,7 +9,7 @@@
  /*
   * 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
@@@ -91,7 -91,7 +91,7 @@@ static void submodule_cache_clear(struc
        /*
         * 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)))
@@@ -190,6 -190,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;
diff --combined submodule-config.h
@@@ -22,9 -22,6 +22,9 @@@ 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;
  
@@@ -48,4 -45,11 +48,11 @@@ extern const struct submodule *submodul
                                                    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 */