Go to https://github.com and register for an account. Make sure to choose a username that's professional and recognizable, since this will be your username even if you switch around jobs.
For purposes of this book, you can go with the free plan. With it, you can create an unlimited number of public and private repositories. The steps and processes will be the same for public or private repositories.
If you decide to configure your account with alternative security mechanisms, such as 2 Factor Authentication (2FA), you may be on your own when it comes to authenticating with the git
command. This book only deals with the basic username/password authentication. For more information on authenticating with GitHub, please see GitHub's Documentation.
Some of the images in this chapter show pages on GitHub. The GitHub interface may have changed since we created these images, so the content may look a bit different. Some of these images may show the repository branch name as master
instead of main
; this is not crucial for our purposes.
Now that you have set up your GitHub account, it is time to learn how to use it. Whenever you are logged in to the GitHub website, you will see a plus icon in the upper right corner. When you click on that, you will see a menu that includes a New Repository link. Click on that link.
Choosing a repository name comes next. There are two general rules to follow:
The repository name has to be unique to your account.
That means that someone else can have a repository on GitHub named my-awesome-repo
, and you can have one as well. You cannot however have two repos by the same name under your account.
Choose a descriptive name based on your project.
As far as naming conventions, some people separate words with hyphens and some use underscores. This is personal preference, and you may separate your words with any character you want except a space or tab.
In this guide, we are going to create a remote repository on GitHub.com where we can push the local repository that we created in the last chapter.
As you will see in this example, your local and remote repos do not have to have the same name. We will use my-first-repository
as the name of our remote repository on GitHub.
You will notice that GitHub has added a green checkmark in the text field where we typed our repo name. That tells us that our repo name has no problems and can be used. If you have spaces in your repo name, GitHub will automatically replace them with hyphens.
The next thing we need to look at is the Initialize this repository with a README checkbox. This is a very important step in creating your remote repo.
If you check the box, it will automatically create and commit a README file in your remote repo. Before you can push any commits to the newly created remote repo, you will need to pull the code from your remote repo into your local repo. You will learn more about this later in the chapter.
If, however, you do not check the box, you will be given instructions for creating and linking a local repo with the newly created remote repo.
You will usually create your local repo first, so you will rarely check this box. Whether you initialize the GitHub repository with a README file or not, you need to understand conceptually the consequences.
If you are using GitHub Codespaces, you must initialize a README
file in order to follow our instructions. If you are not using GitHub Codespaces, you should not create a README
file.
You may now click the Create repository button to create a remote repo on GitHub.com.
The information in this section is for GitHub Codespaces. If you are not using GitHub Codespaces, please skip ahead to the next section, Connecting a GitHub Repo to Your Local Repo.
To connect your new GitHub Repo to GitHub Codespaces:
That's it. You should now be logged in to the codespace associated with your new repository. You should see a single file in the repo: README.md
.
The information in this section does not apply to GitHub Codespaces. If you are using GitHub Codespaces, please skip ahead to the next section, What did we just do?
You should now see instructions on how to connect your local repo to the remote one you just created on GitHub. Looking at just the first option, the set of git commands should look very familiar. We've already done the first four or five commands, though with some differences. We only need to perform the last two commands to link our local repository with the remote.
In the command line, make sure you are in your project directory, then execute the following command. You will need to insert your GitHub username and the remote repo name:
# Substitute your GitHub username and your repo name where indicated
$ git remote add origin https://github.com/GITHUBUSERNAME/REPONAME.git
For instance:
$ git remote add origin https://github.com/xyzzyfixlet/my-first-repository.git
If you are using GitHub Codespaces, we did not run the git remote
command shown below. However, GitHub will do it for us when we create a codespace from this repo. Regardless, you should read this section.
Before we move on, let's take a look at the command we just executed.
$ git remote add origin url_to_remote_git_repo.git
The primary git
command we issued is git remote
. Use this command to work with remote repositories. If you just issue git remote
by itself, git
will list all the remote repositories that your local repository knows about. If you pass additional sub-commands to the git remote
command, you can further add, remove, and modify the remote repos that your local repo is linked to. Knowing that, you can guess that we're using the add
sub-command to add a remote repository to the local repository.
That explains the git remote add
parts of the command, but what about origin
and url_to_remote_git_repo
? Both of those things refer to the remote repository. The latter, the url_to_remote_git_repo
, is pretty self explanatory: it's the URL to the remote git repository, which should end with a .git
extension.
The origin
is what we call an alias. The alias is the name that you will use locally to interact with the remote repo. You can have as many remote repos linked to your local repo as you want, but they must all have unique aliases. The instructions generated by GitHub always use origin
as the alias. Any interaction that you have between your local repo and a remote repo will need to include this alias. You can name it whatever you like, but it must follow git naming conventions (no spaces, for example). Most developers use origin
to mean the central repository where we're keeping the official copy of our codebase. More often than not, that implies a remote repo hosted on github.com.
If you open ~/git_basics/.git/config
in a text editor, you will see how git stores the information we just added. Recall that the .git/config
file is where all the configuration settings for your local repository are held, and overrides any global settings. Note that your .git/config
file may not necessarily look like the one below, which already contains an example remote repository called "origin".
[core]
repositoryformatversion = 0
filemode = true
bare = false
logallrefupdates = true
ignorecase = true
precomposeunicode = true
[remote "origin"]
url = https://github.com/joesmith2444/my-first-repository.git
fetch = +refs/heads/*:refs/remotes/origin/*
[branch "main"]
remote = origin
merge = refs/heads/main
The entries under [remote "origin"]
are settings specific to that remote. The settings under [branch "main"]
set up the tracking. For example, remote = origin
tells your local repo to use the origin remote as the default remote for the local main branch to push and pull against.
If you are using GitHub Codespaces, you will not need to authenticate. You may skip ahead to the git push section.
As you interact with GitHub via the CLI, you'll notice that some form of authentication is required to modify and access resources on GitHub. As of August 13th 2021, GitHub is switching from password-based authentication to require the use of token-based authentication. Token-based authentication can be achieved in a few ways, the simplest being the use of a Personal Access Token (PAT). A PAT is a type of hashed password, meaning that the plaintext form of the password is not saved on the server. When the client (you) provides the token to the server, the token is hashed using the same algorithm that hashed the stored version of the password and these values are compared to determine if they match. If you're enrolled in the Launch School curriculum, you'll learn more about hashed passwords in the Networked Applications course.
The chief benefits of PATs are twofold:
The following steps will walk you through creating a PAT. Note that these steps and menu options are subject to change and may require some troubleshooting on your part. Please submit a feedback item if you find that any of the information below is no longer accurate.
Sign in to GitHub.com and go to 'Settings'.
Select 'Developer Settings' then 'Personal access tokens' in the left sidebar.
Click 'Generate new token' and give it a name (e.g., personal use)
The PAT will, by default, expire in 7 days. You can change this if you wish.
As of Oct 2022, this dialog no longer has a Generate New Token
option. Instead, you have 2 choices: Fine-grained tokens
(currently identified as Beta) and Tokens (classic)
. If you see these two choices, we recommend using Tokens (classic)
. Don't mess with Beta products when learning if you can avoid it.
If you do use Tokens (classic)
, click the Generate new token
button on the page that appears, then select Generate new token (classic)
.
You may have to verify your account at this point, but after that, you should be able to continue with the instructions from below.
Select the scopes you'd like to grant the token. Scopes are a way of setting the permissions for users that have access to the token.
Since this token should be used for your purposes only, we recommend not limiting any scopes and selecting all of the scope checkboxes on the far-left of the "Select scopes" area except repo, which will be checked for you. All of the sub scopes will also be filled in automatically.
If you were working with other individuals or organizations and wanted to grant them different levels of access to your repositories, you could generate new, separate tokens and set the appropriate scopes.
Click 'Generate Token'.
Copy the token and save it for future use. You should treat this token like you would another password. Consider using a password management app, such as 1Password or LastPass, or any other secure means of saving the token.
Note that giving your GitHub token to git
does not permanently save it. You must secure your token through other means.
You should now test that the token works as intended by using it in the 'password' field when you push to GitHub in the next section.
If you decide to configure your account with alternative security mechanisms, such as Two-Factor Authentication (2FA), you can now use this PAT as a starting point for authentication via the command line.
You can cause a branch on your local repo (remember, every repo starts with a main branch by default) to track a branch on your remote repo. When you use a command that interacts with a remote repo, and do not specify which branch to interact with, the tracked branch will be used.
Now that we have laid all of the groundwork necessary to push our code to GitHub, let's do that!
In the command line, type the following:
$ git push -u origin main
The -u
flag tells Git to set the default upstream repo -- that is, the remote repo that you intend to use by default for push
, pull
, and similar operations. In this case, we'll be using the main
branch in the origin
repository, which is a shorthand name for your default remote repo. (The name origin
is conventional in most cases, though other names sometimes get used.) Once you've run this command, you can use git push
and git pull
without specifically giving the repo or branch name.
If you have never pushed anything to GitHub, you should now see a login prompt:
$ git push -u origin main
Username for 'https://github.com':
After you successfully login, you should see a message saying that your objects have been written. You will also see a message saying that you have set up your local main
branch to track the remote main
branch, thanks to the -u
flag.
$ git push -u origin main
Username for 'https://github.com': joesmith2444
Password for 'https://joesmith2444@example.com':
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (5/5), 368 bytes | 0 bytes/s, done.
Total 5 (delta 0), reused 0 (delta 0)
To https://github.com/joesmith2444/my-first-repository.git
* [new branch] main -> main
Branch main set up to track remote branch main from origin.
Once again, here's a breakdown of the command.
Sometimes the code in your remote repository will contain commits you do not have in your local repository. In those situations, you will need to pull the commits from the remote repository into your local repository. There are four basic scenarios when you will run into this:
github.com lets you modify files directly on the website, but behind the scenes, it's packaging that edit into a commit on the remote repository directly. This is not a good habit to get into and is only recommended for very special situations.
The first two scenarios are by far the most likely scenarios, while scenarios #3 and #4 are pretty rare.
Although it is not recommended to make changes using the GitHub editor, we will use this method to simulate and work through this workflow.
The first thing we need to do is view the remote repo. To do that, visit https://github.com. On the bottom right section of the screen, you will see a list of the repos that you currently have stored on GitHub.com.
Note: The GitHub interface may change over time, so these images may be out of date. If you see something different on your screen, don't panic. You should still be able to find the information that you need, though you may need to look around a bit.
Click on the my-first-repository
repo, and you will see the files that we pushed earlier in this chapter.
Notice that the contents of the README.md file are shown below the file list. This allows you to easily create documentation for your project, which GitHub will automatically display.
Now we need to make a change to a file. Click on README.md and then click on the pencil icon which is shown above the file's contents.
Modify the contents of the file using the editor and then scroll down. You will see two input fields. These fields allow you to create commit messages for the remote repo just like the git commit -m
command did for our local repo. Type in a commit message and then click the Commit changes button.
While GitHub gives us a nice UI for editing files, committing a change in their UI has the same effect on the remote repository that modifying a file locally and then using git add
and git commit
does on our local repo. Once again, we're editing files directly on GitHub for purposes of this book only, as this is something you rarely want to do in real projects.
Next, we switch back to our terminal and work with our local repository. We need to check our remote repo for changes. The first thing we need to do is fetch the repo, which will download the commit data for each branch that the remote repo contains. Because we are currently working with our local main
branch, the git fetch
command will fetch the commits from the remote repo containing the tracked remote branch.
In the command line, type:
$ git fetch
You should see some messages related to git downloading the remote changes. If you do not see any messages, your remote repo has no changes.
$ git fetch
remote: Counting objects: 3, done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0)
Unpacking objects: 100% (3/3), done.
From https://github.com/joesmith2444/my-first-repository
5afaf12..9389be5 main -> origin/main
The next thing we need to do is look at what has changed. We do that using the diff command. On the command line, type:
$ git diff main origin/main
That produces the following output:
$ git diff main origin/main
diff --git a/README.md b/README.md
index 0647d92..56289ec 100644
--- a/README.md
+++ b/README.md
@@ -1,0 +2,4 @@
+
+This is my first GitHub Repository!
+
+Here is some more text.
The output from the git diff
command shows some changes in our README.md
file. Let's look at the output in some more detail.
First, we ran this command:
$ git diff main origin/main
This command tells git to compare the main
branch on the local repo to the main
branch on the remote repo (origin/main
). Put another way, we're comparing the most recent commit in the local repository with the most recent commit in the remote repository. This sequence treats the local repo as the original content, and the remote repo as the updated content.
Since we're comparing a modified remote repo to our unmodified local repo, the sequence of repos in the command is backwards from usual. Normally, you want to compare a modified local repo to the original code in a remote repo. When you do that, you should specify the repo names in the opposite order:
$ git diff origin/main main
If you get the repos backwards, the output from git diff
can be confusing.
The git diff
command compares all files in the first repo (the local here) with the corresponding files in the second repo (the remote here). The individual differences begin with a line that looks like this:
diff --git a/README.md b/README.md
This shows that we're doing a git diff on the file named README.md
. The file name that begins with a/
comes from the first repo in the git diff
command (the local), while b/
refers to the second repo (the remote).
Next up comes some mysterious output that you can ignore for now:
index 0647d92..56289ec 100644
We now see the following:
--- a/README.md
+++ b/README.md
This indicates that output will use a -
at the beginning of a line that is only present in the a
file (the local repo), and +
shows lines that are only present in the remote. You can think of +
as added lines, and -
as removed lines. If a line is different in both the local and remote repo, you will see both the +
and -
lines in the output. If some lines haven't changed, they will begin with a space character if they are displayed at all.
The next line shows where a specific difference occurred:
@@ -1,0 +2,4 @@
These are a little hard to read, but they represent line numbers in the -
and +
files. In this case, we're looking at one line starting with line 1 from the local repo version of README.md
and 4 lines starting at line 2 from the remote repo version.
Finally, we see the differences:
+
+This is my first GitHub Repository!
+
+Here is some more text.
Here we see the differences as four additional lines from the remote repo, each preceded by a +
indicating a new line.
Reading diffs can be a little difficult at first. With practice, though, you can learn to read them. The most important thing to remember is that +
represents added lines from the repo specified second on the command line, while -
represents deleted lines from the repo specified first.
Once you're sure that you want to pull the changes into your local repo, type:
$ git pull --ff-only
Since the local main
branch has been configured to track the origin/main
branch, you do not have to specify what branch to pull from.
Note that you can also type git pull --ff-only origin main
if you want to specify exactly from which remote repository (using the alias) and which remote branch you want to pull. The commits will be pulled and merged into the current branch you're on in your local repository.
$ git pull --ff-only
Updating 5afaf12..9389be5
Fast-forward
README.md | 4 ++++
1 file changed, 4 insertions(+)
Now if we open our local README.md
file in a text editor, we will see the changes that we made on our remote repo using GitHub's editor.
# README #
This is my first GitHub Repository!
Here is some more text.
Your local repo is now identical to the remote repo, and you can start working on files locally again. You can make changes to the README file, commit the changes and push them to GitHub again.
Some things to note
The --ff-only
part of this command is an option that is passed to the command. This tells git
exactly how we want to try and combine the remote changes with our local branch. In this case it tells git to use a fast-forward merge
to combine the changes (the ff
part). You don't need to understand exactly what this means or how this works, but in simple terms it moves the history of the local branch forwards to match the history fetched from the remote branch. The -only
part of ff-only
means that if git
can't combine the changes with a fast-forward merge
it should abort the merge.
There are other options that you can pass to git pull
in order to combine the changes in different ways, but they are beyond the scope of this book. Until you start working collaboratively and/ or with multiple different branches, git pull --ff-only
should be sufficient for the majority of situations where you need to pull
changes from a remote repository.
If you use git pull
without passing an option such as --ff-only
, git
will decide itself how best to combine the changes. Generally though, it is good practice to be specific about what you want git
to do. Since version 2.26.0
of git
, if you issue a git pull
without an option you will see a message like this:
warning: Pulling without specifying how to reconcile divergent branches is
discouraged. You can squelch this message by running one of the following
commands sometime before your next pull:
git config pull.rebase false # merge (the default strategy)
git config pull.rebase true # rebase
git config pull.ff only # fast-forward only
You can replace "git config" with "git config --global" to set a default
preference for all repositories. You can also pass --rebase, --no-rebase,
or --ff-only on the command line to override the configured default per
invocation.
You can issue a git pull --ff-only
without first using git fetch
and checking the changes using git diff
. You should only do this if you are sure that you want to combine the remote changes with your local branch without needing to check them first.
If you have already issued a git fetch
, you can use git merge --ff-only
rather than git pull --ff-only
. Essentially, git pull --ff-only
combines git fetch
and git merge --ff-only
into one command.
This first review video covers how to use git fetch
and git pull
separately, while the second talks about how you can just use git pull
by itself:
Thus far, we have been talking about connecting an existing remote repository with an existing local repository. But what if we don't have an existing local repository, and just want to pull down all the contents of a remote repository? This is where git clone
comes in. It makes an exact clone of an existing remote repository, and copies it onto your local machine. The cloned local repository will include all the files, commit history, branches, and everything else associated to that git repository.
The git clone
command has several options, but most of the time you will only need its basic usage. Here is what it looks like:
$ git clone <remote repository url> <local directory name>
Here's what it looks like in action:
$ git clone https://github.com/bob/example.git my_amazing_project
Cloning into 'my_amazing_project'...
remote: Counting objects: 218, done.
remote: Total 218 (delta 0), reused 0 (delta 0)
Receiving objects: 100% (218/218), 180.21 KiB | 0 bytes/s, done.
Resolving deltas: 100% (54/54), done.
Checking connectivity... done.
$ ls
my_amazing_project/
In the one command above, several things happened:
my_amazing_project
.
github.com/bob/example.git
were downloaded into the newly created local repository.
origin
. This is the same thing as issuing git remote add origin https://github.com/bob/example.git
from within the local repository directory.
This means that you can now git push
or git pull
from the newly created local repository to/from the remote repository.
git clone
is used mainly when you need to work with a remote repository, and do not yet have a local repository created. For example, if you just joined a new project, the first thing you'd likely do is git clone
the project in order to start working on it locally.
Another common use case is if you want to pull down an open source project. For example, if you wanted to check out the source code for the popular open source web development framework, Ruby on Rails, you can issue this command:
$ git clone https://github.com/rails/rails.git
Notice that we didn't specify a second parameter, the directory name. If you don't specify a directory name, like we did here, then the default behavior is that a new directory will be created with the same name as the cloned repo. In this case, the directory will be called rails
.
After running this command, you should have a directory called rails
, which is a local git repository containing all the code and contents of the official Rails repository. Further, this local repo will have a remote called origin
that points to the official Rails repository. Unfortunately, this doesn't imply you can now push commits to the official Rails codebase. Though you can set it as a remote in your local repo, you still need permission to push to the actual remote repository, which you don't have. You can, however, poke around and make changes to your local repo.
The three commands, git init
, git clone
and git remote add origin <remote repo>
may seem very similar at first, so let's take a look at when you should use them.
Command | When To Use |
---|---|
git init |
Create a new local repository. |
git remote add origin REMOTEURL |
Add an existing remote repo as a remote of existing local repo. |
git clone REMOTEURL |
Pull down contents of existing remote repo into a new local repo, and add a remote to the local repo pointing to remote repo. |
Let's rehash what just happened in this chapter:
git remote add origin REMOTEURL
.
git push
.
git pull
, syncing up our local repo with our remote repo.
git clone
is, and how you would use it to work on an existing git repository.
As you can see from the above steps, working with git requires very detailed orchestration to make sure all repositories -- your local, your teammates', your other machines, and finally the central repo -- are all synchronized.
You may already see that there are many potential problems lurking just around the corner, but don't worry about that yet. You'll learn how to deal with conflicts and work with advanced git workflows over time. For now, just focus on working with git and GitHub on a one-person project.