Merge branch 'bw/grep-recurse-submodules'
authorJunio C Hamano <gitster@pobox.com>
Tue, 22 Aug 2017 17:29:01 +0000 (10:29 -0700)
committerJunio C Hamano <gitster@pobox.com>
Tue, 22 Aug 2017 17:29:01 +0000 (10:29 -0700)
"git grep --recurse-submodules" has been reworked to give a more
consistent output across submodule boundary (and do its thing
without having to fork a separate process).

* bw/grep-recurse-submodules:
grep: recurse in-process using 'struct repository'
submodule: merge repo_read_gitmodules and gitmodules_config
submodule: check for unmerged .gitmodules outside of config parsing
submodule: check for unstaged .gitmodules outside of config parsing
submodule: remove fetch.recursesubmodules from submodule-config parsing
submodule: remove submodule.fetchjobs from submodule-config parsing
config: add config_from_gitmodules
cache.h: add GITMODULES_FILE macro
repository: have the_repository use the_index
repo_read_index: don't discard the index

12 files changed:
1  2 
builtin/grep.c
builtin/submodule--helper.c
cache.h
config.c
config.h
git.c
repository.c
submodule-config.c
submodule-config.h
submodule.c
submodule.h
unpack-trees.c
diff --combined builtin/grep.c
index 3cbee04dc4164255148b7f4b0c6f8f6dcd86a8fe,cd0e51f3c04b1e6fc297a8806fa663d86ebc7734..a70d8e2fba9f4e371a069bd801d20dcfe195f485
@@@ -28,13 -28,7 +28,7 @@@ static char const * const grep_usage[] 
        NULL
  };
  
- static const char *super_prefix;
  static int recurse_submodules;
- static struct argv_array submodule_options = ARGV_ARRAY_INIT;
- static const char *parent_basename;
- static int grep_submodule_launch(struct grep_opt *opt,
-                                const struct grep_source *gs);
  
  #define GREP_NUM_THREADS_DEFAULT 8
  static int num_threads;
@@@ -186,10 -180,7 +180,7 @@@ static void *run(void *arg
                        break;
  
                opt->output_priv = w;
-               if (w->source.type == GREP_SOURCE_SUBMODULE)
-                       hit |= grep_submodule_launch(opt, &w->source);
-               else
-                       hit |= grep_source(opt, &w->source);
+               hit |= grep_source(opt, &w->source);
                grep_source_clear_data(&w->source);
                work_done(w);
        }
@@@ -284,7 -275,7 +275,7 @@@ static int wait_all(void
  static int grep_cmd_config(const char *var, const char *value, void *cb)
  {
        int st = grep_config(var, value, cb);
 -      if (git_color_default_config(var, value, cb) < 0)
 +      if (git_default_config(var, value, cb) < 0)
                st = -1;
  
        if (!strcmp(var, "grep.threads")) {
@@@ -327,21 -318,13 +318,13 @@@ static int grep_oid(struct grep_opt *op
  {
        struct strbuf pathbuf = STRBUF_INIT;
  
-       if (super_prefix) {
-               strbuf_add(&pathbuf, filename, tree_name_len);
-               strbuf_addstr(&pathbuf, super_prefix);
-               strbuf_addstr(&pathbuf, filename + tree_name_len);
+       if (opt->relative && opt->prefix_length) {
+               quote_path_relative(filename + tree_name_len, opt->prefix, &pathbuf);
+               strbuf_insert(&pathbuf, 0, filename, tree_name_len);
        } else {
                strbuf_addstr(&pathbuf, filename);
        }
  
-       if (opt->relative && opt->prefix_length) {
-               char *name = strbuf_detach(&pathbuf, NULL);
-               quote_path_relative(name + tree_name_len, opt->prefix, &pathbuf);
-               strbuf_insert(&pathbuf, 0, name, tree_name_len);
-               free(name);
-       }
  #ifndef NO_PTHREADS
        if (num_threads) {
                add_work(opt, GREP_SOURCE_OID, pathbuf.buf, path, oid);
@@@ -366,15 -349,10 +349,10 @@@ static int grep_file(struct grep_opt *o
  {
        struct strbuf buf = STRBUF_INIT;
  
-       if (super_prefix)
-               strbuf_addstr(&buf, super_prefix);
-       strbuf_addstr(&buf, filename);
-       if (opt->relative && opt->prefix_length) {
-               char *name = strbuf_detach(&buf, NULL);
-               quote_path_relative(name, opt->prefix, &buf);
-               free(name);
-       }
+       if (opt->relative && opt->prefix_length)
+               quote_path_relative(filename, opt->prefix, &buf);
+       else
+               strbuf_addstr(&buf, filename);
  
  #ifndef NO_PTHREADS
        if (num_threads) {
@@@ -421,284 -399,89 +399,89 @@@ static void run_pager(struct grep_opt *
                exit(status);
  }
  
- static void compile_submodule_options(const struct grep_opt *opt,
-                                     const char **argv,
-                                     int cached, int untracked,
-                                     int opt_exclude, int use_index,
-                                     int pattern_type_arg)
- {
-       struct grep_pat *pattern;
-       if (recurse_submodules)
-               argv_array_push(&submodule_options, "--recurse-submodules");
-       if (cached)
-               argv_array_push(&submodule_options, "--cached");
-       if (!use_index)
-               argv_array_push(&submodule_options, "--no-index");
-       if (untracked)
-               argv_array_push(&submodule_options, "--untracked");
-       if (opt_exclude > 0)
-               argv_array_push(&submodule_options, "--exclude-standard");
-       if (opt->invert)
-               argv_array_push(&submodule_options, "-v");
-       if (opt->ignore_case)
-               argv_array_push(&submodule_options, "-i");
-       if (opt->word_regexp)
-               argv_array_push(&submodule_options, "-w");
-       switch (opt->binary) {
-       case GREP_BINARY_NOMATCH:
-               argv_array_push(&submodule_options, "-I");
-               break;
-       case GREP_BINARY_TEXT:
-               argv_array_push(&submodule_options, "-a");
-               break;
-       default:
-               break;
-       }
-       if (opt->allow_textconv)
-               argv_array_push(&submodule_options, "--textconv");
-       if (opt->max_depth != -1)
-               argv_array_pushf(&submodule_options, "--max-depth=%d",
-                                opt->max_depth);
-       if (opt->linenum)
-               argv_array_push(&submodule_options, "-n");
-       if (!opt->pathname)
-               argv_array_push(&submodule_options, "-h");
-       if (!opt->relative)
-               argv_array_push(&submodule_options, "--full-name");
-       if (opt->name_only)
-               argv_array_push(&submodule_options, "-l");
-       if (opt->unmatch_name_only)
-               argv_array_push(&submodule_options, "-L");
-       if (opt->null_following_name)
-               argv_array_push(&submodule_options, "-z");
-       if (opt->count)
-               argv_array_push(&submodule_options, "-c");
-       if (opt->file_break)
-               argv_array_push(&submodule_options, "--break");
-       if (opt->heading)
-               argv_array_push(&submodule_options, "--heading");
-       if (opt->pre_context)
-               argv_array_pushf(&submodule_options, "--before-context=%d",
-                                opt->pre_context);
-       if (opt->post_context)
-               argv_array_pushf(&submodule_options, "--after-context=%d",
-                                opt->post_context);
-       if (opt->funcname)
-               argv_array_push(&submodule_options, "-p");
-       if (opt->funcbody)
-               argv_array_push(&submodule_options, "-W");
-       if (opt->all_match)
-               argv_array_push(&submodule_options, "--all-match");
-       if (opt->debug)
-               argv_array_push(&submodule_options, "--debug");
-       if (opt->status_only)
-               argv_array_push(&submodule_options, "-q");
-       switch (pattern_type_arg) {
-       case GREP_PATTERN_TYPE_BRE:
-               argv_array_push(&submodule_options, "-G");
-               break;
-       case GREP_PATTERN_TYPE_ERE:
-               argv_array_push(&submodule_options, "-E");
-               break;
-       case GREP_PATTERN_TYPE_FIXED:
-               argv_array_push(&submodule_options, "-F");
-               break;
-       case GREP_PATTERN_TYPE_PCRE:
-               argv_array_push(&submodule_options, "-P");
-               break;
-       case GREP_PATTERN_TYPE_UNSPECIFIED:
-               break;
-       default:
-               die("BUG: Added a new grep pattern type without updating switch statement");
-       }
-       for (pattern = opt->pattern_list; pattern != NULL;
-            pattern = pattern->next) {
-               switch (pattern->token) {
-               case GREP_PATTERN:
-                       argv_array_pushf(&submodule_options, "-e%s",
-                                        pattern->pattern);
-                       break;
-               case GREP_AND:
-               case GREP_OPEN_PAREN:
-               case GREP_CLOSE_PAREN:
-               case GREP_NOT:
-               case GREP_OR:
-                       argv_array_push(&submodule_options, pattern->pattern);
-                       break;
-               /* BODY and HEAD are not used by git-grep */
-               case GREP_PATTERN_BODY:
-               case GREP_PATTERN_HEAD:
-                       break;
-               }
-       }
-       /*
-        * Limit number of threads for child process to use.
-        * This is to prevent potential fork-bomb behavior of git-grep as each
-        * submodule process has its own thread pool.
-        */
-       argv_array_pushf(&submodule_options, "--threads=%d",
-                        DIV_ROUND_UP(num_threads, 2));
-       /* Add Pathspecs */
-       argv_array_push(&submodule_options, "--");
-       for (; *argv; argv++)
-               argv_array_push(&submodule_options, *argv);
- }
+ static int grep_cache(struct grep_opt *opt, struct repository *repo,
+                     const struct pathspec *pathspec, int cached);
+ static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
+                    struct tree_desc *tree, struct strbuf *base, int tn_len,
+                    int check_attr, struct repository *repo);
  
- /*
-  * Launch child process to grep contents of a submodule
-  */
- static int grep_submodule_launch(struct grep_opt *opt,
-                                const struct grep_source *gs)
+ static int grep_submodule(struct grep_opt *opt, struct repository *superproject,
+                         const struct pathspec *pathspec,
+                         const struct object_id *oid,
+                         const char *filename, const char *path)
  {
-       struct child_process cp = CHILD_PROCESS_INIT;
-       int status, i;
-       const char *end_of_base;
-       const char *name;
-       struct strbuf child_output = STRBUF_INIT;
-       end_of_base = strchr(gs->name, ':');
-       if (gs->identifier && end_of_base)
-               name = end_of_base + 1;
-       else
-               name = gs->name;
+       struct repository submodule;
+       int hit;
  
-       prepare_submodule_repo_env(&cp.env_array);
-       argv_array_push(&cp.env_array, GIT_DIR_ENVIRONMENT);
+       if (!is_submodule_active(superproject, path))
+               return 0;
  
-       if (opt->relative && opt->prefix_length)
-               argv_array_pushf(&cp.env_array, "%s=%s",
-                                GIT_TOPLEVEL_PREFIX_ENVIRONMENT,
-                                opt->prefix);
+       if (repo_submodule_init(&submodule, superproject, path))
+               return 0;
  
-       /* Add super prefix */
-       argv_array_pushf(&cp.args, "--super-prefix=%s%s/",
-                        super_prefix ? super_prefix : "",
-                        name);
-       argv_array_push(&cp.args, "grep");
+       repo_read_gitmodules(&submodule);
  
        /*
-        * Add basename of parent project
-        * When performing grep on a tree object the filename is prefixed
-        * with the object's name: 'tree-name:filename'.  In order to
-        * provide uniformity of output we want to pass the name of the
-        * parent project's object name to the submodule so the submodule can
-        * prefix its output with the parent's name and not its own OID.
+        * NEEDSWORK: This adds the submodule's object directory to the list of
+        * alternates for the single in-memory object store.  This has some bad
+        * consequences for memory (processed objects will never be freed) and
+        * performance (this increases the number of pack files git has to pay
+        * attention to, to the sum of the number of pack files in all the
+        * repositories processed so far).  This can be removed once the object
+        * store is no longer global and instead is a member of the repository
+        * object.
         */
-       if (gs->identifier && end_of_base)
-               argv_array_pushf(&cp.args, "--parent-basename=%.*s",
-                                (int) (end_of_base - gs->name),
-                                gs->name);
+       add_to_alternates_memory(submodule.objectdir);
  
-       /* Add options */
-       for (i = 0; i < submodule_options.argc; i++) {
-               /*
-                * If there is a tree identifier for the submodule, add the
-                * rev after adding the submodule options but before the
-                * pathspecs.  To do this we listen for the '--' and insert the
-                * oid before pushing the '--' onto the child process argv
-                * array.
-                */
-               if (gs->identifier &&
-                   !strcmp("--", submodule_options.argv[i])) {
-                       argv_array_push(&cp.args, oid_to_hex(gs->identifier));
-               }
+       if (oid) {
+               struct object *object;
+               struct tree_desc tree;
+               void *data;
+               unsigned long size;
+               struct strbuf base = STRBUF_INIT;
  
-               argv_array_push(&cp.args, submodule_options.argv[i]);
-       }
+               object = parse_object_or_die(oid, oid_to_hex(oid));
  
-       cp.git_cmd = 1;
-       cp.dir = gs->path;
+               grep_read_lock();
+               data = read_object_with_reference(object->oid.hash, tree_type,
+                                                 &size, NULL);
+               grep_read_unlock();
  
-       /*
-        * Capture output to output buffer and check the return code from the
-        * child process.  A '0' indicates a hit, a '1' indicates no hit and
-        * anything else is an error.
-        */
-       status = capture_command(&cp, &child_output, 0);
-       if (status && (status != 1)) {
-               /* flush the buffer */
-               write_or_die(1, child_output.buf, child_output.len);
-               die("process for submodule '%s' failed with exit code: %d",
-                   gs->name, status);
-       }
+               if (!data)
+                       die(_("unable to read tree (%s)"), oid_to_hex(&object->oid));
  
-       opt->output(opt, child_output.buf, child_output.len);
-       strbuf_release(&child_output);
-       /* invert the return code to make a hit equal to 1 */
-       return !status;
- }
+               strbuf_addstr(&base, filename);
+               strbuf_addch(&base, '/');
  
- /*
-  * Prep grep structures for a submodule grep
-  * oid: the oid of the submodule or NULL if using the working tree
-  * filename: name of the submodule including tree name of parent
-  * path: location of the submodule
-  */
- static int grep_submodule(struct grep_opt *opt, const struct object_id *oid,
-                         const char *filename, const char *path)
- {
-       if (!is_submodule_active(the_repository, path))
-               return 0;
-       if (!is_submodule_populated_gently(path, NULL)) {
-               /*
-                * If searching history, check for the presence of the
-                * submodule's gitdir before skipping the submodule.
-                */
-               if (oid) {
-                       const struct submodule *sub =
-                                       submodule_from_path(&null_oid, path);
-                       if (sub)
-                               path = git_path("modules/%s", sub->name);
-                       if (!(is_directory(path) && is_git_directory(path)))
-                               return 0;
-               } else {
-                       return 0;
-               }
+               init_tree_desc(&tree, data, size);
+               hit = grep_tree(opt, pathspec, &tree, &base, base.len,
+                               object->type == OBJ_COMMIT, &submodule);
+               strbuf_release(&base);
+               free(data);
+       } else {
+               hit = grep_cache(opt, &submodule, pathspec, 1);
        }
  
- #ifndef NO_PTHREADS
-       if (num_threads) {
-               add_work(opt, GREP_SOURCE_SUBMODULE, filename, path, oid);
-               return 0;
-       } else
- #endif
-       {
-               struct grep_source gs;
-               int hit;
-               grep_source_init(&gs, GREP_SOURCE_SUBMODULE,
-                                filename, path, oid);
-               hit = grep_submodule_launch(opt, &gs);
-               grep_source_clear(&gs);
-               return hit;
-       }
+       repo_clear(&submodule);
+       return hit;
  }
  
- static int grep_cache(struct grep_opt *opt, const struct pathspec *pathspec,
-                     int cached)
+ static int grep_cache(struct grep_opt *opt, struct repository *repo,
+                     const struct pathspec *pathspec, int cached)
  {
        int hit = 0;
        int nr;
        struct strbuf name = STRBUF_INIT;
        int name_base_len = 0;
-       if (super_prefix) {
-               name_base_len = strlen(super_prefix);
-               strbuf_addstr(&name, super_prefix);
+       if (repo->submodule_prefix) {
+               name_base_len = strlen(repo->submodule_prefix);
+               strbuf_addstr(&name, repo->submodule_prefix);
        }
  
-       read_cache();
+       repo_read_index(repo);
  
-       for (nr = 0; nr < active_nr; nr++) {
-               const struct cache_entry *ce = active_cache[nr];
+       for (nr = 0; nr < repo->index->cache_nr; nr++) {
+               const struct cache_entry *ce = repo->index->cache[nr];
                strbuf_setlen(&name, name_base_len);
                strbuf_addstr(&name, ce->name);
  
                            ce_skip_worktree(ce)) {
                                if (ce_stage(ce) || ce_intent_to_add(ce))
                                        continue;
-                               hit |= grep_oid(opt, &ce->oid, ce->name,
-                                                0, ce->name);
+                               hit |= grep_oid(opt, &ce->oid, name.buf,
+                                                0, name.buf);
                        } else {
-                               hit |= grep_file(opt, ce->name);
+                               hit |= grep_file(opt, name.buf);
                        }
                } else if (recurse_submodules && S_ISGITLINK(ce->ce_mode) &&
                           submodule_path_match(pathspec, name.buf, NULL)) {
-                       hit |= grep_submodule(opt, NULL, ce->name, ce->name);
+                       hit |= grep_submodule(opt, repo, pathspec, NULL, ce->name, ce->name);
                } else {
                        continue;
                }
                if (ce_stage(ce)) {
                        do {
                                nr++;
-                       } while (nr < active_nr &&
-                                !strcmp(ce->name, active_cache[nr]->name));
+                       } while (nr < repo->index->cache_nr &&
+                                !strcmp(ce->name, repo->index->cache[nr]->name));
                        nr--; /* compensate for loop control */
                }
                if (hit && opt->status_only)
  
  static int grep_tree(struct grep_opt *opt, const struct pathspec *pathspec,
                     struct tree_desc *tree, struct strbuf *base, int tn_len,
-                    int check_attr)
+                    int check_attr, struct repository *repo)
  {
        int hit = 0;
        enum interesting match = entry_not_interesting;
        int old_baselen = base->len;
        struct strbuf name = STRBUF_INIT;
        int name_base_len = 0;
-       if (super_prefix) {
-               strbuf_addstr(&name, super_prefix);
+       if (repo->submodule_prefix) {
+               strbuf_addstr(&name, repo->submodule_prefix);
                name_base_len = name.len;
        }
  
                        strbuf_addch(base, '/');
                        init_tree_desc(&sub, data, size);
                        hit |= grep_tree(opt, pathspec, &sub, base, tn_len,
-                                        check_attr);
+                                        check_attr, repo);
                        free(data);
                } else if (recurse_submodules && S_ISGITLINK(entry.mode)) {
-                       hit |= grep_submodule(opt, entry.oid, base->buf,
-                                             base->buf + tn_len);
+                       hit |= grep_submodule(opt, repo, pathspec, entry.oid,
+                                             base->buf, base->buf + tn_len);
                }
  
                strbuf_setlen(base, old_baselen);
  }
  
  static int grep_object(struct grep_opt *opt, const struct pathspec *pathspec,
-                      struct object *obj, const char *name, const char *path)
+                      struct object *obj, const char *name, const char *path,
+                      struct repository *repo)
  {
        if (obj->type == OBJ_BLOB)
                return grep_oid(opt, &obj->oid, name, 0, path);
                if (!data)
                        die(_("unable to read tree (%s)"), oid_to_hex(&obj->oid));
  
-               /* Use parent's name as base when recursing submodules */
-               if (recurse_submodules && parent_basename)
-                       name = parent_basename;
                len = name ? strlen(name) : 0;
                strbuf_init(&base, PATH_MAX + len + 1);
                if (len) {
                }
                init_tree_desc(&tree, data, size);
                hit = grep_tree(opt, pathspec, &tree, &base, base.len,
-                               obj->type == OBJ_COMMIT);
+                               obj->type == OBJ_COMMIT, repo);
                strbuf_release(&base);
                free(data);
                return hit;
  }
  
  static int grep_objects(struct grep_opt *opt, const struct pathspec *pathspec,
+                       struct repository *repo,
                        const struct object_array *list)
  {
        unsigned int i;
                /* load the gitmodules file for this rev */
                if (recurse_submodules) {
                        submodule_free();
 -                      gitmodules_config_sha1(real_obj->oid.hash);
 +                      gitmodules_config_oid(&real_obj->oid);
                }
-               if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path)) {
+               if (grep_object(opt, pathspec, real_obj, list->objects[i].name, list->objects[i].path,
+                               repo)) {
                        hit = 1;
                        if (opt->status_only)
                                break;
@@@ -1005,9 -787,6 +787,6 @@@ int cmd_grep(int argc, const char **arg
                            N_("ignore files specified via '.gitignore'"), 1),
                OPT_BOOL(0, "recurse-submodules", &recurse_submodules,
                         N_("recursively search in each submodule")),
-               OPT_STRING(0, "parent-basename", &parent_basename,
-                          N_("basename"),
-                          N_("prepend parent project's basename to output")),
                OPT_GROUP(""),
                OPT_BOOL('v', "invert-match", &opt.invert,
                        N_("show non-matching lines")),
        init_grep_defaults();
        git_config(grep_cmd_config, NULL);
        grep_init(&opt, prefix);
-       super_prefix = get_super_prefix();
  
        /*
         * If there is no -- then the paths must exist in the working
                        break;
                }
  
 -              if (get_sha1_with_context(arg, GET_SHA1_RECORD_PATH,
 -                                        oid.hash, &oc)) {
 +              if (get_oid_with_context(arg, GET_OID_RECORD_PATH,
 +                                       &oid, &oc)) {
                        if (seen_dashdash)
                                die(_("unable to resolve revision: %s"), arg);
                        break;
  
        if (recurse_submodules) {
                gitmodules_config();
-               compile_submodule_options(&opt, argv + i, cached, untracked,
-                                         opt_exclude, use_index,
-                                         pattern_type_arg);
        }
  
        if (show_in_pager && (cached || list.nr))
                if (!cached)
                        setup_work_tree();
  
-               hit = grep_cache(&opt, &pathspec, cached);
+               hit = grep_cache(&opt, the_repository, &pathspec, cached);
        } else {
                if (cached)
                        die(_("both --cached and trees are given."));
-               hit = grep_objects(&opt, &pathspec, &list);
+               hit = grep_objects(&opt, &pathspec, the_repository, &list);
        }
  
        if (num_threads)
index 353e884d8d2a194904ec9f6871d8f7c855092756,6d9600d4fbada7511bb6abf9df12737479ef87e8..0ff9dd0b85074dfe6e04b6fc56c04f2c1789f7eb
@@@ -350,7 -350,7 +350,7 @@@ static void init_submodule(const char *
        } else
                displaypath = xstrdup(path);
  
 -      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"),
@@@ -476,7 -476,7 +476,7 @@@ static int module_name(int argc, const 
                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'"),
@@@ -795,7 -795,7 +795,7 @@@ static int prepare_to_clone_next_submod
                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,
@@@ -930,7 -930,7 +930,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);
  
        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,
@@@ -1060,7 -1069,7 +1069,7 @@@ static const char *remote_submodule_bra
        gitmodules_config();
        git_config(submodule_config, NULL);
  
 -      sub = submodule_from_path(null_sha1, path);
 +      sub = submodule_from_path(&null_oid, path);
        if (!sub)
                return NULL;
  
@@@ -1108,28 -1117,9 +1117,28 @@@ static int resolve_remote_submodule_bra
  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.hash, 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");
 +                              }
 +                      default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
 +                      }
                }
                free_refspec(refspec_nr, refspec);
        }
 +      free(head);
  
        return 0;
  }
diff --combined cache.h
index 1c69d2a05aaf1f5e737bd5229cfaf0fedbe6ca92,c221434b2306e34b677927a1f0e25108f1f86e60..3c44a25ffe9a703b25a99f978e5d6145fdad8d91
+++ b/cache.h
@@@ -417,7 -417,6 +417,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"
@@@ -1146,14 -1146,6 +1146,14 @@@ char *strip_path_suffix(const char *pat
  int daemon_avoid_alias(const char *path);
  extern int is_ntfs_dotgit(const char *name);
  
 +/*
 + * Returns true iff "str" could be confused as a command-line option when
 + * passed to a sub-program like "ssh". Note that this has nothing to do with
 + * shell-quoting, which should be handled separately; we're assuming here that
 + * the string makes it verbatim to the sub-program.
 + */
 +int looks_like_command_line_option(const char *str);
 +
  /**
   * Return a newly allocated string with the evaluation of
   * "$XDG_CONFIG_HOME/git/$filename" if $XDG_CONFIG_HOME is non-empty, otherwise
@@@ -1291,37 -1283,38 +1291,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 *);
@@@ -1499,7 -1492,6 +1499,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;
diff --combined config.c
index 9ec8c4488229a4f6a15550fd80496ef1b5bb85fe,06645a3250cc1321f3722ffd427d04f3e5dcd3fe..c1450732d9937511a0efa65e9adcf2b3c5319f60
+++ b/config.c
@@@ -16,7 -16,6 +16,7 @@@
  #include "string-list.h"
  #include "utf8.h"
  #include "dir.h"
 +#include "color.h"
  
  struct config_source {
        struct config_source *prev;
@@@ -1351,9 -1350,6 +1351,9 @@@ int git_default_config(const char *var
        if (starts_with(var, "advice."))
                return git_default_advice_config(var, value);
  
 +      if (git_color_config(var, value, dummy) < 0)
 +              return -1;
 +
        if (!strcmp(var, "pager.color") || !strcmp(var, "color.pager")) {
                pager_use_color = git_config_bool(var,value);
                return 0;
@@@ -1464,9 -1460,9 +1464,9 @@@ int git_config_from_mem(config_fn_t fn
        return do_config_from(&top, fn, data);
  }
  
 -int git_config_from_blob_sha1(config_fn_t fn,
 +int git_config_from_blob_oid(config_fn_t fn,
                              const char *name,
 -                            const unsigned char *sha1,
 +                            const struct object_id *oid,
                              void *data)
  {
        enum object_type type;
        unsigned long size;
        int ret;
  
 -      buf = read_sha1_file(sha1, &type, &size);
 +      buf = read_sha1_file(oid->hash, &type, &size);
        if (!buf)
                return error("unable to load config blob object '%s'", name);
        if (type != OBJ_BLOB) {
@@@ -1492,11 -1488,11 +1492,11 @@@ static int git_config_from_blob_ref(con
                                    const char *name,
                                    void *data)
  {
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
 -      if (get_sha1(name, sha1) < 0)
 +      if (get_oid(name, &oid) < 0)
                return error("unable to resolve config blob '%s'", name);
 -      return git_config_from_blob_sha1(fn, name, sha1, data);
 +      return git_config_from_blob_oid(fn, name, &oid, data);
  }
  
  const char *git_etc_gitconfig(void)
@@@ -1719,19 -1715,17 +1719,19 @@@ static int configset_add_value(struct c
  }
  
  static int config_set_element_cmp(const void *unused_cmp_data,
 -                                const struct config_set_element *e1,
 -                                const struct config_set_element *e2,
 +                                const void *entry,
 +                                const void *entry_or_key,
                                  const void *unused_keydata)
  {
 +      const struct config_set_element *e1 = entry;
 +      const struct config_set_element *e2 = entry_or_key;
 +
        return strcmp(e1->key, e2->key);
  }
  
  void git_configset_init(struct config_set *cs)
  {
 -      hashmap_init(&cs->config_hash, (hashmap_cmp_fn)config_set_element_cmp,
 -                   NULL, 0);
 +      hashmap_init(&cs->config_hash, config_set_element_cmp, NULL, 0);
        cs->hash_initialized = 1;
        cs->list.nr = 0;
        cs->list.alloc = 0;
@@@ -2059,6 -2053,23 +2059,23 @@@ int git_config_get_pathname(const char 
        return repo_config_get_pathname(the_repository, key, dest);
  }
  
+ /*
+  * Note: This function exists solely to maintain backward compatibility with
+  * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
+  * NOT be used anywhere else.
+  *
+  * Runs the provided config function on the '.gitmodules' file found in the
+  * working directory.
+  */
+ void config_from_gitmodules(config_fn_t fn, void *data)
+ {
+       if (the_repository->worktree) {
+               char *file = repo_worktree_path(the_repository, GITMODULES_FILE);
+               git_config_from_file(fn, file, data);
+               free(file);
+       }
+ }
  int git_config_get_expiry(const char *key, const char **output)
  {
        int ret = git_config_get_string_const(key, output);
diff --combined config.h
index 827f2b0e4a652b008fd9e3f36cee4ae656836f4e,6998e6645995a3302de0f42234c539d6685da008..18b6f3f724bd823bf98f039e4699b0c2c5dc5393
+++ b/config.h
@@@ -39,8 -39,8 +39,8 @@@ extern int git_default_config(const cha
  extern int git_config_from_file(config_fn_t fn, const char *, void *);
  extern int git_config_from_mem(config_fn_t fn, const enum config_origin_type,
                                        const char *name, const char *buf, size_t len, void *data);
 -extern int git_config_from_blob_sha1(config_fn_t fn, const char *name,
 -                                   const unsigned char *sha1, void *data);
 +extern int git_config_from_blob_oid(config_fn_t fn, const char *name,
 +                                  const struct object_id *oid, 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);
@@@ -187,6 -187,16 +187,16 @@@ extern int repo_config_get_maybe_bool(s
  extern int repo_config_get_pathname(struct repository *repo,
                                    const char *key, const char **dest);
  
+ /*
+  * Note: This function exists solely to maintain backward compatibility with
+  * 'fetch' and 'update_clone' storing configuration in '.gitmodules' and should
+  * NOT be used anywhere else.
+  *
+  * Runs the provided config function on the '.gitmodules' file found in the
+  * working directory.
+  */
+ extern void config_from_gitmodules(config_fn_t fn, void *data);
  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);
diff --combined git.c
index 6b6d9f68e1ea010cb951501cab1fdfa82037b878,9dd9aead6a82feafd9de5cca5b7aa33e051bb43c..f31dca69620ac244e87e04f1d508ee23cf2f92cf
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -33,16 -33,6 +33,16 @@@ static void commit_pager_choice(void) 
        }
  }
  
 +void setup_auto_pager(const char *cmd, int def)
 +{
 +      if (use_pager != -1 || pager_in_use())
 +              return;
 +      use_pager = check_pager_config(cmd);
 +      if (use_pager == -1)
 +              use_pager = def;
 +      commit_pager_choice();
 +}
 +
  static int handle_options(const char ***argv, int *argc, int *envchanged)
  {
        const char **orig_argv = *argv;
@@@ -293,7 -283,6 +293,7 @@@ static int handle_alias(int *argcp, con
   */
  #define NEED_WORK_TREE                (1<<3)
  #define SUPPORT_SUPER_PREFIX  (1<<4)
 +#define DELAY_PAGER_CONFIG    (1<<5)
  
  struct cmd_struct {
        const char *cmd;
@@@ -317,8 -306,7 +317,8 @@@ static int run_builtin(struct cmd_struc
                        prefix = setup_git_directory_gently(&nongit_ok);
                }
  
 -              if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY))
 +              if (use_pager == -1 && p->option & (RUN_SETUP | RUN_SETUP_GENTLY) &&
 +                  !(p->option & DELAY_PAGER_CONFIG))
                        use_pager = check_pager_config(p->cmd);
                if (use_pager == -1 && p->option & USE_PAGER)
                        use_pager = 1;
@@@ -404,7 -392,7 +404,7 @@@ static struct cmd_struct commands[] = 
        { "fsck-objects", cmd_fsck, RUN_SETUP },
        { "gc", cmd_gc, RUN_SETUP },
        { "get-tar-commit-id", cmd_get_tar_commit_id },
-       { "grep", cmd_grep, RUN_SETUP_GENTLY | SUPPORT_SUPER_PREFIX },
+       { "grep", cmd_grep, RUN_SETUP_GENTLY },
        { "hash-object", cmd_hash_object },
        { "help", cmd_help },
        { "index-pack", cmd_index_pack, RUN_SETUP_GENTLY },
        { "stripspace", cmd_stripspace },
        { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX},
        { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
 -      { "tag", cmd_tag, RUN_SETUP },
 +      { "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
        { "unpack-file", cmd_unpack_file, RUN_SETUP },
        { "unpack-objects", cmd_unpack_objects, RUN_SETUP },
        { "update-index", cmd_update_index, RUN_SETUP },
@@@ -559,7 -547,7 +559,7 @@@ static void execv_dashed_external(cons
        if (get_super_prefix())
                die("%s doesn't support --super-prefix", argv[0]);
  
 -      if (use_pager == -1)
 +      if (use_pager == -1 && !is_builtin(argv[0]))
                use_pager = check_pager_config(argv[0]);
        commit_pager_choice();
  
diff --combined repository.c
index 1617467568c76e685d5f852c27ca16f26ed0494c,c0e0e0e7e76015e3f93b21528bff58286fab0fb2..f107af7d763e848648ace5da0010be4df2e0d4dc
@@@ -4,7 -4,9 +4,9 @@@
  #include "submodule-config.h"
  
  /* The main repository */
- static struct repository the_repo;
+ static struct repository the_repo = {
+       NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, NULL, &the_index, 0, 0
+ };
  struct repository *the_repository = &the_repo;
  
  static char *git_path_from_env(const char *envvar, const char *git_dir,
@@@ -158,7 -160,7 +160,7 @@@ int repo_submodule_init(struct reposito
        struct strbuf worktree = STRBUF_INIT;
        int ret = 0;
  
 -      sub = submodule_from_cache(superproject, null_sha1, path);
 +      sub = submodule_from_cache(superproject, &null_oid, path);
        if (!sub) {
                ret = -1;
                goto out;
@@@ -235,8 -237,6 +237,6 @@@ int repo_read_index(struct repository *
  {
        if (!repo->index)
                repo->index = xcalloc(1, sizeof(*repo->index));
-       else
-               discard_index(repo->index);
  
        return read_index_from(repo->index, repo->index_file);
  }
diff --combined submodule-config.c
index bede338c8539f18081168bacd0b562a927e9532c,70400f553aa91c102d55f7fbaa93e6c3aad42c8c..2b83c2319fbf5af69383cf188980e7787c767ab3
@@@ -35,25 -35,19 +35,25 @@@ enum lookup_type 
  };
  
  static int config_path_cmp(const void *unused_cmp_data,
 -                         const struct submodule_entry *a,
 -                         const struct submodule_entry *b,
 +                         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 void *unused_cmp_data,
 -                         const struct submodule_entry *a,
 -                         const struct submodule_entry *b,
 +                         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);
  }
@@@ -65,8 -59,8 +65,8 @@@ static struct submodule_cache *submodul
  
  static void submodule_cache_init(struct submodule_cache *cache)
  {
 -      hashmap_init(&cache->for_path, (hashmap_cmp_fn) config_path_cmp, NULL, 0);
 -      hashmap_init(&cache->for_name, (hashmap_cmp_fn) config_name_cmp, NULL, 0);
 +      hashmap_init(&cache->for_path, config_path_cmp, NULL, 0);
 +      hashmap_init(&cache->for_name, config_name_cmp, NULL, 0);
        cache->initialized = 1;
  }
  
@@@ -254,6 -248,14 +254,14 @@@ static int parse_fetch_recurse(const ch
        }
  }
  
+ 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);
@@@ -447,19 -449,19 +455,19 @@@ static int parse_config(const char *var
        return ret;
  }
  
 -int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
 -                                    unsigned char *gitmodules_sha1,
 +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;
        }
@@@ -570,14 -572,14 +578,14 @@@ int parse_submodule_config_option(cons
        return submodule_config_option(the_repository, var, value);
  }
  
 -const struct submodule *submodule_from_name(const unsigned char *treeish_name,
 +const struct submodule *submodule_from_name(const struct object_id *treeish_name,
                const char *name)
  {
        submodule_cache_check_init(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)
  {
        submodule_cache_check_init(the_repository);
  }
  
  const struct submodule *submodule_from_cache(struct repository *repo,
 -                                           const unsigned char *treeish_name,
 +                                           const struct object_id *treeish_name,
                                             const char *key)
  {
        submodule_cache_check_init(repo);
diff --combined submodule-config.h
index 4ffa2fa840a5fc27ac209a2e976b118b15b124ef,995d404f88a1100fa5e39b6606f61a4e7a78d5dd..cccd34b929f5299fbba6f43c74daeb96773aebdf
@@@ -27,6 -27,7 +27,7 @@@ 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,
@@@ -37,15 -38,15 +38,15 @@@ extern int parse_submodule_config_optio
  extern int submodule_config_option(struct repository *repo,
                                   const char *var, const char *value);
  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);
 +              const struct object_id *commit_or_tree, const char *path);
  extern const struct submodule *submodule_from_cache(struct repository *repo,
 -                                                  const unsigned char *treeish_name,
 +                                                  const struct object_id *treeish_name,
                                                    const char *key);
 -extern int gitmodule_sha1_from_commit(const unsigned char *commit_sha1,
 -                                    unsigned char *gitmodules_sha1,
 -                                    struct strbuf *rev);
 +extern int gitmodule_oid_from_commit(const struct object_id *commit_oid,
 +                                   struct object_id *gitmodules_oid,
 +                                   struct strbuf *rev);
  extern void submodule_free(void);
  
  #endif /* SUBMODULE_CONFIG_H */
diff --combined submodule.c
index 6ba15b41372223a5a77130d9fba7462a45393a5b,9d5eacaf9f2ffad4a7f5d17ced4137e0162215d5..e072036e7965ca82a665ac1eeb88bfb44fa4569a
  #include "worktree.h"
  #include "parse-options.h"
  
- static int config_fetch_recurse_submodules = RECURSE_SUBMODULES_ON_DEMAND;
  static int config_update_recurse_submodules = RECURSE_SUBMODULES_OFF;
- static int parallel_jobs = 1;
  static struct string_list changed_submodule_paths = STRING_LIST_INIT_DUP;
  static int initialized_fetch_ref_tips;
  static struct oid_array ref_tips_before_fetch;
  static struct oid_array ref_tips_after_fetch;
  
  /*
-  * The following flag is set if the .gitmodules file is unmerged. We then
-  * disable recursion for all submodules where .git/config doesn't have a
-  * matching config entry because we can't guess what might be configured in
-  * .gitmodules unless the user resolves the conflict. When a command line
-  * option is given (which always overrides configuration) this flag will be
-  * ignored.
+  * Check if the .gitmodules file is unmerged. Parsing of the .gitmodules file
+  * will be disabled because we can't guess what might be configured in
+  * .gitmodules unless the user resolves the conflict.
   */
- static int gitmodules_is_unmerged;
+ int is_gitmodules_unmerged(const struct index_state *istate)
+ {
+       int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
+       if (pos < 0) { /* .gitmodules not found or isn't merged */
+               pos = -1 - pos;
+               if (istate->cache_nr > pos) {  /* there is a .gitmodules */
+                       const struct cache_entry *ce = istate->cache[pos];
+                       if (ce_namelen(ce) == strlen(GITMODULES_FILE) &&
+                           !strcmp(ce->name, GITMODULES_FILE))
+                               return 1;
+               }
+       }
+       return 0;
+ }
  
  /*
-  * This flag is set if the .gitmodules file had unstaged modifications on
-  * startup. This must be checked before allowing modifications to the
-  * .gitmodules file with the intention to stage them later, because when
-  * continuing we would stage the modifications the user didn't stage herself
-  * too. That might change in a future version when we learn to stage the
-  * changes we do ourselves without staging any previous modifications.
+  * Check if the .gitmodules file has unstaged modifications.  This must be
+  * checked before allowing modifications to the .gitmodules file with the
+  * intention to stage them later, because when continuing we would stage the
+  * modifications the user didn't stage herself too. That might change in a
+  * future version when we learn to stage the changes we do ourselves without
+  * staging any previous modifications.
   */
- static int gitmodules_is_modified;
- int is_staging_gitmodules_ok(void)
+ int is_staging_gitmodules_ok(const struct index_state *istate)
  {
-       return !gitmodules_is_modified;
+       int pos = index_name_pos(istate, GITMODULES_FILE, strlen(GITMODULES_FILE));
+       if ((pos >= 0) && (pos < istate->cache_nr)) {
+               struct stat st;
+               if (lstat(GITMODULES_FILE, &st) == 0 &&
+                   ce_match_stat(istate->cache[pos], &st, 0) & DATA_CHANGED)
+                       return 0;
+       }
+       return 1;
  }
  
  /*
@@@ -63,13 -79,13 +79,13 @@@ int update_path_in_gitmodules(const cha
        struct strbuf entry = STRBUF_INIT;
        const struct submodule *submodule;
  
-       if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+       if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
                return -1;
  
-       if (gitmodules_is_unmerged)
+       if (is_gitmodules_unmerged(&the_index))
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
  
 -      submodule = submodule_from_path(null_sha1, oldpath);
 +      submodule = submodule_from_path(&null_oid, oldpath);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), oldpath);
                return -1;
@@@ -77,7 -93,7 +93,7 @@@
        strbuf_addstr(&entry, "submodule.");
        strbuf_addstr(&entry, submodule->name);
        strbuf_addstr(&entry, ".path");
-       if (git_config_set_in_file_gently(".gitmodules", entry.buf, newpath) < 0) {
+       if (git_config_set_in_file_gently(GITMODULES_FILE, entry.buf, newpath) < 0) {
                /* Maybe the user already did that, don't error out here */
                warning(_("Could not update .gitmodules entry %s"), entry.buf);
                strbuf_release(&entry);
@@@ -97,20 -113,20 +113,20 @@@ int remove_path_from_gitmodules(const c
        struct strbuf sect = STRBUF_INIT;
        const struct submodule *submodule;
  
-       if (!file_exists(".gitmodules")) /* Do nothing without .gitmodules */
+       if (!file_exists(GITMODULES_FILE)) /* Do nothing without .gitmodules */
                return -1;
  
-       if (gitmodules_is_unmerged)
+       if (is_gitmodules_unmerged(&the_index))
                die(_("Cannot change unmerged .gitmodules, resolve merge conflicts first"));
  
 -      submodule = submodule_from_path(null_sha1, path);
 +      submodule = submodule_from_path(&null_oid, path);
        if (!submodule || !submodule->name) {
                warning(_("Could not find section in .gitmodules where path=%s"), path);
                return -1;
        }
        strbuf_addstr(&sect, "submodule.");
        strbuf_addstr(&sect, submodule->name);
-       if (git_config_rename_section_in_file(".gitmodules", sect.buf, NULL) < 0) {
+       if (git_config_rename_section_in_file(GITMODULES_FILE, sect.buf, NULL) < 0) {
                /* Maybe the user already did that, don't error out here */
                warning(_("Could not remove .gitmodules entry for %s"), path);
                strbuf_release(&sect);
  
  void stage_updated_gitmodules(void)
  {
-       if (add_file_to_cache(".gitmodules", 0))
+       if (add_file_to_cache(GITMODULES_FILE, 0))
                die(_("staging updated .gitmodules failed"));
  }
  
@@@ -147,11 -163,11 +163,11 @@@ done
  void set_diffopt_flags_from_submodule_config(struct diff_options *diffopt,
                                             const char *path)
  {
 -      const struct submodule *submodule = submodule_from_path(null_sha1, path);
 +      const struct submodule *submodule = submodule_from_path(&null_oid, path);
        if (submodule) {
                if (submodule->ignore)
                        handle_ignore_submodules_arg(diffopt, submodule->ignore);
-               else if (gitmodules_is_unmerged)
+               else if (is_gitmodules_unmerged(&the_index))
                        DIFF_OPT_SET(diffopt, IGNORE_SUBMODULES);
        }
  }
  /* For loading from the .gitmodules file. */
  static int git_modules_config(const char *var, const char *value, void *cb)
  {
-       if (!strcmp(var, "submodule.fetchjobs")) {
-               parallel_jobs = git_config_int(var, value);
-               if (parallel_jobs < 0)
-                       die(_("negative values not allowed for submodule.fetchJobs"));
-               return 0;
-       } else if (starts_with(var, "submodule."))
+       if (starts_with(var, "submodule."))
                return parse_submodule_config_option(var, value);
-       else if (!strcmp(var, "fetch.recursesubmodules")) {
-               config_fetch_recurse_submodules = parse_fetch_recurse_submodules_arg(var, value);
-               return 0;
-       }
        return 0;
  }
  
@@@ -223,39 -230,6 +230,6 @@@ void load_submodule_cache(void
        git_config(submodule_config, NULL);
  }
  
- void gitmodules_config(void)
- {
-       const char *work_tree = get_git_work_tree();
-       if (work_tree) {
-               struct strbuf gitmodules_path = STRBUF_INIT;
-               int pos;
-               strbuf_addstr(&gitmodules_path, work_tree);
-               strbuf_addstr(&gitmodules_path, "/.gitmodules");
-               if (read_cache() < 0)
-                       die("index file corrupt");
-               pos = cache_name_pos(".gitmodules", 11);
-               if (pos < 0) { /* .gitmodules not found or isn't merged */
-                       pos = -1 - pos;
-                       if (active_nr > pos) {  /* there is a .gitmodules */
-                               const struct cache_entry *ce = active_cache[pos];
-                               if (ce_namelen(ce) == 11 &&
-                                   !memcmp(ce->name, ".gitmodules", 11))
-                                       gitmodules_is_unmerged = 1;
-                       }
-               } else if (pos < active_nr) {
-                       struct stat st;
-                       if (lstat(".gitmodules", &st) == 0 &&
-                           ce_match_stat(active_cache[pos], &st, 0) & DATA_CHANGED)
-                               gitmodules_is_modified = 1;
-               }
-               if (!gitmodules_is_unmerged)
-                       git_config_from_file(git_modules_config,
-                               gitmodules_path.buf, NULL);
-               strbuf_release(&gitmodules_path);
-       }
- }
  static int gitmodules_cb(const char *var, const char *value, void *data)
  {
        struct repository *repo = data;
  
  void repo_read_gitmodules(struct repository *repo)
  {
-       char *gitmodules_path = repo_worktree_path(repo, ".gitmodules");
+       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);
+       }
+ }
  
-       git_config_from_file(gitmodules_cb, gitmodules_path, repo);
-       free(gitmodules_path);
+ void gitmodules_config(void)
+ {
+       repo_read_gitmodules(the_repository);
  }
  
 -void gitmodules_config_sha1(const unsigned char *commit_sha1)
 +void gitmodules_config_oid(const struct object_id *commit_oid)
  {
        struct strbuf rev = STRBUF_INIT;
 -      unsigned char sha1[20];
 +      struct object_id oid;
  
 -      if (gitmodule_sha1_from_commit(commit_sha1, sha1, &rev)) {
 -              git_config_from_blob_sha1(git_modules_config, rev.buf,
 -                                        sha1, NULL);
 +      if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
 +              git_config_from_blob_oid(submodule_config, rev.buf,
 +                                       &oid, NULL);
        }
        strbuf_release(&rev);
  }
@@@ -293,7 -281,7 +281,7 @@@ int is_submodule_active(struct reposito
        const struct string_list *sl;
        const struct submodule *module;
  
 -      module = submodule_from_cache(repo, null_sha1, path);
 +      module = submodule_from_cache(repo, &null_oid, path);
  
        /* early return if there isn't a path->module mapping */
        if (!module)
@@@ -720,11 -708,6 +708,6 @@@ done
                clear_commit_marks(right, ~0);
  }
  
- void set_config_fetch_recurse_submodules(int value)
- {
-       config_fetch_recurse_submodules = value;
- }
  int should_update_submodules(void)
  {
        return config_update_recurse_submodules == RECURSE_SUBMODULES_ON;
@@@ -738,7 -721,7 +721,7 @@@ const struct submodule *submodule_from_
        if (!should_update_submodules())
                return NULL;
  
 -      return submodule_from_path(null_sha1, ce->name);
 +      return submodule_from_path(&null_oid, ce->name);
  }
  
  static struct oid_array *submodule_commits(struct string_list *submodules,
@@@ -1015,8 -998,7 +998,8 @@@ static int push_submodule(const char *p
   * Perform a check in the submodule to see if the remote and refspec work.
   * Die if the submodule can't be pushed.
   */
 -static void submodule_push_check(const char *path, const struct remote *remote,
 +static void submodule_push_check(const char *path, const char *head,
 +                               const struct remote *remote,
                                 const char **refspec, int refspec_nr)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
  
        argv_array_push(&cp.args, "submodule--helper");
        argv_array_push(&cp.args, "push-check");
 +      argv_array_push(&cp.args, head);
        argv_array_push(&cp.args, remote->name);
  
        for (i = 0; i < refspec_nr; i++)
@@@ -1063,20 -1044,10 +1046,20 @@@ int push_unpushed_submodules(struct oid
         * won't be propagated due to the remote being unconfigured (e.g. a URL
         * instead of a remote name).
         */
 -      if (remote->origin != REMOTE_UNCONFIGURED)
 +      if (remote->origin != REMOTE_UNCONFIGURED) {
 +              char *head;
 +              struct object_id head_oid;
 +
 +              head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
 +              if (!head)
 +                      die(_("Failed to resolve HEAD as a valid ref."));
 +
                for (i = 0; i < needs_pushing.nr; i++)
                        submodule_push_check(needs_pushing.items[i].string,
 -                                           remote, refspec, refspec_nr);
 +                                           head, remote,
 +                                           refspec, refspec_nr);
 +              free(head);
 +      }
  
        /* Actually push the submodules */
        for (i = 0; i < needs_pushing.nr; i++) {
@@@ -1182,10 -1153,11 +1165,11 @@@ struct submodule_parallel_fetch 
        const char *work_tree;
        const char *prefix;
        int command_line_option;
+       int default_option;
        int quiet;
        int result;
  };
- #define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0}
+ #define SPF_INIT {0, ARGV_ARRAY_INIT, NULL, NULL, 0, 0, 0, 0}
  
  static int get_next_submodule(struct child_process *cp,
                              struct strbuf *err, void *data, void **task_cb)
                if (!S_ISGITLINK(ce->ce_mode))
                        continue;
  
 -              submodule = submodule_from_path(null_sha1, ce->name);
 +              submodule = submodule_from_path(&null_oid, ce->name);
                if (!submodule)
 -                      submodule = submodule_from_name(null_sha1, ce->name);
 +                      submodule = submodule_from_name(&null_oid, ce->name);
  
                default_argv = "yes";
                if (spf->command_line_option == RECURSE_SUBMODULES_DEFAULT) {
                                        default_argv = "on-demand";
                                }
                        } else {
-                               if ((config_fetch_recurse_submodules == RECURSE_SUBMODULES_OFF) ||
-                                   gitmodules_is_unmerged)
+                               if (spf->default_option == RECURSE_SUBMODULES_OFF)
                                        continue;
-                               if (config_fetch_recurse_submodules == RECURSE_SUBMODULES_ON_DEMAND) {
+                               if (spf->default_option == RECURSE_SUBMODULES_ON_DEMAND) {
                                        if (!unsorted_string_list_lookup(&changed_submodule_paths, ce->name))
                                                continue;
                                        default_argv = "on-demand";
@@@ -1293,6 -1264,7 +1276,7 @@@ static int fetch_finish(int retvalue, s
  
  int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
+                              int default_option,
                               int quiet, int max_parallel_jobs)
  {
        int i;
  
        spf.work_tree = get_git_work_tree();
        spf.command_line_option = command_line_option;
+       spf.default_option = default_option;
        spf.quiet = quiet;
        spf.prefix = prefix;
  
        argv_array_push(&spf.args, "--recurse-submodules-default");
        /* default value, "--submodule-prefix" and its value are added later */
  
-       if (max_parallel_jobs < 0)
-               max_parallel_jobs = parallel_jobs;
        calculate_changed_submodule_paths();
        run_processes_parallel(max_parallel_jobs,
                               get_next_submodule,
@@@ -1582,7 -1552,7 +1564,7 @@@ int submodule_move_head(const char *pat
        if (old && !is_submodule_populated_gently(path, error_code_ptr))
                return 0;
  
 -      sub = submodule_from_path(null_sha1, path);
 +      sub = submodule_from_path(&null_oid, path);
  
        if (!sub)
                die("BUG: could not get submodule information for '%s'", path);
@@@ -1837,11 -1807,6 +1819,6 @@@ int merge_submodule(struct object_id *r
        return 0;
  }
  
- int parallel_submodules(void)
- {
-       return parallel_jobs;
- }
  /*
   * Embeds a single submodules git directory into the superprojects git dir,
   * non recursively.
@@@ -1864,7 -1829,7 +1841,7 @@@ static void relocate_single_git_dir_int
  
        real_old_git_dir = real_pathdup(old_git_dir, 1);
  
 -      sub = submodule_from_path(null_sha1, path);
 +      sub = submodule_from_path(&null_oid, path);
        if (!sub)
                die(_("could not lookup name for submodule '%s'"), path);
  
@@@ -1920,7 -1885,7 +1897,7 @@@ void absorb_git_dir_into_superproject(c
                * superproject did not rewrite the git file links yet,
                * fix it now.
                */
 -              sub = submodule_from_path(null_sha1, path);
 +              sub = submodule_from_path(&null_oid, path);
                if (!sub)
                        die(_("could not lookup name for submodule '%s'"), path);
                connect_work_tree_and_git_dir(path,
@@@ -2063,7 -2028,7 +2040,7 @@@ int submodule_to_gitdir(struct strbuf *
        }
        if (!is_git_directory(buf->buf)) {
                gitmodules_config();
 -              sub = submodule_from_path(null_sha1, submodule);
 +              sub = submodule_from_path(&null_oid, submodule);
                if (!sub) {
                        ret = -1;
                        goto cleanup;
diff --combined submodule.h
index f1aa3ffeb19e4e477295b66f85ab4cb85d24437e,8022faa591f0d35d57189e50670ef28f66134d86..e402b004ff0a7d983d196eb1fc0e34bdd2bacb93
@@@ -33,7 -33,8 +33,8 @@@ struct submodule_update_strategy 
  };
  #define SUBMODULE_UPDATE_STRATEGY_INIT {SM_UPDATE_UNSPECIFIED, NULL}
  
- extern int is_staging_gitmodules_ok(void);
+ extern int is_gitmodules_unmerged(const struct index_state *istate);
+ extern int is_staging_gitmodules_ok(const struct index_state *istate);
  extern int update_path_in_gitmodules(const char *oldpath, const char *newpath);
  extern int remove_path_from_gitmodules(const char *path);
  extern void stage_updated_gitmodules(void);
@@@ -48,7 -49,7 +49,7 @@@ int option_parse_recurse_submodules_wor
  void load_submodule_cache(void);
  extern void gitmodules_config(void);
  extern void repo_read_gitmodules(struct repository *repo);
 -extern void gitmodules_config_sha1(const unsigned char *commit_sha1);
 +extern void gitmodules_config_oid(const struct object_id *commit_oid);
  extern int is_submodule_active(struct repository *repo, const char *path);
  /*
   * Determine if a submodule has been populated at a given 'path' by checking if
@@@ -76,7 -77,6 +77,6 @@@ extern void show_submodule_inline_diff(
                unsigned dirty_submodule, const char *meta,
                const char *del, const char *add, const char *reset,
                const struct diff_options *opt);
- extern void set_config_fetch_recurse_submodules(int value);
  /* Check if we want to update any submodule.*/
  extern int should_update_submodules(void);
  /*
@@@ -87,6 -87,7 +87,7 @@@ extern const struct submodule *submodul
  extern void check_for_new_submodule_commits(struct object_id *oid);
  extern int fetch_populated_submodules(const struct argv_array *options,
                               const char *prefix, int command_line_option,
+                              int default_option,
                               int quiet, int max_parallel_jobs);
  extern unsigned is_submodule_modified(const char *path, int ignore_untracked);
  extern int submodule_uses_gitfile(const char *path);
@@@ -112,7 -113,6 +113,6 @@@ extern int push_unpushed_submodules(str
                                    const struct string_list *push_options,
                                    int dry_run);
  extern void connect_work_tree_and_git_dir(const char *work_tree, const char *git_dir);
- extern int parallel_submodules(void);
  /*
   * Given a submodule path (as in the index), return the repository
   * path of that submodule in 'buf'. Return -1 on error or when the
diff --combined unpack-trees.c
index 862cfce661e57e50f7c6030dd5a8eda0add0cca5,05335fe5bf285f575878440397d641137a8abbd7..38000ac8fad4e8cb626b74bf80197e070084246e
@@@ -286,7 -286,7 +286,7 @@@ static void reload_gitmodules_file(stru
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
                if (ce->ce_flags & CE_UPDATE) {
-                       int r = strcmp(ce->name, ".gitmodules");
+                       int r = strcmp(ce->name, GITMODULES_FILE);
                        if (r < 0)
                                continue;
                        else if (r == 0) {
@@@ -380,7 -380,6 +380,7 @@@ static int check_updates(struct unpack_
        if (should_update_submodules() && o->update && !o->dry_run)
                reload_gitmodules_file(index, &state);
  
 +      enable_delayed_checkout(&state);
        for (i = 0; i < index->cache_nr; i++) {
                struct cache_entry *ce = index->cache[i];
  
                        }
                }
        }
 +      errs |= finish_delayed_checkout(&state);
        stop_progress(&progress);
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKIN, NULL);