Merge branch 'jk/config-ignore-duplicates'
authorJunio C Hamano <gitster@pobox.com>
Wed, 21 Nov 2012 21:16:44 +0000 (13:16 -0800)
committerJunio C Hamano <gitster@pobox.com>
Wed, 21 Nov 2012 21:16:44 +0000 (13:16 -0800)
Drop duplicate detection from "git-config --get"; this lets it
better match the internal config callbacks, which clears up some
corner cases with includes.

* jk/config-ignore-duplicates:
builtin/config.c: Fix a sparse warning
git-config: use git_config_with_options
git-config: do not complain about duplicate entries
git-config: collect values instead of immediately printing
git-config: fix regexp memory leaks on error conditions
git-config: remove memory leak of key regexp
t1300: test "git config --get-all" more thoroughly
t1300: remove redundant test
t1300: style updates

1  2 
builtin/config.c
config.c
t/t1300-repo-config.sh
diff --combined builtin/config.c
index 505bbc7dddc2d080fcaa9acf93ed5c1379fbe75f,e796af4db6c533a936ecfc70d36e936a8fffa4bd..33c9bf9d84f514330f12de5cbd9dfb610a1b16de
@@@ -15,7 -15,6 +15,6 @@@ static int show_keys
  static int use_key_regexp;
  static int do_all;
  static int do_not_match;
- static int seen;
  static char delim = '=';
  static char key_delim = ' ';
  static char term = '\n';
@@@ -95,12 -94,19 +94,19 @@@ static int show_all_config(const char *
        return 0;
  }
  
- static int show_config(const char *key_, const char *value_, void *cb)
+ struct strbuf_list {
+       struct strbuf *items;
+       int nr;
+       int alloc;
+ };
+ static int collect_config(const char *key_, const char *value_, void *cb)
  {
+       struct strbuf_list *values = cb;
+       struct strbuf *buf;
        char value[256];
        const char *vptr = value;
        int must_free_vptr = 0;
-       int dup_error = 0;
        int must_print_delim = 0;
  
        if (!use_key_regexp && strcmp(key_, key))
            (do_not_match ^ !!regexec(regexp, (value_?value_:""), 0, NULL, 0)))
                return 0;
  
+       ALLOC_GROW(values->items, values->nr + 1, values->alloc);
+       buf = &values->items[values->nr++];
+       strbuf_init(buf, 0);
        if (show_keys) {
-               printf("%s", key_);
+               strbuf_addstr(buf, key_);
                must_print_delim = 1;
        }
-       if (seen && !do_all)
-               dup_error = 1;
        if (types == TYPE_INT)
                sprintf(value, "%d", git_config_int(key_, value_?value_:""));
        else if (types == TYPE_BOOL)
                else
                        sprintf(value, "%d", v);
        } else if (types == TYPE_PATH) {
 -              git_config_pathname(&vptr, key_, value_);
 +              if (git_config_pathname(&vptr, key_, value_) < 0)
 +                      return -1;
                must_free_vptr = 1;
        } else if (value_) {
                vptr = value_;
                vptr = "";
                must_print_delim = 0;
        }
-       seen++;
-       if (dup_error) {
-               error("More than one value for the key %s: %s",
-                               key_, vptr);
-       }
-       else {
-               if (must_print_delim)
-                       printf("%c", key_delim);
-               printf("%s%c", vptr, term);
-       }
+       if (must_print_delim)
+               strbuf_addch(buf, key_delim);
+       strbuf_addstr(buf, vptr);
+       strbuf_addch(buf, term);
        if (must_free_vptr)
                /* If vptr must be freed, it's a pointer to a
                 * dynamically allocated buffer, it's safe to cast to
  static int get_value(const char *key_, const char *regex_)
  {
        int ret = CONFIG_GENERIC_ERROR;
-       char *global = NULL, *xdg = NULL, *repo_config = NULL;
-       const char *system_wide = NULL, *local;
-       struct config_include_data inc = CONFIG_INCLUDE_INIT;
-       config_fn_t fn;
-       void *data;
-       local = given_config_file;
-       if (!local) {
-               local = repo_config = git_pathdup("config");
-               if (git_config_system())
-                       system_wide = git_etc_gitconfig();
-               home_config_paths(&global, &xdg, "config");
-       }
+       struct strbuf_list values = {NULL};
+       int i;
  
        if (use_key_regexp) {
                char *tl;
                key_regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(key_regexp, key, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid key pattern: %s\n", key_);
-                       free(key);
+                       free(key_regexp);
+                       key_regexp = NULL;
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
                regexp = (regex_t*)xmalloc(sizeof(regex_t));
                if (regcomp(regexp, regex_, REG_EXTENDED)) {
                        fprintf(stderr, "Invalid pattern: %s\n", regex_);
+                       free(regexp);
+                       regexp = NULL;
                        ret = CONFIG_INVALID_PATTERN;
                        goto free_strings;
                }
        }
  
-       fn = show_config;
-       data = NULL;
-       if (respect_includes) {
-               inc.fn = fn;
-               inc.data = data;
-               fn = git_config_include;
-               data = &inc;
-       }
+       git_config_with_options(collect_config, &values,
+                               given_config_file, respect_includes);
+       ret = !values.nr;
  
-       if (do_all && system_wide)
-               git_config_from_file(fn, system_wide, data);
-       if (do_all && xdg)
-               git_config_from_file(fn, xdg, data);
-       if (do_all && global)
-               git_config_from_file(fn, global, data);
-       if (do_all)
-               git_config_from_file(fn, local, data);
-       git_config_from_parameters(fn, data);
-       if (!do_all && !seen)
-               git_config_from_file(fn, local, data);
-       if (!do_all && !seen && global)
-               git_config_from_file(fn, global, data);
-       if (!do_all && !seen && xdg)
-               git_config_from_file(fn, xdg, data);
-       if (!do_all && !seen && system_wide)
-               git_config_from_file(fn, system_wide, data);
+       for (i = 0; i < values.nr; i++) {
+               struct strbuf *buf = values.items + i;
+               if (do_all || i == values.nr - 1)
+                       fwrite(buf->buf, 1, buf->len, stdout);
+               strbuf_release(buf);
+       }
+       free(values.items);
  
+ free_strings:
        free(key);
+       if (key_regexp) {
+               regfree(key_regexp);
+               free(key_regexp);
+       }
        if (regexp) {
                regfree(regexp);
                free(regexp);
        }
  
-       if (do_all)
-               ret = !seen;
-       else
-               ret = (seen == 1) ? 0 : seen > 1 ? 2 : 1;
- free_strings:
-       free(repo_config);
-       free(global);
-       free(xdg);
        return ret;
  }
  
diff --combined config.c
index fff8a43bc0378d7d7ee6d7ab3deee228c87b1d5c,2fbe634b173d9787f2bbeba0e4bc6bf4e89701a5..fb3f8681eed21ee81cfe36296c438ed135b98485
+++ b/config.c
@@@ -10,6 -10,8 +10,6 @@@
  #include "strbuf.h"
  #include "quote.h"
  
 -#define MAXNAME (256)
 -
  typedef struct config_file {
        struct config_file *prev;
        FILE *f;
@@@ -17,7 -19,7 +17,7 @@@
        int linenr;
        int eof;
        struct strbuf value;
 -      char var[MAXNAME];
 +      struct strbuf var;
  } config_file;
  
  static config_file *cf;
@@@ -258,7 -260,7 +258,7 @@@ static inline int iskeychar(int c
        return isalnum(c) || c == '-';
  }
  
 -static int get_value(config_fn_t fn, void *data, char *name, unsigned int len)
 +static int get_value(config_fn_t fn, void *data, struct strbuf *name)
  {
        int c;
        char *value;
                        break;
                if (!iskeychar(c))
                        break;
 -              name[len++] = tolower(c);
 -              if (len >= MAXNAME)
 -                      return -1;
 +              strbuf_addch(name, tolower(c));
        }
 -      name[len] = 0;
 +
        while (c == ' ' || c == '\t')
                c = get_next_char();
  
                if (!value)
                        return -1;
        }
 -      return fn(name, value, data);
 +      return fn(name->buf, value, data);
  }
  
 -static int get_extended_base_var(char *name, int baselen, int c)
 +static int get_extended_base_var(struct strbuf *name, int c)
  {
        do {
                if (c == '\n')
        /* We require the format to be '[base "extension"]' */
        if (c != '"')
                return -1;
 -      name[baselen++] = '.';
 +      strbuf_addch(name, '.');
  
        for (;;) {
                int c = get_next_char();
                        if (c == '\n')
                                goto error_incomplete_line;
                }
 -              name[baselen++] = c;
 -              if (baselen > MAXNAME / 2)
 -                      return -1;
 +              strbuf_addch(name, c);
        }
  
        /* Final ']' */
        if (get_next_char() != ']')
                return -1;
 -      return baselen;
 +      return 0;
  error_incomplete_line:
        cf->linenr--;
        return -1;
  }
  
 -static int get_base_var(char *name)
 +static int get_base_var(struct strbuf *name)
  {
 -      int baselen = 0;
 -
        for (;;) {
                int c = get_next_char();
                if (cf->eof)
                        return -1;
                if (c == ']')
 -                      return baselen;
 +                      return 0;
                if (isspace(c))
 -                      return get_extended_base_var(name, baselen, c);
 +                      return get_extended_base_var(name, c);
                if (!iskeychar(c) && c != '.')
                        return -1;
 -              if (baselen > MAXNAME / 2)
 -                      return -1;
 -              name[baselen++] = tolower(c);
 +              strbuf_addch(name, tolower(c));
        }
  }
  
@@@ -343,7 -353,7 +343,7 @@@ static int git_parse_file(config_fn_t f
  {
        int comment = 0;
        int baselen = 0;
 -      char *var = cf->var;
 +      struct strbuf *var = &cf->var;
  
        /* U+FEFF Byte Order Mark in UTF8 */
        static const unsigned char *utf8_bom = (unsigned char *) "\xef\xbb\xbf";
                        continue;
                }
                if (c == '[') {
 -                      baselen = get_base_var(var);
 -                      if (baselen <= 0)
 +                      /* Reset prior to determining a new stem */
 +                      strbuf_reset(var);
 +                      if (get_base_var(var) < 0 || var->len < 1)
                                break;
 -                      var[baselen++] = '.';
 -                      var[baselen] = 0;
 +                      strbuf_addch(var, '.');
 +                      baselen = var->len;
                        continue;
                }
                if (!isalpha(c))
                        break;
 -              var[baselen] = tolower(c);
 -              if (get_value(fn, data, var, baselen+1) < 0)
 +              /*
 +               * Truncate the var name back to the section header
 +               * stem prior to grabbing the suffix part of the name
 +               * and the value.
 +               */
 +              strbuf_setlen(var, baselen);
 +              strbuf_addch(var, tolower(c));
 +              if (get_value(fn, data, var) < 0)
                        break;
        }
        die("bad config file line %d in %s", cf->linenr, cf->name);
@@@ -896,14 -899,12 +896,14 @@@ int git_config_from_file(config_fn_t fn
                top.linenr = 1;
                top.eof = 0;
                strbuf_init(&top.value, 1024);
 +              strbuf_init(&top.var, 1024);
                cf = &top;
  
                ret = git_parse_file(fn, data);
  
                /* pop config-file parsing state stack */
                strbuf_release(&top.value);
 +              strbuf_release(&top.var);
                cf = top.prev;
  
                fclose(f);
@@@ -1279,6 -1280,7 +1279,7 @@@ int git_config_parse_key(const char *ke
  
  out_free_ret_1:
        free(*store_key);
+       *store_key = NULL;
        return -CONFIG_INVALID_KEY;
  }
  
diff --combined t/t1300-repo-config.sh
index 7c4c372e374b66844b83ac9343c6c71b362380e2,97a25f14845ec598b79211d1fbc2970781f3fcfb..3c96fda548709835e10f283df8cab667c280af81
@@@ -55,11 -55,13 +55,13 @@@ test_expect_success 'uppercase section
        test_cmp expect .git/config
  '
  
- test_expect_success 'replace with non-match' \
-       'git config core.penguin kingpin !blue'
+ test_expect_success 'replace with non-match' '
+       git config core.penguin kingpin !blue
+ '
  
- test_expect_success 'replace with non-match (actually matching)' \
-       'git config core.penguin "very blue" !kingpin'
+ test_expect_success 'replace with non-match (actually matching)' '
+       git config core.penguin "very blue" !kingpin
+ '
  
  cat > expect << EOF
  [core]
@@@ -108,8 -110,9 +110,9 @@@ baz = multiple 
  lines
  EOF
  
- test_expect_success 'unset with cont. lines' \
-       'git config --unset beta.baz'
+ test_expect_success 'unset with cont. lines' '
+       git config --unset beta.baz
+ '
  
  cat > expect <<\EOF
  [alpha]
@@@ -133,8 -136,9 +136,9 @@@ EO
  
  cp .git/config .git/config2
  
- test_expect_success 'multiple unset' \
-       'git config --unset-all beta.haha'
+ test_expect_success 'multiple unset' '
+       git config --unset-all beta.haha
+ '
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -145,7 -149,9 +149,9 @@@ noIndent= sillyValue ; 'nother silly co
  [nextSection] noNewline = ouch
  EOF
  
- test_expect_success 'multiple unset is correct' 'test_cmp expect .git/config'
+ test_expect_success 'multiple unset is correct' '
+       test_cmp expect .git/config
+ '
  
  cp .git/config2 .git/config
  
@@@ -156,8 -162,9 +162,9 @@@ test_expect_success '--replace-all miss
  
  rm .git/config2
  
- test_expect_success '--replace-all' \
-       'git config --replace-all beta.haha gamma'
+ test_expect_success '--replace-all' '
+       git config --replace-all beta.haha gamma
+ '
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -169,7 -176,9 +176,9 @@@ noIndent= sillyValue ; 'nother silly co
  [nextSection] noNewline = ouch
  EOF
  
- test_expect_success 'all replaced' 'test_cmp expect .git/config'
+ test_expect_success 'all replaced' '
+       test_cmp expect .git/config
+ '
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -200,7 -209,11 +209,11 @@@ test_expect_success 'really really mea
        test_cmp expect .git/config
  '
  
- test_expect_success 'get value' 'test alpha = $(git config beta.haha)'
+ test_expect_success 'get value' '
+       echo alpha >expect &&
+       git config beta.haha >actual &&
+       test_cmp expect actual
+ '
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -231,18 -244,30 +244,30 @@@ test_expect_success 'multivar' 
        test_cmp expect .git/config
  '
  
- test_expect_success 'non-match' \
-       'git config --get nextsection.nonewline !for'
+ test_expect_success 'non-match' '
+       git config --get nextsection.nonewline !for
+ '
  
- test_expect_success 'non-match value' \
-       'test wow = $(git config --get nextsection.nonewline !for)'
+ test_expect_success 'non-match value' '
+       echo wow >expect &&
+       git config --get nextsection.nonewline !for >actual &&
+       test_cmp expect actual
+ '
  
- test_expect_success 'ambiguous get' '
-       test_must_fail git config --get nextsection.nonewline
+ test_expect_success 'multi-valued get returns final one' '
+       echo "wow2 for me" >expect &&
+       git config --get nextsection.nonewline >actual &&
+       test_cmp expect actual
  '
  
- test_expect_success 'get multivar' \
-       'git config --get-all nextsection.nonewline'
+ test_expect_success 'multi-valued get-all returns all' '
+       cat >expect <<-\EOF &&
+       wow
+       wow2 for me
+       EOF
+       git config --get-all nextsection.nonewline >actual &&
+       test_cmp expect actual
+ '
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -259,10 -284,6 +284,6 @@@ test_expect_success 'multivar replace' 
        test_cmp expect .git/config
  '
  
- test_expect_success 'ambiguous value' '
-       test_must_fail git config nextsection.nonewline
- '
  test_expect_success 'ambiguous unset' '
        test_must_fail git config --unset nextsection.nonewline
  '
@@@ -290,8 -311,9 +311,9 @@@ test_expect_success 'invalid key' 'test
  
  test_expect_success 'correct key' 'git config 123456.a123 987'
  
- test_expect_success 'hierarchical section' \
-       'git config Version.1.2.3eX.Alpha beta'
+ test_expect_success 'hierarchical section' '
+       git config Version.1.2.3eX.Alpha beta
+ '
  
  cat > expect << EOF
  [beta] ; silly comment # another comment
@@@ -307,7 -329,9 +329,9 @@@ noIndent= sillyValue ; 'nother silly co
        Alpha = beta
  EOF
  
- test_expect_success 'hierarchical section value' 'test_cmp expect .git/config'
+ test_expect_success 'hierarchical section value' '
+       test_cmp expect .git/config
+ '
  
  cat > expect << EOF
  beta.noindent=sillyValue
@@@ -316,9 -340,10 +340,10 @@@ nextsection.nonewline=wow2 for m
  version.1.2.3eX.alpha=beta
  EOF
  
- test_expect_success 'working --list' \
-       'git config --list > output && cmp output expect'
+ test_expect_success 'working --list' '
+       git config --list > output &&
+       test_cmp expect output
+ '
  cat > expect << EOF
  EOF
  
@@@ -332,8 -357,10 +357,10 @@@ beta.noindent sillyValu
  nextsection.nonewline wow2 for me
  EOF
  
- test_expect_success '--get-regexp' \
-       'git config --get-regexp in > output && cmp output expect'
+ test_expect_success '--get-regexp' '
+       git config --get-regexp in >output &&
+       test_cmp expect output
+ '
  
  cat > expect << EOF
  wow2 for me
@@@ -353,41 -380,48 +380,48 @@@ cat > .git/config << EO
        variable =
  EOF
  
- test_expect_success 'get variable with no value' \
-       'git config --get novalue.variable ^$'
+ test_expect_success 'get variable with no value' '
+       git config --get novalue.variable ^$
+ '
  
- test_expect_success 'get variable with empty value' \
-       'git config --get emptyvalue.variable ^$'
+ test_expect_success 'get variable with empty value' '
+       git config --get emptyvalue.variable ^$
+ '
  
  echo novalue.variable > expect
  
- test_expect_success 'get-regexp variable with no value' \
-       'git config --get-regexp novalue > output &&
-        cmp output expect'
+ test_expect_success 'get-regexp variable with no value' '
+       git config --get-regexp novalue > output &&
+       test_cmp expect output
+ '
  
  echo 'novalue.variable true' > expect
  
- test_expect_success 'get-regexp --bool variable with no value' \
-       'git config --bool --get-regexp novalue > output &&
-        cmp output expect'
+ test_expect_success 'get-regexp --bool variable with no value' '
+       git config --bool --get-regexp novalue > output &&
+       test_cmp expect output
+ '
  
  echo 'emptyvalue.variable ' > expect
  
- test_expect_success 'get-regexp variable with empty value' \
-       'git config --get-regexp emptyvalue > output &&
-        cmp output expect'
+ test_expect_success 'get-regexp variable with empty value' '
+       git config --get-regexp emptyvalue > output &&
+       test_cmp expect output
+ '
  
  echo true > expect
  
- test_expect_success 'get bool variable with no value' \
-       'git config --bool novalue.variable > output &&
-        cmp output expect'
+ test_expect_success 'get bool variable with no value' '
+       git config --bool novalue.variable > output &&
+       test_cmp expect output
+ '
  
  echo false > expect
  
- test_expect_success 'get bool variable with empty value' \
-       'git config --bool emptyvalue.variable > output &&
-        cmp output expect'
+ test_expect_success 'get bool variable with empty value' '
+       git config --bool emptyvalue.variable > output &&
+       test_cmp expect output
+ '
  
  test_expect_success 'no arguments, but no crash' '
        test_must_fail git config >output 2>&1 &&
@@@ -427,8 -461,9 +461,9 @@@ test_expect_success 'new variable inser
        test_cmp expect .git/config
  '
  
- test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' \
-       'test_must_fail git config --file non-existing-config -l'
+ test_expect_success 'alternative GIT_CONFIG (non-existing file should fail)' '
+       test_must_fail git config --file non-existing-config -l
+ '
  
  cat > other-config << EOF
  [ein]
@@@ -444,8 -479,10 +479,10 @@@ test_expect_success 'alternative GIT_CO
        test_cmp expect output
  '
  
- test_expect_success 'alternative GIT_CONFIG (--file)' \
-       'git config --file other-config -l > output && cmp output expect'
+ test_expect_success 'alternative GIT_CONFIG (--file)' '
+       git config --file other-config -l > output &&
+       test_cmp expect output
+ '
  
  test_expect_success 'refer config from subdirectory' '
        mkdir x &&
@@@ -489,8 -526,9 +526,9 @@@ cat > .git/config << EO
  weird
  EOF
  
- test_expect_success "rename section" \
-       "git config --rename-section branch.eins branch.zwei"
+ test_expect_success 'rename section' '
+       git config --rename-section branch.eins branch.zwei
+ '
  
  cat > expect << EOF
  # Hallo
  weird
  EOF
  
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+ '
  
- test_expect_success "rename non-existing section" '
+ test_expect_success 'rename non-existing section' '
        test_must_fail git config --rename-section \
                branch."world domination" branch.drei
  '
  
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+ '
  
- test_expect_success "rename another section" \
-       'git config --rename-section branch."1 234 blabl/a" branch.drei'
+ test_expect_success 'rename another section' '
+       git config --rename-section branch."1 234 blabl/a" branch.drei
+ '
  
  cat > expect << EOF
  # Hallo
  weird
  EOF
  
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+ '
  
  cat >> .git/config << EOF
  [branch "vier"] z = 1
  EOF
  
- test_expect_success "rename a section with a var on the same line" \
-       'git config --rename-section branch.vier branch.zwei'
+ test_expect_success 'rename a section with a var on the same line' '
+       git config --rename-section branch.vier branch.zwei
+ '
  
  cat > expect << EOF
  # Hallo
@@@ -548,7 -594,9 +594,9 @@@ weir
        z = 1
  EOF
  
- test_expect_success "rename succeeded" "test_cmp expect .git/config"
+ test_expect_success 'rename succeeded' '
+       test_cmp expect .git/config
+ '
  
  test_expect_success 'renaming empty section name is rejected' '
        test_must_fail git config --rename-section branch.zwei ""
@@@ -562,7 -610,9 +610,9 @@@ cat >> .git/config << EO
    [branch "zwei"] a = 1 [branch "vier"]
  EOF
  
- test_expect_success "remove section" "git config --remove-section branch.zwei"
+ test_expect_success 'remove section' '
+       git config --remove-section branch.zwei
+ '
  
  cat > expect << EOF
  # Hallo
  weird
  EOF
  
- test_expect_success "section was removed properly" \
-       "test_cmp expect .git/config"
+ test_expect_success 'section was removed properly' '
+       test_cmp expect .git/config
+ '
  
  cat > expect << EOF
  [gitcvs]
  EOF
  
  test_expect_success 'section ending' '
        rm -f .git/config &&
        git config gitcvs.enabled true &&
        git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
  '
  
  test_expect_success numbers '
        git config kilo.gram 1k &&
        git config mega.ton 1m &&
-       k=$(git config --int --get kilo.gram) &&
-       test z1024 = "z$k" &&
-       m=$(git config --int --get mega.ton) &&
-       test z1048576 = "z$m"
+       echo 1024 >expect &&
+       echo 1048576 >>expect &&
+       git config --int --get kilo.gram >actual &&
+       git config --int --get mega.ton >>actual &&
+       test_cmp expect actual
  '
  
- cat > expect <<EOF
- fatal: bad config value for 'aninvalid.unit' in .git/config
- EOF
  test_expect_success 'invalid unit' '
        git config aninvalid.unit "1auto" &&
-       s=$(git config aninvalid.unit) &&
-       test "z1auto" = "z$s" &&
-       if git config --int --get aninvalid.unit 2>actual
-       then
-               echo config should have failed
-               false
-       fi &&
-       cmp actual expect
+       echo 1auto >expect &&
+       git config aninvalid.unit >actual &&
+       test_cmp expect actual &&
+       cat > expect <<-\EOF
+       fatal: bad config value for '\''aninvalid.unit'\'' in .git/config
+       EOF
+       test_must_fail git config --int --get aninvalid.unit 2>actual &&
+       test_cmp actual expect
  '
  
  cat > expect << EOF
@@@ -646,7 -691,7 +691,7 @@@ test_expect_success bool 
            git config --bool --get bool.true$i >>result
            git config --bool --get bool.false$i >>result
          done &&
-       cmp expect result'
+       test_cmp expect result'
  
  test_expect_success 'invalid bool (--get)' '
  
@@@ -680,7 -725,7 +725,7 @@@ test_expect_success 'set --bool' 
        git config --bool bool.false2 "" &&
        git config --bool bool.false3 nO &&
        git config --bool bool.false4 FALSE &&
-       cmp expect .git/config'
+       test_cmp expect .git/config'
  
  cat > expect <<\EOF
  [int]
@@@ -695,39 -740,37 +740,37 @@@ test_expect_success 'set --int' 
        git config --int int.val1 01 &&
        git config --int int.val2 -1 &&
        git config --int int.val3 5m &&
-       cmp expect .git/config'
+       test_cmp expect .git/config
+ '
  
- cat >expect <<\EOF
- [bool]
-       true1 = true
+ test_expect_success 'get --bool-or-int' '
+       cat >.git/config <<-\EOF &&
+       [bool]
+       true1
        true2 = true
-       false1 = false
-       false2 = false
- [int]
+       false = false
+       [int]
        int1 = 0
        int2 = 1
        int3 = -1
- EOF
- test_expect_success 'get --bool-or-int' '
-       rm -f .git/config &&
-       (
-               echo "[bool]"
-               echo true1
-               echo true2 = true
-               echo false = false
-               echo "[int]"
-               echo int1 = 0
-               echo int2 = 1
-               echo int3 = -1
-       ) >>.git/config &&
-       test $(git config --bool-or-int bool.true1) = true &&
-       test $(git config --bool-or-int bool.true2) = true &&
-       test $(git config --bool-or-int bool.false) = false &&
-       test $(git config --bool-or-int int.int1) = 0 &&
-       test $(git config --bool-or-int int.int2) = 1 &&
-       test $(git config --bool-or-int int.int3) = -1
+       EOF
+       cat >expect <<-\EOF &&
+       true
+       true
+       false
+       0
+       1
+       -1
+       EOF
+       {
+               git config --bool-or-int bool.true1 &&
+               git config --bool-or-int bool.true2 &&
+               git config --bool-or-int bool.false &&
+               git config --bool-or-int int.int1 &&
+               git config --bool-or-int int.int2 &&
+               git config --bool-or-int int.int3
+       } >actual &&
+       test_cmp expect actual
  '
  
  cat >expect <<\EOF
@@@ -803,11 -846,6 +846,11 @@@ test_expect_success NOT_MINGW 'get --pa
        test_cmp expect result
  '
  
 +test_expect_success 'get --path barfs on boolean variable' '
 +      echo "[path]bool" >.git/config &&
 +      test_must_fail git config --get --path path.bool
 +'
 +
  cat > expect << EOF
  [quote]
        leading = " test"
@@@ -849,7 -887,7 +892,7 @@@ EO
  
  test_expect_success 'value continued on next line' '
        git config --list > result &&
-       cmp result expect
+       test_cmp result expect
  '
  
  cat > .git/config <<\EOF
@@@ -885,11 -923,12 +928,12 @@@ test_expect_success '--null --get-regex
  
  test_expect_success 'inner whitespace kept verbatim' '
        git config section.val "foo       bar" &&
-       test "z$(git config section.val)" = "zfoo         bar"
+       echo "foo         bar" >expect &&
+       git config section.val >actual &&
+       test_cmp expect actual
  '
  
  test_expect_success SYMLINKS 'symlinked configuration' '
        ln -s notyet myconfig &&
        GIT_CONFIG=myconfig git config test.frotz nitfol &&
        test -h myconfig &&
        GIT_CONFIG=myconfig git config test.xyzzy rezrov &&
        test -h myconfig &&
        test -f notyet &&
-       test "z$(GIT_CONFIG=notyet git config test.frotz)" = znitfol &&
-       test "z$(GIT_CONFIG=notyet git config test.xyzzy)" = zrezrov
+       cat >expect <<-\EOF &&
+       nitfol
+       rezrov
+       EOF
+       {
+               GIT_CONFIG=notyet git config test.frotz &&
+               GIT_CONFIG=notyet git config test.xyzzy
+       } >actual &&
+       test_cmp expect actual
  '
  
  test_expect_success 'nonexistent configuration' '
@@@ -932,12 -977,20 +982,20 @@@ test_expect_success 'check split_cmdlin
        git commit -m 'initial commit' &&
        git config branch.master.mergeoptions 'echo \"' &&
        test_must_fail git merge master
      "
+ "
  
  test_expect_success 'git -c "key=value" support' '
-       test "z$(git -c core.name=value config core.name)" = zvalue &&
-       test "z$(git -c foo.CamelCase=value config foo.camelcase)" = zvalue &&
-       test "z$(git -c foo.flag config --bool foo.flag)" = ztrue &&
+       cat >expect <<-\EOF &&
+       value
+       value
+       true
+       EOF
+       {
+               git -c core.name=value config core.name &&
+               git -c foo.CamelCase=value config foo.camelcase &&
+               git -c foo.flag config --bool foo.flag
+       } >actual &&
+       test_cmp expect actual &&
        test_must_fail git -c name=value config core.name
  '