diff options
59 files changed, 737 insertions, 425 deletions
diff --git a/Documentation/RelNotes/2.32.0.txt b/Documentation/RelNotes/2.32.0.txt index b47d569dc9..87d56fa1aa 100644 --- a/Documentation/RelNotes/2.32.0.txt +++ b/Documentation/RelNotes/2.32.0.txt @@ -47,11 +47,6 @@ UI, Workflows & Features tweak both the message and the contents, and only the message, respectively. - * When accessing a server with a URL like https://user:pass@site/, we - did not to fall back to the basic authentication with the - credential material embedded in the URL after the "Negotiate" - authentication failed. Now we do. - * "git send-email" learned to honor the core.hooksPath configuration. * "git format-patch -v<n>" learned to allow a reroll count that is @@ -371,6 +366,30 @@ Fixes since v2.31 empty directories under $GIT_DIR/refs/ for (merge 5f03e5126d wc/packed-ref-removal-cleanup later to maint). + * "git clean" and "git ls-files -i" had confusion around working on + or showing ignored paths inside an ignored directory, which has + been corrected. + (merge b548f0f156 en/dir-traversal later to maint). + + * The handling of "%(push)" formatting element of "for-each-ref" and + friends was broken when the same codepath started handling + "%(push:<what>)", which has been corrected. + (merge 1e1c4c5eac zh/ref-filter-push-remote-fix later to maint). + + * The bash prompt script (in contrib/) did not work under "set -u". + (merge 5c0cbdb107 en/prompt-under-set-u later to maint). + + * The "chainlint" feature in the test framework is a handy way to + catch common mistakes in writing new tests, but tends to get + expensive. An knob to selectively disable it has been introduced + to help running tests that the developer has not modified. + (merge 2d86a96220 jk/test-chainlint-softer later to maint). + + * The "rev-parse" command did not diagnose the lack of argument to + "--path-format" option, which was introduced in v2.31 era, which + has been corrected. + (merge 99fc555188 wm/rev-parse-path-format-wo-arg later to maint). + * Other code cleanup, docfix, build fix, etc. (merge f451960708 dl/cat-file-doc-cleanup later to maint). (merge 12604a8d0c sv/t9801-test-path-is-file-cleanup later to maint). diff --git a/Documentation/config/stash.txt b/Documentation/config/stash.txt index 413f907cba..9ed775281f 100644 --- a/Documentation/config/stash.txt +++ b/Documentation/config/stash.txt @@ -6,9 +6,9 @@ stash.useBuiltin:: remaining users that setting this now does nothing. stash.showIncludeUntracked:: - If this is set to true, the `git stash show` command without an - option will show the untracked files of a stash entry. Defaults to - false. See description of 'show' command in linkgit:git-stash[1]. + If this is set to true, the `git stash show` command will show + the untracked files of a stash entry. Defaults to false. See + description of 'show' command in linkgit:git-stash[1]. stash.showPatch:: If this is set to true, the `git stash show` command without an diff --git a/Documentation/git-stash.txt b/Documentation/git-stash.txt index a8c8c32f1e..be6084ccef 100644 --- a/Documentation/git-stash.txt +++ b/Documentation/git-stash.txt @@ -91,8 +91,10 @@ show [-u|--include-untracked|--only-untracked] [<diff-options>] [<stash>]:: By default, the command shows the diffstat, but it will accept any format known to 'git diff' (e.g., `git stash show -p stash@{1}` to view the second most recent entry in patch form). - You can use stash.showIncludeUntracked, stash.showStat, and - stash.showPatch config variables to change the default behavior. + If no `<diff-option>` is provided, the default behavior will be given + by the `stash.showStat`, and `stash.showPatch` config variables. You + can also use `stash.showIncludeUntracked` to set whether + `--include-untracked` is enabled by default. pop [--index] [-q|--quiet] [<stash>]:: diff --git a/GIT-VERSION-GEN b/GIT-VERSION-GEN index dd1d8099c7..c0942f12a3 100755 --- a/GIT-VERSION-GEN +++ b/GIT-VERSION-GEN @@ -1,7 +1,7 @@ #!/bin/sh GVF=GIT-VERSION-FILE -DEF_VER=v2.32.0-rc0 +DEF_VER=v2.32.0-rc3 LF=' ' @@ -1687,13 +1687,31 @@ ifdef NO_UNIX_SOCKETS else LIB_OBJS += unix-socket.o LIB_OBJS += unix-stream-server.o - LIB_OBJS += compat/simple-ipc/ipc-shared.o - LIB_OBJS += compat/simple-ipc/ipc-unix-socket.o endif +# Simple IPC requires threads and platform-specific IPC support. +# Only platforms that have both should include these source files +# in the build. +# +# On Windows-based systems, Simple IPC requires threads and Windows +# Named Pipes. These are always available, so Simple IPC support +# is optional. +# +# On Unix-based systems, Simple IPC requires pthreads and Unix +# domain sockets. So support is only enabled when both are present. +# ifdef USE_WIN32_IPC + BASIC_CFLAGS += -DSUPPORTS_SIMPLE_IPC LIB_OBJS += compat/simple-ipc/ipc-shared.o LIB_OBJS += compat/simple-ipc/ipc-win32.o +else +ifndef NO_PTHREADS +ifndef NO_UNIX_SOCKETS + BASIC_CFLAGS += -DSUPPORTS_SIMPLE_IPC + LIB_OBJS += compat/simple-ipc/ipc-shared.o + LIB_OBJS += compat/simple-ipc/ipc-unix-socket.o +endif +endif endif ifdef NO_ICONV @@ -1987,6 +2005,7 @@ ETC_GITCONFIG_SQ = $(subst ','\'',$(ETC_GITCONFIG)) ETC_GITATTRIBUTES_SQ = $(subst ','\'',$(ETC_GITATTRIBUTES)) DESTDIR_SQ = $(subst ','\'',$(DESTDIR)) +NO_GETTEXT_SQ = $(subst ','\'',$(NO_GETTEXT)) bindir_SQ = $(subst ','\'',$(bindir)) bindir_relative_SQ = $(subst ','\'',$(bindir_relative)) mandir_SQ = $(subst ','\'',$(mandir)) @@ -2271,10 +2290,13 @@ perl_localedir_SQ = $(localedir_SQ) ifndef NO_PERL PERL_HEADER_TEMPLATE = perl/header_templates/fixed_prefix.template.pl -PERL_DEFINES = $(PERL_PATH_SQ):$(PERLLIB_EXTRA_SQ):$(perllibdir_SQ) - -PERL_DEFINES := $(PERL_PATH_SQ) $(PERLLIB_EXTRA_SQ) $(perllibdir_SQ) +PERL_DEFINES = +PERL_DEFINES += $(PERL_PATH_SQ) +PERL_DEFINES += $(PERLLIB_EXTRA_SQ) +PERL_DEFINES += $(perllibdir_SQ) PERL_DEFINES += $(RUNTIME_PREFIX) +PERL_DEFINES += $(NO_PERL_CPAN_FALLBACKS) +PERL_DEFINES += $(NO_GETTEXT) # Support Perl runtime prefix. In this mode, a different header is installed # into Perl scripts. @@ -2676,9 +2698,10 @@ endif NO_PERL_CPAN_FALLBACKS_SQ = $(subst ','\'',$(NO_PERL_CPAN_FALLBACKS)) endif -perl/build/lib/%.pm: perl/%.pm +perl/build/lib/%.pm: perl/%.pm GIT-PERL-DEFINES $(QUIET_GEN)mkdir -p $(dir $@) && \ sed -e 's|@@LOCALEDIR@@|$(perl_localedir_SQ)|g' \ + -e 's|@@NO_GETTEXT@@|$(NO_GETTEXT_SQ)|g' \ -e 's|@@NO_PERL_CPAN_FALLBACKS@@|$(NO_PERL_CPAN_FALLBACKS_SQ)|g' \ < $< > $@ diff --git a/builtin/clean.c b/builtin/clean.c index f6d7e8119c..4944cf440b 100644 --- a/builtin/clean.c +++ b/builtin/clean.c @@ -189,10 +189,8 @@ static int remove_dirs(struct strbuf *path, const char *prefix, int force_flag, strbuf_complete(path, '/'); len = path->len; - while ((e = readdir(dir)) != NULL) { + while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) { struct stat st; - if (is_dot_or_dotdot(e->d_name)) - continue; strbuf_setlen(path, len); strbuf_addstr(path, e->d_name); diff --git a/builtin/fsck.c b/builtin/fsck.c index 87a99b0108..b42b6fe21f 100644 --- a/builtin/fsck.c +++ b/builtin/fsck.c @@ -109,7 +109,8 @@ static int fsck_error_func(struct fsck_options *o, static struct object_array pending; -static int mark_object(struct object *obj, int type, void *data, struct fsck_options *options) +static int mark_object(struct object *obj, enum object_type type, + void *data, struct fsck_options *options) { struct object *parent = data; diff --git a/builtin/init-db.c b/builtin/init-db.c index c19b35f1e6..2167796ff2 100644 --- a/builtin/init-db.c +++ b/builtin/init-db.c @@ -212,8 +212,9 @@ static int create_default_files(const char *template_path, * values (since we've just potentially changed what's available on * disk). */ - git_config_get_value("init.templatedir", &init_template_dir); + git_config_get_pathname("init.templatedir", &init_template_dir); copy_templates(template_path, init_template_dir); + free((char *)init_template_dir); git_config_clear(); reset_shared_repository(); git_config(git_default_config, NULL); diff --git a/builtin/ls-files.c b/builtin/ls-files.c index 844c7f4e0e..45cc3b23dd 100644 --- a/builtin/ls-files.c +++ b/builtin/ls-files.c @@ -752,6 +752,9 @@ int cmd_ls_files(int argc, const char **argv, const char *cmd_prefix) if (pathspec.nr && error_unmatch) ps_matched = xcalloc(pathspec.nr, 1); + if ((dir.flags & DIR_SHOW_IGNORED) && !show_others && !show_cached) + die("ls-files -i must be used with either -o or -c"); + if ((dir.flags & DIR_SHOW_IGNORED) && !exc_given) die("ls-files --ignored needs some exclude pattern"); diff --git a/builtin/pack-objects.c b/builtin/pack-objects.c index 6ded130e45..de00adbb9e 100644 --- a/builtin/pack-objects.c +++ b/builtin/pack-objects.c @@ -37,6 +37,134 @@ #include "shallow.h" #include "promisor-remote.h" +/* + * Objects we are going to pack are collected in the `to_pack` structure. + * It contains an array (dynamically expanded) of the object data, and a map + * that can resolve SHA1s to their position in the array. + */ +static struct packing_data to_pack; + +static inline struct object_entry *oe_delta( + const struct packing_data *pack, + const struct object_entry *e) +{ + if (!e->delta_idx) + return NULL; + if (e->ext_base) + return &pack->ext_bases[e->delta_idx - 1]; + else + return &pack->objects[e->delta_idx - 1]; +} + +static inline unsigned long oe_delta_size(struct packing_data *pack, + const struct object_entry *e) +{ + if (e->delta_size_valid) + return e->delta_size_; + + /* + * pack->delta_size[] can't be NULL because oe_set_delta_size() + * must have been called when a new delta is saved with + * oe_set_delta(). + * If oe_delta() returns NULL (i.e. default state, which means + * delta_size_valid is also false), then the caller must never + * call oe_delta_size(). + */ + return pack->delta_size[e - pack->objects]; +} + +unsigned long oe_get_size_slow(struct packing_data *pack, + const struct object_entry *e); + +static inline unsigned long oe_size(struct packing_data *pack, + const struct object_entry *e) +{ + if (e->size_valid) + return e->size_; + + return oe_get_size_slow(pack, e); +} + +static inline void oe_set_delta(struct packing_data *pack, + struct object_entry *e, + struct object_entry *delta) +{ + if (delta) + e->delta_idx = (delta - pack->objects) + 1; + else + e->delta_idx = 0; +} + +static inline struct object_entry *oe_delta_sibling( + const struct packing_data *pack, + const struct object_entry *e) +{ + if (e->delta_sibling_idx) + return &pack->objects[e->delta_sibling_idx - 1]; + return NULL; +} + +static inline struct object_entry *oe_delta_child( + const struct packing_data *pack, + const struct object_entry *e) +{ + if (e->delta_child_idx) + return &pack->objects[e->delta_child_idx - 1]; + return NULL; +} + +static inline void oe_set_delta_child(struct packing_data *pack, + struct object_entry *e, + struct object_entry *delta) +{ + if (delta) + e->delta_child_idx = (delta - pack->objects) + 1; + else + e->delta_child_idx = 0; +} + +static inline void oe_set_delta_sibling(struct packing_data *pack, + struct object_entry *e, + struct object_entry *delta) +{ + if (delta) + e->delta_sibling_idx = (delta - pack->objects) + 1; + else + e->delta_sibling_idx = 0; +} + +static inline void oe_set_size(struct packing_data *pack, + struct object_entry *e, + unsigned long size) +{ + if (size < pack->oe_size_limit) { + e->size_ = size; + e->size_valid = 1; + } else { + e->size_valid = 0; + if (oe_get_size_slow(pack, e) != size) + BUG("'size' is supposed to be the object size!"); + } +} + +static inline void oe_set_delta_size(struct packing_data *pack, + struct object_entry *e, + unsigned long size) +{ + if (size < pack->oe_delta_size_limit) { + e->delta_size_ = size; + e->delta_size_valid = 1; + } else { + packing_data_lock(pack); + if (!pack->delta_size) + ALLOC_ARRAY(pack->delta_size, pack->nr_alloc); + packing_data_unlock(pack); + + pack->delta_size[e - pack->objects] = size; + e->delta_size_valid = 0; + } +} + #define IN_PACK(obj) oe_in_pack(&to_pack, obj) #define SIZE(obj) oe_size(&to_pack, obj) #define SET_SIZE(obj,size) oe_set_size(&to_pack, obj, size) @@ -56,13 +184,6 @@ static const char *pack_usage[] = { NULL }; -/* - * Objects we are going to pack are collected in the `to_pack` structure. - * It contains an array (dynamically expanded) of the object data, and a map - * that can resolve SHA1s to their position in the array. - */ -static struct packing_data to_pack; - static struct pack_idx_entry **written_list; static uint32_t nr_result, nr_written, nr_seen; static struct bitmap_index *bitmap_git; @@ -301,6 +422,17 @@ static void copy_pack_data(struct hashfile *f, } } +static inline int oe_size_greater_than(struct packing_data *pack, + const struct object_entry *lhs, + unsigned long rhs) +{ + if (lhs->size_valid) + return lhs->size_ > rhs; + if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */ + return 1; + return oe_get_size_slow(pack, lhs) > rhs; +} + /* Return 0 if we will bust the pack-size limit */ static unsigned long write_no_reuse_object(struct hashfile *f, struct object_entry *entry, unsigned long limit, int usable_delta) @@ -642,6 +774,14 @@ static int mark_tagged(const char *path, const struct object_id *oid, int flag, return 0; } +static inline unsigned char oe_layer(struct packing_data *pack, + struct object_entry *e) +{ + if (!pack->layer) + return 0; + return pack->layer[e - pack->objects]; +} + static inline void add_to_write_order(struct object_entry **wo, unsigned int *endp, struct object_entry *e) @@ -2231,6 +2371,26 @@ static pthread_mutex_t progress_mutex; * progress_mutex for protection. */ +static inline int oe_size_less_than(struct packing_data *pack, + const struct object_entry *lhs, + unsigned long rhs) +{ + if (lhs->size_valid) + return lhs->size_ < rhs; + if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */ + return 0; + return oe_get_size_slow(pack, lhs) < rhs; +} + +static inline void oe_set_tree_depth(struct packing_data *pack, + struct object_entry *e, + unsigned int tree_depth) +{ + if (!pack->tree_depth) + CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc); + pack->tree_depth[e - pack->objects] = tree_depth; +} + /* * Return the size of the object without doing any delta * reconstruction (so non-deltas are true object sizes, but deltas diff --git a/builtin/rev-parse.c b/builtin/rev-parse.c index 85bad9052e..7af8dab8bc 100644 --- a/builtin/rev-parse.c +++ b/builtin/rev-parse.c @@ -759,6 +759,8 @@ int cmd_rev_parse(int argc, const char **argv, const char *prefix) continue; } if (opt_with_value(arg, "--path-format", &arg)) { + if (!arg) + die("--path-format requires an argument"); if (!strcmp(arg, "absolute")) { format = FORMAT_CANONICAL; } else if (!strcmp(arg, "relative")) { diff --git a/builtin/stash.c b/builtin/stash.c index 56a33fb83a..01066d7085 100644 --- a/builtin/stash.c +++ b/builtin/stash.c @@ -833,7 +833,7 @@ static int show_stash(int argc, const char **argv, const char *prefix) UNTRACKED_NONE, UNTRACKED_INCLUDE, UNTRACKED_ONLY - } show_untracked = UNTRACKED_NONE; + } show_untracked = show_include_untracked ? UNTRACKED_INCLUDE : UNTRACKED_NONE; struct option options[] = { OPT_SET_INT('u', "include-untracked", &show_untracked, N_("include untracked files in the stash"), @@ -876,9 +876,6 @@ static int show_stash(int argc, const char **argv, const char *prefix) if (show_patch) rev.diffopt.output_format |= DIFF_FORMAT_PATCH; - if (show_include_untracked) - show_untracked = UNTRACKED_INCLUDE; - if (!show_stat && !show_patch) { free_stash_info(&info); return 0; diff --git a/builtin/worktree.c b/builtin/worktree.c index f754978e47..976bf8ed06 100644 --- a/builtin/worktree.c +++ b/builtin/worktree.c @@ -118,10 +118,8 @@ static void prune_worktrees(void) struct dirent *d; if (!dir) return; - while ((d = readdir(dir)) != NULL) { + while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) { char *path; - if (is_dot_or_dotdot(d->d_name)) - continue; strbuf_reset(&reason); if (should_prune_worktree(d->d_name, &reason, &path, expire)) prune_worktree(d->d_name, reason.buf); diff --git a/compat/simple-ipc/ipc-shared.c b/compat/simple-ipc/ipc-shared.c index 1edec81595..1b9d359ab6 100644 --- a/compat/simple-ipc/ipc-shared.c +++ b/compat/simple-ipc/ipc-shared.c @@ -4,7 +4,13 @@ #include "pkt-line.h" #include "thread-utils.h" -#ifdef SUPPORTS_SIMPLE_IPC +#ifndef SUPPORTS_SIMPLE_IPC +/* + * This source file should only be compiled when Simple IPC is supported. + * See the top-level Makefile. + */ +#error SUPPORTS_SIMPLE_IPC not defined +#endif int ipc_server_run(const char *path, const struct ipc_server_opts *opts, ipc_server_application_cb *application_cb, @@ -24,5 +30,3 @@ int ipc_server_run(const char *path, const struct ipc_server_opts *opts, return ret; } - -#endif /* SUPPORTS_SIMPLE_IPC */ diff --git a/compat/simple-ipc/ipc-unix-socket.c b/compat/simple-ipc/ipc-unix-socket.c index 38689b278d..1927e6ef4b 100644 --- a/compat/simple-ipc/ipc-unix-socket.c +++ b/compat/simple-ipc/ipc-unix-socket.c @@ -6,8 +6,12 @@ #include "unix-socket.h" #include "unix-stream-server.h" -#ifdef NO_UNIX_SOCKETS -#error compat/simple-ipc/ipc-unix-socket.c requires Unix sockets +#ifndef SUPPORTS_SIMPLE_IPC +/* + * This source file should only be compiled when Simple IPC is supported. + * See the top-level Makefile. + */ +#error SUPPORTS_SIMPLE_IPC not defined #endif enum ipc_active_state ipc_get_active_state(const char *path) diff --git a/compat/simple-ipc/ipc-win32.c b/compat/simple-ipc/ipc-win32.c index 8f89c02037..8dc7bda087 100644 --- a/compat/simple-ipc/ipc-win32.c +++ b/compat/simple-ipc/ipc-win32.c @@ -4,8 +4,12 @@ #include "pkt-line.h" #include "thread-utils.h" -#ifndef GIT_WINDOWS_NATIVE -#error This file can only be compiled on Windows +#ifndef SUPPORTS_SIMPLE_IPC +/* + * This source file should only be compiled when Simple IPC is supported. + * See the top-level Makefile. + */ +#error SUPPORTS_SIMPLE_IPC not defined #endif static int initialize_pipe_name(const char *path, wchar_t *wpath, size_t alloc) diff --git a/contrib/buildsystems/CMakeLists.txt b/contrib/buildsystems/CMakeLists.txt index 75ed198a6a..a87841340e 100644 --- a/contrib/buildsystems/CMakeLists.txt +++ b/contrib/buildsystems/CMakeLists.txt @@ -252,8 +252,15 @@ endif() if(CMAKE_SYSTEM_NAME STREQUAL "Windows") list(APPEND compat_SOURCES compat/simple-ipc/ipc-shared.c compat/simple-ipc/ipc-win32.c) + add_compile_definitions(SUPPORTS_SIMPLE_IPC) + set(SUPPORTS_SIMPLE_IPC 1) else() - list(APPEND compat_SOURCES compat/simple-ipc/ipc-shared.c compat/simple-ipc/ipc-unix-socket.c) + # Simple IPC requires both Unix sockets and pthreads on Unix-based systems. + if(NOT NO_UNIX_SOCKETS AND NOT NO_PTHREADS) + list(APPEND compat_SOURCES compat/simple-ipc/ipc-shared.c compat/simple-ipc/ipc-unix-socket.c) + add_compile_definitions(SUPPORTS_SIMPLE_IPC) + set(SUPPORTS_SIMPLE_IPC 1) + endif() endif() set(EXE_EXTENSION ${CMAKE_EXECUTABLE_SUFFIX}) @@ -974,6 +981,7 @@ file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "X='${EXE_EXTENSION}'\n") file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_GETTEXT='${NO_GETTEXT}'\n") file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "RUNTIME_PREFIX='${RUNTIME_PREFIX}'\n") file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "NO_PYTHON='${NO_PYTHON}'\n") +file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "SUPPORTS_SIMPLE_IPC='${SUPPORTS_SIMPLE_IPC}'\n") if(WIN32) file(APPEND ${CMAKE_BINARY_DIR}/GIT-BUILD-OPTIONS "PATH=\"$PATH:$TEST_DIRECTORY/../compat/vcbuild/vcpkg/installed/x64-windows/bin\"\n") endif() diff --git a/contrib/completion/git-completion.bash b/contrib/completion/git-completion.bash index 3c5739b905..b50c5d0ea3 100644 --- a/contrib/completion/git-completion.bash +++ b/contrib/completion/git-completion.bash @@ -1306,7 +1306,7 @@ __git_count_arguments () local word i c=0 # Skip "git" (first argument) - for ((i="$__git_cmd_idx"; i < ${#words[@]}; i++)); do + for ((i=$__git_cmd_idx; i < ${#words[@]}; i++)); do word="${words[i]}" case "$word" in diff --git a/contrib/completion/git-completion.zsh b/contrib/completion/git-completion.zsh index 6c56296997..cac6f61881 100644 --- a/contrib/completion/git-completion.zsh +++ b/contrib/completion/git-completion.zsh @@ -251,7 +251,7 @@ __git_zsh_main () done ;; (arg) - local command="${words[1]}" __git_dir + local command="${words[1]}" __git_dir __git_cmd_idx=1 if (( $+opt_args[--bare] )); then __git_dir='.' diff --git a/contrib/completion/git-prompt.sh b/contrib/completion/git-prompt.sh index 4640a1535d..db7c0068fb 100644 --- a/contrib/completion/git-prompt.sh +++ b/contrib/completion/git-prompt.sh @@ -433,8 +433,8 @@ __git_ps1 () fi local sparse="" - if [ -z "${GIT_PS1_COMPRESSSPARSESTATE}" ] && - [ -z "${GIT_PS1_OMITSPARSESTATE}" ] && + if [ -z "${GIT_PS1_COMPRESSSPARSESTATE-}" ] && + [ -z "${GIT_PS1_OMITSPARSESTATE-}" ] && [ "$(git config --bool core.sparseCheckout)" = "true" ]; then sparse="|SPARSE" fi @@ -543,7 +543,7 @@ __git_ps1 () u="%${ZSH_VERSION+%}" fi - if [ -n "${GIT_PS1_COMPRESSSPARSESTATE}" ] && + if [ -n "${GIT_PS1_COMPRESSSPARSESTATE-}" ] && [ "$(git config --bool core.sparseCheckout)" = "true" ]; then h="?" fi diff --git a/diff-no-index.c b/diff-no-index.c index 308922e2b3..9a8b09346b 100644 --- a/diff-no-index.c +++ b/diff-no-index.c @@ -26,9 +26,8 @@ static int read_directory_contents(const char *path, struct string_list *list) if (!(dir = opendir(path))) return error("Could not open directory %s", path); - while ((e = readdir(dir))) - if (!is_dot_or_dotdot(e->d_name)) - string_list_insert(list, e->d_name); + while ((e = readdir_skip_dot_and_dotdot(dir))) + string_list_insert(list, e->d_name); closedir(dir); return 0; @@ -59,6 +59,17 @@ void dir_init(struct dir_struct *dir) memset(dir, 0, sizeof(*dir)); } +struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp) +{ + struct dirent *e; + + while ((e = readdir(dirp)) != NULL) { + if (!is_dot_or_dotdot(e->d_name)) + break; + } + return e; +} + int count_slashes(const char *s) { int cnt = 0; @@ -1749,13 +1760,13 @@ static enum exist_status directory_exists_in_index(struct index_state *istate, * Case 3: if we didn't have it in the index previously, we * have a few sub-cases: * - * (a) if "show_other_directories" is true, we show it as - * just a directory, unless "hide_empty_directories" is + * (a) if DIR_SHOW_OTHER_DIRECTORIES flag is set, we show it as + * just a directory, unless DIR_HIDE_EMPTY_DIRECTORIES is * also true, in which case we need to check if it contains any * untracked and / or ignored files. - * (b) if it looks like a git directory, and we don't have - * 'no_gitlinks' set we treat it as a gitlink, and show it - * as a directory. + * (b) if it looks like a git directory and we don't have the + * DIR_NO_GITLINKS flag, then we treat it as a gitlink, and + * show it as a directory. * (c) otherwise, we recurse into it. */ static enum path_treatment treat_directory(struct dir_struct *dir, @@ -1843,7 +1854,7 @@ static enum path_treatment treat_directory(struct dir_struct *dir, return path_recurse; } - /* This is the "show_other_directories" case */ + assert(dir->flags & DIR_SHOW_OTHER_DIRECTORIES); /* * If we have a pathspec which could match something _below_ this @@ -1854,27 +1865,42 @@ static enum path_treatment treat_directory(struct dir_struct *dir, if (matches_how == MATCHED_RECURSIVELY_LEADING_PATHSPEC) return path_recurse; + /* Special cases for where this directory is excluded/ignored */ + if (excluded) { + /* + * If DIR_SHOW_OTHER_DIRECTORIES is set and we're not + * hiding empty directories, there is no need to + * recurse into an ignored directory. + */ + if (!(dir->flags & DIR_HIDE_EMPTY_DIRECTORIES)) + return path_excluded; + + /* + * Even if we are hiding empty directories, we can still avoid + * recursing into ignored directories for DIR_SHOW_IGNORED_TOO + * if DIR_SHOW_IGNORED_TOO_MODE_MATCHING is also set. + */ + if ((dir->flags & DIR_SHOW_IGNORED_TOO) && + (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) + return path_excluded; + } + /* - * Other than the path_recurse case immediately above, we only need - * to recurse into untracked/ignored directories if either of the - * following bits is set: - * - DIR_SHOW_IGNORED_TOO (because then we need to determine if - * there are ignored entries below) + * Other than the path_recurse case above, we only need to + * recurse into untracked directories if any of the following + * bits is set: + * - DIR_SHOW_IGNORED (because then we need to determine if + * there are ignored entries below) + * - DIR_SHOW_IGNORED_TOO (same as above) * - DIR_HIDE_EMPTY_DIRECTORIES (because we have to determine if * the directory is empty) */ - if (!(dir->flags & (DIR_SHOW_IGNORED_TOO | DIR_HIDE_EMPTY_DIRECTORIES))) - return excluded ? path_excluded : path_untracked; - - /* - * ...and even if DIR_SHOW_IGNORED_TOO is set, we can still avoid - * recursing into ignored directories if the path is excluded and - * DIR_SHOW_IGNORED_TOO_MODE_MATCHING is also set. - */ - if (excluded && - (dir->flags & DIR_SHOW_IGNORED_TOO) && - (dir->flags & DIR_SHOW_IGNORED_TOO_MODE_MATCHING)) - return path_excluded; + if (!excluded && + !(dir->flags & (DIR_SHOW_IGNORED | + DIR_SHOW_IGNORED_TOO | + DIR_HIDE_EMPTY_DIRECTORIES))) { + return path_untracked; + } /* * Even if we don't want to know all the paths under an untracked or @@ -2326,7 +2352,7 @@ static int read_cached_dir(struct cached_dir *cdir) struct dirent *de; if (cdir->fdir) { - de = readdir(cdir->fdir); + de = readdir_skip_dot_and_dotdot(cdir->fdir); if (!de) { cdir->d_name = NULL; cdir->d_type = DT_UNKNOWN; @@ -2440,6 +2466,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, if (open_cached_dir(&cdir, dir, untracked, istate, &path, check_only)) goto out; + dir->visited_directories++; if (untracked) untracked->check_only = !!check_only; @@ -2448,6 +2475,7 @@ static enum path_treatment read_directory_recursive(struct dir_struct *dir, /* check how the file or directory should be treated */ state = treat_path(dir, untracked, &cdir, istate, &path, baselen, pathspec); + dir->visited_paths++; if (state > dir_state) dir_state = state; @@ -2760,15 +2788,53 @@ static struct untracked_cache_dir *validate_untracked_cache(struct dir_struct *d return root; } +static void emit_traversal_statistics(struct dir_struct *dir, + struct repository *repo, + const char *path, + int path_len) +{ + if (!trace2_is_enabled()) + return; + + if (!path_len) { + trace2_data_string("read_directory", repo, "path", ""); + } else { + struct strbuf tmp = STRBUF_INIT; + strbuf_add(&tmp, path, path_len); + trace2_data_string("read_directory", repo, "path", tmp.buf); + strbuf_release(&tmp); + } + + trace2_data_intmax("read_directory", repo, + "directories-visited", dir->visited_directories); + trace2_data_intmax("read_directory", repo, + "paths-visited", dir->visited_paths); + + if (!dir->untracked) + return; + trace2_data_intmax("read_directory", repo, + "node-creation", dir->untracked->dir_created); + trace2_data_intmax("read_directory", repo, + "gitignore-invalidation", + dir->untracked->gitignore_invalidated); + trace2_data_intmax("read_directory", repo, + "directory-invalidation", + dir->untracked->dir_invalidated); + trace2_data_intmax("read_directory", repo, + "opendir", dir->untracked->dir_opened); +} + int read_directory(struct dir_struct *dir, struct index_state *istate, const char *path, int len, const struct pathspec *pathspec) { struct untracked_cache_dir *untracked; - trace_performance_enter(); + trace2_region_enter("dir", "read_directory", istate->repo); + dir->visited_paths = 0; + dir->visited_directories = 0; if (has_symlink_leading_path(path, len)) { - trace_performance_leave("read directory %.*s", len, path); + trace2_region_leave("dir", "read_directory", istate->repo); return dir->nr; } @@ -2784,23 +2850,15 @@ int read_directory(struct dir_struct *dir, struct index_state *istate, QSORT(dir->entries, dir->nr, cmp_dir_entry); QSORT(dir->ignored, dir->ignored_nr, cmp_dir_entry); - trace_performance_leave("read directory %.*s", len, path); + emit_traversal_statistics(dir, istate->repo, path, len); + + trace2_region_leave("dir", "read_directory", istate->repo); if (dir->untracked) { static int force_untracked_cache = -1; - static struct trace_key trace_untracked_stats = TRACE_KEY_INIT(UNTRACKED_STATS); if (force_untracked_cache < 0) force_untracked_cache = git_env_bool("GIT_FORCE_UNTRACKED_CACHE", 0); - trace_printf_key(&trace_untracked_stats, - "node creation: %u\n" - "gitignore invalidation: %u\n" - "directory invalidation: %u\n" - "opendir: %u\n", - dir->untracked->dir_created, - dir->untracked->gitignore_invalidated, - dir->untracked->dir_invalidated, - dir->untracked->dir_opened); if (force_untracked_cache && dir->untracked == istate->untracked && (dir->untracked->dir_opened || @@ -2811,6 +2869,7 @@ int read_directory(struct dir_struct *dir, struct index_state *istate, FREE_AND_NULL(dir->untracked); } } + return dir->nr; } @@ -2892,11 +2951,9 @@ int is_empty_dir(const char *path) if (!dir) return 0; - while ((e = readdir(dir)) != NULL) - if (!is_dot_or_dotdot(e->d_name)) { - ret = 0; - break; - } + e = readdir_skip_dot_and_dotdot(dir); + if (e) + ret = 0; closedir(dir); return ret; @@ -2936,10 +2993,8 @@ static int remove_dir_recurse(struct strbuf *path, int flag, int *kept_up) strbuf_complete(path, '/'); len = path->len; - while ((e = readdir(dir)) != NULL) { + while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) { struct stat st; - if (is_dot_or_dotdot(e->d_name)) - continue; strbuf_setlen(path, len); strbuf_addstr(path, e->d_name); @@ -336,8 +336,14 @@ struct dir_struct { struct oid_stat ss_info_exclude; struct oid_stat ss_excludes_file; unsigned unmanaged_exclude_files; + + /* Stats about the traversal */ + unsigned visited_paths; + unsigned visited_directories; }; +struct dirent *readdir_skip_dot_and_dotdot(DIR *dirp); + /*Count the number of slashes for string s*/ int count_slashes(const char *s); @@ -58,12 +58,9 @@ static void remove_subtree(struct strbuf *path) if (!dir) die_errno("cannot opendir '%s'", path->buf); - while ((de = readdir(dir)) != NULL) { + while ((de = readdir_skip_dot_and_dotdot(dir)) != NULL) { struct stat st; - if (is_dot_or_dotdot(de->d_name)) - continue; - strbuf_addch(path, '/'); strbuf_addstr(path, de->d_name); if (lstat(path->buf, &st)) diff --git a/git-send-email.perl b/git-send-email.perl index 175da07d94..25be2ebd2a 100755 --- a/git-send-email.perl +++ b/git-send-email.perl @@ -219,8 +219,18 @@ sub system_or_msg { my $exit_code = $? >> 8; return unless $signalled or $exit_code; + my @sprintf_args = ($args->[0], $exit_code); + if (defined $msg) { + # Quiet the 'redundant' warning category, except we + # need to support down to Perl 5.8, so we can't do a + # "no warnings 'redundant'", since that category was + # introduced in perl 5.22, and asking for it will die + # on older perls. + no warnings; + return sprintf($msg, @sprintf_args); + } return sprintf(__("fatal: command '%s' died with exit code %d"), - $args->[0], $exit_code); + @sprintf_args); } sub system_or_die { @@ -1949,7 +1959,8 @@ sub validate_patch { my ($fn, $xfer_encoding) = @_; if ($repo) { - my $validate_hook = catfile($repo->hooks_path(), + my $hooks_path = $repo->command_oneline('rev-parse', '--git-path', 'hooks'); + my $validate_hook = catfile($hooks_path, 'sendemail-validate'); my $hook_error; if (-x $validate_hook) { @@ -1650,18 +1650,17 @@ static int handle_curl_result(struct slot_results *results) } else if (missing_target(results)) return HTTP_MISSING_TARGET; else if (results->http_code == 401) { -#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY - http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE; - if (results->auth_avail) { - http_auth_methods &= results->auth_avail; - http_auth_methods_restricted = 1; - return HTTP_REAUTH; - } -#endif if (http_auth.username && http_auth.password) { credential_reject(&http_auth); return HTTP_NOAUTH; } else { +#ifdef LIBCURL_CAN_HANDLE_AUTH_ANY + http_auth_methods &= ~CURLAUTH_GSSNEGOTIATE; + if (results->auth_avail) { + http_auth_methods &= results->auth_avail; + http_auth_methods_restricted = 1; + } +#endif return HTTP_REAUTH; } } else { diff --git a/notes-merge.c b/notes-merge.c index 12e8472b65..46c1f7c7f1 100644 --- a/notes-merge.c +++ b/notes-merge.c @@ -695,13 +695,10 @@ int notes_merge_commit(struct notes_merge_options *o, strbuf_addch(&path, '/'); baselen = path.len; - while ((e = readdir(dir)) != NULL) { + while ((e = readdir_skip_dot_and_dotdot(dir)) != NULL) { struct stat st; struct object_id obj_oid, blob_oid; - if (is_dot_or_dotdot(e->d_name)) - continue; - if (get_oid_hex(e->d_name, &obj_oid)) { if (o->verbosity >= 3) printf("Skipping non-SHA1 entry '%s%s'\n", diff --git a/object-file.c b/object-file.c index 884855b9df..f233b440b2 100644 --- a/object-file.c +++ b/object-file.c @@ -2350,10 +2350,8 @@ int for_each_file_in_obj_subdir(unsigned int subdir_nr, strbuf_addch(path, '/'); baselen = path->len; - while ((de = readdir(dir))) { + while ((de = readdir_skip_dot_and_dotdot(dir))) { size_t namelen; - if (is_dot_or_dotdot(de->d_name)) - continue; namelen = strlen(de->d_name); strbuf_setlen(path, baselen); diff --git a/pack-objects.h b/pack-objects.h index 9d88e3e518..dca2351ef9 100644 --- a/pack-objects.h +++ b/pack-objects.h @@ -268,152 +268,10 @@ static inline void oe_set_in_pack(struct packing_data *pack, pack->in_pack[e - pack->objects] = p; } -static inline struct object_entry *oe_delta( - const struct packing_data *pack, - const struct object_entry *e) -{ - if (!e->delta_idx) - return NULL; - if (e->ext_base) - return &pack->ext_bases[e->delta_idx - 1]; - else - return &pack->objects[e->delta_idx - 1]; -} - -static inline void oe_set_delta(struct packing_data *pack, - struct object_entry *e, - struct object_entry *delta) -{ - if (delta) - e->delta_idx = (delta - pack->objects) + 1; - else - e->delta_idx = 0; -} - void oe_set_delta_ext(struct packing_data *pack, struct object_entry *e, const struct object_id *oid); -static inline struct object_entry *oe_delta_child( - const struct packing_data *pack, - const struct object_entry *e) -{ - if (e->delta_child_idx) - return &pack->objects[e->delta_child_idx - 1]; - return NULL; -} - -static inline void oe_set_delta_child(struct packing_data *pack, - struct object_entry *e, - struct object_entry *delta) -{ - if (delta) - e->delta_child_idx = (delta - pack->objects) + 1; - else - e->delta_child_idx = 0; -} - -static inline struct object_entry *oe_delta_sibling( - const struct packing_data *pack, - const struct object_entry *e) -{ - if (e->delta_sibling_idx) - return &pack->objects[e->delta_sibling_idx - 1]; - return NULL; -} - -static inline void oe_set_delta_sibling(struct packing_data *pack, - struct object_entry *e, - struct object_entry *delta) -{ - if (delta) - e->delta_sibling_idx = (delta - pack->objects) + 1; - else - e->delta_sibling_idx = 0; -} - -unsigned long oe_get_size_slow(struct packing_data *pack, - const struct object_entry *e); -static inline unsigned long oe_size(struct packing_data *pack, - const struct object_entry *e) -{ - if (e->size_valid) - return e->size_; - - return oe_get_size_slow(pack, e); -} - -static inline int oe_size_less_than(struct packing_data *pack, - const struct object_entry *lhs, - unsigned long rhs) -{ - if (lhs->size_valid) - return lhs->size_ < rhs; - if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */ - return 0; - return oe_get_size_slow(pack, lhs) < rhs; -} - -static inline int oe_size_greater_than(struct packing_data *pack, - const struct object_entry *lhs, - unsigned long rhs) -{ - if (lhs->size_valid) - return lhs->size_ > rhs; - if (rhs < pack->oe_size_limit) /* rhs < 2^x <= lhs ? */ - return 1; - return oe_get_size_slow(pack, lhs) > rhs; -} - -static inline void oe_set_size(struct packing_data *pack, - struct object_entry *e, - unsigned long size) -{ - if (size < pack->oe_size_limit) { - e->size_ = size; - e->size_valid = 1; - } else { - e->size_valid = 0; - if (oe_get_size_slow(pack, e) != size) - BUG("'size' is supposed to be the object size!"); - } -} - -static inline unsigned long oe_delta_size(struct packing_data *pack, - const struct object_entry *e) -{ - if (e->delta_size_valid) - return e->delta_size_; - - /* - * pack->delta_size[] can't be NULL because oe_set_delta_size() - * must have been called when a new delta is saved with - * oe_set_delta(). - * If oe_delta() returns NULL (i.e. default state, which means - * delta_size_valid is also false), then the caller must never - * call oe_delta_size(). - */ - return pack->delta_size[e - pack->objects]; -} - -static inline void oe_set_delta_size(struct packing_data *pack, - struct object_entry *e, - unsigned long size) -{ - if (size < pack->oe_delta_size_limit) { - e->delta_size_ = size; - e->delta_size_valid = 1; - } else { - packing_data_lock(pack); - if (!pack->delta_size) - ALLOC_ARRAY(pack->delta_size, pack->nr_alloc); - packing_data_unlock(pack); - - pack->delta_size[e - pack->objects] = size; - e->delta_size_valid = 0; - } -} - static inline unsigned int oe_tree_depth(struct packing_data *pack, struct object_entry *e) { @@ -422,23 +280,6 @@ static inline unsigned int oe_tree_depth(struct packing_data *pack, return pack->tree_depth[e - pack->objects]; } -static inline void oe_set_tree_depth(struct packing_data *pack, - struct object_entry *e, - unsigned int tree_depth) -{ - if (!pack->tree_depth) - CALLOC_ARRAY(pack->tree_depth, pack->nr_alloc); - pack->tree_depth[e - pack->objects] = tree_depth; -} - -static inline unsigned char oe_layer(struct packing_data *pack, - struct object_entry *e) -{ - if (!pack->layer) - return 0; - return pack->layer[e - pack->objects]; -} - static inline void oe_set_layer(struct packing_data *pack, struct object_entry *e, unsigned char layer) diff --git a/packfile.c b/packfile.c index b79cbc8cd4..755aa7aec5 100644 --- a/packfile.c +++ b/packfile.c @@ -813,10 +813,7 @@ void for_each_file_in_pack_dir(const char *objdir, } strbuf_addch(&path, '/'); dirnamelen = path.len; - while ((de = readdir(dir)) != NULL) { - if (is_dot_or_dotdot(de->d_name)) - continue; - + while ((de = readdir_skip_dot_and_dotdot(dir)) != NULL) { strbuf_setlen(&path, dirnamelen); strbuf_addstr(&path, de->d_name); diff --git a/perl/Git.pm b/perl/Git.pm index 73ebbf80cc..02eacef0c2 100644 --- a/perl/Git.pm +++ b/perl/Git.pm @@ -619,19 +619,6 @@ Return path to the git repository. Must be called on a repository instance. sub repo_path { $_[0]->{opts}->{Repository} } -=item hooks_path () - -Return path to the hooks directory. Must be called on a repository instance. - -=cut - -sub hooks_path { - my ($self) = @_; - - my $dir = $self->command_oneline('rev-parse', '--git-path', 'hooks'); - my $abs = abs_path($dir); - return $abs; -} =item wc_path () diff --git a/perl/Git/I18N.pm b/perl/Git/I18N.pm index 2037f387c8..895e759c57 100644 --- a/perl/Git/I18N.pm +++ b/perl/Git/I18N.pm @@ -16,9 +16,19 @@ BEGIN { our @EXPORT = qw(__ __n N__); our @EXPORT_OK = @EXPORT; +# See Git::LoadCPAN's NO_PERL_CPAN_FALLBACKS_STR for a description of +# this "'@@' [...] '@@'" pattern. +use constant NO_GETTEXT_STR => '@@' . 'NO_GETTEXT' . '@@'; +use constant NO_GETTEXT => ( + q[@@NO_GETTEXT@@] ne '' + and + q[@@NO_GETTEXT@@] ne NO_GETTEXT_STR +); + sub __bootstrap_locale_messages { our $TEXTDOMAIN = 'git'; our $TEXTDOMAINDIR ||= $ENV{GIT_TEXTDOMAINDIR} || '@@LOCALEDIR@@'; + die "NO_GETTEXT=" . NO_GETTEXT_STR if NO_GETTEXT; require POSIX; POSIX->import(qw(setlocale)); diff --git a/ref-filter.c b/ref-filter.c index e2eac50d95..97116e12d7 100644 --- a/ref-filter.c +++ b/ref-filter.c @@ -1730,7 +1730,7 @@ static int populate_value(struct ref_array_item *ref, struct strbuf *err) else v->s = xstrdup(""); continue; - } else if (atom->u.remote_ref.push) { + } else if (!strcmp(atom->name, "push") || starts_with(atom->name, "push:")) { const char *branch_name; v->s = xstrdup(""); if (!skip_prefix(ref->refname, "refs/heads/", diff --git a/remote-curl.c b/remote-curl.c index 0290b04891..9d432c299a 100644 --- a/remote-curl.c +++ b/remote-curl.c @@ -555,6 +555,8 @@ static void output_refs(struct ref *refs) struct ref *posn; if (options.object_format && options.hash_algo) { printf(":object-format %s\n", options.hash_algo->name); + repo_set_hash_algo(the_repository, + hash_algo_by_ptr(options.hash_algo)); } for (posn = refs; posn; posn = posn->next) { if (posn->symref) @@ -1190,13 +1190,11 @@ void rerere_gc(struct repository *r, struct string_list *rr) if (!dir) die_errno(_("unable to open rr-cache directory")); /* Collect stale conflict IDs ... */ - while ((e = readdir(dir))) { + while ((e = readdir_skip_dot_and_dotdot(dir))) { struct rerere_dir *rr_dir; struct rerere_id id; int now_empty; - if (is_dot_or_dotdot(e->d_name)) - continue; if (!is_rr_cache_dirname(e->d_name)) continue; /* or should we remove e->d_name? */ diff --git a/simple-ipc.h b/simple-ipc.h index dc3606e30b..2c48a5ee00 100644 --- a/simple-ipc.h +++ b/simple-ipc.h @@ -5,10 +5,6 @@ * See Documentation/technical/api-simple-ipc.txt */ -#if defined(GIT_WINDOWS_NATIVE) || !defined(NO_UNIX_SOCKETS) -#define SUPPORTS_SIMPLE_IPC -#endif - #ifdef SUPPORTS_SIMPLE_IPC #include "pkt-line.h" diff --git a/sparse-index.c b/sparse-index.c index b0d5dc5f08..affc4048f2 100644 --- a/sparse-index.c +++ b/sparse-index.c @@ -34,7 +34,7 @@ static int convert_to_sparse_rec(struct index_state *istate, int i, can_convert = 1; int start_converted = num_converted; enum pattern_match_result match; - int dtype; + int dtype = DT_UNKNOWN; struct strbuf child_path = STRBUF_INIT; struct pattern_list *pl = istate->sparse_checkout_patterns; @@ -196,6 +196,11 @@ appropriately before running "make". Short options can be bundled, i.e. this feature by setting the GIT_TEST_CHAIN_LINT environment variable to "1" or "0", respectively. + A few test scripts disable some of the more advanced + chain-linting detection in the name of efficiency. You can + override this by setting the GIT_TEST_CHAIN_LINT_HARDER + environment variable to "1". + --stress:: Run the test script repeatedly in multiple parallel jobs until one of them fails. Useful for reproducing rare failures in diff --git a/t/lib-parallel-checkout.sh b/t/lib-parallel-checkout.sh index 21f5759732..83b279a846 100644 --- a/t/lib-parallel-checkout.sh +++ b/t/lib-parallel-checkout.sh @@ -27,7 +27,7 @@ test_checkout_workers () { rm -f "$trace_file" && GIT_TRACE2="$(pwd)/$trace_file" "$@" 2>&8 && - local workers=$(grep "child_start\[..*\] git checkout--worker" "$trace_file" | wc -l) && + local workers="$(grep "child_start\[..*\] git checkout--worker" "$trace_file" | wc -l)" && test $workers -eq $expected_workers && rm "$trace_file" } 8>&2 2>&4 diff --git a/t/t0001-init.sh b/t/t0001-init.sh index 0803994874..acd662e403 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -186,21 +186,33 @@ test_expect_success 'init with --template (blank)' ' test_path_is_missing template-blank/.git/info/exclude ' -test_expect_success 'init with init.templatedir set' ' - mkdir templatedir-source && - echo Content >templatedir-source/file && - test_config_global init.templatedir "${HOME}/templatedir-source" && +init_no_templatedir_env () { ( - mkdir templatedir-set && - cd templatedir-set && sane_unset GIT_TEMPLATE_DIR && NO_SET_GIT_TEMPLATE_DIR=t && export NO_SET_GIT_TEMPLATE_DIR && - git init - ) && + git init "$1" + ) +} + +test_expect_success 'init with init.templatedir set' ' + mkdir templatedir-source && + echo Content >templatedir-source/file && + test_config_global init.templatedir "${HOME}/templatedir-source" && + + init_no_templatedir_env templatedir-set && test_cmp templatedir-source/file templatedir-set/.git/file ' +test_expect_success 'init with init.templatedir using ~ expansion' ' + mkdir -p templatedir-source && + echo Content >templatedir-source/file && + test_config_global init.templatedir "~/templatedir-source" && + + init_no_templatedir_env templatedir-expansion && + test_cmp templatedir-source/file templatedir-expansion/.git/file +' + test_expect_success 'init --bare/--shared overrides system/global config' ' test_config_global core.bare false && test_config_global core.sharedRepository 0640 && diff --git a/t/t0027-auto-crlf.sh b/t/t0027-auto-crlf.sh index d24d5acfbc..4a5c5c602c 100755 --- a/t/t0027-auto-crlf.sh +++ b/t/t0027-auto-crlf.sh @@ -386,7 +386,9 @@ test_expect_success 'setup main' ' test_tick ' - +# Disable extra chain-linting for the next set of tests. There are many +# auto-generated ones that are not worth checking over and over. +GIT_TEST_CHAIN_LINT_HARDER_DEFAULT=0 warn_LF_CRLF="LF will be replaced by CRLF" warn_CRLF_LF="CRLF will be replaced by LF" @@ -597,6 +599,9 @@ do checkout_files auto "$id" "" false native $NL CRLF CRLF_mix_LF LF_mix_CR LF_nul done +# The rest of the tests are unique; do the usual linting. +unset GIT_TEST_CHAIN_LINT_HARDER_DEFAULT + # Should be the last test case: remove some files from the worktree test_expect_success 'ls-files --eol -d -z' ' rm crlf_false_attr__CRLF.txt crlf_false_attr__CRLF_mix_LF.txt crlf_false_attr__LF.txt .gitattributes && diff --git a/t/t1092-sparse-checkout-compatibility.sh b/t/t1092-sparse-checkout-compatibility.sh index 12e6c45302..e9a815ca7a 100755 --- a/t/t1092-sparse-checkout-compatibility.sh +++ b/t/t1092-sparse-checkout-compatibility.sh @@ -106,18 +106,18 @@ init_repos () { run_on_sparse () { ( cd sparse-checkout && - "$@" >../sparse-checkout-out 2>../sparse-checkout-err + GIT_PROGRESS_DELAY=100000 "$@" >../sparse-checkout-out 2>../sparse-checkout-err ) && ( cd sparse-index && - "$@" >../sparse-index-out 2>../sparse-index-err + GIT_PROGRESS_DELAY=100000 "$@" >../sparse-index-out 2>../sparse-index-err ) } run_on_all () { ( cd full-checkout && - "$@" >../full-checkout-out 2>../full-checkout-err + GIT_PROGRESS_DELAY=100000 "$@" >../full-checkout-out 2>../full-checkout-err ) && run_on_sparse "$@" } diff --git a/t/t1306-xdg-files.sh b/t/t1306-xdg-files.sh index dd87b43be1..40d3c42618 100755 --- a/t/t1306-xdg-files.sh +++ b/t/t1306-xdg-files.sh @@ -116,7 +116,7 @@ test_expect_success 'Exclusion in a non-XDG global ignore file' ' test_expect_success 'Checking XDG ignore file when HOME is unset' ' (sane_unset HOME && git config --unset core.excludesfile && - git ls-files --exclude-standard --ignored >actual) && + git ls-files --exclude-standard --ignored --others >actual) && test_must_be_empty actual ' diff --git a/t/t1500-rev-parse.sh b/t/t1500-rev-parse.sh index deae916707..1c2df08333 100755 --- a/t/t1500-rev-parse.sh +++ b/t/t1500-rev-parse.sh @@ -146,6 +146,10 @@ test_expect_success '--path-format can change in the middle of the command line' test_cmp expect actual ' +test_expect_success '--path-format does not segfault without an argument' ' + test_must_fail git rev-parse --path-format +' + test_expect_success 'git-common-dir from worktree root' ' echo .git >expect && git rev-parse --git-common-dir >actual && diff --git a/t/t2080-parallel-checkout-basics.sh b/t/t2080-parallel-checkout-basics.sh index 7087818550..3e0f8c675f 100755 --- a/t/t2080-parallel-checkout-basics.sh +++ b/t/t2080-parallel-checkout-basics.sh @@ -114,7 +114,7 @@ do test_expect_success "$mode checkout" ' repo=various_$mode && - cp -R various $repo && + cp -R -P various $repo && # The just copied files have more recent timestamps than their # associated index entries. So refresh the cached timestamps diff --git a/t/t3001-ls-files-others-exclude.sh b/t/t3001-ls-files-others-exclude.sh index 1ec7cb57c7..516c95ea0e 100755 --- a/t/t3001-ls-files-others-exclude.sh +++ b/t/t3001-ls-files-others-exclude.sh @@ -292,6 +292,11 @@ EOF test_cmp expect actual ' +test_expect_success 'ls-files with "**" patterns and --directory' ' + # Expectation same as previous test + git ls-files --directory -o -i --exclude "**/a.1" >actual && + test_cmp expect actual +' test_expect_success 'ls-files with "**" patterns and no slashes' ' git ls-files -o -i --exclude "one**a.1" >actual && diff --git a/t/t3003-ls-files-exclude.sh b/t/t3003-ls-files-exclude.sh index d5ec333131..c41c4f046a 100755 --- a/t/t3003-ls-files-exclude.sh +++ b/t/t3003-ls-files-exclude.sh @@ -29,11 +29,11 @@ test_expect_success 'add file to gitignore' ' ' check_all_output -test_expect_success 'ls-files -i lists only tracked-but-ignored files' ' +test_expect_success 'ls-files -i -c lists only tracked-but-ignored files' ' echo content >other-file && git add other-file && echo file >expect && - git ls-files -i --exclude-standard >output && + git ls-files -i -c --exclude-standard >output && test_cmp expect output ' diff --git a/t/t3070-wildmatch.sh b/t/t3070-wildmatch.sh index 891d4d7cb9..56ea4bda13 100755 --- a/t/t3070-wildmatch.sh +++ b/t/t3070-wildmatch.sh @@ -4,6 +4,11 @@ test_description='wildmatch tests' . ./test-lib.sh +# Disable expensive chain-lint tests; all of the tests in this script +# are variants of a few trivial test-tool invocations, and there are a lot of +# them. +GIT_TEST_CHAIN_LINT_HARDER_DEFAULT=0 + should_create_test_file() { file=$1 diff --git a/t/t3905-stash-include-untracked.sh b/t/t3905-stash-include-untracked.sh index 5bed8fd2fd..dd2cdcc114 100755 --- a/t/t3905-stash-include-untracked.sh +++ b/t/t3905-stash-include-untracked.sh @@ -333,6 +333,8 @@ test_expect_success 'stash show --include-untracked shows untracked files' ' git stash show -p --include-untracked >actual && test_cmp expect actual && git stash show --include-untracked -p >actual && + test_cmp expect actual && + git -c stash.showIncludeUntracked=true stash show -p >actual && test_cmp expect actual ' diff --git a/t/t5551-http-fetch-smart.sh b/t/t5551-http-fetch-smart.sh index 984dba22af..4f87d90c5b 100755 --- a/t/t5551-http-fetch-smart.sh +++ b/t/t5551-http-fetch-smart.sh @@ -517,4 +517,45 @@ test_expect_success 'server-side error detected' ' test_i18ngrep "server-side error" actual ' +test_expect_success 'http auth remembers successful credentials' ' + rm -f .git-credentials && + test_config credential.helper store && + + # the first request prompts the user... + set_askpass user@host pass@host && + git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null && + expect_askpass both user@host && + + # ...and the second one uses the stored value rather than + # prompting the user. + set_askpass bogus-user bogus-pass && + git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null && + expect_askpass none +' + +test_expect_success 'http auth forgets bogus credentials' ' + # seed credential store with bogus values. In real life, + # this would probably come from a password which worked + # for a previous request. + rm -f .git-credentials && + test_config credential.helper store && + { + echo "url=$HTTPD_URL" && + echo "username=bogus" && + echo "password=bogus" + } | git credential approve && + + # we expect this to use the bogus values and fail, never even + # prompting the user... + set_askpass user@host pass@host && + test_must_fail git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null && + expect_askpass none && + + # ...but now we should have forgotten the bad value, causing + # us to prompt the user again. + set_askpass user@host pass@host && + git ls-remote "$HTTPD_URL/auth/smart/repo.git" >/dev/null && + expect_askpass both user@host +' + test_done diff --git a/t/t6302-for-each-ref-filter.sh b/t/t6302-for-each-ref-filter.sh index 9866b1b573..1537aa2179 100755 --- a/t/t6302-for-each-ref-filter.sh +++ b/t/t6302-for-each-ref-filter.sh @@ -117,6 +117,25 @@ test_expect_success '%(color) must fail' ' test_must_fail git for-each-ref --format="%(color)%(refname)" ' +test_expect_success '%(color:#aa22ac) must succeed' ' + test_when_finished rm -rf test && + git init test && + ( + cd test && + test_commit initial && + git branch -M main && + cat >expect <<-\EOF && + refs/heads/main + refs/tags/initial + EOF + git remote add origin nowhere && + git config branch.main.remote origin && + git config branch.main.merge refs/heads/main && + git for-each-ref --format="%(color:#aa22ac)%(refname)" >actual && + test_cmp expect actual + ) +' + test_expect_success 'left alignment is default' ' cat >expect <<-\EOF && refname is refs/heads/main |refs/heads/main diff --git a/t/t7063-status-untracked-cache.sh b/t/t7063-status-untracked-cache.sh index accefde72f..a0c123b0a7 100755 --- a/t/t7063-status-untracked-cache.sh +++ b/t/t7063-status-untracked-cache.sh @@ -57,6 +57,20 @@ iuc () { return $ret } +get_relevant_traces () { + # From the GIT_TRACE2_PERF data of the form + # $TIME $FILE:$LINE | d0 | main | data | r1 | ? | ? | read_directo | $RELEVANT_STAT + # extract the $RELEVANT_STAT fields. We don't care about region_enter + # or region_leave, or stats for things outside read_directory. + INPUT_FILE=$1 + OUTPUT_FILE=$2 + grep data.*read_directo $INPUT_FILE | + cut -d "|" -f 9 | + grep -v visited \ + >"$OUTPUT_FILE" +} + + test_lazy_prereq UNTRACKED_CACHE ' { git update-index --test-untracked-cache; ret=$?; } && test $ret -ne 1 @@ -129,19 +143,21 @@ EOF test_expect_success 'status first time (empty cache)' ' avoid_racy && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 3 -gitignore invalidation: 1 -directory invalidation: 0 -opendir: 4 + ....path: + ....node-creation:3 + ....gitignore-invalidation:1 + ....directory-invalidation:0 + ....opendir:4 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'untracked cache after first status' ' @@ -151,19 +167,21 @@ test_expect_success 'untracked cache after first status' ' test_expect_success 'status second time (fully populated cache)' ' avoid_racy && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 0 -opendir: 0 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:0 + ....opendir:0 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'untracked cache after second status' ' @@ -174,8 +192,8 @@ test_expect_success 'untracked cache after second status' ' test_expect_success 'modify in root directory, one dir invalidation' ' avoid_racy && : >four && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -189,13 +207,15 @@ A two EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 1 -opendir: 1 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:1 + ....opendir:1 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' @@ -223,8 +243,8 @@ EOF test_expect_success 'new .gitignore invalidates recursively' ' avoid_racy && echo four >.gitignore && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -238,13 +258,15 @@ A two EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 1 -directory invalidation: 1 -opendir: 4 + ....path: + ....node-creation:0 + ....gitignore-invalidation:1 + ....directory-invalidation:1 + ....opendir:4 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' @@ -272,8 +294,8 @@ EOF test_expect_success 'new info/exclude invalidates everything' ' avoid_racy && echo three >>.git/info/exclude && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -285,13 +307,15 @@ A two EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 1 -directory invalidation: 0 -opendir: 4 + ....path: + ....node-creation:0 + ....gitignore-invalidation:1 + ....directory-invalidation:0 + ....opendir:4 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'verify untracked cache dump' ' @@ -330,8 +354,8 @@ EOF ' test_expect_success 'status after the move' ' - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -343,13 +367,15 @@ A one EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 0 -opendir: 1 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:0 + ....opendir:1 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'verify untracked cache dump' ' @@ -389,8 +415,8 @@ EOF ' test_expect_success 'status after the move' ' - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -402,13 +428,15 @@ A two EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 0 -opendir: 1 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:0 + ....opendir:1 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'verify untracked cache dump' ' @@ -438,8 +466,8 @@ test_expect_success 'set up for sparse checkout testing' ' ' test_expect_success 'status after commit' ' - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -448,13 +476,15 @@ test_expect_success 'status after commit' ' EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 0 -opendir: 2 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:0 + ....opendir:2 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'untracked cache correct after commit' ' @@ -496,9 +526,9 @@ test_expect_success 'create/modify files, some of which are gitignored' ' ' test_expect_success 'test sparse status with untracked cache' ' - : >../trace && + : >../trace.output && avoid_racy && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../status.actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -509,13 +539,15 @@ test_expect_success 'test sparse status with untracked cache' ' EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../status.actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 1 -directory invalidation: 2 -opendir: 2 + ....path: + ....node-creation:0 + ....gitignore-invalidation:1 + ....directory-invalidation:2 + ....opendir:2 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'untracked cache correct after status' ' @@ -539,8 +571,8 @@ EOF test_expect_success 'test sparse status again with untracked cache' ' avoid_racy && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../status.actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -551,13 +583,15 @@ test_expect_success 'test sparse status again with untracked cache' ' EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../status.actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 0 -opendir: 0 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:0 + ....opendir:0 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'set up for test of subdir and sparse checkouts' ' @@ -568,8 +602,8 @@ test_expect_success 'set up for test of subdir and sparse checkouts' ' test_expect_success 'test sparse status with untracked cache and subdir' ' avoid_racy && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../status.actual && iuc status --porcelain >../status.iuc && cat >../status.expect <<EOF && @@ -581,13 +615,15 @@ test_expect_success 'test sparse status with untracked cache and subdir' ' EOF test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../status.actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 2 -gitignore invalidation: 0 -directory invalidation: 1 -opendir: 3 + ....path: + ....node-creation:2 + ....gitignore-invalidation:0 + ....directory-invalidation:1 + ....opendir:3 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'verify untracked cache dump (sparse/subdirs)' ' @@ -616,19 +652,21 @@ EOF test_expect_success 'test sparse status again with untracked cache and subdir' ' avoid_racy && - : >../trace && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace" \ + : >../trace.output && + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ git status --porcelain >../status.actual && iuc status --porcelain >../status.iuc && test_cmp ../status.expect ../status.iuc && test_cmp ../status.expect ../status.actual && + get_relevant_traces ../trace.output ../trace.relevant && cat >../trace.expect <<EOF && -node creation: 0 -gitignore invalidation: 0 -directory invalidation: 0 -opendir: 0 + ....path: + ....node-creation:0 + ....gitignore-invalidation:0 + ....directory-invalidation:0 + ....opendir:0 EOF - test_cmp ../trace.expect ../trace + test_cmp ../trace.expect ../trace.relevant ' test_expect_success 'move entry in subdir from untracked to cached' ' diff --git a/t/t7300-clean.sh b/t/t7300-clean.sh index a74816ca8b..0399701e62 100755 --- a/t/t7300-clean.sh +++ b/t/t7300-clean.sh @@ -746,4 +746,46 @@ test_expect_success 'clean untracked paths by pathspec' ' test_must_be_empty actual ' +test_expect_success 'avoid traversing into ignored directories' ' + test_when_finished rm -f output error trace.* && + test_create_repo avoid-traversing-deep-hierarchy && + ( + cd avoid-traversing-deep-hierarchy && + + mkdir -p untracked/subdir/with/a && + >untracked/subdir/with/a/random-file.txt && + + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace.output" \ + git clean -ffdxn -e untracked + ) && + + # Make sure we only visited into the top-level directory, and did + # not traverse into the "untracked" subdirectory since it was excluded + grep data.*read_directo.*directories-visited trace.output | + cut -d "|" -f 9 >trace.relevant && + cat >trace.expect <<-EOF && + ..directories-visited:1 + EOF + test_cmp trace.expect trace.relevant +' + +test_expect_success 'traverse into directories that may have ignored entries' ' + test_when_finished rm -f output && + test_create_repo need-to-traverse-into-hierarchy && + ( + cd need-to-traverse-into-hierarchy && + mkdir -p modules/foobar/src/generated && + > modules/foobar/src/generated/code.c && + > modules/foobar/Makefile && + echo "/modules/**/src/generated/" >.gitignore && + + git clean -fX modules/foobar >../output && + + grep Removing ../output && + + test_path_is_missing modules/foobar/src/generated/code.c && + test_path_is_file modules/foobar/Makefile + ) +' + test_done diff --git a/t/t7500-commit-template-squash-signoff.sh b/t/t7500-commit-template-squash-signoff.sh index 9092db5fdc..7d02f79c0d 100755 --- a/t/t7500-commit-template-squash-signoff.sh +++ b/t/t7500-commit-template-squash-signoff.sh @@ -413,7 +413,7 @@ test_expect_success 'amend! commit allows empty commit msg body with --allow-emp ' test_fixup_reword_opt () { - test_expect_success C_LOCALE_OUTPUT "--fixup=reword: incompatible with $1" " + test_expect_success "--fixup=reword: incompatible with $1" " echo 'fatal: reword option of --fixup is mutually exclusive with'\ '--patch/--interactive/--all/--include/--only' >expect && test_must_fail git commit --fixup=reword:HEAD~ $1 2>actual && diff --git a/t/t7519-status-fsmonitor.sh b/t/t7519-status-fsmonitor.sh index 45d025f960..637391c6ce 100755 --- a/t/t7519-status-fsmonitor.sh +++ b/t/t7519-status-fsmonitor.sh @@ -334,7 +334,7 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' git config core.fsmonitor .git/hooks/fsmonitor-test && git update-index --untracked-cache && git update-index --fsmonitor && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-before" \ + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-before" \ git status && test-tool dump-untracked-cache >../before ) && @@ -346,12 +346,12 @@ test_expect_success UNTRACKED_CACHE 'ignore .git changes when invalidating UNTR' EOF ( cd dot-git && - GIT_TRACE_UNTRACKED_STATS="$TRASH_DIRECTORY/trace-after" \ + GIT_TRACE2_PERF="$TRASH_DIRECTORY/trace-after" \ git status && test-tool dump-untracked-cache >../after ) && - grep "directory invalidation" trace-before >>before && - grep "directory invalidation" trace-after >>after && + grep "directory-invalidation" trace-before | cut -d"|" -f 9 >>before && + grep "directory-invalidation" trace-after | cut -d"|" -f 9 >>after && # UNTR extension unchanged, dir invalidation count unchanged test_cmp before after ' diff --git a/t/t9001-send-email.sh b/t/t9001-send-email.sh index 65b3035371..3b7540050c 100755 --- a/t/t9001-send-email.sh +++ b/t/t9001-send-email.sh @@ -539,7 +539,7 @@ test_expect_success $PREREQ "--validate respects relative core.hooksPath path" ' test_path_is_file my-hooks.ran && cat >expect <<-EOF && fatal: longline.patch: rejected by sendemail-validate hook - fatal: command '"'"'$(pwd)/my-hooks/sendemail-validate'"'"' died with exit code 1 + fatal: command '"'"'my-hooks/sendemail-validate'"'"' died with exit code 1 warning: no patches were sent EOF test_cmp expect actual @@ -644,14 +644,33 @@ test_expect_success $PREREQ 'In-Reply-To with --chain-reply-to' ' test_cmp expect actual ' +test_set_editor "$(pwd)/fake-editor" + +test_expect_success $PREREQ 'setup erroring fake editor' ' + write_script fake-editor <<-\EOF + echo >&2 "I am about to error" + exit 1 + EOF +' + +test_expect_success $PREREQ 'fake editor dies with error' ' + clean_fake_sendmail && + test_must_fail git send-email \ + --compose --subject foo \ + --from="Example <nobody@example.com>" \ + --to=nobody@example.com \ + --smtp-server="$(pwd)/fake.sendmail" \ + $patches 2>err && + grep "I am about to error" err && + grep "the editor exited uncleanly, aborting everything" err +' + test_expect_success $PREREQ 'setup fake editor' ' write_script fake-editor <<-\EOF echo fake edit >>"$1" EOF ' -test_set_editor "$(pwd)/fake-editor" - test_expect_success $PREREQ '--compose works' ' clean_fake_sendmail && git send-email \ diff --git a/t/test-lib.sh b/t/test-lib.sh index adaa2db601..adaf03543e 100644 --- a/t/test-lib.sh +++ b/t/test-lib.sh @@ -947,8 +947,11 @@ test_run_ () { trace= # 117 is magic because it is unlikely to match the exit # code of other programs - if $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!') || - test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" + if test "OK-117" != "$(test_eval_ "(exit 117) && $1${LF}${LF}echo OK-\$?" 3>&1)" || + { + test "${GIT_TEST_CHAIN_LINT_HARDER:-${GIT_TEST_CHAIN_LINT_HARDER_DEFAULT:-1}}" != 0 && + $(printf '%s\n' "$1" | sed -f "$GIT_BUILD_DIR/t/chainlint.sed" | grep -q '?![A-Z][A-Z]*?!') + } then BUG "broken &&-chain or run-away HERE-DOC: $1" fi diff --git a/worktree.c b/worktree.c index f35ac40a84..237517baee 100644 --- a/worktree.c +++ b/worktree.c @@ -128,10 +128,8 @@ struct worktree **get_worktrees(void) dir = opendir(path.buf); strbuf_release(&path); if (dir) { - while ((d = readdir(dir)) != NULL) { + while ((d = readdir_skip_dot_and_dotdot(dir)) != NULL) { struct worktree *linked = NULL; - if (is_dot_or_dotdot(d->d_name)) - continue; if ((linked = get_linked_worktree(d->d_name))) { ALLOC_GROW(list, counter + 1, alloc); @@ -486,13 +484,9 @@ int submodule_uses_worktrees(const char *path) if (!dir) return 0; - while ((d = readdir(dir)) != NULL) { - if (is_dot_or_dotdot(d->d_name)) - continue; - + d = readdir_skip_dot_and_dotdot(dir); + if (d != NULL) ret = 1; - break; - } closedir(dir); return ret; } diff --git a/write-or-die.c b/write-or-die.c index eab8c8d0b9..d33e68f6ab 100644 --- a/write-or-die.c +++ b/write-or-die.c @@ -57,8 +57,9 @@ void fprintf_or_die(FILE *f, const char *fmt, ...) void fsync_or_die(int fd, const char *msg) { - if (fsync(fd) < 0) { - die_errno("fsync error on '%s'", msg); + while (fsync(fd) < 0) { + if (errno != EINTR) + die_errno("fsync error on '%s'", msg); } } |