Working with multiple remotes

Distributed versus centralised

Older version control systems (cvs, svn) were “centralised”; the history was kept only on a server, and all commits required an internet.



Server has history

Every user has full history

Your computer has one snapshot

Many local branches

To access history, need internet

History always available

You commit to remote server

Users synchronise histories

cvs, subversion(svn)

git, mercurial (hg), bazaar (bzr)

With modern distributed systems, we can add a second remote. This might be a personal fork on github:

import os

top_dir = os.getcwd()
git_dir = os.path.join(top_dir, "learning_git")
working_dir = os.path.join(git_dir, "git_example")
git checkout main
git remote add jack89roberts
git fetch jack89roberts
Switched to branch 'main'
Your branch is up to date with 'origin/main'.
 * [new branch]      main       -> jack89roberts/main
 * [new branch]      master     -> jack89roberts/master

Check your remote branches:

git remote -v
jack89roberts (fetch)
jack89roberts (push)
origin (fetch)
origin (push)

and ensure that the newly-added remote is up-to-date

git fetch jack89roberts
Warning: Permanently added the ECDSA host key for IP address '' to the list of known hosts.

Mountains In the Pennines

* Cross Fell
* Whernside
git add
git commit -am "Add Whernside"
[main a3ce7d0] Add Whernside
 1 file changed, 6 insertions(+)
 create mode 100644

We can specify which remote to push to by name:

git push -uf jack89roberts main || echo "Push failed"
ERROR: Permission to jack89roberts/github-example.git denied to deploy key
fatal: Could not read from remote repository.

Please make sure you have the correct access rights
and the repository exists.
Push failed

… but note that you need to have the correct permissions to do so.

git push -uf origin main
   71cdbbe..a3ce7d0  main -> main
branch 'main' set up to track 'origin/main'.

Referencing remotes

You can always refer to commits on a remote like this:

git fetch
git log --oneline --left-right jack89roberts/main...origin/main
> a3ce7d0 Add Whernside
> 71cdbbe Merge branch 'main' of
> afd1a13 Add Glyder
> 1fe0962 Add another Beacon
> 807e3f8 Merge branch 'main' of
> ea47bd7 Translating from the Welsh
> 0809fde Add a beacon
> 2055725 Merge branch 'main' of
> 54d3883 Add wales
> caaf510 Add Scotland
> 2e2ee6e Add Helvellyn
> e8c018d Include lakes in the scope
> d9160c8 Add lakeland
> fa4dd70 Revert "Add a lie about a mountain"
> 366e9c0 Change title
> 0c51bea Add a lie about a mountain
> d833c8a First commit of discourse on UK topography
< 31ea056 Add Whernside
< 009f998 Add github pages YAML frontmatter
< 2f9bcc8 Add a makefile and ignore generated files
< ae539cc Merge branch 'experiment' into main
< 492fec5 Commit Aonach onto main branch
< fe1c71d Add Cadair Idris
< 338d4d6 Merge branch 'main' of into main
< 07c4fea Add Glyder
< c405c4d Add another Beacon
< f8f20a6 Merge branch 'main' of into main
< 1f69c3f Translating from the Welsh
< b2b4fa3 Add a beacon
< c1897d4 Merge branch 'main' of into main
< 0e96c25 Add wales
< 0de6b80 Add Scotland
< 959e142 Add Helvellyn
< 600ffe1 Include lakes in the scope
< c7454a7 Add lakeland
< 5342922 Revert "Add a lie about a mountain"
< f65fd0b Change title
< 8c467a3 Add a lie about a mountain
< 1f92929 First commit of discourse on UK topography

To see the differences between remotes, for example.

To see what files you have changed that aren’t updated on a particular remote, for example:

git diff --name-only origin/main

When you reference remotes like this, you’re working with a cached copy of the last time you interacted with the remote. You can do git fetch to update local data with the remotes without actually pulling. You can also get useful information about whether tracking branches are ahead or behind the remote branches they track:

git branch -vv
  experiment 497c32c Add Cadair Idris
* main       a3ce7d0 [origin/main] Add Whernside

Hosting Servers

Hosting a local server

  • Any repository can be a remote for pulls

  • Can pull/push over shared folders or ssh

  • Pushing to someone’s working copy is dangerous

  • Use git init --bare to make a copy for pushing

  • You don’t need to create a “server” as such, any ‘bare’ git repo will do.

bare_dir = os.path.join(git_dir, "bare_repo")
mkdir -p bare_repo
rm -rf bare_repo/*
cd bare_repo
git init --bare --initial-branch=main
Initialized empty Git repository in /home/runner/work/rse-course/rse-course/module04_version_control_with_git/learning_git/bare_repo/
git remote add local_bare ../bare_repo
git push -u local_bare main
To ../bare_repo
 * [new branch]      main -> main
branch 'main' set up to track 'local_bare/main'.

Check your remote branches:

git remote -v
jack89roberts (fetch)
jack89roberts (push)
local_bare	../bare_repo (fetch)
local_bare	../bare_repo (push)
origin (fetch)
origin (push)

You can now work with this local repository, just as with any other git server. If you have a colleague on a shared file system, you can use this approach to collaborate through that file system.

Home-made SSH servers

Classroom exercise: Try creating a server for yourself using a machine you can SSH to:

ssh <mymachine>
mkdir mygitserver
cd mygitserver
git init --bare
git remote add <somename> ssh://user@host/mygitserver
git push -u <somename> master

SSH keys and GitHub

Classroom exercise: If you haven’t already, you should set things up so that you don’t have to keep typing in your password whenever you interact with GitHub via the command line.

You can do this with an “ssh keypair”. You may have created a keypair in the Software Carpentry shell training. Go to the ssh settings page on GitHub and upload your public key by copying the content from your computer. (Probably at .ssh/

If you have difficulties, the instructions for this are on the GitHub website.