#include "git-compat-util.h"
#include "strbuf.h"
-#include "hash.h"
+#include "hashmap.h"
#include "advice.h"
#include "gettext.h"
#include "convert.h"
};
struct cache_entry {
+ struct hashmap_entry ent;
struct stat_data ce_stat_data;
unsigned int ce_mode;
unsigned int ce_flags;
unsigned int ce_namelen;
unsigned char sha1[20];
- struct cache_entry *next;
char name[FLEX_ARRAY]; /* more */
};
#define CE_ADDED (1 << 19)
#define CE_HASHED (1 << 20)
-#define CE_UNHASHED (1 << 21)
#define CE_WT_REMOVE (1 << 22) /* remove in work directory */
#define CE_CONFLICTED (1 << 23)
* Copy the sha1 and stat state of a cache entry from one to
* another. But we never change the name, or the hash state!
*/
-#define CE_STATE_MASK (CE_HASHED | CE_UNHASHED)
static inline void copy_cache_entry(struct cache_entry *dst,
const struct cache_entry *src)
{
- unsigned int state = dst->ce_flags & CE_STATE_MASK;
+ unsigned int state = dst->ce_flags & CE_HASHED;
/* Don't copy hash chain and name */
- memcpy(dst, src, offsetof(struct cache_entry, next));
+ memcpy(&dst->ce_stat_data, &src->ce_stat_data,
+ offsetof(struct cache_entry, name) -
+ offsetof(struct cache_entry, ce_stat_data));
/* Restore the hash state */
- dst->ce_flags = (dst->ce_flags & ~CE_STATE_MASK) | state;
+ dst->ce_flags = (dst->ce_flags & ~CE_HASHED) | state;
}
static inline unsigned create_ce_flags(unsigned stage)
struct cache_time timestamp;
unsigned name_hash_initialized : 1,
initialized : 1;
- struct hash_table name_hash;
- struct hash_table dir_hash;
+ struct hashmap name_hash;
+ struct hashmap dir_hash;
};
extern struct index_state the_index;
#define ce_modified(ce, st, options) ie_modified(&the_index, (ce), (st), (options))
#define cache_dir_exists(name, namelen) index_dir_exists(&the_index, (name), (namelen))
#define cache_file_exists(name, namelen, igncase) index_file_exists(&the_index, (name), (namelen), (igncase))
-#define cache_name_exists(name, namelen, igncase) index_name_exists(&the_index, (name), (namelen), (igncase))
#define cache_name_is_other(name, namelen) index_name_is_other(&the_index, (name), (namelen))
#define resolve_undo_clear() resolve_undo_clear_index(&the_index)
#define unmerge_cache_entry_at(at) unmerge_index_entry_at(&the_index, at)
extern int verify_path(const char *path);
extern struct cache_entry *index_dir_exists(struct index_state *istate, const char *name, int namelen);
extern struct cache_entry *index_file_exists(struct index_state *istate, const char *name, int namelen, int igncase);
-extern struct cache_entry *index_name_exists(struct index_state *istate, const char *name, int namelen, int igncase);
extern int index_name_pos(const struct index_state *, const char *name, int namelen);
#define ADD_CACHE_OK_TO_ADD 1 /* Ok to add */
#define ADD_CACHE_OK_TO_REPLACE 2 /* Ok to replace file/directory */
#define ADD_CACHE_IMPLICIT_DOT 32 /* internal to "git add -u/-A" */
extern int add_to_index(struct index_state *, const char *path, struct stat *, int flags);
extern int add_file_to_index(struct index_state *, const char *path, int flags);
-extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, int refresh);
+extern struct cache_entry *make_cache_entry(unsigned int mode, const unsigned char *sha1, const char *path, int stage, unsigned int refresh_options);
extern int ce_same_name(const struct cache_entry *a, const struct cache_entry *b);
+ extern void set_object_name_for_intent_to_add_entry(struct cache_entry *ce);
extern int index_name_is_other(const struct index_state *, const char *, int);
extern void *read_blob_data_from_index(struct index_state *, const char *, unsigned long *);
#define CE_MATCH_RACY_IS_DIRTY 02
/* do stat comparison even if CE_SKIP_WORKTREE is true */
#define CE_MATCH_IGNORE_SKIP_WORKTREE 04
+/* ignore non-existent files during stat update */
+#define CE_MATCH_IGNORE_MISSING 0x08
+/* enable stat refresh */
+#define CE_MATCH_REFRESH 0x10
extern int ie_match_stat(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
extern int ie_modified(const struct index_state *, const struct cache_entry *, struct stat *, unsigned int);
-extern int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec);
-
#define HASH_WRITE_OBJECT 1
#define HASH_FORMAT_CHECK 2
extern int index_fd(unsigned char *sha1, int fd, struct stat *st, enum object_type type, const char *path, unsigned flags);
#include "strbuf.h"
#include "varint.h"
-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really);
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
+ unsigned int options);
/* Mask for the name length in ce_flags in the on-disk index */
struct cache_entry *old = istate->cache[nr];
remove_name_hash(istate, old);
+ free(old);
set_index_entry(istate, nr, ce);
istate->cache_changed = 1;
}
new = xmalloc(cache_entry_size(namelen));
copy_cache_entry(new, old);
- new->ce_flags &= ~CE_STATE_MASK;
+ new->ce_flags &= ~CE_HASHED;
new->ce_namelen = namelen;
memcpy(new->name, new_name, namelen + 1);
record_resolve_undo(istate, ce);
remove_name_hash(istate, ce);
+ free(ce);
istate->cache_changed = 1;
istate->cache_nr--;
if (pos >= istate->cache_nr)
unsigned int i, j;
for (i = j = 0; i < istate->cache_nr; i++) {
- if (ce_array[i]->ce_flags & CE_REMOVE)
+ if (ce_array[i]->ce_flags & CE_REMOVE) {
remove_name_hash(istate, ce_array[i]);
+ free(ce_array[i]);
+ }
else
ce_array[j++] = ce_array[i];
}
return new;
}
- static void record_intent_to_add(struct cache_entry *ce)
+ void set_object_name_for_intent_to_add_entry(struct cache_entry *ce)
{
unsigned char sha1[20];
if (write_sha1_file("", 0, blob_type, sha1))
if (index_path(ce->sha1, path, st, HASH_WRITE_OBJECT))
return error("unable to index file %s", path);
} else
- record_intent_to_add(ce);
+ set_object_name_for_intent_to_add_entry(ce);
if (ignore_case && alias && different_name(ce, alias))
ce = create_alias_ce(ce, alias);
struct cache_entry *make_cache_entry(unsigned int mode,
const unsigned char *sha1, const char *path, int stage,
- int refresh)
+ unsigned int refresh_options)
{
int size, len;
struct cache_entry *ce;
ce->ce_namelen = len;
ce->ce_mode = create_ce_mode(mode);
- if (refresh)
- return refresh_cache_entry(ce, 0);
-
- return ce;
+ return refresh_cache_entry(ce, refresh_options);
}
int ce_same_name(const struct cache_entry *a, const struct cache_entry *b)
return ce_namelen(b) == len && !memcmp(a->name, b->name, len);
}
-int ce_path_match(const struct cache_entry *ce, const struct pathspec *pathspec)
-{
- return match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, NULL);
-}
-
/*
* We fundamentally don't like some paths: we don't want
* dot or dot-dot anywhere, and for obvious reasons don't
struct stat st;
struct cache_entry *updated;
int changed, size;
+ int refresh = options & CE_MATCH_REFRESH;
int ignore_valid = options & CE_MATCH_IGNORE_VALID;
int ignore_skip_worktree = options & CE_MATCH_IGNORE_SKIP_WORKTREE;
+ int ignore_missing = options & CE_MATCH_IGNORE_MISSING;
- if (ce_uptodate(ce))
+ if (!refresh || ce_uptodate(ce))
return ce;
/*
}
if (lstat(ce->name, &st) < 0) {
+ if (ignore_missing && errno == ENOENT)
+ return ce;
if (err)
*err = errno;
return NULL;
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;
+ unsigned int options = (CE_MATCH_REFRESH |
+ (really ? CE_MATCH_IGNORE_VALID : 0) |
+ (not_new ? CE_MATCH_IGNORE_MISSING : 0));
const char *modified_fmt;
const char *deleted_fmt;
const char *typechange_fmt;
if (ignore_submodules && S_ISGITLINK(ce->ce_mode))
continue;
- if (pathspec &&
- !match_pathspec_depth(pathspec, ce->name, ce_namelen(ce), 0, seen))
+ if (pathspec && !ce_path_match(ce, pathspec, seen))
filtered = 1;
if (ce_stage(ce)) {
if (!new) {
const char *fmt;
- if (not_new && cache_errno == ENOENT)
- continue;
if (really && cache_errno == EINVAL) {
/* If we are doing --really-refresh that
* means the index is not valid anymore.
return has_errors;
}
-static struct cache_entry *refresh_cache_entry(struct cache_entry *ce, int really)
+static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
+ unsigned int options)
{
- return refresh_cache_ent(&the_index, ce, really, NULL, NULL);
+ return refresh_cache_ent(&the_index, ce, options, NULL, NULL);
}
new_ce->ce_mode = ce->ce_mode;
if (add_index_entry(istate, new_ce, 0))
return error("%s: cannot drop to stage #0",
- ce->name);
+ new_ce->name);
i = index_name_pos(istate, new_ce->name, len);
}
return unmerged;