Git in CI/CD Pipelines: Jenkins, GitLab CI, GitHub Actions

What is CI/CD and why Git matters

Continuous Integration (CI) and Continuous Delivery (CD) are practices where code changes are automatically built, tested, and deployed. Git is the perfect version control backbone for these pipelines because every push can trigger a workflow. By integrating Git with CI/CD tools, you get immediate feedback, catch bugs early, and deliver features faster.

Key idea: Every Git event (push, pull request, tag) can automatically start a pipeline that builds, tests, and deploys your application. This is the foundation of modern DevOps.

Common CI/CD triggers from Git

Pipelines are usually triggered by specific Git actions:

  • Push to a branch – e.g., running tests on feature branches
  • Pull request / merge request – run validation before merging
  • Tag creation – often used to deploy to production
  • Scheduled runs – nightly builds based on the default branch

Jenkins + Git: classic automation

Jenkins is a self‑hosted automation server. It can poll your Git repository or use webhooks to trigger builds.

Example: Jenkins pipeline from a Jenkinsfile (stored in Git)

// Jenkinsfile (Declarative Pipeline)
pipeline {
    agent any

    stages {
        stage('Checkout') {
            steps {
                git 'https://github.com/user/my-app.git'
            }
        }
        stage('Build') {
            steps {
                sh 'npm install'
                sh 'npm run build'
            }
        }
        stage('Test') {
            steps {
                sh 'npm test'
            }
        }
    }
}

With this Jenkinsfile in the repository, Jenkins automatically fetches the code and runs the pipeline on every push.

GitHub Actions: workflows inside your repository

GitHub Actions uses YAML files stored in .github/workflows/. They are triggered by GitHub events.

Example: Run tests on every push

# .github/workflows/test.yml
name: CI Pipeline
on: [push, pull_request]

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
      - run: npm ci
      - run: npm test

actions/checkout is the official action that checks out your Git repository so the workflow can access it.

GitLab CI: integrated with GitLab

GitLab CI uses a .gitlab-ci.yml file in the repository root. Pipelines run on GitLab runners.

Example: Build and test with GitLab CI

# .gitlab-ci.yml
stages:
  - build
  - test

build-job:
  stage: build
  script:
    - echo "Compiling the code..."
    - make
  artifacts:
    paths:
      - bin/

test-job:
  stage: test
  script:
    - echo "Running tests..."
    - make test

Handling Git branches in pipelines

Most CI systems provide environment variables with the branch name, commit hash, and tag. You can conditionally run steps based on the branch.

# GitHub Actions – deploy only on main branch
on:
  push:
    branches: [ main ]

# GitLab CI – run deploy job only for tags
deploy:
  script: echo "Deploying..."
  only:
    - tags

Using Git commit information in builds

You can embed the Git commit hash into your application to know which version is running. Example with Node.js:

# GitHub Actions step
- name: Set commit hash
  run: echo "REACT_APP_COMMIT_HASH=${{ github.sha }}" >> .env

In the code you can then display process.env.REACT_APP_COMMIT_HASH.

Protecting branches with CI checks

Modern Git hosting platforms allow you to require CI checks to pass before merging a pull request. For example, in GitHub you can set up branch protection rules that require the “CI Pipeline” check to succeed.

Why it matters: This ensures that no broken code ever reaches the main branch – your CI pipeline acts as a safety gate.

Practical workflow: from commit to production

  1. Developer pushes code to a feature branch.
  2. CI pipeline runs tests and linting.
  3. If tests pass, the branch can be merged via pull request.
  4. Merging to main triggers a new pipeline that builds and deploys to a staging environment.
  5. After manual approval (or automatically if tests pass), the same artifact is deployed to production.

All steps are defined in Git and versioned together with the code.

Exercise: Which CI system uses a Jenkinsfile stored in Git?

Select the correct answer:
  • Jenkins (Pipeline from SCM)
  • GitHub Actions
  • GitLab CI
  • Travis CI

Frequently Asked Questions

Can I trigger a pipeline when a tag is pushed?

Absolutely. In GitHub Actions you use on: push: tags: - 'v*'. In GitLab CI: only: - tags. Jenkins can be configured via webhooks or polling to detect tag pushes.

What’s the difference between GitHub Actions and GitLab CI?

Both are YAML‑based and deeply integrated with their respective Git platforms. GitHub Actions is more focused on ecosystem integrations, while GitLab CI has a built‑in container registry and environments. The choice usually depends on where your code lives.

How do I prevent secrets (like API keys) from being exposed in CI logs?

Use secrets management: GitHub Secrets, GitLab CI variables, or Jenkins credentials. They are masked in logs. Never hardcode secrets in your Git repository.

Can I run a CI pipeline only for changes in a specific folder?

Yes. GitHub Actions supports on: push: paths: - 'backend/**'. GitLab CI has only: changes: - "frontend/*". This avoids running unnecessary builds.

Previous: Advanced Git Next: Monorepo Strategies