Skip to content

Remotes

Remote repositories are simply repositories with their own independent Git trackers that are hosted on a server, typically outside of our local machines. Remotely hosted directories that contain Git trackers are a great way to work collaboratively, provide backup for local repositories using a network connection, or even base deployed sites and programs. Centrally hosted repositories are often used as a sort of official or “golden” copy of a repository.

Remotes work in a very similar way to the way local repositories work. The major difference is obvious; they are indeed unique repositories. When we’re ready to update the remote, we “push” our local changes out to the remote server. When a remote is established, the push populates an origin/main pointer on our local repo similar to the HEAD pointer. Our localized origin/main pointer acts like a HEAD pointer for the remote. If we are working collaboratively, others may also push commits to the remote, which will change the remote’s HEAD pointer. To keep in sync, we need to retrieve the latest commits from the remote by performing a “fetch” which pulls the latest commits to our repo and updates our origin/main pointer, but not our local HEAD pointer. To sync our local repo, we perform a “merge” which updates the HEAD pointer to the origin/master that was recently fetched. So this means we make commits locally, then fetch the latest remote version to bring the origin/main in sync, then perform a local merge, and then push that all out back to the remote.

Git Hosts

In order to work with remotes, we need a remote server to host the repository. One of the most popular Git hosts as of the writing of this guide in 2023 is probably GitHub. This guide uses GitHub for its remote repo hosting. GitHub has its own CLI tool that can come in handy, but it also has a fully featured UI that is easy to use.

Getting Started With Remotes

Before we can begin working with remotes, we need to establish a connection. Establishing a connection involves both the access protocol and the order in which we duplicate project information. For accessing the remote we can either set up secure shell (SSH) keys or HTTPS connections via personal access tokens. This guide prefers SSH access because it is much cleaner and easier to work with once established. Duplicating the project information involves either creating a remote from a local project, or cloning an already established project to our local machine. These options all involve different workflows.

SSH Access

Before we can use SSH access, we need to set up the keys. This guide paraphrases the steps found in GitHub’s official guides. More information about SSH can be found on Wikipedia. The gist of it consists of a public/private key pair used to authenticate each individual machine. To set Git up to access GitHub repos, use the following steps.

  1. Check for valid SSH keys by running an ls command in terminal.

    ls -al ~/.ssh

    If the command returns a list of key files, you will notice that there are actually two files per key type, a public and a private key file. The .pub file is the value we’ll use in GitHub. As of 2023, GitHub accepts the following SSH key types;

    • id_rsa.pub
    • id_ecdsa.pub
    • id_ed25519.pub

    Valid SSH keys may contain associated passphrases. If you don’t want to deal with a passphrase, don’t set one up. If you have to have a passphrase but don’t want to have to deal with it every time, add the SSH key to an SSH agent. This is covered below. If none of the listed key files exist, proceed to create an SSH key.

  2. Create a SSH key with the following command. Notice that this command creates an ed25519 type key. The details aren’t necessarily important, just take note of the signature scheme used in this example for consistency.

    ssh-keygen -t ed25519 -C "your_email@example.com"

    When generating keys, the ssh-keygen command prompts you to name the key. If you’re only generating one, the default value is fine, otherwise you will need to provide a unique name so as not to overwrite previous keys! The command also prompts you to enter an optional passphrase. For simple GitHub purposes, a passphrase isn’t strictly necessary.

  3. (Optional) Add the SSH key to an SSH agent. If you opted to use a passphrase and want to manage keys, this is a helpful step. If no passphrase is required, and only one key is being used, this step can be skipped for simplicity.

  4. Add a SSH key to your GitHub account. GitHub forces users to choose between two SSH key types. Authentication keys are used to access Git repos and signing keys are used to sign commits. We need at least an authentication key type to work with remotes. When you set up a GitHub key as a specified type it can be used only for that purpose, however the same public SSH key generated in step 2 can be used to create both an authentication and signing key in GitHub.

    • Copy the value of the desired public key using a command similar to the following terminal command. This example copies the public key for the ed25519 key we just generated.
      pbcopy < ~/.ssh/id_ed25519.pub
    • In the GitHub UI, access your profile’s settings with the gear icon. This is likely easiest to access via the profile icon dropdown.
    • From settings locate the SSH & GPG keys page in the navigation. Click New SSH key.
    • Configure the key. Add title (such as “RemoteAccess” or similar, if more than one key is required, keep names easy to distinguish), select desired key type (remember that we need at least an authentication key type), and paste the copied key value via cmd + v.
    • Finally, click Add SSH key. You may also be required to authorize your key if you’re working with an organization that requires SSH key authorization.
  5. (Conditional) Authorize your SSH key for your organization. If your organization requires SSH key authorization, this relatively easy step involves navigating to the SSH & GPG keys page, and simply clicking Configure SSO to authorize which organization you’d like to work with from the drop-down.

  6. Test the key. In terminal, use the command:

    ssh -T git@github.com

    Add the -v option for verbose output. This may result in a verification step. Check that the public key matches GitHub’s public key fingerprint. Note that it is also possible to add fingerprints to the ~/.ssh/known_hosts file to avoid future verification steps for GitHub.

Setting up a remote

Now that we have the keys, we can either clone a repo to start working with it, or we can create and push to one. Let’s start by cloning a remote because it’s the easiest.

Cloning a remote

This workflow assumes you have access to an established remote repository/project. This could be a project you’ve created previously (and deleted locally), or it could be a project you’re forking.

  1. To clone a repo from GitHub, locate the repo’s url. From the < > Code tab in the repo, locate the similarly named < > Code button. This button contains a dropdown with a couple clone options. Because this guide focuses on SSH we’ll select that url and copy it.

  2. In terminal, navigate to the desired parent directory and run the git clone command.

    $ git clone git@github.com:p5chmitz/tech-docs.git
  3. Use your editor of choice to work with the repo!

Creating a remote Using GitHub UI

This workflow assumes that we already have an established local project with Git tracking. For more information on how to set up a project, see the Git Basics section.

  1. Create a remote on GitHub. From the Repositories tab in the GitHub UI for the desired user select the New button. From here configure the repo as desired. Once ready, click the Create repository button. This will give us the URL(s) for the remote. The UI provides multiple URLs based on the desired communication protocol. For example the HTTPS and SSH URLs will differ. For the sake of illustration, lets say we create a remote called “testing”. The URLs that GitHub generates vary by communication protocol. HTTPS is set up as https://github.com/<user>/<repo name>.git and SSH is set up as git@github.com:<user>/<repo name>.git. For the sake of illustration, lets say we used the “p5chmitz” user to create a repo called “testing”. The SSH URL would be git@github.com:p5chmitz/testing.git.

  2. Create a remote pointer. In order to manage remotes, we need to reference them through the use of pointers. For new local projects that do not have any remote pointers set up, use the remote function to create one. By convention, these are typically named “origin”, and we only typically need only one.

    Syntax: git remote add <remote pointer name> <URL>

    This guide prefers SSH, but HTTPS is still a viable option. The following example lists a call to create an “origin” pointer in a repo called “testing” via SSH protocol.

    $ git remote add origin git@github.com:p5chmitz/testing.git
  3. Push to the remote. Now that we have a remote and a named pointer we can push our local repo to the remote. Note that to specify the exact connection the first push needs to set the upstream pointer. This is done with the -u/--set-upstream-to option. Subsequent pushes to the remote may not require arguments. See the section on pushing to remotes below for more information.

    $ git push -u origin main

Create Remote Repo From CLI

It is also possible to create a remote repo from the command line, but this requires GitHub’s proprietary CLI tool. GitHub’s CLI tool can be downloaded via Homebrew (MacOS) with the brew install gh command. See the GitHub docs for more information. This section, like the previous workflow, assumes that we already have an established Git project running locally.

  1. Navigate to the parent directory of the Git project. For example, if we want to create a remote repo on GitHub for the Java project listed in the example below, we navigate to its parent, in this case ~/MyPrograms.

    Terminal window
    ~/MyPrograms $ tree ../MyPrograms/
    ../MyPrograms/
    ├── Learning-Java
    └── Learning-Rust
  2. Create the repo. From the parent directory of the project directory, run the gh command.

    Syntax: gh repo create --<access modifier> --source ./project

    $ gh repo create --private --source ./Learning-Java
  3. Push the project to the remote. cd into the Git directory and run the following command.

    Terminal window
    $ git push -u origin main

    If the keys we have set up require a passphrase, the system will prompt the user before pushing. Voilà! Now you have a local repo matched with a remote repo on GitHub!

Remove A Remote Pointer

Remote pointers are rarely removed. To remove a remote pointer,

$ git remote rm <remote pointer name>

Remote Branches

Remote branches work the same way local branches do. Remote branches are a great way tool for collaborative efforts before the code is merged into the remote main. Branches are the preferred way of dealing with pull requests (PRs).

Get A List of Remote Branches

Whenever a new branch is created, it is wise to first check which branches are available within the local repo.

$ git branch

Use the following options with git branch,

  • Use the -a option to view local AND remote branches
  • Use the -r option to view ONLY remote branches
  • Use the -v option to add SHAs and commit messages
  • Use the -vv option to add SHAs, commit messages, and relationship to upstream branch

Create A Remote Branch

If the remote repo is empty (as with a fresh remote project) it will first be necessary to create a branch. To create a remote branch, start by creating a local branch based of whatever repo is desired. It is best to start with the pointer in whatever branch we desire to start a new branch from, so use the -b option.

$ git checkout -b main
$ git checkout -b new_feature_221119

Track Remote Branch

Use the -u option in the initial remote branch creation to track a branch either at first push or anytime afterwards.

Clone A Remote Branch

For situations where there is already content within a remote that we want to work with, we can clone a preferred branch to start working with it. This is usually the first step in working with an already established repo.

git clone SSH ex.

$ git clone git@github.com:p5chmitz/learning-java source

Push Commits

After changes are made to our local code, we can commit the changes to the branch we would like to push, and then push the code to the remote. If the remote branch is not yet created, use the -u option previously mentioned to simultaneously track the branch. When used with push or clone, the -u option automatically tracks the new branch.

First commit on a remote: git push -u <remote branch base> <local branch>

Terminal window
$ git push -u origin new_feature_221119

If we’re already tracking the remote alias (in most cases the “origin” branch), then we don’t even need to specify the remote alias or current branch and just use git push.

Fetch Changes From Remote

(First make sure there are changes to the remote.)

The fetch command retrieves changes from the designated remote and brings them into the repo, but does not change the HEAD pointer. That means that even if there are changes, it does not affect the current version of the codebase. Good practice dictates that we fetch often! Fetch before we start work, fetch before we push, and fetch before going offline to get all the changes before we can’t anymore - FETCH OFTEN! To retrieve the changes, use the fetch command.

Syntax: git fetch <target remote branch> <sync to local branch>

$ git fetch origin main

Then check the changes with diff.

$ git diff main..origin/main #The remote lacks...
$ git diff origin/main..main #My local repo adds...

Merge Fetched Changes From Remote

Remote tracking branches cannot be checked out, they simply contain the data from the remote. This means that they will store information and present conflicts if we try to push changes from our local repo to the remote. The local repo must have the fetched changes merged before it can be pushed to update the remote. This is because Git doesn’t know how to resolve a branch that seemingly has two endpoints. It also prevents us from overwriting the remote codebase.

$ git merge

There may be times when the two-step process is more hindrance. For example, if no work has been done to the local repo, but there may be changes on the server, such as at the beginning of a work day, it can be desirable to combine the fetch and merge actions with a simple pull command.

$ git pull

Delete A Remote Branch

This process refers to removing a branch from the remote server, not a local repo. This is most useful when a feature branch has been completed and merged and the extra branches are just clogging things up.

Syntax: git push <target repo>:<target branch to delete>

Syntax: git push <target repo> --delete <target branch to delete>

The first method works because without the first argument, it’s pushing nothing to the tree-ish, effectively deleting it. The --delete method is newer, and clearer, but requires more typing.

Working With Pull Requests

Pull requests (PRs) are a feature that is specific to GitHub. Even though git has an app called request-pull, it is not the same as a GitHub pull request! Pull requests are one of the most common ways for collaborators to ask for changes to be made to a repository. This is done by first cloning (or forking) the repository to a local branch and then either altering the clone or creating another local branch to track alterations before pushing the new branch back to the remote and opening a pull request which compares the changes and formats them to easily decipher changes and provide a space for conversation. Once the PR is approved, it is possible to merge the changes into the main branch.

Creating Pull Requests

Creating PRs can be done in a couple ways.

The first (and easiest) method is to simply initiate PRs in the GitHub UI. To create a pull request, simply navigate to the file you wish to change, edit it, and commit the changes to a new branch. This may require a confirmation step to actually create the PR.

The second and more powerful way to initiate a PR is from an IDE like IntelliJ or VSCode. Because we need a clean branch to work on, first clone the desired repo and create a local branch to edit. Once the edits are complete, commit changes (locally), and then push the branch back to the remote. At this point a pull request can be opened in the UI. Taking this a step further, it’s possible to actually open the PR from the IDE in the Pull Requests tab (IntelliJ).

Reviewing Pull Requests

When proposing changes to a repo without write permissions, first fork the repo.

Making changes