Sync with 2.15.3
authorJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:35:43 +0000 (11:35 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 27 Sep 2018 18:35:43 +0000 (11:35 -0700)
* maint-2.15:
  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

  #include "remote.h"
  #include "refs.h"
  #include "connect.h"
 +#include "revision.h"
 +#include "diffcore.h"
 +#include "diff.h"
 +
 +#define OPT_QUIET (1 << 0)
 +#define OPT_CACHED (1 << 1)
 +#define OPT_RECURSIVE (1 << 2)
 +
 +typedef void (*each_submodule_fn)(const struct cache_entry *list_item,
 +                                void *cb_data);
  
  static char *get_default_remote(void)
  {
@@@ -229,64 -219,6 +229,64 @@@ static int resolve_relative_url_test(in
        return 0;
  }
  
 +/* the result should be freed by the caller. */
 +static char *get_submodule_displaypath(const char *path, const char *prefix)
 +{
 +      const char *super_prefix = get_super_prefix();
 +
 +      if (prefix && super_prefix) {
 +              BUG("cannot have prefix '%s' and superprefix '%s'",
 +                  prefix, super_prefix);
 +      } else if (prefix) {
 +              struct strbuf sb = STRBUF_INIT;
 +              char *displaypath = xstrdup(relative_path(path, prefix, &sb));
 +              strbuf_release(&sb);
 +              return displaypath;
 +      } else if (super_prefix) {
 +              return xstrfmt("%s%s", super_prefix, path);
 +      } else {
 +              return xstrdup(path);
 +      }
 +}
 +
 +static char *compute_rev_name(const char *sub_path, const char* object_id)
 +{
 +      struct strbuf sb = STRBUF_INIT;
 +      const char ***d;
 +
 +      static const char *describe_bare[] = { NULL };
 +
 +      static const char *describe_tags[] = { "--tags", NULL };
 +
 +      static const char *describe_contains[] = { "--contains", NULL };
 +
 +      static const char *describe_all_always[] = { "--all", "--always", NULL };
 +
 +      static const char **describe_argv[] = { describe_bare, describe_tags,
 +                                              describe_contains,
 +                                              describe_all_always, NULL };
 +
 +      for (d = describe_argv; *d; d++) {
 +              struct child_process cp = CHILD_PROCESS_INIT;
 +              prepare_submodule_repo_env(&cp.env_array);
 +              cp.dir = sub_path;
 +              cp.git_cmd = 1;
 +              cp.no_stderr = 1;
 +
 +              argv_array_push(&cp.args, "describe");
 +              argv_array_pushv(&cp.args, *d);
 +              argv_array_push(&cp.args, object_id);
 +
 +              if (!capture_command(&cp, &sb, 0)) {
 +                      strbuf_strip_suffix(&sb, "\n");
 +                      return strbuf_detach(&sb, NULL);
 +              }
 +      }
 +
 +      strbuf_release(&sb);
 +      return NULL;
 +}
 +
  struct module_list {
        const struct cache_entry **entries;
        int alloc, nr;
@@@ -396,29 -328,21 +396,29 @@@ static int module_list(int argc, const 
        return 0;
  }
  
 -static void init_submodule(const char *path, const char *prefix, int quiet)
 +static void for_each_listed_submodule(const struct module_list *list,
 +                                    each_submodule_fn fn, void *cb_data)
 +{
 +      int i;
 +      for (i = 0; i < list->nr; i++)
 +              fn(list->entries[i], cb_data);
 +}
 +
 +struct init_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define INIT_CB_INIT { NULL, 0 }
 +
 +static void init_submodule(const char *path, const char *prefix,
 +                         unsigned int flags)
  {
        const struct submodule *sub;
        struct strbuf sb = STRBUF_INIT;
        char *upd = NULL, *url = NULL, *displaypath;
  
 -      if (prefix && get_super_prefix())
 -              die("BUG: cannot have prefix and superprefix");
 -      else if (prefix)
 -              displaypath = xstrdup(relative_path(path, prefix, &sb));
 -      else if (get_super_prefix()) {
 -              strbuf_addf(&sb, "%s%s", get_super_prefix(), path);
 -              displaypath = strbuf_detach(&sb, NULL);
 -      } else
 -              displaypath = xstrdup(path);
 +      displaypath = get_submodule_displaypath(path, prefix);
  
        sub = submodule_from_path(&null_oid, path);
  
         * Set active flag for the submodule being initialized
         */
        if (!is_submodule_active(the_repository, path)) {
 -              strbuf_reset(&sb);
                strbuf_addf(&sb, "submodule.%s.active", sub->name);
                git_config_set_gently(sb.buf, "true");
 +              strbuf_reset(&sb);
        }
  
        /*
         * To look up the url in .git/config, we must not fall back to
         * .gitmodules, so look it up directly.
         */
 -      strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.url", sub->name);
        if (git_config_get_string(sb.buf, &url)) {
                if (!sub->url)
                if (git_config_set_gently(sb.buf, url))
                        die(_("Failed to register url for submodule path '%s'"),
                            displaypath);
 -              if (!quiet)
 +              if (!(flags & OPT_QUIET))
                        fprintf(stderr,
                                _("Submodule '%s' (%s) registered for path '%s'\n"),
                                sub->name, url, displaypath);
        }
 +      strbuf_reset(&sb);
  
        /* Copy "update" setting when it is not set yet */
 -      strbuf_reset(&sb);
        strbuf_addf(&sb, "submodule.%s.update", sub->name);
        if (git_config_get_string(sb.buf, &upd) &&
            sub->update_strategy.type != SM_UPDATE_UNSPECIFIED) {
        free(upd);
  }
  
 +static void init_submodule_cb(const struct cache_entry *list_item, void *cb_data)
 +{
 +      struct init_cb *info = cb_data;
 +      init_submodule(list_item->name, info->prefix, info->flags);
 +}
 +
  static int module_init(int argc, const char **argv, const char *prefix)
  {
 +      struct init_cb info = INIT_CB_INIT;
        struct pathspec pathspec;
        struct module_list list = MODULE_LIST_INIT;
        int quiet = 0;
 -      int i;
  
        struct option module_init_options[] = {
                OPT__QUIET(&quiet, N_("Suppress output for initializing a submodule")),
        if (!argc && git_config_get_value_multi("submodule.active"))
                module_list_active(&list);
  
 -      for (i = 0; i < list.nr; i++)
 -              init_submodule(list.entries[i]->name, prefix, quiet);
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +
 +      for_each_listed_submodule(&list, init_submodule_cb, &info);
 +
 +      return 0;
 +}
 +
 +struct status_cb {
 +      const char *prefix;
 +      unsigned int flags;
 +};
 +
 +#define STATUS_CB_INIT { NULL, 0 }
 +
 +static void print_status(unsigned int flags, char state, const char *path,
 +                       const struct object_id *oid, const char *displaypath)
 +{
 +      if (flags & OPT_QUIET)
 +              return;
 +
 +      printf("%c%s %s", state, oid_to_hex(oid), displaypath);
 +
 +      if (state == ' ' || state == '+')
 +              printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
 +
 +      printf("\n");
 +}
 +
 +static int handle_submodule_head_ref(const char *refname,
 +                                   const struct object_id *oid, int flags,
 +                                   void *cb_data)
 +{
 +      struct object_id *output = cb_data;
 +      if (oid)
 +              oidcpy(output, oid);
 +
 +      return 0;
 +}
 +
 +static void status_submodule(const char *path, const struct object_id *ce_oid,
 +                           unsigned int ce_flags, const char *prefix,
 +                           unsigned int flags)
 +{
 +      char *displaypath;
 +      struct argv_array diff_files_args = ARGV_ARRAY_INIT;
 +      struct rev_info rev;
 +      int diff_files_result;
 +
 +      if (!submodule_from_path(&null_oid, path))
 +              die(_("no submodule mapping found in .gitmodules for path '%s'"),
 +                    path);
 +
 +      displaypath = get_submodule_displaypath(path, prefix);
 +
 +      if ((CE_STAGEMASK & ce_flags) >> CE_STAGESHIFT) {
 +              print_status(flags, 'U', path, &null_oid, displaypath);
 +              goto cleanup;
 +      }
 +
 +      if (!is_submodule_active(the_repository, path)) {
 +              print_status(flags, '-', path, ce_oid, displaypath);
 +              goto cleanup;
 +      }
 +
 +      argv_array_pushl(&diff_files_args, "diff-files",
 +                       "--ignore-submodules=dirty", "--quiet", "--",
 +                       path, NULL);
 +
 +      git_config(git_diff_basic_config, NULL);
 +      init_revisions(&rev, prefix);
 +      rev.abbrev = 0;
 +      diff_files_args.argc = setup_revisions(diff_files_args.argc,
 +                                             diff_files_args.argv,
 +                                             &rev, NULL);
 +      diff_files_result = run_diff_files(&rev, 0);
 +
 +      if (!diff_result_code(&rev.diffopt, diff_files_result)) {
 +              print_status(flags, ' ', path, ce_oid,
 +                           displaypath);
 +      } else if (!(flags & OPT_CACHED)) {
 +              struct object_id oid;
 +
 +              if (refs_head_ref(get_submodule_ref_store(path),
 +                                handle_submodule_head_ref, &oid))
 +                      die(_("could not resolve HEAD ref inside the "
 +                            "submodule '%s'"), path);
 +
 +              print_status(flags, '+', path, &oid, displaypath);
 +      } else {
 +              print_status(flags, '+', path, ce_oid, displaypath);
 +      }
 +
 +      if (flags & OPT_RECURSIVE) {
 +              struct child_process cpr = CHILD_PROCESS_INIT;
 +
 +              cpr.git_cmd = 1;
 +              cpr.dir = path;
 +              prepare_submodule_repo_env(&cpr.env_array);
 +
 +              argv_array_push(&cpr.args, "--super-prefix");
 +              argv_array_pushf(&cpr.args, "%s/", displaypath);
 +              argv_array_pushl(&cpr.args, "submodule--helper", "status",
 +                               "--recursive", NULL);
 +
 +              if (flags & OPT_CACHED)
 +                      argv_array_push(&cpr.args, "--cached");
 +
 +              if (flags & OPT_QUIET)
 +                      argv_array_push(&cpr.args, "--quiet");
 +
 +              if (run_command(&cpr))
 +                      die(_("failed to recurse into submodule '%s'"), path);
 +      }
 +
 +cleanup:
 +      argv_array_clear(&diff_files_args);
 +      free(displaypath);
 +}
 +
 +static void status_submodule_cb(const struct cache_entry *list_item,
 +                              void *cb_data)
 +{
 +      struct status_cb *info = cb_data;
 +      status_submodule(list_item->name, &list_item->oid, list_item->ce_flags,
 +                       info->prefix, info->flags);
 +}
 +
 +static int module_status(int argc, const char **argv, const char *prefix)
 +{
 +      struct status_cb info = STATUS_CB_INIT;
 +      struct pathspec pathspec;
 +      struct module_list list = MODULE_LIST_INIT;
 +      int quiet = 0;
 +
 +      struct option module_status_options[] = {
 +              OPT__QUIET(&quiet, N_("Suppress submodule status output")),
 +              OPT_BIT(0, "cached", &info.flags, N_("Use commit stored in the index instead of the one stored in the submodule HEAD"), OPT_CACHED),
 +              OPT_BIT(0, "recursive", &info.flags, N_("recurse into nested submodules"), OPT_RECURSIVE),
 +              OPT_END()
 +      };
 +
 +      const char *const git_submodule_helper_usage[] = {
 +              N_("git submodule status [--quiet] [--cached] [--recursive] [<path>...]"),
 +              NULL
 +      };
 +
 +      argc = parse_options(argc, argv, prefix, module_status_options,
 +                           git_submodule_helper_usage, 0);
 +
 +      if (module_list_compute(argc, argv, prefix, &pathspec, &list) < 0)
 +              return 1;
 +
 +      info.prefix = prefix;
 +      if (quiet)
 +              info.flags |= OPT_QUIET;
 +
 +      for_each_listed_submodule(&list, status_submodule_cb, &info);
  
        return 0;
  }
@@@ -741,6 -503,7 +741,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);
  
@@@ -1382,7 -1145,7 +1383,7 @@@ static int push_check(int argc, const c
        argv++;
        argc--;
        /* Get the submodule's head ref and determine if it is detached */
 -      head = resolve_refdup("HEAD", 0, head_oid.hash, NULL);
 +      head = resolve_refdup("HEAD", 0, &head_oid, NULL);
        if (!head)
                die(_("Failed to resolve HEAD as a valid ref."));
        if (!strcmp(head, "HEAD"))
@@@ -1520,7 -1283,6 +1521,7 @@@ static struct cmd_struct commands[] = 
        {"resolve-relative-url", resolve_relative_url, 0},
        {"resolve-relative-url-test", resolve_relative_url_test, 0},
        {"init", module_init, SUPPORT_SUPER_PREFIX},
 +      {"status", module_status, SUPPORT_SUPER_PREFIX},
        {"remote-branch", resolve_remote_submodule_branch, 0},
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
diff --combined submodule-config.c
@@@ -9,7 -9,7 +9,7 @@@
  /*
   * submodule cache lookup structure
   * There is one shared set of 'struct submodule' entries which can be
 - * looked up by their sha1 blob id of the .gitmodule file and either
 + * looked up by their sha1 blob id of the .gitmodules file and either
   * using path or name as key.
   * for_path stores submodule entries with path as key
   * for_name stores submodule entries with name as key
@@@ -91,7 -91,7 +91,7 @@@ static void submodule_cache_clear(struc
        /*
         * We iterate over the name hash here to be symmetric with the
         * allocation of struct submodule entries. Each is allocated by
 -       * their .gitmodule blob sha1 and submodule name.
 +       * their .gitmodules blob sha1 and submodule name.
         */
        hashmap_iter_init(&cache->for_name, &iter);
        while ((entry = hashmap_iter_next(&iter)))
@@@ -383,6 -383,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 -414,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");