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

  • accessibility to past versions

  • save all versions on remote hosts

  • share a source code directory (repository) with people

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.

Installation

First type the following command on your VM/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.

They exist major Git hosting services available to us so far:

Privately, TAs recommend you to use the Montefiore’s GitLab, but you can use any of them. For creating an account, visit a web page and follow the instructions.

Register your ssh public key with the hosting service

Git performs data transfer through the ssh protocol. Once you put your ssh public key on the hosting service, it does not ask your password when you push your changes to the remote repository.

If you already have the ssh key named “info0940_id_rsa”, put the content of “info0940_id_rsa.pub” on the hosting service.

On GitLab, we can add our ssh key from Setting -> SSH Keys.

Create a Git repository on a hosting service

Please follow the instructions of the web page of the hosting service.

In this time, lets’ make a repository named git-tutorial.

Permission setting on a Git hosting service

In short, 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 permissoin setting when you put your secret information.

There are two types of permission about the Git repositories on the hosting services. One is private, and another is 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 all the people in this world.

Please pay attention to the permission of your Git repository on the hosting service. If there is no special reason, it is recommended to start from a private repository.

Note

If you want to share your repository with your friends, you DO NOT need to make your repository public. You can add a user who has accessibility 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. These ones allow to create a local Git repository:

$ cd ~
$ mkdir git-tutorial
$ cd git-tutorial
$ git init
$ touch README.md
$ git add .
$ git commit -m "first commit"

After entering these commands, you can use Git locally. But for backup reason, it is recommended to push the content to a remote server.

Note

the touch command creates a new file named README.md.

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 with the local repository. Please replace YOUR_ACCOUNT_NAME with your account name.

  • 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
    
  • If you use Montefiore’s GitLab:

    $ git remote add origin git@gitlab.montefiore.ulg.ac.be:YOUR_ACCOUNT_NAME/git-tutorial.git
    

Then, push the local repository to the remote repository:

$ git push -u origin master

If the command above does not work, try the following:

$ GIT_SSH_COMMAND='ssh -i ~/.ssh/info0940_id_rsa' git push -u origin master

Afterwards, refresh the web page of the hosting service. You fill find a file named README.md that is sent from the local machine.

Now README.md is saved 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.

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.

On your VM, create a new file within the git-tutorial folder by entering the following command (any editor is fine):

$ vim assignment.c

Let’s write the following code to assignment.c:

#include <stdio.h>

int main(int argc, char const* argv[])
{
    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 printing “hello”.

First, let’s finish the assignment first by editing assignment.c:

#include <stdio.h>

int main(int argc, char const* argv[])
{
    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… In order to simulate this scenario, enter the following command to delete the local repository:

$ cd ~
$ 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.montefiore.ulg.ac.be with git@github.com and git@gitlab.com respectively):

$ cd ~
$ git clone git@gitlab.montefiore.ulg.ac.be:YOUR_ACCOUNT_NAME/git-tutorial.git

Now, you will fecth the directory git-tutorial on your local machine. Please confirm the contents of this directory. Hopefully, you will find your assignment.c:

$ cat assignment.c
#include <stdio.h>

int main(int argc, char const* argv[])
{
    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 he has 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”.

Now, we restore assignment.c with the following commands (change the commit ID depending on your case):

$ git checkout 7762be9249adfb6a611ebc1acd447559d7f16f44 assignment.c
$ git reset

Then check the content of assignment.c. Supposedly, the file is for the first assignment that prints “hello”:

$ cat assignment.c
#include <stdio.h>

int main(int argc, char const* argv[])
{
    printf("hello\n");
    return 0;
}

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(int argc, char const* argv[])
{
    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(int argc, char const* argv[])
{
    printf("good morining\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, 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(int argc, char const* argv[])
 {
-     printf("see you\n");
+     printf("good morining\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. He sends you a friend.patch. The patch makes your third assignment to print “good afternoon”.

Let’s apply his patch.

First, download and save the patch from our website:

$ cd ~
$ wget http://www.montefiore.ulg.ac.be/~yasukata/lecture/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(int argc, char const* argv[])
{
    printf("good afternoon\n");
    return 0;
}

If you have some problem with git am, type the following command and retry:

$ git am --abort

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(int argc, char const* argv[])
{
    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”.

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”. Currenlty, we are working on the branch “master” (asterisk 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(int argc, char const* argv[])
{
    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(int argc, char const* argv[])
{
    printf("good afternoon\n");
    return 0;
}

Practice 9: Merge a branch

Now your friend agrees that he works on your latest update (printing “good evening”). 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(int argc, char const* argv[])
{
    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

We also do no need the remoteevening” branch. Let’s thus remove it as well:

$ git push 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.

Further information

You can find the official documentation about Git on its official web page.