Using Github and Gitlab (1) – About Git

Recently at work we encountered the choice between Github and Gitlab. I did some research and summarized their similarities and differences below.

First of all, both of them are based on Git. Let’s first talk about Git itself. Git is standalone from any of the Git online servers: in principle you don’t need Internet to use Git. But, nobody else can see your project then. What’s the point?

Check whether you have git first. If not, install it.

git --version

How git works

Basically, Git is used to record the changes of a project, which contains folders and files. It stores all these information in a repository in each project folder. Each time some changes are done, and you want to record the status of the project (like you wanna take a selfie for your workout progress), it’s called a commit. Each commit has a reference to it, called a head. The current head is capitalized as HEAD, and each repository can have multiple heads.

Each commit includes 1. The project files; 2. parent commit; 3. a name for this commit (a head).

initializing git and the first commit

Let’s start the demo now. I created a file “History.txt” and wrote “08/09/17 15:09: Ao Created History.txt”. I am ready for my very first commit. So, I initialize the repository by:

git init

It will say Initialized empty Git repository in /path/to/project/directory/.git/. Next you need to tell Git what files are relevant, i.e. which files you want to commit, i.e. you need to add the files to the commit list.

git add file1 file2 file3

Or if you want to commit the whole directory, do

git add .

Now you may do your first commit by:

git commit -m "Initial commit"

You will see a bunch of notifications saying your first commit was successful. Alternatively, you can also use

git commit -a -m "Initial commit"

to automatically add all the files and commit (equivalent to git add . ; git commit -m “…”)Now, let’s add another line to the file: “08/09/17 15:30: Ao Modified History.txt”. Before you do the next commit, you probably want to check which files were modified, and what are different. Use the following commands:

git status

You will see “Modified: History.txt”, indicating the file was modified since last commit. Use

git diff

to get the detailed changes between the current files and the last commit:

Go ahead and do the next commit with git commit -m “Second commit”. Now you have two commits.

Reversing commits

Now say you realized that the changes in your last commit were really stupid/unnecessary. You want to reverse it. There are basically two options: hard and soft. Before demonstrating this technique, let’s add another line in the file, and do another commit. Now you have three commits.

Let’s say you want to go back to the 1st commit and do some changes. First we try the soft way. Each commit head, as you could see, has a unique name, called SHA1 name. You need the first 7 characters to describe a head, e.g. our first commit is 5d28811, but I found you can use more than that, up to the whole SHA1 name. We want to basically “reset” to that commit. So the command is

git reset --soft 5d28811

Also, you can use the name of the head, such as master, to refer to the commit.

You will see the following Git status change:

Oh BOY! There is only one commit left. But your file stays as it was at the 3rd commit. But Wait, you then again realized all you did for the 2nd and 3rd commits make sense! You want to go back to the 3rd commit (cancelling the “reset”). What should you do?

Luckily, all these heads (references) are properly stored in Git. You just need to call another log file, reflog:

For now we ignore the meaning of HEAD@{*}. You see your third commit is still there. Now you can go back by

git reset --soft 3224034

Next, we will try the HARD way. Be very careful when using this option, as this will cause changes to both your commits and files. All right, now we are at the 3rd commit. We are sure we want to discard the 2nd and 3rd commits. Do:

git reset --hard 5d28811

As shown, each hard reset can change both your commits and files. Although you may use hard reset to recover the files, as they are still recorded in reflog, I still recommend you be cautious when using it.

Alternatively, we can use another method: git revert. Revert also changes your file, but it’s different than reset. To demonstrate it let’s again start from the 3rd commit.

git revert 3224034bf 7d9fd5cf80a7a

Each time a revert happens, there will be a notification file opened, looking like this

It is basically a commit message on the first line. The document is opened with vim, so all you have to do is keep/change the commit message (in this case default is: Revert “Second commit”), and press :wq and Enter to save and exit vim. After two reverts, the project looks like this:

As shown, the reverts have been recorded in the log. The status is “up to date” (no unstaged changes), and the file has been reverted to the 1st commit. Now you probably understand: each revert is treated as a new commit, while reset just abandons changes made since then:

 4(2) means the 4th commit = 2nd, same for 5(1)

Therefore, you may use reset when you are working on your own branch, but use revert when you are working on a shared branch.

Now, since we have introduced this term, let’s talk about branch.

Use branches to collaborate on a project

An example of why you should use branches: You have released a game to players for testing, and you are working on adding another character. You received a bug report from a player and it needs to be fixed immediately. Option 1, without branches, you commit the current version with the unfinished character (such as a hero with infinite HP or 1 HP), then you fix the problem and commit again. Now all the players will start reporting this unfinished character.

The story of Nintendo’s Pokemon Go tells us a crashing game should not be seen by the players. BTW, I still couldn’t believe they made a fortune with that app.

The solution is to have two branches, say, one named “new_character” and one named “release”. Players only see the “release” branch, and you commit to “new_character”, go back to “release”, debug, commit, go back again to “new_character”, and work on the HP issue.

To start a new branch from a certain commit head, do

git branch new-branch-name starting-head-reference

Branch is almost just another name for head. To show all branches, do either one of the following two:

git branch -a

git show-branch -a

An example is given below. I have redone the whole repository to be clear – the previous example generated too much trash information.

As shown, there are two branches, master and work_progress. Now you should be able to understand what “On branch master” means. master is the default HEAD name, also the default branch name if you create a new one. To switch to another branch, do

git checkout head-name

(remember a branch is just a head?) NOTICE: all files in your directory will be changed to that commit. 

What we just did can be visualized as follows (remember HEAD is the current head):

You can now work on the file and do another commit. Since this commit won’t be seen on the master branch, let’s call it commit 3′. The change can be shown by the following:

As shown, on master branch the entry at 08/13/17 23:00 isn’t recorded. Vice versa, on the work_progress branch the entry at 08/13/17 15:13 isn’t recorded.

Now you might wonder, Hey, the bug fix is useful for my ongoing work too, how may I add that in the master branch? That’s the idea of (very important!!) merge

Merge files from other branches

Now imagine you added a file called addon.txt to fix the bug in the work_progress branch, now you want that to appear in your master branch. First, in work_progress, you need to add the new file by git add, then you need to commit it, and switch to master

In branch master, you do not see addon.txt. Now do

git merge work_progress

Now you see addon.txt, but you also see a conflict:

The addon.txt showed up, however the History.txt became like this, since work_progress also changed it:

This is a conflict. You need to resolve it. You may keep the current content (below <<<<<< HEAD) and also contents from work_progress (below ====== and above >>>>>>). Then add it and commit. Now, from git log, you’ll realize that we have effectively combined the commits from work_progress and master.

To visualize, what was done is basically:

To delete a branch, just do

git branch -d branch_name

Be sure not to leave a dangling commit when you delete a branch. For example, if you haven’t merged the commit 3′ from work_progress to 4, then you can’t delete it, since 3′ will become a dangling commit.

Now you know most things about the local usage of Git. It’ time to check Github and Gitlab: how to use Git online.