Git Fundamentals

Master version control with Git-- from basic commits and pushes to merge conflicts, rebasing, and branching strategies used in professional cloud engineering teams.

Git Fundamentals

Git was invented by Linus Torvalds in 2005 to manage the Linux kernel development process. Since then, it has become the most popular version control system in the world, used by millions of developers and organizations. Multiple platforms use some form of git (github, gitlab, bitbucket, etc.), with github being the most popular.

Version control is essential for modern software development and infrastructure management. It doesn't matter what you're working on, being able to track changes and collaborate with others is critical. This guide covers the Git fundamentals you need to work effectively in professional cloud engineering environments. You'll learn core concepts, essential commands, branching strategies, and how to handle common Git workflows and problems.


Why Cloud Engineers Need Git

Git is for anyone working on code. This can be software, infrastructure as code, even documentation. Keep a working history of your files, just in case you need to track changes or revert to an earlier version.

  • Track infrastructure as code: Terraform modules, Ansible playbooks, CloudFormation templates, and Helm charts.
  • Collaborate on projects: Work with team members on shared codebases without overwriting each other's changes. If a conflict arises, it's better to fix the merge conflict than overwrite someone else's code without realizing.
  • Review changes before deployment: Use pull requests and code reviews to catch errors before they reach production.
  • Rollback mistakes: If a deployment breaks, revert to a previous working state in seconds.
  • Automate deployments: Push and pull requests can trigger CI/CD pipelines when code is pushed to specific branches.
  • Audit changes: See who changed what, when, and why. This is critical for compliance and troubleshooting.

Core Git Concepts

Repositories

A repository (repo) is a project tracked by Git. It contains:

  • All your files (code, configs, docs)
  • A hidden .git directory storing the full history of changes
  • Metadata about commits, branches, and remote connections

Repos can be local (on your machine) or remote (on GitHub, GitLab, Bitbucket). You son't have to store your code on a remote, git is fully functional on your local machine.

Commits

A commit is a snapshot of your project at a specific point in time. Each commit has:

  • A unique ID (SHA hash like a3f4b2c)
  • An author and timestamp
  • A commit message describing the change
  • A pointer to the previous commit (forming a history chain)

Good commit messages are short but descriptive:

**Good**:
- Add VPC configuration for staging environment
- Fix S3 bucket policy to allow CloudFront access
- Update node scaling thresholds

**Bad**:
- update
- fix bug
- changes
- try1
- try2
- idk

Branches

A branch is an independent line of development. The default branch used to be master, now it's commonly main. You create branches to:

  • Work on features without affecting production code
  • Test changes in isolation
  • Collaborate on separate tasks simultaneously

Common branching patterns:

  • main or master: Production-ready code
  • dev or develop: Integration branch for ongoing work
  • feature/<feature name>: New feature branch
  • hotfix/<hotfix name>: Urgent production fix
  • Sometimes release/<release name>: for when only specific changes are needed for a release

Merging

Merging combines changes from one branch into another. For example:

  1. Create a feature branch: git checkout -b feature/new-vpc
  2. Make changes and commit
  3. Merge back into main: git checkout main && git merge feature/new-vpc

If there are changes to the same lines of code on both branches, you'll get a merge conflict that must be resolved manually.

Remote Repositories

Remotes are versions of your repo hosted on a server (GitHub, GitLab, Bitbucket). Common commands:

  • git clone <url>: Copy a remote repo to your local machine
  • git fetch: Download remote changes without merging
  • git pull: Download and merge remote changes
  • git push: Upload local commits to a remote repo

Essential Git Commands

Setting Up Git

# Configure your name and email (appears in commits)
git config --global user.name "Your Name"
git config --global user.email "you@example.com"

# Check your configuration
git config --list

# Set default branch name to 'main'
git config --global init.defaultBranch main

# Set default editor (optional)
git config --global core.editor "nano"

Creating and Cloning Repositories

# Create a new Git repo in current directory
git init

# Clone an existing repo
git clone https://github.com/username/repo.git

# Clone into a specific folder
git clone https://github.com/username/repo.git my-folder

Making Changes

Most modern IDEs (VSCode, PyCharm, etc.) have built-in Git support. You can stage and commit changes directly from your editor. At first, it can be easier to just point and click, but it's beneficial to learn what you're doing by typing the commands when you're getting started.

# Check status (shows modified, staged, untracked files)
git status

# Stage a file for commit
git add filename.txt

# Stage all changes
git add .

# Commit staged changes
git commit -m "Add Terraform config for VPC"

# Stage and commit in one step (for tracked files only)
git commit -am "Update security group rules"

# View commit history
git log
git log --oneline  # compact view
git log --graph --oneline --all  # visual branch history

git log --oneline is a great way to find a specific commit by its hash. If you want to revert to an earlier version, finding that commit's hash is the first step.

Viewing Changes

# Show unstaged changes
git diff

# Show staged changes
git diff --staged

# Show changes in a specific commit
git show a3f4b2c

# Compare two branches
git diff main feature/new-vpc

Branching and Merging

# List all branches
git branch

# Create a new branch
git branch feature/monitoring

# Switch to a branch
git checkout feature/monitoring

# Create and switch in one command
git checkout -b feature/logging

# Merge a branch into current branch
git merge feature/monitoring

# Delete a branch
git branch -d feature/monitoring

Undoing Changes

# Discard unstaged changes to a file
git checkout -- filename.txt

# Unstage a file (keep changes)
git reset HEAD filename.txt

# Undo last commit (keep changes staged)
git reset --soft HEAD~1

# Undo last commit (discard changes)
git reset --hard HEAD~1

# Revert a commit (creates a new commit that undoes changes)
git revert a3f4b2c

If you want to reset to a specific commit, you can use git reset --hard <commit hash>. From there, you can git push -f to force push the changes to the remote repository and overwrite the newer commits.


Git Workflows for Cloud Engineering

Feature Branch Workflow

This is a sample workflow to create an "add monitoring" branch.

  1. Start from main: git checkout main && git pull
  2. Create a feature branch: git checkout -b feature/add-monitoring. There are multiple ways to accomplish this, git checkout -b, git switch -c, and git branch -c all create a new branch.
  3. Make changes and commit: git add . && git commit -m "Add Prometheus config"
  4. Push to remote: git push -u origin feature/add-monitoring
  5. Open a pull request (PR) on GitHub/GitLab
  6. After review, merge into main
  7. Delete the feature branch: git branch -d feature/add-monitoring

GitFlow Workflow

More structured, common in larger teams:

  • main: Production code
  • develop: Integration branch
  • feature/*: New features (branch off develop, merge back into develop)
  • release/*: Prepare for production release
  • hotfix/*: Urgent production fixes (branch off main, merge back into main and develop)

Trunk-Based Development

Simplified workflow for fast-moving teams:

  • Everyone commits to main frequently (multiple times per day)
  • Feature flags control incomplete features
  • CI/CD runs on every commit
  • Minimal long-lived branches

Handling Merge Conflicts

Conflicts happen when two branches modify the same lines. Git marks conflicts in the file:

<<<<<<< HEAD
resource "aws_instance" "web" {
  instance_type = "t3.medium"
=======
resource "aws_instance" "web" {
  instance_type = "t3.large"
>>>>>>> feature/update-instance-type

To resolve:

  1. Open the file in an editor
  2. Choose which change to keep (or combine them)
  3. Remove conflict markers (<<<<<<<, =======, >>>>>>>)
  4. Stage the file: git add filename.tf
  5. Commit the resolution: git commit -m "Resolve instance type conflict"

Use a merge tool for complex conflicts:

git mergetool

Best Practices for Cloud Engineering

Commit Small, Logical Changes

Each commit should represent a single logical change. Avoid:

  • Mixing unrelated changes in one commit
  • Committing broken code
  • Giant commits with 50+ file changes

Use .gitignore

Exclude files that shouldn't be tracked:

# .gitignore example
*.tfstate
*.tfstate.backup
.terraform/
*.pem
*.key
.env
node_modules/
__pycache__/
*.log

Never Commit Secrets

Never commit:

  • API keys
  • Passwords
  • Private keys
  • Access tokens

Use environment variables, secret managers (AWS Secrets Manager, Azure Key Vault, HashiCorp Vault), or .env files (add to .gitignore). Keep in mind that if you have a .env file with your sensitive values, you will NOT have access to it when you push to GitHub or clone to a new workspace. Every single workspace will need access to the secrets.

If you accidentally commit a secret:

  1. Immediately rotate the credential
  2. Remove it from Git history (use git filter-branch or BFG Repo-Cleaner)
  3. Force-push to remote (NOTE: disrupts team)

Review Changes Before Committing

# Always check what you're about to commit
git status
git diff

# Stage carefully
git add -p  # interactively stage changes

Pull Before You Push

Always pull remote changes before pushing to avoid conflicts:

git pull origin main
# Resolve any conflicts
git push origin main

Use Tags for Releases

Tag production releases for easy reference:

git tag -a v1.2.0 -m "Release version 1.2.0"
git push origin v1.2.0

Integrating Git with Cloud Workflows

Infrastructure as Code

Store Terraform, CloudFormation, or Pulumi configs in Git:

infrastructure/
├── environments/
│   ├── prod/
│   ├── staging/
│   └── dev/
├── modules/
│   ├── vpc/
│   ├── eks/
│   └── rds/
└── README.md

CI/CD Pipelines

Trigger deployments on Git events:

  • Push or merge to main -> deploy to production
  • Push or merge to develop -> deploy to staging
  • Open PR -> run tests and linting

Example GitHub Actions workflow:

name: Deploy to AWS
on:
  push:
    branches: [main]
jobs:
  deploy:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v2
      - name: Configure AWS credentials
        uses: aws-actions/configure-aws-credentials@v1
      - name: Deploy with Terraform
        run: |
          terraform init
          terraform apply -auto-approve

GitOps

Entire system state defined in Git. Tools like ArgoCD or Flux continuously sync Git with Kubernetes clusters. Changes to Git automatically update production.


Common Git Problems and Solutions

Problem: "I committed to the wrong branch"

# Move last commit to another branch
git branch feature/my-feature  # create branch at current commit
git reset --hard HEAD~1  # undo commit on current branch
git checkout feature/my-feature  # switch to new branch

Problem: "I need to undo a pushed commit"

# Revert creates a new commit that undoes changes
git revert a3f4b2c
git push origin main

Problem: "My branch is behind remote"

# Fetch remote changes
git fetch

# Merge remote changes
git pull origin main

# Or rebase (cleaner history but rewrites commits)
git pull --rebase origin main

Problem: "I want to discard all local changes"

# Discard all unstaged changes
git checkout -- .

# Reset to match remote
git fetch origin
git reset --hard origin/main

Problem: "I accidentally committed a large file"

# Remove from last commit
git rm --cached large-file.zip
git commit --amend -m "Remove large file"
git push --force

Learning Path: From Basics to Mastery

  1. First: Set up Git, create a repo, make commits. Practice add, commit, status, log.
  2. Second: Learn branching. Create feature branches, merge them, resolve a simple conflict.
  3. Third: Connect to GitHub/GitLab. Clone, push, pull, and open a pull request.
  4. Fourth: Practice real workflows. Manage a Terraform project with Git, simulate team collaboration.
  5. Fifth: Learn advanced commands: rebase, cherry-pick, stash, reflog.

Another good way to start is find a small public repo, clone it locally, and practice the commands on it. You can find some here: https://github.com/trending


Practical Exercises

  1. Initialize a repo: Create a Git repo for a Terraform project. Make commits for VPC, subnets, and security groups.
  2. Branching practice: Create a feature branch, make changes, merge into main, and resolve a conflict.
  3. Collaborate on GitHub: Fork a public repo, make changes, open a pull request.
  4. Simulate a rollback: Make a breaking change, commit, push, then use git revert to undo it.
  5. Set up CI/CD: Create a GitHub Actions workflow that runs terraform validate on every push.

This needs to become routine. Some skills are "nice to have", this is an absolute "must have".


The Bottom Line: Git Is Essential

Every professional cloud engineer uses Git. Things break all the time, and when that happens, you need to be able to fix it. That's what we use Git for. If you're working on a team that's pushing changes, you need to understand Git in order to be a basic member of the team. You can't just make your code changes, push them, and hope for the best. Use a proper branching strategy and make sure you're not overwriting other people's code.

For more cloud engineering guidance, check out what does a cloud engineer do and how to get a cloud engineering job with no experience.

← Back to Insights