#include "strbuf.h"
#include "varint.h"
#include "split-index.h"
+#include "sigchain.h"
static struct cache_entry *refresh_cache_entry(struct cache_entry *ce,
unsigned int options);
/* changes that can be kept in $GIT_DIR/index (basically all extensions) */
#define EXTMASK (RESOLVE_UNDO_CHANGED | CACHE_TREE_CHANGED | \
- CE_ENTRY_ADDED | CE_ENTRY_REMOVED)
+ CE_ENTRY_ADDED | CE_ENTRY_REMOVED | CE_ENTRY_CHANGED | \
+ SPLIT_INDEX_ORDERED)
struct index_state the_index;
static const char *alternate_index_output;
{
struct cache_entry *old = istate->cache[nr];
+ replace_index_entry_in_base(istate, old, ce);
remove_name_hash(istate, old);
free(old);
set_index_entry(istate, nr, ce);
+ ce->ce_flags |= CE_UPDATE_IN_BASE;
istate->cache_changed |= CE_ENTRY_CHANGED;
}
int skip_df_check = option & ADD_CACHE_SKIP_DFCHECK;
int new_only = option & ADD_CACHE_NEW_ONLY;
- cache_tree_invalidate_path(istate, ce->name);
+ if (!(option & ADD_CACHE_KEEP_CACHE_TREE))
+ cache_tree_invalidate_path(istate, ce->name);
pos = index_name_stage_pos(istate, ce->name, ce_namelen(ce), ce_stage(ce));
/* existing match? Just replace it. */
* means the index is not valid anymore.
*/
ce->ce_flags &= ~CE_VALID;
+ ce->ce_flags |= CE_UPDATE_IN_BASE;
istate->cache_changed |= CE_ENTRY_CHANGED;
}
if (quiet)
}
/* remember to discard_cache() before reading a different cache! */
-static int do_read_index(struct index_state *istate, const char *path,
- int must_exist)
+int do_read_index(struct index_state *istate, const char *path, int must_exist)
{
int fd, i;
struct stat st;
if (is_null_sha1(split_index->base_sha1))
return ret;
- if (istate->cache_nr)
- die("index in split-index mode must contain no entries");
if (split_index->base)
discard_index(split_index->base);
{
int size;
struct ondisk_cache_entry *ondisk;
+ int saved_namelen = saved_namelen; /* compiler workaround */
char *name;
int result;
+ if (ce->ce_flags & CE_STRIP_NAME) {
+ saved_namelen = ce_namelen(ce);
+ ce->ce_namelen = 0;
+ }
+
if (!previous_name) {
size = ondisk_ce_size(ce);
ondisk = xcalloc(1, size);
strbuf_splice(previous_name, common, to_remove,
ce->name + common, ce_namelen(ce) - common);
}
+ if (ce->ce_flags & CE_STRIP_NAME) {
+ ce->ce_namelen = saved_namelen;
+ ce->ce_flags &= ~CE_STRIP_NAME;
+ }
result = ce_write(c, fd, ondisk, size);
free(ondisk);
rollback_lock_file(lockfile);
}
-static int do_write_index(struct index_state *istate, int newfd)
+static int do_write_index(struct index_state *istate, int newfd,
+ int strip_extensions)
{
git_SHA_CTX c;
struct cache_header hdr;
}
}
- if (!istate->version)
+ if (!istate->version) {
istate->version = get_index_format_default();
+ if (getenv("GIT_TEST_SPLIT_INDEX"))
+ init_split_index(istate);
+ }
/* demote version 3 to version 2 when the latter suffices */
if (istate->version == 3 || istate->version == 2)
strbuf_release(&previous_name_buf);
/* Write extension data here */
- if (istate->split_index) {
+ if (!strip_extensions && istate->split_index) {
struct strbuf sb = STRBUF_INIT;
err = write_link_extension(&sb, istate) < 0 ||
if (err)
return -1;
}
- if (istate->cache_tree) {
+ if (!strip_extensions && istate->cache_tree) {
struct strbuf sb = STRBUF_INIT;
cache_tree_write(&sb, istate->cache_tree);
if (err)
return -1;
}
- if (istate->resolve_undo) {
+ if (!strip_extensions && istate->resolve_undo) {
struct strbuf sb = STRBUF_INIT;
resolve_undo_write(&sb, istate->resolve_undo);
static int do_write_locked_index(struct index_state *istate, struct lock_file *lock,
unsigned flags)
{
- int ret = do_write_index(istate, lock->fd);
+ int ret = do_write_index(istate, lock->fd, 0);
if (ret)
return ret;
assert((flags & (COMMIT_LOCK | CLOSE_LOCK)) !=
return ret;
}
+static char *temporary_sharedindex;
+
+static void remove_temporary_sharedindex(void)
+{
+ if (temporary_sharedindex) {
+ unlink_or_warn(temporary_sharedindex);
+ free(temporary_sharedindex);
+ temporary_sharedindex = NULL;
+ }
+}
+
+static void remove_temporary_sharedindex_on_signal(int signo)
+{
+ remove_temporary_sharedindex();
+ sigchain_pop(signo);
+ raise(signo);
+}
+
+static int write_shared_index(struct index_state *istate,
+ struct lock_file *lock, unsigned flags)
+{
+ struct split_index *si = istate->split_index;
+ static int installed_handler;
+ int fd, ret;
+
+ temporary_sharedindex = git_pathdup("sharedindex_XXXXXX");
+ fd = mkstemp(temporary_sharedindex);
+ if (fd < 0) {
+ free(temporary_sharedindex);
+ temporary_sharedindex = NULL;
+ hashclr(si->base_sha1);
+ return do_write_locked_index(istate, lock, flags);
+ }
+ if (!installed_handler) {
+ atexit(remove_temporary_sharedindex);
+ sigchain_push_common(remove_temporary_sharedindex_on_signal);
+ }
+ move_cache_to_base_index(istate);
+ ret = do_write_index(si->base, fd, 1);
+ close(fd);
+ if (ret) {
+ remove_temporary_sharedindex();
+ return ret;
+ }
+ ret = rename(temporary_sharedindex,
+ git_path("sharedindex.%s", sha1_to_hex(si->base->sha1)));
+ free(temporary_sharedindex);
+ temporary_sharedindex = NULL;
+ if (!ret)
+ hashcpy(si->base_sha1, si->base->sha1);
+ return ret;
+}
+
int write_locked_index(struct index_state *istate, struct lock_file *lock,
unsigned flags)
{
struct split_index *si = istate->split_index;
- if (!si || (istate->cache_changed & ~EXTMASK)) {
+ if (!si || alternate_index_output ||
+ (istate->cache_changed & ~EXTMASK)) {
if (si)
hashclr(si->base_sha1);
return do_write_locked_index(istate, lock, flags);
}
+ if (getenv("GIT_TEST_SPLIT_INDEX")) {
+ int v = si->base_sha1[0];
+ if ((v & 15) < 6)
+ istate->cache_changed |= SPLIT_INDEX_ORDERED;
+ }
+ if (istate->cache_changed & SPLIT_INDEX_ORDERED) {
+ int ret = write_shared_index(istate, lock, flags);
+ if (ret)
+ return ret;
+ }
+
return write_split_index(istate, lock, flags);
}