Documentation: document post-rewrite hook
[gitweb.git] / read-cache.c
index 940ec76fdf231ac1345079ca2dc5da88925bcfb6..79938bf09a7e5c12de90af4cd81be0fdf755113a 100644 (file)
 #include "dir.h"
 #include "tree.h"
 #include "commit.h"
-#include "diff.h"
-#include "diffcore.h"
-#include "revision.h"
 #include "blob.h"
+#include "resolve-undo.h"
+
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
 
 /* Index extensions.
  *
@@ -26,6 +26,7 @@
 
 #define CACHE_EXT(s) ( (s[0]<<24)|(s[1]<<16)|(s[2]<<8)|(s[3]) )
 #define CACHE_EXT_TREE 0x54524545      /* "TREE" */
+#define CACHE_EXT_RESOLVE_UNDO 0x52455543 /* "REUN" */
 
 struct index_state the_index;
 
@@ -67,8 +68,10 @@ void rename_index_entry_at(struct index_state *istate, int nr, const char *new_n
  */
 void fill_stat_cache_info(struct cache_entry *ce, struct stat *st)
 {
-       ce->ce_ctime = st->st_ctime;
-       ce->ce_mtime = st->st_mtime;
+       ce->ce_ctime.sec = (unsigned int)st->st_ctime;
+       ce->ce_mtime.sec = (unsigned int)st->st_mtime;
+       ce->ce_ctime.nsec = ST_CTIME_NSEC(*st);
+       ce->ce_mtime.nsec = ST_MTIME_NSEC(*st);
        ce->ce_dev = st->st_dev;
        ce->ce_ino = st->st_ino;
        ce->ce_uid = st->st_uid;
@@ -154,7 +157,7 @@ static int ce_modified_check_fs(struct cache_entry *ce, struct stat *st)
        return 0;
 }
 
-int is_empty_blob_sha1(const unsigned char *sha1)
+static int is_empty_blob_sha1(const unsigned char *sha1)
 {
        static const unsigned char empty_blob_sha1[20] = {
                0xe6,0x9d,0xe2,0x9b,0xb2,0xd1,0xd6,0x43,0x4b,0x8b,
@@ -196,10 +199,17 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
        default:
                die("internal error: ce_mode is %o", ce->ce_mode);
        }
-       if (ce->ce_mtime != (unsigned int) st->st_mtime)
+       if (ce->ce_mtime.sec != (unsigned int)st->st_mtime)
+               changed |= MTIME_CHANGED;
+       if (trust_ctime && ce->ce_ctime.sec != (unsigned int)st->st_ctime)
+               changed |= CTIME_CHANGED;
+
+#ifdef USE_NSEC
+       if (ce->ce_mtime.nsec != ST_MTIME_NSEC(*st))
                changed |= MTIME_CHANGED;
-       if (trust_ctime && ce->ce_ctime != (unsigned int) st->st_ctime)
+       if (trust_ctime && ce->ce_ctime.nsec != ST_CTIME_NSEC(*st))
                changed |= CTIME_CHANGED;
+#endif
 
        if (ce->ce_uid != (unsigned int) st->st_uid ||
            ce->ce_gid != (unsigned int) st->st_gid)
@@ -232,8 +242,16 @@ static int ce_match_stat_basic(struct cache_entry *ce, struct stat *st)
 static int is_racy_timestamp(const struct index_state *istate, struct cache_entry *ce)
 {
        return (!S_ISGITLINK(ce->ce_mode) &&
-               istate->timestamp &&
-               ((unsigned int)istate->timestamp) <= ce->ce_mtime);
+               istate->timestamp.sec &&
+#ifdef USE_NSEC
+                /* nanosecond timestamped files can also be racy! */
+               (istate->timestamp.sec < ce->ce_mtime.sec ||
+                (istate->timestamp.sec == ce->ce_mtime.sec &&
+                 istate->timestamp.nsec <= ce->ce_mtime.nsec))
+#else
+               istate->timestamp.sec <= ce->ce_mtime.sec
+#endif
+                );
 }
 
 int ie_match_stat(const struct index_state *istate,
@@ -242,12 +260,17 @@ int ie_match_stat(const struct index_state *istate,
 {
        unsigned int changed;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
        int assume_racy_is_modified = options & CE_MATCH_RACY_IS_DIRTY;
 
        /*
         * If it's marked as always valid in the index, it's
         * valid whatever the checked-out copy says.
+        *
+        * skip-worktree has the same effect with higher precedence
         */
+       if (!ignore_skip_worktree && ce_skip_worktree(ce))
+               return 0;
        if (!ignore_valid && (ce->ce_flags & CE_VALID))
                return 0;
 
@@ -432,6 +455,7 @@ int remove_index_entry_at(struct index_state *istate, int pos)
 {
        struct cache_entry *ce = istate->cache[pos];
 
+       record_resolve_undo(istate, ce);
        remove_name_hash(ce);
        istate->cache_changed = 1;
        istate->cache_nr--;
@@ -443,6 +467,26 @@ int remove_index_entry_at(struct index_state *istate, int pos)
        return 1;
 }
 
+/*
+ * Remove all cache ententries marked for removal, that is where
+ * CE_REMOVE is set in ce_flags.  This is much more effective than
+ * calling remove_index_entry_at() for each entry to be removed.
+ */
+void remove_marked_cache_entries(struct index_state *istate)
+{
+       struct cache_entry **ce_array = istate->cache;
+       unsigned int i, j;
+
+       for (i = j = 0; i < istate->cache_nr; i++) {
+               if (ce_array[i]->ce_flags & CE_REMOVE)
+                       remove_name_hash(ce_array[i]);
+               else
+                       ce_array[j++] = ce_array[i];
+       }
+       istate->cache_changed = 1;
+       istate->cache_nr = j;
+}
+
 int remove_file_from_index(struct index_state *istate, const char *path)
 {
        int pos = index_name_pos(istate, path, strlen(path));
@@ -527,7 +571,7 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
        int size, namelen, was_same;
        mode_t st_mode = st->st_mode;
        struct cache_entry *ce, *alias;
-       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_RACY_IS_DIRTY;
+       unsigned ce_option = CE_MATCH_IGNORE_VALID|CE_MATCH_IGNORE_SKIP_WORKTREE|CE_MATCH_RACY_IS_DIRTY;
        int verbose = flags & (ADD_CACHE_VERBOSE | ADD_CACHE_PRETEND);
        int pretend = flags & ADD_CACHE_PRETEND;
        int intent_only = flags & ADD_CACHE_INTENT;
@@ -601,7 +645,7 @@ int add_file_to_index(struct index_state *istate, const char *path, int flags)
 {
        struct stat st;
        if (lstat(path, &st))
-               die("%s: unable to stat (%s)", path, strerror(errno));
+               die_errno("unable to stat '%s'", path);
        return add_to_index(istate, path, &st, flags);
 }
 
@@ -963,14 +1007,20 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        struct cache_entry *updated;
        int changed, size;
        int ignore_valid = options & CE_MATCH_IGNORE_VALID;
+       int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
 
        if (ce_uptodate(ce))
                return ce;
 
        /*
-        * CE_VALID means the user promised us that the change to
-        * the work tree does not matter and told us not to worry.
+        * CE_VALID or CE_SKIP_WORKTREE means the user promised us
+        * that the change to the work tree does not matter and told
+        * us not to worry.
         */
+       if (!ignore_skip_worktree && ce_skip_worktree(ce)) {
+               ce_mark_uptodate(ce);
+               return ce;
+       }
        if (!ignore_valid && (ce->ce_flags & CE_VALID)) {
                ce_mark_uptodate(ce);
                return ce;
@@ -1028,7 +1078,18 @@ static struct cache_entry *refresh_cache_ent(struct index_state *istate,
        return updated;
 }
 
-int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec, char *seen)
+static void show_file(const char * fmt, const char * name, int in_porcelain,
+                     int * first, char *header_msg)
+{
+       if (in_porcelain && *first && header_msg) {
+               printf("%s\n", header_msg);
+               *first=0;
+       }
+       printf(fmt, name);
+}
+
+int refresh_index(struct index_state *istate, unsigned int flags, const char **pathspec,
+                 char *seen, char *header_msg)
 {
        int i;
        int has_errors = 0;
@@ -1037,11 +1098,14 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
        int quiet = (flags & REFRESH_QUIET) != 0;
        int not_new = (flags & REFRESH_IGNORE_MISSING) != 0;
        int ignore_submodules = (flags & REFRESH_IGNORE_SUBMODULES) != 0;
+       int first = 1;
+       int in_porcelain = (flags & REFRESH_IN_PORCELAIN);
        unsigned int options = really ? CE_MATCH_IGNORE_VALID : 0;
-       const char *needs_update_message;
+       const char *needs_update_fmt;
+       const char *needs_merge_fmt;
 
-       needs_update_message = ((flags & REFRESH_SAY_CHANGED)
-                               ? "locally modified" : "needs update");
+       needs_update_fmt = (in_porcelain ? "M\t%s\n" : "%s: needs update\n");
+       needs_merge_fmt = (in_porcelain ? "U\t%s\n" : "%s: needs merge\n");
        for (i = 0; i < istate->cache_nr; i++) {
                struct cache_entry *ce, *new;
                int cache_errno = 0;
@@ -1057,7 +1121,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                        i--;
                        if (allow_unmerged)
                                continue;
-                       printf("%s: needs merge\n", ce->name);
+                       show_file(needs_merge_fmt, ce->name, in_porcelain, &first, header_msg);
                        has_errors = 1;
                        continue;
                }
@@ -1080,7 +1144,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
                        }
                        if (quiet)
                                continue;
-                       printf("%s: %s\n", ce->name, needs_update_message);
+                       show_file(needs_update_fmt, ce->name, in_porcelain, &first, header_msg);
                        has_errors = 1;
                        continue;
                }
@@ -1090,7 +1154,7 @@ int refresh_index(struct index_state *istate, unsigned int flags, const char **p
        return has_errors;
 }
 
-struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
 {
        return refresh_cache_ent(&the_index, ce, really, NULL);
 }
@@ -1119,6 +1183,9 @@ static int read_index_extension(struct index_state *istate,
        case CACHE_EXT_TREE:
                istate->cache_tree = cache_tree_read(data, sz);
                break;
+       case CACHE_EXT_RESOLVE_UNDO:
+               istate->resolve_undo = resolve_undo_read(data, sz);
+               break;
        default:
                if (*ext < 'A' || 'Z' < *ext)
                        return error("index uses %.4s extension, which we do not understand",
@@ -1139,8 +1206,10 @@ static void convert_from_disk(struct ondisk_cache_entry *ondisk, struct cache_en
        size_t len;
        const char *name;
 
-       ce->ce_ctime = ntohl(ondisk->ctime.sec);
-       ce->ce_mtime = ntohl(ondisk->mtime.sec);
+       ce->ce_ctime.sec = ntohl(ondisk->ctime.sec);
+       ce->ce_mtime.sec = ntohl(ondisk->mtime.sec);
+       ce->ce_ctime.nsec = ntohl(ondisk->ctime.nsec);
+       ce->ce_mtime.nsec = ntohl(ondisk->mtime.nsec);
        ce->ce_dev   = ntohl(ondisk->dev);
        ce->ce_ino   = ntohl(ondisk->ino);
        ce->ce_mode  = ntohl(ondisk->mode);
@@ -1206,16 +1275,17 @@ int read_index_from(struct index_state *istate, const char *path)
                return istate->cache_nr;
 
        errno = ENOENT;
-       istate->timestamp = 0;
+       istate->timestamp.sec = 0;
+       istate->timestamp.nsec = 0;
        fd = open(path, O_RDONLY);
        if (fd < 0) {
                if (errno == ENOENT)
                        return 0;
-               die("index file open failed (%s)", strerror(errno));
+               die_errno("index file open failed");
        }
 
        if (fstat(fd, &st))
-               die("cannot stat the open index (%s)", strerror(errno));
+               die_errno("cannot stat the open index");
 
        errno = EINVAL;
        mmap_size = xsize_t(st.st_size);
@@ -1225,7 +1295,7 @@ int read_index_from(struct index_state *istate, const char *path)
        mmap = xmmap(NULL, mmap_size, PROT_READ | PROT_WRITE, MAP_PRIVATE, fd, 0);
        close(fd);
        if (mmap == MAP_FAILED)
-               die("unable to map index file");
+               die_errno("unable to map index file");
 
        hdr = mmap;
        if (verify_hdr(hdr, mmap_size) < 0)
@@ -1258,7 +1328,9 @@ int read_index_from(struct index_state *istate, const char *path)
                src_offset += ondisk_ce_size(ce);
                dst_offset += ce_size(ce);
        }
-       istate->timestamp = st.st_mtime;
+       istate->timestamp.sec = st.st_mtime;
+       istate->timestamp.nsec = ST_MTIME_NSEC(st);
+
        while (src_offset <= mmap_size - 20 - 8) {
                /* After an array of active_nr index entries,
                 * there can be arbitrary number of extended
@@ -1266,7 +1338,7 @@ int read_index_from(struct index_state *istate, const char *path)
                 * extension name (4-byte) and section length
                 * in 4-byte network byte order.
                 */
-               unsigned long extsize;
+               uint32_t extsize;
                memcpy(&extsize, (char *)mmap + src_offset + 4, 4);
                extsize = ntohl(extsize);
                if (read_index_extension(istate,
@@ -1288,14 +1360,16 @@ int read_index_from(struct index_state *istate, const char *path)
 
 int is_index_unborn(struct index_state *istate)
 {
-       return (!istate->cache_nr && !istate->alloc && !istate->timestamp);
+       return (!istate->cache_nr && !istate->alloc && !istate->timestamp.sec);
 }
 
 int discard_index(struct index_state *istate)
 {
+       resolve_undo_clear_index(istate);
        istate->cache_nr = 0;
        istate->cache_changed = 0;
-       istate->timestamp = 0;
+       istate->timestamp.sec = 0;
+       istate->timestamp.nsec = 0;
        istate->name_hash_initialized = 0;
        free_hash(&istate->name_hash);
        cache_tree_free(&(istate->cache_tree));
@@ -1441,10 +1515,10 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
        struct ondisk_cache_entry *ondisk = xcalloc(1, size);
        char *name;
 
-       ondisk->ctime.sec = htonl(ce->ce_ctime);
-       ondisk->ctime.nsec = 0;
-       ondisk->mtime.sec = htonl(ce->ce_mtime);
-       ondisk->mtime.nsec = 0;
+       ondisk->ctime.sec = htonl(ce->ce_ctime.sec);
+       ondisk->mtime.sec = htonl(ce->ce_mtime.sec);
+       ondisk->ctime.nsec = htonl(ce->ce_ctime.nsec);
+       ondisk->mtime.nsec = htonl(ce->ce_mtime.nsec);
        ondisk->dev  = htonl(ce->ce_dev);
        ondisk->ino  = htonl(ce->ce_ino);
        ondisk->mode = htonl(ce->ce_mode);
@@ -1466,13 +1540,14 @@ static int ce_write_entry(git_SHA_CTX *c, int fd, struct cache_entry *ce)
        return ce_write(c, fd, ondisk, size);
 }
 
-int write_index(const struct index_state *istate, int newfd)
+int write_index(struct index_state *istate, int newfd)
 {
        git_SHA_CTX c;
        struct cache_header hdr;
        int i, err, removed, extended;
        struct cache_entry **cache = istate->cache;
        int entries = istate->cache_nr;
+       struct stat st;
 
        for (i = removed = extended = 0; i < entries; i++) {
                if (cache[i]->ce_flags & CE_REMOVE)
@@ -1516,7 +1591,23 @@ int write_index(const struct index_state *istate, int newfd)
                if (err)
                        return -1;
        }
-       return ce_flush(&c, newfd);
+       if (istate->resolve_undo) {
+               struct strbuf sb = STRBUF_INIT;
+
+               resolve_undo_write(&sb, istate->resolve_undo);
+               err = write_index_ext_header(&c, newfd, CACHE_EXT_RESOLVE_UNDO,
+                                            sb.len) < 0
+                       || ce_write(&c, newfd, sb.buf, sb.len) < 0;
+               strbuf_release(&sb);
+               if (err)
+                       return -1;
+       }
+
+       if (ce_flush(&c, newfd) || fstat(newfd, &st))
+               return -1;
+       istate->timestamp.sec = (unsigned int)st.st_mtime;
+       istate->timestamp.nsec = ST_MTIME_NSEC(st);
+       return 0;
 }
 
 /*
@@ -1543,9 +1634,8 @@ int read_index_unmerged(struct index_state *istate)
                len = strlen(ce->name);
                size = cache_entry_size(len);
                new_ce = xcalloc(1, size);
-               hashcpy(new_ce->sha1, ce->sha1);
                memcpy(new_ce->name, ce->name, len);
-               new_ce->ce_flags = create_ce_flags(len, 0);
+               new_ce->ce_flags = create_ce_flags(len, 0) | CE_CONFLICTED;
                new_ce->ce_mode = ce->ce_mode;
                if (add_index_entry(istate, new_ce, 0))
                        return error("%s: cannot drop to stage #0",
@@ -1555,81 +1645,6 @@ int read_index_unmerged(struct index_state *istate)
        return unmerged;
 }
 
-struct update_callback_data
-{
-       int flags;
-       int add_errors;
-};
-
-static void update_callback(struct diff_queue_struct *q,
-                           struct diff_options *opt, void *cbdata)
-{
-       int i;
-       struct update_callback_data *data = cbdata;
-
-       for (i = 0; i < q->nr; i++) {
-               struct diff_filepair *p = q->queue[i];
-               const char *path = p->one->path;
-               switch (p->status) {
-               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)) {
-                               if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
-                                       die("updating files failed");
-                               data->add_errors++;
-                       }
-                       break;
-               case DIFF_STATUS_DELETED:
-                       if (data->flags & ADD_CACHE_IGNORE_REMOVAL)
-                               break;
-                       if (!(data->flags & ADD_CACHE_PRETEND))
-                               remove_file_from_index(&the_index, path);
-                       if (data->flags & (ADD_CACHE_PRETEND|ADD_CACHE_VERBOSE))
-                               printf("remove '%s'\n", path);
-                       break;
-               }
-       }
-}
-
-int add_files_to_cache(const char *prefix, const char **pathspec, int flags)
-{
-       struct update_callback_data data;
-       struct rev_info rev;
-       init_revisions(&rev, prefix);
-       setup_revisions(0, NULL, &rev, NULL);
-       rev.prune_data = pathspec;
-       rev.diffopt.output_format = DIFF_FORMAT_CALLBACK;
-       rev.diffopt.format_callback = update_callback;
-       data.flags = flags;
-       data.add_errors = 0;
-       rev.diffopt.format_callback_data = &data;
-       run_diff_files(&rev, DIFF_RACY_IS_MODIFIED);
-       return !!data.add_errors;
-}
-
 /*
  * Returns 1 if the path is an "other" path with respect to
  * the index; that is, the path is not mentioned in the index at all,