From: Junio C Hamano Date: Wed, 10 Feb 2016 22:20:06 +0000 (-0800) Subject: Merge branch 'cc/untracked' X-Git-Tag: v2.8.0-rc0~63 X-Git-Url: https://git.lorimer.id.au/gitweb.git/diff_plain/0e35fcb412965f855e5ac6f469343e2f8e28d5ae?hp=-c Merge branch 'cc/untracked' Update the untracked cache subsystem and change its primary UI from "git update-index" to "git config". * cc/untracked: t7063: add tests for core.untrackedCache test-dump-untracked-cache: don't modify the untracked cache config: add core.untrackedCache dir: simplify untracked cache "ident" field dir: add remove_untracked_cache() dir: add {new,add}_untracked_cache() update-index: move 'uc' var declaration update-index: add untracked cache notifications update-index: add --test-untracked-cache update-index: use enum for untracked cache options dir: free untracked cache when removing it --- 0e35fcb412965f855e5ac6f469343e2f8e28d5ae diff --combined Documentation/config.txt index 02bcde6bb5,e3c8cfe93c..27f02be35e --- a/Documentation/config.txt +++ b/Documentation/config.txt @@@ -308,6 -308,15 +308,15 @@@ core.trustctime: crawlers and some backup systems). See linkgit:git-update-index[1]. True by default. + core.untrackedCache:: + Determines what to do about the untracked cache feature of the + index. It will be kept, if this variable is unset or set to + `keep`. It will automatically be added if set to `true`. And + it will automatically be removed, if set to `false`. Before + setting it to `true`, you should check that mtime is working + properly on your system. + See linkgit:git-update-index[1]. `keep` by default. + core.checkStat:: Determines which stat fields to match between the index and work tree. The user can set this to 'default' or @@@ -870,8 -879,6 +879,8 @@@ When preserve, also pass `--preserve-me so that locally committed merge commits will not be flattened by running 'git pull'. + +When the value is `interactive`, the rebase is run in interactive mode. ++ *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] for details). @@@ -1245,10 -1252,6 +1254,10 @@@ format.coverLetter: format-patch is invoked, but in addition can be set to "auto", to generate a cover-letter only when there's more than one patch. +format.outputDirectory:: + Set a custom directory to store the resulting files instead of the + current working directory. + filter..clean:: The command which is used to convert the content of a worktree file to a blob upon checkin. See linkgit:gitattributes[5] for @@@ -1456,14 -1459,6 +1465,14 @@@ grep.extendedRegexp: option is ignored when the 'grep.patternType' option is set to a value other than 'default'. +grep.threads:: + Number of grep worker threads to use. + See `grep.threads` in linkgit:git-grep[1] for more information. + +grep.fallbackToNoIndex:: + If set to true, fall back to git grep --no-index if git grep + is executed outside of a git repository. Defaults to false. + gpg.program:: Use this custom program instead of "gpg" found on $PATH when making or verifying a PGP signature. The program must support the @@@ -1610,34 -1605,9 +1619,34 @@@ help.htmlPath: http.proxy:: Override the HTTP proxy, normally configured using the 'http_proxy', - 'https_proxy', and 'all_proxy' environment variables (see - `curl(1)`). This can be overridden on a per-remote basis; see - remote..proxy + 'https_proxy', and 'all_proxy' environment variables (see `curl(1)`). In + addition to the syntax understood by curl, it is possible to specify a + proxy string with a user name but no password, in which case git will + attempt to acquire one in the same way it does for other credentials. See + linkgit:gitcredentials[7] for more information. The syntax thus is + '[protocol://][user[:password]@]proxyhost[:port]'. This can be overridden + on a per-remote basis; see remote..proxy + +http.proxyAuthMethod:: + Set the method with which to authenticate against the HTTP proxy. This + only takes effect if the configured proxy string contains a user name part + (i.e. is of the form 'user@host' or 'user@host:port'). This can be + overridden on a per-remote basis; see `remote..proxyAuthMethod`. + Both can be overridden by the 'GIT_HTTP_PROXY_AUTHMETHOD' environment + variable. Possible values are: ++ +-- +* `anyauth` - Automatically pick a suitable authentication method. It is + assumed that the proxy answers an unauthenticated request with a 407 + status code and one or more Proxy-authenticate headers with supported + authentication methods. This is the default. +* `basic` - HTTP Basic authentication +* `digest` - HTTP Digest authentication; this prevents the password from being + transmitted to the proxy in clear text +* `negotiate` - GSS-Negotiate authentication (compare the --negotiate option + of `curl(1)`) +* `ntlm` - NTLM authentication (compare the --ntlm option of `curl(1)`) +-- http.cookieFile:: File containing previously stored cookie lines which should be used @@@ -2188,8 -2158,6 +2197,8 @@@ When preserve, also pass `--preserve-me so that locally committed merge commits will not be flattened by running 'git pull'. + +When the value is `interactive`, the rebase is run in interactive mode. ++ *NOTE*: this is a possibly dangerous operation; do *not* use it unless you understand the implications (see linkgit:git-rebase[1] for details). @@@ -2270,20 -2238,6 +2279,20 @@@ push.gpgSign: override a value from a lower-priority config file. An explicit command-line flag always overrides this config option. +push.recurseSubmodules:: + Make sure all submodule commits used by the revisions to be pushed + are available on a remote-tracking branch. If the value is 'check' + then Git will verify that all submodule commits that changed in the + revisions to be pushed are available on at least one remote of the + submodule. If any commits are missing, the push will be aborted and + exit with non-zero status. If the value is 'on-demand' then all + submodules that changed in the revisions to be pushed will be + pushed. If on-demand was not able to push all necessary revisions + it will also be aborted and exit with non-zero status. If the value + is 'no' then default behavior of ignoring submodules when pushing + is retained. You may override this configuration at time of push by + specifying '--recurse-submodules=check|on-demand|no'. + rebase.stat:: Whether to show a diffstat of what changed upstream since the last rebase. False by default. @@@ -2448,11 -2402,6 +2457,11 @@@ remote..proxy: the proxy to use for that remote. Set to the empty string to disable proxying for that remote. +remote..proxyAuthMethod:: + For remotes that require curl (http, https and ftp), the method to use for + authenticating against the proxy in use (probably set in + `remote..proxy`). See `http.proxyAuthMethod`. + remote..fetch:: The default set of "refspec" for linkgit:git-fetch[1]. See linkgit:git-fetch[1]. diff --combined builtin/update-index.c index 7c5c143de5,7a5533491e..dbc23a46b1 --- a/builtin/update-index.c +++ b/builtin/update-index.c @@@ -35,6 -35,15 +35,15 @@@ static int mark_skip_worktree_only #define UNMARK_FLAG 2 static struct strbuf mtime_dir = STRBUF_INIT; + /* Untracked cache mode */ + enum uc_mode { + UC_UNSPECIFIED = -1, + UC_DISABLE = 0, + UC_ENABLE, + UC_TEST, + UC_FORCE + }; + __attribute__((format (printf, 1, 2))) static void report(const char *fmt, ...) { @@@ -121,7 -130,7 +130,7 @@@ static int test_if_untracked_cache_is_s if (!mkdtemp(mtime_dir.buf)) die_errno("Could not make temporary directory"); - fprintf(stderr, _("Testing ")); + fprintf(stderr, _("Testing mtime in '%s' "), xgetcwd()); atexit(remove_test_directory); xstat_mtime_dir(&st); fill_stat_data(&base, &st); @@@ -468,14 -477,12 +477,14 @@@ static void update_one(const char *path report("add '%s'", path); } -static void read_index_info(int line_termination) +static void read_index_info(int nul_term_line) { struct strbuf buf = STRBUF_INIT; struct strbuf uq = STRBUF_INIT; + strbuf_getline_fn getline_fn; - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; + while (getline_fn(&buf, stdin) != EOF) { char *ptr, *tab; char *path_name; unsigned char sha1[20]; @@@ -524,7 -531,7 +533,7 @@@ goto bad_line; path_name = ptr; - if (line_termination && path_name[0] == '"') { + if (!nul_term_line && path_name[0] == '"') { strbuf_reset(&uq); if (unquote_c_style(&uq, path_name, NULL)) { die("git update-index: bad quoting of path name"); @@@ -846,12 -853,12 +855,12 @@@ static int cacheinfo_callback(struct pa static int stdin_cacheinfo_callback(struct parse_opt_ctx_t *ctx, const struct option *opt, int unset) { - int *line_termination = opt->value; + int *nul_term_line = opt->value; if (ctx->argc != 1) return error("option '%s' must be the last argument", opt->long_name); allow_add = allow_replace = allow_remove = 1; - read_index_info(*line_termination); + read_index_info(*nul_term_line); return 0; } @@@ -903,8 -910,8 +912,8 @@@ static int reupdate_callback(struct par int cmd_update_index(int argc, const char **argv, const char *prefix) { - int newfd, entries, has_errors = 0, line_termination = '\n'; + int newfd, entries, has_errors = 0, nul_term_line = 0; - int untracked_cache = -1; + enum uc_mode untracked_cache = UC_UNSPECIFIED; int read_from_stdin = 0; int prefix_length = prefix ? strlen(prefix) : 0; int preferred_index_format = 0; @@@ -914,7 -921,6 +923,7 @@@ int split_index = -1; struct lock_file *lock_file; struct parse_opt_ctx_t ctx; + strbuf_getline_fn getline_fn; int parseopt_state = PARSE_OPT_UNKNOWN; struct option options[] = { OPT_BIT('q', NULL, &refresh_args.flags, @@@ -966,13 -972,13 +975,13 @@@ N_("add to index only; do not add content to object database"), 1), OPT_SET_INT(0, "force-remove", &force_remove, N_("remove named paths even if present in worktree"), 1), - OPT_SET_INT('z', NULL, &line_termination, - N_("with --stdin: input lines are terminated by null bytes"), '\0'), + OPT_BOOL('z', NULL, &nul_term_line, + N_("with --stdin: input lines are terminated by null bytes")), {OPTION_LOWLEVEL_CALLBACK, 0, "stdin", &read_from_stdin, NULL, N_("read list of paths to be updated from standard input"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_callback}, - {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &line_termination, NULL, + {OPTION_LOWLEVEL_CALLBACK, 0, "index-info", &nul_term_line, NULL, N_("add entries from standard input to the index"), PARSE_OPT_NONEG | PARSE_OPT_NOARG, (parse_opt_cb *) stdin_cacheinfo_callback}, @@@ -999,8 -1005,10 +1008,10 @@@ N_("enable or disable split index")), OPT_BOOL(0, "untracked-cache", &untracked_cache, N_("enable/disable untracked cache")), + OPT_SET_INT(0, "test-untracked-cache", &untracked_cache, + N_("test if the filesystem supports untracked cache"), UC_TEST), OPT_SET_INT(0, "force-untracked-cache", &untracked_cache, - N_("enable untracked cache without testing the filesystem"), 2), + N_("enable untracked cache without testing the filesystem"), UC_FORCE), OPT_END() }; @@@ -1060,8 -1068,6 +1071,8 @@@ } } argc = parse_options_end(&ctx); + + getline_fn = nul_term_line ? strbuf_getline_nul : strbuf_getline_lf; if (preferred_index_format) { if (preferred_index_format < INDEX_FORMAT_LB || INDEX_FORMAT_UB < preferred_index_format) @@@ -1078,9 -1084,9 +1089,9 @@@ struct strbuf buf = STRBUF_INIT, nbuf = STRBUF_INIT; setup_work_tree(); - while (strbuf_getline(&buf, stdin, line_termination) != EOF) { + while (getline_fn(&buf, stdin) != EOF) { char *p; - if (line_termination && buf.buf[0] == '"') { + if (!nul_term_line && buf.buf[0] == '"') { strbuf_reset(&nbuf); if (unquote_c_style(&nbuf, buf.buf, NULL)) die("line is badly quoted"); @@@ -1109,27 -1115,32 +1120,32 @@@ the_index.split_index = NULL; the_index.cache_changed |= SOMETHING_CHANGED; } - if (untracked_cache > 0) { - struct untracked_cache *uc; - if (untracked_cache < 2) { - setup_work_tree(); - if (!test_if_untracked_cache_is_supported()) - return 1; - } - if (!the_index.untracked) { - 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; - the_index.untracked = uc; - } - add_untracked_ident(the_index.untracked); - the_index.cache_changed |= UNTRACKED_CHANGED; - } else if (!untracked_cache && the_index.untracked) { - the_index.untracked = NULL; - the_index.cache_changed |= UNTRACKED_CHANGED; + switch (untracked_cache) { + case UC_UNSPECIFIED: + break; + case UC_DISABLE: + if (git_config_get_untracked_cache() == 1) + warning("core.untrackedCache is set to true; " + "remove or change it, if you really want to " + "disable the untracked cache"); + remove_untracked_cache(&the_index); + report(_("Untracked cache disabled")); + break; + case UC_TEST: + setup_work_tree(); + return !test_if_untracked_cache_is_supported(); + case UC_ENABLE: + case UC_FORCE: + if (git_config_get_untracked_cache() == 0) + warning("core.untrackedCache is set to false; " + "remove or change it, if you really want to " + "enable the untracked cache"); + add_untracked_cache(&the_index); + report(_("Untracked cache enabled for '%s'"), get_git_work_tree()); + break; + default: + die("Bug: bad untracked_cache value: %d", untracked_cache); } if (active_cache_changed) { diff --combined cache.h index 553b04bfb8,255b273d82..26640b421d --- a/cache.h +++ b/cache.h @@@ -9,7 -9,6 +9,7 @@@ #include "convert.h" #include "trace.h" #include "string-list.h" +#include "pack-revindex.h" #include SHA1_HEADER #ifndef platform_SHA_CTX @@@ -215,7 -214,7 +215,7 @@@ struct cache_entry #define CE_INTENT_TO_ADD (1 << 29) #define CE_SKIP_WORKTREE (1 << 30) /* CE_EXTENDED2 is for future extension */ -#define CE_EXTENDED2 (1 << 31) +#define CE_EXTENDED2 (1U << 31) #define CE_EXTENDED_FLAGS (CE_INTENT_TO_ADD | CE_SKIP_WORKTREE) @@@ -260,7 -259,6 +260,7 @@@ static inline unsigned create_ce_flags( #define ce_uptodate(ce) ((ce)->ce_flags & CE_UPTODATE) #define ce_skip_worktree(ce) ((ce)->ce_flags & CE_SKIP_WORKTREE) #define ce_mark_uptodate(ce) ((ce)->ce_flags |= CE_UPTODATE) +#define ce_intent_to_add(ce) ((ce)->ce_flags & CE_INTENT_TO_ADD) #define ce_permissions(mode) (((mode) & 0100) ? 0755 : 0644) static inline unsigned int create_ce_mode(unsigned int mode) @@@ -458,6 -456,7 +458,6 @@@ extern char *git_work_tree_cfg extern int is_inside_work_tree(void); extern const char *get_git_dir(void); extern const char *get_git_common_dir(void); -extern int is_git_directory(const char *path); extern char *get_object_directory(void); extern char *get_index_file(void); extern char *get_graft_file(void); @@@ -468,25 -467,6 +468,25 @@@ extern const char *get_git_namespace(vo extern const char *strip_namespace(const char *namespaced_ref); extern const char *get_git_work_tree(void); +/* + * Return true if the given path is a git directory; note that this _just_ + * looks at the directory itself. If you want to know whether "foo/.git" + * is a repository, you must feed that path, not just "foo". + */ +extern int is_git_directory(const char *path); + +/* + * Return 1 if the given path is the root of a git repository or + * submodule, else 0. Will not return 1 for bare repositories with the + * exception of creating a bare repository in "foo/.git" and calling + * is_git_repository("foo"). + * + * If we run into read errors, we err on the side of saying "yes, it is", + * as we usually consider sub-repos precious, and would prefer to err on the + * side of not disrupting or deleting them. + */ +extern int is_nonbare_repository_dir(struct strbuf *path); + #define READ_GITFILE_ERR_STAT_FAILED 1 #define READ_GITFILE_ERR_NOT_A_FILE 2 #define READ_GITFILE_ERR_OPEN_FAILED 3 @@@ -851,7 -831,6 +851,7 @@@ extern const char *find_unique_abbrev(c extern int find_unique_abbrev_r(char *hex, const unsigned char *sha1, int len); extern const unsigned char null_sha1[GIT_SHA1_RAWSZ]; +extern const struct object_id null_oid; static inline int hashcmp(const unsigned char *sha1, const unsigned char *sha2) { @@@ -1319,7 -1298,6 +1319,7 @@@ extern struct packed_git freshened:1, do_not_close:1; unsigned char sha1[20]; + struct revindex_entry *revindex; /* something like ".git/objects/pack/xxxxx.pack" */ char pack_name[FLEX_ARRAY]; /* more */ } *packed_git; @@@ -1624,6 -1602,14 +1624,14 @@@ extern int git_config_get_bool(const ch extern int git_config_get_bool_or_int(const char *key, int *is_bool, int *dest); extern int git_config_get_maybe_bool(const char *key, int *dest); extern int git_config_get_pathname(const char *key, const char **dest); + extern int git_config_get_untracked_cache(void); + + /* + * This is a hack for test programs like test-dump-untracked-cache to + * ensure that they do not modify the untracked cache when reading it. + * Do not use it otherwise! + */ + extern int ignore_untracked_cache_config; struct key_value_info { const char *filename; diff --combined contrib/completion/git-completion.bash index 15ebba51dc,a429e6ea29..45ec47f2b1 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@@ -664,7 -664,6 +664,7 @@@ __git_list_porcelain_commands ( check-mailmap) : plumbing;; check-ref-format) : plumbing;; checkout-index) : plumbing;; + column) : internal helper;; commit-tree) : plumbing;; count-objects) : infrequent;; credential) : credentials;; @@@ -1169,7 -1168,7 +1169,7 @@@ __git_diff_common_options="--stat --num --no-prefix --src-prefix= --dst-prefix= --inter-hunk-context= --patience --histogram --minimal - --raw --word-diff + --raw --word-diff --word-diff-regex= --dirstat --dirstat= --dirstat-by-file --dirstat-by-file= --cumulative --diff-algorithm= @@@ -1312,7 -1311,6 +1312,7 @@@ _git_grep ( --full-name --line-number --extended-regexp --basic-regexp --fixed-strings --perl-regexp + --threads --files-with-matches --name-only --files-without-match --max-depth @@@ -1688,12 -1686,8 +1688,12 @@@ _git_rebase ( --preserve-merges --stat --no-stat --committer-date-is-author-date --ignore-date --ignore-whitespace --whitespace= - --autosquash --fork-point --no-fork-point - --autostash + --autosquash --no-autosquash + --fork-point --no-fork-point + --autostash --no-autostash + --verify --no-verify + --keep-empty --root --force-rebase --no-ff + --exec " return @@@ -1813,7 -1807,7 +1813,7 @@@ _git_config ( return ;; branch.*.rebase) - __gitcomp "false true" + __gitcomp "false true preserve interactive" return ;; remote.pushdefault) @@@ -2060,6 -2054,7 +2060,7 @@@ core.sparseCheckout core.symlinks core.trustctime + core.untrackedCache core.warnAmbiguousRefs core.whitespace core.worktree @@@ -2373,7 -2368,7 +2374,7 @@@ _git_show_branch ( case "$cur" in --*) __gitcomp " - --all --remotes --topo-order --current --more= + --all --remotes --topo-order --date-order --current --more= --list --independent --merge-base --no-name --color --no-color --sha1-name --sparse --topics --reflog @@@ -2386,7 -2381,7 +2387,7 @@@ _git_stash () { - local save_opts='--keep-index --no-keep-index --quiet --patch' + local save_opts='--all --keep-index --no-keep-index --quiet --patch --include-untracked' local subcommands='save list show apply clear drop pop create branch' local subcommand="$(__git_find_on_cmdline "$subcommands")" if [ -z "$subcommand" ]; then @@@ -2408,20 -2403,9 +2409,20 @@@ apply,--*|pop,--*) __gitcomp "--index --quiet" ;; - show,--*|drop,--*|branch,--*) + drop,--*) + __gitcomp "--quiet" + ;; + show,--*|branch,--*) + ;; + branch,*) + if [ $cword -eq 3 ]; then + __gitcomp_nl "$(__git_refs)"; + else + __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ + | sed -n -e 's/:.*//p')" + fi ;; - show,*|apply,*|drop,*|pop,*|branch,*) + show,*|apply,*|drop,*|pop,*) __gitcomp_nl "$(git --git-dir="$(__gitdir)" stash list \ | sed -n -e 's/:.*//p')" ;; diff --combined dir.c index 29aec12487,42d3b6b100..f0b6d0a3ea --- a/dir.c +++ b/dir.c @@@ -564,7 -564,9 +564,7 @@@ void clear_exclude_list(struct exclude_ free(el->excludes); free(el->filebuf); - el->nr = 0; - el->excludes = NULL; - el->filebuf = NULL; + memset(el, 0, sizeof(*el)); } static void trim_trailing_spaces(char *buf) @@@ -880,6 -882,25 +880,6 @@@ int match_pathname(const char *pathname */ if (!patternlen && !namelen) return 1; - /* - * This can happen when we ignore some exclude rules - * on directories in other to see if negative rules - * may match. E.g. - * - * /abc - * !/abc/def/ghi - * - * The pattern of interest is "/abc". On the first - * try, we should match path "abc" with this pattern - * in the "if" statement right above, but the caller - * ignores it. - * - * On the second try with paths within "abc", - * e.g. "abc/xyz", we come here and try to match it - * with "/abc". - */ - if (!patternlen && namelen && *name == '/') - return 1; } return fnmatch_icase_mem(pattern, patternlen, @@@ -887,6 -908,48 +887,6 @@@ WM_PATHNAME) == 0; } -/* - * Return non-zero if pathname is a directory and an ancestor of the - * literal path in a (negative) pattern. This is used to keep - * descending in "foo" and "foo/bar" when the pattern is - * "!foo/bar/.gitignore". "foo/notbar" will not be descended however. - */ -static int match_neg_path(const char *pathname, int pathlen, int *dtype, - const char *base, int baselen, - const char *pattern, int prefix, int patternlen, - int flags) -{ - assert((flags & EXC_FLAG_NEGATIVE) && !(flags & EXC_FLAG_NODIR)); - - if (*dtype == DT_UNKNOWN) - *dtype = get_dtype(NULL, pathname, pathlen); - if (*dtype != DT_DIR) - return 0; - - if (*pattern == '/') { - pattern++; - patternlen--; - prefix--; - } - - if (baselen) { - if (((pathlen < baselen && base[pathlen] == '/') || - pathlen == baselen) && - !strncmp_icase(pathname, base, pathlen)) - return 1; - pathname += baselen + 1; - pathlen -= baselen + 1; - } - - - if (prefix && - ((pathlen < prefix && pattern[pathlen] == '/') && - !strncmp_icase(pathname, pattern, pathlen))) - return 1; - - return 0; -} - /* * Scan the given exclude list in reverse to see whether pathname * should be ignored. The first match (i.e. the last on the list), if @@@ -900,7 -963,7 +900,7 @@@ static struct exclude *last_exclude_mat struct exclude_list *el) { struct exclude *exc = NULL; /* undecided */ - int i, matched_negative_path = 0; + int i; if (!el->nr) return NULL; /* undefined */ @@@ -935,7 -998,18 +935,7 @@@ exc = x; break; } - - if ((x->flags & EXC_FLAG_NEGATIVE) && !matched_negative_path && - match_neg_path(pathname, pathlen, dtype, x->base, - x->baselen ? x->baselen - 1 : 0, - exclude, prefix, x->patternlen, x->flags)) - matched_negative_path = 1; } - if (exc && - !(exc->flags & EXC_FLAG_NEGATIVE) && - !(exc->flags & EXC_FLAG_NODIR) && - matched_negative_path) - exc = NULL; return exc; } @@@ -1839,31 -1913,67 +1839,67 @@@ static const char *get_ident_string(voi return sb.buf; if (uname(&uts) < 0) die_errno(_("failed to get kernel name and information")); - strbuf_addf(&sb, "Location %s, system %s %s %s", get_git_work_tree(), - uts.sysname, uts.release, uts.version); + strbuf_addf(&sb, "Location %s, system %s", get_git_work_tree(), + uts.sysname); return sb.buf; } static int ident_in_untracked(const struct untracked_cache *uc) { - const char *end = uc->ident.buf + uc->ident.len; - const char *p = uc->ident.buf; + /* + * Previous git versions may have saved many NUL separated + * strings in the "ident" field, but it is insane to manage + * many locations, so just take care of the first one. + */ - for (p = uc->ident.buf; p < end; p += strlen(p) + 1) - if (!strcmp(p, get_ident_string())) - return 1; - return 0; + return !strcmp(uc->ident.buf, get_ident_string()); } - void add_untracked_ident(struct untracked_cache *uc) + static void set_untracked_ident(struct untracked_cache *uc) { - if (ident_in_untracked(uc)) - return; + strbuf_reset(&uc->ident); strbuf_addstr(&uc->ident, get_ident_string()); - /* this strbuf contains a list of strings, save NUL too */ + + /* + * This strbuf used to contain a list of NUL separated + * strings, so save NUL too for backward compatibility. + */ strbuf_addch(&uc->ident, 0); } + static void new_untracked_cache(struct index_state *istate) + { + 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; + set_untracked_ident(uc); + istate->untracked = uc; + istate->cache_changed |= UNTRACKED_CHANGED; + } + + void add_untracked_cache(struct index_state *istate) + { + if (!istate->untracked) { + new_untracked_cache(istate); + } else { + if (!ident_in_untracked(istate->untracked)) { + free_untracked_cache(istate->untracked); + new_untracked_cache(istate); + } + } + } + + void remove_untracked_cache(struct index_state *istate) + { + if (istate->untracked) { + free_untracked_cache(istate->untracked); + istate->untracked = NULL; + istate->cache_changed |= UNTRACKED_CHANGED; + } + } + static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *dir, int base_len, const struct pathspec *pathspec) @@@ -1921,7 -2031,7 +1957,7 @@@ return NULL; if (!ident_in_untracked(dir->untracked)) { - warning(_("Untracked cache is disabled on this system.")); + warning(_("Untracked cache is disabled on this system or location.")); return NULL; } diff --combined environment.c index 1cc4aab4ea,b329024f13..6dec9d0403 --- a/environment.c +++ b/environment.c @@@ -87,6 -87,13 +87,13 @@@ int auto_comment_line_char /* Parallel index stat data preload? */ int core_preload_index = 1; + /* + * This is a hack for test programs like test-dump-untracked-cache to + * ensure that they do not modify the untracked cache when reading it. + * Do not use it otherwise! + */ + int ignore_untracked_cache_config; + /* This is set by setup_git_dir_gently() and/or git_default_config() */ char *git_work_tree_cfg; static char *work_tree; @@@ -235,6 -242,8 +242,6 @@@ void set_git_work_tree(const char *new_ } git_work_tree_initialized = 1; work_tree = xstrdup(real_path(new_work_tree)); - if (setenv(GIT_WORK_TREE_ENVIRONMENT, work_tree, 1)) - die("could not set GIT_WORK_TREE to '%s'", work_tree); } const char *get_git_work_tree(void) diff --combined read-cache.c index 5be7cd1dbf,56614d54c7..d9fb78bc55 --- a/read-cache.c +++ b/read-cache.c @@@ -327,7 -327,7 +327,7 @@@ int ie_match_stat(const struct index_st * by definition never matches what is in the work tree until it * actually gets added. */ - if (ce->ce_flags & CE_INTENT_TO_ADD) + if (ce_intent_to_add(ce)) return DATA_CHANGED | TYPE_CHANGED | MODE_CHANGED; changed = ce_match_stat_basic(ce, st); @@@ -1237,7 -1237,7 +1237,7 @@@ int refresh_index(struct index_state *i if (cache_errno == ENOENT) fmt = deleted_fmt; - else if (ce->ce_flags & CE_INTENT_TO_ADD) + else if (ce_intent_to_add(ce)) fmt = added_fmt; /* must be before other checks */ else if (changed & TYPE_CHANGED) fmt = typechange_fmt; @@@ -1519,6 -1519,28 +1519,28 @@@ static void check_ce_order(struct index } } + static void tweak_untracked_cache(struct index_state *istate) + { + switch (git_config_get_untracked_cache()) { + case -1: /* keep: do nothing */ + break; + case 0: /* false */ + remove_untracked_cache(istate); + break; + case 1: /* true */ + add_untracked_cache(istate); + break; + default: /* unknown value: do nothing */ + break; + } + } + + static void post_read_index_from(struct index_state *istate) + { + check_ce_order(istate); + tweak_untracked_cache(istate); + } + /* remember to discard_cache() before reading a different cache! */ int do_read_index(struct index_state *istate, const char *path, int must_exist) { @@@ -1622,9 -1644,10 +1644,10 @@@ int read_index_from(struct index_state return istate->cache_nr; ret = do_read_index(istate, path, 0); + split_index = istate->split_index; if (!split_index || is_null_sha1(split_index->base_sha1)) { - check_ce_order(istate); + post_read_index_from(istate); return ret; } @@@ -1642,7 -1665,7 +1665,7 @@@ sha1_to_hex(split_index->base_sha1)), sha1_to_hex(split_index->base->sha1)); merge_base_index(istate); - check_ce_order(istate); + post_read_index_from(istate); return ret; }