fetch-pack: match refs exactly
When we are determining the list of refs to fetch via
fetch-pack, we have two sets of refs to compare: those on
the remote side, and a "match" list of things we want to
fetch. We iterate through the remote refs alphabetically,
seeing if each one is wanted by the "match" list.
Since def88e9 (Commit first cut at "git-fetch-pack",
2005-07-04), we have used the "path_match" function to do a
suffix match, where a remote ref is considered wanted if
any of the "match" elements is a suffix of the remote
refname.
This enables callers of fetch-pack to specify unqualified
refs and have them matched up with remote refs (e.g., ask
for "A" and get remote's "refs/heads/A"). However, if you
provide a fully qualified ref, then there are corner cases
where we provide the wrong answer. For example, given a
remote with two refs:
refs/foo/refs/heads/master
refs/heads/master
asking for "refs/heads/master" will first match
"refs/foo/refs/heads/master" by the suffix rule, and we will
erroneously fetch it instead of refs/heads/master.
As it turns out, all callers of fetch_pack do provide
fully-qualified refs for the match list. There are two ways
fetch_pack can get match lists:
1. Through the transport code (i.e., via git-fetch)
2. On the command-line of git-fetch-pack
In the first case, we will always be providing the names of
fully-qualified refs from "struct ref" objects. We will have
pre-matched those ref objects already (since we have to
handle more advanced matching, like wildcard refspecs), and
are just providing a list of the refs whose objects we need.
In the second case, users could in theory be providing
non-qualified refs on the command-line. However, the
fetch-pack documentation claims that refs should be fully
qualified (and has always done so since it was written in
2005).
Let's change this path_match call to simply check for string
equality, matching what the callers of fetch_pack are
expecting.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-13 04:48:08 +04:00
|
|
|
#!/bin/sh
|
|
|
|
|
|
|
|
test_description='test fetching of oddly-named refs'
|
|
|
|
. ./test-lib.sh
|
|
|
|
|
|
|
|
# afterwards we will have:
|
|
|
|
# HEAD - two
|
|
|
|
# refs/for/refs/heads/master - one
|
|
|
|
# refs/heads/master - three
|
|
|
|
test_expect_success 'setup repo with odd suffix ref' '
|
|
|
|
echo content >file &&
|
|
|
|
git add . &&
|
|
|
|
git commit -m one &&
|
|
|
|
git update-ref refs/for/refs/heads/master HEAD &&
|
|
|
|
echo content >>file &&
|
|
|
|
git commit -a -m two &&
|
|
|
|
echo content >>file &&
|
|
|
|
git commit -a -m three &&
|
|
|
|
git checkout HEAD^
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success 'suffix ref is ignored during fetch' '
|
|
|
|
git clone --bare file://"$PWD" suffix &&
|
|
|
|
echo three >expect &&
|
|
|
|
git --git-dir=suffix log -1 --format=%s refs/heads/master >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
pkt-line: allow writing of LARGE_PACKET_MAX buffers
When we send out pkt-lines with refnames, we use a static
1000-byte buffer. This means that the maximum size of a ref
over the git protocol is around 950 bytes (the exact size
depends on the protocol line being written, but figure on a sha1
plus some boilerplate).
This is enough for any sane workflow, but occasionally odd
things happen (e.g., a bug may create a ref "foo/foo/foo/..."
accidentally). With the current code, you cannot even use
"push" to delete such a ref from a remote.
Let's switch to using a strbuf, with a hard-limit of
LARGE_PACKET_MAX (which is specified by the protocol). This
matches the size of the readers, as of 74543a0 (pkt-line:
provide a LARGE_PACKET_MAX static buffer, 2013-02-20).
Versions of git older than that will complain about our
large packets, but it's really no worse than the current
behavior. Right now the sender barfs with "impossibly long
line" trying to send the packet, and afterwards the reader
will barf with "protocol error: bad line length %d", which
is arguably better anyway.
Note that we're not really _solving_ the problem here, but
just bumping the limits. In theory, the length of a ref is
unbounded, and pkt-line can only represent sizes up to
65531 bytes. So we are just bumping the limit, not removing
it. But hopefully 64K should be enough for anyone.
As a bonus, by using a strbuf for the formatting we can
eliminate an unnecessary copy in format_buf_write.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2014-12-10 12:47:02 +03:00
|
|
|
test_expect_success 'try to create repo with absurdly long refname' '
|
|
|
|
ref240=$_z40/$_z40/$_z40/$_z40/$_z40/$_z40 &&
|
|
|
|
ref1440=$ref240/$ref240/$ref240/$ref240/$ref240/$ref240 &&
|
|
|
|
git init long &&
|
|
|
|
(
|
|
|
|
cd long &&
|
|
|
|
test_commit long &&
|
|
|
|
test_commit master
|
|
|
|
) &&
|
|
|
|
if git -C long update-ref refs/heads/$ref1440 long; then
|
|
|
|
test_set_prereq LONG_REF
|
|
|
|
else
|
|
|
|
echo >&2 "long refs not supported"
|
|
|
|
fi
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success LONG_REF 'fetch handles extremely long refname' '
|
|
|
|
git fetch long refs/heads/*:refs/remotes/long/* &&
|
|
|
|
cat >expect <<-\EOF &&
|
|
|
|
long
|
|
|
|
master
|
|
|
|
EOF
|
|
|
|
git for-each-ref --format="%(subject)" refs/remotes/long >actual &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
|
|
|
test_expect_success LONG_REF 'push handles extremely long refname' '
|
|
|
|
git push long :refs/heads/$ref1440 &&
|
|
|
|
git -C long for-each-ref --format="%(subject)" refs/heads >actual &&
|
|
|
|
echo master >expect &&
|
|
|
|
test_cmp expect actual
|
|
|
|
'
|
|
|
|
|
fetch-pack: match refs exactly
When we are determining the list of refs to fetch via
fetch-pack, we have two sets of refs to compare: those on
the remote side, and a "match" list of things we want to
fetch. We iterate through the remote refs alphabetically,
seeing if each one is wanted by the "match" list.
Since def88e9 (Commit first cut at "git-fetch-pack",
2005-07-04), we have used the "path_match" function to do a
suffix match, where a remote ref is considered wanted if
any of the "match" elements is a suffix of the remote
refname.
This enables callers of fetch-pack to specify unqualified
refs and have them matched up with remote refs (e.g., ask
for "A" and get remote's "refs/heads/A"). However, if you
provide a fully qualified ref, then there are corner cases
where we provide the wrong answer. For example, given a
remote with two refs:
refs/foo/refs/heads/master
refs/heads/master
asking for "refs/heads/master" will first match
"refs/foo/refs/heads/master" by the suffix rule, and we will
erroneously fetch it instead of refs/heads/master.
As it turns out, all callers of fetch_pack do provide
fully-qualified refs for the match list. There are two ways
fetch_pack can get match lists:
1. Through the transport code (i.e., via git-fetch)
2. On the command-line of git-fetch-pack
In the first case, we will always be providing the names of
fully-qualified refs from "struct ref" objects. We will have
pre-matched those ref objects already (since we have to
handle more advanced matching, like wildcard refspecs), and
are just providing a list of the refs whose objects we need.
In the second case, users could in theory be providing
non-qualified refs on the command-line. However, the
fetch-pack documentation claims that refs should be fully
qualified (and has always done so since it was written in
2005).
Let's change this path_match call to simply check for string
equality, matching what the callers of fetch_pack are
expecting.
Signed-off-by: Jeff King <peff@peff.net>
Signed-off-by: Junio C Hamano <gitster@pobox.com>
2011-12-13 04:48:08 +04:00
|
|
|
test_done
|