devops

Git & Team Workflows

Git internals, branching strategies, merge vs rebase, PR etiquette, and commit hygiene


Git Internals (Commit Tree Concept)

Git stores your project as a DAG (Directed Acyclic Graph) of commits. Each commit is a snapshot β€” not a diff.

o--o--o--o (main)
\
o--o (feature-branch)

Object Types

Git stores everything as objects in .git/objects/:

ObjectWhat it stores
blobFile contents
treeDirectory listing (points to blobs + other trees)
commitSnapshot metadata (tree + parent + author + message)
tagNamed reference to a commit
Terminal window
# Inspect a commit
git cat-file -p HEAD
# Inspect the tree at HEAD
git cat-file -p HEAD^{tree}
# See what objects exist
git fsck
# See where HEAD points
cat .git/HEAD
cat .git/refs/heads/main

What git commit Actually Does

  1. Hashes all changed files β†’ creates blob objects
  2. Creates tree objects (directories)
  3. Creates a commit object pointing to the root tree + parent commit
  4. Moves HEAD (and current branch ref) to new commit SHA

Branching Strategies

Trunk-Based Development

Everyone commits to main (the β€œtrunk”) frequently β€” multiple times per day. Feature flags control what’s exposed to users.

main: o--o--o--o--o--o--o (continuous commits)
↑feature flags↑

Pros: Fast integration, no long-lived branches, mirrors CI/CD best practices Cons: Requires feature flags, discipline, and good test coverage Used by: Google, Facebook, Netflix

Feature Branch Workflow (GitFlow-lite)

Developers work on branches, merge via PRs, branches are short-lived.

main: o-----------o-----------o
↑PR ↑PR
feature1: o---o
feature2: o---o---o

Pros: Isolated work, code review via PRs, easy rollback Cons: Integration hell if branches are long-lived Used by: Most teams

GitFlow (Full)

Has main, develop, feature/*, release/*, hotfix/* branches.

Verdict: Overcomplicated for most teams. Use trunk-based or simple feature branches instead.


Merge vs Rebase (When & Why)

git merge

Creates a merge commit β€” a commit with two parents. Preserves full history.

Before:
main: A--B--C
feature: D--E
After git merge:
main: A--B--C--M (M = merge commit)
/
feature: D--E
Terminal window
git checkout main
git merge feature-branch
# Merge without fast-forward (always creates merge commit)
git merge --no-ff feature-branch

Use merge when: You want to preserve the exact history of when branches diverged and merged.

git rebase

Moves your commits to apply after the target branch. Creates a linear history.

Before:
main: A--B--C
feature: D--E
After git rebase main:
main: A--B--C
feature: D'--E' (new commits, same changes)
Terminal window
git checkout feature-branch
git rebase main
# Interactive rebase β€” rewrite history
git rebase -i HEAD~3 # rewrite last 3 commits

Use rebase when: You want a clean, linear history. Common pattern: rebase locally before opening a PR.

Merge vs Rebase Decision

SituationUse
Merging a feature PR to mainMerge (preserve PR history)
Keeping feature branch up-to-date with mainRebase (cleaner)
Fixing up commits before PRInteractive rebase
Public/shared branchNEVER rebase (rewrites history)

Golden rule: Never rebase commits that have been pushed to a shared branch.


Conflict Resolution

Terminal window
# When a merge/rebase has conflicts:
# 1. Git marks conflicted files
git status # shows "both modified: file.txt"
# 2. Edit conflicted files β€” look for markers:
# <<<<<<< HEAD
# your version
# =======
# their version
# >>>>>>> feature-branch
# 3. Mark resolved
git add file.txt
# 4. Complete the merge/rebase
git merge --continue
# or
git rebase --continue
# To abort and go back to before
git merge --abort
git rebase --abort

GitHub / GitLab / Bitbucket

Key Concepts

ConceptDescription
ForkYour own copy of someone else’s repo
Pull Request (PR)Request to merge your branch into another
Merge Request (MR)GitLab’s name for PR
IssueTracked bug/feature request
Protected branchBranch that requires PR + review to merge
CI/CD checksAutomated tests that must pass before merge
Terminal window
# GitHub CLI β€” work with PRs from terminal
gh pr create --title "Add logging" --body "Adds structured logging"
gh pr list
gh pr view 42
gh pr merge 42 --squash
# Clone via HTTPS or SSH
git clone https://github.com/user/repo.git
git clone git@github.com:user/repo.git

PR Review Etiquette

As the Author

  • Keep PRs small and focused (< 400 lines when possible)
  • Write a clear description: what changed and why
  • Add screenshots for UI changes
  • Self-review before requesting review
  • Respond to all comments before merging
  • Don’t leave reviewer guessing β€” explain non-obvious choices

As the Reviewer

  • Review within agreed SLA (usually same day or next day)
  • Distinguish blocking issues from suggestions:
    • nit: = cosmetic, non-blocking
    • suggestion: = nice to have
    • (no prefix) = blocking
  • Ask questions rather than demanding changes: β€œWhat do you think about…?” vs β€œChange this”
  • Approve when ready β€” don’t leave PRs in limbo

Commit Hygiene

Good Commit Messages

# Format: <type>(<scope>): <short description>
#
# Types: feat, fix, docs, style, refactor, test, chore, ci
# Scope: optional, e.g. (auth), (api), (deploy)
feat(auth): add JWT token refresh endpoint
Add POST /auth/refresh that accepts a valid refresh token
and returns a new access + refresh token pair.
Closes #142

Conventional Commits standard:

TypeWhen to use
featNew feature
fixBug fix
docsDocumentation only
refactorCode change without new feature or fix
testAdding or fixing tests
choreBuild process, dependency updates
ciCI/CD pipeline changes
perfPerformance improvement

Useful Git Commands for Clean History

Terminal window
# Amend last commit (message or files) β€” only if not pushed
git commit --amend
# Squash last N commits interactively
git rebase -i HEAD~3
# In the interactive editor, change "pick" to:
# s / squash = combine with previous commit
# f / fixup = combine but discard this commit message
# r / reword = keep commit but edit message
# d / drop = delete this commit
# Unstage a file
git restore --staged file.txt
# Discard changes in working directory
git restore file.txt
# Move changes to stash
git stash
git stash pop
git stash list

Tagging & Releases

Terminal window
# Create a lightweight tag
git tag v1.2.3
# Create an annotated tag (with message β€” use this for releases)
git tag -a v1.2.3 -m "Release version 1.2.3"
# Push tags to remote
git push origin v1.2.3
git push origin --tags # push all tags
# List tags
git tag -l
git tag -l "v1.*"
# Delete tag
git tag -d v1.2.3
git push origin --delete v1.2.3

Semantic versioning (semver): MAJOR.MINOR.PATCH

  • MAJOR: breaking changes
  • MINOR: new features, backward compatible
  • PATCH: bug fixes, backward compatible

README Writing (Engineering Communication)

A good README is the first thing a new team member reads. Treat it like documentation that will be read at 2am when things are broken.

Structure

# Project Name
One sentence describing what this does.
## Quick Start
The minimum steps to get it running locally.
## Prerequisites
What you need installed before starting.
## Configuration
Environment variables and their meanings.
## Deployment
How to deploy to different environments.
## Architecture
High-level diagram or description of how components connect.
## Troubleshooting
Common problems and their solutions.

What Makes a README Useful

  • Copy-paste commands that actually work β€” test them
  • Explain WHY not just WHAT β€” future readers need context
  • Keep it updated β€” stale docs are worse than no docs
  • Link to deeper docs β€” don’t bloat the README, link out
  • Include the error messages β€” helps people find the troubleshooting section via search