Imagine your team is building a web application. You have five developers, all writing code on their own laptops. Without a central system, chaos happens fast — two people edit the same file and one overwrites the other, nobody knows who changed what, deploying to the server means manually copying files and hoping nothing breaks, and testing only happens when someone remembers to do it manually. GitLab solves all of this in one place. It is a complete platform where your code lives, your team collaborates, your tests run automatically, and your deployments happen consistently — without manual work. At its core, GitLab is a **Git repository hosting platform** — it stores your code and the complete history of every change ever made. But it goes far beyond storage. It connects version control, code review, issue tracking, automated testing, and deployment into a single workflow. ``` Developer writes code on their laptop ↓ Pushes to GitLab (code stored and versioned safely) ↓ GitLab automatically runs tests (catches bugs immediately) ↓ Team reviews the code in a Merge Request ↓ Code is merged → GitLab deploys it automatically ↓ Production updated — safely, consistently, with full audit trail ``` GitLab was founded by **Dmitriy Zaporozhets and Valery Sizov in October 2011**. It is open-source (Community Edition) and can be installed on your own servers — one of its biggest advantages over alternatives. --- ### GitLab vs GitHub vs Bitbucket All three host Git repositories. The differences matter when choosing the right tool for your team. | Feature | GitHub | GitLab | Bitbucket | |---|---|---|---| | Best known for | Open source community | DevOps, self-hosting | Atlassian/Jira ecosystem | | Self-hosting | Paid (Enterprise) | Free (Community Edition) | Paid (Server) | | CI/CD | GitHub Actions | Built-in (no extra tool) | Bitbucket Pipelines | | Container Registry | Yes (GHCR) | Yes (built-in) | No | | Unlimited private repos | Free (limited features) | Free | Free (limited) | | Review Apps | Needs custom setup | Native built-in feature | No | | Best for | Open source, Microsoft ecosystem | Full DevOps control | Teams using Jira | **Choose GitLab when:** - Your team needs full control over where code lives (compliance, security) - You want CI/CD, registry, and issue tracking without stitching tools together - You are self-hosting on your own infrastructure - You need unlimited private repositories for free --- ### GitLab Editions | Edition | Cost | Who Uses It | |---|---|---| | GitLab.com Free | Free | Individuals, open source, learning | | GitLab.com Premium | Paid per user | Teams needing advanced CI/CD | | GitLab.com Ultimate | Paid per user | Enterprise security and compliance | | Community Edition (CE) | Free, self-hosted | Organizations wanting full control | | Enterprise Edition (EE) | Paid, self-hosted | Enterprises with compliance needs | > **Start here:** Create a free account at gitlab.com. You get unlimited private repos, CI/CD pipelines with 400 free minutes/month, and a container registry. No installation needed. --- ### How GitLab Fits into DevOps GitLab is not just a code storage tool. It is the trigger point for your entire delivery pipeline. Every push, every merged request, every new tag fires events that other tools react to. ``` Code pushed to GitLab ↓ GitLab CI runs: tests → build → Docker image → security scan ↓ Image pushed to GitLab Container Registry ↓ ArgoCD or Flux detects new image tag ↓ Kubernetes rolls out the update ↓ Prometheus monitors health, Grafana shows metrics ↓ Team notified in Slack: deployment complete ``` Master GitLab and you master the starting point of every modern DevOps pipeline. ---
GitLab is built on top of Git. You cannot use GitLab effectively without understanding Git first. This section covers exactly what you need — no more, no less. Git is a system that tracks every change to your files. Every time you save a snapshot (called a **commit**), Git records what changed, who changed it, and when. You can go back to any previous state, compare any two versions, and work on multiple versions simultaneously using branches. --- ### The Three States of Git Every file in a Git project is always in one of three states. This is the most important concept to understand. ``` Working Directory Staging Area Repository ───────────────── ──────────── ────────── You edit files here → git add stages → git commit saves chosen changes permanent snapshot ``` | State | What It Means | |---|---| | **Modified** | You changed the file — Git sees the difference but has not recorded it | | **Staged** | You ran `git add` — Git has queued this change for the next commit | | **Committed** | The snapshot is permanently saved in Git history | The staging area exists so you can craft precise commits. If you changed 10 files but only 3 belong together logically, stage those 3 and commit them as one unit. The other 7 wait. --- ### The .git Folder — What It Actually Is When you run `git init`, Git creates a hidden `.git` folder in your project. This folder **is** the repository. Everything Git knows — all history, all branches, all commits — lives here. ``` .git/ ├── HEAD → points to your current branch ├── config → repo-level git configuration ├── objects/ → all your commits and file snapshots stored compressed ├── refs/ │ ├── heads/ → one file per branch, containing the latest commit SHA │ └── tags/ → version tags └── hooks/ → scripts that fire on git events (pre-commit, post-push, etc.) ``` Never manually edit or delete `.git/`. Deleting it loses all history permanently — your project files stay but every commit disappears. --- ### Core Git Workflow This is the loop you repeat every working day. ```bash # Check what has changed since the last commit git status # See exact line-by-line changes git diff # unstaged changes git diff --staged # staged changes ready to commit # Stage changes git add . # stage everything git add src/server.js # stage one specific file git add -p # interactively choose which chunks to stage # Commit the snapshot git commit -m "feat: add healthcheck endpoint" # See history git log --oneline # compact one-line per commit git log --oneline --graph --all # visual branch graph — use this daily ``` --- ### Writing Good Commit Messages A commit message is a note to your future self — or to the engineer debugging this at 2am six months from now. **Useless messages:** ``` update fix wip changes asdfgh ``` **Useful messages:** ``` feat: add retry logic to the email delivery service fix: prevent crash when config file is missing on startup chore: upgrade postgres driver to v4.8 for security patch docs: add runbook for rotating API credentials refactor: extract notification logic into separate module ``` ### Conventional Commits Standard Most teams use this format: `type: short description` | Type | When to Use | |---|---| | `feat` | New feature or capability | | `fix` | Bug fix | | `chore` | Maintenance, dependency updates, config changes | | `docs` | Documentation only | | `refactor` | Code restructure — no behavior change | | `test` | Adding or fixing tests | | `ci` | Pipeline changes | | `perf` | Performance improvement | Tools like `semantic-release` read these prefixes to automatically generate changelogs and bump version numbers. --- ### Branches — What and Why A branch is an independent line of development. The default is `main`. When you work on a feature or fix, you create a branch — your changes cannot affect `main` until you deliberately merge. ``` main: A ── B ── C ──────────────── G ← merge commit \ / feat/login: D ── E ── F ── ``` Ten engineers on ten branches simultaneously — no one steps on each other. When features are complete, they merge through review one at a time. ```bash # Create and switch to a new branch git checkout -b feat/user-login git switch -c feat/user-login # modern syntax — same result # List branches git branch # local branches git branch -a # all including remote # Switch branches git checkout main git switch main # Delete a branch after merging git branch -d feat/user-login # safe delete git branch -D feat/user-login # force delete git push origin --delete feat/user-login # delete from GitLab too ``` **Branch naming conventions:** ``` feat/payment-gateway-integration fix/null-pointer-in-worker-pool hotfix/critical-auth-vulnerability chore/upgrade-to-node-20 release/v2.4.0 ``` ---
### Option 1 — GitLab.com (Start Here) Go to `https://gitlab.com`, create a free account, and you are ready. This is how most people start — no servers to manage, no installation needed. Everything in this guide works on gitlab.com. --- ### Option 2 — Self-Hosted on Ubuntu The Omnibus package is the recommended way to install GitLab on your own server. It bundles everything GitLab needs — Ruby, PostgreSQL, Redis, Nginx — into one installer. You do not install these separately. ```bash # Step 1 — Install dependencies sudo apt-get update sudo apt-get install -y curl openssh-server ca-certificates postfix # postfix handles GitLab's email notifications # Step 2 — Add the GitLab package repository curl https://packages.gitlab.com/install/repositories/gitlab/gitlab-ce/script.deb.sh | sudo bash # Step 3 — Install GitLab Community Edition # Replace your-server-ip with your actual server IP or domain sudo EXTERNAL_URL="http://your-server-ip" apt-get install gitlab-ce # Step 4 — Apply configuration and start all services sudo gitlab-ctl reconfigure # Step 5 — Verify everything is running sudo gitlab-ctl status ``` Open your browser at `http://your-server-ip`. On first visit, GitLab prompts you to set the `root` admin password. **Managing your GitLab server:** ```bash sudo gitlab-ctl reconfigure # apply config changes from /etc/gitlab/gitlab.rb sudo gitlab-ctl restart # restart all GitLab services sudo gitlab-ctl stop # stop GitLab completely sudo gitlab-ctl start # start GitLab sudo gitlab-ctl status # check status of every service sudo gitlab-ctl tail # watch all logs in real time ``` --- ### GitLab Runner Setup The GitLab Runner is the agent that executes your CI/CD pipeline jobs. Without a runner, pipelines queue but never run. **On Ubuntu:** ```bash # Install the runner curl -L "https://packages.gitlab.com/install/repositories/runner/gitlab-runner/script.deb.sh" | sudo bash sudo apt-get install gitlab-runner # Register the runner sudo gitlab-runner register # It asks: # URL: https://gitlab.com # Token: from Project → Settings → CI/CD → Runners # Description: my-ubuntu-runner # Tags: linux, docker # Executor: docker # Default image: alpine:latest # Start as a background service sudo gitlab-runner start sudo gitlab-runner status ``` **On Windows:** ```bash # Step 1 — Create a folder mkdir C:\DevOps\GitLab-Runner # Step 2 — Download the runner binary for amd64 # Rename downloaded file to gitlab-runner.exe # Step 3 — Register from Command Prompt in that folder gitlab-runner.exe register # Same prompts as Ubuntu above # Step 4 — Install and start as a Windows service gitlab-runner.exe install gitlab-runner.exe start ``` ---
SSH keys let you authenticate with GitLab without entering a password every time you push or pull. Set this up once and you never need credentials again. ### How SSH Authentication Works You generate a pair of mathematically linked keys. The **private key** stays on your machine and never leaves. The **public key** goes on GitLab. When you connect, your machine proves it has the private key without ever sending it. GitLab checks against the stored public key — match means you are in. ``` Your Machine GitLab ──────────────── ────────────────────── Private key (stays here) → Public key (stored in your account) Proves identity without Verifies without knowing the private key ever sending the key ``` --- ### Generating and Adding Your Key ```bash # Step 1 — Generate a key pair (run once per machine) ssh-keygen -t ed25519 -C "you@yourcompany.com" # -t ed25519 = modern, secure algorithm # -C = comment label (your email by convention) # Press Enter to accept default save location # Optionally set a passphrase for extra security # Two files are created: # ~/.ssh/id_ed25519 → PRIVATE key — never share this with anyone # ~/.ssh/id_ed25519.pub → PUBLIC key — this goes on GitLab # Step 2 — View and copy your public key cat ~/.ssh/id_ed25519.pub # Copy the entire output line ``` **Add to GitLab:** 1. Click your profile picture (top right) → **Preferences** 2. Left sidebar → **SSH Keys** 3. Paste your public key into the Key field 4. Give it a title like "Work Laptop" 5. Click **Add key** ```bash # Step 3 — Test the connection ssh -T git@gitlab.com # Expected: Welcome to GitLab, @yourusername! # Step 4 — Clone using SSH from now on git clone git@gitlab.com:username/project-name.git ``` ---
### Creating a New Project 1. Click **+** in the top navigation → **New project** 2. Choose your creation method: - **Blank project** — start from scratch - **Create from template** — use a pre-built structure (Rails, Node.js, Spring, etc.) - **Import project** — bring in from GitHub, Bitbucket, or another GitLab 3. Fill in project name, optional description, and visibility level 4. Optionally initialize with README, .gitignore, and License 5. Click **Create project** **Visibility levels:** | Level | Who Can See It | |---|---| | Private | Only you and invited members | | Internal | Any logged-in user on that GitLab instance | | Public | Anyone on the internet, no account needed | --- ### Pushing an Existing Local Project to GitLab If you already have a project on your machine: ```bash cd your-project/ git init git add . git commit -m "Initial commit" # Connect to GitLab git remote add origin git@gitlab.com:username/project-name.git # Push — -u sets upstream tracking so future pushes just need "git push" git push -u origin main ``` --- ### Cloning a Project ```bash # Clone via SSH (preferred — no password prompts) git clone git@gitlab.com:username/project-name.git # Clone via HTTPS (needs token or password) git clone https://gitlab.com/username/project-name.git cd project-name ``` --- ### Adding a File **Via Command Line:** ```bash # Navigate into your project cd project-name # Create a new file touch deployment-notes.md # Add content echo "# Deployment Notes" >> deployment-notes.md # Stage, commit, push git add deployment-notes.md git commit -m "docs: add deployment notes file" git push origin main ``` **Via GitLab Web UI:** 1. Go to your project on GitLab 2. Click the **+** button next to the branch selector 3. Select **New file** 4. Enter the filename and write your content 5. Write a commit message at the bottom 6. Click **Commit changes** Both methods result in the same thing — a new file committed to your repository. The web UI is convenient for quick edits without needing your local machine. ---
A fork is your own independent copy of someone else's repository, living in your GitLab account. You can make any changes in your fork without affecting the original. **When you need a fork:** - Contributing to a project you do not have write access to - Experimenting with someone else's code without risk - Using a project as a starting point for your own work ### Fork Workflow Step by Step ``` Original project (you have no write access) ↓ click Fork Your fork on GitLab (you own this — work freely) ↓ clone Your local machine ↓ create branch, make changes, push Your fork on GitLab ↓ open Merge Request back to original Original project reviews and merges your contribution ``` **In GitLab:** 1. Open any project → click the **Fork** button (top right area) 2. Choose your namespace (your account or a group) 3. Click **Fork project** 4. Clone your fork locally: ```bash git clone git@gitlab.com:your-username/project-name.git cd project-name # Add the original project as "upstream" so you can pull future updates git remote add upstream git@gitlab.com:original-owner/project-name.git # Verify your remotes git remote -v # origin git@gitlab.com:your-username/project-name.git # upstream git@gitlab.com:original-owner/project-name.git ``` ### Keeping Your Fork Updated ```bash # Get the latest changes from the original project git fetch upstream # Merge them into your main branch git checkout main git merge upstream/main # Push the updated main to your fork git push origin main ``` Do this regularly so your fork does not fall far behind the original. ---
Imagine your team is building a web application. You have five developers, all writing code on their own laptops. Withou...
GitLab is built on top of Git. You cannot use GitLab effectively without understanding Git first. This section covers ex...
Option 1 — GitLab.com (Start Here) Go to https://gitlab.com, create a free account, and you are ready. This is how most ...
SSH keys let you authenticate with GitLab without entering a password every time you push or pull. Set this up once and ...
Creating a New Project Click + in the top navigation → New project Choose your creation method: Blank project — start fr...
A fork is your own independent copy of someone else's repository, living in your GitLab account. You can make any change...
Creating Branches --- Protected Branches — The Most Important Workflow Concept In professional teams, nobody pushes dire...
What Rebase Does Rebase is a way to integrate changes from one branch into another by replaying your commits on top of t...
Why Squash During development you naturally make many small commits: "add form", "fix validation", "fix validation again...
User Permission Levels GitLab has five permission levels. Every project member is assigned exactly one role. Permission ...
GitLab has a full built-in issue tracker — no need for Jira or Trello for most teams. Everything stays in the same place...
Creating a Backup The secrets file — the most important thing to back up separately: The backup command does NOT include...
What you will learn in this Part What CI and CD actually mean and why exit codes are the mechanic that makes everything ...
Before writing a single line of YAML, you need to understand what problem CI/CD actually solves. If you skip this, pipel...
Every GitLab pipeline is defined in a single file called .gitlab-ci.yml placed at the root of your repository — the same...
A runner is the agent that picks up jobs from the pipeline queue and executes them. Without a runner, your pipeline show...
Variables pass configuration values and secrets into your pipeline jobs. Never hardcode passwords, API keys, SSH keys, o...
Who can do what in CI/CD Action Guest Reporter Developer Maintainer Owner See pipeline status ✓ ✓ ✓ ✓ ✓ Download artifac...
This is where most of the complexity in real pipelines lives. You do not want every job running on every push. You want ...
By default, every job in stage 3 waits for every job in stage 2 to finish, which waits for every job in stage 1. This cr...
These two features are often confused because they both involve saving files. They serve completely different purposes. ...
Environments give you visibility into where your application is deployed and what version is running. They also give you...
Scheduled pipelines — running on a timer Run pipelines automatically on a schedule without anyone pushing code. Perfect ...
GitLab includes a Docker image registry for every project. Your images live in the same place as your code. No Docker Hu...
Cycle Analytics measures exactly how long each phase of your development process takes — from the moment an issue is cre...
GitLab CI/CD GitHub Actions Config file .gitlab-ci.yml .github/workflows/.yml Trigger syntax rules: and workflow: on: Pa...
Job stuck in pending forever — Runner tags do not match. Check Project → Settings → CI/CD → Runners. The runner you expe...
These topics exist and are worth knowing about, but do not try to learn them before the rest of Part 2 is solid. They ar...
This lab builds a real project with a complete CI/CD pipeline from scratch. Every step is explained. By the end you will...
Aligns directly with DevOps, Site Reliability (SRE), and Platform Engineering job descriptions.