Sync with 2.19.1
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:53:39 +0000 (11:53 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:53:39 +0000 (11:53 -0700)
* maint:
Git 2.19.1
Git 2.18.1
Git 2.17.2
fsck: detect submodule paths starting with dash
fsck: detect submodule urls starting with dash
Git 2.16.5
Git 2.15.3
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 40844870cfb158b014ee5ea10517c27349e09133,5e6f2db4cdbcf9e88ddfc1890359f7f2f86b2cd2..247881189fde2a910bbd993342bb74fe10e06b0e
@@@ -1233,6 -1233,7 +1233,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);
  
@@@ -1443,72 -1444,6 +1444,72 @@@ static int module_clone(int argc, cons
        return 0;
  }
  
 +static void determine_submodule_update_strategy(struct repository *r,
 +                                              int just_cloned,
 +                                              const char *path,
 +                                              const char *update,
 +                                              struct submodule_update_strategy *out)
 +{
 +      const struct submodule *sub = submodule_from_path(r, &null_oid, path);
 +      char *key;
 +      const char *val;
 +
 +      key = xstrfmt("submodule.%s.update", sub->name);
 +
 +      if (update) {
 +              trace_printf("parsing update");
 +              if (parse_submodule_update_strategy(update, out) < 0)
 +                      die(_("Invalid update mode '%s' for submodule path '%s'"),
 +                              update, path);
 +      } else if (!repo_config_get_string_const(r, key, &val)) {
 +              if (parse_submodule_update_strategy(val, out) < 0)
 +                      die(_("Invalid update mode '%s' configured for submodule path '%s'"),
 +                              val, path);
 +      } else if (sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
 +              trace_printf("loaded thing");
 +              out->type = sub->update_strategy.type;
 +              out->command = sub->update_strategy.command;
 +      } else
 +              out->type = SM_UPDATE_CHECKOUT;
 +
 +      if (just_cloned &&
 +          (out->type == SM_UPDATE_MERGE ||
 +           out->type == SM_UPDATE_REBASE ||
 +           out->type == SM_UPDATE_NONE))
 +              out->type = SM_UPDATE_CHECKOUT;
 +
 +      free(key);
 +}
 +
 +static int module_update_module_mode(int argc, const char **argv, const char *prefix)
 +{
 +      const char *path, *update = NULL;
 +      int just_cloned;
 +      struct submodule_update_strategy update_strategy = { .type = SM_UPDATE_CHECKOUT };
 +
 +      if (argc < 3 || argc > 4)
 +              die("submodule--helper update-module-clone expects <just-cloned> <path> [<update>]");
 +
 +      just_cloned = git_config_int("just_cloned", argv[1]);
 +      path = argv[2];
 +
 +      if (argc == 4)
 +              update = argv[3];
 +
 +      determine_submodule_update_strategy(the_repository,
 +                                          just_cloned, path, update,
 +                                          &update_strategy);
 +      fputs(submodule_strategy_to_string(&update_strategy), stdout);
 +
 +      return 0;
 +}
 +
 +struct update_clone_data {
 +      const struct submodule *sub;
 +      struct object_id oid;
 +      unsigned just_cloned;
 +};
 +
  struct submodule_update_clone {
        /* index into 'list', the list of submodules to look into for cloning */
        int current;
        const char *recursive_prefix;
        const char *prefix;
  
 -      /* Machine-readable status lines to be consumed by git-submodule.sh */
 -      struct string_list projectlines;
 +      /* to be consumed by git-submodule.sh */
 +      struct update_clone_data *update_clone;
 +      int update_clone_nr; int update_clone_alloc;
  
        /* If we want to stop as fast as possible and return an error */
        unsigned quickstop : 1;
        /* failed clones to be retried again */
        const struct cache_entry **failed_clones;
        int failed_clones_nr, failed_clones_alloc;
 +
 +      int max_jobs;
  };
  #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
        SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
        NULL, NULL, NULL, \
 -      STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
 +      NULL, 0, 0, 0, NULL, 0, 0, 0}
  
  
  static void next_submodule_warn_missing(struct submodule_update_clone *suc,
@@@ -1638,12 -1570,11 +1639,12 @@@ static int prepare_to_clone_next_submod
        strbuf_addf(&sb, "%s/.git", ce->name);
        needs_cloning = !file_exists(sb.buf);
  
 -      strbuf_reset(&sb);
 -      strbuf_addf(&sb, "%06o %s %d %d\t%s\n", ce->ce_mode,
 -                      oid_to_hex(&ce->oid), ce_stage(ce),
 -                      needs_cloning, ce->name);
 -      string_list_append(&suc->projectlines, sb.buf);
 +      ALLOC_GROW(suc->update_clone, suc->update_clone_nr + 1,
 +                 suc->update_clone_alloc);
 +      oidcpy(&suc->update_clone[suc->update_clone_nr].oid, &ce->oid);
 +      suc->update_clone[suc->update_clone_nr].just_cloned = needs_cloning;
 +      suc->update_clone[suc->update_clone_nr].sub = sub;
 +      suc->update_clone_nr++;
  
        if (!needs_cloning)
                goto cleanup;
@@@ -1784,44 -1715,11 +1785,44 @@@ static int git_update_clone_config(cons
        return 0;
  }
  
 +static void update_submodule(struct update_clone_data *ucd)
 +{
 +      fprintf(stdout, "dummy %s %d\t%s\n",
 +              oid_to_hex(&ucd->oid),
 +              ucd->just_cloned,
 +              ucd->sub->path);
 +}
 +
 +static int update_submodules(struct submodule_update_clone *suc)
 +{
 +      int i;
 +
 +      run_processes_parallel(suc->max_jobs,
 +                             update_clone_get_next_task,
 +                             update_clone_start_failure,
 +                             update_clone_task_finished,
 +                             suc);
 +
 +      /*
 +       * We saved the output and put it out all at once now.
 +       * That means:
 +       * - the listener does not have to interleave their (checkout)
 +       *   work with our fetching.  The writes involved in a
 +       *   checkout involve more straightforward sequential I/O.
 +       * - the listener can avoid doing any work if fetching failed.
 +       */
 +      if (suc->quickstop)
 +              return 1;
 +
 +      for (i = 0; i < suc->update_clone_nr; i++)
 +              update_submodule(&suc->update_clone[i]);
 +
 +      return 0;
 +}
 +
  static int update_clone(int argc, const char **argv, const char *prefix)
  {
        const char *update = NULL;
 -      int max_jobs = 1;
 -      struct string_list_item *item;
        struct pathspec pathspec;
        struct submodule_update_clone suc = SUBMODULE_UPDATE_CLONE_INIT;
  
                OPT_STRING(0, "depth", &suc.depth, "<depth>",
                           N_("Create a shallow clone truncated to the "
                              "specified number of revisions")),
 -              OPT_INTEGER('j', "jobs", &max_jobs,
 +              OPT_INTEGER('j', "jobs", &suc.max_jobs,
                            N_("parallel jobs")),
                OPT_BOOL(0, "recommend-shallow", &suc.recommend_shallow,
                            N_("whether the initial clone should follow the shallow recommendation")),
        };
        suc.prefix = prefix;
  
 -      update_clone_config_from_gitmodules(&max_jobs);
 -      git_config(git_update_clone_config, &max_jobs);
 +      update_clone_config_from_gitmodules(&suc.max_jobs);
 +      git_config(git_update_clone_config, &suc.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;
  
 -      run_processes_parallel(max_jobs,
 -                             update_clone_get_next_task,
 -                             update_clone_start_failure,
 -                             update_clone_task_finished,
 -                             &suc);
 -
 -      /*
 -       * We saved the output and put it out all at once now.
 -       * That means:
 -       * - the listener does not have to interleave their (checkout)
 -       *   work with our fetching.  The writes involved in a
 -       *   checkout involve more straightforward sequential I/O.
 -       * - the listener can avoid doing any work if fetching failed.
 -       */
 -      if (suc.quickstop)
 -              return 1;
 -
 -      for_each_string_list_item(item, &suc.projectlines)
 -              fprintf(stdout, "%s", item->string);
 -
 -      return 0;
 +      return update_submodules(&suc);
  }
  
  static int resolve_relative_path(int argc, const char **argv, const char *prefix)
@@@ -2021,45 -1939,6 +2022,45 @@@ static int push_check(int argc, const c
        return 0;
  }
  
 +static int ensure_core_worktree(int argc, const char **argv, const char *prefix)
 +{
 +      const struct submodule *sub;
 +      const char *path;
 +      char *cw;
 +      struct repository subrepo;
 +
 +      if (argc != 2)
 +              BUG("submodule--helper connect-gitdir-workingtree <name> <path>");
 +
 +      path = argv[1];
 +
 +      sub = submodule_from_path(the_repository, &null_oid, path);
 +      if (!sub)
 +              BUG("We could get the submodule handle before?");
 +
 +      if (repo_submodule_init(&subrepo, the_repository, path))
 +              die(_("could not get a repository handle for submodule '%s'"), path);
 +
 +      if (!repo_config_get_string(&subrepo, "core.worktree", &cw)) {
 +              char *cfg_file, *abs_path;
 +              const char *rel_path;
 +              struct strbuf sb = STRBUF_INIT;
 +
 +              cfg_file = repo_git_path(&subrepo, "config");
 +
 +              abs_path = absolute_pathdup(path);
 +              rel_path = relative_path(abs_path, subrepo.gitdir, &sb);
 +
 +              git_config_set_in_file(cfg_file, "core.worktree", rel_path);
 +
 +              free(cfg_file);
 +              free(abs_path);
 +              strbuf_release(&sb);
 +      }
 +
 +      return 0;
 +}
 +
  static int absorb_git_dirs(int argc, const char **argv, const char *prefix)
  {
        int i;
@@@ -2137,9 -2016,7 +2138,9 @@@ static struct cmd_struct commands[] = 
        {"list", module_list, 0},
        {"name", module_name, 0},
        {"clone", module_clone, 0},
 +      {"update-module-mode", module_update_module_mode, 0},
        {"update-clone", update_clone, 0},
 +      {"ensure-core-worktree", ensure_core_worktree, 0},
        {"relative-path", resolve_relative_path, 0},
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
diff --combined submodule-config.c
index e04ba756d954e03f4c94785f260c2ac9af6a6f9b,0b2f1647abb935ba63e9230baf0ba7fcef95d19c..b132f7a80ba6fc692069f765caf0b92027b920d8
@@@ -45,7 -45,7 +45,7 @@@ static int config_path_cmp(const void *
        const struct submodule_entry *b = entry_or_key;
  
        return strcmp(a->config->path, b->config->path) ||
 -             oidcmp(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
 +             !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
  }
  
  static int config_name_cmp(const void *unused_cmp_data,
@@@ -57,7 -57,7 +57,7 @@@
        const struct submodule_entry *b = entry_or_key;
  
        return strcmp(a->config->name, b->config->name) ||
 -             oidcmp(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
 +             !oideq(&a->config->gitmodules_oid, &b->config->gitmodules_oid);
  }
  
  static struct submodule_cache *submodule_cache_alloc(void)
@@@ -384,6 -384,12 +384,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 struct object_id *treeish_name;
@@@ -409,6 -415,8 +415,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");