Introduction to Gitlab

Urs Roesch

What is GitLab

GitLab is a complete DevOps platform, delivered as a single application. This makes GitLab unique and creates a streamlined software workflow, unlocking your organization from the constraints of a pieced together toolchain. Learn how GitLab offers unmatched visibility and higher levels of efficiency in a single application across the DevOps lifecycle.

Target audience

The course material presented here is meant for a technically inclined person with a basic proficiency in the Git source management system and an inclination to learn about combining the power of Git with the versatility of GitLab.

Scope & Terminology

GitLab is tightly wedded, as the name suggests, to the git source code management system, its concepts, command and terminology. It helps to be familiar with Git’s interpretations of working directory, staging, repository, branch, tag, commit and revision among others.

GitLab setup

GitLab setup prerequisites

For the course the following prerequisites have to be met:

  • Recent version of docker.io

All docker commands are invoked without sudo. It is therefore assumed that the participants user is part of the docker Unix group.

Gitlab docker setup

The examples in this tutorial are based on gitlab-ce (community edition). The docker image and instruction on how to install it can be found on the gitlab docker hub page.

Table 2. Port mapping
ProtocolLocal PortDocker Port

HTTPS

8443

443

HTTP

8480

80

SSH

8422

22

Container start script with prefilled port numbers.
GITLAB_HOSTNAME=gitlab.local
GITLAB_HOME=${HOME}/var/work/gitlab
OMNIBUS=""
OMNIBUS+="external_url \"http://${GITLAB_HOSTNAME}:8480/\";"
OMNIBUS+="gitlab_rails['gitlab_shell_ssh_port'] = 8422;"

function start() {
  [[ -d ${GITLAB_HOME} ]] && mkdir -p ${GITLAB_HOME}
  docker run \
    --detach \
    --hostname ${GITLAB_HOSTNAME} \
    --env GITLAB_OMNIBUS_CONFIG="${OMNIBUS}" \
    --publish 8443:443 \
    --publish 8480:8480 \
    --publish 8422:22 \
    --name gitlab \
    --restart always \
    --volume ${GITLAB_HOME}/config:/etc/gitlab \
    --volume ${GITLAB_HOME}/logs:/var/log/gitlab \
    --volume ${GITLAB_HOME}/data:/var/opt/gitlab \
    gitlab/gitlab-ce:latest
}

start
The initial startup of the container is taking quite some time. Patience until the first connection is required.
Add gitlab.local to the /etc/hosts file.
sudo sed -i \
  -e '/gitlab.local/d' \
  -e '$a\127.0.0.1 gitlab.local' \
  -e '$a\::1 gitlab.local' \
  /etc/hosts

Gitlab account setup

Configure admin account password

After starting the docker container open a browser and navigate to http://gilab.local:8480.

setup admin password
Figure 1. Admin password setup

Create user account

PropertyValue

First name

Joe

Last name

Developer

User name

jdev

Email

joe.developer@gitlab.local

Password

topsecret

Role

Software Developer

setup user account
Figure 2. User account creation
setup user account role
Figure 3. Define role

Congratulations the initial setup is complete!

Module 1 - User configuration

Goals

  • Navigate the user setting

  • Set privacy settings.

  • Manage ssh public keys.

User profile configuration

For the purpose of the excercises conducted during this tutorial no particular changes in the user profile need to be made but for better recognition the avatar, the privacy setting and the ssh keys are being discussed here.

Navigate to the user' settings

configuration user settings
Figure 4. Navigate to the user settings

Change the avatar

configuration user settings profile
Figure 5. Change the avatar
configuration user settings profile avatar
Figure 6. Upload new avatar from image file

For Joe Developer the chosen avatar is a construction worker with hard hat.

Review privacy settings

configuration user settings profile privacy
Figure 7. Privacy settings

Upload ssh public keys

Generate a ssh public key on the command line
$ ssh-keygen -t ed25519 -f ~/.ssh/gitlab (1)
Generating public/private ed25519 key pair.
Enter passphrase (empty for no passphrase): (2)
Enter same passphrase again: (3)
Your identification has been saved in /home/uroesch/.ssh/gitlab
Your public key has been saved in /home/uroesch/.ssh/gitlab.pub
The key fingerprint is:
SHA256:hXWPmuLBU8fnrEYPNBoSDKwXaITn5Jn/Vtvdin6gJI4 uroesch@uroesch-puzzle
The key's randomart image is:
+--[ED25519 256]--+
|   o.o.o. . .    |
|  . = o .+ o o   |
|   * + .o + * o  |
|    * .. + B =   |
|     o  S + o o  |
|      ...+o..+   |
|       +.+ +oo.. |
|      E + o...o .|
|       .   .o... |
+----[SHA256]-----+
$ ls -l ~/.ssh/gitlab*
-rw------- 1 jdev jdev 464 Nov  9 12:09 /home/jdev/.ssh/gitlab (4)
-rw-r--r-- 1 jdev jdev 104 Nov  9 12:09 /home/jdev/.ssh/gitlab.pub (5)
configuration user settings ssh key add
Figure 8. Upload a ssh public key
configuration user settings ssh key confirm
Figure 9. Upload confirmation for ssh public key

Module 2 - Gitlab project

Goals

  • Create a new GitLab project.

  • How to navigate a project.

  • Protect certain branches like master.

Create a new project

In the following steps a new personal public repository is created. The process of creating a new project is assisted and straight forward.

The creation starts with clicking on the boxed plus sign left to the search field.

project new project
Figure 10. Create a new project from the top navigation bar
project new project create
Figure 11. Fill in the required information

Navigate new project

Right after the project is created the next screen is the project overview. For a first time visitor the screen has quite a few elements and is probably confusing at first sight.

Here the various elements are explained shortly to provide and initial overview where to find which functionality.

project new project initial
Figure 12. Initial project overview screen.

Clone project

GitLab has quite a few tools allowing for changes to the git repository data via the web interface. But for most purposes the content of the git repository is worked on with an IDE or on the command line externally.

In this exercise the previously created gitlab-project is cloned from the command line.

Navigate to the overview page of the project → http://gitlab.local:8480/jdev/gitlab-project

project clone
Figure 13. Copy project address for git clone operation.

Change to terminal window and execute

$ git clone ssh://git@gitlab.local:8422/jdev/gitlab-project.git (1)
Cloning into 'gitlab-project'...
X11 forwarding request failed on channel 0
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Receiving objects: 100% (3/3), done.
$ cd gitlab-project (2)
$ git log (3)
commit 3651309571108055dcafb3dacaf9678e90c91291 (HEAD -> master, origin/master, origin/HEAD) (4)
Author: Joe Developer <joe.developer@gitlab.local>
Date:   Mon Nov 9 12:10:30 2020 +0000

    Initial commit

To simulate different user behaviour in later modules the user information for this cloned repository should be changed to Joe Developer.

$ git config --local user.name "Joe Developer" (1)
$ git config --local user.email "joe.developer@gitlab.local" (2)
$ git config --local --get-regexp 'user' (3)
user.name Joe Developer
user.email joe.developer@gitlab.local

Repository protection

Among the many settings available for a GitLab project at this stage the one that really matters is the protection of the master branch.

Per default only the maintainer can push and as such also force push changes to the master branch. This can be further restricted and no one make changes to master without proper evaluation of the changes.

project new project repository protection
Figure 14. Restrictive master branch settings.
By protecting the master branch from direct pushes one can prevent fat-fingered git pushes where master gets accidentally overwritten with content from another branch. As a disclaimer this never happened to the instructor guiding you currently, ever!!!

Module 3 - Forking projects

Goals

  • Create a new user

  • Fork an existing project.

  • Clone forked project.

  • Branch local copy.

  • Push changes to forked project.

Create new user (fork)

For discussing forking in detail a new user is required. Below are the instructions to do so.

Register user account

Open a new private or incognito browser window and navigate to the GitLab entry page → http://gitlab.local:8480/

Click on the [Register] tab and create a user with the following data:

Property

Value

First name

Mary

Last name

DevOps

User name

mdevops

Email

mary.devops@gitlab.local

Password

topsecret

Role

DevOps Engineer

A ssh public key is not required the change are made over the http protocol.

When finished change the avatar to match the description.

fork new user
Figure 15. Mary DevOps user profile page

Create forked project

User Mary DevOps is going to fork the project gitlab-project of user Joe Developer. The steps are listed here.

Fork gitlab-project

As user Mary Devops navigate to URL → http://gitlab.local:8480/jdev/gitlab-project

fork project fork
Figure 16. Fork the project gitlab-project
fork project fork select
Figure 17. Select namespace for the fork.
fork project fork wip
Figure 18. Fork in progress screen
fork project fork initial
Figure 19. Forked project overview page.

Change content of forked project

With the project forked under Mary DevOps' namespace it is time to make changes to the content.

Clone forked project

Navigate to URL → http://gitlab.local:8480/mdevops/gitlab-project/ Click on the [Clone] button to display and use the Copy with HTTP URL → http://gitlab.local:8480/mdevops/gitlab-project.git

Open terminal window to clone the project.

$ git clone http://gitlab.local:8480/mdevops/gitlab-project.git forked-project (1)
Cloning into 'forked-project'...
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 258 bytes | 258.00 KiB/s, done.

To distinguish changes to the forked and original repository in case of a merge request. The freshly created forked-project user settings are locally modified.

$ cd forked-project/
$ git config --local user.name "Mary DevOps"
$ git config --local user.email "mary.devops@gitlab.local"
$ git config --local --get-regex user
user.name Mary DevOps
user.email mary.devops@gitlab.local

Create branch

To work effectively encapsulate changes in git branches are recommended. When isolating each change in a branch it is possible to work on multiple different changes without independently. To follow this practice the first action in the forked-project repository is to create branch documentation and change to it.

$ git checkout -b documentation (1)
Switched to a new branch 'documentation'

Modify existing files

Under the documentation branch Mary modifies the README.md file adding information about contributors.

$ git diff README.md (1)
diff --git a/README.md b/README.md
index 26a1ddf..3e727fd 100644
--- a/README.md
+++ b/README.md
@@ -1,3 +1,7 @@
 # gitlab-project

-This is a gitlab project for the introduction course.
\ No newline at end of file
+This is a gitlab project for the introduction course.
+
+## Contributors
+* Joe Developer
+* Mary DevOps
$ git commit -m "README: Add contributors" README.md (2)
[documentation 67b94b1] README: Add contributors
 1 file changed, 5 insertions(+), 1 deletion(-)

$ git log (3)
commit 67b94b1886449c14db44524b1b67c71fe2250662 (HEAD -> documentation)
Author: Mary DevOps <mary.devops@gitlab.local>
Date:   Mon Nov 9 17:47:45 2020 +0100

    README: Add contributors

commit 3651309571108055dcafb3dacaf9678e90c91291 (origin/master, origin/HEAD, master)
Author: Joe Developer <joe.developer@gitlab.local>
Date:   Mon Nov 9 12:10:30 2020 +0000

    Initial commit

Push changes to project

With the changes made it is time to push them back onto the forked project.

$ git push origin documentation (1)
Username for 'http://gitlab.local:8480': mdevops (2)
Password for 'http://mdevops@gitlab.local:8480': ******* (3)
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 361 bytes | 361.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for documentation, visit:
remote:   http://gitlab.local:8480/mdevops/gitlab-project/-/merge_requests/new?merge_request%5Bsource_branch%5D=documentation
remote:
To http://gitlab.local:8480/mdevops/gitlab-project.git
 * [new branch]      documentation -> documentation (4)
The username and password for HTTP operations can be cached with below command. The timeout value is seconds. git config --global credential.helper 'cache --timeout=864000'

Navigating once more to the project page of the fork → http://gitlab.local:8480/mdevops/gitlab-project/ to view the changes in the interface.

fork project fork pushed
Figure 20. The forked project’s page after the push

Switching the project’s view to branch documentation.

fork project fork branch
Figure 21. The branch documentation in the overview.

The next step is to propose the changes to Joe Developer with a merge request. The procedure is topic for the next module.

Summary

Module 4 - Merge requests

Goals

  • Create a merge request from a forked project.

  • Submit a merge request.

  • Review changes in a merge request.

  • Amend a merge request.

  • Merge the request.

Create merge request

Initiate merge request

merge request create 01
Figure 22. After pushing a branch notification appears on the overview page.

Alternatively open a merge request via left hand side menu RepositoryCommits

merge request create 02
Figure 23. Create merge request via Commits

A third way is to go via the left hand menu RepositoryBranches page.

merge request create 03
Figure 24. Create merge request via Branches

Submit merge request

To submit the merge request there are a few questions to be answered generally the defaults are fine most of the time.

merge request create form
Figure 25. Create merge request via Branches

Review merge requests

View merge request

merge request create discussion 01
Figure 26. Merge request right after submission.

Add comment

merge request create discussion 02
Figure 27. User Joe Developer adds a comment under changes.
merge request create discussion 06
Figure 28. Mary DevOps views comment and resolves thread.

Amend request

merge request create discussion 04
Figure 29. Create a suggestion
Amendments are only available if the option for Allow commits from member who can manage the target branch has been checked during merge requestion submission.
merge request create discussion 05
Figure 30. Submit the suggestion as review
merge request create discussion 07
Figure 31. Suggestion ready for review or application.
merge request create discussion 08
Figure 32. Applied suggestion.

Merge the request

merge request create discussion 09
Figure 33. Merge the request

Post merge review

Eventually the merge request was merged in this particular case with the Squash commits option checked.

It is now time to find out how the project repository changed.

Web UI post merge review

merge request create discussion 10
Figure 34. Project overview page post merge.
merge request create discussion 11
Figure 35. Review of the commits present.

git command post merge review

$ git pull origin master (1)
X11 forwarding request failed on channel 0
remote: Enumerating objects: 6, done.
remote: Counting objects: 100% (6/6), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 4 (delta 1), reused 0 (delta 0), pack-reused 0
Unpacking objects: 100% (4/4), 513 bytes | 513.00 KiB/s, done.
From ssh://gitlab.local:8422/jdev/gitlab-project
 * branch            master     -> FETCH_HEAD
   3651309..5717883  master     -> origin/master
Updating 3651309..5717883
Fast-forward
 README.md | 6 +++++- (2)
 1 file changed, 5 insertions(+), 1 deletion(-)
$ git log (3)
commit 57178833a3b5b0881becc92de93a45357e2c54ec (HEAD -> master, origin/master, origin/HEAD)
Merge: 3651309 4e59b87 (4)
Author: Joe Developer <joe.developer@gitlab.local>
Date:   Mon Nov 9 21:39:52 2020 +0000

    Merge branch 'documentation' into 'master'

    README: Add contributors

    See merge request jdev/gitlab-project!2

commit 4e59b87c9a4cd0d41837374e5ab257ecc67d5251
Author: Mary DevOps <mary.devops@gitlab.local>
Date:   Mon Nov 9 21:39:52 2020 +0000

    README: Add contributors

commit 3651309571108055dcafb3dacaf9678e90c91291
Author: Joe Developer <joe.developer@gitlab.local>
Date:   Mon Nov 9 12:10:30 2020 +0000

    Initial commit

Module 5 - Submodules

Goals

  • Add a submodule to an existing repository.

  • Inspect the .gitmodules file.

  • Push changes to the repositories.

  • Clone a repository with submodules.

Add a submodule to repository

Create a new project submodule under the GitLab frontend. It will be used as the submodule repository for the following excercises.

submodule create new project

git submodule add

$ cd gitlab-project (1)
$ git submodule add ../../jdev/submodule  (2)
Cloning into '/home/jdev/var/tmp/gitlab-project/submodule'...
X11 forwarding request failed on channel 0
remote: Enumerating objects: 3, done.
remote: Counting objects: 100% (3/3), done.
remote: Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
Inspecting the repository’s status
$ git status
On branch master
Your branch is up to date with 'origin/master'.

Changes to be committed:
  (use "git restore --staged <file>..." to unstage)
        new file:   .gitmodules (1)
        new file:   submodule (2)
Inspecting the .gitmodules file
$ cat .gitmodules
[submodule "submodule"] (1)
        path = submodule (2)
        url = ../../jdev/submodule (3)
Inspecting the content of the submodule
$ cd submodule/
$ ls
README.md (1)
$ git log (2)
commit cebacd281a26b1f0503522eb4344dce1226b9383 (HEAD -> master, origin/master, origin/HEAD)
Author: Joe Developer <joe.developer@gitlab.local>
Date:   Mon Dec 7 22:52:04 2020 +0000

    Initial commit

Push with submodules

git push

Commit changes
$ git commit --all --message "Add submodule"
[master eb326f0] Add submodule
 2 files changed, 4 insertions(+)
 create mode 100644 .gitmodules
 create mode 160000 submodule
Push from master to branch add-submodule
$ git push origin master:add-submodule (1)
X11 forwarding request failed on channel 0
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 8 threads
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 363 bytes | 363.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for add-submodule, visit: (2)
remote:   http://gitlab.local:8480/jdev/gitlab-project/-/merge_requests/new?merge_request%5Bsource_branch%5D=add-submodule
remote:
To ssh://gitlab.local:8422/jdev/gitlab-project.git
 * [new branch]      master -> add-submodule (3)

Modify file content

Modify both README files
$ echo '## Now with submodule' >> README.md  (1)
$ echo "## I'm the submodule" >> submodule/README.md (2)
$ git status --short
 M README.md
 m submodule (3)
Commit and push the submodule first
$ cd submodule/  (1)
$ git commit -a -m "Add new content"
[master bec63ae] Add new content
 1 file changed, 1 insertion(+)

$ git push origin master:submodule (2)
Entering 'submodule'
X11 forwarding request failed on channel 0
Enumerating objects: 5, done.
Counting objects: 100% (5/5), done.
Writing objects: 100% (3/3), 268 bytes | 268.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for submodule, visit:
remote:   http://gitlab.local:8480/jdev/submodule/-/merge_requests/new?merge_request%5Bsource_branch%5D=submodule
remote:
To ssh://gitlab.local:8422/jdev/submodule
 * [new branch]      master -> submodule
submodule after merge 02
Figure 36. Repository submodule after merge
Commit and push the submodule first
$ cd .. (1)
$ git commit -a -m "Add submodule header"
[master 1a44056] Add submodule header
 1 file changed, 1 insertion(+), 1 deletion(-)

$ git push origin master:submodule (2)
X11 forwarding request failed on channel 0
Enumerating objects: 3, done.
Counting objects: 100% (3/3), done.
Delta compression using up to 8 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (2/2), 254 bytes | 254.00 KiB/s, done.
Total 2 (delta 1), reused 0 (delta 0), pack-reused 0
remote:
remote: To create a merge request for submodule, visit:
remote:   http://gitlab.local:8480/jdev/gitlab-project/-/merge_requests/new?merge_request%5Bsource_branch%5D=submodule
remote:
To ssh://gitlab.local:8422/jdev/gitlab-project.git
 * [new branch]      master -> submodule
submodule after merge 03
Figure 37. Repository gitlab-project after merge

Cloning with submodules

git clone

Recursive clone
$ git clone --recursive \
  http://gitlab.local:8480/jdev/gitlab-project.git \
  gitlab-project-with-submodules (1)
Cloning into 'gitlab-project-with-submodules'... (2)
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 23 (delta 10), reused 17 (delta 7), pack-reused 0
Unpacking objects: 100% (23/23), 2.46 KiB | 1.23 MiB/s, done.
Submodule 'submodule' (http://gitlab.local:8480/jdev/submodule) registered for path 'submodule'
Cloning into '/home/uroesch/var/tmp/gitlab-project-with-submodules/submodule'... (3)
warning: redirecting to http://gitlab.local:8480/jdev/submodule.git/
remote: Enumerating objects: 7, done.
remote: Counting objects: 100% (7/7), done.
remote: Compressing objects: 100% (3/3), done.
remote: Total 7 (delta 0), reused 0 (delta 0), pack-reused 0
Submodule path 'submodule': checked out 'bec63ae43dd9ad434af8dcb087900424616de102'
Non-recursive clone
$ git clone http://gitlab.local:8480/jdev/gitlab-project.git \
  gitlab-project-non-recursive (1)
Cloning into 'gitlab-project-non-recursive'...
remote: Enumerating objects: 23, done.
remote: Counting objects: 100% (23/23), done.
remote: Compressing objects: 100% (14/14), done.
remote: Total 23 (delta 10), reused 17 (delta 7), pack-reused 0
Unpacking objects: 100% (23/23), 2.46 KiB | 841.00 KiB/s, done.
$ cd gitlab-project-non-recursive (2)
$ git submodule update --recursive --init (3)
Cloning into '/home/uroesch/var/tmp/gitlab-project-non-recursive/submodule'...
warning: redirecting to http://gitlab.local:8480/jdev/submodule.git/
Submodule path 'submodule': checked out 'bec63ae43dd9ad434af8dcb087900424616de102'