Merge branch 'cf/submodule-progress-dissociate'
authorJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:09 +0000 (14:04 +0900)
committerJunio C Hamano <gitster@pobox.com>
Wed, 30 May 2018 05:04:09 +0000 (14:04 +0900)
"git submodule update" and "git submodule add" supported the
"--reference" option to borrow objects from a neighbouring local
repository like "git clone" does, but lacked the more recent
invention "--dissociate". Also "git submodule add" has been taught
to take the "--progress" option.

* cf/submodule-progress-dissociate:
submodule: add --dissociate option to add/update commands
submodule: add --progress option to add command
submodule: clean up substitutions in script

1  2 
Documentation/git-submodule.txt
builtin/submodule--helper.c
git-submodule.sh
t/t7400-submodule-basic.sh
index 630999f41a902d8d2043e17f797666489792fd57,a75b9504368ad915f708febd5c0ecedd8e44d793..4a5cc38a6f0e10ba5232190942572e4a540e4ecb
@@@ -213,8 -213,8 +213,8 @@@ sync [--recursive] [--] [<path>...]:
        submodule URLs change upstream and you need to update your local
        repositories accordingly.
  +
 -"git submodule sync" synchronizes all submodules while
 -"git submodule sync \-- A" synchronizes submodule "A" only.
 +`git submodule sync` synchronizes all submodules while
 +`git submodule sync -- A` synchronizes submodule "A" only.
  +
  If `--recursive` is specified, this command will recurse into the
  registered submodules, and sync any nested submodules within.
@@@ -239,6 -239,13 +239,13 @@@ OPTION
  --quiet::
        Only print error messages.
  
+ --progress::
+       This option is only valid for add and update commands.
+       Progress status is reported on the standard error stream
+       by default when it is attached to a terminal, unless -q
+       is specified. This flag forces progress status even if the
+       standard error stream is not directed to a terminal.
  --all::
        This option is only valid for the deinit command. Unregister all
        submodules in the working tree.
@@@ -362,7 -369,15 +369,15 @@@ the submodule itself
        this option will be passed to the linkgit:git-clone[1] command.
  +
  *NOTE*: Do *not* use this option unless you have read the note
- for linkgit:git-clone[1]'s `--reference` and `--shared` options carefully.
+ for linkgit:git-clone[1]'s `--reference`, `--shared`, and `--dissociate`
+ options carefully.
+ --dissociate::
+       This option is only valid for add and update commands.  These
+       commands sometimes need to clone a remote repository. In this case,
+       this option will be passed to the linkgit:git-clone[1] command.
+ +
+ *NOTE*: see the NOTE for the `--reference` option.
  
  --recursive::
        This option is only valid for foreach, update, status and sync commands.
index df841d4ab3da7e4d41de53959ad3a42c142d1943,a85b30419e97da9e2421df6727a352c194cff8d7..7c3cd9dbeba68e8c5581992496ec26e7db025ec5
@@@ -16,7 -16,6 +16,7 @@@
  #include "revision.h"
  #include "diffcore.h"
  #include "diff.h"
 +#include "object-store.h"
  
  #define OPT_QUIET (1 << 0)
  #define OPT_CACHED (1 << 1)
@@@ -455,7 -454,7 +455,7 @@@ static void init_submodule(const char *
  
        displaypath = get_submodule_displaypath(path, prefix);
  
 -      sub = submodule_from_path(&null_oid, path);
 +      sub = submodule_from_path(the_repository, &null_oid, path);
  
        if (!sub)
                die(_("No url found for submodule path '%s' in .gitmodules"),
@@@ -596,12 -595,8 +596,12 @@@ static void print_status(unsigned int f
  
        printf("%c%s %s", state, oid_to_hex(oid), displaypath);
  
 -      if (state == ' ' || state == '+')
 -              printf(" (%s)", compute_rev_name(path, oid_to_hex(oid)));
 +      if (state == ' ' || state == '+') {
 +              const char *name = compute_rev_name(path, oid_to_hex(oid));
 +
 +              if (name)
 +                      printf(" (%s)", name);
 +      }
  
        printf("\n");
  }
@@@ -626,7 -621,7 +626,7 @@@ static void status_submodule(const cha
        struct rev_info rev;
        int diff_files_result;
  
 -      if (!submodule_from_path(&null_oid, path))
 +      if (!submodule_from_path(the_repository, &null_oid, path))
                die(_("no submodule mapping found in .gitmodules for path '%s'"),
                      path);
  
                             displaypath);
        } else if (!(flags & OPT_CACHED)) {
                struct object_id oid;
 +              struct ref_store *refs = get_submodule_ref_store(path);
  
 -              if (refs_head_ref(get_submodule_ref_store(path),
 -                                handle_submodule_head_ref, &oid))
 +              if (!refs) {
 +                      print_status(flags, '-', path, ce_oid, displaypath);
 +                      goto cleanup;
 +              }
 +              if (refs_head_ref(refs, handle_submodule_head_ref, &oid))
                        die(_("could not resolve HEAD ref inside the "
                              "submodule '%s'"), path);
  
@@@ -750,7 -741,7 +750,7 @@@ static int module_name(int argc, const 
        if (argc != 2)
                usage(_("git submodule--helper name <path>"));
  
 -      sub = submodule_from_path(&null_oid, argv[1]);
 +      sub = submodule_from_path(the_repository, &null_oid, argv[1]);
  
        if (!sub)
                die(_("no submodule mapping found in .gitmodules for path '%s'"),
@@@ -781,7 -772,7 +781,7 @@@ static void sync_submodule(const char *
        if (!is_submodule_active(the_repository, path))
                return;
  
 -      sub = submodule_from_path(&null_oid, path);
 +      sub = submodule_from_path(the_repository, &null_oid, path);
  
        if (sub && sub->url) {
                if (starts_with_dot_dot_slash(sub->url) ||
@@@ -934,7 -925,7 +934,7 @@@ static void deinit_submodule(const cha
        struct strbuf sb_config = STRBUF_INIT;
        char *sub_git_dir = xstrfmt("%s/.git", path);
  
 -      sub = submodule_from_path(&null_oid, path);
 +      sub = submodule_from_path(the_repository, &null_oid, path);
  
        if (!sub || !sub->name)
                goto cleanup;
@@@ -1065,7 -1056,7 +1065,7 @@@ static int module_deinit(int argc, cons
  }
  
  static int clone_submodule(const char *path, const char *gitdir, const char *url,
-                          const char *depth, struct string_list *reference,
+                          const char *depth, struct string_list *reference, int dissociate,
                           int quiet, int progress)
  {
        struct child_process cp = CHILD_PROCESS_INIT;
                        argv_array_pushl(&cp.args, "--reference",
                                         item->string, NULL);
        }
+       if (dissociate)
+               argv_array_push(&cp.args, "--dissociate");
        if (gitdir && *gitdir)
                argv_array_pushl(&cp.args, "--separate-git-dir", gitdir, NULL);
  
@@@ -1199,6 -1192,7 +1201,7 @@@ static int module_clone(int argc, cons
        char *p, *path = NULL, *sm_gitdir;
        struct strbuf sb = STRBUF_INIT;
        struct string_list reference = STRING_LIST_INIT_NODUP;
+       int dissociate = 0;
        char *sm_alternate = NULL, *error_strategy = NULL;
  
        struct option module_clone_options[] = {
                OPT_STRING_LIST(0, "reference", &reference,
                           N_("repo"),
                           N_("reference repository")),
+               OPT_BOOL(0, "dissociate", &dissociate,
+                          N_("use --reference only while cloning")),
                OPT_STRING(0, "depth", &depth,
                           N_("string"),
                           N_("depth for shallow clones")),
  
                prepare_possible_alternates(name, &reference);
  
-               if (clone_submodule(path, sm_gitdir, url, depth, &reference,
+               if (clone_submodule(path, sm_gitdir, url, depth, &reference, dissociate,
                                    quiet, progress))
                        die(_("clone of '%s' into submodule path '%s' failed"),
                            url, path);
                strbuf_reset(&sb);
        }
  
 -      /* Connect module worktree and git dir */
 -      connect_work_tree_and_git_dir(path, sm_gitdir);
 +      connect_work_tree_and_git_dir(path, sm_gitdir, 0);
  
        p = git_pathdup_submodule(path, "config");
        if (!p)
@@@ -1308,6 -1305,7 +1313,7 @@@ struct submodule_update_clone 
        int quiet;
        int recommend_shallow;
        struct string_list references;
+       int dissociate;
        const char *depth;
        const char *recursive_prefix;
        const char *prefix;
        int failed_clones_nr, failed_clones_alloc;
  };
  #define SUBMODULE_UPDATE_CLONE_INIT {0, MODULE_LIST_INIT, 0, \
-       SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, \
+       SUBMODULE_UPDATE_STRATEGY_INIT, 0, 0, -1, STRING_LIST_INIT_DUP, 0, \
        NULL, NULL, NULL, \
        STRING_LIST_INIT_DUP, 0, NULL, 0, 0}
  
@@@ -1375,7 -1373,7 +1381,7 @@@ static int prepare_to_clone_next_submod
                goto cleanup;
        }
  
 -      sub = submodule_from_path(&null_oid, ce->name);
 +      sub = submodule_from_path(the_repository, &null_oid, ce->name);
  
        if (suc->recursive_prefix)
                displaypath = relative_path(suc->recursive_prefix,
                for_each_string_list_item(item, &suc->references)
                        argv_array_pushl(&child->args, "--reference", item->string, NULL);
        }
+       if (suc->dissociate)
+               argv_array_push(&child->args, "--dissociate");
        if (suc->depth)
                argv_array_push(&child->args, suc->depth);
  
@@@ -1583,6 -1583,8 +1591,8 @@@ static int update_clone(int argc, cons
                           N_("rebase, merge, checkout or none")),
                OPT_STRING_LIST(0, "reference", &suc.references, N_("repo"),
                           N_("reference repository")),
+               OPT_BOOL(0, "dissociate", &suc.dissociate,
+                          N_("use --reference only while cloning")),
                OPT_STRING(0, "depth", &suc.depth, "<depth>",
                           N_("Create a shallow clone truncated to the "
                              "specified number of revisions")),
@@@ -1658,7 -1660,7 +1668,7 @@@ static const char *remote_submodule_bra
        const char *branch = NULL;
        char *key;
  
 -      sub = submodule_from_path(&null_oid, path);
 +      sub = submodule_from_path(the_repository, &null_oid, path);
        if (!sub)
                return NULL;
  
@@@ -1825,29 -1827,6 +1835,29 @@@ static int is_active(int argc, const ch
        return !is_submodule_active(the_repository, argv[1]);
  }
  
 +/*
 + * Exit non-zero if any of the submodule names given on the command line is
 + * invalid. If no names are given, filter stdin to print only valid names
 + * (which is primarily intended for testing).
 + */
 +static int check_name(int argc, const char **argv, const char *prefix)
 +{
 +      if (argc > 1) {
 +              while (*++argv) {
 +                      if (check_submodule_name(*argv) < 0)
 +                              return 1;
 +              }
 +      } else {
 +              struct strbuf buf = STRBUF_INIT;
 +              while (strbuf_getline(&buf, stdin) != EOF) {
 +                      if (!check_submodule_name(buf.buf))
 +                              printf("%s\n", buf.buf);
 +              }
 +              strbuf_release(&buf);
 +      }
 +      return 0;
 +}
 +
  #define SUPPORT_SUPER_PREFIX (1<<0)
  
  struct cmd_struct {
@@@ -1873,7 -1852,6 +1883,7 @@@ static struct cmd_struct commands[] = 
        {"push-check", push_check, 0},
        {"absorb-git-dirs", absorb_git_dirs, SUPPORT_SUPER_PREFIX},
        {"is-active", is_active, 0},
 +      {"check-name", check_name, 0},
  };
  
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix)
diff --combined git-submodule.sh
index 7e27d0a0da4d130f9ccb92612848da8e219427a0,1fddc098f505ccc353e8514f24b824bf1b5065aa..fd0fe081a81530c61480104d5ce6d84e9e4ea371
@@@ -42,6 -42,7 +42,7 @@@ prefix
  custom_name=
  depth=
  progress=
+ dissociate=
  
  die_if_unmatched ()
  {
@@@ -117,6 -118,9 +118,9 @@@ cmd_add(
                -q|--quiet)
                        GIT_QUIET=1
                        ;;
+               --progress)
+                       progress=1
+                       ;;
                --reference)
                        case "$2" in '') usage ;; esac
                        reference_path=$2
                --reference=*)
                        reference_path="${1#--reference=}"
                        ;;
+               --dissociate)
+                       dissociate=1
+                       ;;
                --name)
                        case "$2" in '') usage ;; esac
                        custom_name=$2
@@@ -229,11 -236,6 +236,11 @@@ Use -f if you really want to add it." >
                sm_name="$sm_path"
        fi
  
 +      if ! git submodule--helper check-name "$sm_name"
 +      then
 +              die "$(eval_gettext "'$sm_name' is not a valid submodule name")"
 +      fi
 +
        # perhaps the path exists and is already a git repo, else clone it
        if test -e "$sm_path"
        then
@@@ -260,7 -262,7 +267,7 @@@ or you are unsure what this means choos
                                eval_gettextln "Reactivating local git directory for submodule '\$sm_name'."
                        fi
                fi
-               git submodule--helper clone ${GIT_QUIET:+--quiet} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${depth:+"$depth"} || exit
+               git submodule--helper clone ${GIT_QUIET:+--quiet} ${progress:+"--progress"} --prefix "$wt_prefix" --path "$sm_path" --name "$sm_name" --url "$realrepo" ${reference:+"$reference"} ${dissociate:+"--dissociate"} ${depth:+"$depth"} || exit
                (
                        sanitize_submodule_env
                        cd "$sm_path" &&
@@@ -470,7 -472,7 +477,7 @@@ cmd_update(
                        GIT_QUIET=1
                        ;;
                --progress)
-                       progress="--progress"
+                       progress=1
                        ;;
                -i|--init)
                        init=1
                --reference=*)
                        reference="$1"
                        ;;
+               --dissociate)
+                       dissociate=1
+                       ;;
                -m|--merge)
                        update="merge"
                        ;;
  
        {
        git submodule--helper update-clone ${GIT_QUIET:+--quiet} \
-               ${progress:+"$progress"} \
+               ${progress:+"--progress"} \
                ${wt_prefix:+--prefix "$wt_prefix"} \
                ${prefix:+--recursive-prefix "$prefix"} \
                ${update:+--update "$update"} \
                ${reference:+"$reference"} \
+               ${dissociate:+"--dissociate"} \
                ${depth:+--depth "$depth"} \
-               ${recommend_shallow:+"$recommend_shallow"} \
-               ${jobs:+$jobs} \
+               $recommend_shallow \
+               $jobs \
                "$@" || echo "#unmatched" $?
        } | {
        err=
index 152104412f212190c18279b64e80bb9f58242d47,b5b4922aba72d18c221571a1523d3d5785923797..2f532529b82a847f81d4bdda17f9f07c115c2d86
@@@ -126,6 -126,22 +126,22 @@@ test_expect_success 'submodule add' 
        test_cmp empty untracked
  '
  
+ test_create_repo parent &&
+ test_commit -C parent one
+ test_expect_success 'redirected submodule add does not show progress' '
+       git -C addtest submodule add "file://$submodurl/parent" submod-redirected \
+               2>err &&
+       ! grep % err &&
+       test_i18ngrep ! "Checking connectivity" err
+ '
+ test_expect_success 'redirected submodule add --progress does show progress' '
+       git -C addtest submodule add --progress "file://$submodurl/parent" \
+               submod-redirected-progress 2>err && \
+       grep % err
+ '
  test_expect_success 'submodule add to .gitignored path fails' '
        (
                cd addtest-ignore &&
@@@ -821,21 -837,6 +837,21 @@@ test_expect_success 'moving the superpr
        )
  '
  
 +test_expect_success 'moving the submodule does not break the superproject' '
 +      (
 +              cd addtest2 &&
 +              git submodule status
 +      ) >actual &&
 +      sed -e "s/^ \([^ ]* repo\) .*/-\1/" <actual >expect &&
 +      mv addtest2/repo addtest2/repo.bak &&
 +      test_when_finished "mv addtest2/repo.bak addtest2/repo" &&
 +      (
 +              cd addtest2 &&
 +              git submodule status
 +      ) >actual &&
 +      test_cmp expect actual
 +'
 +
  test_expect_success 'submodule add --name allows to replace a submodule with another at the same path' '
        (
                cd addtest2 &&