git/t/t6300-for-each-ref.sh
Bert Wesarg 7d66f21a1b for-each-ref: :short format for refname
Tries to shorten the refname to a non-ambiguous name.

Szeder Gábor noticed that the git bash completion takes a
tremendous amount of time to strip leading components from
heads and tags refs (i.e. refs/heads, refs/tags, ...). He
proposed a new atom called 'refbasename' which removes at
most two leading components from the ref name.

I myself, proposed a more dynamic solution, which strips off
common leading components with the matched pattern.

But the current bash solution and both proposals suffer from
one mayor problem: ambiguous refs.

A ref is ambiguous, if it resolves to more than one full refs.
I.e. given the refs refs/heads/xyzzy and refs/tags/xyzzy. The
(short) ref xyzzy can point to both refs.

( Note: Its irrelevant whether the referenced objects are the
  same or not. )

This proposal solves this by checking for ambiguity of the
shorten ref name.

The shortening is done with the same rules for resolving refs
but in the reverse order. The short name is checked if it
resolves to a different ref.

To continue the above example, the output would be like this:

heads/xyzzy
xyzzy

So, if you want just tags, xyzzy is not ambiguous, because it
will resolve to a tag. If you need the heads you get a also
a non-ambiguous short form of the ref.

To integrate this new format into the bash completion to get
only non-ambiguous refs is beyond the scope of this patch.

Signed-off-by: Bert Wesarg <bert.wesarg@googlemail.com>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2008-09-05 23:06:37 -07:00

319 lines
9.7 KiB
Bash
Executable file

#!/bin/sh
#
# Copyright (c) 2007 Andy Parkins
#
test_description='for-each-ref test'
. ./test-lib.sh
# Mon Jul 3 15:18:43 2006 +0000
datestamp=1151939923
setdate_and_increment () {
GIT_COMMITTER_DATE="$datestamp +0200"
datestamp=$(expr "$datestamp" + 1)
GIT_AUTHOR_DATE="$datestamp +0200"
datestamp=$(expr "$datestamp" + 1)
export GIT_COMMITTER_DATE GIT_AUTHOR_DATE
}
test_expect_success 'Create sample commit with known timestamp' '
setdate_and_increment &&
echo "Using $datestamp" > one &&
git add one &&
git commit -m "Initial" &&
setdate_and_increment &&
git tag -a -m "Tagging at $datestamp" testtag
'
test_atom() {
case "$1" in
head) ref=refs/heads/master ;;
tag) ref=refs/tags/testtag ;;
esac
printf '%s\n' "$3" >expected
test_expect_${4:-success} "basic atom: $1 $2" "
git for-each-ref --format='%($2)' $ref >actual &&
test_cmp expected actual
"
}
test_atom head refname refs/heads/master
test_atom head objecttype commit
test_atom head objectsize 171
test_atom head objectname 67a36f10722846e891fbada1ba48ed035de75581
test_atom head tree 0e51c00fcb93dffc755546f27593d511e1bdb46f
test_atom head parent ''
test_atom head numparent 0
test_atom head object ''
test_atom head type ''
test_atom head author 'A U Thor <author@example.com> 1151939924 +0200'
test_atom head authorname 'A U Thor'
test_atom head authoremail '<author@example.com>'
test_atom head authordate 'Mon Jul 3 17:18:44 2006 +0200'
test_atom head committer 'C O Mitter <committer@example.com> 1151939923 +0200'
test_atom head committername 'C O Mitter'
test_atom head committeremail '<committer@example.com>'
test_atom head committerdate 'Mon Jul 3 17:18:43 2006 +0200'
test_atom head tag ''
test_atom head tagger ''
test_atom head taggername ''
test_atom head taggeremail ''
test_atom head taggerdate ''
test_atom head creator 'C O Mitter <committer@example.com> 1151939923 +0200'
test_atom head creatordate 'Mon Jul 3 17:18:43 2006 +0200'
test_atom head subject 'Initial'
test_atom head body ''
test_atom head contents 'Initial
'
test_atom tag refname refs/tags/testtag
test_atom tag objecttype tag
test_atom tag objectsize 154
test_atom tag objectname 98b46b1d36e5b07909de1b3886224e3e81e87322
test_atom tag tree ''
test_atom tag parent ''
test_atom tag numparent ''
test_atom tag object '67a36f10722846e891fbada1ba48ed035de75581'
test_atom tag type 'commit'
test_atom tag author ''
test_atom tag authorname ''
test_atom tag authoremail ''
test_atom tag authordate ''
test_atom tag committer ''
test_atom tag committername ''
test_atom tag committeremail ''
test_atom tag committerdate ''
test_atom tag tag 'testtag'
test_atom tag tagger 'C O Mitter <committer@example.com> 1151939925 +0200'
test_atom tag taggername 'C O Mitter'
test_atom tag taggeremail '<committer@example.com>'
test_atom tag taggerdate 'Mon Jul 3 17:18:45 2006 +0200'
test_atom tag creator 'C O Mitter <committer@example.com> 1151939925 +0200'
test_atom tag creatordate 'Mon Jul 3 17:18:45 2006 +0200'
test_atom tag subject 'Tagging at 1151939927'
test_atom tag body ''
test_atom tag contents 'Tagging at 1151939927
'
test_expect_success 'Check invalid atoms names are errors' '
test_must_fail git for-each-ref --format="%(INVALID)" refs/heads
'
test_expect_success 'Check format specifiers are ignored in naming date atoms' '
git for-each-ref --format="%(authordate)" refs/heads &&
git for-each-ref --format="%(authordate:default) %(authordate)" refs/heads &&
git for-each-ref --format="%(authordate) %(authordate:default)" refs/heads &&
git for-each-ref --format="%(authordate:default) %(authordate:default)" refs/heads
'
test_expect_success 'Check valid format specifiers for date fields' '
git for-each-ref --format="%(authordate:default)" refs/heads &&
git for-each-ref --format="%(authordate:relative)" refs/heads &&
git for-each-ref --format="%(authordate:short)" refs/heads &&
git for-each-ref --format="%(authordate:local)" refs/heads &&
git for-each-ref --format="%(authordate:iso8601)" refs/heads &&
git for-each-ref --format="%(authordate:rfc2822)" refs/heads
'
test_expect_success 'Check invalid format specifiers are errors' '
test_must_fail git for-each-ref --format="%(authordate:INVALID)" refs/heads
'
cat >expected <<\EOF
'refs/heads/master' 'Mon Jul 3 17:18:43 2006 +0200' 'Mon Jul 3 17:18:44 2006 +0200'
'refs/tags/testtag' 'Mon Jul 3 17:18:45 2006 +0200'
EOF
test_expect_success 'Check unformatted date fields output' '
(git for-each-ref --shell --format="%(refname) %(committerdate) %(authordate)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate)" refs/tags) >actual &&
test_cmp expected actual
'
test_expect_success 'Check format "default" formatted date fields output' '
f=default &&
(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
test_cmp expected actual
'
# Don't know how to do relative check because I can't know when this script
# is going to be run and can't fake the current time to git, and hence can't
# provide expected output. Instead, I'll just make sure that "relative"
# doesn't exit in error
#
#cat >expected <<\EOF
#
#EOF
#
test_expect_success 'Check format "relative" date fields output' '
f=relative &&
(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual
'
cat >expected <<\EOF
'refs/heads/master' '2006-07-03' '2006-07-03'
'refs/tags/testtag' '2006-07-03'
EOF
test_expect_success 'Check format "short" date fields output' '
f=short &&
(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
'refs/heads/master' 'Mon Jul 3 15:18:43 2006' 'Mon Jul 3 15:18:44 2006'
'refs/tags/testtag' 'Mon Jul 3 15:18:45 2006'
EOF
test_expect_success 'Check format "local" date fields output' '
f=local &&
(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
'refs/heads/master' '2006-07-03 17:18:43 +0200' '2006-07-03 17:18:44 +0200'
'refs/tags/testtag' '2006-07-03 17:18:45 +0200'
EOF
test_expect_success 'Check format "iso8601" date fields output' '
f=iso8601 &&
(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
'refs/heads/master' 'Mon, 3 Jul 2006 17:18:43 +0200' 'Mon, 3 Jul 2006 17:18:44 +0200'
'refs/tags/testtag' 'Mon, 3 Jul 2006 17:18:45 +0200'
EOF
test_expect_success 'Check format "rfc2822" date fields output' '
f=rfc2822 &&
(git for-each-ref --shell --format="%(refname) %(committerdate:$f) %(authordate:$f)" refs/heads &&
git for-each-ref --shell --format="%(refname) %(taggerdate:$f)" refs/tags) >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
refs/heads/master
refs/tags/testtag
EOF
test_expect_success 'Verify ascending sort' '
git for-each-ref --format="%(refname)" --sort=refname >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
refs/tags/testtag
refs/heads/master
EOF
test_expect_success 'Verify descending sort' '
git for-each-ref --format="%(refname)" --sort=-refname >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
'refs/heads/master'
'refs/tags/testtag'
EOF
test_expect_success 'Quoting style: shell' '
git for-each-ref --shell --format="%(refname)" >actual &&
test_cmp expected actual
'
test_expect_success 'Quoting style: perl' '
git for-each-ref --perl --format="%(refname)" >actual &&
test_cmp expected actual
'
test_expect_success 'Quoting style: python' '
git for-each-ref --python --format="%(refname)" >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
"refs/heads/master"
"refs/tags/testtag"
EOF
test_expect_success 'Quoting style: tcl' '
git for-each-ref --tcl --format="%(refname)" >actual &&
test_cmp expected actual
'
for i in "--perl --shell" "-s --python" "--python --tcl" "--tcl --perl"; do
test_expect_success "more than one quoting style: $i" "
git for-each-ref $i 2>&1 | (read line &&
case \$line in
\"error: more than one quoting style\"*) : happy;;
*) false
esac)
"
done
cat >expected <<\EOF
master
testtag
EOF
test_expect_success 'Check short refname format' '
(git for-each-ref --format="%(refname:short)" refs/heads &&
git for-each-ref --format="%(refname:short)" refs/tags) >actual &&
test_cmp expected actual
'
test_expect_success 'Check for invalid refname format' '
test_must_fail git for-each-ref --format="%(refname:INVALID)"
'
cat >expected <<\EOF
heads/master
master
EOF
test_expect_success 'Check ambiguous head and tag refs' '
git checkout -b newtag &&
echo "Using $datestamp" > one &&
git add one &&
git commit -m "Branch" &&
setdate_and_increment &&
git tag -m "Tagging at $datestamp" master &&
git for-each-ref --format "%(refname:short)" refs/heads/master refs/tags/master >actual &&
test_cmp expected actual
'
cat >expected <<\EOF
heads/ambiguous
ambiguous
EOF
test_expect_success 'Check ambiguous head and tag refs II' '
git checkout master &&
git tag ambiguous testtag^0 &&
git branch ambiguous testtag^0 &&
git for-each-ref --format "%(refname:short)" refs/heads/ambiguous refs/tags/ambiguous >actual &&
test_cmp expected actual
'
test_expect_success 'an unusual tag with an incomplete line' '
git tag -m "bogo" bogo &&
bogo=$(git cat-file tag bogo) &&
bogo=$(printf "%s" "$bogo" | git mktag) &&
git tag -f bogo "$bogo" &&
git for-each-ref --format "%(body)" refs/tags/bogo
'
test_done