Re: [PATCH 04/18] t1401-symbolic-ref: avoid direct filesystem access
flat view
From: SZEDER Gábor <hidden>
Date: 2021-04-23 05:13:02
On Thu, Apr 22, 2021 at 03:01:01PM +0200, Han-Wen Nienhuys wrote:
On Thu, Apr 22, 2021 at 6:59 AM SZEDER Gábor [off-list ref] wrote:quoted
quoted
See the comment above the changed line: we don't want auto-detection to clobber the surrounding git repo.Indeed, but then this is not a faithful conversion of the original. That 'echo' will write sane content to HEAD no matter what state the repository is in. That 'symbolic-ref' command, however, won't, because 'git --git-dir .git' turns off only repository discovery, but not repository verification, and in case of a corrupt '.git/HEAD' it will bail out. $ cd test $ git init Initialized empty Git repository in /home/szeder/src/git/test/.git/ $ git commit --allow-empty -m initial [master (root-commit) ec0df0b] initial $ echo "foo bar baz" >.git/HEAD $ git --git-dir .git symbolic-ref HEAD refs/heads/master fatal: not a git repository: '.git'But then it's working as intended, no? It will not corrupt the surrounding repository.
No, it definitely does not.
If one of the test cases fails because 'git symbolic-ref' were to
write bogus content to HEAD, then that new 'git symbolic-ref'
invocation in reset_to_sane() will not corrupt the surrounding
repository, but, crucially, it won't restore the test repository's
HEAD to a sane state either, and git commands invoked in subsequent
tests won't recognize the trash dir as their git repository, and will
operate on the surrounding repo instead:
~/src/git/t (master)$ vim t/t1401-symbolic-ref.sh
~/src/git/t (master *)$ git diff
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index a4ebb0b65f..8f8d93bf6a 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -23,7 +23,11 @@ test_expect_success 'symbolic-ref reads HEAD' '
'
test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
- test_must_fail git symbolic-ref HEAD foo
+ #test_must_fail git symbolic-ref HEAD foo &&
+ # Lets pretend that the above "git symbolic-ref" did write that
+ # bogus content to HEAD:
+ echo foo >.git/HEAD &&
+ false
'
reset_to_sane
~/src/git/t (master *)$ ./t1401-symbolic-ref.sh
ok 1 - symbolic-ref writes HEAD
ok 2 - symbolic-ref reads HEAD
not ok 3 - symbolic-ref refuses non-ref for HEAD
#
# #test_must_fail git symbolic-ref HEAD foo &&
# # Lets pretend that the above "git symbolic-ref" did write that
# # bogus content to HEAD:
# echo foo >.git/HEAD &&
# false
#
ok 4 - symbolic-ref refuses bare sha1
ok 5 - HEAD cannot be removed
ok 6 - symbolic-ref can be deleted
ok 7 - symbolic-ref can delete dangling symref
ok 8 - symbolic-ref fails to delete missing FOO
ok 9 - symbolic-ref fails to delete real ref
ok 10 - create large ref name
ok 11 - symbolic-ref can point to large ref name
ok 12 - we can parse long symbolic ref
ok 13 - symbolic-ref reports failure in exit code
ok 14 - symbolic-ref writes reflog entry
ok 15 - symbolic-ref does not create ref d/f conflicts
ok 16 - symbolic-ref can overwrite pointer to invalid name
ok 17 - symbolic-ref can resolve d/f name (EISDIR)
ok 18 - symbolic-ref can resolve d/f name (ENOTDIR)
# failed 1 among 18 test(s)
1..18
~/src/git/t (master *)$
OK, only one test failed, and the surrounding repo is not affected.
No lets switch to your 'git symbolic-ref command in reset_to_sane():
~/src/git/t (master *)$ vim t/t1401-symbolic-ref.sh
~/src/git/t (master *)$ git diff
diff --git a/t/t1401-symbolic-ref.sh b/t/t1401-symbolic-ref.sh
index a4ebb0b65f..6ef221d1bb 100755
--- a/t/t1401-symbolic-ref.sh
+++ b/t/t1401-symbolic-ref.sh
@@ -7,7 +7,8 @@ test_description='basic symbolic-ref tests'
# the git repo, meaning that further tests will operate on
# the surrounding git repo instead of the trash directory.
reset_to_sane() {
- echo ref: refs/heads/foo >.git/HEAD
+ #echo ref: refs/heads/foo >.git/HEAD
+ git --git-dir .git symbolic-ref HEAD refs/heads/foo
}
test_expect_success 'symbolic-ref writes HEAD' '
@@ -23,7 +24,11 @@ test_expect_success 'symbolic-ref reads HEAD' '
'
test_expect_success 'symbolic-ref refuses non-ref for HEAD' '
- test_must_fail git symbolic-ref HEAD foo
+ #test_must_fail git symbolic-ref HEAD foo &&
+ # Lets pretend that the above "git symbolic-ref" did write that
+ # bogus content to HEAD:
+ echo foo >.git/HEAD &&
+ false
'
reset_to_sane
~/src/git/t (master *)$ ./t1401-symbolic-ref.sh
ok 1 - symbolic-ref writes HEAD
ok 2 - symbolic-ref reads HEAD
not ok 3 - symbolic-ref refuses non-ref for HEAD
#
# #test_must_fail git symbolic-ref HEAD foo &&
# # Lets pretend that the above "git symbolic-ref" did write that
# # bogus content to HEAD:
# echo foo >.git/HEAD &&
# false
#
fatal: not a git repository: '.git'
not ok 4 - symbolic-ref refuses bare sha1
#
# echo content >file && git add file && git commit -m one &&
# test_must_fail git symbolic-ref HEAD $(git rev-parse HEAD)
#
fatal: not a git repository: '.git'
ok 5 - HEAD cannot be removed
fatal: not a git repository: '.git'
not ok 6 - symbolic-ref can be deleted
#
# git symbolic-ref NOTHEAD refs/heads/foo &&
# git symbolic-ref -d NOTHEAD &&
# test_path_is_file .git/refs/heads/foo &&
# test_path_is_missing .git/NOTHEAD
#
fatal: not a git repository: '.git'
ok 7 - symbolic-ref can delete dangling symref
fatal: not a git repository: '.git'
ok 8 - symbolic-ref fails to delete missing FOO
fatal: not a git repository: '.git'
not ok 9 - symbolic-ref fails to delete real ref
#
# echo "fatal: Cannot delete refs/heads/foo, not a symbolic ref" >expect &&
# test_must_fail git symbolic-ref -d refs/heads/foo >actual 2>&1 &&
# git rev-parse --verify refs/heads/foo &&
# test_cmp expect actual
#
fatal: not a git repository: '.git'
ok 10 - create large ref name
ok 11 - symbolic-ref can point to large ref name
ok 12 - we can parse long symbolic ref
not ok 13 - symbolic-ref reports failure in exit code
#
# test_when_finished "rm -f .git/HEAD.lock" &&
# >.git/HEAD.lock &&
# test_must_fail git symbolic-ref HEAD refs/heads/whatever
#
not ok 14 - symbolic-ref writes reflog entry
#
# git checkout -b log1 &&
# test_commit one &&
# git checkout -b log2 &&
# test_commit two &&
# git checkout --orphan orphan &&
# git symbolic-ref -m create HEAD refs/heads/log1 &&
# git symbolic-ref -m update HEAD refs/heads/log2 &&
# cat >expect <<-\EOF &&
# update
# create
# EOF
# git log --format=%gs -g -2 >actual &&
# test_cmp expect actual
#
not ok 15 - symbolic-ref does not create ref d/f conflicts
#
# git checkout -b df &&
# test_commit df &&
# test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df &&
# git pack-refs --all --prune &&
# test_must_fail git symbolic-ref refs/heads/df/conflict refs/heads/df
#
not ok 16 - symbolic-ref can overwrite pointer to invalid name
#
# test_when_finished reset_to_sane &&
# head=$(git rev-parse HEAD) &&
# git symbolic-ref HEAD refs/heads/outer &&
# test_when_finished "git update-ref -d refs/heads/outer/inner" &&
# git update-ref refs/heads/outer/inner $head &&
# git symbolic-ref HEAD refs/heads/unrelated
#
not ok 17 - symbolic-ref can resolve d/f name (EISDIR)
#
# test_when_finished reset_to_sane &&
# head=$(git rev-parse HEAD) &&
# git symbolic-ref HEAD refs/heads/outer/inner &&
# test_when_finished "git update-ref -d refs/heads/outer" &&
# git update-ref refs/heads/outer $head &&
# echo refs/heads/outer/inner >expect &&
# git symbolic-ref HEAD >actual &&
# test_cmp expect actual
#
not ok 18 - symbolic-ref can resolve d/f name (ENOTDIR)
#
# test_when_finished reset_to_sane &&
# head=$(git rev-parse HEAD) &&
# git symbolic-ref HEAD refs/heads/outer &&
# test_when_finished "git update-ref -d refs/heads/outer/inner" &&
# git update-ref refs/heads/outer/inner $head &&
# echo refs/heads/outer >expect &&
# git symbolic-ref HEAD >actual &&
# test_cmp expect actual
#
# failed 10 among 18 test(s)
1..18
Uh-oh, a lot more tests failes, and, much worse!, my git repo is now
on a different and orphaned branch:
~/src/git/t (df *+)$ git status
On branch df
No commits yet
Changes to be committed:
[...]
I see it as the test writer's job to clean up to the extent that git-symbolic-ref can reset to a sane state.
No, it's the job of whoever updates the cleanup routine to make sure that the updated cleanup routine still works just as well as it did in the past.
We could reset back to a known state in a more drastic manner (extracting .git from a tar archive), but that could interfere with the test functions if they're not isolated from each other.