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: * `GitHub `_ : One of the biggest Git hosting service. * `GitLab.com `_ : A hosting service provided by GitLab Inc. * `GitLab offered by Montefiore `_ : Offered by the IT department of Montefiore (**recommended**) 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``: .. code-block:: c #include 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 ..." 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``: .. code-block:: c #include 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 .. code-block:: c #include 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 Date: Sun Feb 9 15:56:43 2020 +0100 assignment file prints see you commit 7762be9249adfb6a611ebc1acd447559d7f16f44 Author: Your Name Date: Sun Feb 9 15:47:04 2020 +0100 assignment file prints hello commit fe4c47c5204df05f9df22fd7ab39e53c9bfb9104 Author: Your Name 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 .. code-block:: c #include 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 .. code-block:: c #include 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: .. code-block:: c #include 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 Date: Sun Feb 9 16:29:55 2020 +0100 assignment file prints good morning commit d8fec2e1c88e7da1e200e98f051f1056c833f666 Author: Your Name Date: Sun Feb 9 15:56:43 2020 +0100 assignment file prints see you commit 7762be9249adfb6a611ebc1acd447559d7f16f44 Author: Your Name Date: Sun Feb 9 15:47:04 2020 +0100 assignment file prints hello commit fe4c47c5204df05f9df22fd7ab39e53c9bfb9104 Author: Your Name 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 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 .. code-block:: c #include 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: .. code-block:: c #include 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 .. code-block:: c #include 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 .. code-block:: c #include 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 .. code-block:: c #include 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 Date: Sun Feb 9 17:16:27 2020 +0100 assignment file prints good evening commit d98463e4aef2a6518a982f206a52435a150a3ca9 (origin/master, origin/HEAD) Author: Your Name Date: Sun Feb 9 16:41:39 2020 +0100 assignment file prints good afternoon commit ec33b1fc149ec5a9b12d415e60c2b36d97d13b73 Author: Your Name Date: Sun Feb 9 16:29:55 2020 +0100 assignment file prints good morning commit d8fec2e1c88e7da1e200e98f051f1056c833f666 Author: Your Name Date: Sun Feb 9 15:56:43 2020 +0100 assignment file prints see you commit 7762be9249adfb6a611ebc1acd447559d7f16f44 Author: Your Name Date: Sun Feb 9 15:47:04 2020 +0100 assignment file prints hello commit fe4c47c5204df05f9df22fd7ab39e53c9bfb9104 Author: Your Name 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 **remote** "*evening*" 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 `_.