Now that we've introduced you to branching in Git we can finally talk about remotes. Remotes are a lot easier to understand once you understand branching so if you're still iffy on that subject it might be worth reading/watching part 2 again. To start let's refer back to a graphic I shared in part 1.
Distributed Version Control means that the same Git repository can exist in multiple places. It is possible to clone that repository multiple times on one computer, but traditionally the point of a remote repository is that it's actually remote, on a server somewhere. The nice thing about DVCS vs VCS is that in a distributed system there is redundancy. For example, let's say your company's server bites the dust and takes your main remote Git repository with it so your team can no longer push their work to it. In that situation you need only set up a new server, clone one of your team member's repositories to it, and then have the rest of your team sync up with it.
You may have pushed work up to that now defunct repository that your teammates did not have. Likewise they may have pushed work up there that you had yet to pull down yourself. But since you all have your own versions of the repository on each of your computers, all you have to do is setup a new remote and have all of you push to it, bringing it back up to date. To actually lose work the server would have had to burn down and one of your team member's repos would have to somehow be destroyed too. Even then, only that specific team member's work that hadn't been pulled down yet by anyone else, would have been lost. DVCS redundancy makes it very hard to actually lose work. This is the reason why Subversion and other non-distributed version control systems are now obsolete.
How do we set up a remote repository?
The easiest way to get started with a remote repository is by using Github.com. There are others, such as Bitbucket or Gitlab, but Github is the most popular and the one I am most familiar with. The first step will be to create a Github account so head on over there and fill out their sign up form :)
Once we have an account let's go ahead and create our first repository. Start by clicking the new repository button, which at the time of this writing is in the upper-right corner of the page.
You will be presented with a form allowing you to input a title and description for your new repository. What we're going to do is create a remote repository for the local repository we created in previous tutorials. After that we'll add our remote to our local repo and push to the remote. What this means is that we will not check the box telling Github to initialize the repository upon creation. If we didn't already have our own repo we could let Github intialize this one and then we could clone it to our computer.
The next step will be to add this repository as a remote, but before we can do that we need to ensure Git on our computer can communicate securely with our Github account.
Creating an SSH key
An SSH key is a pair of encrypted strings most often generated with an RSA 2048-bit encryption algorithm. You don't need to know what that means other than it generates a string of characters that essentially acts a really big password. Generating an SSH key involves generating a "private key" and a "public key". The private key will stay on your computer and should NOT be shared with anyone, ever. Sharing your private key with anyone completely undermines the point of having an SSH key because it would give others the ability to decrypt data that is encrypted using your public key. The public key is meant to be shared with the server that hosts your remote repository. This allows the remote server to use that public key to encrypt authentication challenge data and send it to you. If you were a hacker listening to that request, you would get the encrypted authentication data but you wouldn't be able to decrypt it without the private key. Your computer, having the private key, will be able to decrypt the challenge and reply with the it to the server, proving that your computer owns the private key and can be trusted.
On Linux and OS X (Unix) systems the easiest way to generate an SSH key pair is via the terminal. However, we are going to be discussing Git in the terminal in the next part of the tutorial so we'll cover SSH key generation from the terminal at that point. For now I'll show you how to generate an SSH key pair on Windows using a program called PuTTY which you should already have installed when you installed Sourcetree. To launch PuTTY simply open Sourcetree and navigate to
Tools > Create or Import SSH Keys.
Once the tool is launched we're going to click "Generate" to begin creating our first SSH key pair.
Once we click Generate you will have a couple seconds to move your mouse around randomly in the blank area of the window. The reason for this is that the PuTTY program likes to use random mouse movement in the generation of your random key for extra unpredictability.
Making Github aware of our public SSH key
Now that we have our private key file saved somewhere and our public key on our clipboard, let's head over to Github and tell it to save our public key. There are two places you can store your public key on Github. You can either store it in the settings specific to your new repository, or you can store in your account-wide settings. The first option only allows Git to talk to this specific repository on Github and any others you specifically store that same public key on. The second option allows you to store your public key once and Git will be able to interact with all the repositories stored under your Github account. Most of the time you probably want the second option, which is what I'm going to show here.
Once there you can navigate to "SSH and GPG keys" on the left-hand side.
From there you can see any SSH keys you already have associated with your account. In my case I have a key associated with my Windows Subsystems for Linux (WSL) installation, which grants me access to an Ubuntu terminal on Windows, but don't worry about that. If you're new to this and just created your Github account then you shouldn't have anything in there yet. To store your key simply click "New SSH key".
Now paste your public key string into the "Key" field and give your key a title. The title is arbitrary, meaning you can name it anything you want. It's a good idea to name it after the computer that holds the private key so you know in the future what machine this public key is associated with. Once complete just click "Add SSH key".
Telling PuTTY to host our private key
There is one last step before Sourcetree can communicate securely with Github. The PuTTY SSH agent needs to be made aware of our private key so it can use it to decrypt messages from Github. We used PuTTY to create and save the key file but we still need to load it into the agent, which should be running in your task tray already.
If the agent is not already running you can launch it from Sourcetree. Simply go to
Tools > Launch SSH Agent....
Once the PuTTY agent is running you can simply double-click it in the Windows task tray to launch the agent's key manager.
This is where we will point the PuTTY agent to our private key file we saved. Simply click "Add Key" and navigate to where you saved your private key.
Adding a reference to our remote repository
Now that our key is accessible by Sourcetree when communicating with Github, we can finally add our Github repository as a remote to our local repository. First we need to copy our remote repository's URL. Go to the page on Github for your new repository, ensure you have "SSH" selected, then copy the URL.
Once the URL is on our clipboard we can open up our repository settings in Sourcetree and add it as a remote.
Click "Add" to bring up a dialog for creating a new remote reference. It will ask you for a name and a URL. Paste the URL we copied into the URL field. You are free to give the remote any name you wish but with this being our very first remote for this repository it is traditional to use the name
origin. In fact, you can simply check the box to the right of the name field called "Default remote" and it will do that for you. If our local repository had been created by cloning the Github repository rather than adding the remote manually like we are, then it would have already added the Github repository as a remote called
The crossed-out area is Sourcetree's remote Git hosting provider account integration. It would conveniently let you choose from repositories under your account without the need to manually copy the URL like we did. For this tutorial we are skipping that feature in order to focus on how to manage a Git repository manually without the help of tools like that. Feel free to add your Github account to Sourcetree on your own so that Sourcetree can access the Github API and give you all sorts of helpful tools. I just wanted to focus on manual Git management for learning purposes but there is nothing wrong with exploring the other features of Sourcetree on your own :)
Pushing changes to our remote
Now that we have a remote added to our repository there are various operations we can perform. In this tutorial we created a local repository first and the remote second, then added the remote refernce to our local repository manually. What this means is that our remote repository is currently empty; it does not contain any commits or any of our files. To fix this we simply need to click "Push".
This will bring up a dialog asking you what you would like to push to the remote repository. By default since this is our first push it has not selected any of our branches. In this tutorial we have two branch pointers:
new-feature. Remember, these are just pointers that reference commits. However, Git will only push up the commits that are part of known commit chains starting at our branch pointers. In other words, if we only check the box for
master then it will push the commit referenced by the
master branch pointer and all the commits that came before it, leaving behind any commits that branched off and were never merged back to
master. In our case though, we only have one other branch and all of its commits were merged back into
master. So while we wouldn't be pushing the
new-feature branch pointer to the remote repository if we don't check the box for it, all the commits that pointer references are also referenced by the
master branch pointer and would still be pushed up there.
Check the boxes for which branches you would like to push to the remote and click "Push". Once that is complete we can head over to our history view in Sourcetree and we should see some new pointer references.
Right away in our history view you can now see that we have two new branch pointers. Since both
new-feature were pointed at the same commit, their remote counterpart branches are also pointed at the same commit. Thus we have four branch pointers present. We can also head over to our Github page for our remote repository and refresh it.
Our Github repository is now aware of all the same commits that our local one is. Anyone else that needs to work on the same project can now clone from this Github repo and create their own local Git repo just like ours. By default Github repositories are public so anyone could clone your repository unless you mark it private. However, they cannot push changes to your repository unless you explicitly grant their Github account access to the specific repo you want them to have access to.
Creating a commit via Github's web interface
One nice feature about Github is that it allows you to edit and commit changes to files from right within their web interface. It's not ideal for big changes, but for a minor change or fix while you're away from your computer it's quite handy. You've already seen us push changes to our repository. If you made further commits to your local repository you could simply walk through the same process to push those new changes up to Github. But what about pulling down changes? To demonstrate that let's first make a change via Github itself so that only the remote repository is aware of that change, then we can pull that change down using Sourcetree.
Click the file in your repository and you should see its contents. In the top right of the file view you should find an edit button that will bring you to a text editor so that you may modify the file. I opened up my
Grocery List.txt and added
- Apples to the list. After making your change simply scroll to the bottom of the page where you'll find a small form to fill out in order to make a commit.
Simply add a short message describing your commit and click "Commit Changes". Once that's finished you can head over to the "commits" tab on Github to see the commit history for our remote.
Pulling down changes from our remote
Now let's go back to Sourcetree. The first thing you'll notice is.. nothing. Our local repository is not aware of changes to the remote. This is why it's good to periodically do a "Pull" to bring down any changes your teammates may have pushed up there. To do that simply click "Pull".
Before we click "OK" and begin to pull down any new commits I first want to explain what a "pull" actually is. You may notice another button in the Sourcetree toolbar called "Fetch". A pull is actually a fetch followed by a merge. A fetch is simply a call to the remote repo to update our remote branch pointers. Remember above how we were able to see which commits our remote's branches were pointing too (
origin/new-feature). A fetch simply updates those references so our local repository is aware of any new commits the remote branches might be pointing to. If there are additional commits to pull down then a pull will also perform a merge, which we went over in Part 2 when talking about merging between branches. This merge is essentially the same thing except it will also copy down the missing commits from the remote to your local repository.
You are welcome to use the "Fetch" button as often as you like. It will simply update your local repository's knowledge of what's going on with the remote repository. It's a harmless operation that by itself does not try to update any data or pull down any commits. It only updates remote references. That said, logistically you don't have to ever really use the fetch feature in Git unless you need to check out a new branch that your local repository is unaware of. A fetch will make your local repository aware of that new branch so that you can check it out. Outside of that a periodic pull is all you need to worry about. The longer you go without doing a pull from the remote, the more likely it's going to be that you will have conflicts with one of your colleagues when you do eventually pull.
That's it for part 3! Hopefully you have a good understanding of what a remote repository is and how to set one up for yourself. If things are still fuzzy then I highly recommend returning to the top of this article and giving the video tutorial a watch-through :)