Merge branch 'nd/checkout-m'
authorJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:14 +0000 (16:41 +0900)
committerJunio C Hamano <gitster@pobox.com>
Thu, 25 Apr 2019 07:41:14 +0000 (16:41 +0900)
"git checkout -m <other>" was about carrying the differences
between HEAD and the working-tree files forward while checking out
another branch, and ignored the differences between HEAD and the
index. The command has been taught to abort when the index and the
HEAD are different.

* nd/checkout-m:
checkout: prevent losing staged changes with --merge
read-tree: add --quiet
unpack-trees: rename "gently" flag to "quiet"
unpack-trees: keep gently check inside add_rejected_path

Documentation/git-read-tree.txt
builtin/checkout.c
builtin/read-tree.c
t/t7201-co.sh
unpack-trees.c
unpack-trees.h
index 7061d6634ed422b99495404b3adba9eb04ca7d39..d27184260856131f87fc0071c02204c6323b4f69 100644 (file)
@@ -129,6 +129,10 @@ OPTIONS
        Instead of reading tree object(s) into the index, just empty
        it.
 
+-q::
+--quiet::
+       Quiet, suppress feedback messages.
+
 <tree-ish#>::
        The id of the tree object(s) to be read/merged.
 
index 2e72a5e5a944e99ef7e3e44cdcb2e8b2feb22a90..ffa776c6e10c9665489bd4ca6eac1d35efb011c8 100644 (file)
@@ -700,7 +700,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                topts.initial_checkout = is_cache_unborn();
                topts.update = 1;
                topts.merge = 1;
-               topts.gently = opts->merge && old_branch_info->commit;
+               topts.quiet = opts->merge && old_branch_info->commit;
                topts.verbose_update = opts->show_progress;
                topts.fn = twoway_merge;
                if (opts->overwrite_ignore) {
@@ -725,6 +725,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                         */
                        struct tree *result;
                        struct tree *work;
+                       struct tree *old_tree;
                        struct merge_options o;
                        struct strbuf sb = STRBUF_INIT;
 
@@ -737,6 +738,12 @@ static int merge_working_tree(const struct checkout_opts *opts,
                         */
                        if (!old_branch_info->commit)
                                return 1;
+                       old_tree = get_commit_tree(old_branch_info->commit);
+
+                       if (repo_index_has_changes(the_repository, old_tree, &sb))
+                               die(_("cannot continue with staged changes in "
+                                     "the following files:\n%s"), sb.buf);
+                       strbuf_release(&sb);
 
                        if (repo_index_has_changes(the_repository,
                                                   get_commit_tree(old_branch_info->commit),
@@ -781,7 +788,7 @@ static int merge_working_tree(const struct checkout_opts *opts,
                        ret = merge_trees(&o,
                                          get_commit_tree(new_branch_info->commit),
                                          work,
-                                         get_commit_tree(old_branch_info->commit),
+                                         old_tree,
                                          &result);
                        if (ret < 0)
                                exit(128);
index 9083dcfa28a38f7f804c1fdcaa56fb4260b4e6f0..5c9c0825957532dc5e59668889adaf15708007ac 100644 (file)
@@ -154,6 +154,7 @@ int cmd_read_tree(int argc, const char **argv, const char *unused_prefix)
                { OPTION_CALLBACK, 0, "recurse-submodules", NULL,
                            "checkout", "control recursive updating of submodules",
                            PARSE_OPT_OPTARG, option_parse_recurse_submodules_worktree_updater },
+               OPT__QUIET(&opts.quiet, N_("suppress feedback messages")),
                OPT_END()
        };
 
index 72b9b375baa6b26d0bca91c0c2d214cd4a9b8a42..5990299fc9555d54a59a5de462864a7a98e83e45 100755 (executable)
@@ -223,13 +223,8 @@ test_expect_success 'switch to another branch while carrying a deletion' '
        test_must_fail git checkout simple 2>errs &&
        test_i18ngrep overwritten errs &&
 
-       git checkout --merge simple 2>errs &&
-       test_i18ngrep ! overwritten errs &&
-       git ls-files -u &&
-       test_must_fail git cat-file -t :0:two &&
-       test "$(git cat-file -t :1:two)" = blob &&
-       test "$(git cat-file -t :2:two)" = blob &&
-       test_must_fail git cat-file -t :3:two
+       test_must_fail git read-tree --quiet -m -u HEAD simple 2>errs &&
+       test_must_be_empty errs
 '
 
 test_expect_success 'checkout to detach HEAD (with advice declined)' '
index 5f4325278a0de15091a3437133ebdf34bff7e43e..afa4a5cea815a810334136fecf40c0bb39be716d 100644 (file)
@@ -219,6 +219,9 @@ static int add_rejected_path(struct unpack_trees_options *o,
                             enum unpack_trees_error_types e,
                             const char *path)
 {
+       if (o->quiet)
+               return -1;
+
        if (!o->show_all_errors)
                return error(ERRORMSG(o, e), super_prefixed(path));
 
@@ -268,8 +271,7 @@ static int check_submodule_move_head(const struct cache_entry *ce,
                flags |= SUBMODULE_MOVE_HEAD_FORCE;
 
        if (submodule_move_head(ce->name, old_id, new_id, flags))
-               return o->gently ? -1 :
-                                  add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
+               return add_rejected_path(o, ERROR_WOULD_LOSE_SUBMODULE, ce->name);
        return 0;
 }
 
@@ -1039,7 +1041,7 @@ static int unpack_nondirectories(int n, unsigned long mask,
 static int unpack_failed(struct unpack_trees_options *o, const char *message)
 {
        discard_index(&o->result);
-       if (!o->gently && !o->exiting_early) {
+       if (!o->quiet && !o->exiting_early) {
                if (message)
                        return error("%s", message);
                return -1;
@@ -1646,8 +1648,7 @@ int unpack_trees(unsigned len, struct tree_desc *t, struct unpack_trees_options
 static int reject_merge(const struct cache_entry *ce,
                        struct unpack_trees_options *o)
 {
-       return o->gently ? -1 :
-               add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
+       return add_rejected_path(o, ERROR_WOULD_OVERWRITE, ce->name);
 }
 
 static int same(const struct cache_entry *a, const struct cache_entry *b)
@@ -1694,8 +1695,7 @@ static int verify_uptodate_1(const struct cache_entry *ce,
                        int r = check_submodule_move_head(ce,
                                "HEAD", oid_to_hex(&ce->oid), o);
                        if (r)
-                               return o->gently ? -1 :
-                                       add_rejected_path(o, error_type, ce->name);
+                               return add_rejected_path(o, error_type, ce->name);
                        return 0;
                }
 
@@ -1713,8 +1713,7 @@ static int verify_uptodate_1(const struct cache_entry *ce,
        }
        if (errno == ENOENT)
                return 0;
-       return o->gently ? -1 :
-               add_rejected_path(o, error_type, ce->name);
+       return add_rejected_path(o, error_type, ce->name);
 }
 
 int verify_uptodate(const struct cache_entry *ce,
@@ -1834,8 +1833,7 @@ static int verify_clean_subdirectory(const struct cache_entry *ce,
                d.exclude_per_dir = o->dir->exclude_per_dir;
        i = read_directory(&d, o->src_index, pathbuf, namelen+1, NULL);
        if (i)
-               return o->gently ? -1 :
-                       add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
+               return add_rejected_path(o, ERROR_NOT_UPTODATE_DIR, ce->name);
        free(pathbuf);
        return cnt;
 }
@@ -1904,8 +1902,7 @@ static int check_ok_to_remove(const char *name, int len, int dtype,
                        return 0;
        }
 
-       return o->gently ? -1 :
-               add_rejected_path(o, error_type, name);
+       return add_rejected_path(o, error_type, name);
 }
 
 /*
@@ -2345,7 +2342,7 @@ int bind_merge(const struct cache_entry * const *src,
                return error("Cannot do a bind merge of %d trees",
                             o->merge_size);
        if (a && old)
-               return o->gently ? -1 :
+               return o->quiet ? -1 :
                        error(ERRORMSG(o, ERROR_BIND_OVERLAP),
                              super_prefixed(a->name),
                              super_prefixed(old->name));
index 0135080a7b4e91713b66f68669e57a2f5e4edbdd..d344d7d29694dbf64d6874163810e65915167fd8 100644 (file)
@@ -56,7 +56,7 @@ struct unpack_trees_options {
                     diff_index_cached,
                     debug_unpack,
                     skip_sparse_checkout,
-                    gently,
+                    quiet,
                     exiting_early,
                     show_all_errors,
                     dry_run;