Merge branch 'jc/cache-tree' into next
authorJunio C Hamano <junkio@cox.net>
Tue, 25 Apr 2006 04:28:07 +0000 (21:28 -0700)
committerJunio C Hamano <junkio@cox.net>
Tue, 25 Apr 2006 04:28:07 +0000 (21:28 -0700)
* jc/cache-tree:
index: make the index file format extensible.
cache-tree: protect against "git prune".
Add test-dump-cache-tree

1  2 
.gitignore
Makefile
update-index.c
diff --combined .gitignore
index 145f8555ad4b5c13cb7a6076cf7d9e809beff952,7906909b306f80ed74d6e53bb8514a889057194c..cdb2d53318148dbfde43cbcf218abcbb5cf5a434
@@@ -123,7 -123,7 +123,8 @@@ git-write-tre
  git-core-*/?*
  test-date
  test-delta
+ test-dump-cache-tree
 +test-gsimm
  common-cmds.h
  *.tar.gz
  *.dsc
diff --combined Makefile
index 589dbe1d8b27371157018c438173847995b2465b,1aa96f4f2e166afa3234264fdb4832bdbd535677..41a0d93a6cc7fa075fb1b66eaf40a2907c8bc296
+++ b/Makefile
@@@ -199,7 -199,7 +199,7 @@@ LIB_H = 
        tree-walk.h log-tree.h
  
  DIFF_OBJS = \
 -      diff-lib.o diffcore-break.o diffcore-order.o \
 +      diff.o diff-lib.o diffcore-break.o diffcore-order.o \
        diffcore-pickaxe.o diffcore-rename.o tree-diff.o combine-diff.o \
        diffcore-delta.o log-tree.o
  
@@@ -611,9 -611,9 +611,12 @@@ test-date$X: test-date.c date.o ctype.
  test-delta$X: test-delta.c diff-delta.o patch-delta.o
        $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^ -lz
  
+ test-dump-cache-tree$X: dump-cache-tree.o $(GITLIBS)
+       $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $(filter %.o,$^) $(LIBS)
 +test-gsimm$X: test-gsimm.c gsimm.o rabinpoly.o
 +      $(CC) $(ALL_CFLAGS) -o $@ $(ALL_LDFLAGS) $^
 +
  check:
        for i in *.c; do sparse $(ALL_CFLAGS) $(SPARSE_FLAGS) $$i || exit; done
  
@@@ -662,7 -662,6 +665,7 @@@ clean
        rm -f *.o mozilla-sha1/*.o arm/*.o ppc/*.o compat/*.o xdiff/*.o \
                $(LIB_FILE) $(XDIFF_LIB)
        rm -f $(ALL_PROGRAMS) $(BUILT_INS) git$X
 +      rm -f test-date$X test-delta$X test-gsimm$X
        rm -f *.spec *.pyc *.pyo */*.pyc */*.pyo common-cmds.h TAGS tags
        rm -rf $(GIT_TARNAME)
        rm -f $(GIT_TARNAME).tar.gz git-core_$(GIT_VERSION)-*.tar.gz
diff --combined update-index.c
index ea1a3770573dd00654ea6c7d00ae8b5d7a9387f8,d6d3295e329ed2d0f1f46824a210b86c0c092b8f..157488ff1a87df262e6177671f5e568b8d155de3
@@@ -6,13 -6,8 +6,9 @@@
  #include "cache.h"
  #include "strbuf.h"
  #include "quote.h"
- #include "tree.h"
 +#include "tree-walk.h"
  #include "cache-tree.h"
  
- static unsigned char active_cache_sha1[20];
- static struct cache_tree *active_cache_tree;
  /*
   * Default to not allowing changes to the list of files. The
   * tool doesn't actually care, but this makes it harder to add
@@@ -342,7 -337,7 +338,7 @@@ static int add_cacheinfo(unsigned int m
        return 0;
  }
  
 -static int chmod_path(int flip, const char *path)
 +static void chmod_path(int flip, const char *path)
  {
        int pos;
        struct cache_entry *ce;
  
        pos = cache_name_pos(path, strlen(path));
        if (pos < 0)
 -              return -1;
 +              goto fail;
        ce = active_cache[pos];
        mode = ntohl(ce->ce_mode);
        if (!S_ISREG(mode))
 -              return -1;
 +              goto fail;
        switch (flip) {
        case '+':
                ce->ce_mode |= htonl(0111); break;
        case '-':
                ce->ce_mode &= htonl(~0111); break;
        default:
 -              return -1;
 +              goto fail;
        }
        cache_tree_invalidate_path(active_cache_tree, path);
        active_cache_changed = 1;
 -      return 0;
 +      report("chmod %cx '%s'", flip, path);
 +      return;
 + fail:
 +      die("git-update-index: cannot chmod %cx '%s'", flip, path);
  }
  
  static struct cache_file cache_file;
@@@ -491,125 -483,6 +487,125 @@@ static void read_index_info(int line_te
  static const char update_index_usage[] =
  "git-update-index [-q] [--add] [--replace] [--remove] [--unmerged] [--refresh] [--cacheinfo] [--chmod=(+|-)x] [--info-only] [--force-remove] [--stdin] [--index-info] [--ignore-missing] [-z] [--verbose] [--] <file>...";
  
 +static unsigned char head_sha1[20];
 +static unsigned char merge_head_sha1[20];
 +
 +static struct cache_entry *read_one_ent(const char *which,
 +                                      unsigned char *ent, const char *path,
 +                                      int namelen, int stage)
 +{
 +      unsigned mode;
 +      unsigned char sha1[20];
 +      int size;
 +      struct cache_entry *ce;
 +
 +      if (get_tree_entry(ent, path, sha1, &mode)) {
 +              error("%s: not in %s branch.", path, which);
 +              return NULL;
 +      }
 +      if (mode == S_IFDIR) {
 +              error("%s: not a blob in %s branch.", path, which);
 +              return NULL;
 +      }
 +      size = cache_entry_size(namelen);
 +      ce = xcalloc(1, size);
 +
 +      memcpy(ce->sha1, sha1, 20);
 +      memcpy(ce->name, path, namelen);
 +      ce->ce_flags = create_ce_flags(namelen, stage);
 +      ce->ce_mode = create_ce_mode(mode);
 +      return ce;
 +}
 +
 +static int unresolve_one(const char *path)
 +{
 +      int namelen = strlen(path);
 +      int pos;
 +      int ret = 0;
 +      struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
 +
 +      /* See if there is such entry in the index. */
 +      pos = cache_name_pos(path, namelen);
 +      if (pos < 0) {
 +              /* If there isn't, either it is unmerged, or
 +               * resolved as "removed" by mistake.  We do not
 +               * want to do anything in the former case.
 +               */
 +              pos = -pos-1;
 +              if (pos < active_nr) {
 +                      struct cache_entry *ce = active_cache[pos];
 +                      if (ce_namelen(ce) == namelen &&
 +                          !memcmp(ce->name, path, namelen)) {
 +                              fprintf(stderr,
 +                                      "%s: skipping still unmerged path.\n",
 +                                      path);
 +                              goto free_return;
 +                      }
 +              }
 +      }
 +
 +      /* Grab blobs from given path from HEAD and MERGE_HEAD,
 +       * stuff HEAD version in stage #2,
 +       * stuff MERGE_HEAD version in stage #3.
 +       */
 +      ce_2 = read_one_ent("our", head_sha1, path, namelen, 2);
 +      ce_3 = read_one_ent("their", merge_head_sha1, path, namelen, 3);
 +
 +      if (!ce_2 || !ce_3) {
 +              ret = -1;
 +              goto free_return;
 +      }
 +      if (!memcmp(ce_2->sha1, ce_3->sha1, 20) &&
 +          ce_2->ce_mode == ce_3->ce_mode) {
 +              fprintf(stderr, "%s: identical in both, skipping.\n",
 +                      path);
 +              goto free_return;
 +      }
 +
 +      cache_tree_invalidate_path(active_cache_tree, path);
 +      remove_file_from_cache(path);
 +      if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
 +              error("%s: cannot add our version to the index.", path);
 +              ret = -1;
 +              goto free_return;
 +      }
 +      if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
 +              return 0;
 +      error("%s: cannot add their version to the index.", path);
 +      ret = -1;
 + free_return:
 +      free(ce_2);
 +      free(ce_3);
 +      return ret;
 +}
 +
 +static void read_head_pointers(void)
 +{
 +      if (read_ref(git_path("HEAD"), head_sha1))
 +              die("No HEAD -- no initial commit yet?\n");
 +      if (read_ref(git_path("MERGE_HEAD"), merge_head_sha1)) {
 +              fprintf(stderr, "Not in the middle of a merge.\n");
 +              exit(0);
 +      }
 +}
 +
 +static int do_unresolve(int ac, const char **av)
 +{
 +      int i;
 +      int err = 0;
 +
 +      /* Read HEAD and MERGE_HEAD; if MERGE_HEAD does not exist, we
 +       * are not doing a merge, so exit with success status.
 +       */
 +      read_head_pointers();
 +
 +      for (i = 1; i < ac; i++) {
 +              const char *arg = av[i];
 +              err |= unresolve_one(arg);
 +      }
 +      return err;
 +}
 +
  int main(int argc, const char **argv)
  {
        int i, newfd, entries, has_errors = 0, line_termination = '\n';
        int read_from_stdin = 0;
        const char *prefix = setup_git_directory();
        int prefix_length = prefix ? strlen(prefix) : 0;
 +      char set_executable_bit = 0;
  
        git_config(git_default_config);
  
        if (newfd < 0)
                die("unable to create new cachefile");
  
-       entries = read_cache_1(active_cache_sha1);
+       entries = read_cache();
        if (entries < 0)
                die("cache corrupted");
-       active_cache_tree = read_cache_tree(active_cache_sha1);
  
        for (i = 1 ; i < argc; i++) {
                const char *path = argv[i];
                            !strcmp(path, "--chmod=+x")) {
                                if (argc <= i+1)
                                        die("git-update-index: %s <path>", path);
 -                              if (chmod_path(path[8], argv[++i]))
 -                                      die("git-update-index: %s cannot chmod %s", path, argv[i]);
 +                              set_executable_bit = path[8];
                                continue;
                        }
                        if (!strcmp(path, "--assume-unchanged")) {
                                read_index_info(line_termination);
                                break;
                        }
 +                      if (!strcmp(path, "--unresolve")) {
 +                              has_errors = do_unresolve(argc - i, argv + i);
 +                              if (has_errors)
 +                                      active_cache_changed = 0;
 +                              goto finish;
 +                      }
                        if (!strcmp(path, "--ignore-missing")) {
                                not_new = 1;
                                continue;
                        die("unknown option %s", path);
                }
                update_one(path, prefix, prefix_length);
 +              if (set_executable_bit)
 +                      chmod_path(set_executable_bit, path);
        }
        if (read_from_stdin) {
                struct strbuf buf;
                        else
                                path_name = buf.buf;
                        update_one(path_name, prefix, prefix_length);
 +                      if (set_executable_bit) {
 +                              const char *p = prefix_path(prefix, prefix_length, path_name);
 +                              chmod_path(set_executable_bit, p);
 +                      }
                        if (path_name != buf.buf)
                                free(path_name);
                }
        }
 +
 + finish:
        if (active_cache_changed) {
-               if (write_cache_1(newfd, active_cache, active_nr,
-                                 active_cache_sha1) ||
+               if (write_cache(newfd, active_cache, active_nr) ||
                    commit_index_file(&cache_file))
                        die("Unable to write new cachefile");
-               write_cache_tree(active_cache_sha1, active_cache_tree);
        }
  
        return has_errors ? 1 : 0;