| Contents |

9 Remotes: Repos in Other Places

A remote is just a name for a remote server you can clone, push, and pull from.

We identify these by a URL. With GitHub, this is a URL we copied when we went to clone the repo initially.

It’s possible to use this URL to identify the server in our everyday Git usage, but it’s unwieldy to type. So we give the remote server URLs nicknames that we just tend to call “remotes”.

A remote we’ve already seen a bunch of is origin. This is the nickname for the remote repo you cloned from, and it gets set automatically by Git when you clone.

9.1 Remote and Branch Notation

Before we begin, note that Git uses slash notation to refer to a specific branch on a specific remote: remotename/branchname.

For example, this refers to the main branch on the remote named origin:

origin/main

And this refers to the branch named feature3490 on a remote named nitfol:

nitfol/feature3490

We’ll talk more about this in the Remote Tracking Branches chapter.

9.2 Getting a List of Remotes

You can run git remote with the -v option in any repo directory to see what remotes you have for that repo:

$ git remote -v
  origin    https://github.com/example-repo.git (fetch)
  origin    https://github.com/example-repo.git (push)

We see that we’re using the same URL for the remote named origin for both pull (part of which is fetch) and push. Having the same URL for both is super common.

And that URL is the exact same one we copied from GitHub when cloning the repo in the first place.

9.3 Changing a Remote’s URL

Remember that a remote name is just an alias for some URL that you cloned the repo from.

Let’s say that you are all set up with your SSH keys to use GitHub for both push and pull, but you accidentally cloned the repo using the HTTPS URL. In that case, you’ll see the following remote:

$ git remote -v
origin    https://github.com/example-repo.git (fetch)
origin    https://github.com/example-repo.git (push)

And then you try to push, and GitHub tells you that you can’t push to an HTTPS remote… dang it!

You meant to copy the SSH URL when you cloned, which for me looks like:

git@github.com:beejjorgensen/git-example-repo.git

Luckily it’s not the end of the world. We can just change what the alias points to.

(The example below is split into two lines so that it’s not too wide for the book, but it can be on a single line. The backslash lets Bash know that the line continues.)

$ git remote set-url origin \
             git@github.com:beejjorgensen/git-example-repo.git

And now when we look at our remotes, we see:

$ git remote -v
origin    git@github.com:beejjorgensen/git-example-repo.git (fetch)
origin    git@github.com:beejjorgensen/git-example-repo.git (push)

And now we can push! (Assuming we have our SSH keys set up.)

9.4 Adding a Remote

There’s nothing stopping you from adding another remote.

A common example is if you forked a GitHub Project (more on that later). A fork is a GitHub construct that enables you to easily clone someone else’s public repo into your own account, and gives you a handy way to share changes you make with the original repo.

Let’s say I forked the Linux source repo. When I clone my fork, I’ll see these remotes:

origin    git@github.com:beejjorgensen/linux.git (fetch)
origin    git@github.com:beejjorgensen/linux.git (push)

I don’t have access to the real Linux source code, but I can fork it and get my own copy of the repo.

Now, if Linus Torvalds makes changes to his repo, I won’t automatically see them. So I’d like some way to get his changes and merge them in with my repo.

I need some way to refer to his repo, so I’m going to add a remote called reallinux that points to it:

$ git remote add reallinux https://github.com/torvalds/linux.git

Now my remotes look like this:

origin    git@github.com:beejjorgensen/linux.git (fetch)
origin    git@github.com:beejjorgensen/linux.git (push)
reallinux    https://github.com/torvalds/linux.git (fetch)
reallinux    https://github.com/torvalds/linux.git (push)

Normally when setting up a remote that refers to the source of a forked repo on GitHub, people tend to call that remote upstream, whereas I’ve clearly called it reallinux.

I did this because when we subsequently talk about remote tracking branches, we’re going to use “upstream” to mean something else, and I don’t want the two to be confusing.

Just remember IRL when you set up a remote to point to the forked-from repo, it’s relatively customary to call that remote upstream.

Now I can run this to get all the changes from Linus’s repo:

$ git fetch reallinux

And I can merge it into my branch (the Linux repo uses master for the instead of main for the main branch):

$ git switch master            # My local master
$ git merge reallinux/master   # Note the slash notation!

That will merge the master branch from the reallinux into my local master, once we’ve dealt with any conflicts.

If I make another commit, this will move my local HEAD and master to that new commit, and will leave origin/master (my fork on GitHub) and reallinux/master (Linus’s repo) farther behind.

Let’s say for fun I made two commits that I didn’t have on my origin remote at GitHub. In that case, a chopped up and fabricated-for-demonstration-purposes log might look like this:

commit 2d7d5d (HEAD -> master)
commit cde831
commit 311eb3 (origin/master)
commit d5d2cc (reallinux/master)

At this point I’d do a git push to send my local master changes to GitHub and catch up my origin/master there. So the top commit would show:

commit 2d7d5d (HEAD -> master, origin/master)
commit cde831
commit 311eb3
commit d5d2cc (reallinux/master)

And reallinux/master would still be behind somewhere. (And there it would remain until Linus deigned to merge my changes.)

It’s interesting that my local master can be out of sync from the master on origin, right?

We’ll look at this in the Remote Tracking Branches chapter.


| Contents |