Merge branch 'nd/reset-setup-worktree'
authorJunio C Hamano <gitster@pobox.com>
Fri, 14 Mar 2014 21:25:02 +0000 (14:25 -0700)
committerJunio C Hamano <gitster@pobox.com>
Fri, 14 Mar 2014 21:25:03 +0000 (14:25 -0700)
"git reset" needs to refresh the index when working in a working
tree (it can also be used to match the index to the HEAD in an
otherwise bare repository), but it failed to set up the working
tree properly, causing GIT_WORK_TREE to be ignored.

* nd/reset-setup-worktree:
reset: optionally setup worktree and refresh index on --mixed

1  2 
builtin/reset.c
t/t7102-reset.sh
diff --combined builtin/reset.c
index 4fd1c6c51d3ce5af60f2978f3839c0e595d3fece,a9913443580846b7c401c8c4517890ad91fe8ded..f4e087596b6337d2306af4cf45119752b4a049ea
@@@ -116,34 -116,25 +116,34 @@@ static void update_index_from_diff(stru
                struct diff_options *opt, void *data)
  {
        int i;
 +      int intent_to_add = *(int *)data;
  
        for (i = 0; i < q->nr; i++) {
                struct diff_filespec *one = q->queue[i]->one;
 -              if (one->mode && !is_null_sha1(one->sha1)) {
 -                      struct cache_entry *ce;
 -                      ce = make_cache_entry(one->mode, one->sha1, one->path,
 -                              0, 0);
 -                      if (!ce)
 -                              die(_("make_cache_entry failed for path '%s'"),
 -                                  one->path);
 -                      add_cache_entry(ce, ADD_CACHE_OK_TO_ADD |
 -                              ADD_CACHE_OK_TO_REPLACE);
 -              } else
 +              int is_missing = !(one->mode && !is_null_sha1(one->sha1));
 +              struct cache_entry *ce;
 +
 +              if (is_missing && !intent_to_add) {
                        remove_file_from_cache(one->path);
 +                      continue;
 +              }
 +
 +              ce = make_cache_entry(one->mode, one->sha1, one->path,
 +                                    0, 0);
 +              if (!ce)
 +                      die(_("make_cache_entry failed for path '%s'"),
 +                          one->path);
 +              if (is_missing) {
 +                      ce->ce_flags |= CE_INTENT_TO_ADD;
 +                      set_object_name_for_intent_to_add_entry(ce);
 +              }
 +              add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        }
  }
  
  static int read_from_tree(const struct pathspec *pathspec,
 -                        unsigned char *tree_sha1)
 +                        unsigned char *tree_sha1,
 +                        int intent_to_add)
  {
        struct diff_options opt;
  
        copy_pathspec(&opt.pathspec, pathspec);
        opt.output_format = DIFF_FORMAT_CALLBACK;
        opt.format_callback = update_index_from_diff;
 +      opt.format_callback_data = &intent_to_add;
  
        if (do_diff_cache(tree_sha1, &opt))
                return 1;
@@@ -268,7 -258,6 +268,7 @@@ int cmd_reset(int argc, const char **ar
        const char *rev;
        unsigned char sha1[20];
        struct pathspec pathspec;
 +      int intent_to_add = 0;
        const struct option options[] = {
                OPT__QUIET(&quiet, N_("be quiet, only report errors")),
                OPT_SET_INT(0, "mixed", &reset_type,
                OPT_SET_INT(0, "keep", &reset_type,
                                N_("reset HEAD but keep local changes"), KEEP),
                OPT_BOOL('p', "patch", &patch_mode, N_("select hunks interactively")),
 +              OPT_BOOL('N', "intent-to-add", &intent_to_add,
 +                              N_("record only the fact that removed paths will be added later")),
                OPT_END()
        };
  
        if (reset_type == NONE)
                reset_type = MIXED; /* by default */
  
-       if (reset_type != SOFT && reset_type != MIXED)
+       if (reset_type != SOFT && (reset_type != MIXED || get_git_work_tree()))
                setup_work_tree();
  
        if (reset_type == MIXED && is_bare_repository())
                die(_("%s reset is not allowed in a bare repository"),
                    _(reset_type_names[reset_type]));
  
 +      if (intent_to_add && reset_type != MIXED)
 +              die(_("-N can only be used with --mixed"));
 +
        /* Soft reset does not touch the index file nor the working tree
         * at all, but requires them in a good order.  Other resets reset
         * the index file to the tree object we are switching to. */
                int newfd = hold_locked_index(lock, 1);
                if (reset_type == MIXED) {
                        int flags = quiet ? REFRESH_QUIET : REFRESH_IN_PORCELAIN;
 -                      if (read_from_tree(&pathspec, sha1))
 +                      if (read_from_tree(&pathspec, sha1, intent_to_add))
                                return 1;
-                       refresh_index(&the_index, flags, NULL, NULL,
-                                     _("Unstaged changes after reset:"));
+                       if (get_git_work_tree())
+                               refresh_index(&the_index, flags, NULL, NULL,
+                                             _("Unstaged changes after reset:"));
                } else {
                        int err = reset_index(sha1, reset_type, quiet);
                        if (reset_type == KEEP && !err)
diff --combined t/t7102-reset.sh
index bc0846f4356e548cc72d3cf0c18ef00c21ede87d,ee117e2e727d2bcdc87053684f0c32486452a65e..450529404c686469ed5ba5ad465cf8b3ef651ef9
@@@ -535,19 -535,15 +535,30 @@@ test_expect_success 'reset with paths a
        git diff HEAD --exit-code
  '
  
 +test_expect_success 'reset -N keeps removed files as intent-to-add' '
 +      echo new-file >new-file &&
 +      git add new-file &&
 +      git reset -N HEAD &&
 +
 +      tree=$(git write-tree) &&
 +      git ls-tree $tree new-file >actual &&
 +      >expect &&
 +      test_cmp expect actual &&
 +
 +      git diff --name-only >actual &&
 +      echo new-file >expect &&
 +      test_cmp expect actual
 +'
 +
+ test_expect_success 'reset --mixed sets up work tree' '
+       git init mixed_worktree &&
+       (
+               cd mixed_worktree &&
+               test_commit dummy
+       ) &&
+       : >expect &&
+       git --git-dir=mixed_worktree/.git --work-tree=mixed_worktree reset >actual &&
+       test_cmp expect actual
+ '
  test_done