Topic · Collaboration & Remotes

Remotes

A remote is a named bookmark to another repository. Once you set one up, every push and fetch in Git becomes a short, readable command instead of a URL you have to remember.

1. What a remote actually is

People often picture a remote as "the repository on GitHub." That is one common case, but it understates what Git is doing. A remote, from Git's point of view, is much smaller and much more flexible.

Remote

A remote is a name paired with one or more URLs, recorded in your local .git/config. The name is a shortcut you use in commands; the URL tells Git where to fetch from and push to. Git imposes no rules about how many you have, what they are called, or where they live.

The name origin shows up everywhere because git clone uses it by default, not because Git treats it specially. Renaming origin to something else, or never having an origin at all, is perfectly legal. A repository can have zero remotes (a solo local project), one remote (the typical case), or several (a fork that also tracks an upstream).

Two remotes pointing out of one local repository Local repo .git/config two named remotes origin git@github.com:you/repo.git upstream https://github.com/org/repo.git git push / fetch use remote name

Once a remote exists, you refer to it by its short name in every networking command. git fetch origin contacts whichever URL origin resolves to; git push upstream main targets the URL stored under upstream. The name is the handle; the URL is the address; the rest is just plumbing.

2. Listing remotes

The first thing to do in any unfamiliar repository is ask what remotes it knows about. The bare command lists names; the verbose flag adds URLs.

list remotesshell
git remote
git remote -v

The verbose form prints two lines per remote, one for fetch and one for push. They are usually the same URL, but Git tracks them separately because you can override the push URL while keeping the fetch URL.

git remote -v outputshell
origin    git@github.com:you/project.git (fetch)
origin    git@github.com:you/project.git (push)
upstream  https://github.com/org/project.git (fetch)
upstream  https://github.com/org/project.git (push)

If git remote prints nothing, the repository has no remotes configured. That is normal for a freshly git inited project; it becomes a problem only when you try to push.

3. Adding, renaming, removing

Three commands cover the lifecycle. Each one edits .git/config and nothing else.

manage remotesshell
git remote add <name> <url>
git remote rename <old> <new>
git remote remove <name>

Adding a remote does not talk to the network. It writes a stanza to .git/config and returns instantly. The next time you run git fetch <name>, Git resolves the URL and tries to connect. If the URL is wrong, you find out then.

Renaming updates both the stanza and every existing remote-tracking branch. After git remote rename origin github, the branch you previously knew as origin/main is now github/main. No history is lost; only the labels move.

Removing a remote deletes its config entry and every associated remote-tracking branch. It does not touch the actual repository on the server: that copy still exists, you have just stopped pointing at it from this clone.

Note

git remote rm is a short alias for git remote remove. Both work; the longer form is easier to read in scripts.

4. URL types: HTTPS, SSH, git, file

The URL that follows git remote add can take several forms. Each names the transport Git will use to talk to the other repository.

Form Example Auth When to use
HTTPS https://github.com/user/repo.git Personal access token (no password) Default for new clones; works behind firewalls; easy on shared machines.
SSH git@github.com:user/repo.git SSH keypair Daily driver on your own machine after you have set up keys; no per-push credential prompt.
Git protocol git://example.com/repo.git None (read-only, anonymous) Rare today; was used for fast anonymous mirrors. Most hosts have dropped support.
Local path / file /srv/git/repo.git or file:///srv/git/repo.git Filesystem permissions Mirroring across two directories on one machine; setting up a shared remote on a LAN drive.

HTTPS and SSH are the two you will live with. Look at the same GitHub repository in both forms:

same repo, two URLsshell
https://github.com/user/repo.git
git@github.com:user/repo.git

HTTPS works anywhere a browser does; the trade-off is that every push needs credentials, and GitHub no longer accepts a password here, so you provision a personal access token. SSH demands one-time setup (generate a key, paste the public half into your account), but afterwards every push is silent: the key is the credential.

Tip

Pick one and be consistent. Mixing HTTPS for some clones and SSH for others is fine, but it means two systems to keep working. Most developers settle on SSH for their personal machines and HTTPS on shared or temporary ones.

5. Multiple remotes: origin and upstream

The most common reason to have two remotes is the fork-and-contribute pattern used across open source. You fork someone else's project on GitHub, clone your fork, and then add the original repository as a second remote so you can pull in new changes from it.

fork-and-contribute setupshell
git clone git@github.com:you/project.git
cd project
git remote add upstream https://github.com/org/project.git
git remote -v

By convention:

  • origin is your fork. You have write access. You push feature branches here.
  • upstream is the canonical repository. You only fetch from it, to keep your fork in sync.

Neither name is enforced by Git; they are just the names everyone reads as "mine" and "the real one." When you are ready to contribute, you push a branch to origin and open a pull request from there into upstream. The mechanics of fetching and pushing across these remotes are covered in the next topic, Fetch, Pull & Push.

6. Inspecting a remote in detail

git remote -v tells you the URL. git remote show tells you the relationship.

verbose remote inspectionshell
git remote show origin

This command contacts the remote, so it needs the network. In return it prints the fetch and push URLs, the remote's default branch (its HEAD), every remote branch and how it tracks against your local branches, and which local refs are configured for git push.

example outputshell
* remote origin
  Fetch URL: git@github.com:you/project.git
  Push  URL: git@github.com:you/project.git
  HEAD branch: main
  Remote branches:
    main     tracked
    feature  tracked
  Local branches configured for 'git pull':
    main    merges with remote main
    feature merges with remote feature
  Local refs configured for 'git push':
    main    pushes to main    (up to date)
    feature pushes to feature (fast-forwardable)

Use this command when something feels off: a push goes to a branch you didn't expect, a pull pulls from the wrong place, or you inherit a repository and have no idea how it is wired.

7. Changing a remote's URL

You don't have to remove and re-add a remote when its URL changes. set-url rewrites the URL in place.

switch HTTPS to SSHshell
git remote set-url origin git@github.com:you/project.git
git remote -v

The most common reason to do this is exactly the example above: you cloned over HTTPS, then set up SSH keys, and want every future push to use SSH so it stops asking for credentials. Other reasons include the repository being renamed on the host, moving from one GitHub organization to another, or migrating to a different service entirely.

A pair of useful options:

  • --push changes only the push URL, leaving fetch alone. Handy when you want to read from a public mirror but push to a private writable copy.
  • --add attaches an additional URL rather than replacing. git push against that remote will then push to every URL in turn, which is one way to maintain a mirror.

8. Under the hood: .git/config

Every git remote subcommand is a thin wrapper over editing a text file. Open .git/config in any editor and you will see the remote section directly.

.git/configini
[core]
        repositoryformatversion = 0
        filemode = true
        bare = false
        logallrefupdates = true

[remote "origin"]
        url = git@github.com:you/project.git
        fetch = +refs/heads/*:refs/remotes/origin/*

[remote "upstream"]
        url = https://github.com/org/project.git
        fetch = +refs/heads/*:refs/remotes/upstream/*

[branch "main"]
        remote = origin
        merge = refs/heads/main

Each [remote "name"] stanza holds a url and a fetch refspec. The refspec is the rule that says "when I fetch from this remote, store its branches under refs/remotes/<name>/ in my local repository." That is why, after fetching, you see branches like origin/main: they are local pointers that mirror the remote's branches.

Tip

You can edit .git/config by hand to fix a typo or add an unusual setting. The git remote commands are just safer ways to do the same edits. Knowing the file is plain text demystifies most of what looks magical about remotes.

9. What git clone sets up for you

git clone is not a primitive operation. It is shorthand for several steps that you could perform by hand:

  1. Create an empty repository in a new directory.
  2. Add a remote named origin pointing at the URL you gave.
  3. Fetch every branch from origin.
  4. Check out the remote's default branch (often main) and set it up to track origin/main.

That is why a fresh clone is immediately ready for git fetch, git pull, and git push without any further configuration. The remote is there, named origin, with both fetch and push URLs set, and your local branch already knows which remote branch it tracks.

clone vs. manual setupshell
# shorthand
git clone git@github.com:you/project.git

# rough manual equivalent
mkdir project && cd project
git init
git remote add origin git@github.com:you/project.git
git fetch origin
git checkout -b main --track origin/main

Knowing what clone does has a practical payoff: if you ever start a project locally and then want to publish it, you don't need to clone-then-copy. You run git remote add origin <url> in your existing repo and push from there. Same end state.

10. Hosting your own remote

A remote can live on any machine that runs Git. GitHub, GitLab, and Bitbucket are convenient, but they are not part of Git itself. The minimum a remote needs is a bare repository (one without a working tree) reachable over SSH, HTTPS, or a shared filesystem.

set up a bare repo on a servershell
ssh user@server
mkdir -p /srv/git/project.git
cd /srv/git/project.git
git init --bare

From any clone, you then add that location as a remote:

point a local repo at itshell
git remote add origin user@server:/srv/git/project.git
git push -u origin main

Bare repositories also show up locally. A USB drive with a few project.git directories on it is a perfectly valid remote: git remote add backup /Volumes/usb/project.git and push to it whenever you want a snapshot you control. The point is that "remote" means "another repository," not "a paid service."

11. Common pitfalls

Pitfall 1

Treating origin as a Git keyword. It is only a default name. Renaming, removing, or never having an origin is fine. When tutorials say "push to origin," substitute "push to your default remote." That habit pays off the day you work in a repository configured differently.

Pitfall 2

Confusing local and remote deletion. git remote remove origin only removes the bookmark from your clone. The repository on GitHub is unaffected. Deleting the actual remote repository requires a different action on the hosting platform.

Pitfall 3

Pushing to upstream by accident. If you set up the fork-and-contribute pattern, you almost never have permission to push directly to upstream. A failed push or, worse, a confusing rejection often traces back to running git push upstream instead of git push origin.

Pitfall 4

Stale URLs after a rename. If a repository or organization gets renamed on the host, git push may keep working through redirects for a while and then suddenly fail. Run git remote -v; if the URL still shows the old name, use git remote set-url to fix it before something more important breaks.

12. Worked examples

Example 1: Publish a local project to GitHub

You have been working in a folder you created with git init. You want to push it to a new empty repository on GitHub.

first pushshell
git remote add origin git@github.com:you/new-project.git
git remote -v
git push -u origin main

The -u flag tells Git to remember that the local main tracks origin/main, so future git push and git pull calls don't need arguments. After this, the configuration looks exactly like a freshly cloned repository.

Example 2: Switch a remote from HTTPS to SSH

You cloned over HTTPS in a hurry. Now you have SSH keys set up and want pushes to stop prompting for tokens.

swap the URLshell
git remote -v
# origin  https://github.com/you/project.git (fetch)
# origin  https://github.com/you/project.git (push)

git remote set-url origin git@github.com:you/project.git

git remote -v
# origin  git@github.com:you/project.git (fetch)
# origin  git@github.com:you/project.git (push)

No history changes. You verified before, you verified after; that is the entire safety check.

Example 3: Add upstream to a fork

You forked org/library on GitHub and cloned your fork. To follow changes from the canonical repository, add it as upstream:

fork-and-contributeshell
git remote add upstream https://github.com/org/library.git
git remote -v
# origin    git@github.com:you/library.git    (fetch)
# origin    git@github.com:you/library.git    (push)
# upstream  https://github.com/org/library.git (fetch)
# upstream  https://github.com/org/library.git (push)

git fetch upstream

The fetch step downloads upstream's branches into your local repository as upstream/main, upstream/release-2.x, and so on. You can now diff your work against the canonical repository without leaving the terminal.

Example 4: Inherit an unfamiliar repository

A teammate hands you their clone. Before you push anything, find out where it points.

investigateshell
git remote -v
git remote show origin

The first command answers "where does this clone push?" in one line. The second answers "what is the relationship between my branches and the remote's?" in a paragraph. Together they prevent the worst remote-related accidents: pushing to the wrong fork, or pulling and overwriting work because a tracking relationship was different than you assumed.

Sources & further reading

  • Pro Git, 2.5: Working with Remotes Textbook Scott Chacon and Ben Straub

    The canonical walkthrough of git remote with worked output for listing, adding, fetching, inspecting, renaming, and removing remotes.

  • git-remote(1) Manual Page Reference Git project

    Exhaustive reference for every git remote subcommand and option, including set-url --push, --add, and the tracking flags for add.

  • git-clone(1) Manual Page Reference Git project

    Defines what git clone actually does: create the directory, add origin, fetch, and set up tracking. Helpful when you want to replicate the result manually.

  • About remote repositories Tutorial GitHub Docs

    GitHub's explanation of remote URLs, with a clear breakdown of when to use HTTPS versus SSH and what credentials each one needs.

  • Managing remote repositories Tutorial GitHub Docs

    Recipe-style coverage of git remote add, set-url, rename, and rm against GitHub repositories, including switching protocols.

  • Syncing: git remote Tutorial Atlassian

    A second perspective that frames remotes as bookmarks and walks through the common multi-remote patterns with diagrams.