Merge branch 'ab/test-env'
authorJunio C Hamano <gitster@pobox.com>
Thu, 25 Jul 2019 20:59:20 +0000 (13:59 -0700)
committerJunio C Hamano <gitster@pobox.com>
Thu, 25 Jul 2019 20:59:20 +0000 (13:59 -0700)
Many GIT_TEST_* environment variables control various aspects of
how our tests are run, but a few followed "non-empty is true, empty
or unset is false" while others followed the usual "there are a few
ways to spell true, like yes, on, etc., and also ways to spell
false, like no, off, etc." convention.

* ab/test-env:
env--helper: mark a file-local symbol as static
tests: make GIT_TEST_FAIL_PREREQS a boolean
tests: replace test_tristate with "git env--helper"
tests README: re-flow a previously changed paragraph
tests: make GIT_TEST_GETTEXT_POISON a boolean
t6040 test: stop using global "script" variable
config.c: refactor die_bad_number() to not call gettext() early
env--helper: new undocumented builtin wrapping git_env_*()
config tests: simplify include cycle test

1  2 
.gitignore
Makefile
builtin.h
ci/lib.sh
config.c
gettext.c
git.c
t/t1305-config-include.sh
t/t6040-tracking-info.sh
t/test-lib-functions.sh
t/test-lib.sh
diff --combined .gitignore
index e096e0a51c19966eb743454fab50d232441008ca,1f7a83fb3c78c0f4f3ebe5394395f8d30eb1aa2a..069c190ba078a7fe4ac3b42db67c6d1221939249
@@@ -58,6 -58,7 +58,7 @@@
  /git-difftool
  /git-difftool--helper
  /git-describe
+ /git-env--helper
  /git-fast-export
  /git-fast-import
  /git-fetch
  /git-request-pull
  /git-rerere
  /git-reset
 +/git-restore
  /git-rev-list
  /git-rev-parse
  /git-revert
  /git-submodule
  /git-submodule--helper
  /git-svn
 +/git-switch
  /git-symbolic-ref
  /git-tag
  /git-unpack-file
  *.user
  *.idb
  *.pdb
 +*.ilk
 +*.iobj
 +*.ipdb
 +*.dll
 +.vs/
  /Debug/
  /Release/
  *.dSYM
diff --combined Makefile
index 11ccea40716d9bbcef731f093e530a9b1aee0013,f2cfc8d81291c374c13f898848d73fc4493ead24..b11cdd4fe79234b57211d236930b0798416b8e6c
+++ b/Makefile
@@@ -721,7 -721,6 +721,7 @@@ TEST_BUILTINS_OBJS += test-lazy-init-na
  TEST_BUILTINS_OBJS += test-match-trees.o
  TEST_BUILTINS_OBJS += test-mergesort.o
  TEST_BUILTINS_OBJS += test-mktemp.o
 +TEST_BUILTINS_OBJS += test-oidmap.o
  TEST_BUILTINS_OBJS += test-online-cpus.o
  TEST_BUILTINS_OBJS += test-parse-options.o
  TEST_BUILTINS_OBJS += test-path-utils.o
@@@ -772,11 -771,9 +772,11 @@@ BUILT_INS += git-format-patch$
  BUILT_INS += git-fsck-objects$X
  BUILT_INS += git-init$X
  BUILT_INS += git-merge-subtree$X
 +BUILT_INS += git-restore$X
  BUILT_INS += git-show$X
  BUILT_INS += git-stage$X
  BUILT_INS += git-status$X
 +BUILT_INS += git-switch$X
  BUILT_INS += git-whatchanged$X
  
  # what 'all' will build and 'install' will install in gitexecdir,
@@@ -1062,6 -1059,7 +1062,7 @@@ BUILTIN_OBJS += builtin/diff-index.
  BUILTIN_OBJS += builtin/diff-tree.o
  BUILTIN_OBJS += builtin/diff.o
  BUILTIN_OBJS += builtin/difftool.o
+ BUILTIN_OBJS += builtin/env--helper.o
  BUILTIN_OBJS += builtin/fast-export.o
  BUILTIN_OBJS += builtin/fetch-pack.o
  BUILTIN_OBJS += builtin/fetch.o
@@@ -1238,7 -1236,7 +1239,7 @@@ endi
  
  ifdef SANE_TOOL_PATH
  SANE_TOOL_PATH_SQ = $(subst ','\'',$(SANE_TOOL_PATH))
 -BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix $(SANE_TOOL_PATH_SQ)|'
 +BROKEN_PATH_FIX = 's|^\# @@BROKEN_PATH_FIX@@$$|git_broken_path_fix "$(SANE_TOOL_PATH_SQ)"|'
  PATH := $(SANE_TOOL_PATH):${PATH}
  else
  BROKEN_PATH_FIX = '/^\# @@BROKEN_PATH_FIX@@$$/d'
@@@ -2861,33 -2859,6 +2862,33 @@@ install: al
        $(INSTALL) $(ALL_PROGRAMS) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) -m 644 $(SCRIPT_LIB) '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
        $(INSTALL) $(install_bindir_programs) '$(DESTDIR_SQ)$(bindir_SQ)'
 +ifdef MSVC
 +      # We DO NOT install the individual foo.o.pdb files because they
 +      # have already been rolled up into the exe's pdb file.
 +      # We DO NOT have pdb files for the builtin commands (like git-status.exe)
 +      # because it is just a copy/hardlink of git.exe, rather than a unique binary.
 +      $(INSTALL) git.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) git-shell.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) git-upload-pack.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) git-credential-store.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-daemon.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-fast-import.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-http-backend.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-http-fetch.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-http-push.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-imap-send.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-remote-http.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-remote-testsvn.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-sh-i18n--envsubst.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +      $(INSTALL) git-show-index.pdb '$(DESTDIR_SQ)$(gitexec_instdir_SQ)'
 +ifndef DEBUG
 +      $(INSTALL) $(vcpkg_rel_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) $(vcpkg_rel_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
 +else
 +      $(INSTALL) $(vcpkg_dbg_bin)/*.dll '$(DESTDIR_SQ)$(bindir_SQ)'
 +      $(INSTALL) $(vcpkg_dbg_bin)/*.pdb '$(DESTDIR_SQ)$(bindir_SQ)'
 +endif
 +endif
        $(MAKE) -C templates DESTDIR='$(DESTDIR_SQ)' install
        $(INSTALL) -d -m 755 '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
        $(INSTALL) -m 644 mergetools/* '$(DESTDIR_SQ)$(mergetools_instdir_SQ)'
@@@ -3100,19 -3071,6 +3101,19 @@@ endi
        $(RM) GIT-VERSION-FILE GIT-CFLAGS GIT-LDFLAGS GIT-BUILD-OPTIONS
        $(RM) GIT-USER-AGENT GIT-PREFIX
        $(RM) GIT-SCRIPT-DEFINES GIT-PERL-DEFINES GIT-PERL-HEADER GIT-PYTHON-VARS
 +ifdef MSVC
 +      $(RM) $(patsubst %.o,%.o.pdb,$(OBJECTS))
 +      $(RM) $(patsubst %.exe,%.pdb,$(OTHER_PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.iobj,$(OTHER_PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.ipdb,$(OTHER_PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.pdb,$(PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.iobj,$(PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.ipdb,$(PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.pdb,$(TEST_PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.iobj,$(TEST_PROGRAMS))
 +      $(RM) $(patsubst %.exe,%.ipdb,$(TEST_PROGRAMS))
 +      $(RM) compat/vcbuild/MSVC-DEFS-GEN
 +endif
  
  .PHONY: all install profile-clean cocciclean clean strip
  .PHONY: shell_compatibility_test please_set_SHELL_PATH_to_a_more_modern_shell
diff --combined builtin.h
index 3d449a021002540f1183166c3cfb1dfce765b75b,93bd49fe4f85bbdefa6edf7edb70a54da2f73c0e..5cf5df69f72fd5a660f4dfc8981387f1bcc9c7cc
+++ b/builtin.h
@@@ -160,6 -160,7 +160,7 @@@ int cmd_diff_index(int argc, const cha
  int cmd_diff(int argc, const char **argv, const char *prefix);
  int cmd_diff_tree(int argc, const char **argv, const char *prefix);
  int cmd_difftool(int argc, const char **argv, const char *prefix);
+ int cmd_env__helper(int argc, const char **argv, const char *prefix);
  int cmd_fast_export(int argc, const char **argv, const char *prefix);
  int cmd_fetch(int argc, const char **argv, const char *prefix);
  int cmd_fetch_pack(int argc, const char **argv, const char *prefix);
@@@ -214,7 -215,6 +215,7 @@@ int cmd_remote_fd(int argc, const char 
  int cmd_repack(int argc, const char **argv, const char *prefix);
  int cmd_rerere(int argc, const char **argv, const char *prefix);
  int cmd_reset(int argc, const char **argv, const char *prefix);
 +int cmd_restore(int argc, const char **argv, const char *prefix);
  int cmd_rev_list(int argc, const char **argv, const char *prefix);
  int cmd_rev_parse(int argc, const char **argv, const char *prefix);
  int cmd_revert(int argc, const char **argv, const char *prefix);
@@@ -228,7 -228,6 +229,7 @@@ int cmd_status(int argc, const char **a
  int cmd_stash(int argc, const char **argv, const char *prefix);
  int cmd_stripspace(int argc, const char **argv, const char *prefix);
  int cmd_submodule__helper(int argc, const char **argv, const char *prefix);
 +int cmd_switch(int argc, const char **argv, const char *prefix);
  int cmd_symbolic_ref(int argc, const char **argv, const char *prefix);
  int cmd_tag(int argc, const char **argv, const char *prefix);
  int cmd_tar_tree(int argc, const char **argv, const char *prefix);
diff --combined ci/lib.sh
index 0c7171a17354fd6dba5017e443b3d1b936f73e34,fd799ae66311d62d2eb62b7fe5aaf23171312d15..44db2d5cbb2241c7bd3ffd69d15a73c1fd4357ae
+++ b/ci/lib.sh
@@@ -163,10 -163,8 +163,10 @@@ linux-clang|linux-gcc
        export GIT_TEST_HTTPD=YesPlease
  
        # The Linux build installs the defined dependency versions below.
 -      # The OS X build installs the latest available versions. Keep that
 -      # in mind when you encounter a broken OS X build!
 +      # The OS X build installs much more recent versions, whichever
 +      # were recorded in the Homebrew database upon creating the OS X
 +      # image.
 +      # Keep that in mind when you encounter a broken OS X build!
        export LINUX_P4_VERSION="16.2"
        export LINUX_GIT_LFS_VERSION="1.5.2"
  
@@@ -186,7 -184,7 +186,7 @@@ osx-clang|osx-gcc
        export GIT_SKIP_TESTS="t9810 t9816"
        ;;
  GIT_TEST_GETTEXT_POISON)
-       export GIT_TEST_GETTEXT_POISON=YesPlease
+       export GIT_TEST_GETTEXT_POISON=true
        ;;
  esac
  
diff --combined config.c
index faa57e436cf4fc6d84580f3940bafdb4896c7658,b985d60fa4f89506f29d4dfd29f0b8b956588058..ed7f58e0fcf221733165f3dd6a9d095d727a0a5e
+++ b/config.c
@@@ -19,7 -19,6 +19,7 @@@
  #include "utf8.h"
  #include "dir.h"
  #include "color.h"
 +#include "refs.h"
  
  struct config_source {
        struct config_source *prev;
@@@ -171,12 -170,6 +171,12 @@@ static int handle_path_include(const ch
        return ret;
  }
  
 +static void add_trailing_starstar_for_dir(struct strbuf *pat)
 +{
 +      if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
 +              strbuf_addstr(pat, "**");
 +}
 +
  static int prepare_include_condition_pattern(struct strbuf *pat)
  {
        struct strbuf path = STRBUF_INIT;
        } else if (!is_absolute_path(pat->buf))
                strbuf_insert(pat, 0, "**/", 3);
  
 -      if (pat->len && is_dir_sep(pat->buf[pat->len - 1]))
 -              strbuf_addstr(pat, "**");
 +      add_trailing_starstar_for_dir(pat);
  
        strbuf_release(&path);
        return prefix;
@@@ -270,25 -264,6 +270,25 @@@ done
        return ret;
  }
  
 +static int include_by_branch(const char *cond, size_t cond_len)
 +{
 +      int flags;
 +      int ret;
 +      struct strbuf pattern = STRBUF_INIT;
 +      const char *refname = resolve_ref_unsafe("HEAD", 0, NULL, &flags);
 +      const char *shortname;
 +
 +      if (!refname || !(flags & REF_ISSYMREF) ||
 +                      !skip_prefix(refname, "refs/heads/", &shortname))
 +              return 0;
 +
 +      strbuf_add(&pattern, cond, cond_len);
 +      add_trailing_starstar_for_dir(&pattern);
 +      ret = !wildmatch(pattern.buf, shortname, WM_PATHNAME);
 +      strbuf_release(&pattern);
 +      return ret;
 +}
 +
  static int include_condition_is_true(const struct config_options *opts,
                                     const char *cond, size_t cond_len)
  {
                return include_by_gitdir(opts, cond, cond_len, 0);
        else if (skip_prefix_mem(cond, cond_len, "gitdir/i:", &cond, &cond_len))
                return include_by_gitdir(opts, cond, cond_len, 1);
 +      else if (skip_prefix_mem(cond, cond_len, "onbranch:", &cond, &cond_len))
 +              return include_by_branch(cond, cond_len);
  
        /* unknown conditionals are always false */
        return 0;
@@@ -861,16 -834,22 +861,16 @@@ static int git_parse_source(config_fn_
        return error_return;
  }
  
 -static int parse_unit_factor(const char *end, uintmax_t *val)
 +static uintmax_t get_unit_factor(const char *end)
  {
        if (!*end)
                return 1;
 -      else if (!strcasecmp(end, "k")) {
 -              *val *= 1024;
 -              return 1;
 -      }
 -      else if (!strcasecmp(end, "m")) {
 -              *val *= 1024 * 1024;
 -              return 1;
 -      }
 -      else if (!strcasecmp(end, "g")) {
 -              *val *= 1024 * 1024 * 1024;
 -              return 1;
 -      }
 +      else if (!strcasecmp(end, "k"))
 +              return 1024;
 +      else if (!strcasecmp(end, "m"))
 +              return 1024 * 1024;
 +      else if (!strcasecmp(end, "g"))
 +              return 1024 * 1024 * 1024;
        return 0;
  }
  
@@@ -880,20 -859,19 +880,20 @@@ static int git_parse_signed(const char 
                char *end;
                intmax_t val;
                uintmax_t uval;
 -              uintmax_t factor = 1;
 +              uintmax_t factor;
  
                errno = 0;
                val = strtoimax(value, &end, 0);
                if (errno == ERANGE)
                        return 0;
 -              if (!parse_unit_factor(end, &factor)) {
 +              factor = get_unit_factor(end);
 +              if (!factor) {
                        errno = EINVAL;
                        return 0;
                }
 -              uval = labs(val);
 -              uval *= factor;
 -              if (uval > max || labs(val) > uval) {
 +              uval = val < 0 ? -val : val;
 +              if (unsigned_mult_overflows(factor, uval) ||
 +                  factor * uval > max) {
                        errno = ERANGE;
                        return 0;
                }
@@@ -910,23 -888,21 +910,23 @@@ static int git_parse_unsigned(const cha
        if (value && *value) {
                char *end;
                uintmax_t val;
 -              uintmax_t oldval;
 +              uintmax_t factor;
  
                errno = 0;
                val = strtoumax(value, &end, 0);
                if (errno == ERANGE)
                        return 0;
 -              oldval = val;
 -              if (!parse_unit_factor(end, &val)) {
 +              factor = get_unit_factor(end);
 +              if (!factor) {
                        errno = EINVAL;
                        return 0;
                }
 -              if (val > max || oldval > val) {
 +              if (unsigned_mult_overflows(factor, val) ||
 +                  factor * val > max) {
                        errno = ERANGE;
                        return 0;
                }
 +              val *= factor;
                *ret = val;
                return 1;
        }
@@@ -973,34 -949,44 +973,44 @@@ int git_parse_ssize_t(const char *value
  NORETURN
  static void die_bad_number(const char *name, const char *value)
  {
-       const char * error_type = (errno == ERANGE)? _("out of range"):_("invalid unit");
+       const char *error_type = (errno == ERANGE) ?
+               N_("out of range") : N_("invalid unit");
+       const char *bad_numeric = N_("bad numeric config value '%s' for '%s': %s");
  
        if (!value)
                value = "";
  
+       if (!strcmp(name, "GIT_TEST_GETTEXT_POISON"))
+               /*
+                * We explicitly *don't* use _() here since it would
+                * cause an infinite loop with _() needing to call
+                * use_gettext_poison(). This is why marked up
+                * translations with N_() above.
+                */
+               die(bad_numeric, value, name, error_type);
        if (!(cf && cf->name))
-               die(_("bad numeric config value '%s' for '%s': %s"),
-                   value, name, error_type);
+               die(_(bad_numeric), value, name, _(error_type));
  
        switch (cf->origin_type) {
        case CONFIG_ORIGIN_BLOB:
                die(_("bad numeric config value '%s' for '%s' in blob %s: %s"),
-                   value, name, cf->name, error_type);
+                   value, name, cf->name, _(error_type));
        case CONFIG_ORIGIN_FILE:
                die(_("bad numeric config value '%s' for '%s' in file %s: %s"),
-                   value, name, cf->name, error_type);
+                   value, name, cf->name, _(error_type));
        case CONFIG_ORIGIN_STDIN:
                die(_("bad numeric config value '%s' for '%s' in standard input: %s"),
-                   value, name, error_type);
+                   value, name, _(error_type));
        case CONFIG_ORIGIN_SUBMODULE_BLOB:
                die(_("bad numeric config value '%s' for '%s' in submodule-blob %s: %s"),
-                   value, name, cf->name, error_type);
+                   value, name, cf->name, _(error_type));
        case CONFIG_ORIGIN_CMDLINE:
                die(_("bad numeric config value '%s' for '%s' in command line %s: %s"),
-                   value, name, cf->name, error_type);
+                   value, name, cf->name, _(error_type));
        default:
                die(_("bad numeric config value '%s' for '%s' in %s: %s"),
-                   value, name, cf->name, error_type);
+                   value, name, cf->name, _(error_type));
        }
  }
  
diff --combined gettext.c
index 3f2aca5c3b16d39375fab9b6203c67ae16209023,5c71f4c8b93d0482941833c61567669e7ed8624f..35d2c1218db2e27a6ac07fbf3c1244987e3e3021
+++ b/gettext.c
  #ifndef NO_GETTEXT
  #     include <locale.h>
  #     include <libintl.h>
 -#     ifdef HAVE_LIBCHARSET_H
 +#     ifdef GIT_WINDOWS_NATIVE
 +
 +static const char *locale_charset(void)
 +{
 +      const char *env = getenv("LC_ALL"), *dot;
 +
 +      if (!env || !*env)
 +              env = getenv("LC_CTYPE");
 +      if (!env || !*env)
 +              env = getenv("LANG");
 +
 +      if (!env)
 +              return "UTF-8";
 +
 +      dot = strchr(env, '.');
 +      return !dot ? env : dot + 1;
 +}
 +
 +#     elif defined HAVE_LIBCHARSET_H
  #             include <libcharset.h>
  #     else
  #             include <langinfo.h>
@@@ -68,10 -50,8 +68,8 @@@ const char *get_preferred_languages(voi
  int use_gettext_poison(void)
  {
        static int poison_requested = -1;
-       if (poison_requested == -1) {
-               const char *v = getenv("GIT_TEST_GETTEXT_POISON");
-               poison_requested = v && strlen(v) ? 1 : 0;
-       }
+       if (poison_requested == -1)
+               poison_requested = git_env_bool("GIT_TEST_GETTEXT_POISON", 0);
        return poison_requested;
  }
  
diff --combined git.c
index f4c0478f320fba5e919238c0af19890cb9185242,a43e1dd98ea2170ba3b0d8b86e9130f05fe43080..a9604768578f608ea5268365d2006b57c1f73d86
--- 1/git.c
--- 2/git.c
+++ b/git.c
@@@ -500,6 -500,7 +500,7 @@@ static struct cmd_struct commands[] = 
        { "diff-index", cmd_diff_index, RUN_SETUP | NO_PARSEOPT },
        { "diff-tree", cmd_diff_tree, RUN_SETUP | NO_PARSEOPT },
        { "difftool", cmd_difftool, RUN_SETUP_GENTLY },
+       { "env--helper", cmd_env__helper },
        { "fast-export", cmd_fast_export, RUN_SETUP },
        { "fetch", cmd_fetch, RUN_SETUP },
        { "fetch-pack", cmd_fetch_pack, RUN_SETUP | NO_PARSEOPT },
        { "replace", cmd_replace, RUN_SETUP },
        { "rerere", cmd_rerere, RUN_SETUP },
        { "reset", cmd_reset, RUN_SETUP },
 +      { "restore", cmd_restore, RUN_SETUP | NEED_WORK_TREE },
        { "rev-list", cmd_rev_list, RUN_SETUP | NO_PARSEOPT },
        { "rev-parse", cmd_rev_parse, NO_PARSEOPT },
        { "revert", cmd_revert, RUN_SETUP | NEED_WORK_TREE },
        { "status", cmd_status, RUN_SETUP | NEED_WORK_TREE },
        { "stripspace", cmd_stripspace },
        { "submodule--helper", cmd_submodule__helper, RUN_SETUP | SUPPORT_SUPER_PREFIX | NO_PARSEOPT },
 +      { "switch", cmd_switch, RUN_SETUP | NEED_WORK_TREE },
        { "symbolic-ref", cmd_symbolic_ref, RUN_SETUP },
        { "tag", cmd_tag, RUN_SETUP | DELAY_PAGER_CONFIG },
        { "unpack-file", cmd_unpack_file, RUN_SETUP | NO_PARSEOPT },
index 9571e366f801ea347845eef9736c92197fbdba08,de294c990e19b4aec8b6f4bed1c34518adeda79f..d20b4d150d42c9fd6c14eb5f36e01a442d045cee
@@@ -309,60 -309,14 +309,53 @@@ test_expect_success SYMLINKS 'condition
        )
  '
  
 +test_expect_success 'conditional include, onbranch' '
 +      echo "[includeIf \"onbranch:foo-branch\"]path=bar9" >>.git/config &&
 +      echo "[test]nine=9" >.git/bar9 &&
 +      git checkout -b master &&
 +      test_must_fail git config test.nine &&
 +      git checkout -b foo-branch &&
 +      echo 9 >expect &&
 +      git config test.nine >actual &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success 'conditional include, onbranch, wildcard' '
 +      echo "[includeIf \"onbranch:?oo-*/**\"]path=bar10" >>.git/config &&
 +      echo "[test]ten=10" >.git/bar10 &&
 +      git checkout -b not-foo-branch/a &&
 +      test_must_fail git config test.ten &&
 +
 +      echo 10 >expect &&
 +      git checkout -b foo-branch/a/b/c &&
 +      git config test.ten >actual &&
 +      test_cmp expect actual &&
 +
 +      git checkout -b moo-bar/a &&
 +      git config test.ten >actual &&
 +      test_cmp expect actual
 +'
 +
 +test_expect_success 'conditional include, onbranch, implicit /** for /' '
 +      echo "[includeIf \"onbranch:foo-dir/\"]path=bar11" >>.git/config &&
 +      echo "[test]eleven=11" >.git/bar11 &&
 +      git checkout -b not-foo-dir/a &&
 +      test_must_fail git config test.eleven &&
 +
 +      echo 11 >expect &&
 +      git checkout -b foo-dir/a/b/c &&
 +      git config test.eleven >actual &&
 +      test_cmp expect actual
 +'
 +
  test_expect_success 'include cycles are detected' '
-       cat >.gitconfig <<-\EOF &&
-       [test]value = gitconfig
-       [include]path = cycle
-       EOF
-       cat >cycle <<-\EOF &&
-       [test]value = cycle
-       [include]path = .gitconfig
-       EOF
-       cat >expect <<-\EOF &&
-       gitconfig
-       cycle
-       EOF
-       test_must_fail git config --get-all test.value 2>stderr &&
-       test_i18ngrep "exceeded maximum include depth" stderr
+       git init --bare cycle &&
+       git -C cycle config include.path cycle &&
+       git config -f cycle/cycle include.path config &&
+       test_must_fail \
+               env GIT_TEST_GETTEXT_POISON=false \
+               git -C cycle config --get-all test.value 2>stderr &&
+       grep "exceeded maximum include depth" stderr
  '
  
  test_done
diff --combined t/t6040-tracking-info.sh
index febf63f28a54cd6a1e54e7322830e3ddfbfa9af3,970b25a289a00cefa57d25c48cf750b95fd4ed0d..ad1922b999b18d8437cc48c139a862ab5f59425d
@@@ -38,7 -38,7 +38,7 @@@ test_expect_success setup 
        advance h
  '
  
- script='s/^..\(b.\) *[0-9a-f]* \(.*\)$/\1 \2/p'
t6040_script='s/^..\(b.\) *[0-9a-f]* \(.*\)$/\1 \2/p'
  cat >expect <<\EOF
  b1 [ahead 1, behind 1] d
  b2 [ahead 1, behind 1] d
@@@ -53,7 -53,7 +53,7 @@@ test_expect_success 'branch -v' 
                cd test &&
                git branch -v
        ) |
-       sed -n -e "$script" >actual &&
+       sed -n -e "$t6040_script" >actual &&
        test_i18ncmp expect actual
  '
  
@@@ -71,7 -71,7 +71,7 @@@ test_expect_success 'branch -vv' 
                cd test &&
                git branch -vv
        ) |
-       sed -n -e "$script" >actual &&
+       sed -n -e "$t6040_script" >actual &&
        test_i18ncmp expect actual
  '
  
@@@ -159,19 -159,6 +159,19 @@@ test_expect_success 'status -s -b --no-
        test_i18ncmp expect actual
  '
  
 +cat >expect <<\EOF
 +## b1...origin/master [different]
 +EOF
 +
 +test_expect_success 'status.aheadbehind=false status -s -b (diverged from upstream)' '
 +      (
 +              cd test &&
 +              git checkout b1 >/dev/null &&
 +              git -c status.aheadbehind=false status -s -b | head -1
 +      ) >actual &&
 +      test_i18ncmp expect actual
 +'
 +
  cat >expect <<\EOF
  On branch b1
  Your branch and 'origin/master' have diverged,
@@@ -187,15 -174,6 +187,15 @@@ test_expect_success 'status --long --br
        test_i18ncmp expect actual
  '
  
 +test_expect_success 'status --long --branch' '
 +      (
 +              cd test &&
 +              git checkout b1 >/dev/null &&
 +              git -c status.aheadbehind=true status --long -b | head -3
 +      ) >actual &&
 +      test_i18ncmp expect actual
 +'
 +
  cat >expect <<\EOF
  On branch b1
  Your branch and 'origin/master' refer to different commits.
@@@ -208,15 -186,6 +208,15 @@@ test_expect_success 'status --long --br
                git status --long -b --no-ahead-behind | head -2
        ) >actual &&
        test_i18ncmp expect actual
 +'
 +
 +test_expect_success 'status.aheadbehind=false status --long --branch' '
 +      (
 +              cd test &&
 +              git checkout b1 >/dev/null &&
 +              git -c status.aheadbehind=false status --long -b | head -2
 +      ) >actual &&
 +      test_i18ncmp expect actual
  '
  
  cat >expect <<\EOF
diff --combined t/test-lib-functions.sh
index 7308f679229044030336922515a4e2870e6451d1,1cd0655f9653867c9bf11cfb488891b7bde5b4da..27b81276fc22569249bb5e83dcf4ba95e9823a57
@@@ -309,7 -309,7 +309,7 @@@ test_unset_prereq () 
  }
  
  test_set_prereq () {
-       if test -n "$GIT_TEST_FAIL_PREREQS"
+       if test -n "$GIT_TEST_FAIL_PREREQS_INTERNAL"
        then
                case "$1" in
                # The "!" case is handled below with
@@@ -908,21 -908,6 +908,21 @@@ test_cmp_rev () 
        fi
  }
  
 +# Compare paths respecting core.ignoreCase
 +test_cmp_fspath () {
 +      if test "x$1" = "x$2"
 +      then
 +              return 0
 +      fi
 +
 +      if test true != "$(git config --get --type=bool core.ignorecase)"
 +      then
 +              return 1
 +      fi
 +
 +      test "x$(echo "$1" | tr A-Z a-z)" =  "x$(echo "$2" | tr A-Z a-z)"
 +}
 +
  # Print a sequence of integers in increasing order, either with
  # two arguments (start and end):
  #
@@@ -1050,62 -1035,20 +1050,20 @@@ perl () 
        command "$PERL_PATH" "$@" 2>&7
  } 7>&2 2>&4
  
- # Is the value one of the various ways to spell a boolean true/false?
- test_normalize_bool () {
-       git -c magic.variable="$1" config --bool magic.variable 2>/dev/null
- }
- # Given a variable $1, normalize the value of it to one of "true",
- # "false", or "auto" and store the result to it.
- #
- #     test_tristate GIT_TEST_HTTPD
- #
- # A variable set to an empty string is set to 'false'.
- # A variable set to 'false' or 'auto' keeps its value.
- # Anything else is set to 'true'.
- # An unset variable defaults to 'auto'.
- #
- # The last rule is to allow people to set the variable to an empty
- # string and export it to decline testing the particular feature
- # for versions both before and after this change.  We used to treat
- # both unset and empty variable as a signal for "do not test" and
- # took any non-empty string as "please test".
- test_tristate () {
-       if eval "test x\"\${$1+isset}\" = xisset"
-       then
-               # explicitly set
-               eval "
-                       case \"\$$1\" in
-                       '')     $1=false ;;
-                       auto)   ;;
-                       *)      $1=\$(test_normalize_bool \$$1 || echo true) ;;
-                       esac
-               "
-       else
-               eval "$1=auto"
-       fi
- }
  # Exit the test suite, either by skipping all remaining tests or by
- # exiting with an error. If "$1" is "auto", we then we assume we were
- # opportunistically trying to set up some tests and we skip. If it is
- # "true", then we report a failure.
+ # exiting with an error. If our prerequisite variable $1 falls back
+ # on a default assume we were opportunistically trying to set up some
+ # tests and we skip. If it is explicitly "true", then we report a failure.
  #
  # The error/skip message should be given by $2.
  #
  test_skip_or_die () {
-       case "$1" in
-       auto)
+       if ! git env--helper --type=bool --default=false --exit-code $1
+       then
                skip_all=$2
                test_done
-               ;;
-       true)
-               error "$2"
-               ;;
-       *)
-               error "BUG: test tristate is '$1' (real error: $2)"
-       esac
+       fi
+       error "$2"
  }
  
  # The following mingw_* functions obey POSIX shell syntax, but are actually
diff --combined t/test-lib.sh
index d1ba33745a24c92411baca54604c853373b9bc39,1af4e50653c517a463b50e3f75e707f793e3312f..30b07e310f59493616f766ea6cf7c45a335c9258
@@@ -386,6 -386,7 +386,6 @@@ unset VISUAL EMAIL LANGUAGE COLUMNS $("
        my @env = keys %ENV;
        my $ok = join("|", qw(
                TRACE
 -              TR2_
                DEBUG
                TEST
                .*_TEST
@@@ -1388,6 -1389,25 +1388,25 @@@ yes () 
        done
  }
  
+ # The GIT_TEST_FAIL_PREREQS code hooks into test_set_prereq(), and
+ # thus needs to be set up really early, and set an internal variable
+ # for convenience so the hot test_set_prereq() codepath doesn't need
+ # to call "git env--helper". Only do that work if needed by seeing if
+ # GIT_TEST_FAIL_PREREQS is set at all.
+ GIT_TEST_FAIL_PREREQS_INTERNAL=
+ if test -n "$GIT_TEST_FAIL_PREREQS"
+ then
+       if git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS
+       then
+               GIT_TEST_FAIL_PREREQS_INTERNAL=true
+               test_set_prereq FAIL_PREREQS
+       fi
+ else
+       test_lazy_prereq FAIL_PREREQS '
+               git env--helper --type=bool --default=0 --exit-code GIT_TEST_FAIL_PREREQS
+       '
+ fi
  # Fix some commands on Windows
  uname_s=$(uname -s)
  case $uname_s in
@@@ -1442,11 -1462,9 +1461,9 @@@ the
        unset GIT_TEST_GETTEXT_POISON_ORIG
  fi
  
- # Can we rely on git's output in the C locale?
- if test -z "$GIT_TEST_GETTEXT_POISON"
- then
-       test_set_prereq C_LOCALE_OUTPUT
- fi
+ test_lazy_prereq C_LOCALE_OUTPUT '
+       ! git env--helper --type=bool --default=0 --exit-code GIT_TEST_GETTEXT_POISON
+ '
  
  if test -z "$GIT_TEST_CHECK_CACHE_TREE"
  then
@@@ -1606,7 -1624,3 +1623,3 @@@ test_lazy_prereq SHA1 
  test_lazy_prereq REBASE_P '
        test -z "$GIT_TEST_SKIP_REBASE_P"
  '
- test_lazy_prereq FAIL_PREREQS '
-       test -n "$GIT_TEST_FAIL_PREREQS"
- '