repo refs: the .git suffix is reserved in every case
Commit

The CLI spelled one rule five ways -- a HasSuffix in repo create, three
TrimSuffix calls across the ref parsers, and a ToLower-wrapped one in the
mirror-URL parse. All case-sensitive, each with its own list of examples.
Three were wrong, and each one's tests passed.
repo create refused "test.git" with a message naming the spelling to use,
and let "test.GIT" through to the server, which rejects it for carrying
uppercase: a true statement about a different problem, leaving the suffix
rule to be discovered on a second attempt.
parseMirrorCloneURL ran ToLower(TrimSuffix(x)). "CLI.GIT" missed the case-sensitive cut and folded to "cli.git" -- a spelling stored mirrors never carry, so the EqualFold match below it could not find a mirror that plainly exists.
The ref parsers disagreed with the server they dial. A repo transport path
accepts the suffix whatever its case, so git clone entire://.../et/acme/widgets.GIT succeeds while entire repo clone /et/acme/widgets.GIT reported no such repo.
One helper now answers the question. Canonical git draws this line by
purpose, not by taste: case-sensitive when it is merely guessing a local
directory name from a URL (strncmp in git_url_basename), and aggressively
case-insensitive -- plus HFS ignorable codepoints and NTFS short names --
when asking whether a path IS the reserved .git (is_hfs_dotgit,
is_ntfs_dotgit). Both of the CLI's uses are the latter.
The helper lives in gitremote, exported with the constant, and the cli package calls it: cli already imports gitremote, so there is one copy of the rule rather than two kept in sync by comments.
The fold is Entire's, so gitremote.ParseURL applies it only to entire://
remotes. A remote dialed straight at a forge keeps git's case-sensitive
cut, because that is what the forge does: GitHub's transport does not find
git/git.GIT, and reporting "repo" for github.com/org/repo.GIT would
name a repo the URL never reaches.
The .git miss hint now covers both bare-name routes. With --project
given by name, a bare name resolves through repos/resolve, which matches
the name as sent, and its miss (noRepoAtPathErr) was the one that never
said why.
Also send the name that was checked. repo create validated
TrimSpace(args[0]) and put the raw args[0] on the wire, which only ever
worked because the server trims too.
The fixture tables are shared by every call site's tests, so none can pass behind a narrower list again. They cover the case variants, whitespace at both ends, single-cut semantics, the near-misses git pins in its own tests (gitops, .gitignore), and multi-byte final runes.
Refs COR-1892
Entire-Checkpoint: 01M3SM7D59ZJGE3CBT8BABWQ7Q