shorten_unambiguous_ref(): Allow shortening refs/remotes/origin/HEAD to origin

When expanding shorthand refs to full ref names (e.g. in dwim_ref()),
we use the ref_rev_parse_rules list of expansion patterns. This list
allows "origin" to be expanded into "refs/remotes/origin/HEAD", by
using the "refs/remotes/%.*s/HEAD" pattern from that list.

shorten_unambiguous_ref() exists to provide the reverse operation:
turning a full ref name into a shorter (but still unambiguous) name.
It does so by matching the given refname against each pattern from
the ref_rev_parse_rules list (in reverse), and extracting the short-
hand name from the matching rule.

However, when given "refs/remotes/origin/HEAD" it fails to shorten it
into "origin", because we misuse the sscanf() function when matching
"refs/remotes/origin/HEAD" against "refs/remotes/%.*s/HEAD": We end
up calling sscanf like this:

  sscanf("refs/remotes/origin/HEAD", "refs/remotes/%s/HEAD", short_name)

In this case, sscanf() will match the initial "refs/remotes/" part, and
then match the remainder of the refname against the "%s", and place it
("origin/HEAD") into short_name. The part of the pattern following the
"%s" format is never verified, because sscanf() apparently does not
need to do that (it has performed the one expected format extraction,
and will return 1 correspondingly; see [1] for more details).

This patch replaces the misuse of sscanf() with a fairly simple function
that manually matches the refname against patterns, and extracts the
shorthand name.

Also a testcase verifying "refs/remotes/origin/HEAD" -> "origin" has
been added.

[1]: If we assume that sscanf() does not do a verification pass prior
to format extraction, there is AFAICS _no_ way for sscanf() - having
already done one or more format extractions - to indicate to its caller
that the input fails to match the trailing part of the format string.
In other words, AFAICS, the scanf() family of function will only verify
matching input up to and including the last format specifier in the
format string. Any data following the last format specifier will not be
verified. Yet another reason to consider the scanf functions harmful...

Cc: Bert Wesarg <bert.wesarg@googlemail.com>
Signed-off-by: Johan Herland <johan@herland.net>
t7900: Start testing usability of namespaced remote refs

Some users are interested in fetching remote refs into a separate namespace
in the local repo. E.g. instead of the usual remote config:

  [remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/*
	url = ...

they want to keep remote tags separate from local tags, and they may also
want to fetch other ref types:

  [remote "origin"]
	fetch = +refs/heads/*:refs/remotes/origin/heads/*
	fetch = +refs/tags/*:refs/remotes/origin/tags/*
	fetch = +refs/notes/*:refs/remotes/origin/notes/*
	fetch = +refs/replace/*:refs/remotes/origin/replace/*
	tagopt = "--no-tags"
	url = ...

This configuration creates a separate namespace under refs/remotes/origin/*
mirroring the structure of local refs (under refs/*) where all the relevant
refs from the 'origin' remote can be found.

This patch introduces a test whose main purpose is to verify that git will
work comfortably with this kind of setup. For now, we only verify that it
is possible (though not exactly easy) to establish a clone with the above
configuration, and that fetching into it yields the expected result.

Signed-off-by: Johan Herland <johan@herland.net>
t7900: Demonstrate failure to expand "$remote/$branch" according to refspecs

This test verifies that the following expressions all evaluate to
"refs/remotes/origin/heads/master":

 - refs/remotes/origin/heads/master
 - remotes/origin/heads/master
 - origin/heads/master
 - origin/master

Currently the last of these fail, because the "$remote/$branch" syntax only
works for remotes with conventional (refs/heads/*:refs/remotes/origin/*)
refspecs.

In order for users of namespaced remote refs (or any other unconventional
refspec configuration) to be able to use the "$remote/$branch" syntax, we
need to extend the parsing of "$remote/$branch" expressions to take the
configured refspecs into account (i.e. look up the fetch refspecs for
$remote, and map "refs/heads/$branch" through the refspecs to find the
corresponding remote-tracking branch name).

Signed-off-by: Johan Herland <johan@herland.net>
refs.c: Refactor rules for expanding shorthand names into full refnames

In preparation for allowing alternative ways of expanding shorthand refs
(like "master") into full refnames (like "refs/heads/master"): Expand
the current ref_rev_parse_rules list into ref_expand_rules, a list of
struct ref_expand_rule objects that encode both an expansion pattern
(e.g. "refs/heads/%.*s") and an associated expansion function
(e.g. the code that applies "master" to "refs/heads/%.*s" to produce
"refs/heads/master"). This allows us to later add expansion rules that
do something other than the current purely textual expansion.

The current expansion behavior is encoded in the new ref_expand_txtly()
helper function, which does the mksnpath() call that were previously
performed by all users of ref_rev_parse_rules.

The end result is identical in behavior to the existing code, but makes
it much easier to adjust the way ref expansion happens for remote-
tracking branches in future patches

Existing code that uses ref_rev_parse_rules to expand shorthand refs are
converted to use ref_expand_rules instead. One of these sites is
refname_match(), whose callers all pass the ref_rev_parse_rules list as
the third argument to the function. In this case, we remove the third
argument and make the rules list internal to refname_match() rather than
exposing ref_expand_rules and struct ref_expand_rule in cache.h.

Signed-off-by: Johan Herland <johan@herland.net>
refs.c: Refactor code for shortening full refnames into shorthand names

shorten_unambiguous_ref() provides the reverse functionality to the
expansion of shorthand names into full refnames, i.e. it takes a full
refname (like "refs/heads/master"), and matches it against a pattern
(like "refs/heads/%.*s") to produce a shorthand name (like "master").

Being the last remaining user of ref_rev_parse_rules list, this patch
converts it to use ref_expand_rules instead. However, as we associated
an expansion function with each expansion rule - to allow for alternative
expansion behavior in the future - we also need to associate a
"shortening" function with each rule, to allow for the reverse operation
to be customized as well.

Therefore, we add a "shorten" function to struct ref_expand_rule, to
encode the shortening of a full refname into a shorthand name. The
relevant rule and the full refname is passed as arguments, and the
resulting shorthand name is returned as an allocated string. If the
refname could not be shortened according to the given rule, NULL is
returned.

The reason for moving the allocation of the shorthand name into the
shortening function, is that one assumes the shortening function itself
would best know exactly how much memory is needed to hold the shorthand
string.

Naturally, we provide a shortening function that encodes the current
textual shortening algorithm - called ref_shorten_txtly() - which is
merely a slight refactoring of the former shorten_ref() function.

This patch removes the only remaining user of ref_rev_parse_rules.
It has now been fully replaced by ref_expand_rules. Hence this patch
also removes ref_rev_parse_rules.

Signed-off-by: Johan Herland <johan@herland.net>
refs.c: Add rules for resolving refs using remote refspecs

FIXME: Add shortening of remote-tracking branches into shorthand names as well.
WIP: This strcmp is needed when we add the extra rule for remote refspec resolving

The "$remote/$branch" expression is often used as a shorthand with the
intention of referring to the remote-tracking branch corresponding to
the given $branch in the $remote repo.

Currently, Git resolves this by prepending "refs/remotes/" to the given
"$remote/$branch" expression, resulting in "refs/remotes/$remote/$branch",
which is equivalent to the above intention only when conventional
refspecs are being used (e.g. refs/heads/*:refs/remotes/origin/*).

If unconventional refspecs (e.g. refs/heads/*:refs/remotes/origin/heads/*)
are being used, then the current expansion ("refs/remotes/$remote/$branch")
fails to match the remote-tracking branches from the configured remotes.

Instead of doing a pure textual expansion (from "$remote/$branch" to
"refs/remotes/$remote/$branch"), we should find all remotes matching
"$remote", look up their fetch refspecs, and map "refs/heads/$branch"
through them to find the appropriate remote-tracking branch name
corresponding to "$remote/$branch". This would yield the correct
remote-tracking branch in all cases, both for conventional and
unconventional refspecs.

This patch adds a new expansion method - ref_expand_refspec() - that
performs the remote refspec traversal described above. This expansion
method complements the existing ref_expand_txtly() which performs the
current textual expansion.

Implementing the proper expansion of "$remote/$branch" is now a simple
matter of adding another entry to the ref_expand_rules list, using the
ref_expand_refspec() expansion function.

Note that the  existing "refs/remotes/*" textual expansion is kept to
preserve backwards compatibility for refs under refs/remotes/* that are
not covered by any configured refspec.

Signed-off-by: Johan Herland <johan@herland.net>