You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
A sweep of 64 URL forms against libvcs v0.45.1 finds 35 detected correctly, 4 detected as the wrong VCS, and 25 not detected at all. The failures are not one bug — they come from two independent gates, and the two gates need different fixes. This issue consolidates the URL-detection gaps into one place.
Detection here means registry.match(url=url, is_explicit=True), which is what downstream callers use to pick a VCS backend.
Gate 1: the git scheme regex only matches http|https
RE_SCHEME in url/git.py accepts only http and https. Every other transport git supports has no matching rule, so GitURL.is_valid() returns False.
URL
git(1) supports
GitURL.is_valid
ssh://git@github.com/o/r.git
yes
False
ssh://git@github.com:22/o/r.git
yes
False
git://github.com/o/r.git
yes
False
file:///path/to/repo.git
yes
False
file://localhost/path/to/repo.git
yes
False
/path/to/repo.git
yes
False
ftp://host.xz/path/to/repo.git
yes, deprecated
False
ftps://host.xz/path/to/repo.git
yes, deprecated
False
git-clone(1) "GIT URLS" documents ssh://, git://, http[s]:// and ftp[s]://, plus the scp-like form and bare local paths. It explicitly deprecates ftp[s] ("this is inefficient and deprecated; do not use it"), so those two are low priority. ssh:// is the significant omission, since it is the form many hosts display for copy-paste.
Because match(is_explicit=True) only consults explicit rules, hg and svn are reachable only through their pip-style spellings. Their native URLs parse but never surface:
URL
own parser is_valid
registry.match
ssh://hg@bitbucket.org/user/repo
True
no match
svn://svn.example.com/repo/trunk
True
no match
The same gate produces four cases where an http(s) URL for an hg or svn repository is claimed by git, since core-git-https is the only explicit rule that can match it:
URL
actual
detected
https://bitbucket.org/user/repo
hg
git
http://hg.example.com/repo
hg
git
https://svn.example.com/repo/trunk
svn
git
http://svn.example.com/repo/trunk
svn
git
This is the worst class in the sweep: a confident wrong answer rather than an error. Mercurial and Subversion both serve over plain http(s), so these are ordinary URLs, not exotic ones.
Flipping the flag alone regresses git
Marking core-hg, core-hg-scp, core-svn and core-svn-scp explicit fixes the two undetected rows, but makes the most common git URLs ambiguous, because three parsers then match the same string:
Callers that treat "more than one match" as undetectable would start failing on https://github.com/... and on scp-style URLs. So this needs a disambiguation strategy, not a one-line change.
Rule already declares a weight field described as "Higher is more likely to win", but VCSRegistry.match() never reads it — it appends every parser whose is_valid returns True and returns them unranked. Wiring weight into match() (or returning matches sorted by it) looks like the missing piece that would let the core rules be explicit without making git ambiguous.
Other gaps in the sweep
Uppercase schemes are rejected.HTTPS://github.com/o/r.git and GIT+SSH://git@host/o/r.git both fail. RFC 3986 §3.1 states schemes are case-insensitive and that implementations "should accept uppercase letters as equivalent to lowercase in scheme names for robustness".
Trailing whitespace validates, then breaks at clone. A trailing space or newline is accepted as a valid URL; a leading space is rejected. The trailing form reaches git and fails there:
fatal: '/path/to/repo.git ' does not appear to be a git repository
fatal: Could not read from remote repository.
A URL pasted from a terminal or read line-wise from a file carries exactly this, and the resulting error names no cause. Trimming on parse, or rejecting both ends, would be consistent.
git+git:// is rejected, and should stay rejected.pip discourages git, git+git and git+http because the git protocol has no authentication and http has no TLS. Noted so it is not mistaken for a gap.
Local and Windows paths are rejected, which is correct for path-vs-URL routing./srv/git/repo.git, ./repo.git, ../repo.git, ~/code/repo.git, C:\code\repo.git, C:/code/repo.git and \\server\share\repo.git all return no match. Notably C:\... is not mistaken for scp-style despite resembling host:path, which matches git's own rule that the scp form "is only recognized if there are no slashes before the first colon". Callers that use is_valid to distinguish a URL argument from a filesystem path can rely on this. It is listed here only because a caller storing a bare local path in a config cannot then resolve it.
Minor: attribute docstrings in Rule are shifted by one. In base.py, defaults is followed by "Is the match unambiguous with other VCS systems? e.g. git+ prefix" (which describes is_explicit), and is_explicit is followed by "Weight: Higher is more likely to win" (which describes weight). weight itself ends up undocumented.
Evidence that this is unfinished rather than intentional
NPM_DEFAULT_RULES is an empty list whose own docstring gives ssh://git@github.com:npm/cli.git#v1.0.27 and git://github.com/npm/cli.git#v1.0.27 as target formats. It is never referenced anywhere else in the package. tests/url/test_git.py contains no assertion that bare ssh:// or git:// must fail; its ssh:// occurrences are all git+ssh:// fixtures plus an AWS CodeCommit comment. The only "unsupported" assertions in the suite are the is_generic=False markers for the host-specific CodeCommit rule.
URL Parser: ADA compliance #495 (URL Parser: ADA compliance) proposes replacing the regex engine with WHATWG URL / ada-url parsing. That would likely subsume Gate 1 and the uppercase-scheme and whitespace items, but not Gate 2, which is about rule metadata rather than parsing. Complementary, not duplicate.
GitPipURL: to_pip_url() #387 (GitPipURL: to_pip_url()) covers serialising back out to a pip URL — the reverse direction. Related through the pip-vs-git URL split, but distinct.
Abstract away pip url / url pattern support #272 (Abstract away pip url / url pattern support) proposes runtime-registrable patterns and VCS detection hint callbacks. The "detection hint" idea overlaps directly with the disambiguation problem above.
Suggested order
Wire weight into VCSRegistry.match() so ranked matches are possible.
Mark the hg and svn core rules explicit, using weight to keep git winning for bare http(s) and scp-style.
Extend git's RE_SCHEME to ssh, git and file, plus tilde-path support.
Normalise scheme case and trim surrounding whitespace on parse.
Summary
A sweep of 64 URL forms against libvcs v0.45.1 finds 35 detected correctly, 4 detected as the wrong VCS, and 25 not detected at all. The failures are not one bug — they come from two independent gates, and the two gates need different fixes. This issue consolidates the URL-detection gaps into one place.
Detection here means
registry.match(url=url, is_explicit=True), which is what downstream callers use to pick a VCS backend.Gate 1: the git scheme regex only matches
http|httpsRE_SCHEMEinurl/git.pyaccepts onlyhttpandhttps. Every other transport git supports has no matching rule, soGitURL.is_valid()returnsFalse.GitURL.is_validssh://git@github.com/o/r.gitFalsessh://git@github.com:22/o/r.gitFalsegit://github.com/o/r.gitFalsefile:///path/to/repo.gitFalsefile://localhost/path/to/repo.gitFalse/path/to/repo.gitFalseftp://host.xz/path/to/repo.gitFalseftps://host.xz/path/to/repo.gitFalsegit-clone(1) "GIT URLS" documents
ssh://,git://,http[s]://andftp[s]://, plus the scp-like form and bare local paths. It explicitly deprecatesftp[s]("this is inefficient and deprecated; do not use it"), so those two are low priority.ssh://is the significant omission, since it is the form many hosts display for copy-paste.Contrast:
url/hg.pyacceptshttp|https|sshandurl/svn.pyacceptsfile|http|https|svn|svn+ssh. The git parser is the narrow one.Not covered by the regex either, both documented by git-clone(1) under tilde expansion:
GitURL.is_validgit@github.com:~user/repo.gitFalsessh://git@host/~user/repo.gitFalseGate 2: hg and svn core rules are not marked explicit
is_explicitper rule, read from v0.45.1:git.pycore-git-https,core-git-scp, 4 AWS CodeCommit rules,pip-url,pip-scp-url,pip-file-urlhg.pypip-url,pip-file-urlcore-hg,core-hg-scpsvn.pypip-url,pip-file-urlcore-svn,core-svn-scpBecause
match(is_explicit=True)only consults explicit rules, hg and svn are reachable only through their pip-style spellings. Their native URLs parse but never surface:is_validregistry.matchssh://hg@bitbucket.org/user/repoTruesvn://svn.example.com/repo/trunkTrueThe same gate produces four cases where an http(s) URL for an hg or svn repository is claimed by git, since
core-git-httpsis the only explicit rule that can match it:https://bitbucket.org/user/repohttp://hg.example.com/repohttps://svn.example.com/repo/trunkhttp://svn.example.com/repo/trunkThis is the worst class in the sweep: a confident wrong answer rather than an error. Mercurial and Subversion both serve over plain http(s), so these are ordinary URLs, not exotic ones.
Flipping the flag alone regresses git
Marking
core-hg,core-hg-scp,core-svnandcore-svn-scpexplicit fixes the two undetected rows, but makes the most common git URLs ambiguous, because three parsers then match the same string:Callers that treat "more than one match" as undetectable would start failing on
https://github.com/...and on scp-style URLs. So this needs a disambiguation strategy, not a one-line change.Rulealready declares aweightfield described as "Higher is more likely to win", butVCSRegistry.match()never reads it — it appends every parser whoseis_validreturnsTrueand returns them unranked. Wiringweightintomatch()(or returning matches sorted by it) looks like the missing piece that would let the core rules be explicit without making git ambiguous.Other gaps in the sweep
Uppercase schemes are rejected.
HTTPS://github.com/o/r.gitandGIT+SSH://git@host/o/r.gitboth fail. RFC 3986 §3.1 states schemes are case-insensitive and that implementations "should accept uppercase letters as equivalent to lowercase in scheme names for robustness".Trailing whitespace validates, then breaks at clone. A trailing space or newline is accepted as a valid URL; a leading space is rejected. The trailing form reaches git and fails there:
A URL pasted from a terminal or read line-wise from a file carries exactly this, and the resulting error names no cause. Trimming on parse, or rejecting both ends, would be consistent.
git+git://is rejected, and should stay rejected. pip discouragesgit,git+gitandgit+httpbecause the git protocol has no authentication and http has no TLS. Noted so it is not mistaken for a gap.Local and Windows paths are rejected, which is correct for path-vs-URL routing.
/srv/git/repo.git,./repo.git,../repo.git,~/code/repo.git,C:\code\repo.git,C:/code/repo.gitand\\server\share\repo.gitall return no match. NotablyC:\...is not mistaken for scp-style despite resemblinghost:path, which matches git's own rule that the scp form "is only recognized if there are no slashes before the first colon". Callers that useis_validto distinguish a URL argument from a filesystem path can rely on this. It is listed here only because a caller storing a bare local path in a config cannot then resolve it.Minor: attribute docstrings in
Ruleare shifted by one. Inbase.py,defaultsis followed by "Is the match unambiguous with other VCS systems? e.g. git+ prefix" (which describesis_explicit), andis_explicitis followed by "Weight: Higher is more likely to win" (which describesweight).weightitself ends up undocumented.Evidence that this is unfinished rather than intentional
NPM_DEFAULT_RULESis an empty list whose own docstring givesssh://git@github.com:npm/cli.git#v1.0.27andgit://github.com/npm/cli.git#v1.0.27as target formats. It is never referenced anywhere else in the package.tests/url/test_git.pycontains no assertion that baressh://orgit://must fail; itsssh://occurrences are allgit+ssh://fixtures plus an AWS CodeCommit comment. The only "unsupported" assertions in the suite are theis_generic=Falsemarkers for the host-specific CodeCommit rule.Consolidation
GitPipURL:to_pip_url()#387 (GitPipURL:to_pip_url()) covers serialising back out to a pip URL — the reverse direction. Related through the pip-vs-git URL split, but distinct.Suggested order
weightintoVCSRegistry.match()so ranked matches are possible.http(s)and scp-style.RE_SCHEMEtossh,gitandfile, plus tilde-path support.ftp/ftps, noting git deprecates them.Bibliography
git+*,hg+*,bzr+*scheme lists and the security note ongit/git+git/git+httpfile://,http(s)://,ssh://,static-http://file://,svn://,svn+ssh://,http(s)://NPM_DEFAULT_RULESstub targets