NOTICE: If at any point reading this guide you want to skip a section that you are already familiar with, click the hamburger menu at the top left of this file preceding the title and to the left of the filename, see example below
Git allows different people in different locations to contribute to a project in a centralized location. The project is usually stored on a website, and a tool known as git
can modify it. This tool also preserves project history, so every version of the project is accessible at any time.
A programmer generally refers to these project "versions" as commits. You can always revert to a previous commit if you make a mistake and lose your progress.
The programmer commits to a branch. Think of branches as a slightly different version of the project. For example, you might want to have a stable
branch that gets updated infrequently to have a stable version of the code. A programmer can use a testing
branch to test and implement new features.
The commits in the image contain messages informing the team about the purpose of that commit. While commit messages aren't required, it's considered bad practice to leave them out.
Now that you have a basic understanding of what Git's, the following parts explain the setup process.
NOTICE: If you are using a Windows computer you may need to configure Windows Subsystem for Linux to follow the rest of the guide from here on. You should be able to run wsl --install
from PowerShell as an administrator (https://learn.microsoft.com/en-us/windows/wsl/install).
You can use git
through a command line interface. This means that you'll be utilizing git through a terminal emulator or terminal on your computer. This is an interactive prompt that allows you to type commands in the bash language to execute. An example of a terminal command that commits to the current working branch looks like this:
$ git commit --message 'Added methods for telemetry'
The $
indicates the start of the line for the user to enter a command. It's not typed by the user but it'll exist on its own line in the terminal emulator by default. If the line is blank, then your terminal emulator is already executing a task and not ready for user input.
The command itself is then entered: git
. Since the git
command takes one required argument, it's then followed by the phrase: commit
. In other words, you are telling the terminal that you would like to make a new git commit. Now you can finish the command by hitting the enter key and you have made a git commit. However, as stated prior, it's good practice to include an optional message describing the purpose of the commit.
Next are the optional arguments or options. You can choose a specific option by starting with a --
followed by one or more words. In this case, --message
tells the git commit
to include a message. If there is an option with multiple words it'll probably look something like this: --option-with-multiple-words
.
Since the user separates arguments by a space in bash, the message argument must start and end with a single quote mark or it only considers the first word in the message. i.e:
$ git commit -m Added methods for telemetry
      Incorrect
$ git commit -m 'Added methods for telemetry'
 Correct
Feel free to follow along in your own computer's terminal emulator during this section.
The following paragraphs explain how to access a bash shell from your operating system. A shell runs inside of your terminal emulator and is what you interface with when typing out commands.
On a Windows computer you can search for "PowerShell" without running as administrator, and type wsl
followed by the enter key. If the command hangs or isn't found, that means you haven't set up the Windows Subsystem for Linux correctly and you must go back to the previous step to try again.
On MacOS search for the "terminal" app. On Windows search for the "Ubuntu" app. On Ubuntu search for the "terminal" app.
When you first open your terminal emulator, there might be a message at the top. Below that message you should see your computer's username followed by a special symbol, usually a dollar sign. In my case, it looks like this:
eli@laptop$
Depending on what operating system you are using, this might look a bit different than the example, e.g: a %
symbol for MacOS. You may start typing your commands after the $
, %
, >
or whatever other symbol is present. This is the indicator that lets you know the shell has finished executing its previous process and is ready for more input. If there is no symbol present then the terminal is currently executing a previous command and isn't ready for you to type input.
I'll now be using the $
delimiter to mark the beginning of a line of input for the rest of this guide. It should appear automatically. You'll see a $
after your username and this is where you can start typing your command. If you don't see a $
, then that line is the output of the command. Don't get confused when you see a slightly different output. I.e: the example says "eli" because that's my username. The first command to type is pwd
:
$ pwd
/home/eli
The second line of this example isn't prefixed with a $
symbol as it's the output of the previous command and isn't typed out by the user.
This command prints the current working directory. You are basically telling your bash shell to print folder on your computer that you are running commands inside of.
If you would like to see the folders and files that are inside of your current folder, you can list them with ls
.
$ ls
Desktop Documents Downloads Git-Guide.txt Music Pictures Public Videos
Note that this command lists everything in the current directory, including files. Your terminal might show the directories in bold, or they might be a different color to separate them from the files.
Now that you are aware of the folders inside (I'll call them subdirectories from now on) use cd
to change directories. This command takes a single argument unlike ls
; you need to type the name of the directory to change to (case sensitive).
$ cd Downloads
$ pwd
/home/eli/Downloads
$ ls
File.txt Minecraft.jar Movie.mp4 Song.mp3 Virus.sh
You now know how to move around in the terminal.
If you would like to exit the terminal, type: exit
.
If you have taken a Computer Science class prior to reading this guide, then you may remember asymmetric encryption.
If you don't, I'll provide a simple example. Start by generating a key pair: two keys that are mathematically linked. A key consists of randomly generated symbols and letters that would be difficult to guess. One key is public and everyone can access it. The other is private and you shouldn't distribute it.
If a peer wants to send a message to a programmer, they can encrypt it with the programmer's public key. Now, the message is gibberish and makes no sense to anyone. This means if someone with mal-intent were to intercept this message, it would be of no use to them.
The programmer can then decrypt the encrypted message with their own private key. Therefore, only the programmer understands message, and nobody else can interpret it. Anything that's encrypted with the public key can only be decrypted with the private key and vice-versa.
You may ask what the use is of encrypting something with the programmer's private key, if everyone can just decrypt it with their public key. You are correct in that it doesn't work to obfuscate the message. However, it can be used as a digital signature.
If everyone can decrypt the message with the programmer's public key, that means they must have encrypted it with their own private key. In other words, no one can falsely claim that they're the programmer because they don't have the programmer's private key and therefore can't sign their messages under the programmer's name.
In other words you'll need SSH for two reasons:
-
You are going to be signing your commits so everyone can verify that you are the one who made them.
-
If you are working on a private repository, meaning only authorized users can see your code, you'll need an SSH key pair to do this.
DISCLAIMER: the private key is private and stays on your computer. Don't share your private key ever, not even between devices that you own. If you need to work on a repository with another device, you must generate a new key pair.
A repository is a cloud location that stores your projects and tracks their history. You'll be working with repositories using git as an interface to contribute and collaborate.
Open the terminal and type cd ~
, (~
is an alias for "home" and in my case really translates to "/home/eli"), although you proabably are already in the home directory (you will know if you run pwd
).
Now that you are home you should type ls --all
which will list all files and folders (hence --all
). When you use the option --all
, 0 arguments will follow. Once again, most command-line options also have a shorter, one letter counterpart. They are usually preceeded by a single -
in their one letter form: ls -a
. These options are functionally equiavalent. If you would like to see more options for a specific command, such as ls
, you can follow it with a --help
or -h
option. If you already see a directory named .ssh
(after executing ls --all
), skip the next step.
If you do not see a .ssh
directory, enter the command mkdir .ssh
. This makes a directory under your current working directory called .ssh
. Now you should run ls -a
and see a directory named .ssh
in the list of files and folders.
Now that everyone has an empty .ssh
directory, you will need to generate an ssh keypair. To do this you will need to enter the following command, replacing the text in "<filename>" with a name of your choice without spaces and <your_email_address> with your actual email address:
$ ssh-keygen -a 100 -t ed25519 -f ~/.ssh/<filename> -C <your_email_address>
-a
is an option that specifies the number of rounds of KDF (key derivation function) to be used. A higher number of rounds means the random strings are more secure; 100 is plenty. -t
allows you to pick the type of function used to generate the keypair. We are using ed25519 because it's secure, convenient, and fast. -f
lets you pick where to store the keypair and -C
allows you to type out the email address that you will be identified with.
If you are prompted to enter a password, you can, or just leave it blank (it doesn't really matter which one you choose). However, if you are using a shared device I HIGHLY suggest you use a strong password.
Now you have files in the .ssh directory named <filename>
and <filename>.pub
. The key ending in .pub
is your public key, the other (no extension) is your private and STAYS ON YOUR COMPUTER.
We have to then tell Git to use your keypair. You should now create a file in .ssh
directory and name it config
. Not config.txt
. If you want to know how to do this from the terminal just do this:
$ cd ~/.ssh
$ pwd
/home/eli/.ssh
$ ls
<filename> <filename>.pub
$ touch config
$ ls
config <filename> <filename>.pub
Of course you don't have to type ls
but it's nice to know that you have successfully followed the guide thus far. Now you can edit the config
file in your favorite text editor of choice, a good option is VSCode if you are not sure or haven't used one before.
The following config file is an example that you should follow. You may not have a Github account yet so you can leave that part blank for now, but make sure that you come back to the config file to input your username where stated in the example.
# ~/.ssh/config
# Primary Github account
Host github-<Github Account Username>
HostName ssh.github.com
Port 443
IdentityFile ~/.ssh/<filename>
IdentitiesOnly yes
The lines preceeded with a #
are comments to help you remember the purpose of this file and not required. Basically this tells Git to use our <filename>
and <filename>.pub
keypair when connecting to github.com. Just make sure to replace all instances of "github.com" with "github-<Github Account Username>" when using a url with the former in it.
For example, instead of "git@github.com:ElijaRock/git-guide.git", I would change the url to "git@github-ElijaRock:ElijaRock/git-guide.git". You will need to do this for your username that you setup in the config file in the future. Don't worry about the semantics yet as they will be explained in the next parts of this guide.
Throughout this guide I have mentioned git
many times and now I am talking about Github. What's the difference? Well, git
is the tool that you use to interface with repositories on the Github website, which is a cloud service that allows you to store many repositories.
TLDR: git
is the tool you work with; the results of using git
are seen on the Github website.
Visit https://github.com/ and create an account with your preferred email address, etc. Choose your preferred username, eg: "first-lastname", and you are good to go.
Click on your profile picture on Github and press settings.
Then, on the left, find SSH and GPG Keys
, click on it.
Press New SSH Key
and title it whatever you want.
Key type: Authentication Key
. Paste in the file contents of your public key (located in your .ssh
folder): <filename>.pub
. After doing this, we will repeat these steps but instead choose Signing Key.
In total you will have added two keys. An authentication key is used if you are working on a private repository. This means that the people who created the repository only want specific trusted people to be able to view it, meaning you will need this key to gain access to the repository.
The signing key is used to sign your commits. This means that everyone knows you are the person who made the commit and not somebody posing as you. Now you can test your keypair like so (replacing <Github Account Username> with your actual Github account username):
$ ssh -T git@github-<Github Account Username>
Hi <Github Account Username>! You've successfully authenticated, but GitHub does not provide shell access.
Success! If you have not yet changed your ~/.ssh/config
file to include your actual github username, please do so now.
You may get a prompt about a fingerprint and it will ask you to input yes or no. Double check that it says SHA256:+DiY3wvvV6TuJJhbpZisF/zLDA0zPMSvHdkr4UvCOqU
, then type yes (this is the Github website's public key fingerprint). If it does not show the correct fingerprint, then you are not connecting to github.com
and something has gone wrong.
Depending on which operating system you use, there may or may not be a package manager installed by default. A package manager does all the heavy work for you, preventing the need to search for applications on the internet.
On Ubuntu and WSL (Windows) systems, a package manager apt
is included by default. On MacOS, you will need to install brew
by following the steps on the brew homepage.
Once you have a package manager, you can then install git
with the following command (depending on your operating system):
For Ubuntu and Windows users: $ sudo apt install git
For MacOS Users: $ brew install git
Aptitude (apt) requires that you have elevated permissions when installing packages, which requires you to preceed it with the sudo
command ("Superuser Do") and enter your password to confirm. You may need access to an administrator account on your computer to execute some of these commands.
It's time to clone your first repository (repo). Cloning allows you to have a local copy of the code from a repository on your machine. Essentially you are "downloading" the code.
Open terminal and cd
into a directory of your choice. Then, go to the top of the page on a Github repo that you would like to work on (if you don't have one you can create it yourself) and click on the <> Code
green button, then click ssh and copy the link.
Now you have to change the link. In my case, I am working on the "git-guide" repo and my username is "ElijaRock", therefore it looks like this: [email protected]:ElijaRock/git-guide.git
. You should change it to look like the following: git@github-ElijaRock:ElijaRock/git-guide.git
. I have changed the part that says "github.com" to "github-ElijaRock". This allows us to use our authentication key to gain access to the (private) repository. This is not necessary for a public repository but is still good practice.
Now you can type this into your terminal (replacing my Github username with yours):
$ git clone git@github-ElijaRock:ElijaRock/git-guide.git
$ ls
git-guide
$ cd git-guide
Now I am in the "git-guide" directory.
You must now tell git some information so it can properly identify you (you need to be inside of the cloned repo to do this):
$ git config user.name '<your name>'
$ git config user.email '<your email address>'
$ git config gpg.format ssh
$ git config user.signingkey ~/.ssh/<filename>.pub
Replace "<your name>" with your name, "<your email address>" with your email address, and "<filename>" with the name of your keypair. Make sure you are using the key ending in ".pub" (your public key).
You are now working in your cloned repo, on the main
branch. NEVER commit to or push to the main branch directly. We want to protect the stability of the main branch.
You can see which branch you are working on using git status
. It should say something like "On branch main" at the top, along with other information I'll explain later.
You should create another branch if there is only branch main.
The first line creates a new branch called new-feature
. You can call your new branch whatever you like, but there cannot be spaces (use the -
instead). The second line switches from the main
branch to the new-feature
branch so you can start working on it without changing main
.
$ git branch new-feature
$ git checkout new-feature
If you run git status
again, this time it should say "On branch new-feature" since in the use case above, that's what I called my new branch. If you call your new branch something else, that name should appear.
If you would like to see a list of the existing branches at any time you can run git branch
.
You can start working/coding inside of your branch.
If you want to see the changes you have made thus far type: git diff
and it will highlight the differences between the original code and modified version.
Now you must track and/or stage, then commit the changes you have made to a repo. Files need to be tracked so that Git will see them. You track new files, but if you modify a file that is already tracked, what you are doing is called staging. Although these are two different names, you only have to run one command for either tracking and/or staging.
By default, any new files you create in the branch are untracked. That means that if you make a commit they will not show up and only stay on your machine. To track and stage a new file, you can type git add <filename>
, followed by the actual file name. This can get tedious if you are adding a lot of new files, so you can also type git add --all
which will track and stage the new files you have added.
There may also be some files on your computer that are already tracked. These need to be staged if you have made any modifications to them. In addition to tracking the newly created files, git add <filename>
or git add --all
commands can be used to stage the existing, modified ones.
After you have tracked and staged your changes, you might be interested to see what the repo will look like before you commit. You can compare the branch on your computer with the one on the Github website by doing the following (change new-feature
to the name of your branch).
git diff new-feature origin/new-feature
In this command, "origin" is shorthand for the url of the Github repo. In other words you are telling git
to look at what is on the website and then compare it with what is on your computer. If it shows differences, that means you have properly staged your changes.
You can now commit to the repo. The -S
option for the commit will sign it with your signing key. Then, type -m
option to create a title for the commit. You should describe what you have changed in a few words here. If needed, you should use another -m
option to provide a longer description of what you have done.
As noted in the example below, messages need to be enclosed in single quotes:
$ git commit -S -m 'This is a short message describing the changes I have made' -m 'This is a longer, more thorough description of the changes made'
You can ommit the second -m
or "message" option if you have only made small, incremental changes. The -S
option allows you to sign the commit with your signing key, in other words we can verify that YOU made these changes (in the case of identity theft). That is why it's so important to not give your private key to anyone ever.
The last step is to push the commit to the branch you are working on. Now that the commit's on your computer and everything is as you like it, you can update it to the repository online through a git push
command. This will show the commit on github.com website and everyone else will be able to see it. Type (remember to replace new-feature
with your branch name):
$ git push origin new-feature
This pushes it to the branch that you specified and now we all will be able to see the changes on the website.
Now visit the repository on github.com, go to the top left where is says you are on the main branch, and switch to new-feature
branch. The checkmark will move from main
to new-feature
.
The website will refresh automatically and you should click on the x commits
. x=the number of commits that have been made. It will be located below the code
button you found earlier.
You should now be able to see a list of commits including your own. If you have set up your ssh key correctly there will be a green Verified
bubble on the right side of your commit. At the top left of the image, you can see that I am on the main branch; however, you should be on your new branch.
If you feel that your branch has been extensively tested and is stable, you are ready to merge it back into the main
branch.
Go to the Pull Requests
tab at the top bar of the repository page, and choose New Pull Request
.
At the top it will allow you to select the new-feature
branch to be merged into main
(see below). In my case, there is only one branch: main
but yours will say "compare: new-feature to base: main" if your branch name is new-feature
.
Then provide a description of the changes you have made and submit the request. Some repositories require that at least one other person (usually a specialized contributor) review the code in your request before giving the OK. Then, they can accept the request so your branch can be merged into main. Congrats!
You may have also noticed an Issues
tab on the repo page to the left of "pull requests". You should open an issue for any problems or inaccuracies that you find in this guide.
So essentially the workflow is that there can be an issue
opened for a new feature or a bug. Then, someone creates a new branch to work on the issue. Once that branch has been tested and is ready, a pull request can be submitted to merge that branch back into main
. In the pull request, you will specify the issues that it fixes in order to close them.
Suppose someone on your team worked on your branch while you were gone to help implement the feature. Before you start making changes on your computer again, you need to fetch their changes so you have the modified files. Do this by running the following command:
$ git fetch origin new-feature
Now you have their changes to compare to the branch on your computer, and need to review them before replacing the files on your computer with the new ones from the repo online.
If you want to see the difference between the new-feature
branch on your computer and the repository's up-to-date new-feature
branch, run this command:
$ git diff new-feature origin/new-feature
You are now looking at the changes your team member made to your branch compared to the one you had from before. If you like these changes, you can replace the current copy of the branch on your computer with the new version. This is called "rebasing". You can do the following:
$ git rebase origin/new-feature
You may get an error that you need to stash your changes before a rebase. This happens if you made changes and forgot to commit them. Git allows you to keep your changes in a special safe place called "stash" while having the latest version of the branch to work on.
$ git stash
You may then run rebase
again and you will be on the most up to date version of new-feature
branch. But your uncommitted changes will be missing (temporarily). If you would then like to reapply your changes to this latest version of the branch, run the following command:
$ git stash apply
Your changes have safely been restored and you can get rid of the stash:
$ git stash drop
Now I am on the latest version of the branch new-feature
and can track and commit my changes as usual. Git forces you to do this because it would be impossible to have your commit and your peer's commit to be "next to each other" at the same time on the same branch. Essentially what you just did is moved your changes from "next to" the peer's commit to after their commit, creating a linear branch history (think of the image at the beginning of this guide). If this is confusing at first, do not worry, the more you use git
the more you will understand over time.
I'll remind you again that you only need to clone the repo once; always use fetch to grab the newest changes. Also, git
has many many more features than specified here and can be used to do even more powerful things.
Now that you have the background knowledge, I'll let you know of some best practices that I learned in the time that I have used git.
-
If ever in doubt run
git status
. This will give you valuable information on the current state of the git repo on your computer, changes you have made, etc. -
Do not make changes to the main branch. The code on this branch is stable, tested, and reliable.
-
Do not force push other people's code off the repo. As annoying as it may be to deal with merge conflicts (you'll experience these at some point), do not force push your own code. Make sure to fetch and rebase to resolve the conflicts instead.
-
Write detailed commit messages. Make it obvious what your commit does to change the code (don't add a meaningless message).
-
Use the built-in issues feature. Get in the habit of submitting proper bug reports as an issue and document what you did and what didn't work. You can also use a
feature-request
tag on your issue to request a new feature, which can later be closed in the pull request that fixes the issue. -
Read the docs. I have gathered almost all of my information from the official Github documentation. If you are ever unsure or would like to know about more powerful features, try reading the documentation first.