t7900: Demonstrate failure to expand "$remote/$branch" according to refspecs

This test verifies that the following expressions all evaluate to the
full refname "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).

Mirroring the expansion of the above 4 expressions into the full refname,
the same 4 expression should also be shortened into "origin/master" when
abbreviating them into their shortest unambiguous representation, e.g.
when running "git rev-parse --abbrev-ref" on them. A (currently failing)
test verifying this behavior is also added by this patch.

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>
refname_match(): Caller must declare if we're matching local or remote refs

In preparation for adding alternative ways of expanding refspecs, we
need to take into account that not all such alternatives may be
appropriate in all circumstances. Specifically, refname_match() is used
to check whether a given shorthand name matches a given full refname,
but that full refname does not always belong in the local repo, rather
it is sometimes taken from list of refs sent over from a remote repo.

When a remote refname is passed, it would be wrong to apply expansion
rules whose behavior rely on configuration specific to the local repo.
Hence, when calling refname_match(), we must specify whether we want
expansion of a local ref or a remote ref.

Implement this differentiation by adding a flags argument to
refname_match() that takes either REFNAME_MATCH_LOCAL or
REFNAME_MATCH_REMOTE. Furthermore, tag each expansion rule with the
flags it supports (currently all rules support expansion in both
local and remote contexts, since the rules are constant and independent
of local repo details). Finally, teach refname_match() to skip rules
that don't support the given context.

The callers of refname_match now pass the appropriate context in the
new flags argument. The same flags argument could be added to the other
functions that use ref_expand_rules as well (dwim_ref(), dwim_log() and
shorten_unambiguous_ref()), but are AFAICS always called in a local
context.

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

WIP: This strcmp is needed when we add the extra rule for remote refspec resolving
FIXME: Add more tests, with multiple new-style remotes, and making sure shortening is unambiguous, etc.
FIXME: Add removal of { ref_expand_txtly, ref_shorten_txtly, "refs/remotes/%.*s" } as the next commit (does it pass tests?).
FIXME: What about { ref_expand_txtly, ref_shorten_txtly, "refs/remotes/%.*s/HEAD" }, txtly -> refspec entry?
FIXME: What about prettify_refname()?

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/*).
Correspondingly, a full remote-tracking branch name, can only be
shortened to the "$remote/$branch" form if it textually matches the
"refs/remotes/$remote/$branch" format.

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.
Ditto for the corresponding shortening.

Instead of doing pure textual expansion (from "$remote/$branch" to
"refs/remotes/$remote/$branch"), we should expand by finding 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.

Likewise, when shortening full refnames for remote-tracking branches into
their shorthand form ("$remote/$branch"), we should find the refspec with
the RHS that matches the full remote-tracking branch name, and map
through that refspec to produce the corresponding LHS (minus the leading
"refs/heads/" part), and from that construct the corresponding
"$remote/$branch" shorthand.

This patch adds a new expansion method - ref_expand_refspec() - and a
corresponding shortening method - ref_shorten_refspec() - that implements
the remote refspec traversal and expanding/shortening logic described
above. These expand/shorten methods complement the existing
ref_expand_txtly() and ref_shorten_txtly() methods that implement the
current textual expanding/shortening logic.

Implementing the proper expanding/shortening of "$remote/$branch" is now
a simple matter of adding another entry to the ref_expand_rules list,
using the new ref_expand_refspec() and ref_shorten_refspec() functions.

Note that the existing "refs/remotes/*" textual expansion/shortening rule
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>
DOA: Prepare for removal of textual refs/remotes/* substitution