DevOps
Getting Started with Git: A DevOps Perspective
Git is the version control system that underpins every modern DevOps workflow. It tracks every change to your code and infrastructure files, enables team collaboration through branching and merging, and triggers the automated pipelines that build, test, and deploy your applications. If you are starting a career in DevOps or cloud engineering, Git is one of the first tools you need to learn.
This guide covers Git from a DevOps perspective -- not just the commands, but why they matter, how they connect to CI/CD pipelines, and which practices separate professionals from beginners.
Why Git is the foundation of DevOps
Before version control, teams shared code by copying files between machines, emailing zip archives, or overwriting each other's changes on a shared drive. There was no history, no accountability, and no way to undo a mistake without manual backups.
Git changed that completely. Every change is recorded. Every change has an author, a timestamp, and a message explaining why it was made. You can view the complete history of any file, compare any two versions, and reverse any change.
But Git is not just a safety net for code. In DevOps, Git is the trigger for everything:
- A push to the main branch triggers a CI/CD pipeline that builds, tests, and deploys your application automatically.
- A pull request triggers automated tests and requires a code review before changes merge.
- Infrastructure as Code files (Terraform, Kubernetes manifests, Ansible playbooks) live in Git, so infrastructure changes go through the same review and automation process as application code.
- Configuration files for monitoring, alerting, and security policies are versioned in Git.
This concept -- treating everything as code and storing it in Git -- is called GitOps, and it is the standard operating model for modern DevOps teams. Without Git, there is no GitOps, no CI/CD, and no collaborative infrastructure management.
Core concepts
Git has a small number of core concepts. Understanding them clearly makes every command intuitive.
Repositories
A repository (repo) is a directory that Git tracks. It contains your project files plus a hidden .git folder that stores the complete history of every change. You can create a local repository on your machine or clone one from a remote service like GitHub or GitLab.
# Create a new repository
mkdir my-project && cd my-project
git init
# Clone an existing repository from GitHub
git clone https://github.com/your-org/your-project.git
Commits
A commit is a snapshot of your files at a specific point in time. Each commit has a unique ID (a SHA hash), an author, a timestamp, and a message describing what changed and why.
# Stage changes (tell Git which files to include in the next commit)
git add deploy.sh
git add config/nginx.conf
# Create a commit with a descriptive message
git commit -m "Add nginx reverse proxy configuration for API service"
Good commit messages describe the why, not just the what. "Update config" tells a reviewer nothing. "Add nginx reverse proxy to route /api traffic to port 3000" tells them exactly what changed and why.
Branches
A branch is a parallel version of your repository. The default branch is called main (or master in older repos). When you create a new branch, you get an independent copy of the code where you can make changes without affecting the main branch.
# Create a new branch and switch to it
git checkout -b feature/add-monitoring
# Make changes, commit them
git add prometheus.yml
git commit -m "Add Prometheus configuration for API metrics"
# Switch back to main
git checkout main
Branches are lightweight in Git -- creating one takes milliseconds. This is why branching is central to every Git workflow.
Merging
Merging combines changes from one branch into another. When your feature is complete and reviewed, you merge it into the main branch.
# Switch to main and merge the feature branch
git checkout main
git merge feature/add-monitoring
If two people edited the same lines in the same file, Git reports a merge conflict. You resolve it manually by choosing which version to keep (or combining both), then commit the resolution.
The staging area
Git has a staging area (also called the index) between your working directory and the repository. When you run git add, files move to the staging area. When you run git commit, the staged files are committed.
This two-step process lets you control exactly which changes go into each commit. You might have modified five files, but only three are related to the current task. You stage and commit those three, then deal with the other two separately.
Essential commands for daily DevOps work
These are the commands you will use every single day.
Setting up and configuring
# Set your identity (do this once per machine)
git config --global user.name "Your Name"
git config --global user.email "you@example.com"
# Set the default branch name to main
git config --global init.defaultBranch main
The daily workflow
# Check which files have changed
git status
# View the actual changes (line-by-line diff)
git diff
# Stage specific files
git add filename.tf
# Stage all changed files
git add .
# Commit with a message
git commit -m "Descriptive message about what and why"
# Push to the remote repository
git push origin main
# Pull the latest changes from the remote
git pull origin main
Viewing history
# View commit history
git log
# Compact single-line history
git log --oneline
# View who changed each line of a file
git blame deploy.sh
# View the changes in a specific commit
git show abc1234
Undoing mistakes
# Discard changes to a file (revert to last commit)
git checkout -- filename.tf
# Unstage a file (remove from staging area)
git reset HEAD filename.tf
# Undo the last commit but keep the changes
git reset --soft HEAD~1
# Completely undo the last commit and discard changes
git reset --hard HEAD~1
The ability to undo mistakes safely is one of Git's greatest strengths. With git log and git reset, you can always get back to a known good state.
Branching strategies for DevOps teams
How you use branches matters as much as knowing the commands. A good branching strategy keeps the main branch stable, enables parallel work, and integrates smoothly with CI/CD pipelines.
Feature branch workflow
The most common strategy. Every change gets its own branch.
- Create a branch from
main:git checkout -b feature/add-health-check - Make your changes and commit them
- Push the branch to the remote:
git push origin feature/add-health-check - Open a pull request on GitHub/GitLab
- Team reviews the changes, automated tests run
- Merge into
mainafter approval - Delete the feature branch
This workflow ensures no untested or unreviewed code reaches the main branch.
Trunk-based development
The preferred strategy for teams practising continuous deployment. Developers work on very short-lived branches (hours, not days) and merge back to main frequently.
Key principles:
- Short-lived branches -- merge within a day or two
- Small commits -- each commit is a logical, deployable unit
- Feature flags -- incomplete features are hidden behind flags, not long-lived branches
- Main is always deployable -- every commit to main passes all tests and can be released
Trunk-based development reduces merge conflicts, speeds up feedback loops, and aligns naturally with continuous integration.
Release branches (when needed)
Some teams maintain release branches for version-specific bug fixes:
main ----*----*----*----*----*---->
\ \
release/1.0 *---* \
\
release/2.0 *---*
This is less common in cloud-native DevOps, where continuous deployment from main is the norm. But it is still used for software distributed to customers (on-premise installations, mobile apps).
Git in CI/CD pipelines
Git is the trigger mechanism for CI/CD. Understanding this connection is essential for DevOps engineers.
How it works
- A developer pushes a commit or opens a pull request
- The Git hosting platform (GitHub, GitLab) sends a webhook notification to your CI/CD tool (Jenkins, GitHub Actions, GitLab CI)
- The CI/CD tool pulls the latest code from the repository
- It runs the pipeline: build, test, security scan, deploy
Here is a simplified GitHub Actions workflow that deploys on every push to main:
name: Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
uses: actions/checkout@v4
name: Build application
run: npm run build
name: Run tests
run: npm test
name: Deploy to production
run: ./scripts/deploy.sh
Every merge to main automatically triggers this pipeline. No manual steps. No "I forgot to deploy." The pipeline runs the same way every time, which is the entire point of automation.
Branch protection rules
In production environments, you protect the main branch so nobody can push to it directly:
- Require pull request reviews -- at least one approval before merging
- Require status checks -- all automated tests must pass
- Require up-to-date branches -- branch must be current with main before merging
- No force pushes -- prevents rewriting history on main
These rules enforce the DevOps principle that every change is reviewed, tested, and traceable.
Best practices
Write meaningful commit messages
# Bad
git commit -m "fix bug"
git commit -m "update"
git commit -m "changes"
# Good
git commit -m "Fix timeout in health check endpoint by increasing threshold to 30s"
git commit -m "Add rate limiting to API gateway (max 100 req/min per client)"
git commit -m "Remove deprecated v1 authentication endpoint"
A commit message is documentation. Six months from now, when someone runs git log to understand why a change was made, your message is the answer.
Commit often, push regularly
Small, frequent commits are easier to review, easier to revert, and create a clearer history. Do not wait until the end of the day to commit a massive change. Commit each logical step.
Never commit secrets
API keys, passwords, database credentials, and private certificates do not belong in Git. Once committed, they exist in the repository history forever (even if you delete the file later).
Use .gitignore to prevent accidental commits:
# .gitignore
.env
*.pem
*.key
credentials.json
For secrets that your application needs, use environment variables or a secrets manager like AWS Secrets Manager or HashiCorp Vault.
Use .gitignore from the start
Every repository should have a .gitignore file that excludes build artifacts, dependencies, and environment-specific files:
# Dependencies
node_modules/
vendor/
# Build output
dist/
build/
# Environment files
.env
.env.local
# OS files
.DS_Store
Thumbs.db
# IDE files
.vscode/
.idea/
Learn to resolve merge conflicts
Merge conflicts are normal. They happen when two people edit the same lines. Git marks the conflicting sections:
<<<<<<< HEAD
timeout: 30s
=======
timeout: 60s
>>>>>>> feature/increase-timeout
You decide which version to keep (or combine them), remove the markers, stage the file, and commit. Practising conflict resolution in a safe environment removes the fear factor when it happens in production.
Where to go from here
Git is a skill you refine through daily use. The commands in this guide cover what you need for the first months of DevOps work. As you progress, you will learn more advanced operations like rebasing, cherry-picking, and bisecting, but these are not required to be productive.
The tools that build on Git -- CI/CD pipelines, Terraform, Docker, and Kubernetes -- all assume you are comfortable with version control. Git is the common thread that connects every part of the DevOps toolchain.
Start by putting a personal project in Git today. Create a repository, make some changes, commit them, push to GitHub. Then create a branch, make more changes, open a pull request, and merge it. That single exercise teaches you 80% of what you will use daily.
Frequently Asked Questions
Ola
Founder, CloudPros
Building the most hands-on DevOps bootcamp for the AI era. 16 weeks of real infrastructure, real projects, real career outcomes.
