Code

Merge branch 'maint'
[git.git] / read-cache.c
index 4362b11f475748e89e9deaf6257fb0c411948105..056b322fb0c83aeda378f548e13f84d4a65c1e29 100644 (file)
@@ -7,6 +7,7 @@
 #include "cache.h"
 #include "cache-tree.h"
 #include "refs.h"
+#include "dir.h"
 
 /* Index extensions.
  *
@@ -148,6 +149,8 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
                else if (ce_compare_gitlink(ce))
                        changed |= DATA_CHANGED;
                return changed;
+       case 0: /* Special case: unmerged file in index */
+               return MODE_CHANGED | DATA_CHANGED | TYPE_CHANGED;
        default:
                die("internal error: ce_mode is %o", ntohl(ce->ce_mode));
        }
@@ -345,14 +348,43 @@ int remove_file_from_index(struct index_state *istate, const char *path)
        int pos = index_name_pos(istate, path, strlen(path));
        if (pos < 0)
                pos = -pos-1;
+       cache_tree_invalidate_path(istate->cache_tree, path);
        while (pos < istate->cache_nr && !strcmp(istate->cache[pos]->name, path))
                remove_index_entry_at(istate, pos);
        return 0;
 }
 
+static int compare_name(struct cache_entry *ce, const char *path, int namelen)
+{
+       return namelen != ce_namelen(ce) || memcmp(path, ce->name, namelen);
+}
+
+static int index_name_pos_also_unmerged(struct index_state *istate,
+       const char *path, int namelen)
+{
+       int pos = index_name_pos(istate, path, namelen);
+       struct cache_entry *ce;
+
+       if (pos >= 0)
+               return pos;
+
+       /* maybe unmerged? */
+       pos = -1 - pos;
+       if (pos >= istate->cache_nr ||
+                       compare_name((ce = istate->cache[pos]), path, namelen))
+               return -1;
+
+       /* order of preference: stage 2, 1, 3 */
+       if (ce_stage(ce) == 1 && pos + 1 < istate->cache_nr &&
+                       ce_stage((ce = istate->cache[pos + 1])) == 2 &&
+                       !compare_name(ce, path, namelen))
+               pos++;
+       return pos;
+}
+
 int add_file_to_index(struct index_state *istate, const char *path, int verbose)
 {
-       int size, namelen;
+       int size, namelen, pos;
        struct stat st;
        struct cache_entry *ce;
 
@@ -380,22 +412,55 @@ int add_file_to_index(struct index_state *istate, const char *path, int verbose)
                 * from it, otherwise assume unexecutable regular file.
                 */
                struct cache_entry *ent;
-               int pos = index_name_pos(istate, path, namelen);
+               int pos = index_name_pos_also_unmerged(istate, path, namelen);
 
                ent = (0 <= pos) ? istate->cache[pos] : NULL;
                ce->ce_mode = ce_mode_from_stat(ent, st.st_mode);
        }
 
+       pos = index_name_pos(istate, ce->name, namelen);
+       if (0 <= pos &&
+           !ce_stage(istate->cache[pos]) &&
+           !ie_modified(istate, istate->cache[pos], &st, 1)) {
+               /* Nothing changed, really */
+               free(ce);
+               return 0;
+       }
+
        if (index_path(ce->sha1, path, &st, 1))
                die("unable to index file %s", path);
        if (add_index_entry(istate, ce, ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE))
                die("unable to add %s to index",path);
        if (verbose)
                printf("add '%s'\n", path);
-       cache_tree_invalidate_path(istate->cache_tree, path);
        return 0;
 }
 
+struct cache_entry *make_cache_entry(unsigned int mode,
+               const unsigned char *sha1, const char *path, int stage,
+               int refresh)
+{
+       int size, len;
+       struct cache_entry *ce;
+
+       if (!verify_path(path))
+               return NULL;
+
+       len = strlen(path);
+       size = cache_entry_size(len);
+       ce = xcalloc(1, size);
+
+       hashcpy(ce->sha1, sha1);
+       memcpy(ce->name, path, len);
+       ce->ce_flags = create_ce_flags(len, stage);
+       ce->ce_mode = create_ce_mode(mode);
+
+       if (refresh)
+               return refresh_cache_entry(ce, 0);
+
+       return ce;
+}
+
 int ce_same_name(struct cache_entry *a, struct cache_entry *b)
 {
        int len = ce_namelen(a);
@@ -628,13 +693,14 @@ static int check_file_directory_conflict(struct index_state *istate,
        return retval + has_dir_name(istate, ce, pos, ok_to_replace);
 }
 
-int add_index_entry(struct index_state *istate, struct cache_entry *ce, int option)
+static int add_index_entry_with_check(struct index_state *istate, struct cache_entry *ce, int option)
 {
        int pos;
        int ok_to_add = option & ADD_CACHE_OK_TO_ADD;
        int ok_to_replace = option & ADD_CACHE_OK_TO_REPLACE;
        int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
 
+       cache_tree_invalidate_path(istate->cache_tree, ce->name);
        pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags));
 
        /* existing match? Just replace it. */
@@ -670,6 +736,22 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
                pos = index_name_pos(istate, ce->name, ntohs(ce->ce_flags));
                pos = -pos-1;
        }
+       return pos + 1;
+}
+
+int add_index_entry(struct index_state *istate, struct cache_entry *ce, int option)
+{
+       int pos;
+
+       if (option & ADD_CACHE_JUST_APPEND)
+               pos = istate->cache_nr;
+       else {
+               int ret;
+               ret = add_index_entry_with_check(istate, ce, option);
+               if (ret <= 0)
+                       return ret;
+               pos = ret - 1;
+       }
 
        /* Make sure the array is big enough .. */
        if (istate->cache_nr == istate->cache_alloc) {
@@ -680,7 +762,7 @@ int add_index_entry(struct index_state *istate, struct cache_entry *ce, int opti
 
        /* Add it in.. */
        istate->cache_nr++;
-       if (istate->cache_nr > pos)
+       if (istate->cache_nr > pos + 1)
                memmove(istate->cache + pos + 1,
                        istate->cache + pos,
                        (istate->cache_nr - pos - 1) * sizeof(ce));
@@ -745,7 +827,7 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        return updated;
 }
 
-int refresh_index(struct index_state *istate, unsigned int flags)
+int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
 {
        int i;
        int has_errors = 0;
@@ -771,6 +853,9 @@ int refresh_index(struct index_state *istate, unsigned int flags)
                        continue;
                }
 
+               if (pathspec && !match_pathspec(pathspec, ce->name, strlen(ce->name), 0, seen))
+                       continue;
+
                new = refresh_cache_ent(istate, ce, really, &cache_errno);
                if (new == ce)
                        continue;
@@ -1053,7 +1138,7 @@ int write_index(struct index_state *istate, int newfd)
 {
        SHA_CTX c;
        struct cache_header hdr;
-       int i, removed;
+       int i, err, removed;
        struct cache_entry **cache = istate->cache;
        int entries = istate->cache_nr;
 
@@ -1082,16 +1167,15 @@ int write_index(struct index_state *istate, int newfd)
 
        /* Write extension data here */
        if (istate->cache_tree) {
-               unsigned long sz;
-               void *data = cache_tree_write(istate->cache_tree, &sz);
-               if (data &&
-                   !write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sz) &&
-                   !ce_write(&c, newfd, data, sz))
-                       free(data);
-               else {
-                       free(data);
+               struct strbuf sb;
+
+               strbuf_init(&sb, 0);
+               cache_tree_write(&sb, istate->cache_tree);
+               err = write_index_ext_header(&c, newfd, CACHE_EXT_TREE, sb.len) < 0
+                       || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+               strbuf_release(&sb);
+               if (err)
                        return -1;
-               }
        }
        return ce_flush(&c, newfd);
 }