Git¶
Git is a version control system. Software engineers use Git for managing source code in collaboration with team members.
Git allows us to…
keep file version histories.
access past versions.
save all versions on remote hosts.
share a source code directory (repository) with others.
For instance, if you go to GitHub (a Git repository hosting service), you can find a lot of source code written by developers, and you can download them using Git.
Note
This year, it won’t be mandatory to use Git for the project. However, if you have time, it is highly recommended to learn (and use) Git for your future projects (not only for this course). It is therefore recommended to follow this tutorial at least until the end of “Practice 3” (especially if you have no experience in using Git). If you are already familiar with Git, you still will probably learn some new things by following “Practice 4” to “Practice 9”.
Installation¶
First, you can install Git by typing the following command either on your VM or your local machine (if you have apt on your local machine):
$ sudo apt install git
After the Git installation, you must setup your name and e-mail address by entering the following commands:
$ git config --global user.name "Your Name"
$ git config --global user.email "my.name@student.uliege.be"
Creating an account on a Git hosting service¶
We can experience usefulness of Git by using a Git hosting service that provides a remote server hosting your Git repositories.
There are several Git hosting services available, the most popular being:
GitHub : One of the biggest Git hosting service (public)
GitLab (Uliege) : A hosting service provided by GitLab Inc (recommended)
Privately, TAs recommend you to use the ULiege’s GitLab. For creating an account, visit their web page and follow the instructions.
Register your ssh public key with the hosting service¶
Git performs data transfer through the ssh protocol.
If you want to reuse the ssh key you have already created, put the content of “info0940_id_rsa.pub” on the hosting service (and place the private key (“info0940_id_rsa”) in the “~/.ssh” directory on the VM or on your host, depending on where you want to connect from).
Note however that if your keys do have custom names (such as “info0940_id_rsa”), you will need to configure your ssh client to use them (click here for the gitlab documentation) or use a particular prefix for some git commands (see the section “Synchronize the local repo with the remote repo” below).
If you want to create a new ssh key with the default name, type the following command (be careful that if you already have a key with the default name, it will overwrite it):
$ ssh-keygen
On GitLab, we can add the public key from [Profile Picture] ->
Preferences -> SSH Keys
.
Note
If you choose to reuse the SSH key to connect to Git from your VM, it will contain the private key needed to connect to itself. For better security, the best practice would be to use different key pairs for connecting to the VM and for connecting to Git.
Create a Git repository on a hosting service¶
Please follow the instructions of the web page of the hosting service to create
a repository named git-tutorial.
It should not be too complicated, but help pages are available on the hosting service’s web page if you need them (for example, here for GitLab).
Do not go further until you have created the repository.
Permission setting on a Git hosting service¶
You need to create first a private repository.
Danger
Your repository on a hosting service can become visible from all the people in this world. So please pay attention to the permission setting when you put your secret information.
There are two types of permissions on the Git repositories on the hosting services: private and public.
If it is a private repository, the repository can be accessed only from you.
If it is a public repository, the repository is visible to everyone.
Please pay attention to the permission of your Git repository on the hosting service. If there is no special reason to do otherwise, it is generally recommended to use private repositories.
Note
If you want to share your repository with your friends, you DO NOT need to make your repository public. You can grant a user the access to your private repository through the web pages of the hosting services.
At this stage, you have an empty repository. In other words, there is no data on the remote repository yet. We need to create a Git repository locally, and push it to the created remote repository. We will do it in the next sections.
Create a new local repository¶
First type the following commands on your VM. They allow to create a local Git repository:
$ cd ~ # cd = "change directory"; ~ = home directory of the current user. You can choose another directory if you want.
$ mkdir git-tutorial # mkdir = "make directory".
$ cd git-tutorial
$ git init # Create an empty Git repository in the current directory.
$ touch README.md # Create a new file named "README.md".
$ git add . # These two commands are explained in the next sections.
$ git commit -m "first commit"
Note
You can almost always check what a command does by checking its manual with man <command>
. For example, try using man git-init
(type q
to exit the manual). More details on man pages will be shown in the next tutorial.
After entering these commands, you have a local Git repository in the directory git-tutorial
containing a file named README.md
. But the content of the local repository is not yet present on any remote repository.
It is thus recommended to push the content to a remote server for backup and/or for other people to access it if needed.
Synchronize the local repo with the remote repo¶
Once the local repository and the setup of the Git hosting service are done, we need to synchronize the content of the local repository with the remote repository.
The following command registers the remote repository to the local repository. Please replace YOUR_ACCOUNT_NAME with your account name.
If you use ULiege’s GitLab:
$ git remote add origin git@gitlab.uliege.be:YOUR_ACCOUNT_NAME/git-tutorial.git
If you use GitHub:
$ git remote add origin git@github.com:YOUR_ACCOUNT_NAME/git-tutorial.git
If you use Gitlab (official):
$ git remote add origin git@gitlab.com:YOUR_ACCOUNT_NAME/git-tutorial.git
Note
“origin” is the default name of the remote repository. You can always see its value by typing git remote -v
.
Then, push the local repository to the remote repository:
$ git push -u origin master
Note
“master” is the default name of the main branch. It is also often called “main”. You will learn about branches later in “Practice 7”.
If the command above does not work, try the following:
$ GIT_SSH_COMMAND='ssh -i ~/.ssh/info0940_id_rsa' git push -u origin master
Now, refresh the web page of the hosting service and you will find the file
README.md
on the remote repository. Therefore, even if the disk of your
computer is broken and you lose all your data (and thus the local file
README.md
), you can restore the file README.md
from the remote
repository.
Overview of how Git works¶
Now that you have created a local repository and pushed it to a remote repository, let’s see how Git works.

The Working wirectory is where you edit files on your computer.
The Staging area is used when Git starts tracking and saving changes that occur in files. You can think of it as a “pre-commit” area (but commiting does not mean that the staging area is cleared. It just means that the changes are saved in the local repository).
The Local repository is where Git saves the history of changes (commits) for all files. It is under Git’s control.
The Remote repository is the equivalent of the local repository, but it is on a remote server. It is used for sharing the code with others or for backup purposes.
Here is an overview of the useful Git commands:
Command |
Description |
---|---|
|
Copy a Git repository from a remote server |
|
Add file(s) or directory(ies) to the staging area |
|
Record changes to the current repository |
|
View the status of your files in the working directory and staging area |
|
Show changes between commits. Without arguments, it shows changes between the working directory and the staging area |
|
Get help about a particular command |
|
Fetch from a remote repository and try to merge it with the current branch |
|
Push your new branch(es) and commit(s) to a remote repository |
others: init
, reset
, branch
, checkout
, merge
, log
, tag
, patch
, …
Practice 1: Commit a new file¶
Now, let’s do a small exercice. The scenario is to start to work on an assignment asking you to write a C program which prints a “hello” message.
Create and edit a new file within the git-tutorial
folder (any editor is fine, but it is illustrated with neovim
here):
$ nvim assignment.c
Let’s write the following code to assignment.c
:
#include <stdio.h>
int main(void)
{
printf("hello\n");
return 0;
}
After editing this C file, save this version under Git (We call it a “commit”).
Before doing the commit, we first need to add the file(s) to a list of commit target (called the staging area) by typing the following command:
$ git add assignment.c
Then enter the “git status” command in order to check if the file assignment.c
is added to the staging area. You will see the following output:
$ git status
On branch master
Your branch is up to date with 'origin/master'.
Changes to be committed:
(use "git reset HEAD <file>..." to unstage)
new file: assignment.c
Now we see that assignment.c
is listed in “Changes to be committed”.
Let’s commit this file with the command below:
$ git commit -m "assignment file prints hello"
where the “-m” option specifies the comment for the commit.
Note
Each commit requires a short comment. If you do not specify “-m”, Git jumps to an editor to write your comment.
After entering this command, the current version is saved LOCALLY. So, let’s synchronize the current local repository status with the remote repository by entering the following command.:
$ git push origin master
Afterwards, assignment.c
is sent to the remote repository. Confirm it by visiting
the web page of the hosting service. Supposedly you will find a file assignment.c
there.
Practice 2: Commit file update¶
In the next assignment, students are asked to write a C code that prints “see you” by modifying the previous code.
Let’s update the file assignment.c
with the following code:
#include <stdio.h>
int main(void)
{
printf("see you\n");
return 0;
}
Now, the assignment is done. Let’s save this new version by entering the following command:
$ git add assignment.c
$ git commit -m "assignment file prints see you"
Let’s push the change to the remote repository.:
$ git push origin master
Visit the hosting web page, and confirm that the latest C file on the remote repository is updated to print the “see you” message.
Practice 3: Restore lost files from a remote repo¶
Danger
Perform this step after you are sure that your remote repository contains the C file which prints “see you”.
Good Job! You finished the second assignment (writing C code that prints “see you”). Unfortunately, you lost the C file before submitting it to the submission platform… In order to simulate this scenario, enter the following command to delete the local repository:
$ cd ~ # If you placed the repository in another directory, please replace "~" with the directory path.
$ rm -rf git-tutorial
Fortunately, you have been using Git for version control, and your work was saved on the remote repository. So, let’s restore the lost file(s) from the remote repository with the following commands. (If you use GitHub or GitLab.com, replace git@gitlab.uliege.be with git@github.com and git@gitlab.com respectively):
$ cd ~
$ git clone git@gitlab.uliege.be:YOUR_ACCOUNT_NAME/git-tutorial.git
This will fetch the directory git-tutorial
from the remote repository to your local machine.
Please confirm the contents of this directory. Hopefully, you will find your assignment.c
:
$ cat git-tutorial/assignment.c
#include <stdio.h>
int main(void)
{
printf("see you\n");
return 0;
}
Practice 4: Restore a past version¶
You could have submitted the second assignment. However, a stupid TA says that they have lost the files of the first assignment (printing “hello”). The TA asks you to submit your first assignment again…
Nevertheless, you do not have the first file because you have overwritten it. But, luckily you are using Git. So, let’s restore the first assignment.
First, let’s see the list of versions with the following command:
$ git log
commit d8fec2e1c88e7da1e200e98f051f1056c833f666 (HEAD -> master, origin/master, origin/HEAD)
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:56:43 2020 +0100
assignment file prints see you
commit 7762be9249adfb6a611ebc1acd447559d7f16f44
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:47:04 2020 +0100
assignment file prints hello
commit fe4c47c5204df05f9df22fd7ab39e53c9bfb9104
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:14:51 2020 +0100
first commit
In Git, each commit is identified by a commit ID. For instance, in the above case, the commit ID of the first assignment (whose comment is “assignment prints prints hello”) is “7762be9249adfb6a611ebc1acd447559d7f16f44”.
We can restore assignment.c
with the following commands (change the commit ID depending on your case):
$ git checkout 7762be9249adfb6a611ebc1acd447559d7f16f44 assignment.c
Then check the content of assignment.c
, which should contain the code that prints “hello”:
$ cat assignment.c
#include <stdio.h>
int main(void)
{
printf("hello\n");
return 0;
}
Note
Right now, the version of the assignment.c
file you checked out is placed in the staging area. If you want to remove it from the staging area, you can use git reset
. This note is just a detail, don’t worry if this is not clear for you.
If you wish to restore the latest state, you can use the following command. In this command “HEAD” means the latest commit:
$ git checkout HEAD assignment.c
$ cat assignment.c
#include <stdio.h>
int main(void)
{
printf("see you\n");
return 0;
}
Practice 5: Create a patch¶
In the third project, students are asked to write a C program which prints “good morning”. Students are also requested to submit a patch that has the diffs from the second project (prints “see you”).
First, let’s finish the assignment:
#include <stdio.h>
int main(void)
{
printf("good morning\n");
return 0;
}
Second, let’s commit the changes and push it to the remote host:
$ git add assignment.c
$ git commit -m "assignment file prints good morning"
$ git push origin master
Now, the assignment is mostly done. Let’s generate a patch for the submission. Again, the patch has to contain the diffs from the second assignment.
For patch creation, first, let’s check the commit ID of the second assignment:
$ git log
commit ec33b1fc149ec5a9b12d415e60c2b36d97d13b73 (HEAD -> master, origin/master, origin/HEAD)
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 16:29:55 2020 +0100
assignment file prints good morning
commit d8fec2e1c88e7da1e200e98f051f1056c833f666
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:56:43 2020 +0100
assignment file prints see you
commit 7762be9249adfb6a611ebc1acd447559d7f16f44
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:47:04 2020 +0100
assignment file prints hello
commit fe4c47c5204df05f9df22fd7ab39e53c9bfb9104
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:14:51 2020 +0100
first commit
According to the output, the commit ID of the second project is d8fec2e1c88e7da1e200e98f051f1056c833f666. After you know the commit ID, you can generate a patch using the following command (change the commit id depending on your case):
$ git format-patch d8fec2e1c88e7da1e200e98f051f1056c833f666 --stdout > submission.patch
The content of the patch will be:
$ cat submission.patch
From ec33b1fc149ec5a9b12d415e60c2b36d97d13b73 Mon Sep 17 00:00:00 2001
Author: Your Name <my.name@student.uliege.be>
Date: Sun, 9 Feb 2020 16:29:55 +0100
Subject: [PATCH] assignment file prints good morning
---
assignment.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/assignment.c b/assignment.c
index 61cdc4a..08f4f65 100644
--- a/assignment.c
+++ b/assignment.c
@@ -2,6 +2,6 @@
int main(void)
{
- printf("see you\n");
+ printf("good morning\n");
return 0;
}
--
2.17.1
The patch shows the diffs between second and third assignments.
Practice 6: Apply a patch¶
One of your friends has extended your third project and asked you to test it. They send you a friend.patch. The patch makes your third assignment print “good afternoon”.
Let’s apply their patch.
First, download and save the patch from our website:
$ cd ~
$ wget --no-check-certificate https://people.montefiore.uliege.be/~gain/courses/info0940/asset/friend.patch
Then go back within the git-tutorial
directory:
$ cd git-tutorial
Apply your friend’s patch with the following command:
$ git am ~/friend.patch
Applying: assignment file prints good afternoon
Finally check the content. It should print “good afternoon”:
$ cat assignment.c
#include <stdio.h>
int main(void)
{
printf("good afternoon\n");
return 0;
}
If you have some problem with git am
, type the following command and retry:
$ git am --abort
Tip
A common issue is that your editor might be using tabs instead of spaces.
Practice 7: Create a branch¶
You find your friend’s patch is cool and you decided to work together.
First, let’s push the latest commit including your friend’s patch by typing the following command:
$ git push origin master
Now, you wish to add a new feature making the program to print “good evening”. The updated C file will look as follows:
#include <stdio.h>
int main(void)
{
printf("good evening\n");
return 0;
}
However, your friend is also working on the same file. Your change(s) may conflict with the change(s) made by your friend.
To avoid this issue, let’s create a new branch. Branch allows you to maintain updates while keeping the current branch safe. By default, we are initially working on a branch named “master”, which can also be called the “main” branch.

Branches are useful to manage projects with multiple developers. Each developer can work on their own branch and merge their changes to the main branch when they are ready. Or, as in the example on the figure, student2 can also create a branch from student1’s branch to work on a new feature while using student1’s work as a base.
It is also possible for multiple people to work on the same branch, but it is generally recommended to use branches to avoid conflicts.
Now, let’s make a new branch named “evening”:
$ git branch evening
Let’s check the list of branches. The following output shows that we have 2 branches: “evening” and “master”. Currently, we are working on the branch “master” (the asterisk symbol shows the current branch):
$ git branch
evening
* master
We are on the “master” branch now. So let’s switch to the newly created “evening” branch:
$ git checkout evening
M assignment.c
Switched to branch 'evening'
Let’s confirm the branch state again. The asterisk should have moved to “evening”:
$ git branch
* evening
master
Now, we are working on the “evening” branch. From here, commits are only reflected to the “evening” branch.
Let’s commit the current change (printing “good evening”):
$ git add assignment.c
$ git commit -m "assignment file prints good evening"
Let’s push the change to the remote repository. Since we want to push the “evening” branch, we need to specify “evening” here (not “master”):
$ git push origin evening
Afterwards, visit the hosting web page and please check the branch. Supposedly, there is a new branch named “evening”.
Practice 8: Switch a branch¶
Currently, we have the following file content on the “evening” branch.:
$ cat assignment.c
#include <stdio.h>
int main(void)
{
printf("good evening\n");
return 0;
}
If we wish to go back to the “master” branch, we can do it by typing the following command:
$ git checkout master
Switched to branch 'master'
Your branch is up to date with 'origin/master'.
Let’s check the file content of the “master” branch. It should be the previous version (printing “good afternoon”) because the latest commit is only applied to the branch named “evening”:
$ cat assignment.c
#include <stdio.h>
int main(void)
{
printf("good afternoon\n");
return 0;
}
Practice 9: Merge a branch¶
Your friend has agreed that your latest update (printing “good evening”) is a good idea and they are willing to merge it with the “master” branch. So, let’s merge the “evening” branch with the “master” branch.
First, we need to go to the “master” branch:
$ git checkout master
Afterwards, type the following command to merge the “evening” branch into the “master” branch:
$ git merge evening
Updating d98463e..8a3043c
Fast-forward
assignment.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
Then perform a check on the file content. The “master” branch should also have a file printing “good evening”:
$ cat assignment.c
#include <stdio.h>
int main(void)
{
printf("good evening\n");
return 0;
}
The commit log will look as follows:
$ git log
commit 8a3043c7c33c416094788c62d4de1288fc869785 (HEAD -> master, origin/evening, evening)
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 17:16:27 2020 +0100
assignment file prints good evening
commit d98463e4aef2a6518a982f206a52435a150a3ca9 (origin/master, origin/HEAD)
Author: Your Name <my.name@uliege.be>
Date: Sun Feb 9 16:41:39 2020 +0100
assignment file prints good afternoon
commit ec33b1fc149ec5a9b12d415e60c2b36d97d13b73
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 16:29:55 2020 +0100
assignment file prints good morning
commit d8fec2e1c88e7da1e200e98f051f1056c833f666
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:56:43 2020 +0100
assignment file prints see you
commit 7762be9249adfb6a611ebc1acd447559d7f16f44
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:47:04 2020 +0100
assignment file prints hello
commit fe4c47c5204df05f9df22fd7ab39e53c9bfb9104
Author: Your Name <my.name@student.uliege.be>
Date: Sun Feb 9 15:14:51 2020 +0100
first commit
Here, the update on the “master” branch is not reflected to the remote repository. Let’s push it to the “master” branch of the remote host:
$ git push origin master
We do not need the “evening” branch anymore. Let’s thus remove it:
$ git branch -d evening
This only removes the branch locally. As you can see using:
$ git branch --all
* master
remotes/origin/HEAD -> origin/master
remotes/origin/evening
remotes/origin/master
We also do not need the remote “evening” branch. Let’s thus remove it as well:
$ git push --delete origin evening
Up to here…
You have made changes on the new branch named “evening”.
You merged the “evening” branch to “master”.
You have reflected changes to the remote repository.
Tip
For more serious projects, merging into the master branch is generally done through a pull request (aka merge request). This is a way to review the changes before merging them into the master branch. This is not something which is built-in Git, but rather a feature of the hosting services like GitLab and GitHub. If you are curious and have time, you can try doing one using the GitLab/GitHub web interface.
Further information¶
You can find the official documentation about Git on its official web page.