Git Tutorial and Reference (not only for Beginners)
Today, almost no software project is possible without a version control system. The most popular software for this purpose is Git. This tutorial is my try to teach you how to use Git for your own work. It is also a reference you can use in your daily routine with Git. This tutorial is not complete yet and will be updated regularly, even if I find out something interesting or new about Git that you should know.
What is Git?
Git is a distributed version control software, which helps you to track changes in any type of file, mostly used for source code and software development. It was originally developed in 2005 by Linus Torvalds, the creator of the Linux Kernel. Unlike other version control systems, like Subversion or CVS, Git has a distributed architecture, which means every local Git copy is also a full repository with a complete history of changes. Git is also the best choice in terms of performance and security, which is reflected in a market share of 93.9% in 2022.
Why use Git?
During software development, tracking changes and collaborating on the code with others is very important. Without a version control system, it would be very hard to see what has changed in the code, work on multiple versions, revert changes or work with others. So a version control system is a must-have when developing software.
While Git is the most popular version control software it also has the most and best tools which makes it easy to use in all environments.
How is it Working?
Every project you control with Git is called a repository and acts like a database. You can imagine it like this: First, Git has a database that stores all files and folders in a directory. Second, Git also stores the changes made to any type of file and folder in this directory with a complete history in so-called Commits. A Commit is a set of changes that represents a snapshot of your repository at a point in time.
Furthermore, you can have different versions of your working copy with a separate set of commits. This is called branches. The main branch is called "master", "main" or "trunk" and is often used as the current status of your production environment.
The local database and all pieces of information about files, commits, branches, and configurations related to your local Git repository are stored inside the .git
subfolder located in the top directory of your project.
To work with other people or to collaborate on projects using Git, a copy of the repository must be hosted on a server connected to the internet or any local network. You can do this on a self-hosted machine or use a service like GitHub, Bitbucket or GitLab.
Installation
The best way to learn Git is the command line version. You have to type in the commands to use and execute Git. There are many good graphical user interfaces for Git, but in this tutorial, i will focus on the command line.
First, we will check if you have Git already installed. To do so, please open the Command Prompt (or PowerShell) in Windows or the Terminal in macOS and type the following command:
git --version
If Git is installed on your system, you should see something like:
git version 2.38.1
In case of an error, you should see a message like "command not found" or something else. Then you should install Git with one of the following options.
If you are on a Mac and Git is not installed, you will be prompted to install the Xcode Command Line Tools, which includes Git. You can go for it or look below.
Installation on Windows
There are several ways to install Git on Windows. The most popular is to use the build provided by the official Git website. You can download the installer here: https://git-scm.com/download/win. The download should start as soon as you open the page.
Another option is to use the installer from a project called Git for Windows: https://gitforwindows.org/.
After the download just execute the installer and follow the provided instructions.
Installation on Mac OS
In macOS, you also have multiple ways to install Git. The first is to install the Xcode Command Line Tools directly from Apple. Perhaps you have been already prompted to installation by the git command above. If not, you can manually install the Xcode Command Line Tools by typing the following command in the Terminal:
xcode-select –install
The Xcode Command Line Tools are command line tools for software development. Besides Git they include tools like Make, Compilers and many other dev-related tools. The installer file size is around 1.2GB. If this is too much for you, you can go with the next option.
The other option to install Git on a Mac is to use the official installer from Git. This version is more up-to-date and can be downloaded from the Git website: https://git-scm.com/download/mac.
When the download is finished, just execute the binary and follow the provided instructions.
Installation on Linux
Installation of Git on Linux is even simpler. Just use your favorite package manager provided by your installed Linux distribution. If you are on a Debian-based distribution like Ubuntu or Debian itself, just use the following command on your shell for installation:
sudo apt-get install git-all
If you are using Fedora, RHEL or CentOS, use one of the following commands in your shell:
sudo yum install git-all
sudo dnf install git-all
Configuration
If you have successfully installed Git on your machine, you can now start using it by configuring and customizing your Git environment.
Before you can commit any changes you have to provide your personal information like your name and email address. This information is used in every commit and is therefore very important. Now, let's tell Git who you are by typing the following commands:
git config --global user.name "Your Name"git config --global user.email your@emailaddress.com
Let's break this down.
git config
tells Git that you want to set configuration options--global
means, that these options should be set for all repositories on this machineuser.name
oruser.email
selects the name of the option"Your Name"
oryour@emailaddress.com
sets the value which should be set for this option
You can view the value of any option with the command git config
followed by the name of the option:
git config user.name
For a list of all settings you can use the following command:
git config --list --show-origin
Clone a Git repository
To copy an existing Git repository to your local machine you can use the git clone
command. Repositories can be cloned from an remote server or local folder.
Cloning a remote repository, can be done using the following command:
git clone user@hostname:path/to/repository
Before you can do that, you need to be authenticated to the server. This is mostly done via HTTP Authentication or SSH and an SSH key. More on this here.
In most situations, you can simply follow the authentication instructions from your repo provider.
So let's clone a Git repository. Here is an example for GitHub with SSH:
git clone git@github.com:vercel/next.js.git
This will create a folder next.js (without the .git extension) with a full copy of the target repository. You can now cd next.js
and make changes.
A clone via HTTPS is also possible:
git clone https://github.com/vercel/next.js.git
If you like to clone a local repository you just have to provide the local path:
git clone /path/to/repository
Set up a Git repository
If you like to start from scratch, you can create a Git repository from every folder that is not under version control, no matter if it is an existing or new project.
For a new project, you have to create a directory for this project first:
mkdir myproject
With an existing project including files and folders or the previously newly created folder, now let's change to this directory with the cd command:
cd myproject
.. and initialize the new repository:
git init
The command will create a subfolder .git
with all necessary files for this repository.
🥳 Congratulations! You have created your first Git repository! But hold on, before your project is under version control, you have to add some files first.
Adding files
Before you can track files and the history of their changes you have to add these files to the repository. You can do this using the git add
command.
The git add
command marks (or stages) changes for the next commit. It has to be used when adding new files or preparing changed files for the next commit.
In case of a new project or if you don't have a README file, let's add one first. The README file should be in markdown format and contain information and documentation about the repo. In GitHub, it will be shown on the front page of the repository. You can use your favorite editor to create the README or use the following command:
echo "# My new Git repo" >> README.md
Now let's add this file to the repo. All you have to do is use the git add
command followed by the filename.
git add README.md
You can also add complete folders:
git add folder
It's also possible to add multiple files or folders:
git add file1.js file2.js folder folder2/subfolder
To add all changes and new files you can use:
git add .
The dot means the current directory. But don't worry: Git will add only new and changed files. Existing won't be added twice, they just will be ignored.
If you like to add also deleted files, you can use the command line option -A
or --all
.
git add -A
It will prepare all new, changed and deleted files to be staged for the next commit.
Status
To view the current state of your working copy, use the git status
command. It will display all paths (files and folders) that have differences between the last commit and your current working copy including changes and untracked files. The list is divided into changes that have not yet been staged or already staged for commit. Additionally, it shows the current branch and any differences to the remote branch, if your repo is linked to any.
git status
It sould display something like:
On branch mainYour branch is up to date with 'origin/main'.Changes not staged for commit:(use "git add <file>..." to update what will be committed)(use "git restore <file>..." to discard changes in working directory)modified: _posts/git-tutorial-reference.mdmodified: components/CodeSnippet.jsmodified: components/Post.jsmodified: components/SignupForm.jsmodified: components/TableOfContents.jsmodified: helpers/syntax-theme.jsUntracked files:(use "git add <file>..." to include in what will be committed)components/MyComponent.jsno changes added to commit (use "git add" and/or "git commit -a")
You can also output a short version with the -s
option.
git status -s
The Git status command is very important. You should always use it before committing any changes or if you're in doubt. To see detailed changes in the file contents, you can use git diff
, which we'll cover in the next chapter.
Diff
Commit
Every time you've made a logical set of changes to your code, you should do a git commit
.
A commit is like a snapshot of your repository at a specific point in time. It includes all changes made to your working copy as well as some meta information like a commit message, the author and the timestamp.
Unlike other version control systems, a Git commit is committed to the local repository and needs absolutely no connection to a remote repository. Git will create a unique SHA hash as an identifier for every commit, which can later be used to checkout the repository at exactly this commit and moment.
With every commit, you need to supply a commit message. This message should describe your set of changes and what you have done in a short form. It's very helpful for you and even more important when collaborating with a team. A good commit message should be well-readable and between 50 and 72 chars long.
git commit -m "Updated README file with the new API specification."
It's also possible to automatically add all changes before committing. This can be done with option -a
and will only affect modifications in already tracked files. New files will not be added.
git commit -a -m "Added new favicon with the updated logo."
If you've made a mistake in the commit message or like to add additional files to the last commit, you can do this with the option --amend
.
This acts like a merge of the last and the current commit you make. The last commit will be replaced, so you shouldn't do this with public commits already in production.
Per default, the commit message will be replaced and should be added with the -m`` option. If you only want to add files, you can use the
--no-edit` option and the commit message will not be replaced.
Examples:
git add public/touch-icon-iphone.pnggit commit --amend -m "Added new icons for updated logo." # Commit message will be replaced
git add public/favicon2.pnggit commit --amend --no-edit # Commit message will NOT be replaced
Branches
Branches are a very important and powerful tool in Git. Each branch acts as a separate version of your working copy including all changes, starting at a specific point in time. While every repository has one main branch which starts at the very beginning, any other branch you create will have a reference to a specific commit in your main branch.
When you create a new branch, you can think of it as an isolated version. You can make changes, add or delete files and create commits without affecting the main branch. Once you're done and happy with your changes, you can merge them into the main branch. The main branch will then include all commits and changes you've made to your custom branch.
The default main branch in Git is called "master", but you can rename it to main or any other name as well. "main" is recently more often used. So we go with that in this tutorial.
Create a branch
There are two common ways to create a new branch in Git. You can create a new branch and directly switch to that new branch and start working, or you can just create a new branch while staying at the current branch. While the first method makes sense in most situations, we will start with that.
Before you create and check out a new branch you should check if you have any current changes with git status
.
If you don't like to include these changes in the new commit, do a git commit
first. Otherwise, you can add these changes in the new branch.
Just create the new branch as described below and add your changes for the next commit.
To create and checkout a new branch, you can use the git checkout
command with the -b
option followed by the name of the new branch:
git checkout -b branchname
The name of the branch should be unique, short and describe what you are doing. Good and useful names are wip
, bugfix
, feature name
or test
. You can also use group tokens separated by a /
.
git checkout -b group/bugfix
If you just want to create a branch, you can use the git branch
command:
git branch branchname
List branches
To view a list of your local branches you can just use the git branch
command.
git branch
For a list that also include remote branches, add the option -a
:
git branch -a
If you only want to show remote branches, use -r
.
git branch -r
There is also a possibility to view a list including the last commit message:
git show-branch
You can also use the options -a
and -r
here.
Switch branch
When you like to switch between branches, you can do this with the git checkout
command, followed by the branch name:
git checkout branchname
Your working copy will be updated to the current state (commit) of this branch. All following commits will be added to this branch too.
Example: You are working an a new feature, an image editor. The current branch is image_editor. A customer reports a bug which needs a urgent quick fix in the main branch, which is used in production. So you checkout the main branch:
git checkout main
Then you fix the bug, commit the changes and deploy the code to production. To work again on the image editor, check out the image_editor branch:
git checkout image_editor
Tip: It is not always a good idea to fix bugs in a main branch, which is used in production. If you can estimate it's taking longer, create a new branch or switch to a bug fix branch.
From time to time (better often) you should also merge the main branch into your working branch. More on this in the next chapter.
Merge branches
Your work is done, be it a bug fix or a new feature, and now you like to integrate your work into the main branch. This is what git merge
does. It merges the set of commits from one branch to another and creates a merge commit.
You can merge any branches, that have the same origin branch. Git will try to find the best possibility to merge the two branches.
The branch you want to merge your other branch in must be checked out. But before doing that, you should check if all changes are added and committed using git status
. If it looks good, just try to merge the main branch into the current branch.
git merge main
Why we are doing that? It could be that the main branch has changes that your current branch doesn't know. Then Git has to merge three different branches: the main branch, your current branch, and the changed main branch. This is called the three-way merge and often leads to conflicts, which can't be automatically resolved. It's better that your current branch is not behind the main branch and Git can do a fast-forward merge. So it's always a good idea to merge the main branch often into your working branch.
Now we can check out the main branch and merge your branch into the main branch.
git checkout maingit merge feature
When the merge is successful, Git has merged the commits into the main branch. Otherwise, the merge has failed and you have to fix the conflicts.
For the summary, a typical workflow will look like this:
$ git checkout -b feature/videoSwitched to a new branch 'feature/video'$ git add components/Video.js$ git commit -a -m "Added video component for embedding videos from YouTube and Vimeo"[feature/video 499f387] Added video component for embedding videos from YouTube and Vimeo1 file changed, 248 insertions(+), 0 deletions(-)create mode 100644 components/Video.js$ git checkout mainSwitched to branch 'main'$ git merge feature/videoUpdating 7dd9d5d..499f387Fast-forwardcomponents/Video.js | 01 file changed, 248 insertions(+), 0 deletions(-)create mode 100644 components/Video.js
Resolving conflicts
When you like to merge branches and Git is not able to automatically merge the changes between these branches, because changes are made to the same line(s) of a file or one will delete the file and the other will edit it, then you need to resolve those conflicts manually. Git will pause the current merge and marks any files with problems as conflicted.
Resolving conflicts in Git consists of four steps:
1. Checking the status with git status
Use the git status
command to see which files have conflicts. It lists each file with a conflict and suggests your next steps.
Let's take a simple example. We have a file README with current changes on the same line in our main branch and our branch test/conflict. Therefore the last merge failed and git status
will show the following:
$ git statusOn branch mainYou have unmerged paths.(fix conflicts and run "git commit")(use "git merge --abort" to abort the merge)Unmerged paths:(use "git add <file>..." to mark resolution)both modified: README.mdno changes added to commit (use "git add" and/or "git commit -a")
Here the both modified: README.md
means, that two different commits in the involved branches have changes in the same file README.md. Let's look at the file:
$ cat README.md# Git test repository<<<<<<< HEADMy new Git repo is a nice place=======My new Git repo and this will produce a confict>>>>>>> test/conflictJust another line in README.
The line between <<<<<<< HEAD
and =======
represents the changes made in our HEAD (latest commit) of the main branch and the part between =======
and >>>>>>> test/conflict
is the change made in our branch "test/conflict" - both on the same line.
In bigger files or when having multiple conflicts, you can search the file for the marker <<<<<<<
, representing the start of a Git merge conflict.
2. Editing the files and resolving conflicts
Now you need to decide what change you want to make. You need to replace the complete part starting with <<<<<<< HEAD
and ending with >>>>>>> test/conflict
. In the example above we will keep the change in the head: "My new Git repo is a nice place". We use our favorite editor and replace the lines just mentioned.
$ cat README.md# Git test repositoryMy new Git repo is a nice placeJust another line in README.
3. Adding the files with git add
for the next commit
After editing the file and manually resolving all conflicts, you have to add this file to the next commit. This also will mark the conflicts as resolved.
$ git add README.md
Do the same (editing and adding) with all files that have conflicts.
4. Commit the merge
Once you've resolved all the conflicts, all you have to do is commit them. Git will prepare a Git message for you with a list of all conflicts. This is a nice feature for later reference and documentation. To use the message you can omit the -m
option.
$ git commit
If you like to use your own Git commit message and replace the one provided by Git, just use the -m
option as usual.
$ git commit -a -m "Git merge with resolved conflicts in README.md"
Remote repositories
Learn to let go. Remotely to connect you have. 🤩
When you want to share your code, collaborate on it with others, or even when you want to make a backup of your code, you have to store your repository on a remote machine.
This is where Git Remote comes into play. A remote Git repository is hosted on a server on the internet or a machine in your local network and works like the .git
folder in your local copy.
You can think of it as a full copy of your local repository. It includes the initial files, commits, branches, and information about the repository.
A local repository can have multiple remote repositories. Each remote repo is identified by a name and can have different states. You can connect to remote repositories with the following protocols:
-
HTTP. Your connection to the remote repo will be made using the HTTP protocol, which is also used by every browser. A typical URL will look like the following:
https://hostname/path/to/repository.git
-
SSH (Secure Shell). The connection is made with your local SSH client and you will be connected to the remote machine in the same way as if you were using ssh. An SSH Git URL will look like this:
username@hostname:/path/to/repository.git
-
Git. The Git protocol comes with absolutely no authentication and is therefore rarely used. Although it is the fastest protocol, it is not recommended due to the low level of security. A URL will look like this:
git://hostname/path/to/repository.git
To manage your remotes you can use the git remote
command. It can be used to view, add, update, or delete remotes.
List remotes
For a list of the remotes use the git remote
command without any argument. If you like to view the URL's for each remote, just add the -v
option:
git remote -v
Add a remote
To add a Git remote, just use git remote add
in the following format:
git remote add <name> <url>
<name>
is the name of the remote. <url> the URL of the remote repo:
git remote add origin username@hostname:/path/to/repository.git
Rename a remote
You can rename a Git remote using the following command:
git remote rename <old_name> <new_name>
Remove a remote
You can remove the entry of the Git remote using the rm
argument. Note, that only the link to the remote will be removed, not the remote repo itself.
git remote rm <name>
Syncing remotes
Keeping your local repository in sync with a remote can be done with the git fetch
, git pull
and git push
commands.
git fetch
will download all data from the remote repository that you don't already have.
git pull
downloads all data from the remote repository for your current branch.
git push
will upload all your data, that he remote that you don't already have.
git remote rm <name>
Quick reference
Init repo
If you know what you are doing, you can use the following commands to quickly create a new Git repository.
cd myprojectgit initecho "# My new Git repo" >> README.mdgit add .git commit -m "first commit"git branch -M main
Make a private fork
Create a new repo (let's call it private-repo) via the Github UI. Then:
git clone --bare https://github.com/exampleuser/public-repo.gitcd public-repo.gitgit push --mirror https://github.com/yourname/private-repo.gitcd ..rm -rf public-repo.git
To pull new hotness from the public repo:
cd private-repogit remote add public https://github.com/exampleuser/public-repo.gitgit pull public master # Creates a merge commitgit push origin masterrm -rf public-repo.git
Awesome, your private repo now has the latest code from the public repo plus your changes.
Further Information
Enjoyed this post?
My goal with this blog is to help people to get started with developing wonderful software while doing business and make a living from it.
Subscribe here to get my latest content by email.
I won't send you spam. You can unsubscribe at any time.