git.el: Prepend a slash to the file name when adding to .gitignore.
[gitweb.git] / builtin-read-tree.c
index d70411f2afc6f6efa3d3479b97f68c24db099051..6df5d7c5cbe2cd524cda9e0636c3ed5a8259cf33 100644 (file)
@@ -31,8 +31,7 @@ static int merge_size = 0;
 
 static struct object_list *trees = NULL;
 
-static struct cache_entry df_conflict_entry = {
-};
+static struct cache_entry df_conflict_entry;
 
 struct tree_entry_list {
        struct tree_entry_list *next;
@@ -44,38 +43,30 @@ struct tree_entry_list {
        const unsigned char *sha1;
 };
 
-static struct tree_entry_list df_conflict_list = {
-       .name = NULL,
-       .next = &df_conflict_list
-};
+static struct tree_entry_list df_conflict_list;
 
 typedef int (*merge_fn_t)(struct cache_entry **src);
 
 static struct tree_entry_list *create_tree_entry_list(struct tree *tree)
 {
        struct tree_desc desc;
+       struct name_entry one;
        struct tree_entry_list *ret = NULL;
        struct tree_entry_list **list_p = &ret;
 
        desc.buf = tree->buffer;
        desc.size = tree->size;
 
-       while (desc.size) {
-               unsigned mode;
-               const char *path;
-               const unsigned char *sha1;
+       while (tree_entry(&desc, &one)) {
                struct tree_entry_list *entry;
 
-               sha1 = tree_entry_extract(&desc, &path, &mode);
-               update_tree_entry(&desc);
-
                entry = xmalloc(sizeof(struct tree_entry_list));
-               entry->name = path;
-               entry->sha1 = sha1;
-               entry->mode = mode;
-               entry->directory = S_ISDIR(mode) != 0;
-               entry->executable = (mode & S_IXUSR) != 0;
-               entry->symlink = S_ISLNK(mode) != 0;
+               entry->name = one.path;
+               entry->sha1 = one.sha1;
+               entry->mode = one.mode;
+               entry->directory = S_ISDIR(one.mode) != 0;
+               entry->executable = (one.mode & S_IXUSR) != 0;
+               entry->symlink = S_ISLNK(one.mode) != 0;
                entry->next = NULL;
 
                *list_p = entry;
@@ -339,14 +330,9 @@ static void setup_progress_signal(void)
        setitimer(ITIMER_REAL, &v, NULL);
 }
 
+static struct checkout state;
 static void check_updates(struct cache_entry **src, int nr)
 {
-       static struct checkout state = {
-               .base_dir = "",
-               .force = 1,
-               .quiet = 1,
-               .refresh_cache = 1,
-       };
        unsigned short mask = htons(CE_UPDATE);
        unsigned last_percent = 200, cnt = 0, total = 0;
 
@@ -382,6 +368,7 @@ static void check_updates(struct cache_entry **src, int nr)
                                        fprintf(stderr, "%4u%% (%u/%u) done\r",
                                                percent, cnt, total);
                                        last_percent = percent;
+                                       progress_update = 0;
                                }
                        }
                }
@@ -804,10 +791,8 @@ static int oneway_merge(struct cache_entry **src)
                return error("Cannot do a oneway merge of %d trees",
                             merge_size);
 
-       if (!a) {
-               invalidate_ce_path(old);
+       if (!a)
                return deleted_entry(old, old);
-       }
        if (old && same(old, a)) {
                if (reset) {
                        struct stat st;
@@ -822,51 +807,47 @@ static int oneway_merge(struct cache_entry **src)
 
 static int read_cache_unmerged(void)
 {
-       int i, deleted;
+       int i;
        struct cache_entry **dst;
+       struct cache_entry *last = NULL;
 
        read_cache();
        dst = active_cache;
-       deleted = 0;
        for (i = 0; i < active_nr; i++) {
                struct cache_entry *ce = active_cache[i];
                if (ce_stage(ce)) {
-                       deleted++;
+                       if (last && !strcmp(ce->name, last->name))
+                               continue;
                        invalidate_ce_path(ce);
-                       continue;
+                       last = ce;
+                       ce->ce_mode = 0;
+                       ce->ce_flags &= ~htons(CE_STAGEMASK);
                }
-               if (deleted)
-                       *dst = ce;
-               dst++;
+               *dst++ = ce;
        }
-       active_nr -= deleted;
-       return deleted;
+       active_nr = dst - active_cache;
+       return !!last;
 }
 
 static void prime_cache_tree_rec(struct cache_tree *it, struct tree *tree)
 {
        struct tree_desc desc;
+       struct name_entry entry;
        int cnt;
 
        memcpy(it->sha1, tree->object.sha1, 20);
        desc.buf = tree->buffer;
        desc.size = tree->size;
        cnt = 0;
-       while (desc.size) {
-               unsigned mode;
-               const char *name;
-               const unsigned char *sha1;
-
-               sha1 = tree_entry_extract(&desc, &name, &mode);
-               update_tree_entry(&desc);
-               if (!S_ISDIR(mode))
+       while (tree_entry(&desc, &entry)) {
+               if (!S_ISDIR(entry.mode))
                        cnt++;
                else {
                        struct cache_tree_sub *sub;
-                       struct tree *subtree = lookup_tree(sha1);
+                       struct tree *subtree = lookup_tree(entry.sha1);
                        if (!subtree->object.parsed)
                                parse_tree(subtree);
-                       sub = cache_tree_sub(it, name);
+                       sub = cache_tree_sub(it, entry.path);
                        sub->cache_tree = cache_tree();
                        prime_cache_tree_rec(sub->cache_tree, subtree);
                        cnt += sub->cache_tree->entry_count;
@@ -887,7 +868,7 @@ static void prime_cache_tree(void)
 
 static const char read_tree_usage[] = "git-read-tree (<sha> | [[-m [--aggressive] | --reset | --prefix=<prefix>] [-u | -i]] <sha1> [<sha2> [<sha3>]])";
 
-static struct cache_file cache_file;
+static struct lock_file lock_file;
 
 int cmd_read_tree(int argc, const char **argv, char **envp)
 {
@@ -895,12 +876,18 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
        unsigned char sha1[20];
        merge_fn_t fn = NULL;
 
+       df_conflict_list.next = &df_conflict_list;
+       state.base_dir = "";
+       state.force = 1;
+       state.quiet = 1;
+       state.refresh_cache = 1;
+
        setup_git_directory();
        git_config(git_default_config);
 
-       newfd = hold_index_file_for_update(&cache_file, get_index_file());
+       newfd = hold_lock_file_for_update(&lock_file, get_index_file());
        if (newfd < 0)
-               die("unable to create new cachefile");
+               die("unable to create new index file");
 
        git_config(git_default_config);
 
@@ -945,7 +932,10 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
                        continue;
                }
 
-               /* This differs from "-m" in that we'll silently ignore unmerged entries */
+               /* This differs from "-m" in that we'll silently ignore
+                * unmerged entries and overwrite working tree files that
+                * correspond to them.
+                */
                if (!strcmp(arg, "--reset")) {
                        if (stage || merge || prefix)
                                usage(read_tree_usage);
@@ -1040,13 +1030,13 @@ int cmd_read_tree(int argc, const char **argv, char **envp)
         * valid cache-tree because the index must match exactly
         * what came from the tree.
         */
-       if (trees && trees->item && (!merge || (stage == 2))) {
+       if (trees && trees->item && !prefix && (!merge || (stage == 2))) {
                cache_tree_free(&active_cache_tree);
                prime_cache_tree();
        }
 
        if (write_cache(newfd, active_cache, active_nr) ||
-           commit_index_file(&cache_file))
+           close(newfd) || commit_lock_file(&lock_file))
                die("unable to write new index file");
        return 0;
 }