Git Collaboration Workflow#
Introduction#
Effective Git collaboration workflows are essential for modern software development teams. A well-defined workflow ensures that team members can work in parallel without conflicts, maintain code quality through peer review, and deploy changes safely and efficiently.
This guide covers fundamental Git concepts, popular branching strategies, and best practices for collaboration. By the end, you’ll understand how to choose and implement the right workflow for your team’s needs, whether you’re working on a small project or a large-scale cloud-native application.
Why Git Workflows Matter:
Parallel Development: Multiple developers can work simultaneously without interfering with each other
Code Quality: Structured review processes catch bugs before they reach production
Release Management: Clear processes for deploying tested code to production
Traceability: Every change is tracked, documented, and reversible
Git Fundamentals#
Repository & Commits#
Repository (Repo): A repository is a storage location for your project that contains all files, history, and branches. It can exist locally on your machine or remotely on platforms like GitHub, GitLab, or Bitbucket.
Commits: A commit is a snapshot of your project at a specific point in time. Each commit contains:
Changes made to files
Author information
Timestamp
Commit message describing the changes
Unique SHA-1 hash identifier
Staging Area: Git uses a staging area (also called “index”) as an intermediate step between your working directory and the repository. This allows you to selectively choose which changes to include in your next commit.
Basic Workflow:
Working Directory → Staging Area → Repository
(edit) → (git add) → (git commit)
Key Commands:
# Initialize a new repository
git init
# Check status of files
git status
# Add files to staging area
git add filename.txt
git add . # Add all changes
# Commit staged changes
git commit -m "Descriptive commit message"
# View commit history
git log
git log --oneline --graph --all
Branches#
What is a Branch?: A branch is an independent line of development. It’s a pointer to a specific commit that moves forward as you create new commits. Branches allow you to work on features, fixes, or experiments without affecting the main codebase.
Why Use Branches?
Isolate feature development
Test experimental ideas safely
Enable parallel workflows
Facilitate code review before merging
Default Branch: Traditionally named master, now commonly main. This is typically your production-ready code.
Key Commands:
# List all branches
git branch
# Create a new branch
git branch feature-name
# Switch to a branch
git checkout feature-name
# Or using newer syntax:
git switch feature-name
# Create and switch in one command
git checkout -b feature-name
git switch -c feature-name
# Merge a branch into current branch
git merge feature-name
# Use --no-ff to preserve branch history (recommended for feature branches)
git merge --no-ff feature-name
# Rebase current branch onto another (clean up history before PR)
git rebase main
# Delete a branch
git branch -d feature-name
Security Best Practices#
.gitignore Essentials#
Prevent sensitive files from being committed:
# Environment and secrets
.env
.env.local
.env.*.local
*.pem
*.key
secrets/
config/local.yaml
# Credentials
credentials.json
service-account.json
.aws/
.gcloud/
# IDE and OS
.vscode/
.idea/
.DS_Store
Thumbs.db
# Dependencies
node_modules/
venv/
__pycache__/
If you accidentally commit a secret, assume it’s compromised. Rotate the credential immediately, then use git filter-branch or BFG Repo-Cleaner to remove it from history.
Pre-commit Secrets Detection#
Use tools to catch secrets before they’re committed:
# Install detect-secrets
pip install detect-secrets
# Create baseline (ignore existing findings)
detect-secrets scan > .secrets.baseline
# Add to pre-commit hooks
# .pre-commit-config.yaml
repos:
- repo: https://github.com/Yelp/detect-secrets
rev: v1.4.0
hooks:
- id: detect-secrets
args: ['--baseline', '.secrets.baseline']
Alternatives: gitleaks, trufflehog, git-secrets
Branch Protection & Governance#
Protected Branches#
Configure branch protection rules (GitHub/GitLab):
Rule |
Purpose |
|---|---|
Require PR reviews |
At least 1-2 approvals before merge |
Require status checks |
CI must pass before merge |
Require signed commits |
Verify commit authenticity |
Restrict force push |
Prevent history rewriting on main |
Require linear history |
No merge commits (rebase only) |
CODEOWNERS#
Automatic reviewer assignment based on file paths:
# .github/CODEOWNERS (or .gitlab/CODEOWNERS)
# Default owners for everything
* @team-leads
# Frontend owners
/src/frontend/ @frontend-team
*.tsx @frontend-team
# Backend owners
/src/api/ @backend-team
*.py @backend-team
# DevOps/Infra
.github/ @devops-team
Dockerfile @devops-team
*.yml @devops-team
Draft Pull Requests#
Use draft PRs to:
Get early feedback on WIP code
Run CI without enabling merge
Signal “not ready for review yet”
# Create a draft PR via GitHub CLI
gh pr create --draft --title "WIP: Add user authentication"
Branching Strategies#
Gitflow Workflow#
Gitflow is a robust branching model designed around project releases. It defines a strict branching structure with specific roles for different branch types.
Branch Types in Gitflow:
Main Branches:
main(ormaster): Contains production-ready code. Every commit here represents a production release.develop: Integration branch for features. Contains the latest development changes for the next release.
Supporting Branches:
Feature branches (
feature/*): Branch fromdevelop, merge back todevelopUsed for developing new features
Naming:
feature/user-authentication,feature/payment-integration
Release branches (
release/*): Branch fromdevelop, merge tomainanddevelopPrepare for a new production release
Allow for minor bug fixes and metadata preparation
Naming:
release/1.2.0
Hotfix branches (
hotfix/*): Branch frommain, merge tomainanddevelopQuick fixes for production issues
Naming:
hotfix/critical-security-patch
Gitflow Workflow Steps:
Feature Development:
develop → feature/new-feature → develop
Release Preparation:
develop → release/1.0.0 → main + develop (tagged v1.0.0)
Hotfix:
main → hotfix/critical-bug → main + develop (tagged v1.0.1)
Pros:
Clear structure for releases
Parallel development of features and releases
Good for scheduled release cycles
Cons:
Complex for small teams or continuous deployment
Multiple long-lived branches can lead to merge conflicts
May slow down deployment velocity
Feature Branch Workflow#
A simpler alternative to Gitflow, the Feature Branch Workflow is based on a single main branch with feature branches for all new work.
Core Principles:
mainbranch always contains production-ready codeAll new work happens in dedicated feature branches
Feature branches are merged back to
mainvia pull requestsContinuous integration tests run on every branch
Typical Flow:
# 1. Create feature branch from main
git checkout main
git pull origin main
git checkout -b feature/add-login
# 2. Work on feature, commit regularly
git add .
git commit -m "Add login form UI"
git commit -m "Implement authentication logic"
# 3. Push feature branch
git push origin feature/add-login
# 4. Create Pull Request (on GitHub/GitLab)
# 5. Code review and CI checks
# 6. Merge to main after approval
# 7. Delete feature branch
Best Practices:
Keep feature branches short-lived (ideally < 1 week)
Sync regularly with
mainto avoid conflictsOne feature = one branch
Use descriptive branch names
Trunk-Based Development (Advanced Variation):
For teams practicing Continuous Delivery, trunk-based development takes this further:
Developers merge to
main(trunk) dailyFeature branches are very short-lived (< 1 day)
Every merge to
maintriggers automated deployment to dev/QAProduction releases are explicit actions with semantic versioning
Key Consideration: Trunk-based development requires:
Robust automated testing (unit, integration, full pipeline tests)
Feature flags for incomplete features
Strong CI/CD infrastructure
Team discipline and maturity
Pull Requests#
Creating Effective PRs#
A Pull Request (PR) is a mechanism for proposing changes to a codebase. It facilitates code review, discussion, and quality control before merging.
Anatomy of a Good Pull Request:
Descriptive Title: Summarize the change in one line
Good: “Add user authentication with JWT tokens”
Bad: “Update code”
Clear Description: Explain what, why, and how
## What Implements JWT-based authentication for API endpoints ## Why Needed to secure user data and implement role-based access ## How - Added JWT middleware for Express - Created login/logout endpoints - Implemented token refresh mechanism ## Testing - Added unit tests for auth functions - Tested manually with Postman ## Screenshots [If applicable]
Small, Focused Changes:
Aim for < 400 lines changed
One logical change per PR
If larger, consider breaking into multiple PRs
Reference Issues: Link to related issues or tickets
“Closes #123”
“Related to #456”
Self-Review: Review your own PR first
Check for debug code, console.logs
Ensure tests pass
Verify formatting and style
PR Checklist Before Submitting:
- [ ] Code follows project style guidelines
- [ ] Self-review completed
- [ ] Comments added for complex logic
- [ ] Tests added/updated and passing
- [ ] Documentation updated
- [ ] No merge conflicts with target branch
- [ ] CI/CD pipeline passing
Code Review Process#
Code review is a critical quality gate that improves code quality, shares knowledge, and catches bugs early.
Reviewer Responsibilities:
Understand the Context: Read the PR description and related issues
Check Functionality: Does the code do what it claims?
Review Code Quality:
Readability and maintainability
Adherence to coding standards
Proper error handling
Security considerations
Test Coverage: Are critical paths tested?
Performance: Any obvious performance issues?
Providing Constructive Feedback:
Be Specific:
Good: “This function could be simplified using array.map() instead of a for loop”
Bad: “This code is messy”
Be Kind:
Use “we” language: “We could consider…”
Ask questions: “Have you considered…?”
Praise good work: “Nice solution to this edge case!”
Categorize Comments:
Blocking: Must be fixed before merge
Non-blocking: Suggestions for improvement
Question: Need clarification
Author Responsibilities:
Respond to All Comments: Even if just “Fixed” or “Good point”
Explain Decisions: If you disagree, explain why politely
Keep Discussion on Topic: Move lengthy debates to separate discussions
Update the PR: Push fixes and re-request review
Example Review Comment Types:
🔴 Blocking: This will cause a null pointer exception if user is undefined
🟡 Suggestion: Consider extracting this into a separate function for readability
💭 Question: Why did we choose this approach over using the existing utility?
✅ Approval: LGTM! Great work on the error handling
Merge Strategies:
Merge Commit: Preserves full history with a merge commit
Squash and Merge: Combines all commits into one (cleaner history)
Rebase and Merge: Replays commits on top of base branch (linear history)
Choose based on your team’s preference and project needs.
Conflict Resolution#
Understanding Merge Conflicts#
Conflicts occur when Git can’t automatically merge changes (same lines edited by different branches).
Conflict Markers:
<<<<<<< HEAD
Your changes (current branch)
=======
Their changes (incoming branch)
>>>>>>> feature-branch
Resolution Strategies#
# 1. See which files have conflicts
git status
# 2. Open conflicted files and resolve manually
# - Remove conflict markers
# - Keep the correct code
# 3. Mark as resolved
git add resolved-file.py
# 4. Complete the merge
git commit
Using ours/theirs:
# Keep your version for all conflicts
git checkout --ours path/to/file.py
# Keep their version for all conflicts
git checkout --theirs path/to/file.py
# Keep one side for entire merge
git merge -X ours feature-branch # Prefer current branch
git merge -X theirs feature-branch # Prefer incoming branch
GUI Tools for Complex Conflicts:
# Launch configured merge tool
git mergetool
# Popular tools: VS Code, IntelliJ, Meld, Beyond Compare
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
Sync with main frequently (
git pull --rebase origin main)Keep branches short-lived
Communicate with team about overlapping work
Conventional Commits#
Conventional Commits is a specification for writing standardized commit messages. It provides a lightweight convention that creates an explicit commit history, making it easier to write automated tools on top of.
The Specification#
A conventional commit message follows this structure:
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
Components:
Type (required): Describes the category of change
Scope (optional): Describes what part of the codebase is affected
Description (required): Short summary of the change
Body (optional): Detailed explanation of the change
Footer (optional): Metadata like breaking changes or issue references
Common Commit Types#
Type |
Description |
Example |
|---|---|---|
|
A new feature |
|
|
A bug fix |
|
|
Documentation changes |
|
|
Code style changes (formatting, semicolons) |
|
|
Code refactoring without changing functionality |
|
|
Performance improvements |
|
|
Adding or updating tests |
|
|
Build system or external dependencies |
|
|
CI/CD configuration changes |
|
|
Other changes (maintenance tasks) |
|
|
Reverts a previous commit |
|
Examples#
Simple commit:
feat: add email validation to registration form
Commit with scope:
fix(auth): resolve token expiration issue
Commit with body:
feat(api): add pagination to user list endpoint
Implemented cursor-based pagination to improve performance
when loading large user datasets. The page size defaults to
20 items but can be configured via query parameter.
Breaking change:
feat(api)!: change authentication to JWT tokens
BREAKING CHANGE: The API now requires JWT tokens instead of
session cookies. All clients must update their authentication
flow to request and include Bearer tokens.
Closes #456
Multiple footers:
fix(payment): correct currency conversion calculation
The previous implementation used outdated exchange rates.
Now fetches real-time rates from the currency API.
Fixes #789
Reviewed-by: John Doe
Co-authored-by: Jane Smith <jane@example.com>
Benefits#
Automatic Changelog Generation: Tools can parse conventional commits to generate release notes
Semantic Versioning: Commit types determine version bumps:
fix→ PATCH (1.0.0 → 1.0.1)feat→ MINOR (1.0.0 → 1.1.0)BREAKING CHANGE→ MAJOR (1.0.0 → 2.0.0)
Clear Communication: Team members understand changes at a glance
Better Git History: Structured commits make history easier to navigate
Automation Ready: CI/CD pipelines can trigger actions based on commit types
Tools and Enforcement#
Commitlint: Lint commit messages to ensure they follow conventions
# Install
npm install --save-dev @commitlint/cli @commitlint/config-conventional
# Create config file (commitlint.config.js)
module.exports = { extends: ['@commitlint/config-conventional'] };
Husky: Git hooks to run commitlint before commits
# Install husky
npm install --save-dev husky
# Enable Git hooks
npx husky install
# Add commit-msg hook
npx husky add .husky/commit-msg 'npx --no -- commitlint --edit "$1"'
Commitizen: Interactive CLI for writing conventional commits
# Install globally
npm install -g commitizen cz-conventional-changelog
# Use instead of git commit
git cz
Automated Versioning & Changelog#
semantic-release automates version bumps and changelog generation based on Conventional Commits:
# .github/workflows/release.yml
name: Release
on:
push:
branches: [main]
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
persist-credentials: false
- uses: actions/setup-node@v4
with:
node-version: 20
- name: Install dependencies
run: npm ci
- name: Semantic Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
Configuration (.releaserc.json):
{
"branches": ["main"],
"plugins": [
"@semantic-release/commit-analyzer",
"@semantic-release/release-notes-generator",
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/github",
[
"@semantic-release/git",
{
"assets": ["CHANGELOG.md", "package.json"],
"message": "chore(release): ${nextRelease.version}"
}
]
]
}
This automatically:
Determines next version from commit types
Generates CHANGELOG.md
Creates GitHub releases with notes
Publishes to npm (if configured)
Summary#
Key Takeaways:
Git Fundamentals
Repository stores complete project history
Commits are snapshots; stage changes before committing
Branches enable parallel development
Branching Strategies
Gitflow: Structured approach with main, develop, feature, release, and hotfix branches. Best for scheduled releases.
Feature Branch Workflow: Simpler model with main branch and feature branches. Better for continuous delivery.
Trunk-Based Development: Advanced approach requiring mature CI/CD and testing practices.
Pull Requests
Essential for code review and quality control
Should be small, focused, and well-documented
Code review improves quality and shares knowledge
Choosing a Workflow
Use Gitflow if: You have scheduled releases, need to support multiple production versions, or have a complex release process
Use Feature Branch Workflow if: You deploy continuously, want simplicity, or have a small to medium team
Use Trunk-Based if: You have strong CI/CD, mature testing practices, and can deploy multiple times per day
Best Practices Across All Workflows:
Commit early and often with meaningful messages
Keep branches short-lived when possible
Use pull requests for all code changes
Automate testing and deployment
Document your chosen workflow for the team
Be consistent across the team
Next Steps:
Practice the exercises to build muscle memory
Choose a workflow that fits your team’s deployment frequency and maturity
Implement automation (CI/CD) to support your workflow
Regularly review and refine your process