Documentation
¶
Overview ¶
Package gitremote provides general-purpose git remote URL utilities: parsing, resolving, and redacting remote URLs. It has no dependency on checkpoint, strategy, or settings packages.
Index ¶
- Constants
- func CutGitDirSuffix(name string) (string, bool)
- func ForgePathLabels(forge string) string
- func GetPushURLs(ctx context.Context, remoteName string) ([]string, error)
- func GetPushURLsInDir(ctx context.Context, dir string, env []string, remoteName string) ([]string, error)
- func GetRemoteURL(ctx context.Context, remoteName string) (string, error)
- func GetRemoteURLInDir(ctx context.Context, dir, remoteName string) (string, error)
- func GetRemoteURLInDirEnv(ctx context.Context, dir string, env []string, remoteName string) (string, error)
- func IsForgePathToken(forge string) bool
- func RedactURL(rawURL string) string
- func RedactURLOrPath(remote string) string
- func ResolveRemoteRepo(ctx context.Context, remoteName string) (forge, owner, repo string, err error)
- type Info
Constants ¶
const ( // ProtocolSSH is the ssh transport, whichever of git's three spellings // named it: ssh://, git+ssh://, or ssh+git:// (see normalizeProtocol). ProtocolSSH = "ssh" ProtocolHTTPS = "https" // ProtocolHTTP and ProtocolGit are the remaining schemes whose host is the // git host itself. ParseURL returns them for http:// and git:// remotes; // nothing derives such a URL, so they exist to be recognized. ProtocolHTTP = "http" ProtocolGit = "git" // ProtocolEntire is the scheme of Entire's git remote helper (entire://). // These URLs carry a forge/namespace prefix before owner/repo. ProtocolEntire = "entire" )
const ( // ForgeGitHub is the entire:// path token for a GitHub mirror. ForgeGitHub = "gh" // ForgeNative is the entire:// path token for an Entire-native repo. // Exported so callers holding a parsed forge can ask the question without a // bare "et" literal. ForgeNative = "et" )
const GitDirSuffix = ".git"
GitDirSuffix is the suffix git tools habitually append to a repo path. It is never part of a repo name Entire stores — see CutGitDirSuffix, and cli.gitDirSuffix for why names have to stay free of it.
Variables ¶
This section is empty.
Functions ¶
func CutGitDirSuffix ¶ added in v0.11.4
CutGitDirSuffix removes a trailing GitDirSuffix in ANY case, reporting whether one was there. Every place in the CLI that asks Entire's `.git` question goes through it, so the answer cannot vary by call site — which it did, in five separate hand-rolled spellings, until this existed.
Case-insensitive is the deliberate half of the choice, and it is not what canonical git does everywhere. Git draws the line by PURPOSE. When it is merely guessing a local directory name out of a URL the user pasted, it cuts case-sensitively (git_url_basename in dir.c: `strncmp(end - 4, ".git", 4)`, then one strip_suffix_mem). When the question is instead whether a path IS the reserved `.git` — a safety question, where a miss is a vulnerability — it matches with aggressive case-insensitivity and then some: is_hfs_dotgit (utf8.c) skips Unicode codepoints HFS+ ignores, and is_ntfs_dotgit (path.c) also admits `git~1`, trailing dots and spaces, and NTFS stream suffixes.
Entire's uses fall on the reserved-spelling side of that line. `repo create` asks whether a name collides with a spelling git tooling reserves. The ref parsers ask which repository a path names — and the answer belongs to the server, not to a local directory heuristic. Entire's transport accepts the suffix on a repo path whatever its case, so a case-sensitive client disagrees with the server it is dialing: `git clone entire://…/et/acme/widgets.GIT` resolves while `entire repo clone /et/acme/widgets.GIT` reports no such repo.
That reasoning is Entire's alone. GitHub's transport cuts the suffix case-sensitively (`github.com/git/git.GIT` is not found), so a URL a forge serves directly must not come through here — see splitOwnerRepo.
The cut happens exactly once, as git's single strip_suffix_mem does, so "widgets.git.git" yields "widgets.git" rather than collapsing every dotted segment. Slicing the last four bytes is safe against a multi-byte final rune: a split rune decodes to RuneError, which never folds equal to ASCII.
func ForgePathLabels ¶ added in v0.10.5
ForgePathLabels returns the placeholder spelling of the two path segments that follow forge in an entire:// URL, for error messages. Empty for a forge IsForgePathToken rejects.
func GetPushURLs ¶ added in v0.10.0
GetPushURLs returns every URL a push to remoteName delivers to, in the order git will use them.
A remote's push destinations are remote.<name>.pushurl when any is set and its remote.<name>.url otherwise (git's push_url_of_remote), and BOTH may repeat — git pushes to all of them, in config order. So this, not GetRemoteURL, describes where a push actually goes; GetRemoteURL reports the FETCH URL, which can name a different repository entirely.
Returns at least one entry on success.
func GetPushURLsInDir ¶ added in v0.11.0
func GetPushURLsInDir(ctx context.Context, dir string, env []string, remoteName string) ([]string, error)
GetPushURLsInDir is GetPushURLs against a specific worktree, the push-side counterpart of GetRemoteURLInDir.
env, when non-nil, replaces the child's environment. Pass gitrepo.EnvWithoutRepoOverrides() when dir names the target and the caller can run inside a git hook: git exports GIT_DIR and GIT_WORK_TREE to its hooks and they outrank cmd.Dir. Pass nil when dir is empty — there the ambient environment is what names the repository, and filtering it would silently retarget the child at the process working directory.
Filtered by the caller, because this package depends on nothing beyond the standard library while gitrepo pulls in go-git.
func GetRemoteURL ¶
GetRemoteURL returns the URL configured for the named git remote.
func GetRemoteURLInDir ¶ added in v0.6.3
GetRemoteURLInDir returns the URL configured for the named git remote in dir.
func GetRemoteURLInDirEnv ¶ added in v0.11.0
func GetRemoteURLInDirEnv(ctx context.Context, dir string, env []string, remoteName string) (string, error)
GetRemoteURLInDirEnv is GetRemoteURLInDir with an explicit child environment, the fetch-side counterpart of GetPushURLsInDir's env parameter — see there for when to pass one, including why an empty dir takes nil. Both halves of an ownership vote must make the same choice, or they reach git differently and can describe different repositories.
func IsForgePathToken ¶ added in v0.10.5
IsForgePathToken reports whether forge is one of the forge tokens Entire uses in an entire:// path ("gh", "et"). It rejects forge hostnames ("github.com") and any other unrecognized value, so a caller parsing a bare forge/owner/repo triple can fail clearly instead of forwarding a malformed forge, and a caller holding a URL can tell a forge id typed in the cluster-host slot apart from a real host.
The name says syntax deliberately: this is NOT a capability check, and it once was one (it read the upstream-host map, so it answered `{gh}`). Widening it to the real path tokens is what a URL needs, but it means a caller after a capability still has to narrow afterwards. Trails are the worked example: a native repo is reachable there, but only by ULID rather than by the forge/owner/repo path a mirror uses, so trailRepoBasePath routes on the forge after this has answered yes. A caller that treats this as the capability gets a token it says yes to and a route that does not exist.
func RedactURL ¶
RedactURL removes credentials and query parameters from a URL for safe logging. SCP-style SSH URLs (e.g., git@github.com:org/repo.git) are returned as-is since they contain no embedded credentials.
func RedactURLOrPath ¶ added in v0.10.0
RedactURLOrPath renders a remote for display with any credentials removed, accepting values that are not URLs at all.
RedactURL cannot be applied blanket-fashion: it round-trips through url.Parse and rebuilds "scheme://host/path", so a bare filesystem path like /srv/repo.git comes back as ":///srv/repo.git" and a bare word like "origin" as "://origin". Those inputs carry no credentials, so they pass through unchanged. Use this wherever the value may be a remote name, a local path, or a URL — i.e. anywhere a push/fetch target is shown to a user.
func ResolveRemoteRepo ¶
func ResolveRemoteRepo(ctx context.Context, remoteName string) (forge, owner, repo string, err error)
ResolveRemoteRepo returns the forge identifier, owner, and repo name for the given git remote. The forge is the short id used by the trails API ("gh", "et", ...); it is derived from the hostname for direct git URLs or from the path prefix on entire:// URLs. It is empty for unrecognized hosts. For example, git@github.com:org/my-repo.git returns ("gh", "org", "my-repo").
Types ¶
type Info ¶
Info holds the parsed components of a git remote URL. Host is the hostname only (never includes a port). Port is empty unless the source URL specified an explicit non-default port. Callers that need the combined "host[:port]" form should use HostPort.
Forge is the short identifier of the upstream forge ("gh", "et", ...) used by the Entire trails API. It is populated from the path prefix on entire:// URLs (entire://host/<forge>/owner/repo) and from a hostname lookup on direct git URLs (github.com → "gh"). It is empty for direct git URLs to unrecognized hosts, and for entire:// URLs without a forge segment.
func (*Info) CanonicalHost ¶ added in v0.7.6
CanonicalHost returns the canonical public host of the upstream forge.
For direct git URLs this is just Host. For entire:// remotes — whose Host is the Entire cluster (e.g. aws-us-east-2.entire.io) rather than the forge — it maps the forge prefix back to the forge's host (gh → github.com). Falls back to Host when the forge is unknown (e.g. a self-hosted GitHub Enterprise), preserving the only host we know for it.
func (*Info) UpstreamHost ¶ added in v0.11.4
UpstreamHost is CanonicalHost without the fallback: it returns the forge's canonical public host and whether one is known at all.
The distinction matters for an entire:// remote, and only there. Host is a cluster rather than a git host, so when the forge maps to nothing there is no upstream host to fall back TO — CanonicalHost answers the cluster, which is the right answer for "where do I reach this" and the wrong one for "which forge backs this". ParseURL preserves any non-empty forge token it finds in the path, so an unrecognized one reaches callers looking exactly like a mirror. A caller that needs a real forge host must ask this instead and handle the false.