diff options
Diffstat (limited to 'dir.c')
-rw-r--r-- | dir.c | 134 |
1 files changed, 102 insertions, 32 deletions
@@ -727,7 +727,7 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern } if (given->patternlen < 2 || - *given->pattern == '*' || + *given->pattern != '/' || strstr(given->pattern, "**")) { /* Not a cone pattern. */ warning(_("unrecognized pattern: '%s'"), given->pattern); @@ -819,9 +819,7 @@ static void add_pattern_to_hashsets(struct pattern_list *pl, struct path_pattern /* we already included this at the parent level */ warning(_("your sparse-checkout file may have issues: pattern '%s' is repeated"), given->pattern); - hashmap_remove(&pl->parent_hashmap, &translated->ent, &data); - free(data); - free(translated); + goto clear_hashmaps; } return; @@ -1115,7 +1113,7 @@ static int add_patterns(const char *fname, const char *base, int baselen, &istate->cache[pos]->oid); else hash_object_file(the_hash_algo, buf, size, - "blob", &oid_stat->oid); + OBJ_BLOB, &oid_stat->oid); fill_stat_data(&oid_stat->stat, &st); oid_stat->valid = 1; } @@ -1465,10 +1463,11 @@ static int path_in_sparse_checkout_1(const char *path, const char *end, *slash; /* - * We default to accepting a path if there are no patterns or - * they are of the wrong type. + * We default to accepting a path if the path is empty, there are no + * patterns, or the patterns are of the wrong type. */ - if (init_sparse_checkout_patterns(istate) || + if (!*path || + init_sparse_checkout_patterns(istate) || (require_cone_mode && !istate->sparse_checkout_patterns->use_cone_patterns)) return 1; @@ -2748,13 +2747,33 @@ static void set_untracked_ident(struct untracked_cache *uc) strbuf_addch(&uc->ident, 0); } -static void new_untracked_cache(struct index_state *istate) +static unsigned new_untracked_cache_flags(struct index_state *istate) +{ + struct repository *repo = istate->repo; + char *val; + + /* + * This logic is coordinated with the setting of these flags in + * wt-status.c#wt_status_collect_untracked(), and the evaluation + * of the config setting in commit.c#git_status_config() + */ + if (!repo_config_get_string(repo, "status.showuntrackedfiles", &val) && + !strcmp(val, "all")) + return 0; + + /* + * The default, if "all" is not set, is "normal" - leading us here. + * If the value is "none" then it really doesn't matter. + */ + return DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; +} + +static void new_untracked_cache(struct index_state *istate, int flags) { struct untracked_cache *uc = xcalloc(1, sizeof(*uc)); strbuf_init(&uc->ident, 100); uc->exclude_per_dir = ".gitignore"; - /* should be the same flags used by git-status */ - uc->dir_flags = DIR_SHOW_OTHER_DIRECTORIES | DIR_HIDE_EMPTY_DIRECTORIES; + uc->dir_flags = flags >= 0 ? flags : new_untracked_cache_flags(istate); set_untracked_ident(uc); istate->untracked = uc; istate->cache_changed |= UNTRACKED_CHANGED; @@ -2763,11 +2782,11 @@ static void new_untracked_cache(struct index_state *istate) void add_untracked_cache(struct index_state *istate) { if (!istate->untracked) { - new_untracked_cache(istate); + new_untracked_cache(istate, -1); } else { if (!ident_in_untracked(istate->untracked)) { free_untracked_cache(istate->untracked); - new_untracked_cache(istate); + new_untracked_cache(istate, -1); } } } @@ -2783,7 +2802,8 @@ void remove_untracked_cache(struct index_state *istate) static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir, int base_len, - const struct pathspec *pathspec) + const struct pathspec *pathspec, + struct index_state *istate) { struct untracked_cache_dir *root; static int untracked_cache_disabled = -1; @@ -2814,17 +2834,9 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d if (base_len || (pathspec && pathspec->nr)) return NULL; - /* Different set of flags may produce different results */ - if (dir->flags != dir->untracked->dir_flags || - /* - * See treat_directory(), case index_nonexistent. Without - * this flag, we may need to also cache .git file content - * for the resolve_gitlink_ref() call, which we don't. - */ - !(dir->flags & DIR_SHOW_OTHER_DIRECTORIES) || - /* We don't support collecting ignore files */ - (dir->flags & (DIR_SHOW_IGNORED | DIR_SHOW_IGNORED_TOO | - DIR_COLLECT_IGNORED))) + /* We don't support collecting ignore files */ + if (dir->flags & (DIR_SHOW_IGNORED | DIR_SHOW_IGNORED_TOO | + DIR_COLLECT_IGNORED)) return NULL; /* @@ -2847,8 +2859,55 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d return NULL; } - if (!dir->untracked->root) + /* + * If the untracked structure we received does not have the same flags + * as requested in this run, we're going to need to either discard the + * existing structure (and potentially later recreate), or bypass the + * untracked cache mechanism for this run. + */ + if (dir->flags != dir->untracked->dir_flags) { + /* + * If the untracked structure we received does not have the same flags + * as configured, then we need to reset / create a new "untracked" + * structure to match the new config. + * + * Keeping the saved and used untracked cache consistent with the + * configuration provides an opportunity for frequent users of + * "git status -uall" to leverage the untracked cache by aligning their + * configuration - setting "status.showuntrackedfiles" to "all" or + * "normal" as appropriate. + * + * Previously using -uall (or setting "status.showuntrackedfiles" to + * "all") was incompatible with untracked cache and *consistently* + * caused surprisingly bad performance (with fscache and fsmonitor + * enabled) on Windows. + * + * IMPROVEMENT OPPORTUNITY: If we reworked the untracked cache storage + * to not be as bound up with the desired output in a given run, + * and instead iterated through and stored enough information to + * correctly serve both "modes", then users could get peak performance + * with or without '-uall' regardless of their + * "status.showuntrackedfiles" config. + */ + if (dir->untracked->dir_flags != new_untracked_cache_flags(istate)) { + free_untracked_cache(istate->untracked); + new_untracked_cache(istate, dir->flags); + dir->untracked = istate->untracked; + } + else { + /* + * Current untracked cache data is consistent with config, but not + * usable in this request/run; just bypass untracked cache. + */ + return NULL; + } + } + + if (!dir->untracked->root) { + /* Untracked cache existed but is not initialized; fix that */ FLEX_ALLOC_STR(dir->untracked->root, name, ""); + istate->cache_changed |= UNTRACKED_CHANGED; + } /* Validate $GIT_DIR/info/exclude and core.excludesfile */ root = dir->untracked->root; @@ -2918,7 +2977,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate, return dir->nr; } - untracked = validate_untracked_cache(dir, len, pathspec); + untracked = validate_untracked_cache(dir, len, pathspec, istate); if (!untracked) /* * make sure untracked cache code path is disabled, @@ -2938,7 +2997,9 @@ int read_directory(struct dir_struct *dir, struct index_state *istate, if (force_untracked_cache < 0) force_untracked_cache = - git_env_bool("GIT_FORCE_UNTRACKED_CACHE", 0); + git_env_bool("GIT_FORCE_UNTRACKED_CACHE", -1); + if (force_untracked_cache < 0) + force_untracked_cache = (istate->repo->settings.core_untracked_cache == UNTRACKED_CACHE_WRITE); if (force_untracked_cache && dir->untracked == istate->untracked && (dir->untracked->dir_opened || @@ -3049,7 +3110,7 @@ char *git_url_basename(const char *repo, int is_bundle, int is_bare) * Skip scheme. */ start = strstr(repo, "://"); - if (start == NULL) + if (!start) start = repo; else start += 3; @@ -3169,6 +3230,7 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up) int ret = 0, original_len = path->len, len, kept_down = 0; int only_empty = (flag & REMOVE_DIR_EMPTY_ONLY); int keep_toplevel = (flag & REMOVE_DIR_KEEP_TOPLEVEL); + int purge_original_cwd = (flag & REMOVE_DIR_PURGE_ORIGINAL_CWD); struct object_id submodule_head; if ((flag & REMOVE_DIR_KEEP_NESTED_GIT) && @@ -3224,9 +3286,14 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up) closedir(dir); strbuf_setlen(path, original_len); - if (!ret && !keep_toplevel && !kept_down) - ret = (!rmdir(path->buf) || errno == ENOENT) ? 0 : -1; - else if (kept_up) + if (!ret && !keep_toplevel && !kept_down) { + if (!purge_original_cwd && + startup_info->original_cwd && + !strcmp(startup_info->original_cwd, path->buf)) + ret = -1; /* Do not remove current working directory */ + else + ret = (!rmdir(path->buf) || errno == ENOENT) ? 0 : -1; + } else if (kept_up) /* * report the uplevel that it is not an error that we * did not rmdir() our directory. @@ -3292,6 +3359,9 @@ int remove_path(const char *name) slash = dirs + (slash - name); do { *slash = '\0'; + if (startup_info->original_cwd && + !strcmp(startup_info->original_cwd, dirs)) + break; } while (rmdir(dirs) == 0 && (slash = strrchr(dirs, '/'))); free(dirs); } |