12. 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.

Centralised

Distributed

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

try:
    from google.colab import drive  # type: ignore

    drive.mount("/content/drive")
    drive_dir = "/content/drive/MyDrive"
except ImportError:
    print("Not running on colab")
    drive_dir = os.path.join(os.getcwd(), "drive", "MyDrive")
    os.makedirs(drive_dir, exist_ok=True)

print(f"Drive dir: {drive_dir}")

git_dir = os.path.join(drive_dir, "learning_git")
working_dir = os.path.join(git_dir, "git_example")

if os.path.exists(working_dir):
    print(f"Git example directory: {working_dir}")
    os.chdir(working_dir)
else:
    print("Start from the beginning")
Not running on colab
Drive dir: /mnt/nvme1n1p2/home/yj.lee/workspace/projects/lecture/book/lectures/softeng/vcs/drive/MyDrive
Git example directory: /mnt/nvme1n1p2/home/yj.lee/workspace/projects/lecture/book/lectures/softeng/vcs/drive/MyDrive/learning_git/git_example
%%bash
git checkout main
git remote add entelecheia-ai https://github.com/entelecheia-ai/github-example.git
git fetch entelecheia-ai
Already on 'main'
Your branch is up to date with 'origin/main'.
From https://github.com/entelecheia-ai/github-example
 * [new branch]      main       -> entelecheia-ai/main

Check your remote branches:

%%bash
git remote -v
entelecheia-ai	https://github.com/entelecheia-ai/github-example.git (fetch)
entelecheia-ai	https://github.com/entelecheia-ai/github-example.git (push)
origin	https://github.com/chu-aie/github-example.git (fetch)
origin	https://github.com/chu-aie/github-example.git (push)

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

%%bash
git fetch entelecheia-ai
%%writefile Pennines.md

Mountains In the Pennines
========================

* Cross Fell
* Whernside
Writing Pennines.md
%%bash
git add Pennines.md
git commit -am "Add Whernside"
[main 8977bc2] Add Whernside
 1 file changed, 6 insertions(+)
 create mode 100644 Pennines.md

We can specify which remote to push to by name:

%%bash
git push -uf entelecheia-ai || echo "Push failed"
To https://github.com/entelecheia-ai/github-example.git
 ! [remote rejected] main -> main (permission denied)
error: failed to push some refs to 'https://github.com/entelecheia-ai/github-example.git'
Push failed

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

%%bash
git push -uf origin main
To https://github.com/chu-aie/github-example.git
   964c673..8977bc2  main -> main
branch 'main' set up to track 'origin/main'.

Referencing remotes#

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

%%bash
git fetch
git log --oneline --left-right entelecheia-ai/main...origin/main
> 8977bc2 Add Whernside

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:

%%bash
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:

%%bash
git branch -vv
* main 8977bc2 [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")
os.chdir(git_dir)
%%bash
mkdir -p bare_repo
rm -rf bare_repo/*
cd bare_repo
git init --bare --initial-branch=main
Initialized empty Git repository in /raid/cis/yjlee/workspace/projects/lecture/book/lectures/softeng/vcs/learning_git/bare_repo/
os.chdir(working_dir)
%%bash
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:

%%bash
git remote -v
entelecheia-ai	https://github.com/entelecheia-ai/github-example.git (fetch)
entelecheia-ai	https://github.com/entelecheia-ai/github-example.git (push)
local_bare	../bare_repo (fetch)
local_bare	../bare_repo (push)
origin	https://github.com/chu-aie/github-example.git (fetch)
origin	https://github.com/chu-aie/github-example.git (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
exit
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/id_rsa.pub)

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