git/t/t7004-tag.sh

1998 lines
53 KiB
Bash
Raw Normal View History

#!/bin/sh
#
# Copyright (c) 2007 Carlos Rica
#
test_description='git tag
Tests for operations with tags.'
. ./test-lib.sh
. "$TEST_DIRECTORY"/lib-gpg.sh
# creating and listing lightweight tags:
tag_exists () {
git show-ref --quiet --verify refs/tags/"$1"
}
test_expect_success 'listing all tags in an empty tree should succeed' '
git tag -l &&
git tag
'
test_expect_success 'listing all tags in an empty tree should output nothing' '
test $(git tag -l | wc -l) -eq 0 &&
test $(git tag | wc -l) -eq 0
'
test_expect_success 'sort tags, ignore case' '
(
git init sort &&
cd sort &&
test_commit initial &&
git tag tag-one &&
git tag TAG-two &&
git tag -l >actual &&
cat >expected <<-\EOF &&
TAG-two
initial
tag-one
EOF
test_cmp expected actual &&
git tag -l -i >actual &&
cat >expected <<-\EOF &&
initial
tag-one
TAG-two
EOF
test_cmp expected actual
)
'
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 09:50:53 +00:00
test_expect_success 'looking for a tag in an empty tree should fail' \
'! (tag_exists mytag)'
test_expect_success 'creating a tag in an empty tree should fail' '
test_must_fail git tag mynotag &&
! tag_exists mynotag
'
test_expect_success 'creating a tag for HEAD in an empty tree should fail' '
test_must_fail git tag mytaghead HEAD &&
! tag_exists mytaghead
'
test_expect_success 'creating a tag for an unknown revision should fail' '
test_must_fail git tag mytagnorev aaaaaaaaaaa &&
! tag_exists mytagnorev
'
# commit used in the tests, test_tick is also called here to freeze the date:
test_expect_success 'creating a tag using default HEAD should succeed' '
test_config core.logAllRefUpdates true &&
test_tick &&
echo foo >foo &&
git add foo &&
git commit -m Foo &&
git tag mytag &&
test_must_fail git reflog exists refs/tags/mytag
'
test_expect_success 'creating a tag with --create-reflog should create reflog' '
git log -1 \
--format="format:tag: tagging %h (%s, %cd)%n" \
--date=format:%Y-%m-%d >expected &&
test_when_finished "git tag -d tag_with_reflog" &&
git tag --create-reflog tag_with_reflog &&
git reflog exists refs/tags/tag_with_reflog &&
sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
test_cmp expected actual
'
test_expect_success 'annotated tag with --create-reflog has correct message' '
git log -1 \
--format="format:tag: tagging %h (%s, %cd)%n" \
--date=format:%Y-%m-%d >expected &&
test_when_finished "git tag -d tag_with_reflog" &&
git tag -m "annotated tag" --create-reflog tag_with_reflog &&
git reflog exists refs/tags/tag_with_reflog &&
sed -e "s/^.* //" .git/logs/refs/tags/tag_with_reflog >actual &&
test_cmp expected actual
'
test_expect_success '--create-reflog does not create reflog on failure' '
test_must_fail git tag --create-reflog mytag &&
test_must_fail git reflog exists refs/tags/mytag
'
test_expect_success 'option core.logAllRefUpdates=always creates reflog' '
test_when_finished "git tag -d tag_with_reflog" &&
test_config core.logAllRefUpdates always &&
git tag tag_with_reflog &&
git reflog exists refs/tags/tag_with_reflog
'
test_expect_success 'listing all tags if one exists should succeed' '
git tag -l &&
git tag
'
cat >expect <<EOF
mytag
EOF
test_expect_success 'Multiple -l or --list options are equivalent to one -l option' '
git tag -l -l >actual &&
test_cmp expect actual &&
git tag --list --list >actual &&
test_cmp expect actual &&
git tag --list -l --list >actual &&
test_cmp expect actual
'
test_expect_success 'listing all tags if one exists should output that tag' '
test $(git tag -l) = mytag &&
test $(git tag) = mytag
'
# pattern matching:
test_expect_success 'listing a tag using a matching pattern should succeed' \
'git tag -l mytag'
test_expect_success 'listing a tag with --ignore-case' \
'test $(git tag -l --ignore-case MYTAG) = mytag'
test_expect_success \
'listing a tag using a matching pattern should output that tag' \
'test $(git tag -l mytag) = mytag'
test_expect_success \
'listing tags using a non-matching pattern should succeed' \
'git tag -l xxx'
test_expect_success \
'listing tags using a non-matching pattern should output nothing' \
'test $(git tag -l xxx | wc -l) -eq 0'
# special cases for creating tags:
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 09:50:53 +00:00
test_expect_success \
'trying to create a tag with the name of one existing should fail' \
'test_must_fail git tag mytag'
test_expect_success \
'trying to create a tag with a non-valid name should fail' '
test $(git tag -l | wc -l) -eq 1 &&
test_must_fail git tag "" &&
test_must_fail git tag .othertag &&
test_must_fail git tag "other tag" &&
test_must_fail git tag "othertag^" &&
test_must_fail git tag "other~tag" &&
test $(git tag -l | wc -l) -eq 1
'
test_expect_success 'creating a tag using HEAD directly should succeed' '
git tag myhead HEAD &&
tag_exists myhead
'
test_expect_success '--force can create a tag with the name of one existing' '
tag_exists mytag &&
git tag --force mytag &&
tag_exists mytag'
test_expect_success '--force is moot with a non-existing tag name' '
test_when_finished git tag -d newtag forcetag &&
git tag newtag >expect &&
git tag --force forcetag >actual &&
test_cmp expect actual
'
# deleting tags:
test_expect_success 'trying to delete an unknown tag should fail' '
! tag_exists unknown-tag &&
test_must_fail git tag -d unknown-tag
'
cat >expect <<EOF
myhead
mytag
EOF
test_expect_success \
'trying to delete tags without params should succeed and do nothing' '
git tag -l > actual && test_cmp expect actual &&
git tag -d &&
git tag -l > actual && test_cmp expect actual
'
test_expect_success \
'deleting two existing tags in one command should succeed' '
tag_exists mytag &&
tag_exists myhead &&
git tag -d mytag myhead &&
! tag_exists mytag &&
! tag_exists myhead
'
test_expect_success \
'creating a tag with the name of another deleted one should succeed' '
! tag_exists mytag &&
git tag mytag &&
tag_exists mytag
'
test_expect_success \
'trying to delete two tags, existing and not, should fail in the 2nd' '
tag_exists mytag &&
! tag_exists myhead &&
test_must_fail git tag -d mytag anothertag &&
! tag_exists mytag &&
! tag_exists myhead
'
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 09:50:53 +00:00
test_expect_success 'trying to delete an already deleted tag should fail' \
'test_must_fail git tag -d mytag'
# listing various tags with pattern matching:
cat >expect <<EOF
a1
aa1
cba
t210
t211
v0.2.1
v1.0
v1.0.1
v1.1.3
EOF
test_expect_success 'listing all tags should print them ordered' '
git tag v1.0.1 &&
git tag t211 &&
git tag aa1 &&
git tag v0.2.1 &&
git tag v1.1.3 &&
git tag cba &&
git tag a1 &&
git tag v1.0 &&
git tag t210 &&
git tag -l > actual &&
test_cmp expect actual &&
git tag > actual &&
test_cmp expect actual
'
cat >expect <<EOF
a1
aa1
cba
EOF
test_expect_success \
'listing tags with substring as pattern must print those matching' '
rm *a* &&
git tag -l "*a*" > current &&
test_cmp expect current
'
cat >expect <<EOF
v0.2.1
v1.0.1
EOF
test_expect_success \
'listing tags with a suffix as pattern must print those matching' '
git tag -l "*.1" > actual &&
test_cmp expect actual
'
cat >expect <<EOF
t210
t211
EOF
test_expect_success \
'listing tags with a prefix as pattern must print those matching' '
git tag -l "t21*" > actual &&
test_cmp expect actual
'
cat >expect <<EOF
a1
EOF
test_expect_success \
'listing tags using a name as pattern must print that one matching' '
git tag -l a1 > actual &&
test_cmp expect actual
'
cat >expect <<EOF
v1.0
EOF
test_expect_success \
'listing tags using a name as pattern must print that one matching' '
git tag -l v1.0 > actual &&
test_cmp expect actual
'
cat >expect <<EOF
v1.0.1
v1.1.3
EOF
test_expect_success \
'listing tags with ? in the pattern should print those matching' '
git tag -l "v1.?.?" > actual &&
test_cmp expect actual
'
>expect
test_expect_success \
'listing tags using v.* should print nothing because none have v.' '
git tag -l "v.*" > actual &&
test_cmp expect actual
'
cat >expect <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
EOF
test_expect_success \
'listing tags using v* should print only those having v' '
git tag -l "v*" > actual &&
test_cmp expect actual
'
test_expect_success 'tag -l can accept multiple patterns' '
git tag -l "v1*" "v0*" >actual &&
test_cmp expect actual
'
# Between v1.7.7 & v2.13.0 a fair reading of the git-tag documentation
# could leave you with the impression that "-l <pattern> -l <pattern>"
# was how we wanted to accept multiple patterns.
#
# This test should not imply that this is a sane thing to support. but
# since the documentation was worded like it was let's at least find
# out if we're going to break this long-documented form of taking
# multiple patterns.
test_expect_success 'tag -l <pattern> -l <pattern> works, as our buggy documentation previously suggested' '
git tag -l "v1*" -l "v0*" >actual &&
test_cmp expect actual
'
test_expect_success 'listing tags in column' '
COLUMNS=40 git tag -l --column=row >actual &&
cat >expected <<\EOF &&
a1 aa1 cba t210 t211
v0.2.1 v1.0 v1.0.1 v1.1.3
EOF
test_cmp expected actual
'
test_expect_success 'listing tags in column with column.*' '
test_config column.tag row &&
test_config column.ui dense &&
COLUMNS=40 git tag -l >actual &&
cat >expected <<\EOF &&
a1 aa1 cba t210 t211
v0.2.1 v1.0 v1.0.1 v1.1.3
EOF
test_cmp expected actual
'
test_expect_success 'listing tag with -n --column should fail' '
test_must_fail git tag --column -n
'
test_expect_success 'listing tags -n in column with column.ui ignored' '
test_config column.ui "row dense" &&
COLUMNS=40 git tag -l -n >actual &&
cat >expected <<\EOF &&
a1 Foo
aa1 Foo
cba Foo
t210 Foo
t211 Foo
v0.2.1 Foo
v1.0 Foo
v1.0.1 Foo
v1.1.3 Foo
EOF
test_cmp expected actual
'
# creating and verifying lightweight tags:
test_expect_success \
'a non-annotated tag created without parameters should point to HEAD' '
git tag non-annotated-tag &&
test $(git cat-file -t non-annotated-tag) = commit &&
test $(git rev-parse non-annotated-tag) = $(git rev-parse HEAD)
'
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 09:50:53 +00:00
test_expect_success 'trying to verify an unknown tag should fail' \
'test_must_fail git tag -v unknown-tag'
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 09:50:53 +00:00
test_expect_success \
'trying to verify a non-annotated and non-signed tag should fail' \
'test_must_fail git tag -v non-annotated-tag'
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 09:50:53 +00:00
test_expect_success \
'trying to verify many non-annotated or unknown tags, should fail' \
'test_must_fail git tag -v unknown-tag1 non-annotated-tag unknown-tag2'
# creating annotated tags:
get_tag_msg () {
git cat-file tag "$1" | sed -e "/BEGIN PGP/q"
}
# run test_tick before committing always gives the time in that timezone
get_tag_header () {
cat <<EOF
object $2
type $3
tag $1
tagger C O Mitter <committer@example.com> $4 -0700
EOF
}
commit=$(git rev-parse HEAD)
time=$test_tick
get_tag_header annotated-tag $commit commit $time >expect
echo "A message" >>expect
test_expect_success \
'creating an annotated tag with -m message should succeed' '
git tag -m "A message" annotated-tag &&
get_tag_msg annotated-tag >actual &&
test_cmp expect actual
'
cat >msgfile <<EOF
Another message
in a file.
EOF
get_tag_header file-annotated-tag $commit commit $time >expect
cat msgfile >>expect
test_expect_success \
'creating an annotated tag with -F messagefile should succeed' '
git tag -F msgfile file-annotated-tag &&
get_tag_msg file-annotated-tag >actual &&
test_cmp expect actual
'
cat >inputmsg <<EOF
A message from the
standard input
EOF
get_tag_header stdin-annotated-tag $commit commit $time >expect
cat inputmsg >>expect
test_expect_success 'creating an annotated tag with -F - should succeed' '
git tag -F - stdin-annotated-tag <inputmsg &&
get_tag_msg stdin-annotated-tag >actual &&
test_cmp expect actual
'
test_expect_success \
'trying to create a tag with a non-existing -F file should fail' '
! test -f nonexistingfile &&
! tag_exists notag &&
test_must_fail git tag -F nonexistingfile notag &&
! tag_exists notag
'
test_expect_success \
'trying to create tags giving both -m or -F options should fail' '
echo "message file 1" >msgfile1 &&
echo "message file 2" >msgfile2 &&
! tag_exists msgtag &&
test_must_fail git tag -m "message 1" -F msgfile1 msgtag &&
! tag_exists msgtag &&
test_must_fail git tag -F msgfile1 -m "message 1" msgtag &&
! tag_exists msgtag &&
test_must_fail git tag -m "message 1" -F msgfile1 \
-m "message 2" msgtag &&
! tag_exists msgtag
'
# blank and empty messages:
get_tag_header empty-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with an empty -m message should succeed' '
git tag -m "" empty-annotated-tag &&
get_tag_msg empty-annotated-tag >actual &&
test_cmp expect actual
'
>emptyfile
get_tag_header emptyfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with an empty -F messagefile should succeed' '
git tag -F emptyfile emptyfile-annotated-tag &&
get_tag_msg emptyfile-annotated-tag >actual &&
test_cmp expect actual
'
printf '\n\n \n\t\nLeading blank lines\n' >blanksfile
printf '\n\t \t \nRepeated blank lines\n' >>blanksfile
printf '\n\n\nTrailing spaces \t \n' >>blanksfile
printf '\nTrailing blank lines\n\n\t \n\n' >>blanksfile
get_tag_header blanks-annotated-tag $commit commit $time >expect
cat >>expect <<EOF
Leading blank lines
Repeated blank lines
Trailing spaces
Trailing blank lines
EOF
test_expect_success \
'extra blanks in the message for an annotated tag should be removed' '
git tag -F blanksfile blanks-annotated-tag &&
get_tag_msg blanks-annotated-tag >actual &&
test_cmp expect actual
'
get_tag_header blank-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with blank -m message with spaces should succeed' '
git tag -m " " blank-annotated-tag &&
get_tag_msg blank-annotated-tag >actual &&
test_cmp expect actual
'
echo ' ' >blankfile
echo '' >>blankfile
echo ' ' >>blankfile
get_tag_header blankfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with blank -F messagefile with spaces should succeed' '
git tag -F blankfile blankfile-annotated-tag &&
get_tag_msg blankfile-annotated-tag >actual &&
test_cmp expect actual
'
printf ' ' >blanknonlfile
get_tag_header blanknonlfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with -F file of spaces and no newline should succeed' '
git tag -F blanknonlfile blanknonlfile-annotated-tag &&
get_tag_msg blanknonlfile-annotated-tag >actual &&
test_cmp expect actual
'
# messages with commented lines:
cat >commentsfile <<EOF
# A comment
############
The message.
############
One line.
# commented lines
# commented lines
Another line.
# comments
Last line.
EOF
get_tag_header comments-annotated-tag $commit commit $time >expect
cat >>expect <<EOF
The message.
One line.
Another line.
Last line.
EOF
test_expect_success \
'creating a tag using a -F messagefile with #comments should succeed' '
git tag -F commentsfile comments-annotated-tag &&
get_tag_msg comments-annotated-tag >actual &&
test_cmp expect actual
'
get_tag_header comment-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with a #comment in the -m message should succeed' '
git tag -m "#comment" comment-annotated-tag &&
get_tag_msg comment-annotated-tag >actual &&
test_cmp expect actual
'
echo '#comment' >commentfile
echo '' >>commentfile
echo '####' >>commentfile
get_tag_header commentfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with #comments in the -F messagefile should succeed' '
git tag -F commentfile commentfile-annotated-tag &&
get_tag_msg commentfile-annotated-tag >actual &&
test_cmp expect actual
'
printf '#comment' >commentnonlfile
get_tag_header commentnonlfile-annotated-tag $commit commit $time >expect
test_expect_success \
'creating a tag with a file of #comment and no newline should succeed' '
git tag -F commentnonlfile commentnonlfile-annotated-tag &&
get_tag_msg commentnonlfile-annotated-tag >actual &&
test_cmp expect actual
'
# listing messages for annotated non-signed tags:
test_expect_success \
'listing the one-line message of a non-signed tag should succeed' '
git tag -m "A msg" tag-one-line &&
echo "tag-one-line" >expect &&
git tag -l | grep "^tag-one-line" >actual &&
test_cmp expect actual &&
git tag -n0 -l | grep "^tag-one-line" >actual &&
test_cmp expect actual &&
git tag -n0 -l tag-one-line >actual &&
test_cmp expect actual &&
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
git tag -n0 | grep "^tag-one-line" >actual &&
test_cmp expect actual &&
git tag -n0 tag-one-line >actual &&
test_cmp expect actual &&
echo "tag-one-line A msg" >expect &&
git tag -n1 -l | grep "^tag-one-line" >actual &&
test_cmp expect actual &&
git tag -n -l | grep "^tag-one-line" >actual &&
test_cmp expect actual &&
git tag -n1 -l tag-one-line >actual &&
test_cmp expect actual &&
git tag -n2 -l tag-one-line >actual &&
test_cmp expect actual &&
git tag -n999 -l tag-one-line >actual &&
test_cmp expect actual
'
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
test_expect_success 'The -n 100 invocation means -n --list 100, not -n100' '
>expect &&
git tag -n 100 >actual &&
test_cmp expect actual &&
git tag -m "A msg" 100 &&
echo "100 A msg" >expect &&
git tag -n 100 >actual &&
test_cmp expect actual
'
test_expect_success \
'listing the zero-lines message of a non-signed tag should succeed' '
git tag -m "" tag-zero-lines &&
echo "tag-zero-lines" >expect &&
git tag -l | grep "^tag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l | grep "^tag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l tag-zero-lines >actual &&
test_cmp expect actual &&
echo "tag-zero-lines " >expect &&
git tag -n1 -l | grep "^tag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n -l | grep "^tag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n1 -l tag-zero-lines >actual &&
test_cmp expect actual &&
git tag -n2 -l tag-zero-lines >actual &&
test_cmp expect actual &&
git tag -n999 -l tag-zero-lines >actual &&
test_cmp expect actual
'
echo 'tag line one' >annotagmsg
echo 'tag line two' >>annotagmsg
echo 'tag line three' >>annotagmsg
test_expect_success \
'listing many message lines of a non-signed tag should succeed' '
git tag -F annotagmsg tag-lines &&
echo "tag-lines" >expect &&
git tag -l | grep "^tag-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l | grep "^tag-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l tag-lines >actual &&
test_cmp expect actual &&
echo "tag-lines tag line one" >expect &&
git tag -n1 -l | grep "^tag-lines" >actual &&
test_cmp expect actual &&
git tag -n -l | grep "^tag-lines" >actual &&
test_cmp expect actual &&
git tag -n1 -l tag-lines >actual &&
test_cmp expect actual &&
echo " tag line two" >>expect &&
git tag -n2 -l | grep "^ *tag.line" >actual &&
test_cmp expect actual &&
git tag -n2 -l tag-lines >actual &&
test_cmp expect actual &&
echo " tag line three" >>expect &&
git tag -n3 -l | grep "^ *tag.line" >actual &&
test_cmp expect actual &&
git tag -n3 -l tag-lines >actual &&
test_cmp expect actual &&
git tag -n4 -l | grep "^ *tag.line" >actual &&
test_cmp expect actual &&
git tag -n4 -l tag-lines >actual &&
test_cmp expect actual &&
git tag -n99 -l | grep "^ *tag.line" >actual &&
test_cmp expect actual &&
git tag -n99 -l tag-lines >actual &&
test_cmp expect actual
'
test_expect_success 'annotations for blobs are empty' '
blob=$(git hash-object -w --stdin <<-\EOF
Blob paragraph 1.
Blob paragraph 2.
EOF
) &&
git tag tag-blob $blob &&
echo "tag-blob " >expect &&
git tag -n1 -l tag-blob >actual &&
test_cmp expect actual
'
# trying to verify annotated non-signed tags:
test_expect_success GPG \
'trying to verify an annotated non-signed tag should fail' '
tag_exists annotated-tag &&
test_must_fail git tag -v annotated-tag
'
test_expect_success GPG \
'trying to verify a file-annotated non-signed tag should fail' '
tag_exists file-annotated-tag &&
test_must_fail git tag -v file-annotated-tag
'
test_expect_success GPG \
'trying to verify two annotated non-signed tags should fail' '
tag_exists annotated-tag file-annotated-tag &&
test_must_fail git tag -v annotated-tag file-annotated-tag
'
# creating and verifying signed tags:
get_tag_header signed-tag $commit commit $time >expect
echo 'A signed tag message' >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'creating a signed tag with -m message should succeed' '
git tag -s -m "A signed tag message" signed-tag &&
get_tag_msg signed-tag >actual &&
test_cmp expect actual
'
get_tag_header u-signed-tag $commit commit $time >expect
echo 'Another message' >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'sign with a given key id' '
git tag -u committer@example.com -m "Another message" u-signed-tag &&
get_tag_msg u-signed-tag >actual &&
test_cmp expect actual
'
test_expect_success GPG 'sign with an unknown id (1)' '
test_must_fail git tag -u author@example.com \
-m "Another message" o-signed-tag
'
test_expect_success GPG 'sign with an unknown id (2)' '
test_must_fail git tag -u DEADBEEF -m "Another message" o-signed-tag
'
cat >fakeeditor <<'EOF'
#!/bin/sh
test -n "$1" && exec >"$1"
echo A signed tag message
echo from a fake editor.
EOF
chmod +x fakeeditor
get_tag_header implied-sign $commit commit $time >expect
./fakeeditor >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG '-u implies signed tag' '
GIT_EDITOR=./fakeeditor git tag -u CDDE430D implied-sign &&
get_tag_msg implied-sign >actual &&
test_cmp expect actual
'
cat >sigmsgfile <<EOF
Another signed tag
message in a file.
EOF
get_tag_header file-signed-tag $commit commit $time >expect
cat sigmsgfile >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with -F messagefile should succeed' '
git tag -s -F sigmsgfile file-signed-tag &&
get_tag_msg file-signed-tag >actual &&
test_cmp expect actual
'
cat >siginputmsg <<EOF
A signed tag message from
the standard input
EOF
get_tag_header stdin-signed-tag $commit commit $time >expect
cat siginputmsg >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG 'creating a signed tag with -F - should succeed' '
git tag -s -F - stdin-signed-tag <siginputmsg &&
get_tag_msg stdin-signed-tag >actual &&
test_cmp expect actual
'
get_tag_header implied-annotate $commit commit $time >expect
./fakeeditor >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG '-s implies annotated tag' '
GIT_EDITOR=./fakeeditor git tag -s implied-annotate &&
get_tag_msg implied-annotate >actual &&
test_cmp expect actual
'
get_tag_header forcesignannotated-implied-sign $commit commit $time >expect
echo "A message" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'git tag -s implied if configured with tag.forcesignannotated' \
'test_config tag.forcesignannotated true &&
git tag -m "A message" forcesignannotated-implied-sign &&
get_tag_msg forcesignannotated-implied-sign >actual &&
test_cmp expect actual
'
test_expect_success GPG \
'lightweight with no message when configured with tag.forcesignannotated' \
'test_config tag.forcesignannotated true &&
git tag forcesignannotated-lightweight &&
tag_exists forcesignannotated-lightweight &&
test_must_fail git tag -v forcesignannotated-no-message
'
get_tag_header forcesignannotated-annotate $commit commit $time >expect
echo "A message" >>expect
test_expect_success GPG \
'git tag -a disable configured tag.forcesignannotated' \
'test_config tag.forcesignannotated true &&
git tag -a -m "A message" forcesignannotated-annotate &&
get_tag_msg forcesignannotated-annotate >actual &&
test_cmp expect actual &&
test_must_fail git tag -v forcesignannotated-annotate
'
get_tag_header forcesignannotated-disabled $commit commit $time >expect
echo "A message" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'git tag --sign enable GPG sign' \
'test_config tag.forcesignannotated false &&
git tag --sign -m "A message" forcesignannotated-disabled &&
get_tag_msg forcesignannotated-disabled >actual &&
test_cmp expect actual
'
test_expect_success GPG \
'trying to create a signed tag with non-existing -F file should fail' '
! test -f nonexistingfile &&
! tag_exists nosigtag &&
test_must_fail git tag -s -F nonexistingfile nosigtag &&
! tag_exists nosigtag
'
test_expect_success GPG 'verifying a signed tag should succeed' \
'git tag -v signed-tag'
test_expect_success GPG 'verifying two signed tags in one command should succeed' \
'git tag -v signed-tag file-signed-tag'
test_expect_success GPG \
'verifying many signed and non-signed tags should fail' '
test_must_fail git tag -v signed-tag annotated-tag &&
test_must_fail git tag -v file-annotated-tag file-signed-tag &&
test_must_fail git tag -v annotated-tag \
file-signed-tag file-annotated-tag &&
test_must_fail git tag -v signed-tag annotated-tag file-signed-tag
'
test_expect_success GPG 'verifying a forged tag should fail' '
forged=$(git cat-file tag signed-tag |
sed -e "s/signed-tag/forged-tag/" |
git mktag) &&
git tag forged-tag $forged &&
test_must_fail git tag -v forged-tag
'
test_expect_success 'verifying a proper tag with --format pass and format accordingly' '
cat >expect <<-\EOF
tagname : signed-tag
EOF &&
git tag -v --format="tagname : %(tag)" "signed-tag" >actual &&
test_cmp expect actual
'
test_expect_success 'verifying a forged tag with --format fail and format accordingly' '
cat >expect <<-\EOF
tagname : forged-tag
EOF &&
test_must_fail git tag -v --format="tagname : %(tag)" "forged-tag" >actual &&
test_cmp expect actual
'
# blank and empty messages for signed tags:
get_tag_header empty-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with an empty -m message should succeed' '
git tag -s -m "" empty-signed-tag &&
get_tag_msg empty-signed-tag >actual &&
test_cmp expect actual &&
git tag -v empty-signed-tag
'
>sigemptyfile
get_tag_header emptyfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with an empty -F messagefile should succeed' '
git tag -s -F sigemptyfile emptyfile-signed-tag &&
get_tag_msg emptyfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v emptyfile-signed-tag
'
printf '\n\n \n\t\nLeading blank lines\n' > sigblanksfile
printf '\n\t \t \nRepeated blank lines\n' >>sigblanksfile
printf '\n\n\nTrailing spaces \t \n' >>sigblanksfile
printf '\nTrailing blank lines\n\n\t \n\n' >>sigblanksfile
get_tag_header blanks-signed-tag $commit commit $time >expect
cat >>expect <<EOF
Leading blank lines
Repeated blank lines
Trailing spaces
Trailing blank lines
EOF
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'extra blanks in the message for a signed tag should be removed' '
git tag -s -F sigblanksfile blanks-signed-tag &&
get_tag_msg blanks-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blanks-signed-tag
'
get_tag_header blank-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with a blank -m message should succeed' '
git tag -s -m " " blank-signed-tag &&
get_tag_msg blank-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blank-signed-tag
'
echo ' ' >sigblankfile
echo '' >>sigblankfile
echo ' ' >>sigblankfile
get_tag_header blankfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with blank -F file with spaces should succeed' '
git tag -s -F sigblankfile blankfile-signed-tag &&
get_tag_msg blankfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v blankfile-signed-tag
'
printf ' ' >sigblanknonlfile
get_tag_header blanknonlfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with spaces and no newline should succeed' '
git tag -s -F sigblanknonlfile blanknonlfile-signed-tag &&
get_tag_msg blanknonlfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v signed-tag
'
# messages with commented lines for signed tags:
cat >sigcommentsfile <<EOF
# A comment
############
The message.
############
One line.
# commented lines
# commented lines
Another line.
# comments
Last line.
EOF
get_tag_header comments-signed-tag $commit commit $time >expect
cat >>expect <<EOF
The message.
One line.
Another line.
Last line.
EOF
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with a -F file with #comments should succeed' '
git tag -s -F sigcommentsfile comments-signed-tag &&
get_tag_msg comments-signed-tag >actual &&
test_cmp expect actual &&
git tag -v comments-signed-tag
'
get_tag_header comment-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with #commented -m message should succeed' '
git tag -s -m "#comment" comment-signed-tag &&
get_tag_msg comment-signed-tag >actual &&
test_cmp expect actual &&
git tag -v comment-signed-tag
'
echo '#comment' >sigcommentfile
echo '' >>sigcommentfile
echo '####' >>sigcommentfile
get_tag_header commentfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with #commented -F messagefile should succeed' '
git tag -s -F sigcommentfile commentfile-signed-tag &&
get_tag_msg commentfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v commentfile-signed-tag
'
printf '#comment' >sigcommentnonlfile
get_tag_header commentnonlfile-signed-tag $commit commit $time >expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag with a #comment and no newline should succeed' '
git tag -s -F sigcommentnonlfile commentnonlfile-signed-tag &&
get_tag_msg commentnonlfile-signed-tag >actual &&
test_cmp expect actual &&
git tag -v commentnonlfile-signed-tag
'
# listing messages for signed tags:
test_expect_success GPG \
'listing the one-line message of a signed tag should succeed' '
git tag -s -m "A message line signed" stag-one-line &&
echo "stag-one-line" >expect &&
git tag -l | grep "^stag-one-line" >actual &&
test_cmp expect actual &&
git tag -n0 -l | grep "^stag-one-line" >actual &&
test_cmp expect actual &&
git tag -n0 -l stag-one-line >actual &&
test_cmp expect actual &&
echo "stag-one-line A message line signed" >expect &&
git tag -n1 -l | grep "^stag-one-line" >actual &&
test_cmp expect actual &&
git tag -n -l | grep "^stag-one-line" >actual &&
test_cmp expect actual &&
git tag -n1 -l stag-one-line >actual &&
test_cmp expect actual &&
git tag -n2 -l stag-one-line >actual &&
test_cmp expect actual &&
git tag -n999 -l stag-one-line >actual &&
test_cmp expect actual
'
test_expect_success GPG \
'listing the zero-lines message of a signed tag should succeed' '
git tag -s -m "" stag-zero-lines &&
echo "stag-zero-lines" >expect &&
git tag -l | grep "^stag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l | grep "^stag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l stag-zero-lines >actual &&
test_cmp expect actual &&
echo "stag-zero-lines " >expect &&
git tag -n1 -l | grep "^stag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n -l | grep "^stag-zero-lines" >actual &&
test_cmp expect actual &&
git tag -n1 -l stag-zero-lines >actual &&
test_cmp expect actual &&
git tag -n2 -l stag-zero-lines >actual &&
test_cmp expect actual &&
git tag -n999 -l stag-zero-lines >actual &&
test_cmp expect actual
'
echo 'stag line one' >sigtagmsg
echo 'stag line two' >>sigtagmsg
echo 'stag line three' >>sigtagmsg
test_expect_success GPG \
'listing many message lines of a signed tag should succeed' '
git tag -s -F sigtagmsg stag-lines &&
echo "stag-lines" >expect &&
git tag -l | grep "^stag-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l | grep "^stag-lines" >actual &&
test_cmp expect actual &&
git tag -n0 -l stag-lines >actual &&
test_cmp expect actual &&
echo "stag-lines stag line one" >expect &&
git tag -n1 -l | grep "^stag-lines" >actual &&
test_cmp expect actual &&
git tag -n -l | grep "^stag-lines" >actual &&
test_cmp expect actual &&
git tag -n1 -l stag-lines >actual &&
test_cmp expect actual &&
echo " stag line two" >>expect &&
git tag -n2 -l | grep "^ *stag.line" >actual &&
test_cmp expect actual &&
git tag -n2 -l stag-lines >actual &&
test_cmp expect actual &&
echo " stag line three" >>expect &&
git tag -n3 -l | grep "^ *stag.line" >actual &&
test_cmp expect actual &&
git tag -n3 -l stag-lines >actual &&
test_cmp expect actual &&
git tag -n4 -l | grep "^ *stag.line" >actual &&
test_cmp expect actual &&
git tag -n4 -l stag-lines >actual &&
test_cmp expect actual &&
git tag -n99 -l | grep "^ *stag.line" >actual &&
test_cmp expect actual &&
git tag -n99 -l stag-lines >actual &&
test_cmp expect actual
'
# tags pointing to objects different from commits:
tree=$(git rev-parse HEAD^{tree})
blob=$(git rev-parse HEAD:foo)
tag=$(git rev-parse signed-tag 2>/dev/null)
get_tag_header tree-signed-tag $tree tree $time >expect
echo "A message for a tree" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag pointing to a tree should succeed' '
git tag -s -m "A message for a tree" tree-signed-tag HEAD^{tree} &&
get_tag_msg tree-signed-tag >actual &&
test_cmp expect actual
'
get_tag_header blob-signed-tag $blob blob $time >expect
echo "A message for a blob" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag pointing to a blob should succeed' '
git tag -s -m "A message for a blob" blob-signed-tag HEAD:foo &&
get_tag_msg blob-signed-tag >actual &&
test_cmp expect actual
'
get_tag_header tag-signed-tag $tag tag $time >expect
echo "A message for another tag" >>expect
echo '-----BEGIN PGP SIGNATURE-----' >>expect
test_expect_success GPG \
'creating a signed tag pointing to another tag should succeed' '
git tag -s -m "A message for another tag" tag-signed-tag signed-tag &&
get_tag_msg tag-signed-tag >actual &&
test_cmp expect actual
'
# usage with rfc1991 signatures
get_tag_header rfc1991-signed-tag $commit commit $time >expect
echo "RFC1991 signed tag" >>expect
echo '-----BEGIN PGP MESSAGE-----' >>expect
test_expect_success GPG,RFC1991 \
'creating a signed tag with rfc1991' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -s -m "RFC1991 signed tag" rfc1991-signed-tag $commit &&
get_tag_msg rfc1991-signed-tag >actual &&
test_cmp expect actual
'
cat >fakeeditor <<'EOF'
#!/bin/sh
cp "$1" actual
EOF
chmod +x fakeeditor
test_expect_success GPG,RFC1991 \
'reediting a signed tag body omits signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
test_cmp expect actual
'
test_expect_success GPG,RFC1991 \
'verifying rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
git tag -v rfc1991-signed-tag
'
test_expect_success GPG,RFC1991 \
'list tag with rfc1991 signature' '
echo "rfc1991" >gpghome/gpg.conf &&
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
test_cmp expect actual &&
git tag -l -n2 rfc1991-signed-tag >actual &&
test_cmp expect actual &&
git tag -l -n999 rfc1991-signed-tag >actual &&
test_cmp expect actual
'
rm -f gpghome/gpg.conf
test_expect_success GPG,RFC1991 \
'verifying rfc1991 signature without --rfc1991' '
git tag -v rfc1991-signed-tag
'
test_expect_success GPG,RFC1991 \
'list tag with rfc1991 signature without --rfc1991' '
echo "rfc1991-signed-tag RFC1991 signed tag" >expect &&
git tag -l -n1 rfc1991-signed-tag >actual &&
test_cmp expect actual &&
git tag -l -n2 rfc1991-signed-tag >actual &&
test_cmp expect actual &&
git tag -l -n999 rfc1991-signed-tag >actual &&
test_cmp expect actual
'
test_expect_success GPG,RFC1991 \
'reediting a signed tag body omits signature' '
echo "RFC1991 signed tag" >expect &&
GIT_EDITOR=./fakeeditor git tag -f -s rfc1991-signed-tag $commit &&
test_cmp expect actual
'
git-tag -s must fail if gpg cannot sign the tag. Most of this patch code and message was written by Shawn O. Pearce. I made some tests to know what the problem was, and then I changed the code related with the SIGPIPE signal. If the user has misconfigured `user.signingkey` in their .git/config or just doesn't have any secret keys on their keyring and they ask for a signed tag with `git tag -s` we better make sure the resulting tag was actually signed by gpg. Prior versions of builtin git-tag allowed this failure to slip by without error as they were not checking the return value of the finish_command() so they did not notice when gpg exited with an error exit status. They also did not fail if gpg produced an empty output or if read_in_full received an error from the read system call while trying to read the pipe back from gpg. Finally, we did not actually honor any return value from the do_sign function as it returns ssize_t but was being stored into an unsigned long. This caused the compiler to optimize out the die condition, allowing git-tag to continue along and create the tag object. However, when gpg gets a wrong username, it exits before any read was done and then the writing process receives SIGPIPE and program is terminated. By ignoring this signal, anyway, the function write_or_die gets EPIPE from write_in_full and exits returning 0 to the system without a message. Here we better call to write_in_full directly so we can fail printing a message and return safely to the caller. With these issues fixed `git-tag -s` will now fail to create the tag and will report a non-zero exit status to its caller, thereby allowing automated helper scripts to detect (and recover from) failure if gpg is not working properly. Proposed-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Carlos Rica <jasampler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-09 00:39:29 +00:00
# try to sign with bad user.signingkey
test_expect_success GPG \
'git tag -s fails if gpg is misconfigured (bad key)' \
'test_config user.signingkey BobTheMouse &&
test_must_fail git tag -s -m tail tag-gpg-failure'
git-tag -s must fail if gpg cannot sign the tag. Most of this patch code and message was written by Shawn O. Pearce. I made some tests to know what the problem was, and then I changed the code related with the SIGPIPE signal. If the user has misconfigured `user.signingkey` in their .git/config or just doesn't have any secret keys on their keyring and they ask for a signed tag with `git tag -s` we better make sure the resulting tag was actually signed by gpg. Prior versions of builtin git-tag allowed this failure to slip by without error as they were not checking the return value of the finish_command() so they did not notice when gpg exited with an error exit status. They also did not fail if gpg produced an empty output or if read_in_full received an error from the read system call while trying to read the pipe back from gpg. Finally, we did not actually honor any return value from the do_sign function as it returns ssize_t but was being stored into an unsigned long. This caused the compiler to optimize out the die condition, allowing git-tag to continue along and create the tag object. However, when gpg gets a wrong username, it exits before any read was done and then the writing process receives SIGPIPE and program is terminated. By ignoring this signal, anyway, the function write_or_die gets EPIPE from write_in_full and exits returning 0 to the system without a message. Here we better call to write_in_full directly so we can fail printing a message and return safely to the caller. With these issues fixed `git-tag -s` will now fail to create the tag and will report a non-zero exit status to its caller, thereby allowing automated helper scripts to detect (and recover from) failure if gpg is not working properly. Proposed-by: Shawn O. Pearce <spearce@spearce.org> Signed-off-by: Carlos Rica <jasampler@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2007-09-09 00:39:29 +00:00
# try to produce invalid signature
test_expect_success GPG \
'git tag -s fails if gpg is misconfigured (bad signature format)' \
'test_config gpg.program echo &&
test_must_fail git tag -s -m tail tag-gpg-failure'
# try to verify without gpg:
rm -rf gpghome
test_expect_success GPG \
'verify signed tag fails when public key is not present' \
'test_must_fail git tag -v signed-tag'
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 09:50:53 +00:00
test_expect_success \
'git tag -a fails if tag annotation is empty' '
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 09:50:53 +00:00
! (GIT_EDITOR=cat git tag -a initial-comment)
'
test_expect_success \
'message in editor has initial comment' '
! (GIT_EDITOR=cat git tag -a initial-comment > actual)
'
test_expect_success 'message in editor has initial comment: first line' '
# check the first line --- should be empty
echo >first.expect &&
sed -e 1q <actual >first.actual &&
test_i18ncmp first.expect first.actual
'
test_expect_success \
'message in editor has initial comment: remainder' '
# remove commented lines from the remainder -- should be empty
>rest.expect &&
sed -e 1d -e "/^#/d" <actual >rest.actual &&
test_cmp rest.expect rest.actual
'
get_tag_header reuse $commit commit $time >expect
echo "An annotation to be reused" >> expect
test_expect_success \
'overwriting an annoted tag should use its previous body' '
git tag -a -m "An annotation to be reused" reuse &&
GIT_EDITOR=true git tag -f -a reuse &&
get_tag_msg reuse >actual &&
test_cmp expect actual
'
test_expect_success 'filename for the message is relative to cwd' '
mkdir subdir &&
echo "Tag message in top directory" >msgfile-5 &&
echo "Tag message in sub directory" >subdir/msgfile-5 &&
(
cd subdir &&
git tag -a -F msgfile-5 tag-from-subdir
) &&
git cat-file tag tag-from-subdir | grep "in sub directory"
'
test_expect_success 'filename for the message is relative to cwd' '
echo "Tag message in sub directory" >subdir/msgfile-6 &&
(
cd subdir &&
git tag -a -F msgfile-6 tag-from-subdir-2
) &&
git cat-file tag tag-from-subdir-2 | grep "in sub directory"
'
# create a few more commits to test --contains
hash1=$(git rev-parse HEAD)
test_expect_success 'creating second commit and tag' '
echo foo-2.0 >foo &&
git add foo &&
git commit -m second &&
git tag v2.0
'
hash2=$(git rev-parse HEAD)
test_expect_success 'creating third commit without tag' '
echo foo-dev >foo &&
git add foo &&
git commit -m third
'
hash3=$(git rev-parse HEAD)
# simple linear checks of --continue
cat > expected <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
v2.0
EOF
test_expect_success 'checking that first commit is in all tags (hash)' "
git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
"
# other ways of specifying the commit
test_expect_success 'checking that first commit is in all tags (tag)' "
git tag -l --contains v1.0 v* >actual &&
test_cmp expected actual
"
test_expect_success 'checking that first commit is in all tags (relative)' "
git tag -l --contains HEAD~2 v* >actual &&
test_cmp expected actual
"
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
# All the --contains tests above, but with --no-contains
test_expect_success 'checking that first commit is not listed in any tag with --no-contains (hash)' "
>expected &&
git tag -l --no-contains $hash1 v* >actual &&
test_cmp expected actual
"
test_expect_success 'checking that first commit is in all tags (tag)' "
git tag -l --no-contains v1.0 v* >actual &&
test_cmp expected actual
"
test_expect_success 'checking that first commit is in all tags (relative)' "
git tag -l --no-contains HEAD~2 v* >actual &&
test_cmp expected actual
"
cat > expected <<EOF
v2.0
EOF
test_expect_success 'checking that second commit only has one tag' "
git tag -l --contains $hash2 v* >actual &&
test_cmp expected actual
"
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
cat > expected <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
EOF
test_expect_success 'inverse of the last test, with --no-contains' "
git tag -l --no-contains $hash2 v* >actual &&
test_cmp expected actual
"
cat > expected <<EOF
EOF
test_expect_success 'checking that third commit has no tags' "
git tag -l --contains $hash3 v* >actual &&
test_cmp expected actual
"
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
cat > expected <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
v2.0
EOF
test_expect_success 'conversely --no-contains on the third commit lists all tags' "
git tag -l --no-contains $hash3 v* >actual &&
test_cmp expected actual
"
# how about a simple merge?
test_expect_success 'creating simple branch' '
git branch stable v2.0 &&
git checkout stable &&
echo foo-3.0 > foo &&
git commit foo -m fourth &&
git tag v3.0
'
hash4=$(git rev-parse HEAD)
cat > expected <<EOF
v3.0
EOF
test_expect_success 'checking that branch head only has one tag' "
git tag -l --contains $hash4 v* >actual &&
test_cmp expected actual
"
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
cat > expected <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
v2.0
EOF
test_expect_success 'checking that branch head with --no-contains lists all but one tag' "
git tag -l --no-contains $hash4 v* >actual &&
test_cmp expected actual
"
test_expect_success 'merging original branch into this branch' '
git merge --strategy=ours master &&
git tag v4.0
'
cat > expected <<EOF
v4.0
EOF
test_expect_success 'checking that original branch head has one tag now' "
git tag -l --contains $hash3 v* >actual &&
test_cmp expected actual
"
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
cat > expected <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
v2.0
v3.0
EOF
test_expect_success 'checking that original branch head with --no-contains lists all but one tag now' "
git tag -l --no-contains $hash3 v* >actual &&
test_cmp expected actual
"
cat > expected <<EOF
v0.2.1
v1.0
v1.0.1
v1.1.3
v2.0
v3.0
v4.0
EOF
test_expect_success 'checking that initial commit is in all tags' "
git tag -l --contains $hash1 v* >actual &&
test_cmp expected actual
"
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
test_expect_success 'checking that --contains can be used in non-list mode' '
git tag --contains $hash1 v* >actual &&
test_cmp expected actual
'
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
test_expect_success 'checking that initial commit is in all tags with --no-contains' "
>expected &&
git tag -l --no-contains $hash1 v* >actual &&
test_cmp expected actual
"
# mixing modes and options:
test_expect_success 'mixing incompatibles modes and options is forbidden' '
test_must_fail git tag -a &&
test_must_fail git tag -a -l &&
test_must_fail git tag -s &&
test_must_fail git tag -s -l &&
test_must_fail git tag -m &&
test_must_fail git tag -m -l &&
test_must_fail git tag -m "hlagh" &&
test_must_fail git tag -m "hlagh" -l &&
test_must_fail git tag -F &&
test_must_fail git tag -F -l &&
test_must_fail git tag -f &&
test_must_fail git tag -f -l &&
test_must_fail git tag -a -s -m -F &&
test_must_fail git tag -a -s -m -F -l &&
test_must_fail git tag -l -v &&
test_must_fail git tag -l -d &&
test_must_fail git tag -l -v -d &&
test_must_fail git tag -n 100 -v &&
test_must_fail git tag -l -m msg &&
test_must_fail git tag -l -F some file &&
test_must_fail git tag -v -s &&
test_must_fail git tag --contains tag-tree &&
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
test_must_fail git tag --contains tag-blob &&
test_must_fail git tag --no-contains tag-tree &&
test_must_fail git tag --no-contains tag-blob &&
test_must_fail git tag --contains --no-contains &&
test_must_fail git tag --no-with HEAD &&
test_must_fail git tag --no-without HEAD
'
for option in --contains --with --no-contains --without --merged --no-merged --points-at
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
do
test_expect_success "mixing incompatible modes with $option is forbidden" "
test_must_fail git tag -d $option HEAD &&
test_must_fail git tag -d $option HEAD some-tag &&
test_must_fail git tag -v $option HEAD
"
test_expect_success "Doing 'git tag --list-like $option <commit> <pattern> is permitted" "
git tag -n $option HEAD HEAD &&
git tag $option HEAD HEAD &&
git tag $option
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
"
done
# check points-at
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
test_expect_success '--points-at can be used in non-list mode' '
echo v4.0 >expect &&
git tag --points-at=v4.0 "v*" >actual &&
test_cmp expect actual
'
test_expect_success '--points-at is a synonym for --points-at HEAD' '
echo v4.0 >expect &&
git tag --points-at >actual &&
test_cmp expect actual
'
test_expect_success '--points-at finds lightweight tags' '
echo v4.0 >expect &&
git tag --points-at v4.0 >actual &&
test_cmp expect actual
'
test_expect_success '--points-at finds annotated tags of commits' '
git tag -m "v4.0, annotated" annotated-v4.0 v4.0 &&
echo annotated-v4.0 >expect &&
git tag -l --points-at v4.0 "annotated*" >actual &&
test_cmp expect actual
'
test_expect_success '--points-at finds annotated tags of tags' '
git tag -m "describing the v4.0 tag object" \
annotated-again-v4.0 annotated-v4.0 &&
cat >expect <<-\EOF &&
annotated-again-v4.0
annotated-v4.0
EOF
git tag --points-at=annotated-v4.0 >actual &&
test_cmp expect actual
'
test_expect_success 'multiple --points-at are OR-ed together' '
cat >expect <<-\EOF &&
v2.0
v3.0
EOF
git tag --points-at=v2.0 --points-at=v3.0 >actual &&
test_cmp expect actual
'
test_expect_success 'lexical sort' '
git tag foo1.3 &&
git tag foo1.6 &&
git tag foo1.10 &&
git tag -l --sort=refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.10
foo1.3
foo1.6
EOF
test_cmp expect actual
'
test_expect_success 'version sort' '
git tag -l --sort=version:refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.3
foo1.6
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'reverse version sort' '
git tag -l --sort=-version:refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.10
foo1.6
foo1.3
EOF
test_cmp expect actual
'
test_expect_success 'reverse lexical sort' '
git tag -l --sort=-refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.6
foo1.3
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'configured lexical sort' '
test_config tag.sort "v:refname" &&
git tag -l "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.3
foo1.6
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'option override configured sort' '
test_config tag.sort "v:refname" &&
git tag -l --sort=-refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.6
foo1.3
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'invalid sort parameter on command line' '
test_must_fail git tag -l --sort=notvalid "foo*" >actual
'
test_expect_success 'invalid sort parameter in configuratoin' '
test_config tag.sort "v:notvalid" &&
test_must_fail git tag -l "foo*"
'
test_expect_success 'version sort with prerelease reordering' '
test_config versionsort.prereleaseSuffix -rc &&
git tag foo1.6-rc1 &&
git tag foo1.6-rc2 &&
git tag -l --sort=version:refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.3
foo1.6-rc1
foo1.6-rc2
foo1.6
foo1.10
EOF
test_cmp expect actual
'
test_expect_success 'reverse version sort with prerelease reordering' '
test_config versionsort.prereleaseSuffix -rc &&
git tag -l --sort=-version:refname "foo*" >actual &&
cat >expect <<-\EOF &&
foo1.10
foo1.6
foo1.6-rc2
foo1.6-rc1
foo1.3
EOF
test_cmp expect actual
'
versioncmp: cope with common part overlapping with prerelease suffix Version sort with prerelease reordering sometimes puts tagnames in the wrong order, when the common part of two compared tagnames overlaps with the leading character(s) of one or more configured prerelease suffixes. Note the position of "v2.1.0-beta-1": $ git -c versionsort.prereleaseSuffix=-beta \ tag -l --sort=version:refname v2.1.* v2.1.0-beta-2 v2.1.0-beta-3 v2.1.0 v2.1.0-RC1 v2.1.0-RC2 v2.1.0-beta-1 v2.1.1 v2.1.2 The reason is that when comparing a pair of tagnames, first versioncmp() looks for the first different character in a pair of tagnames, and then the swap_prereleases() helper function looks for a configured prerelease suffix _starting at_ that character. Thus, when in the above example the sorting algorithm happens to compare the tagnames "v2.1.0-beta-1" and "v2.1.0-RC2", swap_prereleases() tries to match the suffix "-beta" against "beta-1" to no avail, and the two tagnames erroneously end up being ordered lexicographically. To fix this issue change swap_prereleases() to look for configured prerelease suffixes _containing_ the position of that first different character. Care must be taken, when a configured suffix is longer than the tagnames' common part up to the first different character, to avoid reading memory before the beginning of the tagnames. Add a test that uses an exceptionally long prerelease suffix to check for this, in the hope that in case of a regression the illegal memory access causes a segfault in 'git tag' on one of the commonly used platforms (the test happens to pass successfully on my Linux system with the safety check removed), or at least makes valgrind complain. Under some circumstances it's possible that more than one prerelease suffixes can be found in the same tagname around that first different character. With this simple bugfix patch such a tagname is sorted according to the contained suffix that comes first in the configuration for now. This is less than ideal in some cases, and the following patch will take care of those. Reported-by: Leho Kraav <leho@conversionready.com> Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-08 14:23:59 +00:00
test_expect_success 'version sort with prerelease reordering and common leading character' '
test_config versionsort.prereleaseSuffix -before &&
git tag foo1.7-before1 &&
git tag foo1.7 &&
git tag foo1.7-after1 &&
git tag -l --sort=version:refname "foo1.7*" >actual &&
cat >expect <<-\EOF &&
foo1.7-before1
foo1.7
foo1.7-after1
EOF
test_cmp expect actual
'
versioncmp: cope with common part overlapping with prerelease suffix Version sort with prerelease reordering sometimes puts tagnames in the wrong order, when the common part of two compared tagnames overlaps with the leading character(s) of one or more configured prerelease suffixes. Note the position of "v2.1.0-beta-1": $ git -c versionsort.prereleaseSuffix=-beta \ tag -l --sort=version:refname v2.1.* v2.1.0-beta-2 v2.1.0-beta-3 v2.1.0 v2.1.0-RC1 v2.1.0-RC2 v2.1.0-beta-1 v2.1.1 v2.1.2 The reason is that when comparing a pair of tagnames, first versioncmp() looks for the first different character in a pair of tagnames, and then the swap_prereleases() helper function looks for a configured prerelease suffix _starting at_ that character. Thus, when in the above example the sorting algorithm happens to compare the tagnames "v2.1.0-beta-1" and "v2.1.0-RC2", swap_prereleases() tries to match the suffix "-beta" against "beta-1" to no avail, and the two tagnames erroneously end up being ordered lexicographically. To fix this issue change swap_prereleases() to look for configured prerelease suffixes _containing_ the position of that first different character. Care must be taken, when a configured suffix is longer than the tagnames' common part up to the first different character, to avoid reading memory before the beginning of the tagnames. Add a test that uses an exceptionally long prerelease suffix to check for this, in the hope that in case of a regression the illegal memory access causes a segfault in 'git tag' on one of the commonly used platforms (the test happens to pass successfully on my Linux system with the safety check removed), or at least makes valgrind complain. Under some circumstances it's possible that more than one prerelease suffixes can be found in the same tagname around that first different character. With this simple bugfix patch such a tagname is sorted according to the contained suffix that comes first in the configuration for now. This is less than ideal in some cases, and the following patch will take care of those. Reported-by: Leho Kraav <leho@conversionready.com> Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-08 14:23:59 +00:00
test_expect_success 'version sort with prerelease reordering, multiple suffixes and common leading character' '
test_config versionsort.prereleaseSuffix -before &&
git config --add versionsort.prereleaseSuffix -after &&
git tag -l --sort=version:refname "foo1.7*" >actual &&
cat >expect <<-\EOF &&
foo1.7-before1
foo1.7-after1
foo1.7
EOF
test_cmp expect actual
'
versioncmp: use earliest-longest contained suffix to determine sorting order When comparing tagnames, it is possible that a tagname contains more than one of the configured prerelease suffixes around the first different character. After fixing a bug in the previous commit such a tagname is sorted according to the contained suffix which comes first in the configuration. This is, however, not quite the right thing to do in the following corner cases: 1. $ git -c versionsort.suffix=-bar -c versionsort.suffix=-foo-baz -c versionsort.suffix=-foo-bar tag -l --sort=version:refname 'v1*' v1.0-foo-bar v1.0-foo-baz The suffix of the tagname 'v1.0-foo-bar' is clearly '-foo-bar', so it should be listed last. However, as it also contains '-bar' around the first different character, it is listed first instead, because that '-bar' suffix comes first the configuration. 2. One of the configured suffixes starts with the other: $ git -c versionsort.prereleasesuffix=-pre \ -c versionsort.prereleasesuffix=-prerelease \ tag -l --sort=version:refname 'v2*' v2.0-prerelease1 v2.0-pre1 v2.0-pre2 Here the tagname 'v2.0-prerelease1' should be the last. When comparing 'v2.0-pre1' and 'v2.0-prerelease1' the first different characters are '1' and 'r', respectively. Since this first different character must be part of the configured suffix, the '-pre' suffix is not recognized in the first tagname. OTOH, the '-prerelease' suffix is properly recognized in 'v2.0-prerelease1', thus it is listed first. Improve version sort in these corner cases, and - look for a configured prerelease suffix containing the first different character or ending right before it, so the '-pre' suffixes are recognized in case (2). This also means that when comparing tagnames 'v2.0-pre1' and 'v2.0-pre2', swap_prereleases() would find the '-pre' suffix in both, but then it will return "undecided" and the caller will do the right thing by sorting based in '1' and '2'. - If the tagname contains more than one suffix, then give precedence to the contained suffix that starts at the earliest offset in the tagname to address (1). - If there are more than one suffixes starting at that earliest position, then give precedence to the longest of those suffixes, thus ensuring that in (2) the tagname 'v2.0-prerelease1' won't be sorted based on the '-pre' suffix. Add tests for these corner cases and adjust the documentation accordingly. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-08 14:24:00 +00:00
test_expect_success 'version sort with prerelease reordering, multiple suffixes match the same tag' '
test_config versionsort.prereleaseSuffix -bar &&
git config --add versionsort.prereleaseSuffix -foo-baz &&
git config --add versionsort.prereleaseSuffix -foo-bar &&
git tag foo1.8-foo-bar &&
git tag foo1.8-foo-baz &&
git tag foo1.8 &&
git tag -l --sort=version:refname "foo1.8*" >actual &&
cat >expect <<-\EOF &&
foo1.8-foo-baz
foo1.8-foo-bar
foo1.8
EOF
test_cmp expect actual
'
test_expect_success 'version sort with prerelease reordering, multiple suffixes match starting at the same position' '
test_config versionsort.prereleaseSuffix -pre &&
git config --add versionsort.prereleaseSuffix -prerelease &&
git tag foo1.9-pre1 &&
git tag foo1.9-pre2 &&
git tag foo1.9-prerelease1 &&
git tag -l --sort=version:refname "foo1.9*" >actual &&
cat >expect <<-\EOF &&
foo1.9-pre1
foo1.9-pre2
foo1.9-prerelease1
EOF
test_cmp expect actual
'
versioncmp: generalize version sort suffix reordering The 'versionsort.prereleaseSuffix' configuration variable, as its name suggests, is supposed to only deal with tagnames with prerelease suffixes, and allows sorting those prerelease tags in a user-defined order before the suffixless main release tag, instead of sorting them simply lexicographically. However, the previous changes in this series resulted in an interesting and useful property of version sort: - The empty string as a configured suffix matches all tagnames, including tagnames without any suffix, but - tagnames containing a "real" configured suffix are still ordered according to that real suffix, because any longer suffix takes precedence over the empty string. Exploiting this property we can easily generalize suffix reordering and specify the order of tags with given suffixes not only before but even after a main release tag by using the empty suffix to denote the position of the main release tag, without any algorithm changes: $ git -c versionsort.prereleaseSuffix=-alpha \ -c versionsort.prereleaseSuffix=-beta \ -c versionsort.prereleaseSuffix="" \ -c versionsort.prereleaseSuffix=-gamma \ -c versionsort.prereleaseSuffix=-delta \ tag -l --sort=version:refname 'v3.0*' v3.0-alpha1 v3.0-beta1 v3.0 v3.0-gamma1 v3.0-delta1 Since 'versionsort.prereleaseSuffix' is not a fitting name for a configuration variable to control this more general suffix reordering, introduce the new variable 'versionsort.suffix'. Still keep the old configuration variable name as a deprecated alias, though, to avoid suddenly breaking setups already using it. Ignore the old variable if both old and new configuration variables are set, but emit a warning so users will be aware of it and can fix their configuration. Extend the documentation to describe and add a test to check this more general behavior. Note: since the empty suffix matches all tagnames, tagnames with suffixes not included in the configuration are listed together with the suffixless main release tag, ordered lexicographically right after that, i.e. before tags with suffixes listed in the configuration following the empty suffix. Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-08 14:24:01 +00:00
test_expect_success 'version sort with general suffix reordering' '
test_config versionsort.suffix -alpha &&
git config --add versionsort.suffix -beta &&
git config --add versionsort.suffix "" &&
git config --add versionsort.suffix -gamma &&
git config --add versionsort.suffix -delta &&
git tag foo1.10-alpha &&
git tag foo1.10-beta &&
git tag foo1.10-gamma &&
git tag foo1.10-delta &&
git tag foo1.10-unlisted-suffix &&
git tag -l --sort=version:refname "foo1.10*" >actual &&
cat >expect <<-\EOF &&
foo1.10-alpha
foo1.10-beta
foo1.10
foo1.10-unlisted-suffix
foo1.10-gamma
foo1.10-delta
EOF
test_cmp expect actual
'
test_expect_success 'versionsort.suffix overrides versionsort.prereleaseSuffix' '
test_config versionsort.suffix -before &&
test_config versionsort.prereleaseSuffix -after &&
git tag -l --sort=version:refname "foo1.7*" >actual &&
cat >expect <<-\EOF &&
foo1.7-before1
foo1.7
foo1.7-after1
EOF
test_cmp expect actual
'
versioncmp: cope with common part overlapping with prerelease suffix Version sort with prerelease reordering sometimes puts tagnames in the wrong order, when the common part of two compared tagnames overlaps with the leading character(s) of one or more configured prerelease suffixes. Note the position of "v2.1.0-beta-1": $ git -c versionsort.prereleaseSuffix=-beta \ tag -l --sort=version:refname v2.1.* v2.1.0-beta-2 v2.1.0-beta-3 v2.1.0 v2.1.0-RC1 v2.1.0-RC2 v2.1.0-beta-1 v2.1.1 v2.1.2 The reason is that when comparing a pair of tagnames, first versioncmp() looks for the first different character in a pair of tagnames, and then the swap_prereleases() helper function looks for a configured prerelease suffix _starting at_ that character. Thus, when in the above example the sorting algorithm happens to compare the tagnames "v2.1.0-beta-1" and "v2.1.0-RC2", swap_prereleases() tries to match the suffix "-beta" against "beta-1" to no avail, and the two tagnames erroneously end up being ordered lexicographically. To fix this issue change swap_prereleases() to look for configured prerelease suffixes _containing_ the position of that first different character. Care must be taken, when a configured suffix is longer than the tagnames' common part up to the first different character, to avoid reading memory before the beginning of the tagnames. Add a test that uses an exceptionally long prerelease suffix to check for this, in the hope that in case of a regression the illegal memory access causes a segfault in 'git tag' on one of the commonly used platforms (the test happens to pass successfully on my Linux system with the safety check removed), or at least makes valgrind complain. Under some circumstances it's possible that more than one prerelease suffixes can be found in the same tagname around that first different character. With this simple bugfix patch such a tagname is sorted according to the contained suffix that comes first in the configuration for now. This is less than ideal in some cases, and the following patch will take care of those. Reported-by: Leho Kraav <leho@conversionready.com> Signed-off-by: SZEDER Gábor <szeder.dev@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-12-08 14:23:59 +00:00
test_expect_success 'version sort with very long prerelease suffix' '
test_config versionsort.prereleaseSuffix -very-looooooooooooooooooooooooong-prerelease-suffix &&
git tag -l --sort=version:refname
'
run_with_limited_stack () {
(ulimit -s 128 && "$@")
}
test_lazy_prereq ULIMIT_STACK_SIZE 'run_with_limited_stack true'
# we require ulimit, this excludes Windows
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
test_expect_success ULIMIT_STACK_SIZE '--contains and --no-contains work in a deep repo' '
>expect &&
i=1 &&
while test $i -lt 8000
do
echo "commit refs/heads/master
committer A U Thor <author@example.com> $((1000000000 + $i * 100)) +0200
data <<EOF
commit #$i
EOF"
test $i = 1 && echo "from refs/heads/master^0"
i=$(($i + 1))
done | git fast-import &&
git checkout master &&
git tag far-far-away HEAD^ &&
run_with_limited_stack git tag --contains HEAD >actual &&
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
test_cmp expect actual &&
run_with_limited_stack git tag --no-contains HEAD >actual &&
test_line_count "-gt" 10 actual
'
test_expect_success '--format should list tags as per format given' '
cat >expect <<-\EOF &&
refname : refs/tags/v1.0
refname : refs/tags/v1.0.1
refname : refs/tags/v1.1.3
EOF
git tag -l --format="refname : %(refname)" "v1*" >actual &&
test_cmp expect actual
'
test_expect_success 'setup --merged test tags' '
git tag mergetest-1 HEAD~2 &&
git tag mergetest-2 HEAD~1 &&
git tag mergetest-3 HEAD
'
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
test_expect_success '--merged can be used in non-list mode' '
cat >expect <<-\EOF &&
mergetest-1
mergetest-2
EOF
git tag --merged=mergetest-2 "mergetest*" >actual &&
test_cmp expect actual
'
test_expect_success '--merged is incompatible with --no-merged' '
test_must_fail git tag --merged HEAD --no-merged HEAD
'
test_expect_success '--merged shows merged tags' '
cat >expect <<-\EOF &&
mergetest-1
mergetest-2
EOF
git tag -l --merged=mergetest-2 mergetest-* >actual &&
test_cmp expect actual
'
test_expect_success '--no-merged show unmerged tags' '
cat >expect <<-\EOF &&
mergetest-3
EOF
git tag -l --no-merged=mergetest-2 mergetest-* >actual &&
test_cmp expect actual
'
tag: implicitly supply --list given another list-like option Change the "tag" command to implicitly turn on its --list mode when provided with a list-like option such as --contains, --points-at etc. This is for consistency with how "branch" works. When "branch" is given a list-like option, such as --contains, it implicitly provides --list. Before this change "tag" would error out on those sorts of invocations. I.e. while both of these worked for "branch": git branch --contains v2.8.0 <pattern> git branch --list --contains v2.8.0 <pattern> Only the latter form worked for "tag": git tag --contains v2.8.0 '*rc*' git tag --list --contains v2.8.0 '*rc*' Now "tag", like "branch", will implicitly supply --list when a list-like option is provided, and no other conflicting non-list options (such as -d) are present on the command-line. Spelunking through the history via: git log --reverse -p -G'only allowed with' -- '*builtin*tag*c' Reveals that there was no good reason for not allowing this in the first place. The --contains option added in 32c35cfb1e ("git-tag: Add --contains option", 2009-01-26) made this an error. All the other subsequent list-like options that were added copied its pattern of making this usage an error. The only tests that break as a result of this change are tests that were explicitly checking that this "branch-like" usage wasn't permitted. Change those failing tests to check that this invocation mode is permitted, add extra tests for the list-like options we weren't testing, and tests to ensure that e.g. we don't toggle the list mode in the presence of other conflicting non-list options. With this change errors messages such as "--contains option is only allowed with -l" don't make sense anymore, since options like --contain turn on -l. Instead we error out when list-like options such as --contain are used in conjunction with conflicting options such as -d or -v. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:55 +00:00
test_expect_success '--no-merged can be used in non-list mode' '
git tag --no-merged=mergetest-2 mergetest-* >actual &&
test_cmp expect actual
'
tag: do not show ambiguous tag names as "tags/foo" Since b7cc53e9 (tag.c: use 'ref-filter' APIs, 2015-07-11), git-tag has started showing tags with ambiguous names (i.e., when both "heads/foo" and "tags/foo" exists) as "tags/foo" instead of just "foo". This is both: - pointless; the output of "git tag" includes only refs/tags, so we know that "foo" means the one in "refs/tags". and - ambiguous; in the original output, we know that the line "foo" means that "refs/tags/foo" exists. In the new output, it is unclear whether we mean "refs/tags/foo" or "refs/tags/tags/foo". The reason this happens is that commit b7cc53e9 switched git-tag to use ref-filter's "%(refname:short)" output formatting, which was adapted from for-each-ref. This more general code does not know that we care only about tags, and uses shorten_unambiguous_ref to get the short-name. We need to tell it that we care only about "refs/tags/", and it should shorten with respect to that value. In theory, the ref-filter code could figure this out by us passing FILTER_REFS_TAGS. But there are two complications there: 1. The handling of refname:short is deep in formatting code that does not even have our ref_filter struct, let alone the arguments to the filter_ref struct. 2. In git v2.7.0, we expose the formatting language to the user. If we follow this path, it will mean that "%(refname:short)" behaves differently for "tag" versus "for-each-ref" (including "for-each-ref refs/tags/"), which can lead to confusion. Instead, let's add a new modifier to the formatting language, "strip", to remove a specific set of prefix components. This fixes "git tag", and lets users invoke the same behavior from their own custom formats (for "tag" or "for-each-ref") while leaving ":short" with its same consistent meaning in all places. We introduce a test in t7004 for "git tag", which fails without this patch. We also add a similar test in t3203 for "git branch", which does not actually fail. But since it is likely that "branch" will eventually use the same formatting code, the test helps defend against future regressions. Signed-off-by: Jeff King <peff@peff.net> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2016-01-26 03:00:05 +00:00
test_expect_success 'ambiguous branch/tags not marked' '
git tag ambiguous &&
git branch ambiguous &&
echo ambiguous >expect &&
git tag -l ambiguous >actual &&
test_cmp expect actual
'
ref-filter: add --no-contains option to tag/branch/for-each-ref Change the tag, branch & for-each-ref commands to have a --no-contains option in addition to their longstanding --contains options. This allows for finding the last-good rollout tag given a known-bad <commit>. Given a hypothetically bad commit cf5c7253e0, the git version to revert to can be found with this hacky two-liner: (git tag -l 'v[0-9]*'; git tag -l --contains cf5c7253e0 'v[0-9]*') | sort | uniq -c | grep -E '^ *1 ' | awk '{print $2}' | tail -n 10 With this new --no-contains option the same can be achieved with: git tag -l --no-contains cf5c7253e0 'v[0-9]*' | sort | tail -n 10 As the filtering machinery is shared between the tag, branch & for-each-ref commands, implement this for those commands too. A practical use for this with "branch" is e.g. finding branches which were branched off between v2.8.0 and v2.10.0: git branch --contains v2.8.0 --no-contains v2.10.0 The "describe" command also has a --contains option, but its semantics are unrelated to what tag/branch/for-each-ref use --contains for. A --no-contains option for "describe" wouldn't make any sense, other than being exactly equivalent to not supplying --contains at all, which would be confusing at best. Add a --without option to "tag" as an alias for --no-contains, for consistency with --with and --contains. The --with option is undocumented, and possibly the only user of it is Junio (<xmqqefy71iej.fsf@gitster.mtv.corp.google.com>). But it's trivial to support, so let's do that. The additions to the the test suite are inverse copies of the corresponding --contains tests. With this change --no-contains for tag, branch & for-each-ref is just as well tested as the existing --contains option. In addition to those tests, add a test for "tag" which asserts that --no-contains won't find tree/blob tags, which is slightly unintuitive, but consistent with how --contains works & is documented. Signed-off-by: Ævar Arnfjörð Bjarmason <avarab@gmail.com> Signed-off-by: Junio C Hamano <gitster@pobox.com>
2017-03-24 18:40:57 +00:00
test_expect_success '--contains combined with --no-contains' '
(
git init no-contains &&
cd no-contains &&
test_commit v0.1 &&
test_commit v0.2 &&
test_commit v0.3 &&
test_commit v0.4 &&
test_commit v0.5 &&
cat >expected <<-\EOF &&
v0.2
v0.3
v0.4
EOF
git tag --contains v0.2 --no-contains v0.5 >actual &&
test_cmp expected actual
)
'
# As the docs say, list tags which contain a specified *commit*. We
# don't recurse down to tags for trees or blobs pointed to by *those*
# commits.
test_expect_success 'Does --[no-]contains stop at commits? Yes!' '
cd no-contains &&
blob=$(git rev-parse v0.3:v0.3.t) &&
tree=$(git rev-parse v0.3^{tree}) &&
git tag tag-blob $blob &&
git tag tag-tree $tree &&
git tag --contains v0.3 >actual &&
cat >expected <<-\EOF &&
v0.3
v0.4
v0.5
EOF
test_cmp expected actual &&
git tag --no-contains v0.3 >actual &&
cat >expected <<-\EOF &&
v0.1
v0.2
EOF
test_cmp expected actual
'
test_done