1
0
Fork 0
mirror of https://github.com/git/git.git synced 2024-05-19 11:46:07 +02:00
git/t/t1300-config.sh

2323 lines
58 KiB
Bash
Raw Normal View History

#!/bin/sh
#
# Copyright (c) 2005 Johannes Schindelin
#
test_description='Test git config in different settings'
GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=main
tests: mark tests relying on the current default for `init.defaultBranch` In addition to the manual adjustment to let the `linux-gcc` CI job run the test suite with `master` and then with `main`, this patch makes sure that GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME is set in all test scripts that currently rely on the initial branch name being `master by default. To determine which test scripts to mark up, the first step was to force-set the default branch name to `master` in - all test scripts that contain the keyword `master`, - t4211, which expects `t/t4211/history.export` with a hard-coded ref to initialize the default branch, - t5560 because it sources `t/t556x_common` which uses `master`, - t8002 and t8012 because both source `t/annotate-tests.sh` which also uses `master`) This trick was performed by this command: $ sed -i '/^ *\. \.\/\(test-lib\|lib-\(bash\|cvs\|git-svn\)\|gitweb-lib\)\.sh$/i\ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\ ' $(git grep -l master t/t[0-9]*.sh) \ t/t4211*.sh t/t5560*.sh t/t8002*.sh t/t8012*.sh After that, careful, manual inspection revealed that some of the test scripts containing the needle `master` do not actually rely on a specific default branch name: either they mention `master` only in a comment, or they initialize that branch specificially, or they do not actually refer to the current default branch. Therefore, the aforementioned modification was undone in those test scripts thusly: $ git checkout HEAD -- \ t/t0027-auto-crlf.sh t/t0060-path-utils.sh \ t/t1011-read-tree-sparse-checkout.sh \ t/t1305-config-include.sh t/t1309-early-config.sh \ t/t1402-check-ref-format.sh t/t1450-fsck.sh \ t/t2024-checkout-dwim.sh \ t/t2106-update-index-assume-unchanged.sh \ t/t3040-subprojects-basic.sh t/t3301-notes.sh \ t/t3308-notes-merge.sh t/t3423-rebase-reword.sh \ t/t3436-rebase-more-options.sh \ t/t4015-diff-whitespace.sh t/t4257-am-interactive.sh \ t/t5323-pack-redundant.sh t/t5401-update-hooks.sh \ t/t5511-refspec.sh t/t5526-fetch-submodules.sh \ t/t5529-push-errors.sh t/t5530-upload-pack-error.sh \ t/t5548-push-porcelain.sh \ t/t5552-skipping-fetch-negotiator.sh \ t/t5572-pull-submodule.sh t/t5608-clone-2gb.sh \ t/t5614-clone-submodules-shallow.sh \ t/t7508-status.sh t/t7606-merge-custom.sh \ t/t9302-fast-import-unpack-limit.sh We excluded one set of test scripts in these commands, though: the range of `git p4` tests. The reason? `git p4` stores the (foreign) remote branch in the branch called `p4/master`, which is obviously not the default branch. Manual analysis revealed that only five of these tests actually require a specific default branch name to pass; They were modified thusly: $ sed -i '/^ *\. \.\/lib-git-p4\.sh$/i\ GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME=master\ export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME\ ' t/t980[0167]*.sh t/t9811*.sh Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2020-11-19 00:44:19 +01:00
export GIT_TEST_DEFAULT_INITIAL_BRANCH_NAME
. ./test-lib.sh
test_expect_success 'clear default config' '
rm -f .git/config
'
cat > expect << EOF
[section]
penguin = little blue
EOF
test_expect_success 'initial' '
git config section.penguin "little blue" &&
test_cmp expect .git/config
'
cat > expect << EOF
[section]
penguin = little blue
Movie = BadPhysics
EOF
test_expect_success 'mixed case' '
git config Section.Movie BadPhysics &&
test_cmp expect .git/config
'
cat > expect << EOF
[section]
penguin = little blue
Movie = BadPhysics
[Sections]
WhatEver = Second
EOF
test_expect_success 'similar section' '
git config Sections.WhatEver Second &&
test_cmp expect .git/config
'
cat > expect << EOF
[section]
penguin = little blue
Movie = BadPhysics
UPPERCASE = true
[Sections]
WhatEver = Second
EOF
test_expect_success 'uppercase section' '
git config SECTION.UPPERCASE true &&
test_cmp expect .git/config
'
test_expect_success 'replace with non-match' '
git config section.penguin kingpin !blue
'
test_expect_success 'replace with non-match (actually matching)' '
git config section.penguin "very blue" !kingpin
'
cat > expect << EOF
[section]
penguin = very blue
Movie = BadPhysics
UPPERCASE = true
penguin = kingpin
[Sections]
WhatEver = Second
EOF
test_expect_success 'non-match result' 'test_cmp expect .git/config'
test_expect_success 'find mixed-case key by canonical name' '
test_cmp_config Second sections.whatever
'
test_expect_success 'find mixed-case key by non-canonical name' '
test_cmp_config Second SeCtIoNs.WhAtEvEr
'
test_expect_success 'subsections are not canonicalized by git-config' '
cat >>.git/config <<-\EOF &&
[section.SubSection]
key = one
[section "SubSection"]
key = two
EOF
test_cmp_config one section.subsection.key &&
test_cmp_config two section.SubSection.key
'
cat > .git/config <<\EOF
[alpha]
bar = foo
[beta]
baz = multiple \
lines
foo = bar
EOF
test_expect_success 'unset with cont. lines' '
git config --unset beta.baz
'
cat > expect <<\EOF
[alpha]
bar = foo
[beta]
foo = bar
EOF
test_expect_success 'unset with cont. lines is correct' 'test_cmp expect .git/config'
cat > .git/config << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha ="beta" # last silly comment
haha = hello
haha = bello
[nextSection] noNewline = ouch
EOF
cp .git/config .git/config2
test_expect_success 'multiple unset' '
git config --unset-all beta.haha
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection] noNewline = ouch
EOF
test_expect_success 'multiple unset is correct' '
test_cmp expect .git/config
'
cp .git/config2 .git/config
test_expect_success '--replace-all missing value' '
test_must_fail git config --replace-all beta.haha &&
test_cmp .git/config2 .git/config
'
rm .git/config2
test_expect_success '--replace-all' '
git config --replace-all beta.haha gamma
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha = gamma
[nextSection] noNewline = ouch
EOF
test_expect_success 'all replaced' '
test_cmp expect .git/config
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha = alpha
[nextSection] noNewline = ouch
EOF
test_expect_success 'really mean test' '
git config beta.haha alpha &&
test_cmp expect .git/config
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
haha = alpha
[nextSection]
nonewline = wow
EOF
test_expect_success 'really really mean test' '
git config nextsection.nonewline wow &&
test_cmp expect .git/config
'
test_expect_success 'get value' '
test_cmp_config alpha beta.haha
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
nonewline = wow
EOF
test_expect_success 'unset' '
git config --unset beta.haha &&
test_cmp expect .git/config
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
nonewline = wow
NoNewLine = wow2 for me
EOF
test_expect_success 'multivar' '
git config nextsection.NoNewLine "wow2 for me" "for me$" &&
test_cmp expect .git/config
'
test_expect_success 'non-match' '
git config --get nextsection.nonewline !for
'
test_expect_success 'non-match value' '
test_cmp_config wow --get nextsection.nonewline !for
'
git-config: do not complain about duplicate entries If git-config is asked for a single value, it will complain and exit with an error if it finds multiple instances of that value. This is unlike the usual internal config parsing, however, which will generally overwrite previous values, leaving only the final one. For example: [set a multivar] $ git config user.email one@example.com $ git config --add user.email two@example.com [use the internal parser to fetch it] $ git var GIT_AUTHOR_IDENT Your Name <two@example.com> ... [use git-config to fetch it] $ git config user.email one@example.com error: More than one value for the key user.email: two@example.com This overwriting behavior is critical for the regular parser, which starts with the lowest-priority file (e.g., /etc/gitconfig) and proceeds to the highest-priority file ($GIT_DIR/config). Overwriting yields the highest priority value at the end. Git-config solves this problem by implementing its own parsing. It goes from highest to lowest priorty, but does not proceed to the next file if it has seen a value. So in practice, this distinction never mattered much, because it only triggered for values in the same file. And there was not much point in doing that; the real value is in overwriting values from lower-priority files. However, this changed with the implementation of config include files. Now we might see an include overriding a value from the parent file, which is a sensible thing to do, but git-config will flag as a duplication. This patch drops the duplicate detection for git-config and switches to a pure-overwrite model (for the single case; --get-all can still be used if callers want to do something more fancy). As is shown by the modifications to the test suite, this is a user-visible change in behavior. An alternative would be to just change the include case, but this is much cleaner for a few reasons: 1. If you change the include case, then to what? If you just stop parsing includes after getting a value, then you will get a _different_ answer than the regular config parser (you'll get the first value instead of the last value). So you'd want to implement overwrite semantics anyway. 2. Even though it is a change in behavior for git-config, it is bringing us in line with what the internal parsers already do. 3. The file-order reimplementation is the only thing keeping us from sharing more code with the internal config parser, which will help keep differences to a minimum. Going under the assumption that the primary purpose of git-config is to behave identically to how git's internal parsing works, this change can be seen as a bug-fix. Signed-off-by: Jeff King <peff@peff.net>
2012-10-23 22:52:44 +02:00
test_expect_success 'multi-valued get returns final one' '
test_cmp_config "wow2 for me" --get nextsection.nonewline
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
'
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
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
nonewline = wow3
NoNewLine = wow2 for me
EOF
test_expect_success 'multivar replace' '
git config nextsection.nonewline "wow3" "wow$" &&
test_cmp expect .git/config
'
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
test_expect_success 'ambiguous unset' '
test_must_fail git config --unset nextsection.nonewline
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
'
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
test_expect_success 'invalid unset' '
test_must_fail git config --unset somesection.nonewline
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
NoNewLine = wow2 for me
EOF
test_expect_success 'multivar unset' '
git config --unset nextsection.nonewline "wow3$" &&
test_cmp expect .git/config
'
test_expect_success 'invalid key' 'test_must_fail git config inval.2key blabla'
test_expect_success 'correct key' 'git config 123456.a123 987'
test_expect_success 'hierarchical section' '
git config Version.1.2.3eX.Alpha beta
'
cat > expect << EOF
[beta] ; silly comment # another comment
noIndent= sillyValue ; 'nother silly comment
# empty line
; comment
[nextSection]
NoNewLine = wow2 for me
[123456]
a123 = 987
git config syntax updates This updates the hierarchical section name syntax to [section<space>+"<randomstring>"] where the only rule for "randomstring" is that it can't contain a newline, and if you really want to insert a double-quote, you do it with \". It turns that into the section name "secion.randomstring". The "section" part is still case insensitive, but the "randomstring" part is case sensitive. So you could use this for things like [email "torvalds@osdl.org"] name = Linus Torvalds if you wanted to do the "email->name" conversion as part of the config file format (I'm not claiming that is sensible, I'm just giving it as an insane example). That would show up as the association email.torvalds@osdl.org.name -> Linus Torvalds which is easy to parse (the "." in the email _looks_ ambiguous, but it isn't: you know that there will always be a single key-name, so you find the key name with "strrchr(name, '.')" and things are entirely unambiguous). Repo-config is updated to be able to parse the new format, and also write things out in the new format. [jc: rolled two patches from Linus and one fix-up from Sean into one, with additional adjustments for t/t1300 test to check the case insensitiveness of section base and variable and case sensitiveness of the extended section part. Then stripped some part off to make the result applicable to the stale 1.3.X series that does not have recent enhancements. ] Signed-off-by: Linus Torvalds <torvalds@osdl.org> Signed-off-by: Sean Estabrooks <seanlkml@sympatico.ca> Signed-off-by: Junio C Hamano <junkio@cox.net>
2006-05-09 21:24:02 +02:00
[Version "1.2.3eX"]
Alpha = beta
EOF
test_expect_success 'hierarchical section value' '
test_cmp expect .git/config
'
cat > expect << EOF
beta.noindent=sillyValue
nextsection.nonewline=wow2 for me
123456.a123=987
version.1.2.3eX.alpha=beta
EOF
test_expect_success 'working --list' '
git config --list > output &&
test_cmp expect output
'
test_expect_success '--list without repo produces empty output' '
git --git-dir=nonexistent config --list >output &&
tests: use 'test_must_be_empty' instead of 'test_cmp <empty> <out>' Using 'test_must_be_empty' is shorter and more idiomatic than >empty && test_cmp empty out as it saves the creation of an empty file. Furthermore, sometimes the expected empty file doesn't have such a descriptive name like 'empty', and its creation is far away from the place where it's finally used for comparison (e.g. in 't7600-merge.sh', where two expected empty files are created in the 'setup' test, but are used only about 500 lines later). These cases were found by instrumenting 'test_cmp' to error out the test script when it's used to compare empty files, and then converted manually. Note that even after this patch there still remain a lot of cases where we use 'test_cmp' to check empty files: - Sometimes the expected output is not hard-coded in the test, but 'test_cmp' is used to ensure that two similar git commands produce the same output, and that output happens to be empty, e.g. the test 'submodule update --merge - ignores --merge for new submodules' in 't7406-submodule-update.sh'. - Repetitive common tasks, including preparing the expected results and running 'test_cmp', are often extracted into a helper function, and some of this helper's callsites expect no output. - For the same reason as above, the whole 'test_expect_success' block is within a helper function, e.g. in 't3070-wildmatch.sh'. - Or 'test_cmp' is invoked in a loop, e.g. the test 'cvs update (-p)' in 't9400-git-cvsserver-server.sh'. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-08-19 23:57:25 +02:00
test_must_be_empty output
'
cat > expect << EOF
beta.noindent
nextsection.nonewline
123456.a123
version.1.2.3eX.alpha
EOF
test_expect_success '--name-only --list' '
git config --name-only --list >output &&
test_cmp expect output
'
cat > expect << EOF
beta.noindent sillyValue
nextsection.nonewline wow2 for me
EOF
test_expect_success '--get-regexp' '
git config --get-regexp in >output &&
test_cmp expect output
'
cat > expect << EOF
beta.noindent
nextsection.nonewline
EOF
test_expect_success '--name-only --get-regexp' '
git config --name-only --get-regexp in >output &&
test_cmp expect output
'
cat > expect << EOF
wow2 for me
wow4 for you
EOF
test_expect_success '--add' '
git config --add nextsection.nonewline "wow4 for you" &&
git config --get-all nextsection.nonewline > output &&
test_cmp expect output
'
cat > .git/config << EOF
[novalue]
variable
[emptyvalue]
variable =
EOF
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 ^$
'
echo novalue.variable > 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 &&
test_cmp expect output
'
echo 'emptyvalue.variable ' > 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 &&
test_cmp expect output
'
echo false > 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 &&
test_i18ngrep usage output
'
cat > .git/config << EOF
[a.b]
c = d
EOF
cat > expect << EOF
[a.b]
c = d
[a]
x = y
EOF
test_expect_success 'new section is partial match of another' '
git config a.x y &&
test_cmp expect .git/config
'
cat > expect << EOF
[a.b]
c = d
[a]
x = y
b = c
[b]
x = y
EOF
test_expect_success 'new variable inserts into proper section' '
git config b.x y &&
git config a.b c &&
test_cmp expect .git/config
'
test_expect_success 'alternative --file (non-existing file should fail)' '
test_must_fail git config --file non-existing-config -l &&
test_must_fail git config --file non-existing-config test.xyzzy
'
cat > other-config << EOF
[ein]
bahn = strasse
EOF
cat > expect << EOF
ein.bahn=strasse
EOF
test_expect_success 'alternative GIT_CONFIG' '
GIT_CONFIG=other-config git config --list >output &&
test_cmp expect output
'
test_expect_success 'alternative GIT_CONFIG (--file)' '
git config --file other-config --list >output &&
test_cmp expect output
'
test_expect_success 'alternative GIT_CONFIG (--file=-)' '
git config --file - --list <other-config >output &&
test_cmp expect output
'
test_expect_success 'setting a value in stdin is an error' '
test_must_fail git config --file - some.value foo
'
test_expect_success 'editing stdin is an error' '
test_must_fail git config --file - --edit
'
test_expect_success 'refer config from subdirectory' '
mkdir x &&
test_cmp_config -C x strasse --file=../other-config --get ein.bahn
'
cat > expect << EOF
[ein]
bahn = strasse
[anwohner]
park = ausweis
EOF
test_expect_success '--set in alternative file' '
git config --file=other-config anwohner.park ausweis &&
test_cmp expect other-config
'
cat > .git/config << EOF
# Hallo
#Bello
[branch "eins"]
x = 1
[branch.eins]
y = 1
[branch "1 234 blabl/a"]
weird
EOF
test_expect_success 'rename section' '
git config --rename-section branch.eins branch.zwei
'
cat > expect << EOF
# Hallo
#Bello
[branch "zwei"]
x = 1
[branch "zwei"]
y = 1
[branch "1 234 blabl/a"]
weird
EOF
test_expect_success 'rename succeeded' '
test_cmp expect .git/config
'
test_expect_success 'rename non-existing section' '
test_must_fail git config --rename-section \
branch."world domination" branch.drei
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
'
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
'
cat > expect << EOF
# Hallo
#Bello
[branch "zwei"]
x = 1
[branch "zwei"]
y = 1
[branch "drei"]
weird
EOF
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
'
cat > expect << EOF
# Hallo
#Bello
[branch "zwei"]
x = 1
[branch "zwei"]
y = 1
[branch "drei"]
weird
[branch "zwei"]
z = 1
EOF
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 ""
'
test_expect_success 'renaming to bogus section is rejected' '
test_must_fail git config --rename-section branch.zwei "bogus name"
'
config: avoid fixed-sized buffer when renaming/deleting a section When renaming (or deleting) a section of configuration, Git uses the function `git_config_copy_or_rename_section_in_file()` to rewrite the configuration file after applying the rename or deletion to the given section. To do this, Git repeatedly calls `fgets()` to read the existing configuration data into a fixed size buffer. When the configuration value under `old_name` exceeds the size of the buffer, we will call `fgets()` an additional time even if there is no newline in the configuration file, since our read length is capped at `sizeof(buf)`. If the first character of the buffer (after zero or more characters satisfying `isspace()`) is a '[', Git will incorrectly treat it as beginning a new section when the original section is being removed. In other words, a configuration value satisfying this criteria can incorrectly be considered as a new secftion instead of a variable in the original section. Avoid this issue by using a variable-width buffer in the form of a strbuf rather than a fixed-with region on the stack. A couple of small points worth noting: - Using a strbuf will cause us to allocate arbitrary sizes to match the length of each line. In practice, we don't expect any reasonable configuration files to have lines that long, and a bandaid will be introduced in a later patch to ensure that this is the case. - We are using strbuf_getwholeline() here instead of strbuf_getline() in order to match `fgets()`'s behavior of leaving the trailing LF character on the buffer (as well as a trailing NUL). This could be changed later, but using strbuf_getwholeline() changes the least about this function's implementation, so it is picked as the safest path. - It is temping to want to replace the loop to skip over characters matching isspace() at the beginning of the buffer with a convenience function like `strbuf_ltrim()`. But this is the wrong approach for a couple of reasons: First, it involves a potentially large and expensive `memmove()` which we would like to avoid. Second, and more importantly, we also *do* want to preserve those spaces to avoid changing the output of other sections. In all, this patch is a minimal replacement of the fixed-width buffer in `git_config_copy_or_rename_section_in_file()` to instead use a `struct strbuf`. Reported-by: André Baptista <andre@ethiack.com> Reported-by: Vítor Pinho <vitor@ethiack.com> Helped-by: Patrick Steinhardt <ps@pks.im> Co-authored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Taylor Blau <me@ttaylorr.com>
2023-04-06 20:07:58 +02:00
test_expect_success 'renaming a section with a long line' '
{
printf "[b]\\n" &&
printf " c = d %1024s [a] e = f\\n" " " &&
printf "[a] g = h\\n"
} >y &&
git config -f y --rename-section a xyz &&
test_must_fail git config -f y b.e
'
config: avoid fixed-sized buffer when renaming/deleting a section When renaming (or deleting) a section of configuration, Git uses the function `git_config_copy_or_rename_section_in_file()` to rewrite the configuration file after applying the rename or deletion to the given section. To do this, Git repeatedly calls `fgets()` to read the existing configuration data into a fixed size buffer. When the configuration value under `old_name` exceeds the size of the buffer, we will call `fgets()` an additional time even if there is no newline in the configuration file, since our read length is capped at `sizeof(buf)`. If the first character of the buffer (after zero or more characters satisfying `isspace()`) is a '[', Git will incorrectly treat it as beginning a new section when the original section is being removed. In other words, a configuration value satisfying this criteria can incorrectly be considered as a new secftion instead of a variable in the original section. Avoid this issue by using a variable-width buffer in the form of a strbuf rather than a fixed-with region on the stack. A couple of small points worth noting: - Using a strbuf will cause us to allocate arbitrary sizes to match the length of each line. In practice, we don't expect any reasonable configuration files to have lines that long, and a bandaid will be introduced in a later patch to ensure that this is the case. - We are using strbuf_getwholeline() here instead of strbuf_getline() in order to match `fgets()`'s behavior of leaving the trailing LF character on the buffer (as well as a trailing NUL). This could be changed later, but using strbuf_getwholeline() changes the least about this function's implementation, so it is picked as the safest path. - It is temping to want to replace the loop to skip over characters matching isspace() at the beginning of the buffer with a convenience function like `strbuf_ltrim()`. But this is the wrong approach for a couple of reasons: First, it involves a potentially large and expensive `memmove()` which we would like to avoid. Second, and more importantly, we also *do* want to preserve those spaces to avoid changing the output of other sections. In all, this patch is a minimal replacement of the fixed-width buffer in `git_config_copy_or_rename_section_in_file()` to instead use a `struct strbuf`. Reported-by: André Baptista <andre@ethiack.com> Reported-by: Vítor Pinho <vitor@ethiack.com> Helped-by: Patrick Steinhardt <ps@pks.im> Co-authored-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Johannes Schindelin <Johannes.Schindelin@gmx.de> Signed-off-by: Taylor Blau <me@ttaylorr.com>
2023-04-06 20:07:58 +02:00
test_expect_success 'renaming an embedded section with a long line' '
{
printf "[b]\\n" &&
printf " c = d %1024s [a] [foo] e = f\\n" " " &&
printf "[a] g = h\\n"
} >y &&
git config -f y --rename-section a xyz &&
test_must_fail git config -f y foo.e
'
test_expect_success 'renaming a section with an overly-long line' '
{
printf "[b]\\n" &&
printf " c = d %525000s e" " " &&
printf "[a] g = h\\n"
} >y &&
test_must_fail git config -f y --rename-section a xyz 2>err &&
grep "refusing to work with overly long line in .y. on line 2" err
'
cat >> .git/config << EOF
[branch "zwei"] a = 1 [branch "vier"]
EOF
test_expect_success 'remove section' '
git config --remove-section branch.zwei
'
cat > expect << EOF
# Hallo
#Bello
[branch "drei"]
weird
EOF
test_expect_success 'section was removed properly' '
test_cmp expect .git/config
'
cat > expect << EOF
[gitcvs]
enabled = true
dbname = %Ggitcvs2.%a.%m.sqlite
[gitcvs "ext"]
dbname = %Ggitcvs1.%a.%m.sqlite
EOF
test_expect_success 'section ending' '
rm -f .git/config &&
git config gitcvs.enabled true &&
git config gitcvs.ext.dbname %Ggitcvs1.%a.%m.sqlite &&
git config gitcvs.dbname %Ggitcvs2.%a.%m.sqlite &&
test_cmp expect .git/config
'
test_expect_success numbers '
git config kilo.gram 1k &&
git config mega.ton 1m &&
echo 1024 >expect &&
echo 1048576 >>expect &&
git config --int --get kilo.gram >actual &&
git config --int --get mega.ton >>actual &&
test_cmp expect actual
'
git-config: always treat --int as 64-bit internally When you run "git config --int", the maximum size of integer you get depends on how git was compiled, and what it considers to be an "int". This is almost useful, because your scripts calling "git config" will behave similarly to git internally. But relying on this is dubious; you have to actually know how git treats each value internally (e.g., int versus unsigned long), which is not documented and is subject to change. And even if you know it is "unsigned long", we do not have a git-config option to match that behavior. Furthermore, you may simply be asking git to store a value on your behalf (e.g., configuration for a hook). In that case, the relevant range check has nothing at all to do with git, but rather with whatever scripting tools you are using (and git has no way of knowing what the appropriate range is there). Not only is the range check useless, but it is actively harmful, as there is no way at all for scripts to look at config variables with large values. For instance, one cannot reliably get the value of pack.packSizeLimit via git-config. On an LP64 system, git happily uses a 64-bit "unsigned long" internally to represent the value, but the script cannot read any value over 2G. Ideally, the "--int" option would simply represent an arbitrarily large integer. For practical purposes, however, a 64-bit integer is large enough, and is much easier to implement (and if somebody overflows it, we will still notice the problem, and not simply return garbage). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-08 10:40:02 +02:00
test_expect_success '--int is at least 64 bits' '
git config giga.watts 121g &&
echo >expect &&
test_cmp_config 129922760704 --int --get giga.watts
git-config: always treat --int as 64-bit internally When you run "git config --int", the maximum size of integer you get depends on how git was compiled, and what it considers to be an "int". This is almost useful, because your scripts calling "git config" will behave similarly to git internally. But relying on this is dubious; you have to actually know how git treats each value internally (e.g., int versus unsigned long), which is not documented and is subject to change. And even if you know it is "unsigned long", we do not have a git-config option to match that behavior. Furthermore, you may simply be asking git to store a value on your behalf (e.g., configuration for a hook). In that case, the relevant range check has nothing at all to do with git, but rather with whatever scripting tools you are using (and git has no way of knowing what the appropriate range is there). Not only is the range check useless, but it is actively harmful, as there is no way at all for scripts to look at config variables with large values. For instance, one cannot reliably get the value of pack.packSizeLimit via git-config. On an LP64 system, git happily uses a 64-bit "unsigned long" internally to represent the value, but the script cannot read any value over 2G. Ideally, the "--int" option would simply represent an arbitrarily large integer. For practical purposes, however, a 64-bit integer is large enough, and is much easier to implement (and if somebody overflows it, we will still notice the problem, and not simply return garbage). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2013-09-08 10:40:02 +02:00
'
test_expect_success 'invalid unit' '
git config aninvalid.unit "1auto" &&
test_cmp_config 1auto aninvalid.unit &&
test_must_fail git config --int --get aninvalid.unit 2>actual &&
test_i18ngrep "bad numeric config value .1auto. for .aninvalid.unit. in file .git/config: invalid unit" actual
'
test_expect_success 'invalid unit boolean' '
git config commit.gpgsign "1true" &&
test_cmp_config 1true commit.gpgsign &&
test_must_fail git config --bool --get commit.gpgsign 2>actual &&
test_i18ngrep "bad boolean config value .1true. for .commit.gpgsign." actual
'
test_expect_success 'line number is reported correctly' '
printf "[bool]\n\tvar\n" >invalid &&
test_must_fail git config -f invalid --path bool.var 2>actual &&
test_i18ngrep "line 2" actual
'
test_expect_success 'invalid stdin config' '
echo "[broken" | test_must_fail git config --list --file - >output 2>&1 &&
test_i18ngrep "bad config line 1 in standard input" output
'
cat > expect << EOF
true
false
true
false
true
false
true
false
EOF
test_expect_success bool '
git config bool.true1 01 &&
git config bool.true2 -1 &&
git config bool.true3 YeS &&
git config bool.true4 true &&
git config bool.false1 000 &&
git config bool.false2 "" &&
git config bool.false3 nO &&
git config bool.false4 FALSE &&
rm -f result &&
for i in 1 2 3 4
do
git config --bool --get bool.true$i >>result
git config --bool --get bool.false$i >>result
done &&
test_cmp expect result'
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
test_expect_success 'invalid bool (--get)' '
git config bool.nobool foobar &&
test_must_fail git config --bool --get bool.nobool'
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
test_expect_success 'invalid bool (set)' '
test_must_fail git config --bool bool.nobool foobar'
cat > expect <<\EOF
[bool]
true1 = true
true2 = true
true3 = true
true4 = true
false1 = false
false2 = false
false3 = false
false4 = false
EOF
test_expect_success 'set --bool' '
rm -f .git/config &&
git config --bool bool.true1 01 &&
git config --bool bool.true2 -1 &&
git config --bool bool.true3 YeS &&
git config --bool bool.true4 true &&
git config --bool bool.false1 000 &&
git config --bool bool.false2 "" &&
git config --bool bool.false3 nO &&
git config --bool bool.false4 FALSE &&
test_cmp expect .git/config'
cat > expect <<\EOF
[int]
val1 = 1
val2 = -1
val3 = 5242880
EOF
test_expect_success 'set --int' '
rm -f .git/config &&
git config --int int.val1 01 &&
git config --int int.val2 -1 &&
git config --int int.val3 5m &&
test_cmp expect .git/config
'
test_expect_success 'get --bool-or-int' '
cat >.git/config <<-\EOF &&
[bool]
true1
true2 = true
false = false
[int]
int1 = 0
int2 = 1
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
[bool]
true1 = true
false1 = false
true2 = true
false2 = false
[int]
int1 = 0
int2 = 1
int3 = -1
EOF
test_expect_success 'set --bool-or-int' '
rm -f .git/config &&
git config --bool-or-int bool.true1 true &&
git config --bool-or-int bool.false1 false &&
git config --bool-or-int bool.true2 yes &&
git config --bool-or-int bool.false2 no &&
git config --bool-or-int int.int1 0 &&
git config --bool-or-int int.int2 1 &&
git config --bool-or-int int.int3 -1 &&
test_cmp expect .git/config
'
cat >expect <<\EOF
[path]
home = ~/
normal = /dev/null
trailingtilde = foo~
EOF
test_expect_success !MINGW 'set --path' '
rm -f .git/config &&
git config --path path.home "~/" &&
git config --path path.normal "/dev/null" &&
git config --path path.trailingtilde "foo~" &&
test_cmp expect .git/config'
if test_have_prereq !MINGW && test "${HOME+set}"
then
test_set_prereq HOMEVAR
fi
cat >expect <<EOF
$HOME/
/dev/null
foo~
EOF
test_expect_success HOMEVAR 'get --path' '
git config --get --path path.home > result &&
git config --get --path path.normal >> result &&
git config --get --path path.trailingtilde >> result &&
test_cmp expect result
'
cat >expect <<\EOF
/dev/null
foo~
EOF
test_expect_success !MINGW 'get --path copes with unset $HOME' '
(
sane_unset HOME &&
test_must_fail git config --get --path path.home \
>result 2>msg &&
git config --get --path path.normal >>result &&
git config --get --path path.trailingtilde >>result
) &&
test_i18ngrep "[Ff]ailed to expand.*~/" msg &&
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
'
test_expect_success 'get --expiry-date' '
rel="3.weeks.5.days.00:00" &&
rel_out="$rel ->" &&
cat >.git/config <<-\EOF &&
[date]
valid1 = "3.weeks.5.days 00:00"
valid2 = "Fri Jun 4 15:46:55 2010"
valid3 = "2017/11/11 11:11:11PM"
valid4 = "2017/11/10 09:08:07 PM"
valid5 = "never"
invalid1 = "abc"
EOF
cat >expect <<-EOF &&
$(test-tool date timestamp $rel)
1275666415
1510441871
1510348087
0
EOF
: "work around heredoc parsing bug fixed in dash 0.5.7 (in ec2c84d)" &&
{
echo "$rel_out $(git config --expiry-date date.valid1)"
git config --expiry-date date.valid2 &&
git config --expiry-date date.valid3 &&
git config --expiry-date date.valid4 &&
git config --expiry-date date.valid5
} >actual &&
test_cmp expect actual &&
test_must_fail git config --expiry-date date.invalid1
'
test_expect_success 'get --type=color' '
rm .git/config &&
git config foo.color "red" &&
git config --get --type=color foo.color >actual.raw &&
test_decode_color <actual.raw >actual &&
echo "<RED>" >expect &&
test_cmp expect actual
'
cat >expect << EOF
[foo]
color = red
EOF
test_expect_success 'set --type=color' '
rm .git/config &&
git config --type=color foo.color "red" &&
test_cmp expect .git/config
'
test_expect_success 'get --type=color barfs on non-color' '
echo "[foo]bar=not-a-color" >.git/config &&
test_must_fail git config --get --type=color foo.bar
'
test_expect_success 'set --type=color barfs on non-color' '
test_must_fail git config --type=color foo.color "not-a-color" 2>error &&
test_i18ngrep "cannot parse color" error
'
cat > expect << EOF
[quote]
leading = " test"
ending = "test "
semicolon = "test;test"
hash = "test#test"
EOF
test_expect_success 'quoting' '
rm -f .git/config &&
git config quote.leading " test" &&
git config quote.ending "test " &&
git config quote.semicolon "test;test" &&
git config quote.hash "test#test" &&
test_cmp expect .git/config
'
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
test_expect_success 'key with newline' '
test_must_fail git config "key.with
Sane use of test_expect_failure Originally, test_expect_failure was designed to be the opposite of test_expect_success, but this was a bad decision. Most tests run a series of commands that leads to the single command that needs to be tested, like this: test_expect_{success,failure} 'test title' ' setup1 && setup2 && setup3 && what is to be tested ' And expecting a failure exit from the whole sequence misses the point of writing tests. Your setup$N that are supposed to succeed may have failed without even reaching what you are trying to test. The only valid use of test_expect_failure is to check a trivial single command that is expected to fail, which is a minority in tests of Porcelain-ish commands. This large-ish patch rewrites all uses of test_expect_failure to use test_expect_success and rewrites the condition of what is tested, like this: test_expect_success 'test title' ' setup1 && setup2 && setup3 && ! this command should fail ' test_expect_failure is redefined to serve as a reminder that that test *should* succeed but due to a known breakage in git it currently does not pass. So if git-foo command should create a file 'bar' but you discovered a bug that it doesn't, you can write a test like this: test_expect_failure 'git-foo should create bar' ' rm -f bar && git foo && test -f bar ' This construct acts similar to test_expect_success, but instead of reporting "ok/FAIL" like test_expect_success does, the outcome is reported as "FIXED/still broken". Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-02-01 10:50:53 +01:00
newline" 123'
test_expect_success 'value with newline' 'git config key.sub value.with\\\
newline'
cat > .git/config <<\EOF
[section]
; comment \
continued = cont\
inued
noncont = not continued ; \
quotecont = "cont;\
inued"
EOF
cat > expect <<\EOF
section.continued=continued
section.noncont=not continued
section.quotecont=cont;inued
EOF
test_expect_success 'value continued on next line' '
git config --list > result &&
test_cmp expect result
'
cat > .git/config <<\EOF
[section "sub=section"]
val1 = foo=bar
val2 = foo\nbar
val3 = \n\n
val4 =
val5
EOF
cat > expect <<\EOF
section.sub=section.val1
foo=barQsection.sub=section.val2
foo
barQsection.sub=section.val3
Qsection.sub=section.val4
Qsection.sub=section.val5Q
EOF
test_expect_success '--null --list' '
git config --null --list >result.raw &&
nul_to_q <result.raw >result &&
echo >>result &&
test_cmp expect result
'
test_expect_success '--null --get-regexp' '
git config --null --get-regexp "val[0-9]" >result.raw &&
nul_to_q <result.raw >result &&
echo >>result &&
test_cmp expect result
'
test_expect_success 'inner whitespace kept verbatim' '
git config section.val "foo bar" &&
test_cmp_config "foo bar" section.val
'
test_expect_success SYMLINKS 'symlinked configuration' '
ln -s notyet myconfig &&
git config --file=myconfig test.frotz nitfol &&
test -h myconfig &&
test -f notyet &&
test "z$(git config --file=notyet test.frotz)" = znitfol &&
git config --file=myconfig test.xyzzy rezrov &&
test -h myconfig &&
test -f notyet &&
cat >expect <<-\EOF &&
nitfol
rezrov
EOF
{
git config --file=notyet test.frotz &&
git config --file=notyet test.xyzzy
} >actual &&
test_cmp expect actual
'
test_expect_success SYMLINKS 'symlink to nonexistent configuration' '
ln -s doesnotexist linktonada &&
ln -s linktonada linktolinktonada &&
test_must_fail git config --file=linktonada --list &&
test_must_fail git config --file=linktolinktonada --list
'
test_expect_success 'check split_cmdline return' "
git config alias.split-cmdline-fix 'echo \"' &&
test_must_fail git split-cmdline-fix &&
echo foo > foo &&
git add foo &&
git commit -m 'initial commit' &&
git config branch.main.mergeoptions 'echo \"' &&
test_must_fail git merge main
"
test_expect_success 'git -c "key=value" support' '
cat >expect <<-\EOF &&
value
value
true
EOF
{
git -c section.name=value config section.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 section.name
'
# We just need a type-specifier here that cares about the
# distinction internally between a NULL boolean and a real
# string (because most of git's internal parsers do care).
# Using "--path" works, but we do not otherwise care about
# its semantics.
test_expect_success 'git -c can represent empty string' '
echo >expect &&
git -c foo.empty= config --path foo.empty >actual &&
test_cmp expect actual
'
test_expect_success 'key sanity-checking' '
test_must_fail git config foo=bar &&
test_must_fail git config foo=.bar &&
test_must_fail git config foo.ba=r &&
test_must_fail git config foo.1bar &&
test_must_fail git config foo."ba
z".bar &&
test_must_fail git config . false &&
test_must_fail git config .foo false &&
test_must_fail git config foo. false &&
test_must_fail git config .foo. false &&
git config foo.bar true &&
git config foo."ba =z".bar false
'
test_expect_success 'git -c works with aliases of builtins' '
git config alias.checkconfig "-c foo.check=bar config foo.check" &&
echo bar >expect &&
git checkconfig >actual &&
test_cmp expect actual
'
test_expect_success 'aliases can be CamelCased' '
test_config alias.CamelCased "rev-parse HEAD" &&
git CamelCased >out &&
git rev-parse HEAD >expect &&
test_cmp expect out
'
test_expect_success 'git -c does not split values on equals' '
echo "value with = in it" >expect &&
git -c section.foo="value with = in it" config section.foo >actual &&
test_cmp expect actual
'
test_expect_success 'git -c dies on bogus config' '
test_must_fail git -c core.bare=foo rev-parse
'
test_expect_success 'git -c complains about empty key' '
test_must_fail git -c "=foo" rev-parse
'
test_expect_success 'git -c complains about empty key and value' '
test_must_fail git -c "" rev-parse
'
git_config_push_parameter: handle empty GIT_CONFIG_PARAMETERS The "git -c var=value" option stuffs the config value into $GIT_CONFIG_PARAMETERS, so that sub-processes can see it. When the config is later read via git_config() or similar, we parse it back out of that variable. The parsing end is a little bit picky; it assumes that each entry was generated with sq_quote_buf(), and that there is no extraneous whitespace. On the generating end, we are careful to append to an existing $GIT_CONFIG_PARAMETERS variable if it exists. However, our test for "should we add a space separator" is too liberal: it will add one even if the environment variable exists but is empty. As a result, you might end up with: GIT_CONFIG_PARAMETERS=" 'core.foo=bar'" which the parser will choke on. This was hard to trigger in older versions of git, since we only set the variable when we had something to put into it (though you could certainly trigger it manually). But since 14111fc (git: submodule honor -c credential.* from command line, 2016-02-29), the submodule code will unconditionally put the $GIT_CONFIG_PARAMETERS variable into the environment of any operation in the submodule, whether it is empty or not. So any of those operations which themselves use "git -c" will generate the unparseable value and fail. We can easily fix it by catching this case on the generating side. While we're adding a test, let's also check that multiple layers of "git -c" work, which was previously not tested at all. Reported-by: Shin Fan <shinfan@google.com> Signed-off-by: Jeff King <peff@peff.net> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Tested-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-22 20:50:51 +01:00
test_expect_success 'multiple git -c appends config' '
test_config alias.x "!git -c x.two=2 config --get-regexp ^x\.*" &&
cat >expect <<-\EOF &&
x.one 1
x.two 2
EOF
git -c x.one=1 x >actual &&
test_cmp expect actual
'
test_expect_success 'last one wins: two level vars' '
# sec.var and sec.VAR are the same variable, as the first
# and the last level of a configuration variable name is
# case insensitive.
echo VAL >expect &&
git -c sec.var=val -c sec.VAR=VAL config --get sec.var >actual &&
test_cmp expect actual &&
git -c SEC.var=val -c sec.var=VAL config --get sec.var >actual &&
test_cmp expect actual &&
git -c sec.var=val -c sec.VAR=VAL config --get SEC.var >actual &&
test_cmp expect actual &&
git -c SEC.var=val -c sec.var=VAL config --get sec.VAR >actual &&
test_cmp expect actual
'
test_expect_success 'last one wins: three level vars' '
# v.a.r and v.A.r are not the same variable, as the middle
# level of a three-level configuration variable name is
# case sensitive.
echo val >expect &&
git -c v.a.r=val -c v.A.r=VAL config --get v.a.r >actual &&
test_cmp expect actual &&
git -c v.a.r=val -c v.A.r=VAL config --get V.a.R >actual &&
test_cmp expect actual &&
# v.a.r and V.a.R are the same variable, as the first
# and the last level of a configuration variable name is
# case insensitive.
echo VAL >expect &&
git -c v.a.r=val -c v.a.R=VAL config --get v.a.r >actual &&
test_cmp expect actual &&
git -c v.a.r=val -c V.a.r=VAL config --get v.a.r >actual &&
test_cmp expect actual &&
git -c v.a.r=val -c v.a.R=VAL config --get V.a.R >actual &&
test_cmp expect actual &&
git -c v.a.r=val -c V.a.r=VAL config --get V.a.R >actual &&
test_cmp expect actual
'
test_expect_success 'old-fashioned settings are case insensitive' '
test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
cat >testConfig_actual <<-EOF &&
[V.A]
r = value1
EOF
q_to_tab >testConfig_expect <<-EOF &&
[V.A]
Qr = value2
EOF
git config -f testConfig_actual "v.a.r" value2 &&
test_cmp testConfig_expect testConfig_actual &&
cat >testConfig_actual <<-EOF &&
[V.A]
r = value1
EOF
q_to_tab >testConfig_expect <<-EOF &&
[V.A]
QR = value2
EOF
git config -f testConfig_actual "V.a.R" value2 &&
test_cmp testConfig_expect testConfig_actual &&
cat >testConfig_actual <<-EOF &&
[V.A]
r = value1
EOF
q_to_tab >testConfig_expect <<-EOF &&
[V.A]
r = value1
Qr = value2
EOF
git config -f testConfig_actual "V.A.r" value2 &&
test_cmp testConfig_expect testConfig_actual &&
cat >testConfig_actual <<-EOF &&
[V.A]
r = value1
EOF
q_to_tab >testConfig_expect <<-EOF &&
[V.A]
r = value1
Qr = value2
EOF
git config -f testConfig_actual "v.A.r" value2 &&
test_cmp testConfig_expect testConfig_actual
'
test_expect_success 'setting different case sensitive subsections ' '
test_when_finished "rm -f testConfig testConfig_expect testConfig_actual" &&
cat >testConfig_actual <<-EOF &&
[V "A"]
R = v1
[K "E"]
Y = v1
[a "b"]
c = v1
[d "e"]
f = v1
EOF
q_to_tab >testConfig_expect <<-EOF &&
[V "A"]
Qr = v2
[K "E"]
Qy = v2
[a "b"]
Qc = v2
[d "e"]
f = v1
[d "E"]
Qf = v2
EOF
# exact match
git config -f testConfig_actual a.b.c v2 &&
# match section and subsection, key is cased differently.
git config -f testConfig_actual K.E.y v2 &&
# section and key are matched case insensitive, but subsection needs
# to match; When writing out new values only the key is adjusted
git config -f testConfig_actual v.A.r v2 &&
# subsection is not matched:
git config -f testConfig_actual d.E.f v2 &&
test_cmp testConfig_expect testConfig_actual
'
for VAR in a .a a. a.0b a."b c". a."b c".0d
do
test_expect_success "git -c $VAR=VAL rejects invalid '$VAR'" '
test_must_fail git -c "$VAR=VAL" config -l
'
done
for VAR in a.b a."b c".d
do
test_expect_success "git -c $VAR=VAL works with valid '$VAR'" '
echo VAL >expect &&
git -c "$VAR=VAL" config --get "$VAR" >actual &&
test_cmp expect actual
'
done
git_config_push_parameter: handle empty GIT_CONFIG_PARAMETERS The "git -c var=value" option stuffs the config value into $GIT_CONFIG_PARAMETERS, so that sub-processes can see it. When the config is later read via git_config() or similar, we parse it back out of that variable. The parsing end is a little bit picky; it assumes that each entry was generated with sq_quote_buf(), and that there is no extraneous whitespace. On the generating end, we are careful to append to an existing $GIT_CONFIG_PARAMETERS variable if it exists. However, our test for "should we add a space separator" is too liberal: it will add one even if the environment variable exists but is empty. As a result, you might end up with: GIT_CONFIG_PARAMETERS=" 'core.foo=bar'" which the parser will choke on. This was hard to trigger in older versions of git, since we only set the variable when we had something to put into it (though you could certainly trigger it manually). But since 14111fc (git: submodule honor -c credential.* from command line, 2016-02-29), the submodule code will unconditionally put the $GIT_CONFIG_PARAMETERS variable into the environment of any operation in the submodule, whether it is empty or not. So any of those operations which themselves use "git -c" will generate the unparseable value and fail. We can easily fix it by catching this case on the generating side. While we're adding a test, let's also check that multiple layers of "git -c" work, which was previously not tested at all. Reported-by: Shin Fan <shinfan@google.com> Signed-off-by: Jeff King <peff@peff.net> Reviewed-by: Jonathan Nieder <jrnieder@gmail.com> Tested-by: Jonathan Nieder <jrnieder@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-03-22 20:50:51 +01:00
test_expect_success 'git -c is not confused by empty environment' '
GIT_CONFIG_PARAMETERS="" git -c x.one=1 config --list
'
config: parse more robust format in GIT_CONFIG_PARAMETERS When we stuff config options into GIT_CONFIG_PARAMETERS, we shell-quote each one as a single unit, like: 'section.one=value1' 'section.two=value2' On the reading side, we de-quote to get the individual strings, and then parse them by splitting on the first "=" we find. This format is ambiguous, because an "=" may appear in a subsection. So the config represented in a file by both: [section "subsection=with=equals"] key = value and: [section] subsection = with=equals.key=value ends up in this flattened format like: 'section.subsection=with=equals.key=value' and we can't tell which was desired. We have traditionally resolved this by taking the first "=" we see starting from the left, meaning that we allowed arbitrary content in the value, but not in the subsection. Let's make our environment format a bit more robust by separately quoting the key and value. That turns those examples into: 'section.subsection=with=equals.key'='value' and: 'section.subsection'='with=equals.key=value' respectively, and we can tell the difference between them. We can detect which format is in use for any given element of the list based on the presence of the unquoted "=". That means we can continue to allow the old format to work to support any callers which manually used the old format, and we can even intermingle the two formats. The old format wasn't documented, and nobody was supposed to be using it. But it's likely that such callers exist in the wild, so it's nice if we can avoid breaking them. Likewise, it may be possible to trigger an older version of "git -c" that runs a script that calls into a newer version of "git -c"; that new version would see the intermingled format. This does create one complication, which is that the obvious format in the new scheme for [section] some-bool is: 'section.some-bool' with no equals. We'd mistake that for an old-style variable. And it even has the same meaning in the old style, but: [section "with=equals"] some-bool does not. It would be: 'section.with=equals=some-bool' which we'd take to mean: [section] with = equals=some-bool in the old, ambiguous style. Likewise, we can't use: 'section.some-bool'='' because that's ambiguous with an actual empty string. Instead, we'll again use the shell-quoting to give us a hint, and use: 'section.some-bool'= to show that we have no value. Note that this commit just expands the reading side. We'll start writing the new format via "git -c" in a future patch. In the meantime, the existing "git -c" tests will make sure we didn't break reading the old format. But we'll also add some explicit coverage of the two formats to make sure we continue to handle the old one after we move the writing side over. And one final note: since we're now using the shell-quoting as a semantically meaningful hint, this closes the door to us ever allowing arbitrary shell quoting, like: 'a'shell'would'be'ok'with'this'.key=value But we have never supported that (only what sq_quote() would produce), and we are probably better off keeping things simple, robust, and backwards-compatible, than trying to make it easier for humans. We'll continue not to advertise the format of the variable to users, and instead keep "git -c" as the recommended mechanism for setting config (even if we are trying to be kind not to break users who may be relying on the current undocumented format). Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2021-01-12 13:27:06 +01:00
test_expect_success 'GIT_CONFIG_PARAMETERS handles old-style entries' '
v="${SQ}key.one=foo${SQ}" &&
v="$v ${SQ}key.two=bar${SQ}" &&
v="$v ${SQ}key.ambiguous=section.whatever=value${SQ}" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
cat >expect <<-EOF &&
key.one foo
key.two bar
key.ambiguous section.whatever=value
EOF
test_cmp expect actual
'
test_expect_success 'GIT_CONFIG_PARAMETERS handles new-style entries' '
v="${SQ}key.one${SQ}=${SQ}foo${SQ}" &&
v="$v ${SQ}key.two${SQ}=${SQ}bar${SQ}" &&
v="$v ${SQ}key.ambiguous=section.whatever${SQ}=${SQ}value${SQ}" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
cat >expect <<-EOF &&
key.one foo
key.two bar
key.ambiguous=section.whatever value
EOF
test_cmp expect actual
'
test_expect_success 'old and new-style entries can mix' '
v="${SQ}key.oldone=oldfoo${SQ}" &&
v="$v ${SQ}key.newone${SQ}=${SQ}newfoo${SQ}" &&
v="$v ${SQ}key.oldtwo=oldbar${SQ}" &&
v="$v ${SQ}key.newtwo${SQ}=${SQ}newbar${SQ}" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
cat >expect <<-EOF &&
key.oldone oldfoo
key.newone newfoo
key.oldtwo oldbar
key.newtwo newbar
EOF
test_cmp expect actual
'
test_expect_success 'old and new bools with ambiguous subsection' '
v="${SQ}key.with=equals.oldbool${SQ}" &&
v="$v ${SQ}key.with=equals.newbool${SQ}=" &&
GIT_CONFIG_PARAMETERS=$v git config --get-regexp "key.*" >actual &&
cat >expect <<-EOF &&
key.with equals.oldbool
key.with=equals.newbool
EOF
test_cmp expect actual
'
sq_dequote: fix extra consumption of source string This fixes a (probably harmless) parsing problem in sq_dequote_step(), in which we parse some bogus input incorrectly rather than complaining that it's bogus. Our shell-dequoting function is very strict: it can unquote everything generated by sq_quote(), but not arbitrary strings. In particular, it only allows characters outside of the single-quoted string if they are immediately backslashed and then the single-quoted string is resumed. So: 'foo'\''bar' is OK. But these are not: 'foo'\'bar 'foo'\' 'foo'\'\''bar' even though they are all valid shell. The parser has a funny corner case here. When we see a backslashed character, we keep incrementing the "src" pointer as we parse it. For a single sq_dequote() call, that's OK; our next step is to bail with an error, and we don't care where "src" points. But if we're parsing multiple strings with sq_dequote_to_argv(), then our next step is to see if the string is followed by whitespace. Because we erroneously incremented the "src" pointer, we don't barf on the bogus backslash that we skipped. Instead, we may find whitespace that immediately follows it, and continue as if all is well (skipping the backslashed character completely!). In practice, this shouldn't be a big deal. The input is bogus, and our sq_quote() would never generate this bogus input. In all but one callers, we are parsing input created by an earlier call to sq_quote(). That final case is "git shell", which parses shell-quoting generated by the client. And in that case we use the singular sq_quote(), which has always behaved correctly. One might also wonder if you could provoke a read past the end of the string. But the answer is no; we still parse character by character, and would never advance past a NUL. This patch implements the minimal fix, along with documenting the restriction (which confused at least me while reading the code). We should possibly consider being more liberal in accepting valid shell-quoted words. I suspect the code may actually be simpler, and it would be more friendly to anybody generating or editing input by hand. But I wanted to fix just the immediate bug in this patch. We don't have a direct way to unit-test the sq_dequote() functions, but we can do this by feeding input to GIT_CONFIG_PARAMETERS (which is not normally a user-facing interface, but serves here as it expects to see sq_quote() input from "git -c"). I've included both a bogus example, and a related "good" one to confirm that we still parse it correctly. Noticed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-14 00:41:49 +01:00
test_expect_success 'detect bogus GIT_CONFIG_PARAMETERS' '
cat >expect <<-\EOF &&
env.one one
env.two two
EOF
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ} ${SQ}env.two=two${SQ}" \
sq_dequote: fix extra consumption of source string This fixes a (probably harmless) parsing problem in sq_dequote_step(), in which we parse some bogus input incorrectly rather than complaining that it's bogus. Our shell-dequoting function is very strict: it can unquote everything generated by sq_quote(), but not arbitrary strings. In particular, it only allows characters outside of the single-quoted string if they are immediately backslashed and then the single-quoted string is resumed. So: 'foo'\''bar' is OK. But these are not: 'foo'\'bar 'foo'\' 'foo'\'\''bar' even though they are all valid shell. The parser has a funny corner case here. When we see a backslashed character, we keep incrementing the "src" pointer as we parse it. For a single sq_dequote() call, that's OK; our next step is to bail with an error, and we don't care where "src" points. But if we're parsing multiple strings with sq_dequote_to_argv(), then our next step is to see if the string is followed by whitespace. Because we erroneously incremented the "src" pointer, we don't barf on the bogus backslash that we skipped. Instead, we may find whitespace that immediately follows it, and continue as if all is well (skipping the backslashed character completely!). In practice, this shouldn't be a big deal. The input is bogus, and our sq_quote() would never generate this bogus input. In all but one callers, we are parsing input created by an earlier call to sq_quote(). That final case is "git shell", which parses shell-quoting generated by the client. And in that case we use the singular sq_quote(), which has always behaved correctly. One might also wonder if you could provoke a read past the end of the string. But the answer is no; we still parse character by character, and would never advance past a NUL. This patch implements the minimal fix, along with documenting the restriction (which confused at least me while reading the code). We should possibly consider being more liberal in accepting valid shell-quoted words. I suspect the code may actually be simpler, and it would be more friendly to anybody generating or editing input by hand. But I wanted to fix just the immediate bug in this patch. We don't have a direct way to unit-test the sq_dequote() functions, but we can do this by feeding input to GIT_CONFIG_PARAMETERS (which is not normally a user-facing interface, but serves here as it expects to see sq_quote() input from "git -c"). I've included both a bogus example, and a related "good" one to confirm that we still parse it correctly. Noticed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-14 00:41:49 +01:00
git config --get-regexp "env.*" >actual &&
test_cmp expect actual &&
cat >expect <<-EOF &&
env.one one${SQ}
sq_dequote: fix extra consumption of source string This fixes a (probably harmless) parsing problem in sq_dequote_step(), in which we parse some bogus input incorrectly rather than complaining that it's bogus. Our shell-dequoting function is very strict: it can unquote everything generated by sq_quote(), but not arbitrary strings. In particular, it only allows characters outside of the single-quoted string if they are immediately backslashed and then the single-quoted string is resumed. So: 'foo'\''bar' is OK. But these are not: 'foo'\'bar 'foo'\' 'foo'\'\''bar' even though they are all valid shell. The parser has a funny corner case here. When we see a backslashed character, we keep incrementing the "src" pointer as we parse it. For a single sq_dequote() call, that's OK; our next step is to bail with an error, and we don't care where "src" points. But if we're parsing multiple strings with sq_dequote_to_argv(), then our next step is to see if the string is followed by whitespace. Because we erroneously incremented the "src" pointer, we don't barf on the bogus backslash that we skipped. Instead, we may find whitespace that immediately follows it, and continue as if all is well (skipping the backslashed character completely!). In practice, this shouldn't be a big deal. The input is bogus, and our sq_quote() would never generate this bogus input. In all but one callers, we are parsing input created by an earlier call to sq_quote(). That final case is "git shell", which parses shell-quoting generated by the client. And in that case we use the singular sq_quote(), which has always behaved correctly. One might also wonder if you could provoke a read past the end of the string. But the answer is no; we still parse character by character, and would never advance past a NUL. This patch implements the minimal fix, along with documenting the restriction (which confused at least me while reading the code). We should possibly consider being more liberal in accepting valid shell-quoted words. I suspect the code may actually be simpler, and it would be more friendly to anybody generating or editing input by hand. But I wanted to fix just the immediate bug in this patch. We don't have a direct way to unit-test the sq_dequote() functions, but we can do this by feeding input to GIT_CONFIG_PARAMETERS (which is not normally a user-facing interface, but serves here as it expects to see sq_quote() input from "git -c"). I've included both a bogus example, and a related "good" one to confirm that we still parse it correctly. Noticed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-14 00:41:49 +01:00
env.two two
EOF
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ$SQ$SQ ${SQ}env.two=two${SQ}" \
sq_dequote: fix extra consumption of source string This fixes a (probably harmless) parsing problem in sq_dequote_step(), in which we parse some bogus input incorrectly rather than complaining that it's bogus. Our shell-dequoting function is very strict: it can unquote everything generated by sq_quote(), but not arbitrary strings. In particular, it only allows characters outside of the single-quoted string if they are immediately backslashed and then the single-quoted string is resumed. So: 'foo'\''bar' is OK. But these are not: 'foo'\'bar 'foo'\' 'foo'\'\''bar' even though they are all valid shell. The parser has a funny corner case here. When we see a backslashed character, we keep incrementing the "src" pointer as we parse it. For a single sq_dequote() call, that's OK; our next step is to bail with an error, and we don't care where "src" points. But if we're parsing multiple strings with sq_dequote_to_argv(), then our next step is to see if the string is followed by whitespace. Because we erroneously incremented the "src" pointer, we don't barf on the bogus backslash that we skipped. Instead, we may find whitespace that immediately follows it, and continue as if all is well (skipping the backslashed character completely!). In practice, this shouldn't be a big deal. The input is bogus, and our sq_quote() would never generate this bogus input. In all but one callers, we are parsing input created by an earlier call to sq_quote(). That final case is "git shell", which parses shell-quoting generated by the client. And in that case we use the singular sq_quote(), which has always behaved correctly. One might also wonder if you could provoke a read past the end of the string. But the answer is no; we still parse character by character, and would never advance past a NUL. This patch implements the minimal fix, along with documenting the restriction (which confused at least me while reading the code). We should possibly consider being more liberal in accepting valid shell-quoted words. I suspect the code may actually be simpler, and it would be more friendly to anybody generating or editing input by hand. But I wanted to fix just the immediate bug in this patch. We don't have a direct way to unit-test the sq_dequote() functions, but we can do this by feeding input to GIT_CONFIG_PARAMETERS (which is not normally a user-facing interface, but serves here as it expects to see sq_quote() input from "git -c"). I've included both a bogus example, and a related "good" one to confirm that we still parse it correctly. Noticed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-14 00:41:49 +01:00
git config --get-regexp "env.*" >actual &&
test_cmp expect actual &&
test_must_fail env \
GIT_CONFIG_PARAMETERS="${SQ}env.one=one${SQ}\\$SQ ${SQ}env.two=two${SQ}" \
sq_dequote: fix extra consumption of source string This fixes a (probably harmless) parsing problem in sq_dequote_step(), in which we parse some bogus input incorrectly rather than complaining that it's bogus. Our shell-dequoting function is very strict: it can unquote everything generated by sq_quote(), but not arbitrary strings. In particular, it only allows characters outside of the single-quoted string if they are immediately backslashed and then the single-quoted string is resumed. So: 'foo'\''bar' is OK. But these are not: 'foo'\'bar 'foo'\' 'foo'\'\''bar' even though they are all valid shell. The parser has a funny corner case here. When we see a backslashed character, we keep incrementing the "src" pointer as we parse it. For a single sq_dequote() call, that's OK; our next step is to bail with an error, and we don't care where "src" points. But if we're parsing multiple strings with sq_dequote_to_argv(), then our next step is to see if the string is followed by whitespace. Because we erroneously incremented the "src" pointer, we don't barf on the bogus backslash that we skipped. Instead, we may find whitespace that immediately follows it, and continue as if all is well (skipping the backslashed character completely!). In practice, this shouldn't be a big deal. The input is bogus, and our sq_quote() would never generate this bogus input. In all but one callers, we are parsing input created by an earlier call to sq_quote(). That final case is "git shell", which parses shell-quoting generated by the client. And in that case we use the singular sq_quote(), which has always behaved correctly. One might also wonder if you could provoke a read past the end of the string. But the answer is no; we still parse character by character, and would never advance past a NUL. This patch implements the minimal fix, along with documenting the restriction (which confused at least me while reading the code). We should possibly consider being more liberal in accepting valid shell-quoted words. I suspect the code may actually be simpler, and it would be more friendly to anybody generating or editing input by hand. But I wanted to fix just the immediate bug in this patch. We don't have a direct way to unit-test the sq_dequote() functions, but we can do this by feeding input to GIT_CONFIG_PARAMETERS (which is not normally a user-facing interface, but serves here as it expects to see sq_quote() input from "git -c"). I've included both a bogus example, and a related "good" one to confirm that we still parse it correctly. Noticed-by: Michael Haggerty <mhagger@alum.mit.edu> Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-02-14 00:41:49 +01:00
git config --get-regexp "env.*"
'
test_expect_success 'git --config-env=key=envvar support' '
cat >expect <<-\EOF &&
value
value
false
EOF
{
ENVVAR=value git --config-env=core.name=ENVVAR config core.name &&
ENVVAR=value git --config-env=foo.CamelCase=ENVVAR config foo.camelcase &&
ENVVAR= git --config-env=foo.flag=ENVVAR config --bool foo.flag
} >actual &&
test_cmp expect actual
'
test_expect_success 'git --config-env fails with invalid parameters' '
test_must_fail git --config-env=foo.flag config --bool foo.flag 2>error &&
test_i18ngrep "invalid config format: foo.flag" error &&
test_must_fail git --config-env=foo.flag= config --bool foo.flag 2>error &&
test_i18ngrep "missing environment variable name for configuration ${SQ}foo.flag${SQ}" error &&
sane_unset NONEXISTENT &&
test_must_fail git --config-env=foo.flag=NONEXISTENT config --bool foo.flag 2>error &&
test_i18ngrep "missing environment variable ${SQ}NONEXISTENT${SQ} for configuration ${SQ}foo.flag${SQ}" error
'
test_expect_success 'git -c and --config-env work together' '
cat >expect <<-\EOF &&
bar.cmd cmd-value
bar.env env-value
EOF
ENVVAR=env-value git \
-c bar.cmd=cmd-value \
--config-env=bar.env=ENVVAR \
config --get-regexp "^bar.*" >actual &&
test_cmp expect actual
'
test_expect_success 'git -c and --config-env override each other' '
cat >expect <<-\EOF &&
env
cmd
EOF
{
ENVVAR=env git -c bar.bar=cmd --config-env=bar.bar=ENVVAR config bar.bar &&
ENVVAR=env git --config-env=bar.bar=ENVVAR -c bar.bar=cmd config bar.bar
} >actual &&
test_cmp expect actual
'
test_expect_success '--config-env handles keys with equals' '
echo value=with=equals >expect &&
ENVVAR=value=with=equals git \
--config-env=section.subsection=with=equals.key=ENVVAR \
config section.subsection=with=equals.key >actual &&
test_cmp expect actual
'
test_expect_success 'git config handles environment config pairs' '
GIT_CONFIG_COUNT=2 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="foo" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="bar" \
git config --get-regexp "pair.*" >actual &&
cat >expect <<-EOF &&
pair.one foo
pair.two bar
EOF
test_cmp expect actual
'
test_expect_success 'git config ignores pairs without count' '
test_must_fail env GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one 2>error &&
test_must_be_empty error
'
test_expect_success 'git config ignores pairs with zero count' '
test_must_fail env \
GIT_CONFIG_COUNT=0 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one
'
test_expect_success 'git config ignores pairs exceeding count' '
GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
GIT_CONFIG_KEY_1="pair.two" GIT_CONFIG_VALUE_1="value" \
git config --get-regexp "pair.*" >actual &&
cat >expect <<-EOF &&
pair.one value
EOF
test_cmp expect actual
'
test_expect_success 'git config ignores pairs with zero count' '
test_must_fail env \
GIT_CONFIG_COUNT=0 GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one >error &&
test_must_be_empty error
'
test_expect_success 'git config ignores pairs with empty count' '
test_must_fail env \
GIT_CONFIG_COUNT= GIT_CONFIG_KEY_0="pair.one" GIT_CONFIG_VALUE_0="value" \
git config pair.one >error &&
test_must_be_empty error
'
test_expect_success 'git config fails with invalid count' '
test_must_fail env GIT_CONFIG_COUNT=10a git config --list 2>error &&
test_i18ngrep "bogus count" error &&
test_must_fail env GIT_CONFIG_COUNT=9999999999999999 git config --list 2>error &&
test_i18ngrep "too many entries" error
'
test_expect_success 'git config fails with missing config key' '
test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_VALUE_0="value" \
git config --list 2>error &&
test_i18ngrep "missing config key" error
'
test_expect_success 'git config fails with missing config value' '
test_must_fail env GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0="pair.one" \
git config --list 2>error &&
test_i18ngrep "missing config value" error
'
test_expect_success 'git config fails with invalid config pair key' '
test_must_fail env GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0= GIT_CONFIG_VALUE_0=value \
git config --list &&
test_must_fail env GIT_CONFIG_COUNT=1 \
GIT_CONFIG_KEY_0=missing-section GIT_CONFIG_VALUE_0=value \
git config --list
'
test_expect_success 'environment overrides config file' '
test_when_finished "rm -f .git/config" &&
cat >.git/config <<-EOF &&
[pair]
one = value
EOF
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=override \
git config pair.one >actual &&
cat >expect <<-EOF &&
override
EOF
test_cmp expect actual
'
test_expect_success 'GIT_CONFIG_PARAMETERS overrides environment config' '
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \
GIT_CONFIG_PARAMETERS="${SQ}pair.one=override${SQ}" \
git config pair.one >actual &&
cat >expect <<-EOF &&
override
EOF
test_cmp expect actual
'
test_expect_success 'command line overrides environment config' '
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=pair.one GIT_CONFIG_VALUE_0=value \
git -c pair.one=override config pair.one >actual &&
cat >expect <<-EOF &&
override
EOF
test_cmp expect actual
'
test_expect_success 'git config --edit works' '
git config -f tmp test.value no &&
echo test.value=yes >expect &&
GIT_EDITOR="echo [test]value=yes >" git config -f tmp --edit &&
git config -f tmp --list >actual &&
test_cmp expect actual
'
test_expect_success 'git config --edit respects core.editor' '
git config -f tmp test.value no &&
echo test.value=yes >expect &&
test_config core.editor "echo [test]value=yes >" &&
git config -f tmp --edit &&
git config -f tmp --list >actual &&
test_cmp expect actual
'
# malformed configuration files
test_expect_success 'barf on syntax error' '
cat >.git/config <<-\EOF &&
# broken section line
[section]
key garbage
EOF
test_must_fail git config --get section.key >actual 2>error &&
test_i18ngrep " line 3 " error
'
test_expect_success 'barf on incomplete section header' '
cat >.git/config <<-\EOF &&
# broken section line
[section
key = value
EOF
test_must_fail git config --get section.key >actual 2>error &&
test_i18ngrep " line 2 " error
'
test_expect_success 'barf on incomplete string' '
cat >.git/config <<-\EOF &&
# broken section line
[section]
key = "value string
EOF
test_must_fail git config --get section.key >actual 2>error &&
test_i18ngrep " line 3 " error
'
test_expect_success 'urlmatch' '
cat >.git/config <<-\EOF &&
[http]
sslVerify
[http "https://weak.example.com"]
sslVerify = false
cookieFile = /tmp/cookie.txt
EOF
test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual &&
test_must_be_empty actual &&
echo true >expect &&
git config --bool --get-urlmatch http.SSLverify https://good.example.com >actual &&
test_cmp expect actual &&
echo false >expect &&
git config --bool --get-urlmatch http.sslverify https://weak.example.com >actual &&
test_cmp expect actual &&
{
echo http.cookiefile /tmp/cookie.txt &&
echo http.sslverify false
} >expect &&
git config --get-urlmatch HTTP https://weak.example.com >actual &&
test_cmp expect actual
'
test_expect_success 'urlmatch favors more specific URLs' '
cat >.git/config <<-\EOF &&
[http "https://example.com/"]
cookieFile = /tmp/root.txt
[http "https://example.com/subdirectory"]
cookieFile = /tmp/subdirectory.txt
[http "https://user@example.com/"]
cookieFile = /tmp/user.txt
[http "https://averylonguser@example.com/"]
cookieFile = /tmp/averylonguser.txt
[http "https://preceding.example.com"]
cookieFile = /tmp/preceding.txt
[http "https://*.example.com"]
cookieFile = /tmp/wildcard.txt
[http "https://*.example.com/wildcardwithsubdomain"]
cookieFile = /tmp/wildcardwithsubdomain.txt
[http "https://*.example.*"]
cookieFile = /tmp/multiwildcard.txt
[http "https://trailing.example.com"]
cookieFile = /tmp/trailing.txt
[http "https://user@*.example.com/"]
cookieFile = /tmp/wildcardwithuser.txt
[http "https://sub.example.com/"]
cookieFile = /tmp/sub.txt
EOF
echo http.cookiefile /tmp/root.txt >expect &&
git config --get-urlmatch HTTP https://example.com >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://example.com/subdirectory >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://example.com/subdirectory/nested >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/user.txt >expect &&
git config --get-urlmatch HTTP https://user@example.com/ >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/subdirectory.txt >expect &&
git config --get-urlmatch HTTP https://averylonguser@example.com/subdirectory >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/preceding.txt >expect &&
git config --get-urlmatch HTTP https://preceding.example.com >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/wildcard.txt >expect &&
git config --get-urlmatch HTTP https://wildcard.example.com >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/sub.txt >expect &&
git config --get-urlmatch HTTP https://sub.example.com/wildcardwithsubdomain >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/trailing.txt >expect &&
git config --get-urlmatch HTTP https://trailing.example.com >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/sub.txt >expect &&
git config --get-urlmatch HTTP https://user@sub.example.com >actual &&
test_cmp expect actual &&
echo http.cookiefile /tmp/multiwildcard.txt >expect &&
git config --get-urlmatch HTTP https://wildcard.example.org >actual &&
test_cmp expect actual
'
test_expect_success 'urlmatch with wildcard' '
cat >.git/config <<-\EOF &&
[http]
sslVerify
[http "https://*.example.com"]
sslVerify = false
cookieFile = /tmp/cookie.txt
EOF
test_expect_code 1 git config --bool --get-urlmatch doesnt.exist https://good.example.com >actual &&
test_must_be_empty actual &&
echo true >expect &&
git config --bool --get-urlmatch http.SSLverify https://example.com >actual &&
test_cmp expect actual &&
echo true >expect &&
git config --bool --get-urlmatch http.SSLverify https://good-example.com >actual &&
test_cmp expect actual &&
echo true >expect &&
git config --bool --get-urlmatch http.sslverify https://deep.nested.example.com >actual &&
test_cmp expect actual &&
echo false >expect &&
git config --bool --get-urlmatch http.sslverify https://good.example.com >actual &&
test_cmp expect actual &&
{
echo http.cookiefile /tmp/cookie.txt &&
echo http.sslverify false
} >expect &&
git config --get-urlmatch HTTP https://good.example.com >actual &&
test_cmp expect actual &&
echo http.sslverify >expect &&
git config --get-urlmatch HTTP https://more.example.com.au >actual &&
test_cmp expect actual
'
# good section hygiene
git config --unset: remove empty sections (in the common case) The original reasoning for not removing section headers upon removal of the last entry went like this: the user could have added comments about the section, or about the entries therein, and if there were other comments there, we would not know whether we should remove them. In particular, a concocted example was presented that looked like this (and was added to t1300): # some generic comment on the configuration file itself # a comment specific to this "section" section. [section] # some intervening lines # that should also be dropped key = value # please be careful when you update the above variable The ideal thing for `git config --unset section.key` in this case would be to leave only the first line behind, because all the other comments are now obsolete. However, this is unfeasible, short of adding a complete Natural Language Processing module to Git, which seems not only a lot of work, but a totally unreasonable feature (for little benefit to most users). Now, the real kicker about this problem is: most users do not edit their config files at all! In their use case, the config looks like this instead: [section] key = value ... and it is totally obvious what should happen if the entry is removed: the entire section should vanish. Let's generalize this observation to this conservative strategy: if we are removing the last entry from a section, and there are no comments inside that section nor surrounding it, then remove the entire section. Otherwise behave as before: leave the now-empty section (including those comments, even ones about the now-deleted entry). We have to be extra careful to handle the case where more than one entry is removed: any subset of them might be the last entries of their respective sections (and if there are no comments in or around that section, the section should be removed, too). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 10:32:24 +02:00
test_expect_success '--unset last key removes section (except if commented)' '
cat >.git/config <<-\EOF &&
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
key = value
# please be careful when you update the above variable
EOF
cat >expect <<-\EOF &&
# some generic comment on the configuration file itself
# a comment specific to this "section" section.
[section]
# some intervening lines
# that should also be dropped
# please be careful when you update the above variable
EOF
git config --unset section.key &&
test_cmp expect .git/config &&
cat >.git/config <<-\EOF &&
[section]
key = value
[next-section]
EOF
cat >expect <<-\EOF &&
[next-section]
EOF
git config --unset section.key &&
test_cmp expect .git/config &&
q_to_tab >.git/config <<-\EOF &&
[one]
Qkey = "multiline \
QQ# with comment"
[two]
key = true
EOF
git config --unset two.key &&
! grep two .git/config &&
q_to_tab >.git/config <<-\EOF &&
[one]
Qkey = "multiline \
QQ# with comment"
[one]
key = true
EOF
git config --unset-all one.key &&
test_line_count = 0 .git/config &&
q_to_tab >.git/config <<-\EOF &&
[one]
Qkey = true
Q# a comment not at the start
[two]
Qkey = true
EOF
git config --unset two.key &&
grep two .git/config &&
q_to_tab >.git/config <<-\EOF &&
[one]
Qkey = not [two "subsection"]
[two "subsection"]
[two "subsection"]
Qkey = true
[TWO "subsection"]
[one]
EOF
git config --unset two.subsection.key &&
test "not [two subsection]" = "$(git config one.key)" &&
test_line_count = 3 .git/config
'
git config --unset: remove empty sections (in the common case) The original reasoning for not removing section headers upon removal of the last entry went like this: the user could have added comments about the section, or about the entries therein, and if there were other comments there, we would not know whether we should remove them. In particular, a concocted example was presented that looked like this (and was added to t1300): # some generic comment on the configuration file itself # a comment specific to this "section" section. [section] # some intervening lines # that should also be dropped key = value # please be careful when you update the above variable The ideal thing for `git config --unset section.key` in this case would be to leave only the first line behind, because all the other comments are now obsolete. However, this is unfeasible, short of adding a complete Natural Language Processing module to Git, which seems not only a lot of work, but a totally unreasonable feature (for little benefit to most users). Now, the real kicker about this problem is: most users do not edit their config files at all! In their use case, the config looks like this instead: [section] key = value ... and it is totally obvious what should happen if the entry is removed: the entire section should vanish. Let's generalize this observation to this conservative strategy: if we are removing the last entry from a section, and there are no comments inside that section nor surrounding it, then remove the entire section. Otherwise behave as before: leave the now-empty section (including those comments, even ones about the now-deleted entry). We have to be extra careful to handle the case where more than one entry is removed: any subset of them might be the last entries of their respective sections (and if there are no comments in or around that section, the section should be removed, too). Signed-off-by: Johannes Schindelin <johannes.schindelin@gmx.de> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2018-04-09 10:32:24 +02:00
test_expect_success '--unset-all removes section if empty & uncommented' '
cat >.git/config <<-\EOF &&
[section]
key = value1
key = value2
EOF
git config --unset-all section.key &&
test_line_count = 0 .git/config
'
test_expect_success 'adding a key into an empty section reuses header' '
cat >.git/config <<-\EOF &&
[section]
EOF
q_to_tab >expect <<-\EOF &&
[section]
Qkey = value
EOF
git config section.key value &&
test_cmp expect .git/config
'
test_expect_success POSIXPERM,PERL 'preserves existing permissions' '
chmod 0600 .git/config &&
git config imap.pass Hunter2 &&
perl -e \
"die q(badset) if ((stat(q(.git/config)))[2] & 07777) != 0600" &&
git config --rename-section imap pop &&
perl -e \
"die q(badrename) if ((stat(q(.git/config)))[2] & 07777) != 0600"
'
! test_have_prereq MINGW ||
HOME="$(pwd)" # convert to Windows path
test_expect_success 'set up --show-origin tests' '
INCLUDE_DIR="$HOME/include" &&
mkdir -p "$INCLUDE_DIR" &&
cat >"$INCLUDE_DIR"/absolute.include <<-\EOF &&
[user]
absolute = include
EOF
cat >"$INCLUDE_DIR"/relative.include <<-\EOF &&
[user]
relative = include
EOF
cat >"$HOME"/.gitconfig <<-EOF &&
[user]
global = true
override = global
[include]
path = "$INCLUDE_DIR/absolute.include"
EOF
cat >.git/config <<-\EOF
[user]
local = true
override = local
[include]
path = ../include/relative.include
EOF
'
test_expect_success '--show-origin with --list' '
cat >expect <<-EOF &&
file:$HOME/.gitconfig user.global=true
file:$HOME/.gitconfig user.override=global
file:$HOME/.gitconfig include.path=$INCLUDE_DIR/absolute.include
file:$INCLUDE_DIR/absolute.include user.absolute=include
file:.git/config user.local=true
file:.git/config user.override=local
file:.git/config include.path=../include/relative.include
file:.git/../include/relative.include user.relative=include
command line: user.environ=true
command line: user.cmdline=true
EOF
GIT_CONFIG_COUNT=1 GIT_CONFIG_KEY_0=user.environ GIT_CONFIG_VALUE_0=true\
git -c user.cmdline=true config --list --show-origin >output &&
test_cmp expect output
'
test_expect_success '--show-origin with --list --null' '
cat >expect <<-EOF &&
file:$HOME/.gitconfigQuser.global
trueQfile:$HOME/.gitconfigQuser.override
globalQfile:$HOME/.gitconfigQinclude.path
$INCLUDE_DIR/absolute.includeQfile:$INCLUDE_DIR/absolute.includeQuser.absolute
includeQfile:.git/configQuser.local
trueQfile:.git/configQuser.override
localQfile:.git/configQinclude.path
../include/relative.includeQfile:.git/../include/relative.includeQuser.relative
includeQcommand line:Quser.cmdline
trueQ
EOF
git -c user.cmdline=true config --null --list --show-origin >output.raw &&
nul_to_q <output.raw >output &&
# The here-doc above adds a newline that the --null output would not
# include. Add it here to make the two comparable.
echo >>output &&
test_cmp expect output
'
test_expect_success '--show-origin with single file' '
cat >expect <<-\EOF &&
file:.git/config user.local=true
file:.git/config user.override=local
file:.git/config include.path=../include/relative.include
EOF
git config --local --list --show-origin >output &&
test_cmp expect output
'
test_expect_success '--show-origin with --get-regexp' '
cat >expect <<-EOF &&
file:$HOME/.gitconfig user.global true
file:.git/config user.local true
EOF
git config --show-origin --get-regexp "user\.[g|l].*" >output &&
test_cmp expect output
'
test_expect_success '--show-origin getting a single key' '
cat >expect <<-\EOF &&
file:.git/config local
EOF
git config --show-origin user.override >output &&
test_cmp expect output
'
test_expect_success 'set up custom config file' '
CUSTOM_CONFIG_FILE="custom.conf" &&
cat >"$CUSTOM_CONFIG_FILE" <<-\EOF
[user]
custom = true
EOF
'
test_expect_success !MINGW 'set up custom config file with special name characters' '
WEIRDLY_NAMED_FILE="file\" (dq) and spaces.conf" &&
cp "$CUSTOM_CONFIG_FILE" "$WEIRDLY_NAMED_FILE"
'
test_expect_success !MINGW '--show-origin escape special file name characters' '
cat >expect <<-\EOF &&
file:"file\" (dq) and spaces.conf" user.custom=true
EOF
git config --file "$WEIRDLY_NAMED_FILE" --show-origin --list >output &&
test_cmp expect output
'
test_expect_success '--show-origin stdin' '
cat >expect <<-\EOF &&
standard input: user.custom=true
EOF
git config --file - --show-origin --list <"$CUSTOM_CONFIG_FILE" >output &&
test_cmp expect output
'
test_expect_success '--show-origin stdin with file include' '
cat >"$INCLUDE_DIR"/stdin.include <<-EOF &&
[user]
stdin = include
EOF
cat >expect <<-EOF &&
file:$INCLUDE_DIR/stdin.include include
EOF
echo "[include]path=\"$INCLUDE_DIR\"/stdin.include" |
git config --show-origin --includes --file - user.stdin >output &&
test_cmp expect output
'
test_expect_success '--show-origin blob' '
blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
cat >expect <<-EOF &&
blob:$blob user.custom=true
EOF
git config --blob=$blob --show-origin --list >output &&
test_cmp expect output
'
test_expect_success '--show-origin blob ref' '
cat >expect <<-\EOF &&
blob:main:custom.conf user.custom=true
EOF
git add "$CUSTOM_CONFIG_FILE" &&
git commit -m "new config file" &&
git config --blob=main:"$CUSTOM_CONFIG_FILE" --show-origin --list >output &&
test_cmp expect output
'
test_expect_success '--show-scope with --list' '
cat >expect <<-EOF &&
global user.global=true
global user.override=global
global include.path=$INCLUDE_DIR/absolute.include
global user.absolute=include
local user.local=true
local user.override=local
local include.path=../include/relative.include
local user.relative=include
command user.cmdline=true
EOF
git -c user.cmdline=true config --list --show-scope >output &&
test_cmp expect output
'
test_expect_success !MINGW '--show-scope with --blob' '
blob=$(git hash-object -w "$CUSTOM_CONFIG_FILE") &&
cat >expect <<-EOF &&
command user.custom=true
EOF
git config --blob=$blob --show-scope --list >output &&
test_cmp expect output
'
test_expect_success '--show-scope with --local' '
cat >expect <<-\EOF &&
local user.local=true
local user.override=local
local include.path=../include/relative.include
EOF
git config --local --list --show-scope >output &&
test_cmp expect output
'
test_expect_success '--show-scope getting a single value' '
cat >expect <<-\EOF &&
local true
EOF
git config --show-scope --get user.local >output &&
test_cmp expect output
'
test_expect_success '--show-scope with --show-origin' '
cat >expect <<-EOF &&
global file:$HOME/.gitconfig user.global=true
global file:$HOME/.gitconfig user.override=global
global file:$HOME/.gitconfig include.path=$INCLUDE_DIR/absolute.include
global file:$INCLUDE_DIR/absolute.include user.absolute=include
local file:.git/config user.local=true
local file:.git/config user.override=local
local file:.git/config include.path=../include/relative.include
local file:.git/../include/relative.include user.relative=include
command command line: user.cmdline=true
EOF
git -c user.cmdline=true config --list --show-origin --show-scope >output &&
test_cmp expect output
'
for opt in --local --worktree
do
test_expect_success "$opt requires a repo" '
# we expect 128 to ensure that we do not simply
# fail to find anything and return code "1"
test_expect_code 128 nongit git config $opt foo.bar
'
done
cat >.git/config <<-\EOF &&
[section]
foo = true
number = 10
big = 1M
EOF
test_expect_success 'identical modern --type specifiers are allowed' '
test_cmp_config 1048576 --type=int --type=int section.big
'
test_expect_success 'identical legacy --type specifiers are allowed' '
test_cmp_config 1048576 --int --int section.big
'
test_expect_success 'identical mixed --type specifiers are allowed' '
test_cmp_config 1048576 --int --type=int section.big
'
test_expect_success 'non-identical modern --type specifiers are not allowed' '
test_must_fail git config --type=int --type=bool section.big 2>error &&
test_i18ngrep "only one type at a time" error
'
test_expect_success 'non-identical legacy --type specifiers are not allowed' '
test_must_fail git config --int --bool section.big 2>error &&
test_i18ngrep "only one type at a time" error
'
test_expect_success 'non-identical mixed --type specifiers are not allowed' '
test_must_fail git config --type=int --bool section.big 2>error &&
test_i18ngrep "only one type at a time" error
'
test_expect_success '--type allows valid type specifiers' '
test_cmp_config true --type=bool section.foo
'
test_expect_success '--no-type unsets type specifiers' '
test_cmp_config 10 --type=bool --no-type section.number
'
test_expect_success 'unset type specifiers may be reset to conflicting ones' '
test_cmp_config 1048576 --type=bool --no-type --type=int section.big
'
test_expect_success '--type rejects unknown specifiers' '
test_must_fail git config --type=nonsense section.foo 2>error &&
test_i18ngrep "unrecognized --type argument" error
'
test_expect_success '--replace-all does not invent newlines' '
q_to_tab >.git/config <<-\EOF &&
[abc]key
QkeepSection
[xyz]
Qkey = 1
[abc]
Qkey = a
EOF
q_to_tab >expect <<-\EOF &&
[abc]
QkeepSection
[xyz]
Qkey = 1
[abc]
Qkey = b
EOF
git config --replace-all abc.key b &&
test_cmp expect .git/config
'
test_expect_success 'set all config with value-pattern' '
test_when_finished rm -f config initial &&
git config --file=initial abc.key one &&
# no match => add new entry
cp initial config &&
git config --file=config abc.key two a+ &&
git config --file=config --list >actual &&
cat >expect <<-\EOF &&
abc.key=one
abc.key=two
EOF
test_cmp expect actual &&
# multiple matches => failure
test_must_fail git config --file=config abc.key three o+ 2>err &&
test_i18ngrep "has multiple values" err &&
# multiple values, no match => add
git config --file=config abc.key three a+ &&
git config --file=config --list >actual &&
cat >expect <<-\EOF &&
abc.key=one
abc.key=two
abc.key=three
EOF
test_cmp expect actual &&
# single match => replace
git config --file=config abc.key four h+ &&
git config --file=config --list >actual &&
cat >expect <<-\EOF &&
abc.key=one
abc.key=two
abc.key=four
EOF
test_cmp expect actual
'
test_expect_success '--replace-all and value-pattern' '
test_when_finished rm -f config &&
git config --file=config --add abc.key one &&
git config --file=config --add abc.key two &&
git config --file=config --add abc.key three &&
git config --file=config --replace-all abc.key four "o+" &&
git config --file=config --list >actual &&
cat >expect <<-\EOF &&
abc.key=four
abc.key=three
EOF
test_cmp expect actual
'
test_expect_success 'refuse --fixed-value for incompatible actions' '
test_when_finished rm -f config &&
git config --file=config dev.null bogus &&
# These modes do not allow --fixed-value at all
test_must_fail git config --file=config --fixed-value --add dev.null bogus &&
test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus &&
test_must_fail git config --file=config --fixed-value --get-urlmatch dev.null bogus &&
test_must_fail git config --file=config --fixed-value --rename-section dev null &&
test_must_fail git config --file=config --fixed-value --remove-section dev &&
test_must_fail git config --file=config --fixed-value --list &&
test_must_fail git config --file=config --fixed-value --get-color dev.null &&
test_must_fail git config --file=config --fixed-value --get-colorbool dev.null &&
# These modes complain when --fixed-value has no value-pattern
test_must_fail git config --file=config --fixed-value dev.null bogus &&
test_must_fail git config --file=config --fixed-value --replace-all dev.null bogus &&
test_must_fail git config --file=config --fixed-value --get dev.null &&
test_must_fail git config --file=config --fixed-value --get-all dev.null &&
test_must_fail git config --file=config --fixed-value --get-regexp "dev.*" &&
test_must_fail git config --file=config --fixed-value --unset dev.null &&
test_must_fail git config --file=config --fixed-value --unset-all dev.null
'
test_expect_success '--fixed-value uses exact string matching' '
test_when_finished rm -f config initial &&
META="a+b*c?d[e]f.g" &&
git config --file=initial fixed.test "$META" &&
cp initial config &&
git config --file=config fixed.test bogus "$META" &&
git config --file=config --list >actual &&
cat >expect <<-EOF &&
fixed.test=$META
fixed.test=bogus
EOF
test_cmp expect actual &&
cp initial config &&
git config --file=config --fixed-value fixed.test bogus "$META" &&
git config --file=config --list >actual &&
cat >expect <<-\EOF &&
fixed.test=bogus
EOF
test_cmp expect actual &&
cp initial config &&
test_must_fail git config --file=config --unset fixed.test "$META" &&
git config --file=config --fixed-value --unset fixed.test "$META" &&
test_must_fail git config --file=config fixed.test &&
cp initial config &&
test_must_fail git config --file=config --unset-all fixed.test "$META" &&
git config --file=config --fixed-value --unset-all fixed.test "$META" &&
test_must_fail git config --file=config fixed.test &&
cp initial config &&
git config --file=config --replace-all fixed.test bogus "$META" &&
git config --file=config --list >actual &&
cat >expect <<-EOF &&
fixed.test=$META
fixed.test=bogus
EOF
test_cmp expect actual &&
git config --file=config --fixed-value --replace-all fixed.test bogus "$META" &&
git config --file=config --list >actual &&
cat >expect <<-EOF &&
fixed.test=bogus
fixed.test=bogus
EOF
test_cmp expect actual
'
test_expect_success '--get and --get-all with --fixed-value' '
test_when_finished rm -f config &&
META="a+b*c?d[e]f.g" &&
git config --file=config fixed.test bogus &&
git config --file=config --add fixed.test "$META" &&
git config --file=config --get fixed.test bogus &&
test_must_fail git config --file=config --get fixed.test "$META" &&
git config --file=config --get --fixed-value fixed.test "$META" &&
test_must_fail git config --file=config --get --fixed-value fixed.test non-existent &&
git config --file=config --get-all fixed.test bogus &&
test_must_fail git config --file=config --get-all fixed.test "$META" &&
git config --file=config --get-all --fixed-value fixed.test "$META" &&
test_must_fail git config --file=config --get-all --fixed-value fixed.test non-existent &&
git config --file=config --get-regexp fixed+ bogus &&
test_must_fail git config --file=config --get-regexp fixed+ "$META" &&
git config --file=config --get-regexp --fixed-value fixed+ "$META" &&
test_must_fail git config --file=config --get-regexp --fixed-value fixed+ non-existent
'
test_done