Merge branch 'jk/checkout-from-tree'
authorJunio C Hamano <gitster@pobox.com>
Fri, 5 Dec 2014 19:41:33 +0000 (11:41 -0800)
committerJunio C Hamano <gitster@pobox.com>
Fri, 5 Dec 2014 19:41:33 +0000 (11:41 -0800)
"git checkout $treeish $path", when $path in the index and the
working tree already matched what is in $treeish at the $path,
still overwrote the $path unnecessarily.

* jk/checkout-from-tree:
checkout $tree: do not throw away unchanged index entries

1  2 
builtin/checkout.c
diff --combined builtin/checkout.c
index 5410dacea0699f70cd942837394c06eac99873d1,8129eee837d68df4238c898829a945a6145f71c3..5a787580368bd3e6410128ff300853a10e4a50ee
@@@ -1,5 -1,5 +1,5 @@@
 -#include "cache.h"
  #include "builtin.h"
 +#include "lockfile.h"
  #include "parse-options.h"
  #include "refs.h"
  #include "commit.h"
@@@ -53,10 -53,10 +53,10 @@@ struct checkout_opts 
  static int post_checkout_hook(struct commit *old, struct commit *new,
                              int changed)
  {
 -      return run_hook(NULL, "post-checkout",
 -                      sha1_to_hex(old ? old->object.sha1 : null_sha1),
 -                      sha1_to_hex(new ? new->object.sha1 : null_sha1),
 -                      changed ? "1" : "0", NULL);
 +      return run_hook_le(NULL, "post-checkout",
 +                         sha1_to_hex(old ? old->object.sha1 : null_sha1),
 +                         sha1_to_hex(new ? new->object.sha1 : null_sha1),
 +                         changed ? "1" : "0", NULL);
        /* "new" can be NULL when checking out from the index before
           a commit exists. */
  
@@@ -67,6 -67,7 +67,7 @@@ static int update_some(const unsigned c
  {
        int len;
        struct cache_entry *ce;
+       int pos;
  
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
        ce->ce_flags = create_ce_flags(0) | CE_UPDATE;
        ce->ce_namelen = len;
        ce->ce_mode = create_ce_mode(mode);
+       /*
+        * If the entry is the same as the current index, we can leave the old
+        * entry in place. Whether it is UPTODATE or not, checkout_entry will
+        * do the right thing.
+        */
+       pos = cache_name_pos(ce->name, ce->ce_namelen);
+       if (pos >= 0) {
+               struct cache_entry *old = active_cache[pos];
+               if (ce->ce_mode == old->ce_mode &&
+                   !hashcmp(ce->sha1, old->sha1)) {
+                       old->ce_flags |= CE_UPDATE;
+                       free(ce);
+                       return 0;
+               }
+       }
        add_cache_entry(ce, ADD_CACHE_OK_TO_ADD | ADD_CACHE_OK_TO_REPLACE);
        return 0;
  }
@@@ -225,6 -243,7 +243,6 @@@ static int checkout_paths(const struct 
        int flag;
        struct commit *head;
        int errs = 0;
 -      int newfd;
        struct lock_file *lock_file;
  
        if (opts->track != BRANCH_TRACK_UNSPECIFIED)
  
        lock_file = xcalloc(1, sizeof(struct lock_file));
  
 -      newfd = hold_locked_index(lock_file, 1);
 +      hold_locked_index(lock_file, 1);
        if (read_cache_preload(&opts->pathspec) < 0)
                return error(_("corrupt index file"));
  
                 * match_pathspec() for _all_ entries when
                 * opts->source_tree != NULL.
                 */
 -              if (match_pathspec_depth(&opts->pathspec, ce->name, ce_namelen(ce),
 -                                 0, ps_matched))
 +              if (ce_path_match(ce, &opts->pathspec, ps_matched))
                        ce->ce_flags |= CE_MATCHED;
        }
  
        memset(&state, 0, sizeof(state));
        state.force = 1;
        state.refresh_cache = 1;
 +      state.istate = &the_index;
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
                if (ce->ce_flags & CE_MATCHED) {
                }
        }
  
 -      if (write_cache(newfd, active_cache, active_nr) ||
 -          commit_locked_index(lock_file))
 +      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
 -      read_ref_full("HEAD", rev, 0, &flag);
 +      read_ref_full("HEAD", 0, rev, &flag);
        head = lookup_commit_reference_gently(rev, 1);
  
        errs |= post_checkout_hook(head, head, 0);
@@@ -378,8 -398,8 +396,8 @@@ static void show_local_changes(struct o
  static void describe_detached_head(const char *msg, struct commit *commit)
  {
        struct strbuf sb = STRBUF_INIT;
 -      parse_commit(commit);
 -      pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
 +      if (!parse_commit(commit))
 +              pp_commit_easy(CMIT_FMT_ONELINE, commit, &sb);
        fprintf(stderr, "%s %s... %s\n", msg,
                find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV), sb.buf);
        strbuf_release(&sb);
@@@ -443,8 -463,8 +461,8 @@@ static int merge_working_tree(const str
  {
        int ret;
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
 -      int newfd = hold_locked_index(lock_file, 1);
  
 +      hold_locked_index(lock_file, 1);
        if (read_cache_preload(NULL) < 0)
                return error(_("corrupt index file"));
  
                }
        }
  
 -      if (write_cache(newfd, active_cache, active_nr) ||
 -          commit_locked_index(lock_file))
 +      if (!active_cache_tree)
 +              active_cache_tree = cache_tree();
 +
 +      if (!cache_tree_fully_valid(active_cache_tree))
 +              cache_tree_update(&the_index, WRITE_TREE_SILENT | WRITE_TREE_REPAIR);
 +
 +      if (write_locked_index(&the_index, lock_file, COMMIT_LOCK))
                die(_("unable to write new index file"));
  
        if (!opts->force && !opts->quiet)
@@@ -628,7 -643,7 +646,7 @@@ static void update_refs_for_switch(cons
                /* Nothing to do. */
        } else if (opts->force_detach || !new->path) {  /* No longer on any branch. */
                update_ref(msg.buf, "HEAD", new->commit->object.sha1, NULL,
 -                         REF_NODEREF, DIE_ON_ERR);
 +                         REF_NODEREF, UPDATE_REFS_DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path && advice_detached_head)
                                detach_advice(new->name);
                        }
                }
                if (old->path && old->name) {
 -                      char log_file[PATH_MAX], ref_file[PATH_MAX];
 -
 -                      git_snpath(log_file, sizeof(log_file), "logs/%s", old->path);
 -                      git_snpath(ref_file, sizeof(ref_file), "%s", old->path);
 -                      if (!file_exists(ref_file) && file_exists(log_file))
 -                              remove_path(log_file);
 +                      if (!ref_exists(old->path) && reflog_exists(old->path))
 +                              delete_reflog(old->path);
                }
        }
        remove_branch_state();
@@@ -676,12 -695,12 +694,12 @@@ static int add_pending_uninteresting_re
  
  static void describe_one_orphan(struct strbuf *sb, struct commit *commit)
  {
 -      parse_commit(commit);
        strbuf_addstr(sb, "  ");
        strbuf_addstr(sb,
                find_unique_abbrev(commit->object.sha1, DEFAULT_ABBREV));
        strbuf_addch(sb, ' ');
 -      pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
 +      if (!parse_commit(commit))
 +              pp_commit_easy(CMIT_FMT_ONELINE, commit, sb);
        strbuf_addch(sb, '\n');
  }
  
@@@ -775,20 -794,20 +793,20 @@@ static int switch_branches(const struc
        unsigned char rev[20];
        int flag, writeout_error = 0;
        memset(&old, 0, sizeof(old));
 -      old.path = path_to_free = resolve_refdup("HEAD", rev, 0, &flag);
 +      old.path = path_to_free = resolve_refdup("HEAD", 0, rev, &flag);
        old.commit = lookup_commit_reference_gently(rev, 1);
        if (!(flag & REF_ISSYMREF))
                old.path = NULL;
  
 -      if (old.path && !prefixcmp(old.path, "refs/heads/"))
 -              old.name = old.path + strlen("refs/heads/");
 +      if (old.path)
 +              skip_prefix(old.path, "refs/heads/", &old.name);
  
        if (!new->name) {
                new->name = "HEAD";
                new->commit = old.commit;
                if (!new->commit)
                        die(_("You are on a branch yet to be born"));
 -              parse_commit(new->commit);
 +              parse_commit_or_die(new->commit);
        }
  
        ret = merge_working_tree(opts, &old, new, &writeout_error);
@@@ -815,7 -834,7 +833,7 @@@ static int git_checkout_config(const ch
                return 0;
        }
  
 -      if (!prefixcmp(var, "submodule."))
 +      if (starts_with(var, "submodule."))
                return parse_submodule_config_option(var, value);
  
        return git_xmerge_config(var, value, NULL);
@@@ -895,7 -914,7 +913,7 @@@ static int parse_branchname_arg(int arg
         *       between A and B, A...B names that merge base.
         *
         *   (b) If <something> is _not_ a commit, either "--" is present
 -       *       or <something> is not a path, no -t nor -b was given, and
 +       *       or <something> is not a path, no -t or -b was given, and
         *       and there is a tracking branch whose name is <something>
         *       in one and only one remote, then this is a short-hand to
         *       fork local <something> from that remote-tracking branch.
                /* not a commit */
                *source_tree = parse_tree_indirect(rev);
        } else {
 -              parse_commit(new->commit);
 +              parse_commit_or_die(new->commit);
                *source_tree = new->commit->tree;
        }
  
@@@ -1072,7 -1091,7 +1090,7 @@@ static int checkout_branch(struct check
                unsigned char rev[20];
                int flag;
  
 -              if (!read_ref_full("HEAD", rev, 0, &flag) &&
 +              if (!read_ref_full("HEAD", 0, rev, &flag) &&
                    (flag & REF_ISSYMREF) && is_null_sha1(rev))
                        return switch_unborn_to_new_branch(opts);
        }
@@@ -1095,7 -1114,7 +1113,7 @@@ int cmd_checkout(int argc, const char *
                OPT_BOOL(0, "detach", &opts.force_detach, N_("detach the HEAD at named commit")),
                OPT_SET_INT('t', "track",  &opts.track, N_("set upstream info for new branch"),
                        BRANCH_TRACK_EXPLICIT),
 -              OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new branch"), N_("new unparented branch")),
 +              OPT_STRING(0, "orphan", &opts.new_orphan_branch, N_("new-branch"), N_("new unparented branch")),
                OPT_SET_INT('2', "ours", &opts.writeout_stage, N_("checkout our version for unmerged files"),
                            2),
                OPT_SET_INT('3', "theirs", &opts.writeout_stage, N_("checkout their version for unmerged files"),
                const char *argv0 = argv[0];
                if (!argc || !strcmp(argv0, "--"))
                        die (_("--track needs a branch name"));
 -              if (!prefixcmp(argv0, "refs/"))
 -                      argv0 += 5;
 -              if (!prefixcmp(argv0, "remotes/"))
 -                      argv0 += 8;
 +              skip_prefix(argv0, "refs/", &argv0);
 +              skip_prefix(argv0, "remotes/", &argv0);
                argv0 = strchr(argv0, '/');
                if (!argv0 || !argv0[1])
                        die (_("Missing branch name; try -b"));