Merge branch 'jc/read-tree-df' (early part)
authorJunio C Hamano <junkio@cox.net>
Sun, 8 Apr 2007 06:52:40 +0000 (23:52 -0700)
committerJunio C Hamano <junkio@cox.net>
Sun, 8 Apr 2007 06:52:40 +0000 (23:52 -0700)
* 'jc/read-tree-df' (early part):
Fix switching to a branch with D/F when current branch has file D.
Fix twoway_merge that passed d/f conflict marker to merged_entry().
Fix read-tree --prefix=dir/.
unpack-trees: get rid of *indpos parameter.
unpack_trees.c: pass unpack_trees_options structure to keep_entry() as well.
add_cache_entry(): removal of file foo does not conflict with foo/bar

1  2 
builtin-read-tree.c
read-cache.c
diff --combined builtin-read-tree.c
index 213bd93c7f535ad90c49bc30280563fc3f4e6268,5fb84b81a7fd239141c83df1d5e3582a65543984..316fb0f8dae022b35a89b71c94a22331a77a500a
@@@ -84,7 -84,7 +84,7 @@@ static void prime_cache_tree(void
  
  }
  
 -static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] <sha1> [<sha2> [<sha3>]])";
 +static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] [--exclude-per-directory=<gitignore>] [--index-output=<file>] <sha1> [<sha2> [<sha3>]])";
  
  static struct lock_file lock_file;
  
@@@ -100,7 -100,7 +100,7 @@@ int cmd_read_tree(int argc, const char 
        setup_git_directory();
        git_config(git_default_config);
  
 -      newfd = hold_lock_file_for_update(&lock_file, get_index_file(), 1);
 +      newfd = hold_locked_index(&lock_file, 1);
  
        git_config(git_default_config);
  
                        continue;
                }
  
 +              if (!prefixcmp(arg, "--index-output=")) {
 +                      set_alternate_index_output(arg + 15);
 +                      continue;
 +              }
 +
                /* "--prefix=<subdirectory>/" means keep the current index
                 *  entries and put the entries from the tree under the
                 * given subdirectory.
                if (0 <= pos)
                        die("file '%.*s' already exists.",
                                        pfxlen-1, opts.prefix);
+               opts.pos = -1 - pos;
        }
  
        if (opts.merge) {
        }
  
        if (write_cache(newfd, active_cache, active_nr) ||
 -          close(newfd) || commit_lock_file(&lock_file))
 +          close(newfd) || commit_locked_index(&lock_file))
                die("unable to write new index file");
        return 0;
  }
diff --combined read-cache.c
index a8f8a6b2b23cdba612db175ee86a5f0db125c245,823c2c3b08e559a5b0a29dc30c00772301b8cb79..54573ce2ee3b2c70d5419716b20ade61683bc289
@@@ -24,6 -24,8 +24,6 @@@ unsigned int active_nr, active_alloc, a
  
  struct cache_tree *active_cache_tree;
  
 -int cache_errno;
 -
  static void *cache_mmap;
  static size_t cache_mmap_size;
  
@@@ -325,7 -327,7 +325,7 @@@ int remove_file_from_cache(const char *
        return 0;
  }
  
 -int add_file_to_index(const char *path, int verbose)
 +int add_file_to_cache(const char *path, int verbose)
  {
        int size, namelen;
        struct stat st;
@@@ -485,6 -487,8 +485,8 @@@ static int has_file_name(const struct c
                        continue;
                if (p->name[len] != '/')
                        continue;
+               if (!ce_stage(p) && !p->ce_mode)
+                       continue;
                retval = -1;
                if (!ok_to_replace)
                        break;
@@@ -517,26 -521,37 +519,37 @@@ static int has_dir_name(const struct ca
  
                pos = cache_name_pos(name, ntohs(create_ce_flags(len, stage)));
                if (pos >= 0) {
-                       retval = -1;
-                       if (!ok_to_replace)
-                               break;
-                       remove_cache_entry_at(pos);
-                       continue;
+                       /*
+                        * Found one, but not so fast.  This could
+                        * be a marker that says "I was here, but
+                        * I am being removed".  Such an entry is
+                        * not a part of the resulting tree, and
+                        * it is Ok to have a directory at the same
+                        * path.
+                        */
+                       if (stage || active_cache[pos]->ce_mode) {
+                               retval = -1;
+                               if (!ok_to_replace)
+                                       break;
+                               remove_cache_entry_at(pos);
+                               continue;
+                       }
                }
+               else
+                       pos = -pos-1;
  
                /*
                 * Trivial optimization: if we find an entry that
                 * already matches the sub-directory, then we know
                 * we're ok, and we can exit.
                 */
-               pos = -pos-1;
                while (pos < active_nr) {
                        struct cache_entry *p = active_cache[pos];
                        if ((ce_namelen(p) <= len) ||
                            (p->name[len] != '/') ||
                            memcmp(p->name, name, len))
                                break; /* not our subdirectory */
-                       if (ce_stage(p) == stage)
+                       if (ce_stage(p) == stage && (stage || p->ce_mode))
                                /* p is at the same stage as our entry, and
                                 * is a subdirectory of what we are looking
                                 * at, so we cannot have conflicts at our
   */
  static int check_file_directory_conflict(const struct cache_entry *ce, int pos, int ok_to_replace)
  {
+       int retval;
+       /*
+        * When ce is an "I am going away" entry, we allow it to be added
+        */
+       if (!ce_stage(ce) && !ce->ce_mode)
+               return 0;
        /*
         * We check if the path is a sub-path of a subsequent pathname
         * first, since removing those will not change the position
-        * in the array
+        * in the array.
         */
-       int retval = has_file_name(ce, pos, ok_to_replace);
+       retval = has_file_name(ce, pos, ok_to_replace);
        /*
         * Then check if the path might have a clashing sub-directory
         * before it.
@@@ -641,15 -665,14 +663,15 @@@ int add_cache_entry(struct cache_entry 
   * For example, you'd want to do this after doing a "git-read-tree",
   * to link up the stat cache details with the proper files.
   */
 -struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
 +static struct cache_entry *refresh_cache_ent(struct cache_entry *ce, int really, int *err)
  {
        struct stat st;
        struct cache_entry *updated;
        int changed, size;
  
        if (lstat(ce->name, &st) < 0) {
 -              cache_errno = errno;
 +              if (err)
 +                      *err = errno;
                return NULL;
        }
  
        }
  
        if (ce_modified(ce, &st, really)) {
 -              cache_errno = EINVAL;
 +              if (err)
 +                      *err = EINVAL;
                return NULL;
        }
  
@@@ -696,8 -718,6 +718,8 @@@ int refresh_cache(unsigned int flags
  
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce, *new;
 +              int cache_errno = 0;
 +
                ce = active_cache[i];
                if (ce_stage(ce)) {
                        while ((i < active_nr) &&
                        continue;
                }
  
 -              new = refresh_cache_entry(ce, really);
 +              new = refresh_cache_ent(ce, really, &cache_errno);
                if (new == ce)
                        continue;
                if (!new) {
        return has_errors;
  }
  
 +struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
 +{
 +      return refresh_cache_ent(ce, really, NULL);
 +}
 +
  static int verify_hdr(struct cache_header *hdr, unsigned long size)
  {
        SHA_CTX c;