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

1  2 
Documentation/git-read-tree.txt
builtin/checkout.c
unpack-trees.c
index 7061d6634ed422b99495404b3adba9eb04ca7d39,1e81f9c4e6deec2f719098ebad351bc3c073c6cc..d27184260856131f87fc0071c02204c6323b4f69
@@@ -38,9 -38,8 +38,9 @@@ OPTION
        started.
  
  --reset::
 -        Same as -m, except that unmerged entries are discarded
 -        instead of failing.
 +      Same as -m, except that unmerged entries are discarded instead
 +      of failing. When used with `-u`, updates leading to loss of
 +      working tree changes will not abort the operation.
  
  -u::
        After a successful merge, update the files in the work
        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.
  
diff --combined builtin/checkout.c
index 2e72a5e5a944e99ef7e3e44cdcb2e8b2feb22a90,7cd01f62be0c249911731a824805af9193664f66..ffa776c6e10c9665489bd4ca6eac1d35efb011c8
@@@ -376,7 -376,7 +376,7 @@@ static int checkout_paths(const struct 
                                                        ps_matched,
                                                        opts);
  
 -      if (report_path_error(ps_matched, &opts->pathspec, opts->prefix)) {
 +      if (report_path_error(ps_matched, &opts->pathspec)) {
                free(ps_matched);
                return 1;
        }
@@@ -700,7 -700,7 +700,7 @@@ static int merge_working_tree(const str
                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) {
                         */
                        struct tree *result;
                        struct tree *work;
+                       struct tree *old_tree;
                        struct merge_options o;
                        struct strbuf sb = STRBUF_INIT;
  
                         */
                        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),
 +                                                 &sb))
 +                              warning(_("staged changes in the following files may be lost: %s"),
 +                                      sb.buf);
 +                      strbuf_release(&sb);
 +
                        /* Do more real merge */
  
                        /*
                        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);
diff --combined unpack-trees.c
index 5f4325278a0de15091a3437133ebdf34bff7e43e,2e5d7b202e249e41b5ad4e59607a74afbbf1b750..afa4a5cea815a810334136fecf40c0bb39be716d
@@@ -219,6 -219,9 +219,9 @@@ static int add_rejected_path(struct unp
                             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 +271,7 @@@ static int check_submodule_move_head(co
                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;
  }
  
@@@ -707,6 -709,7 +709,6 @@@ static int index_pos_by_traverse_info(s
   * instead of ODB since we already know what these trees contain.
   */
  static int traverse_by_cache_tree(int pos, int nr_entries, int nr_names,
 -                                struct name_entry *names,
                                  struct traverse_info *info)
  {
        struct cache_entry *src[MAX_UNPACK_TREES + 1] = { NULL, };
@@@ -796,7 -799,7 +798,7 @@@ static int traverse_trees_recursive(in
                 * unprocessed entries before 'pos'.
                 */
                bottom = o->cache_bottom;
 -              ret = traverse_by_cache_tree(pos, nr_entries, n, names, info);
 +              ret = traverse_by_cache_tree(pos, nr_entries, n, info);
                o->cache_bottom = bottom;
                return ret;
        }
@@@ -1039,7 -1042,7 +1041,7 @@@ static int unpack_nondirectories(int n
  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;
@@@ -1617,8 -1620,6 +1619,8 @@@ int unpack_trees(unsigned len, struct t
                                                  WRITE_TREE_SILENT |
                                                  WRITE_TREE_REPAIR);
                }
 +
 +              o->result.updated_workdir = 1;
                discard_index(o->dst_index);
                *o->dst_index = o->result;
        } else {
@@@ -1646,8 -1647,7 +1648,7 @@@ return_failed
  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 -1694,7 +1695,7 @@@ static int verify_uptodate_1(const stru
                        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;
                }
  
        }
        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,
@@@ -1760,6 -1758,7 +1759,6 @@@ static void invalidate_ce_path(const st
   */
  static int verify_clean_submodule(const char *old_sha1,
                                  const struct cache_entry *ce,
 -                                enum unpack_trees_error_types error_type,
                                  struct unpack_trees_options *o)
  {
        if (!submodule_from_ce(ce))
  }
  
  static int verify_clean_subdirectory(const struct cache_entry *ce,
 -                                   enum unpack_trees_error_types error_type,
                                     struct unpack_trees_options *o)
  {
        /*
                if (!sub_head && oideq(&oid, &ce->oid))
                        return 0;
                return verify_clean_submodule(sub_head ? NULL : oid_to_hex(&oid),
 -                                            ce, error_type, o);
 +                                            ce, o);
        }
  
        /*
                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;
  }
@@@ -1888,7 -1887,7 +1886,7 @@@ static int check_ok_to_remove(const cha
                 * files that are in "foo/" we would lose
                 * them.
                 */
 -              if (verify_clean_subdirectory(ce, error_type, o) < 0)
 +              if (verify_clean_subdirectory(ce, o) < 0)
                        return -1;
                return 0;
        }
                        return 0;
        }
  
-       return o->gently ? -1 :
-               add_rejected_path(o, error_type, name);
+       return add_rejected_path(o, error_type, name);
  }
  
  /*
@@@ -2345,7 -2343,7 +2342,7 @@@ int bind_merge(const struct cache_entr
                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));
@@@ -2385,7 -2383,7 +2382,7 @@@ int oneway_merge(const struct cache_ent
                if (o->update && S_ISGITLINK(old->ce_mode) &&
                    should_update_submodules() && !verify_uptodate(old, o))
                        update |= CE_UPDATE;
 -              add_entry(o, old, update, 0);
 +              add_entry(o, old, update, CE_STAGEMASK);
                return 0;
        }
        return merged_entry(a, old, o);