From 0e94ee9415e6cf6952b755347b57319e93356210 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:17 -0700 Subject: hash-object: always try to set up the git repository When "hash-object" is run without "-w", we don't need to be in a git repository at all; we can just hash the object and write its sha1 to stdout. However, if we _are_ in a git repository, we would want to know that so we can follow the normal rules for respecting config, .gitattributes, etc. This happens to work at the top-level of a git repository because we blindly read ".git/config", but as the included test shows, it does not work when you are in a subdirectory. The solution is to just do a "gentle" setup in this case. We already take care to use prefix_filename() on any filename arguments we get (to handle the "-w" case), so we don't need to do anything extra to handle the side effects of repo setup. An alternative would be to specify RUN_SETUP_GENTLY for this command in git.c, and then die if "-w" is set but we are not in a repository. However, the error messages generated at the time of setup_git_directory() are more detailed, so it's better to find out which mode we are in, and then call the appropriate function. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t1007-hash-object.sh | 11 +++++++++++ 1 file changed, 11 insertions(+) (limited to 't') diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 7d2baa15bb..285871c24d 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -121,6 +121,17 @@ test_expect_success 'check that appropriate filter is invoke when --path is used git config --unset core.autocrlf ' +test_expect_success 'gitattributes also work in a subdirectory' ' + mkdir subdir && + ( + cd subdir && + subdir_sha0=$(git hash-object ../file0) && + subdir_sha1=$(git hash-object ../file1) && + test "$file0_sha" = "$subdir_sha0" && + test "$file1_sha" = "$subdir_sha1" + ) +' + test_expect_success 'check that --no-filters option works' ' echo fooQ | tr Q "\\015" >file0 && cp file0 file1 && -- cgit v1.2.3 From 4a73aaaf18099ec1897330dd6c4a09f10ea2f573 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:22 -0700 Subject: patch-id: use RUN_SETUP_GENTLY Patch-id does not require a repository because it is just processing the incoming diff on stdin, but it may look at git config for keys like patchid.stable. Even though we do not setup_git_directory(), this works from the top-level of a repository because we blindly look at ".git/config" in this case. But as the included test demonstrates, it does not work from a subdirectory. We can fix it by using RUN_SETUP_GENTLY. We do not take any filenames from the user on the command line, so there's no need to adjust them via prefix_filename(). Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t4204-patch-id.sh | 14 ++++++++++++++ 1 file changed, 14 insertions(+) (limited to 't') diff --git a/t/t4204-patch-id.sh b/t/t4204-patch-id.sh index baa9d3c82e..10b6ad02e2 100755 --- a/t/t4204-patch-id.sh +++ b/t/t4204-patch-id.sh @@ -143,6 +143,20 @@ test_expect_success 'patch-id supports git-format-patch MIME output' ' test_cmp patch-id_master patch-id_same ' +test_expect_success 'patch-id respects config from subdir' ' + test_config patchid.stable true && + mkdir subdir && + + # copy these because test_patch_id() looks for them in + # the current directory + cp bar-then-foo foo-then-bar subdir && + + ( + cd subdir && + test_patch_id irrelevant patchid.stable=true + ) +' + cat >nonl <<\EOF diff --git i/a w/a index e69de29..2e65efe 100644 -- cgit v1.2.3 From 7d8930d903fd8b775a1db63bcf373df5ac5af0be Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:32 -0700 Subject: diff: handle --no-index prefixes consistently If we see an explicit "git diff --no-index ../foo ../bar", then we do not set up the git repository at all (we already know we are in --no-index mode, so do not have to check "are we in a repository?"), and hence have no "prefix" within the repository. A patch generated by this command will have the filenames "a/../foo" and "b/../bar", no matter which directory we are in with respect to any repository. However, in the implicit case, where we notice that the files are outside the repository, we will have chdir()'d to the top-level of the repository. We then feed the prefix back to the diff machinery. As a result, running the same diff from a subdirectory will result in paths that look like "a/subdir/../../foo". Besides being unnecessarily long, this may also be confusing to the user: they don't care about the subdir or the repository at all; it's just where they happened to be when running the command. We should treat this the same as the explicit --no-index case. One way to address this would be to chdir() back to the original path before running our diff. However, that's a bit hacky, as we would also need to adjust $GIT_DIR, which could be a relative path from our top-level. Instead, we can reuse the diff machinery's RELATIVE_NAME option, which automatically strips off the prefix. Note that this _also_ restricts the diff to this relative prefix, but that's OK for our purposes: we queue our own diff pairs manually, and do not rely on that part of the diff code. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t4053-diff-no-index.sh | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) (limited to 't') diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index 6eb83211b5..e60c951180 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -89,4 +89,22 @@ test_expect_success 'turning a file into a directory' ' ) ' +test_expect_success 'diff from repo subdir shows real paths (explicit)' ' + echo "diff --git a/../../non/git/a b/../../non/git/b" >expect && + test_expect_code 1 \ + git -C repo/sub \ + diff --no-index ../../non/git/a ../../non/git/b >actual && + head -n 1 actual.head && + test_cmp expect actual.head +' + +test_expect_success 'diff from repo subdir shows real paths (implicit)' ' + echo "diff --git a/../../non/git/a b/../../non/git/b" >expect && + test_expect_code 1 \ + git -C repo/sub \ + diff ../../non/git/a ../../non/git/b >actual && + head -n 1 actual.head && + test_cmp expect actual.head +' + test_done -- cgit v1.2.3 From 28a4e580218b79dd5a7d55c2a30431469129321d Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:36 -0700 Subject: diff: always try to set up the repository If we see an explicit "--no-index", we do not bother calling setup_git_directory_gently() at all. This means that we may miss out on reading repo-specific config. It's arguable whether this is correct or not. If we were designing from scratch, making "git diff --no-index" completely ignore the repository makes some sense. But we are nowhere near scratch, so let's look at the existing behavior: 1. If you're in the top-level of a repository and run an explicit "diff --no-index", the config subsystem falls back to reading ".git/config", and we will respect repo config. 2. If you're in a subdirectory of a repository, then we still try to read ".git/config", but it generally doesn't exist. So "diff --no-index" there does not respect repo config. 3. If you have $GIT_DIR set in the environment, we read and respect $GIT_DIR/config, 4. If you run "git diff /tmp/foo /tmp/bar" to get an implicit no-index, we _do_ run the repository setup, and set $GIT_DIR (or respect an existing $GIT_DIR variable). We find the repo config no matter where we started, and respect it. So we already respect the repository config in a number of common cases, and case (2) is the only one that does not. And at least one of our tests, t4034, depends on case (1) behaving as it does now (though it is just incidental, not an explicit test for this behavior). So let's bring case (2) in line with the others by always running the repository setup, even with an explicit "--no-index". We shouldn't need to change anything else, as the implicit case already handles the prefix. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t4053-diff-no-index.sh | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) (limited to 't') diff --git a/t/t4053-diff-no-index.sh b/t/t4053-diff-no-index.sh index e60c951180..453e6c35eb 100755 --- a/t/t4053-diff-no-index.sh +++ b/t/t4053-diff-no-index.sh @@ -107,4 +107,24 @@ test_expect_success 'diff from repo subdir shows real paths (implicit)' ' test_cmp expect actual.head ' +test_expect_success 'diff --no-index from repo subdir respects config (explicit)' ' + echo "diff --git ../../non/git/a ../../non/git/b" >expect && + test_config -C repo diff.noprefix true && + test_expect_code 1 \ + git -C repo/sub \ + diff --no-index ../../non/git/a ../../non/git/b >actual && + head -n 1 actual.head && + test_cmp expect actual.head +' + +test_expect_success 'diff --no-index from repo subdir respects config (implicit)' ' + echo "diff --git ../../non/git/a ../../non/git/b" >expect && + test_config -C repo diff.noprefix true && + test_expect_code 1 \ + git -C repo/sub \ + diff ../../non/git/a ../../non/git/b >actual && + head -n 1 actual.head && + test_cmp expect actual.head +' + test_done -- cgit v1.2.3 From 11ca4bec96e00f7ed18dbd2a475a8d568f4b85f3 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:24:00 -0700 Subject: t1302: use "git -C" This is shorter, and saves a subshell. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t1302-repo-version.sh | 30 ++++++------------------------ 1 file changed, 6 insertions(+), 24 deletions(-) (limited to 't') diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh index 9bcd34969f..f859809b36 100755 --- a/t/t1302-repo-version.sh +++ b/t/t1302-repo-version.sh @@ -25,10 +25,7 @@ test_expect_success 'setup' ' test_expect_success 'gitdir selection on normal repos' ' echo 0 >expect && git config core.repositoryformatversion >actual && - ( - cd test && - git config core.repositoryformatversion >../actual2 - ) && + git -C test config core.repositoryformatversion >actual2 && test_cmp expect actual && test_cmp expect actual2 ' @@ -36,35 +33,20 @@ test_expect_success 'gitdir selection on normal repos' ' test_expect_success 'gitdir selection on unsupported repo' ' # Make sure it would stop at test2, not trash echo 99 >expect && - ( - cd test2 && - git config core.repositoryformatversion >../actual - ) && + git -C test2 config core.repositoryformatversion >actual && test_cmp expect actual ' test_expect_success 'gitdir not required mode' ' git apply --stat test.patch && - ( - cd test && - git apply --stat ../test.patch - ) && - ( - cd test2 && - git apply --stat ../test.patch - ) + git -C test apply --stat ../test.patch && + git -C test2 apply --stat ../test.patch ' test_expect_success 'gitdir required mode' ' git apply --check --index test.patch && - ( - cd test && - git apply --check --index ../test.patch - ) && - ( - cd test2 && - test_must_fail git apply --check --index ../test.patch - ) + git -C test apply --check --index ../test.patch && + test_must_fail git -C test2 apply --check --index ../test.patch ' check_allow () { -- cgit v1.2.3 From b9605bc4f2e44042824571f70b9a3a74eeebabff Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:24:15 -0700 Subject: config: only read .git/config from configured repos When git_config() runs, it looks in the system, user-wide, and repo-level config files. It gets the latter by calling git_pathdup(), which in turn calls get_git_dir(). If we haven't set up the git repository yet, this may simply return ".git", and we will look at ".git/config". This seems like it would be helpful (presumably we haven't set up the repository yet, so it tries to find it), but it turns out to be a bad idea for a few reasons: - it's not sufficient, and therefore hides bugs in a confusing way. Config will be respected if commands are run from the top-level of the working tree, but not from a subdirectory. - it's not always true that we haven't set up the repository _yet_; we may not want to do it at all. For instance, if you run "git init /some/path" from inside another repository, it should not load config from the existing repository. - there might be a path ".git/config", but it is not the actual repository we would find via setup_git_directory(). This may happen, e.g., if you are storing a git repository inside another git repository, but have munged one of the files in such a way that the inner repository is not valid (e.g., by removing HEAD). We have at least two bugs of the second type in git-init, introduced by ae5f677 (lazily load core.sharedrepository, 2016-03-11). It causes init to use git_configset(), which loads all of the config, including values from the current repo (if any). This shows up in two ways: 1. If we happen to be in an existing repository directory, we'll read and respect core.sharedrepository from it, even though it should have no bearing on the new repository. A new test in t1301 covers this. 2. Similarly, if we're in an existing repo that sets core.logallrefupdates, that will cause init to fail to set it in a newly created repository (because it thinks that the user's templates already did so). A new test in t0001 covers this. We also need to adjust an existing test in t1302, which gives another example of why this patch is an improvement. That test creates an embedded repository with a bogus core.repositoryformatversion of "99". It wants to make sure that we actually stop at the bogus repo rather than continuing upward to find the outer repo. So it checks that "git config core.repositoryformatversion" returns 99. But that only works because we blindly read ".git/config", even though we _know_ we're in a repository whose vintage we do not understand. After this patch, we avoid reading config from the unknown vintage repository at all, which is a safer choice. But we need to tweak the test, since core.repositoryformatversion will not return 99; it will claim that it could not find the variable at all. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t0001-init.sh | 9 +++++++++ t/t1301-shared-repo.sh | 9 +++++++++ t/t1302-repo-version.sh | 4 +--- 3 files changed, 19 insertions(+), 3 deletions(-) (limited to 't') diff --git a/t/t0001-init.sh b/t/t0001-init.sh index a6fdd5ef3a..8ffbbea4d6 100755 --- a/t/t0001-init.sh +++ b/t/t0001-init.sh @@ -384,4 +384,13 @@ test_expect_success MINGW 'bare git dir not hidden' ' ! is_hidden newdir ' +test_expect_success 'remote init from does not use config from cwd' ' + rm -rf newdir && + test_config core.logallrefupdates true && + git init newdir && + echo true >expect && + git -C newdir config --bool core.logallrefupdates >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index ac10875408..7c28642f2e 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -172,4 +172,13 @@ test_expect_success POSIXPERM 'forced modes' ' }" actual)" ' +test_expect_success POSIXPERM 'remote init does not use config from cwd' ' + git config core.sharedrepository 0666 && + umask 0022 && + git init --bare child.git && + echo "-rw-r--r--" >expect && + modebits child.git/config >actual && + test_cmp expect actual +' + test_done diff --git a/t/t1302-repo-version.sh b/t/t1302-repo-version.sh index f859809b36..ce4cff13bb 100755 --- a/t/t1302-repo-version.sh +++ b/t/t1302-repo-version.sh @@ -32,9 +32,7 @@ test_expect_success 'gitdir selection on normal repos' ' test_expect_success 'gitdir selection on unsupported repo' ' # Make sure it would stop at test2, not trash - echo 99 >expect && - git -C test2 config core.repositoryformatversion >actual && - test_cmp expect actual + test_expect_code 1 git -C test2 config core.repositoryformatversion >actual ' test_expect_success 'gitdir not required mode' ' -- cgit v1.2.3 From 4543926ba8f8ec596dd4e45f206f4fbc29350567 Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:24:23 -0700 Subject: init: reset cached config when entering new repo After we copy the templates into place, we re-read the config in case we copied in a default config file. But since git_config() is backed by a cache these days, it's possible that the call will not actually touch the filesystem at all; we need to tell it that something has changed behind the scenes. Note that we also need to reset the shared_repository config. At first glance, it seems like this should probably just be folded into git_config_clear(). But unfortunately that is not quite right. The shared repository value may come from config, _or_ it may have been set manually. So only the caller who knows whether or not they set it is the one who can clear it (and indeed, if you _do_ put it into git_config_clear(), then many tests fail, as we have to clear the config cache any time we set a new config variable). There are three tests here. The first two actually pass already, though it's largely luck: they just don't happen to actually read any config before we enter the new repo. But the third one does fail without this patch; we look at core.sharedrepository while creating the directory, but need to make sure the value from the template config overrides it. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t1301-shared-repo.sh | 32 ++++++++++++++++++++++++++++++++ 1 file changed, 32 insertions(+) (limited to 't') diff --git a/t/t1301-shared-repo.sh b/t/t1301-shared-repo.sh index 7c28642f2e..1312004f8c 100755 --- a/t/t1301-shared-repo.sh +++ b/t/t1301-shared-repo.sh @@ -181,4 +181,36 @@ test_expect_success POSIXPERM 'remote init does not use config from cwd' ' test_cmp expect actual ' +test_expect_success POSIXPERM 're-init respects core.sharedrepository (local)' ' + git config core.sharedrepository 0666 && + umask 0022 && + echo whatever >templates/foo && + git init --template=templates && + echo "-rw-rw-rw-" >expect && + modebits .git/foo >actual && + test_cmp expect actual +' + +test_expect_success POSIXPERM 're-init respects core.sharedrepository (remote)' ' + rm -rf child.git && + umask 0022 && + git init --bare --shared=0666 child.git && + test_path_is_missing child.git/foo && + git init --bare --template=../templates child.git && + echo "-rw-rw-rw-" >expect && + modebits child.git/foo >actual && + test_cmp expect actual +' + +test_expect_success POSIXPERM 'template can set core.sharedrepository' ' + rm -rf child.git && + umask 0022 && + git config core.sharedrepository 0666 && + cp .git/config templates/config && + git init --bare --template=../templates child.git && + echo "-rw-rw-rw-" >expect && + modebits child.git/HEAD >actual && + test_cmp expect actual +' + test_done -- cgit v1.2.3 From 4d0efa101bbbc63d8bd1ec0477f027f23b9f573b Mon Sep 17 00:00:00 2001 From: Jeff King Date: Mon, 12 Sep 2016 20:23:12 -0700 Subject: t1007: factor out repeated setup We have a series of 3 CRLF tests that do exactly the same (long) setup sequence. Let's pull it out into a common setup test, which is shorter, more efficient, and will make it easier to add new tests. Note that we don't have to worry about cleaning up any of the setup which was previously per-test; we call pop_repo after the CRLF tests, which cleans up everything. Signed-off-by: Jeff King Signed-off-by: Junio C Hamano --- t/t1007-hash-object.sh | 32 ++++++++------------------------ 1 file changed, 8 insertions(+), 24 deletions(-) (limited to 't') diff --git a/t/t1007-hash-object.sh b/t/t1007-hash-object.sh index 285871c24d..acca9ac562 100755 --- a/t/t1007-hash-object.sh +++ b/t/t1007-hash-object.sh @@ -101,7 +101,7 @@ test_expect_success 'git hash-object --stdin file1 file0 && cp file0 file1 && echo "file0 -crlf" >.gitattributes && @@ -109,7 +109,10 @@ test_expect_success 'check that appropriate filter is invoke when --path is used git config core.autocrlf true && file0_sha=$(git hash-object file0) && file1_sha=$(git hash-object file1) && - test "$file0_sha" != "$file1_sha" && + test "$file0_sha" != "$file1_sha" +' + +test_expect_success 'check that appropriate filter is invoke when --path is used' ' path1_sha=$(git hash-object --path=file1 file0) && path0_sha=$(git hash-object --path=file0 file1) && test "$file0_sha" = "$path0_sha" && @@ -117,8 +120,7 @@ test_expect_success 'check that appropriate filter is invoke when --path is used path1_sha=$(cat file0 | git hash-object --path=file1 --stdin) && path0_sha=$(cat file1 | git hash-object --path=file0 --stdin) && test "$file0_sha" = "$path0_sha" && - test "$file1_sha" = "$path1_sha" && - git config --unset core.autocrlf + test "$file1_sha" = "$path1_sha" ' test_expect_success 'gitattributes also work in a subdirectory' ' @@ -133,33 +135,15 @@ test_expect_success 'gitattributes also work in a subdirectory' ' ' test_expect_success 'check that --no-filters option works' ' - echo fooQ | tr Q "\\015" >file0 && - cp file0 file1 && - echo "file0 -crlf" >.gitattributes && - echo "file1 crlf" >>.gitattributes && - git config core.autocrlf true && - file0_sha=$(git hash-object file0) && - file1_sha=$(git hash-object file1) && - test "$file0_sha" != "$file1_sha" && nofilters_file1=$(git hash-object --no-filters file1) && test "$file0_sha" = "$nofilters_file1" && nofilters_file1=$(cat file1 | git hash-object --stdin) && - test "$file0_sha" = "$nofilters_file1" && - git config --unset core.autocrlf + test "$file0_sha" = "$nofilters_file1" ' test_expect_success 'check that --no-filters option works with --stdin-paths' ' - echo fooQ | tr Q "\\015" >file0 && - cp file0 file1 && - echo "file0 -crlf" >.gitattributes && - echo "file1 crlf" >>.gitattributes && - git config core.autocrlf true && - file0_sha=$(git hash-object file0) && - file1_sha=$(git hash-object file1) && - test "$file0_sha" != "$file1_sha" && nofilters_file1=$(echo "file1" | git hash-object --stdin-paths --no-filters) && - test "$file0_sha" = "$nofilters_file1" && - git config --unset core.autocrlf + test "$file0_sha" = "$nofilters_file1" ' pop_repo -- cgit v1.2.3