Git has no memory for server addresses. Every fetch, pull and push needs one, and git remote is the command that attaches a short name to a URL so you can type the name instead.
A fresh clone has exactly one such entry, origin. Teams on GitHub or GitLab pile on more for forks and mirrors.
The entry is only a name and a URL, with a default fetch refspec stored alongside them in .git/config. Nothing executable is attached.
The add subcommand contacts no server unless -f is passed (git-remote manual, Git 2.53.0, 2026). A mistyped URL goes unnoticed until the first fetch or push.
What Is git remote?

The Pro Git book describes a remote as a version of your project hosted on the internet or another network. It doesn’t have to be far away, since a path on the same machine counts too.
git remote manages the named shortcuts that link your local repository to those URLs. The name stands in for the full address in fetch, pull and push.
A remote is a reference, not a copy of the code. The remote repository on the other end holds the commits, and the remote entry only points to it.
Each remote has a shortname like origin or upstream and a URL, which can be HTTPS, SSH, git:// or a plain filesystem path. The refspec sits behind both and decides which remote branches Git tracks locally.
Git calls the server you cloned from origin by default. You never picked that name, because cloning a repository creates it automatically.
Run git remote with no arguments in any fresh clone and it prints origin.
Git doesn’t care which host is behind it. GitHub, GitLab, Bitbucket, Azure DevOps or a self-hosted Gitea server all look the same to it, since a remote is just a name and a URL.
How Does Git Store a Remote in the Repository?

Inside .git/config. Each remote gets a [remote "name"] section with a url key and a fetch refspec key, and the git remote command edits that file so you don’t have to.
A fresh clone writes this entry for the default origin remote:
[remote "origin"]
url = https://github.com/OWNER/REPOSITORY.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/mainThe section header names the remote, and url holds the address used for both fetch and push. The fetch line holds the refspec. The branch block at the bottom records which remote the local main branch pulls from.
The Git documentation lists these as the variables remote.origin.url and remote.origin.fetch, and the git config command reads and writes them directly.
What the fetch line controls

The refspec has two sides. On the left, refs/heads/* matches every branch on the server. On the right, refs/remotes/origin/* is where Git records them locally.
The leading plus sign lets Git update a local reference even when the update is not a fast-forward (Pro Git).
To track one branch instead of all of them, pass -t when adding the remote. The git-remote manual (Git 2.53.0, February 2026) says this replaces the default glob with a refspec for that single branch.
Since Git 2.6.0 the pattern also accepts partial globs such as qa*.
Where remote settings do not travel
The config file stays inside your clone. Pushing never copies remote definitions, so every teammate’s clone starts with its own origin.
Which git remote Subcommands Manage Remotes?

Day to day you’ll mostly touch add, rename, remove, set-url, get-url, show and prune. Only show and prune contact the server by default. The manual also lists set-head, set-branches and update, and update does fetch from the server.
| Subcommand | Syntax | Effect | Contacts server |
|---|---|---|---|
| add | git remote add NAME URL | Writes a new remote section | No (yes with -f) |
| rename | git remote rename OLD NEW | Renames the remote and its tracking branches | No |
| remove | git remote remove NAME | Deletes the section and its tracking branches | No |
| set-url | git remote set-url NAME NEWURL | Changes the stored URL | No |
| prune | git remote prune NAME | Deletes stale tracking branches | Yes |
Adding and Changing a Remote
Add writes config and nothing else. Pass -f and Git runs a fetch right away.
Rename carries all remote-tracking branches over to the new name, so pb/master becomes paul/master (Pro Git).
Changing a URL is set-url’s job. It swaps the first matching URL, and with --push it changes only the push URL. If the old URL you pass matches nothing, the command errors and changes nothing.
Fetch and push URLs must still refer to the same place. To fetch from one repository and push to another, the manual says to use two separate remotes.
Scripts can read the exit codes. A name that already exists returns status 3, while a missing remote in rename or remove returns status 2. The familiar “remote origin already exists” error is the first case.
Inspecting and Cleaning Up Remotes
With no arguments, git remote lists names. Add -v and each remote shows one fetch URL and one push URL.
get-url NAME prints the URL with insteadOf rewrites applied, and --push prints the push URL instead.
show NAME reports the HEAD branch, tracked and stale branches, and the pull and push configuration, but only after querying the server (-n skips the query). prune NAME does the same job as git fetch --prune NAME without fetching anything new.
show flags branches deleted on the server as stale, which is the cue to run prune.
Use prune --dry-run first on a repository you do not recognize.
HTTPS or SSH: Which Remote URL Should You Use?
Use HTTPS when a firewall or a shared machine makes key setup awkward. CI runners usually land here too. On your own machine, SSH is nicer if you push often. Both are authenticated and encrypted.
| Protocol | URL format | Authentication | Best fit |
|---|---|---|---|
| HTTPS | https://host/owner/repo.git | Token or credential helper | Firewalled networks, CI, quick setup |
| SSH | git@host:owner/repo.git | SSH key | Frequent pushes from a trusted machine |
| git:// | git://host/owner/repo.git | None | Public read-only serving, rarely |
| Local path | /srv/git/project.git | File permissions | Shared filesystem on one host |
GitHub stopped accepting account passwords for Git operations on August 13, 2021 (GitHub Blog). Token or SSH key authentication is required since then.
On HTTPS, you generate a GitHub token and paste it where Git asks for the password. Git Credential Manager can store it so the prompt does not return.
For SSH, start with adding an SSH key to your GitHub account. Skip it and the push ends in a “Permission denied (publickey)” error.
Pro Git adds that corporate firewalls often allow HTTP and HTTPS traffic, which is why HTTPS tends to work where other transports fail.
On HTTPS the old account password is rejected on GitHub, so a token is mandatory. SSH has no anonymous access, which means even read-only cloners need SSH access to the host.
git:// has no authentication or encryption, and port 9418 is often blocked. Pro Git warns that cloning over it can lead to arbitrary code execution if traffic is tampered with.
Local paths use hardlinks or direct copies, while file:// runs the slower network transfer. Either way, the local protocol does not protect the repository from accidental damage.
Switching an existing remote between protocols
Change the URL in place instead of removing and re-adding the remote. From HTTPS to SSH:
git remote set-url origin git@github.com:OWNER/REPOSITORY.gitFrom SSH back to HTTPS:
git remote set-url origin https://github.com/OWNER/REPOSITORY.gitConfirm the change with git remote -v. Remote-tracking branches and branch settings stay intact.
How Do Fetch, Pull and Push Use a Remote?

Clone is what creates the entry in the first place. After that, fetch downloads, pull downloads and then merges, and push sends your commits up.
Name no remote and fetch and push use the branch’s upstream, or origin when none is set, according to the Git manuals.
Remote-tracking branches
Git keeps a local reference recording where a remote branch stood the last time you talked to the server. It lives under refs/remotes, for example refs/remotes/origin/main, usually shortened to origin/main.
The remote branch itself sits on the server and moves only when someone pushes. origin/main in your repository is its remote-tracking counterpart, which fetch and pull move. Then there’s plain main, the local branch you commit to.
Local commits never move origin/main. Only contact with the server does.
Fetch or pull
Fetch downloads new commits and moves the remote-tracking branches, leaving your working files and local branches alone (Pro Git).
Pull runs that fetch, then merges the tracked remote branch into the branch you have checked out.
Under the hood, a pull is exactly that two-step sequence with no pause in between.
Since Git 2.27, pull warns until pull.rebase is set. Set it to false to keep merge behavior or true to rebase (Pro Git).
Fetch first on a shared branch when you want to read what changed before merging. Plain pull is fine on a branch only you touch.
Upstream tracking and automatic pruning
The first push of a new branch is usually where tracking gets set.
git push -u origin mainadds the upstream reference that argument-less pull and push readpush.autoSetupRemoteset to true does the same on the first push of a branch that has no upstream yet (withpush.defaultset to simple, upstream or current)push.defaulthas been simple since Git 2.0, which pushes to the same-named branch- Setting
fetch.pruneorremote.NAME.prunemakes every fetch drop stale remote-tracking branches
Pruning follows the remote’s refspec, not branch names. If the refspec includes refs/tags/*:refs/tags/*, prune deletes local tags missing from the remote instead, per the git-fetch manual for Git 2.56.0 (September 2026).
How Do Multiple Remotes Work With origin and upstream?

In a fork workflow, origin is your fork and upstream is the original repository. You fetch from upstream and push to origin.
Git gives the name upstream no special meaning, because only origin is created automatically. It is a convention, and the upstream remote pattern exists because a fork on GitHub is a separate repository you can write to, while the original is one you usually cannot.
- Fork the project on the host, then clone your fork. Git names it origin.
- Run
git remote -vand confirm origin lists your fork for fetch and push. - Run
git remote add upstreamfollowed by the original repository URL. - Run
git remote -vagain. Four lines appear, fetch and push for each remote. - Run
git fetch upstreamto create the upstream/main remote-tracking branch (or the project’s default branch). - Switch to main and run
git merge --ff-only upstream/main. - Run
git push origin mainto publish the synced branch to your fork.
Steps 2 to 4 follow the GitHub Docs procedure for configuring a remote for a fork. The fast-forward flag in step 6 makes the merge fail instead of creating a merge commit when your main has diverged from upstream.
Cloned the original first and forked later? Rename the existing remote, then add your fork under the old name (Happy Git with R):
git remote rename origin upstream
git remote add origin git@github.com:YOUR-USERNAME/YOUR-FORK.gitTwo remotes is not the ceiling. The git-remote manual’s own example adds a staging remote from a kernel.org tree and fetches three branches from it, and Pro Git’s grit example lists five.
Pushing to several remotes at once
The git-push manual (updated in Git 2.55.0, June 2026) documents remote groups, a named list set with git config remotes.all-remotes "origin gitlab backup". Then git push all-remotes pushes to each member in turn.
Each push runs independently. A failure on one member does not stop the rest, but the overall exit code is non-zero.
Group pushes refuse --atomic, because atomicity holds only within a single connection to a single remote.
Why Do git remote Commands Fail?

| Message | Cause | Fix |
|---|---|---|
| fatal: remote origin already exists | A remote with that name is already configured | Use set-url to repoint it, or rename the old remote first |
| fatal: not a git repository | Command run outside a repository | Change into the repository root and retry |
| remote: Repository not found | Wrong URL, or no access to a private repository | Check git remote -v, correct the URL, confirm credentials |
| Permission denied (publickey) | SSH offered no key the host accepts | Run ssh -vT git@github.com, load the key, add the public key to the account |
| ! [rejected] (non-fast-forward) | The remote branch has commits you do not have | Fetch, merge or rebase, then push again |
On GitHub, SSH connections must use the “git” user, per GitHub Docs. A remote URL containing your account name fails with the same publickey error, and set-url fixes it.
Rejected versus remote rejected
Rejected means Git refused to send the update, usually because it is not a fast-forward. Rebasing your commits onto the fetched work, or merging it, makes the push fast-forward.
Remote rejected means the server refused the update, typically through a hook or a safety option such as receive.denyCurrentBranch or receive.denyNonFastForwards (git-push manual).
The receive.denyCurrentBranch safeguard explains why shared remotes are usually a bare repository. With no checked-out branch, nothing is there to protect.
Prefer --force-with-lease over --force when you must overwrite history. It fails if the remote branch moved since you last looked, though a background fetch can defeat that check.
git remote FAQ
Can a Git repository work without any remote?
Yes. Commits, branches, merges and history all work locally, and git remote simply prints nothing in a repository that has none.
A remote only becomes necessary when you want to share work or keep an off-machine copy.
Is a Git remote the same thing as GitHub?

No. GitHub is one host, while the remote is the named URL stored in your repository’s config.
The same remote entry can point at GitLab, Bitbucket, a self-hosted server or a folder on disk.
Does removing a remote delete my code?
No. git remote remove deletes the config entry and the matching remote-tracking branches, according to the git-remote manual.
Your local branches and commits stay, and the repository on the server is untouched.
What is a bare repository, and why do servers use one?
Pro Git defines a bare repository as one that holds only the contents of a .git directory and has no working directory.
Nobody edits files on a shared server, so there is no checkout to keep in sync, and pushes to a checked-out branch are refused by default.
How can I see which remote branch a local branch tracks?
Run git branch -vv. Each local branch is listed with its upstream in square brackets.
git status adds how many commits the branch is ahead of or behind that upstream.
How to Verify a New Remote Before Relying on It
A new git remote earns trust through a read-only call, not through a successful add. git ls-remote NAME lists the references on the server and fails at once on a wrong URL or rejected credentials.
Run the checks in this order, cheapest first:
git remote -vto read the stored URLsgit ls-remote NAMEto test reachability and logingit push --dry-runto rehearse the upload
ls-remote proves read access only, so a read-only token passes the second check and can still fail on the first real push.
Position verified against the Git 2.56 manuals (September 2026). Rerun the check on any remote untouched for months, since hosts change authentication rules.
With the checks passed, pushing your first commits to GitHub is the natural next step.
- How Software Teams Write SOPs for Releases and Deployments - October 22, 2026
- Notepad++ Android Options: Apps That Come Close - October 21, 2026
- Data Management Services: A Practical Guide for Growing Companies - October 21, 2026




