Merge branch 'nd/checkout-noisy'
authorJunio C Hamano <gitster@pobox.com>
Mon, 14 Jan 2019 23:29:28 +0000 (15:29 -0800)
committerJunio C Hamano <gitster@pobox.com>
Mon, 14 Jan 2019 23:29:29 +0000 (15:29 -0800)
"git checkout [<tree-ish>] path..." learned to report the number of
paths that have been checked out of the index or the tree-ish,
which gives it the same degree of noisy-ness as the case in which
the command checks out a branch.

* nd/checkout-noisy:
t0027: squelch checkout path run outside test_expect_* block
checkout: print something when checking out paths

1  2 
apply.c
builtin/checkout-index.c
builtin/checkout.c
entry.c
unpack-trees.c
diff --combined apply.c
index 01793d612620246b14fa57f6ce3ed6c33df65d0f,5876b021972e745f586214bf522cc6a8ad1d54f8..3703bfc8d03deb3be3a3fa9a45a2dd64b0a8eafd
+++ b/apply.c
@@@ -1748,7 -1748,7 +1748,7 @@@ static int parse_fragment(struct apply_
        }
        if (oldlines || newlines)
                return -1;
 -      if (!deleted && !added)
 +      if (!patch->recount && !deleted && !added)
                return -1;
  
        fragment->leading = leading;
@@@ -3352,7 -3352,8 +3352,8 @@@ static int checkout_target(struct index
  
        costate.refresh_cache = 1;
        costate.istate = istate;
-       if (checkout_entry(ce, &costate, NULL) || lstat(ce->name, st))
+       if (checkout_entry(ce, &costate, NULL, NULL) ||
+           lstat(ce->name, st))
                return error(_("cannot checkout %s"), ce->name);
        return 0;
  }
@@@ -4772,9 -4773,6 +4773,9 @@@ static int apply_option_parse_exclude(c
                                      const char *arg, int unset)
  {
        struct apply_state *state = opt->value;
 +
 +      BUG_ON_OPT_NEG(unset);
 +
        add_name_limit(state, arg, 1);
        return 0;
  }
@@@ -4783,9 -4781,6 +4784,9 @@@ static int apply_option_parse_include(c
                                      const char *arg, int unset)
  {
        struct apply_state *state = opt->value;
 +
 +      BUG_ON_OPT_NEG(unset);
 +
        add_name_limit(state, arg, 0);
        state->has_include = 1;
        return 0;
@@@ -4796,9 -4791,6 +4797,9 @@@ static int apply_option_parse_p(const s
                                int unset)
  {
        struct apply_state *state = opt->value;
 +
 +      BUG_ON_OPT_NEG(unset);
 +
        state->p_value = atoi(arg);
        state->p_value_known = 1;
        return 0;
@@@ -4808,9 -4800,6 +4809,9 @@@ static int apply_option_parse_space_cha
                                           const char *arg, int unset)
  {
        struct apply_state *state = opt->value;
 +
 +      BUG_ON_OPT_ARG(arg);
 +
        if (unset)
                state->ws_ignore_action = ignore_ws_none;
        else
@@@ -4822,12 -4811,9 +4823,12 @@@ static int apply_option_parse_whitespac
                                         const char *arg, int unset)
  {
        struct apply_state *state = opt->value;
 +
 +      BUG_ON_OPT_NEG(unset);
 +
        state->whitespace_option = arg;
        if (parse_whitespace_option(state, arg))
 -              exit(1);
 +              return -1;
        return 0;
  }
  
@@@ -4835,9 -4821,6 +4836,9 @@@ static int apply_option_parse_directory
                                        const char *arg, int unset)
  {
        struct apply_state *state = opt->value;
 +
 +      BUG_ON_OPT_NEG(unset);
 +
        strbuf_reset(&state->root);
        strbuf_addstr(&state->root, arg);
        strbuf_complete(&state->root, '/');
@@@ -4957,10 -4940,10 +4958,10 @@@ int apply_parse_options(int argc, cons
        struct option builtin_apply_options[] = {
                { OPTION_CALLBACK, 0, "exclude", state, N_("path"),
                        N_("don't apply changes matching the given path"),
 -                      0, apply_option_parse_exclude },
 +                      PARSE_OPT_NONEG, apply_option_parse_exclude },
                { OPTION_CALLBACK, 0, "include", state, N_("path"),
                        N_("apply changes matching the given path"),
 -                      0, apply_option_parse_include },
 +                      PARSE_OPT_NONEG, apply_option_parse_include },
                { OPTION_CALLBACK, 'p', NULL, state, N_("num"),
                        N_("remove <num> leading slashes from traditional diff paths"),
                        0, apply_option_parse_p },
diff --combined builtin/checkout-index.c
index eb74774cbc9d6bd6acf1b7fe2f31b8e80e461a12,bada491f5808db38a34ad40fae19bd780aa3354c..a2a726ad8d8fa65d2fbcd1b111d71bad61c5cee8
@@@ -67,7 -67,8 +67,8 @@@ static int checkout_file(const char *na
                        continue;
                did_checkout = 1;
                if (checkout_entry(ce, &state,
-                   to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
+                                  to_tempfile ? topath[ce_stage(ce)] : NULL,
+                                  NULL) < 0)
                        errs++;
        }
  
@@@ -111,7 -112,8 +112,8 @@@ static void checkout_all(const char *pr
                                write_tempfile_record(last_ce->name, prefix);
                }
                if (checkout_entry(ce, &state,
-                   to_tempfile ? topath[ce_stage(ce)] : NULL) < 0)
+                                  to_tempfile ? topath[ce_stage(ce)] : NULL,
+                                  NULL) < 0)
                        errs++;
                last_ce = ce;
        }
@@@ -132,8 -134,6 +134,8 @@@ static const char * const builtin_check
  static int option_parse_stage(const struct option *opt,
                              const char *arg, int unset)
  {
 +      BUG_ON_OPT_NEG(unset);
 +
        if (!strcmp(arg, "all")) {
                to_tempfile = 1;
                checkout_stage = CHECKOUT_ALL;
diff --combined builtin/checkout.c
index d338d96fe9a7518852e5461a913ba4dbdb19dc4d,3a0b86ec1c86f11608c9a9772cbcf7412dc9fb52..6fadf412e830ba4aeaa8d2940fd9a7aab9bd8fa5
@@@ -44,6 -44,7 +44,7 @@@ struct checkout_opts 
        int ignore_skipworktree;
        int ignore_other_worktrees;
        int show_progress;
+       int count_checkout_paths;
        /*
         * If new checkout options are added, skip_merge_working_tree
         * should be updated accordingly.
@@@ -115,8 -116,7 +116,8 @@@ static int update_some(const struct obj
  
  static int read_tree_some(struct tree *tree, const struct pathspec *pathspec)
  {
 -      read_tree_recursive(tree, "", 0, 0, pathspec, update_some, NULL);
 +      read_tree_recursive(the_repository, tree, "", 0, 0,
 +                          pathspec, update_some, NULL);
  
        /* update the index with the given tree's info
         * for all args, expanding wildcards, and exit
@@@ -166,12 -166,13 +167,13 @@@ static int check_stages(unsigned stages
  }
  
  static int checkout_stage(int stage, const struct cache_entry *ce, int pos,
-                         const struct checkout *state)
+                         const struct checkout *state, int *nr_checkouts)
  {
        while (pos < active_nr &&
               !strcmp(active_cache[pos]->name, ce->name)) {
                if (ce_stage(active_cache[pos]) == stage)
-                       return checkout_entry(active_cache[pos], state, NULL);
+                       return checkout_entry(active_cache[pos], state,
+                                             NULL, nr_checkouts);
                pos++;
        }
        if (stage == 2)
                return error(_("path '%s' does not have their version"), ce->name);
  }
  
- static int checkout_merged(int pos, const struct checkout *state)
+ static int checkout_merged(int pos, const struct checkout *state, int *nr_checkouts)
  {
        struct cache_entry *ce = active_cache[pos];
        const char *path = ce->name;
        ce = make_transient_cache_entry(mode, &oid, path, 2);
        if (!ce)
                die(_("make_cache_entry failed for path '%s'"), path);
-       status = checkout_entry(ce, state, NULL);
+       status = checkout_entry(ce, state, NULL, nr_checkouts);
        discard_cache_entry(ce);
        return status;
  }
@@@ -258,6 -259,7 +260,7 @@@ static int checkout_paths(const struct 
        struct commit *head;
        int errs = 0;
        struct lock_file lock_file = LOCK_INIT;
+       int nr_checkouts = 0;
  
        if (opts->track != BRANCH_TRACK_UNSPECIFIED)
                die(_("'%s' cannot be used with updating paths"), "--track");
                struct cache_entry *ce = active_cache[pos];
                if (ce->ce_flags & CE_MATCHED) {
                        if (!ce_stage(ce)) {
-                               errs |= checkout_entry(ce, &state, NULL);
+                               errs |= checkout_entry(ce, &state,
+                                                      NULL, &nr_checkouts);
                                continue;
                        }
                        if (opts->writeout_stage)
-                               errs |= checkout_stage(opts->writeout_stage, ce, pos, &state);
+                               errs |= checkout_stage(opts->writeout_stage,
+                                                      ce, pos,
+                                                      &state, &nr_checkouts);
                        else if (opts->merge)
-                               errs |= checkout_merged(pos, &state);
+                               errs |= checkout_merged(pos, &state,
+                                                       &nr_checkouts);
                        pos = skip_same_name(ce, pos) - 1;
                }
        }
-       errs |= finish_delayed_checkout(&state);
+       errs |= finish_delayed_checkout(&state, &nr_checkouts);
+       if (opts->count_checkout_paths) {
+               if (opts->source_tree)
+                       fprintf_ln(stderr, Q_("Checked out %d path out of %s",
+                                             "Checked out %d paths out of %s",
+                                             nr_checkouts),
+                                  nr_checkouts,
+                                  find_unique_abbrev(&opts->source_tree->object.oid,
+                                                     DEFAULT_ABBREV));
+               else
+                       fprintf_ln(stderr, Q_("Checked out %d path out of the index",
+                                             "Checked out %d paths out of the index",
+                                             nr_checkouts),
+                                  nr_checkouts);
+       }
  
        if (write_locked_index(&the_index, &lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
@@@ -754,8 -775,7 +776,8 @@@ static void update_refs_for_switch(cons
                        free(refname);
                }
                else
 -                      create_branch(opts->new_branch, new_branch_info->name,
 +                      create_branch(the_repository,
 +                                    opts->new_branch, new_branch_info->name,
                                      opts->new_branch_force ? 1 : 0,
                                      opts->new_branch_force ? 1 : 0,
                                      opts->new_branch_log,
                                delete_reflog(old_branch_info->path);
                }
        }
 -      remove_branch_state();
 +      remove_branch_state(the_repository);
        strbuf_release(&msg);
        if (!opts->quiet &&
            (new_branch_info->path || (!opts->force_detach && !strcmp(new_branch_info->name, "HEAD"))))
@@@ -1066,6 -1086,7 +1088,7 @@@ static int parse_branchname_arg(int arg
                has_dash_dash = 1; /* case (3) or (1) */
        else if (dash_dash_pos >= 2)
                die(_("only one reference expected, %d given."), dash_dash_pos);
+       opts->count_checkout_paths = !opts->quiet && !has_dash_dash;
  
        if (!strcmp(arg, "-"))
                arg = "@{-1}";
                 */
                int recover_with_dwim = dwim_new_local_branch_ok;
  
 -              if (!has_dash_dash &&
 -                  (check_filename(opts->prefix, arg) || !no_wildcard(arg)))
 +              int could_be_checkout_paths = !has_dash_dash &&
 +                      check_filename(opts->prefix, arg);
 +
 +              if (!has_dash_dash && !no_wildcard(arg))
                        recover_with_dwim = 0;
 +
                /*
                 * Accept "git checkout foo" and "git checkout foo --"
                 * as candidates for dwim.
                        const char *remote = unique_tracking_name(arg, rev,
                                                                  dwim_remotes_matched);
                        if (remote) {
 +                              if (could_be_checkout_paths)
 +                                      die(_("'%s' could be both a local file and a tracking branch.\n"
 +                                            "Please use -- (and optionally --no-guess) to disambiguate"),
 +                                          arg);
                                *new_branch = arg;
                                arg = remote;
                                /* DWIMmed to create local branch, case (3).(b) */
@@@ -1237,7 -1251,7 +1260,7 @@@ int cmd_checkout(int argc, const char *
        struct checkout_opts opts;
        struct branch_info new_branch_info;
        char *conflict_style = NULL;
 -      int dwim_new_local_branch = 1;
 +      int dwim_new_local_branch, no_dwim_new_local_branch = 0;
        int dwim_remotes_matched = 0;
        struct option options[] = {
                OPT__QUIET(&opts.quiet, N_("suppress progress reporting")),
                OPT_BOOL('p', "patch", &opts.patch_mode, N_("select hunks interactively")),
                OPT_BOOL(0, "ignore-skip-worktree-bits", &opts.ignore_skipworktree,
                         N_("do not limit pathspecs to sparse entries only")),
 -              OPT_HIDDEN_BOOL(0, "guess", &dwim_new_local_branch,
 -                              N_("second guess 'git checkout <no-such-branch>'")),
 +              OPT_BOOL(0, "no-guess", &no_dwim_new_local_branch,
 +                       N_("do not second guess 'git checkout <no-such-branch>'")),
                OPT_BOOL(0, "ignore-other-worktrees", &opts.ignore_other_worktrees,
                         N_("do not check if another worktree is holding the given ref")),
                { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
        argc = parse_options(argc, argv, prefix, options, checkout_usage,
                             PARSE_OPT_KEEP_DASHDASH);
  
 +      dwim_new_local_branch = !no_dwim_new_local_branch;
        if (opts.show_progress < 0) {
                if (opts.quiet)
                        opts.show_progress = 0;
diff --combined entry.c
index 0a3c451f5f0f08deabe20b4ca1858825f2b29f3f,5f213c30fe8c099a25492beca8b074919d7fbfe1..6fd72b30c8768677f044923ef5e715949d32fdae
+++ b/entry.c
@@@ -161,7 -161,7 +161,7 @@@ static int remove_available_paths(struc
        return !available;
  }
  
- int finish_delayed_checkout(struct checkout *state)
+ int finish_delayed_checkout(struct checkout *state, int *nr_checkouts)
  {
        int errs = 0;
        unsigned delayed_object_count;
                                ce = index_file_exists(state->istate, path->string,
                                                       strlen(path->string), 0);
                                if (ce) {
-                                       errs |= checkout_entry(ce, state, NULL);
+                                       errs |= checkout_entry(ce, state, NULL, nr_checkouts);
                                        filtered_bytes += ce->ce_stat_data.sd_size;
                                        display_throughput(progress, filtered_bytes);
                                } else
@@@ -404,7 -404,7 +404,7 @@@ static void mark_colliding_entries(cons
  {
        int i, trust_ino = check_stat;
  
 -#if defined(GIT_WINDOWS_NATIVE)
 +#if defined(GIT_WINDOWS_NATIVE) || defined(__CYGWIN__)
        trust_ino = 0;
  #endif
  
                if (dup->ce_flags & (CE_MATCHED | CE_VALID | CE_SKIP_WORKTREE))
                        continue;
  
 -              if ((trust_ino && dup->ce_stat_data.sd_ino == st->st_ino) ||
 +              if ((trust_ino && !match_stat_data(&dup->ce_stat_data, st)) ||
                    (!trust_ino && !fspathcmp(ce->name, dup->name))) {
                        dup->ce_flags |= CE_MATCHED;
                        break;
   * its name is returned in topath[], which must be able to hold at
   * least TEMPORARY_FILENAME_LENGTH bytes long.
   */
- int checkout_entry(struct cache_entry *ce,
-                  const struct checkout *state, char *topath)
+ int checkout_entry(struct cache_entry *ce, const struct checkout *state,
+                  char *topath, int *nr_checkouts)
  {
        static struct strbuf path = STRBUF_INIT;
        struct stat st;
                return 0;
  
        create_directories(path.buf, path.len, state);
+       if (nr_checkouts)
+               (*nr_checkouts)++;
        return write_entry(ce, path.buf, state, 0);
  }
diff --combined unpack-trees.c
index c70e9926e40a530b3da982fc6d10655fc949af03,17f1e601da5b344a6ed12c9fc3a7e449d745cb5e..94265a7df0fe78e49b720b7514d0457645f9ff05
@@@ -294,7 -294,7 +294,7 @@@ static void load_gitmodules_file(struc
                        repo_read_gitmodules(the_repository);
                } else if (state && (ce->ce_flags & CE_UPDATE)) {
                        submodule_free(the_repository);
-                       checkout_entry(ce, state, NULL);
+                       checkout_entry(ce, state, NULL, NULL);
                        repo_read_gitmodules(the_repository);
                }
        }
@@@ -450,12 -450,12 +450,12 @@@ static int check_updates(struct unpack_
                        display_progress(progress, ++cnt);
                        ce->ce_flags &= ~CE_UPDATE;
                        if (o->update && !o->dry_run) {
-                               errs |= checkout_entry(ce, &state, NULL);
+                               errs |= checkout_entry(ce, &state, NULL, NULL);
                        }
                }
        }
        stop_progress(&progress);
-       errs |= finish_delayed_checkout(&state);
+       errs |= finish_delayed_checkout(&state, NULL);
        if (o->update)
                git_attr_set_direction(GIT_ATTR_CHECKIN);
  
@@@ -794,7 -794,6 +794,7 @@@ static int traverse_trees_recursive(in
                                    struct name_entry *names,
                                    struct traverse_info *info)
  {
 +      struct unpack_trees_options *o = info->data;
        int i, ret, bottom;
        int nr_buf = 0;
        struct tree_desc t[MAX_UNPACK_TREES];
  
        nr_entries = all_trees_same_as_cache_tree(n, dirmask, names, info);
        if (nr_entries > 0) {
 -              struct unpack_trees_options *o = info->data;
                int pos = index_pos_by_traverse_info(names, info);
  
                if (!o->merge || df_conflicts)
        }
  
        bottom = switch_cache_bottom(&newinfo);
 -      ret = traverse_trees(n, t, &newinfo);
 +      ret = traverse_trees(o->src_index, n, t, &newinfo);
        restore_cache_bottom(&newinfo, bottom);
  
        for (i = 0; i < nr_buf; i++)
@@@ -1550,7 -1550,7 +1550,7 @@@ int unpack_trees(unsigned len, struct t
                }
  
                trace_performance_enter();
 -              ret = traverse_trees(len, t, &info);
 +              ret = traverse_trees(o->src_index, len, t, &info);
                trace_performance_leave("traverse_trees");
                if (ret < 0)
                        goto return_failed;
                move_index_extensions(&o->result, o->src_index);
                if (!ret) {
                        if (git_env_bool("GIT_TEST_CHECK_CACHE_TREE", 0))
 -                              cache_tree_verify(&o->result);
 +                              cache_tree_verify(the_repository, &o->result);
                        if (!o->result.cache_tree)
                                o->result.cache_tree = cache_tree();
                        if (!cache_tree_fully_valid(o->result.cache_tree))