Code

Merge branch 'lt/maint-diff-reduce-lstat'
authorJunio C Hamano <gitster@pobox.com>
Sat, 23 May 2009 08:40:33 +0000 (01:40 -0700)
committerJunio C Hamano <gitster@pobox.com>
Sat, 23 May 2009 08:40:33 +0000 (01:40 -0700)
* lt/maint-diff-reduce-lstat:
  Teach 'git checkout' to preload the index contents
  Avoid unnecessary 'lstat()' calls in 'get_stat_data()'

1  2 
builtin-checkout.c
diff-lib.c

diff --combined builtin-checkout.c
index f2d7ef01b0bbe667ae8042f7a806a634fa0aa46b,f1342abd025a3dc5f533205f623c1a82ffbf2ebe..b8a4b0139b3b9c2f731315413a73db30edaf9231
@@@ -5,7 -5,6 +5,7 @@@
  #include "commit.h"
  #include "tree.h"
  #include "tree-walk.h"
 +#include "cache-tree.h"
  #include "unpack-trees.h"
  #include "dir.h"
  #include "run-command.h"
@@@ -39,13 -38,23 +39,13 @@@ struct checkout_opts 
  static int post_checkout_hook(struct commit *old, struct commit *new,
                              int changed)
  {
 -      struct child_process proc;
 -      const char *name = git_path("hooks/post-checkout");
 -      const char *argv[5];
 +      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);
 +      /* "new" can be NULL when checking out from the index before
 +         a commit exists. */
  
 -      if (access(name, X_OK) < 0)
 -              return 0;
 -
 -      memset(&proc, 0, sizeof(proc));
 -      argv[0] = name;
 -      argv[1] = xstrdup(sha1_to_hex(old ? old->object.sha1 : null_sha1));
 -      argv[2] = xstrdup(sha1_to_hex(new->object.sha1));
 -      argv[3] = changed ? "1" : "0";
 -      argv[4] = NULL;
 -      proc.argv = argv;
 -      proc.no_stdin = 1;
 -      proc.stdout_to_stderr = 1;
 -      return run_command(&proc);
  }
  
  static int update_some(const unsigned char *sha1, const char *base, int baselen,
@@@ -54,6 -63,9 +54,6 @@@
        int len;
        struct cache_entry *ce;
  
 -      if (S_ISGITLINK(mode))
 -              return 0;
 -
        if (S_ISDIR(mode))
                return READ_TREE_RECURSIVE;
  
@@@ -179,7 -191,7 +179,7 @@@ static int checkout_merged(int pos, str
        /*
         * NEEDSWORK:
         * There is absolutely no reason to write this as a blob object
 -       * and create a phoney cache entry just to leak.  This hack is
 +       * and create a phony cache entry just to leak.  This hack is
         * primarily to get to the write_entry() machinery that massages
         * the contents to work-tree format and writes out which only
         * allows it for a cache entry.  The code in write_entry() needs
@@@ -216,7 -228,7 +216,7 @@@ static int checkout_paths(struct tree *
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
  
        newfd = hold_locked_index(lock_file, 1);
-       if (read_cache() < 0)
+       if (read_cache_preload(pathspec) < 0)
                return error("corrupt index file");
  
        if (source_tree)
  
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
 -              pathspec_match(pathspec, ps_matched, ce->name, 0);
 +              match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, ps_matched);
        }
  
        if (report_path_error(ps_matched, pathspec, 0))
        /* Any unmerged paths? */
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
 -              if (pathspec_match(pathspec, NULL, ce->name, 0)) {
 +              if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
                        if (!ce_stage(ce))
                                continue;
                        if (opts->force) {
        state.refresh_cache = 1;
        for (pos = 0; pos < active_nr; pos++) {
                struct cache_entry *ce = active_cache[pos];
 -              if (pathspec_match(pathspec, NULL, ce->name, 0)) {
 +              if (match_pathspec(pathspec, ce->name, ce_namelen(ce), 0, NULL)) {
                        if (!ce_stage(ce)) {
                                errs |= checkout_entry(ce, &state, NULL);
                                continue;
@@@ -293,8 -305,6 +293,8 @@@ static void show_local_changes(struct o
        init_revisions(&rev, NULL);
        rev.abbrev = 0;
        rev.diffopt.output_format |= DIFF_FORMAT_NAME_STATUS;
 +      if (diff_setup_done(&rev.diffopt) < 0)
 +              die("diff_setup_done failed");
        add_pending_object(&rev, head, NULL);
        run_diff_index(&rev, 0);
  }
@@@ -351,11 -361,8 +351,11 @@@ struct branch_info 
  static void setup_branch_path(struct branch_info *branch)
  {
        struct strbuf buf = STRBUF_INIT;
 -      strbuf_addstr(&buf, "refs/heads/");
 -      strbuf_addstr(&buf, branch->name);
 +
 +      strbuf_branchname(&buf, branch->name);
 +      if (strcmp(buf.buf, branch->name))
 +              branch->name = xstrdup(buf.buf);
 +      strbuf_splice(&buf, 0, 0, "refs/heads/", 11);
        branch->path = strbuf_detach(&buf, NULL);
  }
  
@@@ -366,7 -373,7 +366,7 @@@ static int merge_working_tree(struct ch
        struct lock_file *lock_file = xcalloc(1, sizeof(struct lock_file));
        int newfd = hold_locked_index(lock_file, 1);
  
-       if (read_cache() < 0)
+       if (read_cache_preload(NULL) < 0)
                return error("corrupt index file");
  
        if (opts->force) {
                topts.verbose_update = !opts->quiet;
                topts.fn = twoway_merge;
                topts.dir = xcalloc(1, sizeof(*topts.dir));
 -              topts.dir->show_ignored = 1;
 +              topts.dir->flags |= DIR_SHOW_IGNORED;
                topts.dir->exclude_per_dir = ".gitignore";
                tree = parse_tree_indirect(old->commit->object.sha1);
                init_tree_desc(&trees[0], tree->buffer, tree->size);
@@@ -496,10 -503,10 +496,10 @@@ static void update_refs_for_switch(stru
                create_symref("HEAD", new->path, msg.buf);
                if (!opts->quiet) {
                        if (old->path && !strcmp(new->path, old->path))
 -                              fprintf(stderr, "Already on \"%s\"\n",
 +                              fprintf(stderr, "Already on '%s'\n",
                                        new->name);
                        else
 -                              fprintf(stderr, "Switched to%s branch \"%s\"\n",
 +                              fprintf(stderr, "Switched to%s branch '%s'\n",
                                        opts->new_branch ? " a new" : "",
                                        new->name);
                }
                           REF_NODEREF, DIE_ON_ERR);
                if (!opts->quiet) {
                        if (old->path)
 -                              fprintf(stderr, "Note: moving to \"%s\" which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
 +                              fprintf(stderr, "Note: moving to '%s' which isn't a local branch\nIf you want to create a new branch from this checkout, you may do so\n(now or later) by using -b with the checkout command again. Example:\n  git checkout -b <new_branch_name>\n", new->name);
                        describe_detached_head("HEAD is now at", new->commit);
                }
        }
@@@ -541,10 -548,18 +541,10 @@@ static int switch_branches(struct check
                parse_commit(new->commit);
        }
  
 -      /*
 -       * If we were on a detached HEAD, but we are now moving to
 -       * a new commit, we want to mention the old commit once more
 -       * to remind the user that it might be lost.
 -       */
 -      if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
 -              describe_detached_head("Previous HEAD position was", old.commit);
 -
        if (!old.commit && !opts->force) {
                if (!opts->quiet) {
 -                      fprintf(stderr, "warning: You appear to be on a branch yet to be born.\n");
 -                      fprintf(stderr, "warning: Forcing checkout of %s.\n", new->name);
 +                      warning("You appear to be on a branch yet to be born.");
 +                      warning("Forcing checkout of %s.", new->name);
                }
                opts->force = 1;
        }
        if (ret)
                return ret;
  
 +      /*
 +       * If we were on a detached HEAD, but have now moved to
 +       * a new commit, we want to mention the old commit once more
 +       * to remind the user that it might be lost.
 +       */
 +      if (!opts->quiet && !old.path && old.commit && new->commit != old.commit)
 +              describe_detached_head("Previous HEAD position was", old.commit);
 +
        update_refs_for_switch(opts, &old, new);
  
        ret = post_checkout_hook(old.commit, new->commit, 1);
@@@ -664,9 -671,6 +664,9 @@@ int cmd_checkout(int argc, const char *
                arg = argv[0];
                has_dash_dash = (argc > 1) && !strcmp(argv[1], "--");
  
 +              if (!strcmp(arg, "-"))
 +                      arg = "@{-1}";
 +
                if (get_sha1(arg, rev)) {
                        if (has_dash_dash)          /* case (1) */
                                die("invalid reference: %s", arg);
@@@ -731,11 -735,12 +731,11 @@@ no_reference
  
        if (opts.new_branch) {
                struct strbuf buf = STRBUF_INIT;
 -              strbuf_addstr(&buf, "refs/heads/");
 -              strbuf_addstr(&buf, opts.new_branch);
 +              if (strbuf_check_branch_ref(&buf, opts.new_branch))
 +                      die("git checkout: we do not like '%s' as a branch name.",
 +                          opts.new_branch);
                if (!get_sha1(buf.buf, rev))
                        die("git checkout: branch %s already exists", opts.new_branch);
 -              if (check_ref_format(buf.buf))
 -                      die("git checkout: we do not like '%s' as a branch name.", opts.new_branch);
                strbuf_release(&buf);
        }
  
diff --combined diff-lib.c
index a310fb2ad08cfb5fac01f5519e8b95b2338b07db,d230efc146a73ae84cfd11c829c8404345d77273..0aba6cda3c01e17b07bb7235b0395ba50256aedd
@@@ -31,7 -31,7 +31,7 @@@ static int check_removed(const struct c
                        return -1;
                return 1;
        }
 -      if (has_symlink_leading_path(ce_namelen(ce), ce->name))
 +      if (has_symlink_leading_path(ce->name, ce_namelen(ce)))
                return 1;
        if (S_ISDIR(st->st_mode)) {
                unsigned char sub[20];
@@@ -61,12 -61,14 +61,12 @@@ int run_diff_files(struct rev_info *rev
        int silent_on_removed = option & DIFF_SILENT_ON_REMOVED;
        unsigned ce_option = ((option & DIFF_RACY_IS_MODIFIED)
                              ? CE_MATCH_RACY_IS_DIRTY : 0);
 -      char symcache[PATH_MAX];
  
        diff_set_mnemonic_prefix(&revs->diffopt, "i/", "w/");
  
        if (diff_unmerged_stage < 0)
                diff_unmerged_stage = 2;
        entries = active_nr;
 -      symcache[0] = '\0';
        for (i = 0; i < entries; i++) {
                struct stat st;
                unsigned int oldmode, newmode;
   * diff-index
   */
  
 -struct oneway_unpack_data {
 -      struct rev_info *revs;
 -      char symcache[PATH_MAX];
 -};
 -
  /* A file entry went away or appeared */
  static void diff_index_show_file(struct rev_info *revs,
                                 const char *prefix,
  static int get_stat_data(struct cache_entry *ce,
                         const unsigned char **sha1p,
                         unsigned int *modep,
 -                       int cached, int match_missing,
 -                       struct oneway_unpack_data *cbdata)
 +                       int cached, int match_missing)
  {
        const unsigned char *sha1 = ce->sha1;
        unsigned int mode = ce->ce_mode;
  
-       if (!cached) {
+       if (!cached && !ce_uptodate(ce)) {
                int changed;
                struct stat st;
                changed = check_removed(ce, &st);
        return 0;
  }
  
 -static void show_new_file(struct oneway_unpack_data *cbdata,
 +static void show_new_file(struct rev_info *revs,
                          struct cache_entry *new,
                          int cached, int match_missing)
  {
        const unsigned char *sha1;
        unsigned int mode;
 -      struct rev_info *revs = cbdata->revs;
  
        /*
         * New file in the index: it might actually be different in
         * the working copy.
         */
 -      if (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0)
 +      if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0)
                return;
  
        diff_index_show_file(revs, "+", new, sha1, mode);
  }
  
 -static int show_modified(struct oneway_unpack_data *cbdata,
 +static int show_modified(struct rev_info *revs,
                         struct cache_entry *old,
                         struct cache_entry *new,
                         int report_missing,
  {
        unsigned int mode, oldmode;
        const unsigned char *sha1;
 -      struct rev_info *revs = cbdata->revs;
  
 -      if (get_stat_data(new, &sha1, &mode, cached, match_missing, cbdata) < 0) {
 +      if (get_stat_data(new, &sha1, &mode, cached, match_missing) < 0) {
                if (report_missing)
                        diff_index_show_file(revs, "-", old,
                                             old->sha1, old->ce_mode);
@@@ -334,7 -344,8 +334,7 @@@ static void do_oneway_diff(struct unpac
        struct cache_entry *idx,
        struct cache_entry *tree)
  {
 -      struct oneway_unpack_data *cbdata = o->unpack_data;
 -      struct rev_info *revs = cbdata->revs;
 +      struct rev_info *revs = o->unpack_data;
        int match_missing, cached;
  
        /*
         * Something added to the tree?
         */
        if (!tree) {
 -              show_new_file(cbdata, idx, cached, match_missing);
 +              show_new_file(revs, idx, cached, match_missing);
                return;
        }
  
        }
  
        /* Show difference between old and new */
 -      show_modified(cbdata, tree, idx, 1, cached, match_missing);
 +      show_modified(revs, tree, idx, 1, cached, match_missing);
  }
  
  static inline void skip_same_name(struct cache_entry *ce, struct unpack_trees_options *o)
@@@ -407,7 -418,8 +407,7 @@@ static int oneway_diff(struct cache_ent
  {
        struct cache_entry *idx = src[0];
        struct cache_entry *tree = src[1];
 -      struct oneway_unpack_data *cbdata = o->unpack_data;
 -      struct rev_info *revs = cbdata->revs;
 +      struct rev_info *revs = o->unpack_data;
  
        if (idx && ce_stage(idx))
                skip_same_name(idx, o);
@@@ -434,6 -446,7 +434,6 @@@ int run_diff_index(struct rev_info *rev
        const char *tree_name;
        struct unpack_trees_options opts;
        struct tree_desc t;
 -      struct oneway_unpack_data unpack_cb;
  
        mark_merge_entries();
  
        if (!tree)
                return error("bad tree object %s", tree_name);
  
 -      unpack_cb.revs = revs;
 -      unpack_cb.symcache[0] = '\0';
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
        opts.index_only = cached;
        opts.merge = 1;
        opts.fn = oneway_diff;
 -      opts.unpack_data = &unpack_cb;
 +      opts.unpack_data = revs;
        opts.src_index = &the_index;
        opts.dst_index = NULL;
  
@@@ -471,6 -486,7 +471,6 @@@ int do_diff_cache(const unsigned char *
        struct cache_entry *last = NULL;
        struct unpack_trees_options opts;
        struct tree_desc t;
 -      struct oneway_unpack_data unpack_cb;
  
        /*
         * This is used by git-blame to run diff-cache internally;
        if (!tree)
                die("bad tree object %s", sha1_to_hex(tree_sha1));
  
 -      unpack_cb.revs = &revs;
 -      unpack_cb.symcache[0] = '\0';
        memset(&opts, 0, sizeof(opts));
        opts.head_idx = 1;
        opts.index_only = 1;
        opts.merge = 1;
        opts.fn = oneway_diff;
 -      opts.unpack_data = &unpack_cb;
 +      opts.unpack_data = &revs;
        opts.src_index = &the_index;
        opts.dst_index = &the_index;
  
                exit(128);
        return 0;
  }
 +
 +int index_differs_from(const char *def, int diff_flags)
 +{
 +      struct rev_info rev;
 +
 +      init_revisions(&rev, NULL);
 +      setup_revisions(0, NULL, &rev, def);
 +      DIFF_OPT_SET(&rev.diffopt, QUIET);
 +      DIFF_OPT_SET(&rev.diffopt, EXIT_WITH_STATUS);
 +      rev.diffopt.flags |= diff_flags;
 +      run_diff_index(&rev, 1);
 +      if (rev.pending.alloc)
 +              free(rev.pending.objects);
 +      return (DIFF_OPT_TST(&rev.diffopt, HAS_CHANGES) != 0);
 +}