Sync with Git 2.14.4
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:20:22 +0000 (11:20 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:20:22 +0000 (11:20 -0700)
* maint-2.14:
Git 2.14.5
submodule-config: ban submodule paths that start with a dash
submodule-config: ban submodule urls that start with dash
submodule--helper: use "--" to signal end of clone options

1  2 
builtin/submodule--helper.c
submodule-config.c
index 77940499b0c0670798a19548c023f7c27ddfd327,676cfed770f3cce91b4f5eebcb88d17b7f2056b2..30e0bb876cffa1884267f616e0c31cb605f67019
@@@ -17,8 -17,9 +17,8 @@@
  static char *get_default_remote(void)
  {
        char *dest = NULL, *ret;
 -      unsigned char sha1[20];
        struct strbuf sb = STRBUF_INIT;
 -      const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 +      const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
  
        if (!refname)
                die(_("No such ref: %s"), "HEAD");
@@@ -274,6 -275,8 +274,6 @@@ static void module_list_active(struct m
        int i;
        struct module_list active_modules = MODULE_LIST_INIT;
  
 -      gitmodules_config();
 -
        for (i = 0; i < list->nr; i++) {
                const struct cache_entry *ce = list->entries[i];
  
@@@ -334,6 -337,9 +334,6 @@@ static void init_submodule(const char *
        struct strbuf sb = STRBUF_INIT;
        char *upd = NULL, *url = NULL, *displaypath;
  
 -      /* Only loads from .gitmodules, no overlay with .git/config */
 -      gitmodules_config();
 -
        if (prefix && get_super_prefix())
                die("BUG: cannot have prefix and superprefix");
        else if (prefix)
        } 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"),
@@@ -469,7 -475,8 +469,7 @@@ static int module_name(int argc, const 
        if (argc != 2)
                usage(_("git submodule--helper name <path>"));
  
 -      gitmodules_config();
 -      sub = submodule_from_path(null_sha1, argv[1]);
 +      sub = submodule_from_path(&null_oid, argv[1]);
  
        if (!sub)
                die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@@ -503,6 -510,7 +503,7 @@@ static int clone_submodule(const char *
        if (gitdir && *gitdir)
                argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
  
+       argv_array_push(&cp.args, "--");
        argv_array_push(&cp.args, url);
        argv_array_push(&cp.args, path);
  
@@@ -773,10 -781,6 +774,10 @@@ static int prepare_to_clone_next_submod
                                           struct strbuf *out)
  {
        const struct submodule *sub = NULL;
 +      const char *url = NULL;
 +      const char *update_string;
 +      enum submodule_update_type update_type;
 +      char *key;
        struct strbuf displaypath_sb = STRBUF_INIT;
        struct strbuf sb = STRBUF_INIT;
        const char *displaypath = NULL;
                goto cleanup;
        }
  
 -      sub = submodule_from_path(null_sha1, ce->name);
 +      sub = submodule_from_path(&null_oid, ce->name);
  
        if (suc->recursive_prefix)
                displaypath = relative_path(suc->recursive_prefix,
                goto cleanup;
        }
  
 +      key = xstrfmt("submodule.%s.update", sub->name);
 +      if (!repo_config_get_string_const(the_repository, key, &update_string)) {
 +              update_type = parse_submodule_update_type(update_string);
 +      } else {
 +              update_type = sub->update_strategy.type;
 +      }
 +      free(key);
 +
        if (suc->update.type == SM_UPDATE_NONE
            || (suc->update.type == SM_UPDATE_UNSPECIFIED
 -              && sub->update_strategy.type == SM_UPDATE_NONE)) {
 +              && update_type == SM_UPDATE_NONE)) {
                strbuf_addf(out, _("Skipping submodule '%s'"), displaypath);
                strbuf_addch(out, '\n');
                goto cleanup;
                goto cleanup;
        }
  
 +      strbuf_reset(&sb);
 +      strbuf_addf(&sb, "submodule.%s.url", sub->name);
 +      if (repo_config_get_string_const(the_repository, sb.buf, &url))
 +              url = sub->url;
 +
        strbuf_reset(&sb);
        strbuf_addf(&sb, "%s/.git", ce->name);
        needs_cloning = !file_exists(sb.buf);
                argv_array_push(&child->args, "--depth=1");
        argv_array_pushl(&child->args, "--path", sub->path, NULL);
        argv_array_pushl(&child->args, "--name", sub->name, NULL);
 -      argv_array_pushl(&child->args, "--url", sub->url, NULL);
 +      argv_array_pushl(&child->args, "--url", url, NULL);
        if (suc->references.nr) {
                struct string_list_item *item;
                for_each_string_list_item(item, &suc->references)
@@@ -970,19 -961,10 +971,19 @@@ static int update_clone_task_finished(i
        return 0;
  }
  
 +static int gitmodules_update_clone_config(const char *var, const char *value,
 +                                        void *cb)
 +{
 +      int *max_jobs = cb;
 +      if (!strcmp(var, "submodule.fetchjobs"))
 +              *max_jobs = parse_submodule_fetchjobs(var, value);
 +      return 0;
 +}
 +
  static int update_clone(int argc, const char **argv, const char *prefix)
  {
        const char *update = NULL;
 -      int max_jobs = -1;
 +      int max_jobs = 1;
        struct string_list_item *item;
        struct pathspec pathspec;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
        };
        suc.prefix = prefix;
  
 +      config_from_gitmodules(gitmodules_update_clone_config, &max_jobs);
 +      git_config(gitmodules_update_clone_config, &max_jobs);
 +
        argc = parse_options(argc, argv, prefix, module_update_clone_options,
                             git_submodule_helper_usage, 0);
  
        if (pathspec.nr)
                suc.warn_if_uninitialized = 1;
  
 -      /* Overlay the parsed .gitmodules file with .git/config */
 -      gitmodules_config();
 -      git_config(submodule_config, NULL);
 -
 -      if (max_jobs < 0)
 -              max_jobs = parallel_submodules();
 -
        run_processes_parallel(max_jobs,
                               update_clone_get_next_task,
                               update_clone_start_failure,
@@@ -1072,23 -1058,19 +1073,23 @@@ static int resolve_relative_path(int ar
  static const char *remote_submodule_branch(const char *path)
  {
        const struct submodule *sub;
 -      gitmodules_config();
 -      git_config(submodule_config, NULL);
 +      const char *branch = NULL;
 +      char *key;
  
 -      sub = submodule_from_path(null_sha1, path);
 +      sub = submodule_from_path(&null_oid, path);
        if (!sub)
                return NULL;
  
 -      if (!sub->branch)
 +      key = xstrfmt("submodule.%s.branch", sub->name);
 +      if (repo_config_get_string_const(the_repository, key, &branch))
 +              branch = sub->branch;
 +      free(key);
 +
 +      if (!branch)
                return "master";
  
 -      if (!strcmp(sub->branch, ".")) {
 -              unsigned char sha1[20];
 -              const char *refname = resolve_ref_unsafe("HEAD", 0, sha1, NULL);
 +      if (!strcmp(branch, ".")) {
 +              const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, NULL);
  
                if (!refname)
                        die(_("No such ref: %s"), "HEAD");
                return refname;
        }
  
 -      return sub->branch;
 +      return branch;
  }
  
  static int resolve_remote_submodule_branch(int argc, const char **argv,
@@@ -1187,7 -1169,6 +1188,7 @@@ static int push_check(int argc, const c
                                                break;
                                        die("HEAD does not match the named branch in the superproject");
                                }
 +                              /* fallthrough */
                        default:
                                die("src refspec '%s' must name a ref",
                                    rs->src);
@@@ -1224,6 -1205,9 +1225,6 @@@ static int absorb_git_dirs(int argc, co
        argc = parse_options(argc, argv, prefix, embed_gitdir_options,
                             git_submodule_helper_usage, 0);
  
 -      gitmodules_config();
 -      git_config(submodule_config, NULL);
 -
        if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
                return 1;
  
@@@ -1239,6 -1223,8 +1240,6 @@@ static int is_active(int argc, const ch
        if (argc != 2)
                die("submodule--helper is-active takes exactly 1 argument");
  
 -      gitmodules_config();
 -
        return !is_submodule_active(the_repository, argv[1]);
  }
  
diff --combined submodule-config.c
index aa026417678ff51117fcd1151aeb16d6719a1bb5,774fb105440a431d741124278987151ac2ea9166..3414fa1c1b1e67387a5fc0f1f72ad82eb1651497
@@@ -18,7 -18,6 +18,7 @@@ struct submodule_cache 
        struct hashmap for_path;
        struct hashmap for_name;
        unsigned initialized:1;
 +      unsigned gitmodules_read:1;
  };
  
  /*
@@@ -36,25 -35,19 +36,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);
  }
@@@ -66,8 -59,8 +66,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;
  }
  
@@@ -100,7 -93,6 +100,7 @@@ static void submodule_cache_clear(struc
        hashmap_free(&cache->for_path, 1);
        hashmap_free(&cache->for_name, 1);
        cache->initialized = 0;
 +      cache->gitmodules_read = 0;
  }
  
  void submodule_cache_free(struct submodule_cache *cache)
@@@ -271,7 -263,7 +271,7 @@@ static struct submodule *lookup_or_crea
  static int parse_fetch_recurse(const char *opt, const char *arg,
                               int die_on_error)
  {
 -      switch (git_config_maybe_bool(opt, arg)) {
 +      switch (git_parse_maybe_bool(arg)) {
        case 1:
                return RECURSE_SUBMODULES_ON;
        case 0:
        }
  }
  
 +int parse_submodule_fetchjobs(const char *var, const char *value)
 +{
 +      int fetchjobs = git_config_int(var, value);
 +      if (fetchjobs < 0)
 +              die(_("negative values not allowed for submodule.fetchjobs"));
 +      return fetchjobs;
 +}
 +
  int parse_fetch_recurse_submodules_arg(const char *opt, const char *arg)
  {
        return parse_fetch_recurse(opt, arg, 1);
@@@ -324,7 -308,7 +324,7 @@@ int option_fetch_parse_recurse_submodul
  static int parse_update_recurse(const char *opt, const char *arg,
                                int die_on_error)
  {
 -      switch (git_config_maybe_bool(opt, arg)) {
 +      switch (git_parse_maybe_bool(arg)) {
        case 1:
                return RECURSE_SUBMODULES_ON;
        case 0:
@@@ -344,7 -328,7 +344,7 @@@ int parse_update_recurse_submodules_arg
  static int parse_push_recurse(const char *opt, const char *arg,
                               int die_on_error)
  {
 -      switch (git_config_maybe_bool(opt, arg)) {
 +      switch (git_parse_maybe_bool(arg)) {
        case 1:
                /* There's no simple "on" value when pushing */
                if (die_on_error)
@@@ -383,6 -367,12 +383,12 @@@ static void warn_multiple_config(const 
                        commit_string, name, option);
  }
  
+ static void warn_command_line_option(const char *var, const char *value)
+ {
+       warning(_("ignoring '%s' which may be interpreted as"
+                 " a command-line option: %s"), var, value);
+ }
  struct parse_config_parameter {
        struct submodule_cache *cache;
        const unsigned char *treeish_name;
@@@ -408,6 -398,8 +414,8 @@@ static int parse_config(const char *var
        if (!strcmp(item.buf, "path")) {
                if (!value)
                        ret = config_error_nonbool(var);
+               else if (looks_like_command_line_option(value))
+                       warn_command_line_option(var, value);
                else if (!me->overwrite && submodule->path)
                        warn_multiple_config(me->treeish_name, submodule->name,
                                        "path");
        } else if (!strcmp(item.buf, "url")) {
                if (!value) {
                        ret = config_error_nonbool(var);
+               } else if (looks_like_command_line_option(value)) {
+                       warn_command_line_option(var, value);
                } else if (!me->overwrite && submodule->url) {
                        warn_multiple_config(me->treeish_name, submodule->name,
                                        "url");
        return ret;
  }
  
 -int gitmodule_sha1_from_commit(const unsigned char *treeish_name,
 -                                    unsigned char *gitmodules_sha1,
 -                                    struct strbuf *rev)
 +static int gitmodule_oid_from_commit(const struct object_id *treeish_name,
 +                                   struct object_id *gitmodules_oid,
 +                                   struct strbuf *rev)
  {
        int ret = 0;
  
 -      if (is_null_sha1(treeish_name)) {
 -              hashclr(gitmodules_sha1);
 +      if (is_null_oid(treeish_name)) {
 +              oidclr(gitmodules_oid);
                return 1;
        }
  
 -      strbuf_addf(rev, "%s:.gitmodules", sha1_to_hex(treeish_name));
 -      if (get_sha1(rev->buf, gitmodules_sha1) >= 0)
 +      strbuf_addf(rev, "%s:.gitmodules", oid_to_hex(treeish_name));
 +      if (get_oid(rev->buf, gitmodules_oid) >= 0)
                ret = 1;
  
        return ret;
   * revisions.
   */
  static const struct submodule *config_from(struct submodule_cache *cache,
 -              const unsigned char *treeish_name, const char *key,
 +              const struct object_id *treeish_name, const char *key,
                enum lookup_type lookup_type)
  {
        struct strbuf rev = STRBUF_INIT;
        unsigned long config_size;
        char *config = NULL;
 -      unsigned char sha1[20];
 +      struct object_id oid;
        enum object_type type;
        const struct submodule *submodule = NULL;
        struct parse_config_parameter parameter;
                return entry->config;
        }
  
 -      if (!gitmodule_sha1_from_commit(treeish_name, sha1, &rev))
 +      if (!gitmodule_oid_from_commit(treeish_name, &oid, &rev))
                goto out;
  
        switch (lookup_type) {
        case lookup_name:
 -              submodule = cache_lookup_name(cache, sha1, key);
 +              submodule = cache_lookup_name(cache, oid.hash, key);
                break;
        case lookup_path:
 -              submodule = cache_lookup_path(cache, sha1, key);
 +              submodule = cache_lookup_path(cache, oid.hash, key);
                break;
        }
        if (submodule)
                goto out;
  
 -      config = read_sha1_file(sha1, &type, &config_size);
 +      config = read_sha1_file(oid.hash, &type, &config_size);
        if (!config || type != OBJ_BLOB)
                goto out;
  
        /* fill the submodule config into the cache */
        parameter.cache = cache;
 -      parameter.treeish_name = treeish_name;
 -      parameter.gitmodules_sha1 = sha1;
 +      parameter.treeish_name = treeish_name->hash;
 +      parameter.gitmodules_sha1 = oid.hash;
        parameter.overwrite = 0;
        git_config_from_mem(parse_config, CONFIG_ORIGIN_SUBMODULE_BLOB, rev.buf,
                        config, config_size, &parameter);
  
        switch (lookup_type) {
        case lookup_name:
 -              return cache_lookup_name(cache, sha1, key);
 +              return cache_lookup_name(cache, oid.hash, key);
        case lookup_path:
 -              return cache_lookup_path(cache, sha1, key);
 +              return cache_lookup_path(cache, oid.hash, key);
        default:
                return NULL;
        }
@@@ -591,11 -585,13 +601,11 @@@ static void submodule_cache_check_init(
        submodule_cache_init(repo->submodule_cache);
  }
  
 -int submodule_config_option(struct repository *repo,
 -                          const char *var, const char *value)
 +static int gitmodules_cb(const char *var, const char *value, void *data)
  {
 +      struct repository *repo = data;
        struct parse_config_parameter parameter;
  
 -      submodule_cache_check_init(repo);
 -
        parameter.cache = repo->submodule_cache;
        parameter.treeish_name = NULL;
        parameter.gitmodules_sha1 = null_sha1;
        return parse_config(var, value, &parameter);
  }
  
 -int parse_submodule_config_option(const char *var, const char *value)
 +void repo_read_gitmodules(struct repository *repo)
  {
 -      return submodule_config_option(the_repository, var, value);
 +      submodule_cache_check_init(repo);
 +
 +      if (repo->worktree) {
 +              char *gitmodules;
 +
 +              if (repo_read_index(repo) < 0)
 +                      return;
 +
 +              gitmodules = repo_worktree_path(repo, GITMODULES_FILE);
 +
 +              if (!is_gitmodules_unmerged(repo->index))
 +                      git_config_from_file(gitmodules_cb, gitmodules, repo);
 +
 +              free(gitmodules);
 +      }
 +
 +      repo->submodule_cache->gitmodules_read = 1;
  }
  
 -const struct submodule *submodule_from_name(const unsigned char *treeish_name,
 -              const char *name)
 +void gitmodules_config_oid(const struct object_id *commit_oid)
  {
 +      struct strbuf rev = STRBUF_INIT;
 +      struct object_id oid;
 +
        submodule_cache_check_init(the_repository);
 +
 +      if (gitmodule_oid_from_commit(commit_oid, &oid, &rev)) {
 +              git_config_from_blob_oid(gitmodules_cb, rev.buf,
 +                                       &oid, the_repository);
 +      }
 +      strbuf_release(&rev);
 +
 +      the_repository->submodule_cache->gitmodules_read = 1;
 +}
 +
 +static void gitmodules_read_check(struct repository *repo)
 +{
 +      submodule_cache_check_init(repo);
 +
 +      /* read the repo's .gitmodules file if it hasn't been already */
 +      if (!repo->submodule_cache->gitmodules_read)
 +              repo_read_gitmodules(repo);
 +}
 +
 +const struct submodule *submodule_from_name(const struct object_id *treeish_name,
 +              const char *name)
 +{
 +      gitmodules_read_check(the_repository);
        return config_from(the_repository->submodule_cache, treeish_name, name, lookup_name);
  }
  
 -const struct submodule *submodule_from_path(const unsigned char *treeish_name,
 +const struct submodule *submodule_from_path(const struct object_id *treeish_name,
                const char *path)
  {
 -      submodule_cache_check_init(the_repository);
 +      gitmodules_read_check(the_repository);
        return config_from(the_repository->submodule_cache, treeish_name, path, lookup_path);
  }
  
  const struct submodule *submodule_from_cache(struct repository *repo,
 -                                           const unsigned char *treeish_name,
 +                                           const struct object_id *treeish_name,
                                             const char *key)
  {
 -      submodule_cache_check_init(repo);
 +      gitmodules_read_check(repo);
        return config_from(repo->submodule_cache, treeish_name,
                           key, lookup_path);
  }