lstat_cache(): print a warning if doing ping-pong between cache types
[gitweb.git] / read-cache.c
index 8579663ee09b1e01cf5228bd8be7c5eb371c5d31..940ec76fdf231ac1345079ca2dc5da88925bcfb6 100644 (file)
@@ -99,27 +99,21 @@ static int ce_compare_data(struct cache_entry *ce, struct stat *st)
 static int ce_compare_link(struct cache_entry *ce, size_t expected_size)
 {
        int match = -1;
-       char *target;
        void *buffer;
        unsigned long size;
        enum object_type type;
-       int len;
+       struct strbuf sb = STRBUF_INIT;
 
-       target = xmalloc(expected_size);
-       len = readlink(ce->name, target, expected_size);
-       if (len != expected_size) {
-               free(target);
+       if (strbuf_readlink(&sb, ce->name, expected_size))
                return -1;
-       }
+
        buffer = read_sha1_file(ce->sha1, &type, &size);
-       if (!buffer) {
-               free(target);
-               return -1;
+       if (buffer) {
+               if (size == sb.len)
+                       match = memcmp(buffer, sb.buf, size);
+               free(buffer);
        }
-       if (size == expected_size)
-               match = memcmp(buffer, target, size);
-       free(buffer);
-       free(target);
+       strbuf_release(&sb);
        return match;
 }
 
@@ -1527,7 +1521,7 @@ int write_index(const struct index_state *istate, int newfd)
 
 /*
  * Read the index file that is potentially unmerged into given
- * index_state, dropping any unmerged entries.  Returns true is
+ * index_state, dropping any unmerged entries.  Returns true if
  * the index is unmerged.  Callers who want to refuse to work
  * from an unmerged state can call this and check its return value,
  * instead of calling read_cache().
@@ -1580,6 +1574,26 @@ static void update_callback(struct diff_queue_struct *q,
                default:
                        die("unexpected diff status %c", p->status);
                case DIFF_STATUS_UNMERGED:
+                       /*
+                        * ADD_CACHE_IGNORE_REMOVAL is unset if "git
+                        * add -u" is calling us, In such a case, a
+                        * missing work tree file needs to be removed
+                        * if there is an unmerged entry at stage #2,
+                        * but such a diff record is followed by
+                        * another with DIFF_STATUS_DELETED (and if
+                        * there is no stage #2, we won't see DELETED
+                        * nor MODIFIED).  We can simply continue
+                        * either way.
+                        */
+                       if (!(data->flags & ADD_CACHE_IGNORE_REMOVAL))
+                               continue;
+                       /*
+                        * Otherwise, it is "git add path" is asking
+                        * to explicitly add it; we fall through.  A
+                        * missing work tree file is an error and is
+                        * caught by add_file_to_index() in such a
+                        * case.
+                        */
                case DIFF_STATUS_MODIFIED:
                case DIFF_STATUS_TYPE_CHANGED:
                        if (add_file_to_index(&the_index, path, data->flags)) {