aboutsummaryrefslogtreecommitdiff
path: root/read-cache.c
diff options
context:
space:
mode:
Diffstat (limited to 'read-cache.c')
-rw-r--r--read-cache.c129
1 files changed, 98 insertions, 31 deletions
diff --git a/read-cache.c b/read-cache.c
index 032480d0c7..38a04b8de3 100644
--- a/read-cache.c
+++ b/read-cache.c
@@ -47,6 +47,9 @@
#include "csum-file.h"
#include "promisor-remote.h"
#include "hook.h"
+#include "submodule.h"
+#include "submodule-config.h"
+#include "advice.h"
/* Mask for the name length in ce_flags in the on-disk index */
@@ -470,6 +473,17 @@ int ie_modified(struct index_state *istate,
* then we know it is.
*/
if ((changed & DATA_CHANGED) &&
+#ifdef GIT_WINDOWS_NATIVE
+ /*
+ * Work around Git for Windows v2.27.0 fixing a bug where symlinks'
+ * target path lengths were not read at all, and instead recorded
+ * as 4096: now, all symlinks would appear as modified.
+ *
+ * So let's just special-case symlinks with a target path length
+ * (i.e. `sd_size`) of 4096 and force them to be re-checked.
+ */
+ (!S_ISLNK(st->st_mode) || ce->ce_stat_data.sd_size != MAX_PATH) &&
+#endif
(S_ISGITLINK(ce->ce_mode) || ce->ce_stat_data.sd_size != 0))
return changed;
@@ -706,7 +720,6 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
int add_option = (ADD_CACHE_OK_TO_ADD|ADD_CACHE_OK_TO_REPLACE|
(intent_only ? ADD_CACHE_NEW_ONLY : 0));
unsigned hash_flags = pretend ? 0 : INDEX_WRITE_OBJECT;
- struct object_id oid;
if (flags & ADD_CACHE_RENORMALIZE)
hash_flags |= INDEX_RENORMALIZE;
@@ -716,8 +729,6 @@ int add_to_index(struct index_state *istate, const char *path, struct stat *st,
namelen = strlen(path);
if (S_ISDIR(st_mode)) {
- if (repo_resolve_gitlink_ref(the_repository, path, "HEAD", &oid) < 0)
- return error(_("'%s' does not have a commit checked out"), path);
while (namelen && path[namelen-1] == '/')
namelen--;
}
@@ -2298,13 +2309,9 @@ int do_read_index(struct index_state *istate, const char *path, int must_exist)
}
munmap((void *)mmap, mmap_size);
- /*
- * TODO trace2: replace "the_repository" with the actual repo instance
- * that is associated with the given "istate".
- */
- trace2_data_intmax("index", the_repository, "read/version",
+ trace2_data_intmax("index", istate->repo, "read/version",
istate->version);
- trace2_data_intmax("index", the_repository, "read/cache_nr",
+ trace2_data_intmax("index", istate->repo, "read/cache_nr",
istate->cache_nr);
/*
@@ -2349,16 +2356,12 @@ int read_index_from(struct index_state *istate, const char *path,
if (istate->initialized)
return istate->cache_nr;
- /*
- * TODO trace2: replace "the_repository" with the actual repo instance
- * that is associated with the given "istate".
- */
- trace2_region_enter_printf("index", "do_read_index", the_repository,
+ trace2_region_enter_printf("index", "do_read_index", istate->repo,
"%s", path);
trace_performance_enter();
ret = do_read_index(istate, path, 0);
trace_performance_leave("read cache %s", path);
- trace2_region_leave_printf("index", "do_read_index", the_repository,
+ trace2_region_leave_printf("index", "do_read_index", istate->repo,
"%s", path);
split_index = istate->split_index;
@@ -3085,13 +3088,9 @@ static int do_write_index(struct index_state *istate, struct tempfile *tempfile,
istate->timestamp.nsec = ST_MTIME_NSEC(st);
trace_performance_since(start, "write index, changed mask = %x", istate->cache_changed);
- /*
- * TODO trace2: replace "the_repository" with the actual repo instance
- * that is associated with the given "istate".
- */
- trace2_data_intmax("index", the_repository, "write/version",
+ trace2_data_intmax("index", istate->repo, "write/version",
istate->version);
- trace2_data_intmax("index", the_repository, "write/cache_nr",
+ trace2_data_intmax("index", istate->repo, "write/cache_nr",
istate->cache_nr);
ret = 0;
@@ -3133,14 +3132,10 @@ static int do_write_locked_index(struct index_state *istate,
return ret;
}
- /*
- * TODO trace2: replace "the_repository" with the actual repo instance
- * that is associated with the given "istate".
- */
- trace2_region_enter_printf("index", "do_write_index", the_repository,
+ trace2_region_enter_printf("index", "do_write_index", istate->repo,
"%s", get_lock_file_path(lock));
ret = do_write_index(istate, lock->tempfile, write_extensions, flags);
- trace2_region_leave_printf("index", "do_write_index", the_repository,
+ trace2_region_leave_printf("index", "do_write_index", istate->repo,
"%s", get_lock_file_path(lock));
if (was_full)
@@ -3810,7 +3805,7 @@ void overlay_tree_on_index(struct index_state *istate,
if (repo_get_oid(the_repository, tree_name, &oid))
die("tree-ish %s not found.", tree_name);
- tree = parse_tree_indirect(&oid);
+ tree = repo_parse_tree_indirect(the_repository, &oid);
if (!tree)
die("bad tree-ish %s", tree_name);
@@ -3881,9 +3876,12 @@ void overlay_tree_on_index(struct index_state *istate,
struct update_callback_data {
struct index_state *index;
+ struct repository *repo;
+ struct pathspec *pathspec;
int include_sparse;
int flags;
int add_errors;
+ int ignored_too;
};
static int fix_unmerged_status(struct diff_filepair *p,
@@ -3907,8 +3905,68 @@ static int fix_unmerged_status(struct diff_filepair *p,
return DIFF_STATUS_MODIFIED;
}
+static int skip_submodule(const char *path,
+ struct repository *repo,
+ struct pathspec *pathspec,
+ int ignored_too)
+{
+ struct stat st;
+ const struct submodule *sub;
+ int pathspec_matches = 0;
+ int ps_i;
+ char *norm_pathspec = NULL;
+
+ /* Only consider if path is a directory */
+ if (lstat(path, &st) || !S_ISDIR(st.st_mode))
+ return 0;
+
+ /* Check if it's a submodule with ignore=all */
+ sub = submodule_from_path(repo, null_oid(the_hash_algo), path);
+ if (!sub || !sub->name || !sub->ignore || strcmp(sub->ignore, "all"))
+ return 0;
+
+ trace_printf("ignore=all: %s\n", path);
+ trace_printf("pathspec %s\n", (pathspec && pathspec->nr)
+ ? "has pathspec"
+ : "no pathspec");
+
+ /* Check if submodule path is explicitly mentioned in pathspec */
+ if (pathspec) {
+ for (ps_i = 0; ps_i < pathspec->nr; ps_i++) {
+ const char *m = pathspec->items[ps_i].match;
+ if (!m)
+ continue;
+ norm_pathspec = xstrdup(m);
+ strip_dir_trailing_slashes(norm_pathspec);
+ if (!strcmp(path, norm_pathspec)) {
+ pathspec_matches = 1;
+ FREE_AND_NULL(norm_pathspec);
+ break;
+ }
+ FREE_AND_NULL(norm_pathspec);
+ }
+ }
+
+ /* If explicitly matched and forced, allow adding */
+ if (pathspec_matches) {
+ if (ignored_too && ignored_too > 0) {
+ trace_printf("Add submodule due to --force: %s\n", path);
+ return 0;
+ } else {
+ advise_if_enabled(ADVICE_ADD_IGNORED_FILE,
+ _("Skipping submodule due to ignore=all: %s\n"
+ "Use --force if you really want to add the submodule."), path);
+ return 1;
+ }
+ }
+
+ /* No explicit pathspec match -> skip silently */
+ trace_printf("Pathspec to submodule does not match explicitly: %s\n", path);
+ return 1;
+}
+
static void update_callback(struct diff_queue_struct *q,
- struct diff_options *opt UNUSED, void *cbdata)
+ struct diff_options *opt UNUSED, void *cbdata)
{
int i;
struct update_callback_data *data = cbdata;
@@ -3918,7 +3976,7 @@ static void update_callback(struct diff_queue_struct *q,
const char *path = p->one->path;
if (!data->include_sparse &&
- !path_in_sparse_checkout(path, data->index))
+ !path_in_sparse_checkout(path, data->index))
continue;
switch (fix_unmerged_status(p, data)) {
@@ -3926,6 +3984,11 @@ static void update_callback(struct diff_queue_struct *q,
die(_("unexpected diff status %c"), p->status);
case DIFF_STATUS_MODIFIED:
case DIFF_STATUS_TYPE_CHANGED:
+ if (skip_submodule(path, data->repo,
+ data->pathspec,
+ data->ignored_too))
+ continue;
+
if (add_file_to_index(data->index, path, data->flags)) {
if (!(data->flags & ADD_CACHE_IGNORE_ERRORS))
die(_("updating files failed"));
@@ -3946,7 +4009,7 @@ static void update_callback(struct diff_queue_struct *q,
int add_files_to_cache(struct repository *repo, const char *prefix,
const struct pathspec *pathspec, char *ps_matched,
- int include_sparse, int flags)
+ int include_sparse, int flags, int ignored_too )
{
struct odb_transaction *transaction;
struct update_callback_data data;
@@ -3956,6 +4019,9 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
data.index = repo->index;
data.include_sparse = include_sparse;
data.flags = flags;
+ data.repo = repo;
+ data.ignored_too = ignored_too;
+ data.pathspec = (struct pathspec *)pathspec;
repo_init_revisions(repo, &rev, prefix);
setup_revisions(0, NULL, &rev, NULL);
@@ -3967,6 +4033,7 @@ int add_files_to_cache(struct repository *repo, const char *prefix,
rev.diffopt.format_callback = update_callback;
rev.diffopt.format_callback_data = &data;
rev.diffopt.flags.override_submodule_config = 1;
+ rev.diffopt.detect_rename = 0; /* staging worktree changes does not need renames */
rev.max_count = 0; /* do not compare unmerged paths with stage #2 */
/*