*
* Copyright (C) Linus Torvalds, 2005
*/
-#define USE_THE_INDEX_COMPATIBILITY_MACROS
+#define USE_THE_INDEX_VARIABLE
#include "cache.h"
+#include "bulk-checkin.h"
#include "config.h"
+#include "environment.h"
+#include "gettext.h"
+#include "hash.h"
+#include "hex.h"
#include "lockfile.h"
#include "quote.h"
#include "cache-tree.h"
#include "tree-walk.h"
#include "builtin.h"
+#include "object-file.h"
#include "refs.h"
#include "resolve-undo.h"
#include "parse-options.h"
#include "pathspec.h"
#include "dir.h"
+#include "repository.h"
+#include "setup.h"
+#include "sparse-index.h"
#include "split-index.h"
+#include "symlinks.h"
#include "fsmonitor.h"
+#include "write-or-die.h"
/*
* Default to not allowing changes to the list of files. The
if (!verbose)
return;
+ /*
+ * It is possible, though unlikely, that a caller could use the verbose
+ * output to synchronize with addition of objects to the object
+ * database. The current implementation of ODB transactions leaves
+ * objects invisible while a transaction is active, so flush the
+ * transaction here before reporting a change made by update-index.
+ */
+ flush_odb_transaction();
va_start(vp, fmt);
vprintf(fmt, vp);
putchar('\n');
{
int fd;
path = get_mtime_path(path);
- fd = open(path, O_CREAT | O_RDWR, 0644);
- if (fd < 0)
- die_errno(_("failed to create file %s"), path);
+ fd = xopen(path, O_CREAT | O_RDWR, 0644);
return fd;
}
static int mark_ce_flags(const char *path, int flag, int mark)
{
int namelen = strlen(path);
- int pos = cache_name_pos(path, namelen);
+ int pos = index_name_pos(&the_index, path, namelen);
if (0 <= pos) {
- mark_fsmonitor_invalid(&the_index, active_cache[pos]);
+ mark_fsmonitor_invalid(&the_index, the_index.cache[pos]);
if (mark)
- active_cache[pos]->ce_flags |= flag;
+ the_index.cache[pos]->ce_flags |= flag;
else
- active_cache[pos]->ce_flags &= ~flag;
- active_cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
+ the_index.cache[pos]->ce_flags &= ~flag;
+ the_index.cache[pos]->ce_flags |= CE_UPDATE_IN_BASE;
cache_tree_invalidate_path(&the_index, path);
- active_cache_changed |= CE_ENTRY_CHANGED;
+ the_index.cache_changed |= CE_ENTRY_CHANGED;
return 0;
}
return -1;
{
if (!allow_remove)
return error("%s: does not exist and --remove not passed", path);
- if (remove_file_from_cache(path))
+ if (remove_file_from_index(&the_index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
struct cache_entry *ce;
/* Was the old index entry already up-to-date? */
- if (old && !ce_stage(old) && !ce_match_stat(old, st, 0))
+ if (old && !ce_stage(old) && !ie_match_stat(&the_index, old, st, 0))
return 0;
ce = make_empty_cache_entry(&the_index, len);
}
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option)) {
+ if (add_index_entry(&the_index, ce, option)) {
discard_cache_entry(ce);
return error("%s: cannot add to the index - missing --add option?", path);
}
static int process_directory(const char *path, int len, struct stat *st)
{
struct object_id oid;
- int pos = cache_name_pos(path, len);
+ int pos = index_name_pos(&the_index, path, len);
/* Exact match: file or existing gitlink */
if (pos >= 0) {
- const struct cache_entry *ce = active_cache[pos];
+ const struct cache_entry *ce = the_index.cache[pos];
if (S_ISGITLINK(ce->ce_mode)) {
/* Do nothing to the index if there is no HEAD! */
/* Inexact match: is there perhaps a subdirectory match? */
pos = -pos-1;
- while (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos++];
+ while (pos < the_index.cache_nr) {
+ const struct cache_entry *ce = the_index.cache[pos++];
if (strncmp(ce->name, path, len))
break;
if (has_symlink_leading_path(path, len))
return error("'%s' is beyond a symbolic link", path);
- pos = cache_name_pos(path, len);
- ce = pos < 0 ? NULL : active_cache[pos];
+ pos = index_name_pos(&the_index, path, len);
+ ce = pos < 0 ? NULL : the_index.cache[pos];
if (ce && ce_skip_worktree(ce)) {
/*
* working directory version is assumed "good"
* On the other hand, removing it from index should work
*/
if (!ignore_skip_worktree_entries && allow_remove &&
- remove_file_from_cache(path))
+ remove_file_from_index(&the_index, path))
return error("%s: cannot remove from the index", path);
return 0;
}
ce->ce_flags |= CE_VALID;
option = allow_add ? ADD_CACHE_OK_TO_ADD : 0;
option |= allow_replace ? ADD_CACHE_OK_TO_REPLACE : 0;
- if (add_cache_entry(ce, option))
+ if (add_index_entry(&the_index, ce, option))
return error("%s: cannot add to the index - missing --add option?",
path);
report("add '%s'", path);
int pos;
struct cache_entry *ce;
- pos = cache_name_pos(path, strlen(path));
+ pos = index_name_pos(&the_index, path, strlen(path));
if (pos < 0)
goto fail;
- ce = active_cache[pos];
- if (chmod_cache_entry(ce, flip) < 0)
+ ce = the_index.cache[pos];
+ if (chmod_index_entry(&the_index, ce, flip) < 0)
goto fail;
report("chmod %cx '%s'", flip, path);
}
if (force_remove) {
- if (remove_file_from_cache(path))
+ if (remove_file_from_index(&the_index, path))
die("git update-index: unable to remove %s", path);
report("remove '%s'", path);
return;
if (!mode) {
/* mode == 0 means there is no such path -- remove */
- if (remove_file_from_cache(path_name))
+ if (remove_file_from_index(&the_index, path_name))
die("git update-index: unable to remove %s",
ptr);
}
error("%s: not in %s branch.", path, which);
return NULL;
}
- if (mode == S_IFDIR) {
+ if (!the_index.sparse_index && mode == S_IFDIR) {
if (which)
error("%s: not a blob in %s branch.", path, which);
return NULL;
struct cache_entry *ce_2 = NULL, *ce_3 = NULL;
/* See if there is such entry in the index. */
- pos = cache_name_pos(path, namelen);
+ pos = index_name_pos(&the_index, path, namelen);
if (0 <= pos) {
/* already merged */
- pos = unmerge_cache_entry_at(pos);
- if (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos];
+ pos = unmerge_index_entry_at(&the_index, pos);
+ if (pos < the_index.cache_nr) {
+ const struct cache_entry *ce = the_index.cache[pos];
if (ce_stage(ce) &&
ce_namelen(ce) == namelen &&
!memcmp(ce->name, path, namelen))
* want to do anything in the former case.
*/
pos = -pos-1;
- if (pos < active_nr) {
- const struct cache_entry *ce = active_cache[pos];
+ if (pos < the_index.cache_nr) {
+ const struct cache_entry *ce = the_index.cache[pos];
if (ce_namelen(ce) == namelen &&
!memcmp(ce->name, path, namelen)) {
fprintf(stderr,
goto free_return;
}
- remove_file_from_cache(path);
- if (add_cache_entry(ce_2, ADD_CACHE_OK_TO_ADD)) {
+ remove_file_from_index(&the_index, path);
+ if (add_index_entry(&the_index, ce_2, ADD_CACHE_OK_TO_ADD)) {
error("%s: cannot add our version to the index.", path);
ret = -1;
goto free_return;
}
- if (!add_cache_entry(ce_3, ADD_CACHE_OK_TO_ADD))
+ if (!add_index_entry(&the_index, ce_3, ADD_CACHE_OK_TO_ADD))
return 0;
error("%s: cannot add their version to the index.", path);
ret = -1;
return err;
}
-static int do_reupdate(int ac, const char **av,
+static int do_reupdate(const char **paths,
const char *prefix)
{
/* Read HEAD and run update-index on paths that are
parse_pathspec(&pathspec, 0,
PATHSPEC_PREFER_CWD,
- prefix, av + 1);
+ prefix, paths);
if (read_ref("HEAD", &head_oid))
/* If there is no HEAD, that means it is an initial
*/
has_head = 0;
redo:
- /* TODO: audit for interaction with sparse-index. */
- ensure_full_index(&the_index);
- for (pos = 0; pos < active_nr; pos++) {
- const struct cache_entry *ce = active_cache[pos];
+ for (pos = 0; pos < the_index.cache_nr; pos++) {
+ const struct cache_entry *ce = the_index.cache[pos];
struct cache_entry *old = NULL;
int save_nr;
char *path;
discard_cache_entry(old);
continue; /* unchanged */
}
+
+ /* At this point, we know the contents of the sparse directory are
+ * modified with respect to HEAD, so we expand the index and restart
+ * to process each path individually
+ */
+ if (S_ISSPARSEDIR(ce->ce_mode)) {
+ ensure_full_index(&the_index);
+ goto redo;
+ }
+
/* Be careful. The working tree may not have the
* path anymore, in which case, under 'allow_remove',
* or worse yet 'allow_replace', active_nr may decrease.
*/
- save_nr = active_nr;
+ save_nr = the_index.cache_nr;
path = xstrdup(ce->name);
update_one(path);
free(path);
discard_cache_entry(old);
- if (save_nr != active_nr)
+ if (save_nr != the_index.cache_nr)
goto redo;
}
clear_pathspec(&pathspec);
static int refresh(struct refresh_params *o, unsigned int flag)
{
setup_work_tree();
- read_cache();
- *o->has_errors |= refresh_cache(o->flags | flag);
+ repo_read_index(the_repository);
+ *o->has_errors |= refresh_index(&the_index, o->flags | flag, NULL,
+ NULL, NULL);
+ if (has_racy_timestamp(&the_index)) {
+ /*
+ * Even if nothing else has changed, updating the file
+ * increases the chance that racy timestamps become
+ * non-racy, helping future run-time performance.
+ * We do that even in case of "errors" returned by
+ * refresh_index() as these are no actual errors.
+ * cmd_status() does the same.
+ */
+ the_index.cache_changed |= SOMETHING_CHANGED;
+ }
return 0;
}
{
BUG_ON_OPT_NEG(unset);
BUG_ON_OPT_ARG(arg);
- resolve_undo_clear();
+ resolve_undo_clear_index(&the_index);
return 0;
}
*has_errors = do_unresolve(ctx->argc, ctx->argv,
prefix, prefix ? strlen(prefix) : 0);
if (*has_errors)
- active_cache_changed = 0;
+ the_index.cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
/* consume remaining arguments. */
setup_work_tree();
- *has_errors = do_reupdate(ctx->argc, ctx->argv, prefix);
+ *has_errors = do_reupdate(ctx->argv + 1, prefix);
if (*has_errors)
- active_cache_changed = 0;
+ the_index.cache_changed = 0;
ctx->argv += ctx->argc - 1;
ctx->argc = 1;
git_config(git_default_config, NULL);
+ prepare_repo_settings(r);
+ the_repository->settings.command_requires_full_index = 0;
+
/* we will diagnose later if it turns out that we need to update it */
- newfd = hold_locked_index(&lock_file, 0);
+ newfd = repo_hold_locked_index(the_repository, &lock_file, 0);
if (newfd < 0)
lock_error = errno;
- entries = read_cache();
+ entries = repo_read_index(the_repository);
if (entries < 0)
die("cache corrupted");
*/
parse_options_start(&ctx, argc, argv, prefix,
options, PARSE_OPT_STOP_AT_NON_OPTION);
+
+ /*
+ * Allow the object layer to optimize adding multiple objects in
+ * a batch.
+ */
+ begin_odb_transaction();
while (ctx.argc) {
if (parseopt_state != PARSE_OPT_DONE)
parseopt_state = parse_options_step(&ctx, options,
INDEX_FORMAT_LB, INDEX_FORMAT_UB);
if (the_index.version != preferred_index_format)
- active_cache_changed |= SOMETHING_CHANGED;
+ the_index.cache_changed |= SOMETHING_CHANGED;
the_index.version = preferred_index_format;
}
strbuf_release(&buf);
}
+ /*
+ * By now we have added all of the new objects
+ */
+ end_odb_transaction();
+
if (split_index > 0) {
if (git_config_get_split_index() == 0)
warning(_("core.splitIndex is set to false; "
}
if (fsmonitor > 0) {
- if (git_config_get_fsmonitor() == 0)
+ enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ enum fsmonitor_reason reason = fsm_settings__get_reason(r);
+
+ /*
+ * The user wants to turn on FSMonitor using the command
+ * line argument. (We don't know (or care) whether that
+ * is the IPC or HOOK version.)
+ *
+ * Use one of the __get routines to force load the FSMonitor
+ * config settings into the repo-settings. That will detect
+ * whether the file system is compatible so that we can stop
+ * here with a nice error message.
+ */
+ if (reason > FSMONITOR_REASON_OK)
+ die("%s",
+ fsm_settings__get_incompatible_msg(r, reason));
+
+ if (fsm_mode == FSMONITOR_MODE_DISABLED) {
warning(_("core.fsmonitor is unset; "
"set it if you really want to "
"enable fsmonitor"));
+ }
add_fsmonitor(&the_index);
report(_("fsmonitor enabled"));
} else if (!fsmonitor) {
- if (git_config_get_fsmonitor() == 1)
+ enum fsmonitor_mode fsm_mode = fsm_settings__get_mode(r);
+ if (fsm_mode > FSMONITOR_MODE_DISABLED)
warning(_("core.fsmonitor is set; "
"remove it if you really want to "
"disable fsmonitor"));
report(_("fsmonitor disabled"));
}
- if (active_cache_changed || force_write) {
+ if (the_index.cache_changed || force_write) {
if (newfd < 0) {
if (refresh_args.flags & REFRESH_QUIET)
exit(128);