Skip to content

Git access

Remote Git operations run on the Mend server. Session workspaces do not receive SSH keys or Git credentials.

Your Git access is per user. Settings → Git access sets the mode for projects you adopt: A Mend key on your git account (mend-key, the default) or Your machine’s key (bridge). mend keys mode does the same from the terminal. A project’s Setup page can override the mode with mend key or bridge, and mend adopt --auth overrides it for one adoption.

Each Mend user has one ed25519 key, generated and held on the server and never copied into a workspace or the database. Create it with Create my Mend key under Settings → Git access, or from the terminal:

Terminal window
mend keys init
mend keys show

Add the printed public key to your Git account’s SSH keys. Every repository your account can reach then works, including from detached sessions, the phone, and the hot pool. For access to one repository only, add the key as that repository’s deploy key instead, and grant it write access only when sessions need to push.

Terminal window
mend adopt git@github.com:acme/api.git --auth mend-key

The key acts as you and nobody else on the same server: a session signs with its owner’s key.

Bridge mode keeps the signing key on your machine. The server’s Git operations sign through the SSH agent there, so a hardware key never leaves your desk.

Terminal window
mend adopt git@github.com:acme/api.git --auth bridge

When your mode is bridge, every attaching mend command and the dashboard share your machine’s agent for as long as they run. mend keys share does the same on a machine that is not running one; Ctrl+C stops it. The server takes one signer per account at a time, and a newer share replaces the older one.

Git transport bytes travel to the Mend server, while SSH signing requests travel back to the shared agent. Hardware-key touch happens on the machine holding the key. While no signer is connected, Git for bridge projects does not wait: the base is not fetched, and pushes fail with a message that says so. The project’s Setup page shows signer connected · <machine> or no signer connected.

Until 0.36 a third mode, ambient, used whatever Git and SSH setup existed where the server ran. On a server from mend server setup or the Kubernetes chart that is a container with no key, agent or credential, so it reached only public HTTPS remotes, which both modes above reach the same way. It is gone: upgrading moves each project that used it to its creator’s own mode (mend keys mode), or to mend-key when they never chose one. A client from before 0.36 that asks for ambient is refused with:

Mend no longer has an ambient git mode: a packaged server holds no git or ssh credential of its own. Use your Mend key (`--auth mend-key`; `mend keys` prints it to add on your git host) or your own key through `mend keys share` (`--auth bridge`).

Your Mend key and the bridge sign SSH; neither answers an HTTPS remote, so neither is needed for one: a bridge project with nobody sharing still adopts and fetches a public HTTPS repository. On a server from mend server setup (or the Kubernetes chart), Mend’s own Git (adoption, mend refresh, the base fetch and the push of a landing) runs in a container with no HTTPS credential, so there an https:// URL clones and fetches a public repository only, and no push to it succeeds. Adopt the SSH URL instead: git@github.com:acme/api.git rather than https://github.com/acme/api.git.

A private repository adopted by its HTTPS URL on such a server fails with:

Mend found no HTTPS credential for this remote, so over HTTPS it reaches public repositories only; this one is private, or the URL is wrong. Your Mend key signs ssh remotes only: adopt git@github.com:acme/api.git instead. (observed: fatal: could not read Username for 'https://github.com': terminal prompts disabled)

A public one adopts, and its first landing fails at the push with Mend found no HTTPS credential for this remote: a public repository clones over HTTPS without one, but a push needs one. followed by the SSH URL to adopt.

Mend names the SSH URL for GitHub, GitLab, Bitbucket and Codeberg on their default HTTPS port, whose SSH path matches the HTTPS one; for other hosts, copy the SSH URL your host shows.

A server you run from source as your own user runs Git with that user’s Git config, so a credential helper configured there (gh auth setup-git, the macOS keychain) answers HTTPS remotes in either mode, for clone and push alike, and a url.<base>.insteadOf rewrite applies too. Mend decides who signs by the URL Git actually dials: an HTTPS URL that a rewrite sends over SSH (insteadOf, or pushInsteadOf for a landing’s push) signs with your Mend key or your bridge like any SSH remote. Mend’s own SSH never answers with the server process’s agent, default keys or SSH config: where Mend resolved no signer, SSH refuses.

When Mend signs (your Mend key, your bridge, or a session’s Git through the workspace transport), it ignores the server user’s ~/.ssh/config, so an IdentityFile or IdentityAgent there cannot stand beside or replace Mend’s choice. A server run from source that reached a Git host through a Host alias or a ProxyJump in that file must use the host’s real name in the project’s URL, and a host reachable only through a jump host is not reachable from Mend’s Git.

Mend points the workspace’s system Git config at a transport shim (core.sshCommand). Plain commands still work:

Terminal window
git fetch
git push

The shim carries the SSH transport over the session socket. The Mend server resolves the project’s current authentication mode, signs as the session’s owner, and opens the remote connection. In a per-person workspace it signs as the person whose process runs git, with their Mend key or their own bridge, so a joiner’s push is the joiner’s. Git over HTTPS to GitHub there uses Mend’s credential helper, which answers with the GitHub login in that person’s own home. No SSH credential enters the container. The socket carries Git’s own remote commands only (git-upload-pack, git-receive-pack, git-upload-archive).

The shim signs only for the project’s own origin host. A fetch or push to another host is refused with this session's Git access is bound to <origin host>; pushes and fetches to <host> run without Mend's signer. An operator on a machine they alone use can set MEND_GIT_TRANSPORT_BIND_ORIGIN=false to let the shim sign for any host, for mirrors and forks.

In a captured workspace (the default store) the repository is built from captures and has no remote of its own. Mend names the project’s origin for the workspace, with any login or token in an HTTPS URL removed before it gets there; an SSH login name stays.

Mend records the remote operation and its outcome. Changing the project’s auth mode applies to the next Git operation without rebuilding the workspace.

Commits the agent makes in your workspaces name your Git author. Until you set one, it is the name and email you registered with. Change it under Settings → Git author, or from the terminal:

Terminal window
mend git-author "Anna Example" anna@example.com
mend git-author --clear

mend git-author with no arguments prints the current author and where it comes from. --clear returns to your account’s name and email.

Mend writes the author into each workspace as system Git config before the agent starts. A user section in your dotfiles .gitconfig or in a repository’s own config still decides. Sessions launched after a change commit as the new author.

In a per-person workspace each person commits as themselves: Mend writes your author into your own home (~/.mend/git-author, included at the top of ~/.config/git/config) when your user is given its identity, so a changed author applies from your next start there.

Adoption, reference repositories, and dotfiles clone from a URL someone typed, with the server’s network position. MEND_SOURCE_POLICY decides which addresses those clones may reach:

  • operator (the default) fits one team’s own machine: private networks are allowed, the cloud metadata service never is, and loopback or link-local addresses only for the operator;
  • tenant refuses private, reserved, and local addresses, and unauthenticated git://, unless MEND_SOURCE_ALLOWED_HOSTS (a comma-separated list) names the host. Loopback and the metadata service can never be allowed.

Read Server environment for every server variable.

Mend refuses a repository URL that carries a login or token, such as https://oauth2:TOKEN@gitlab.com/acme/api.git or https://ghp_…@github.com/acme/api.git, wherever one is typed: adoption, reference repositories and dotfiles, in the CLI, the web, the phone, VS Code and the API. Mend shows a project’s URL to everyone who can see the project, which on a shared project is the whole organization, so a token in it would be theirs to read. mend adopt from a checkout whose origin carries one is refused the same way.

This URL carries a login or token before the "@". Mend shows a repository URL to everyone who can
see the repository, so it never stores one. Use the SSH URL (git@host:owner/repo.git) with your Mend
key (`mend keys` shows it), or your own key through the agent bridge (`--auth bridge`).

An SSH login name is not a credential and stays: git@github.com:acme/api.git and ssh://git@example.com/acme/api.git are accepted as typed. Use the SSH URL with your Mend key or the bridge; on a server you run from source as your own user, that user’s Git credential helper answers an HTTPS URL without a token in it (see HTTPS remotes).

Mend also removes a credential from any repository URL it returns or logs, and from the Git errors it reports. For projects adopted before 0.36, see Known issues.

mend connect github supplies a GitHub token to gh and compatible API clients inside workspaces. It does not choose how the server clones, fetches, or pushes the repository.

Landing a change uses both: the push goes over the project’s Git access, and the pull request is opened or updated as your connected GitHub account.

Use provider accounts for GitHub API access. Use a Git auth mode for repository transport.

Permission denied means the selected identity cannot access the remote. Add your Mend public key to your Git account, or verify that the shared agent holds an authorized key.

Mend found no HTTPS credential for this remote means the URL is https:// and the server’s Git has no credential for it: the repository is private (or the URL is wrong), or the operation was a push. Adopt its SSH URL; see HTTPS remotes.

Host key verification failed means the remote’s host key changed since the Mend server first saw it: every mode accepts a first-contact key and refuses a changed one. Verify the new key out of band, then fix the known_hosts entry where the server’s Git runs. Do not disable host-key checking in a workspace.

No signer connected means bridge mode has no machine sharing its agent. Run any attaching mend command, or mend keys share, on the machine holding the key.

Git access is bound to another host means the workspace tried to reach a remote other than the project’s origin. See Git inside a workspace.