Skip to main content

Git Best Practices

 Git Best Practices: The DevOps Engineer's Guide to Collaborative Version Control

Master professional Git workflows, commit standards, and team collaboration strategies used by high-performing engineering teams.

📅 Published: Feb 2026
⏱️ Estimated Reading Time: 22 minutes
🏷️ Tags: Git Best Practices, Commit Messages, Branching Strategy, Git Workflow, Team Collaboration, DevOps


📝 Commit Message Standards: Writing History That Matters

Why Commit Messages Matter

Think of commit messages as captain's logs for your codebase. They tell the story of why changes were made, not just what changed. When someone (including your future self) looks at a commit from 6 months ago, they shouldn't have to read the code to understand the purpose.

Bad commit messages (avoid these):

text
update
fix
changes
WIP
asdf

Good commit messages (aim for these):

text
feat(auth): add OAuth2 authentication for Google login

- Implement Google OAuth2 flow with Passport.js
- Add database migration for user providers table
- Update login page with Google sign-in button
- Add integration tests for OAuth callback

Fixes #1234

The Conventional Commits Standard

This is the industry standard for commit messages, used by teams at Google, Netflix, and thousands of other companies.

text
<type>(<scope>): <subject>
<BLANK LINE>
<body>
<BLANK LINE>
<footer>

Types:

text
feat:     New feature (user-facing)
fix:      Bug fix
docs:     Documentation only
style:    Code style (formatting, missing semicolons)
refactor: Code change that neither fixes bug nor adds feature
perf:     Performance improvement
test:     Adding missing tests
chore:    Maintenance tasks (dependencies, build tools)
ci:       CI configuration changes
build:    Build system changes
revert:   Revert previous commit

Example with full structure:

bash
git commit -m "feat(api): add rate limiting middleware

Implement token bucket algorithm for API rate limiting.
- 100 requests per minute per API key
- Redis-backed counter for distributed rate limiting
- Custom headers for rate limit status (X-RateLimit-*)

Closes #456
BREAKING CHANGE: API now requires authentication headers"

Commit Message Best Practices

bash
# 1. Subject line: 50 characters or less, imperative mood
# ✅ "feat: add user login endpoint"
# ❌ "feat: added user login endpoint"
# ❌ "feat: this is a very long commit message subject that definitely exceeds the fifty character limit"

# 2. Capitalize subject line
# ✅ "fix: resolve memory leak in worker threads"
# ❌ "fix: resolve memory leak in worker threads"

# 3. No period at end of subject
# ✅ "docs: update installation instructions"
# ❌ "docs: update installation instructions."

# 4. Use body to explain WHY, not WHAT
# ✅ "The previous implementation created a new connection pool for each request,
# causing excessive memory usage under load. Switching to a singleton pattern
# reduces memory consumption by 60%."
# ❌ "Changed ConnectionPool to singleton pattern."

# 5. Reference issues and pull requests
# ✅ "Closes #123"
# ✅ "Fixes #456"
# ✅ "See also #789"

Automating Commit Message Standards

bash
#!/bin/bash
# .git/hooks/commit-msg
# Enforce conventional commits

commit_message_file=$1
commit_message=$(cat "$commit_message_file")

# Conventional commit pattern
pattern="^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)(\([a-z0-9-]+\))?: .{1,50}$"

if ! echo "$commit_message" | grep -qE "$pattern"; then
    echo "ERROR: Commit message does not follow conventional commits standard"
    echo ""
    echo "Format: <type>(<scope>): <subject>"
    echo ""
    echo "Valid types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert"
    echo ""
    echo "Example: feat(auth): implement JWT token refresh"
    exit 1
fi

# Check subject line length
subject=$(echo "$commit_message" | head -n1)
if [ ${#subject} -gt 72 ]; then
    echo "WARNING: Subject line exceeds 72 characters"
fi

# Check for empty commit message
if [ -z "$commit_message" ]; then
    echo "ERROR: Commit message cannot be empty"
    exit 1
fi

# Check for WIP commits
if echo "$commit_message" | grep -qi "^wip"; then
    echo "WARNING: This is a Work In Progress commit"
    echo "Consider using 'chore(wip):' instead of 'WIP'"
fi

exit 0

Commit Message Templates

bash
# Create commit message template for your team
git config --global commit.template ~/.gitmessage

# ~/.gitmessage
# <type>(<scope>): <subject>
# 
# <body>
# 
# <footer>

# Example template with helpful comments
cat > ~/.gitmessage << 'EOF'
# <type>(<scope>): <subject>
# |<----  Using up to 50 characters  ---->|
# 
# Explain why this change is necessary, not how it works.
# More detailed explanation:
# - Bullet points are fine
# - Use imperative mood
# 
# Closes #<issue-number>
# See also: <links>
# 
# --- COMMIT END ---
# Types: feat, fix, docs, style, refactor, perf, test, chore, ci, build, revert
# Scope: optional, e.g., auth, api, ui, db
EOF

🌿 Branch Naming Strategy: Organizing Your Development

Why Branch Naming Matters

Branches are like labeled containers for your work. Good branch names tell you immediately:

  • What type of work is being done

  • Who is working on it

  • What issue it addresses

  • The current state of the work

Branch Naming Convention

text
<type>/<ticket>-<short-description>

Examples:
feat/JIRA-123-user-authentication
fix/GH-456-null-pointer-exception
hotfix/JIRA-789-payment-gateway-timeout
release/v2.1.0
chore/update-dependencies
docs/api-usage-examples

Type prefixes:

text
feat/       # New features
fix/        | Bug fixes
hotfix/     # Urgent production fixes
release/    # Release preparation
chore/      # Maintenance tasks
docs/       # Documentation
test/       # Test additions/modifications
refactor/   # Code refactoring
perf/       # Performance improvements

Automated Branch Name Validation

bash
#!/bin/bash
# .git/hooks/pre-commit
# Validate branch name before allowing commits

branch_name=$(git symbolic-ref --short HEAD 2>/dev/null)

if [ -n "$branch_name" ]; then
    # Skip validation for main/master/develop
    if [[ "$branch_name" =~ ^(main|master|develop|staging|production)$ ]]; then
        exit 0
    fi
    
    # Pattern: type/ticket-id-description
    pattern="^(feat|fix|hotfix|release|chore|docs|test|refactor|perf)\/[A-Z]+-[0-9]+-[a-z0-9-]+$"
    
    if ! echo "$branch_name" | grep -qE "$pattern"; then
        echo "❌ ERROR: Invalid branch name: $branch_name"
        echo ""
        echo "Branch name must follow pattern: <type>/<ticket>-<description>"
        echo ""
        echo "Examples:"
        echo "  feat/JIRA-123-user-authentication"
        echo "  fix/GITHUB-456-fix-null-pointer"
        echo "  hotfix/JIRA-789-payment-timeout"
        echo ""
        exit 1
    fi
    
    # Check description length
    description=$(echo "$branch_name" | cut -d'-' -f2-)
    if [ ${#description} -gt 50 ]; then
        echo "⚠️  WARNING: Branch description too long (${#description} chars)"
        echo "   Keep it under 50 characters for readability"
    fi
fi

exit 0

Cleanup Script for Stale Branches

bash
#!/bin/bash
# cleanup-branches.sh
# Identify and clean up stale branches

echo "=== Git Branch Cleanup ==="
echo

# 1. Local branches merged into main
echo "1. Local branches already merged into main:"
git branch --merged main | grep -v "main\|develop" | head -20

# 2. Branches without commits in 30 days
echo -e "\n2. Branches untouched for 30+ days:"
for branch in $(git branch | sed 's/^* //'); do
    if [[ "$branch" != "main" && "$branch" != "develop" ]]; then
        last_commit=$(git log -1 --format=%cd --date=relative $branch)
        echo "   $branch: $last_commit"
    fi
done | grep "days\|weeks\|months"

# 3. Delete local merged branches
echo -e "\n3. Deleting local merged branches..."
git branch --merged main | grep -v "main\|develop" | xargs -r git branch -d

# 4. Remote tracking branches that are gone
echo -e "\n4. Pruning remote tracking branches..."
git remote prune origin --dry-run

# 5. Interactive deletion
echo -e "\n5. Remote branches to consider deleting:"
git branch -r --merged origin/main | grep -v "main\|develop" | sed 's/origin\///' | head -10

read -p "Delete these remote branches? (y/n) " -n 1 -r
echo
if [[ $REPLY =~ ^[Yy]$ ]]; then
    git branch -r --merged origin/main | grep -v "main\|develop" | sed 's/origin\///' | \
    xargs -r -I {} git push origin --delete {}
fi

🔄 Git Workflow: Feature, Release, Hotfix

GitHub Flow: Simple and Effective

This is the simplest workflow, perfect for teams doing continuous deployment.

text
main ────────────────────────────────────────────
        \                 \                 \
         feature/A         feature/B         hotfix
           ↓                 ↓                 ↓
         PR to main        PR to main        PR to main

Rules:

  1. main is always deployable

  2. Create feature branches from main

  3. Open pull requests for code review

  4. Merge via squash or rebase

  5. Deploy immediately after merge

bash
#!/bin/bash
# github-flow.sh

echo "=== GitHub Flow Workflow ==="

# Start a new feature
feature_name="user-profile-editor"
git checkout main
git pull origin main
git checkout -b feat/$feature_name

# Make commits
git commit -m "feat(profile): add profile edit form"
git commit -m "feat(profile): implement form validation"
git commit -m "test(profile): add unit tests for profile editor"

# Push and create PR
git push origin feat/$feature_name

echo "✅ Feature branch pushed. Create PR at:"
echo "   https://github.com/company/repo/pull/new/feat/$feature_name"

# After PR is approved and merged
git checkout main
git pull origin main
git branch -d feat/$feature_name

GitFlow: Structured for Releases

More complex workflow for teams with scheduled releases.

text
develop ──────────────────────────────────────────────
    \                 \                 \
     feature/A         feature/B         release/v2.0
       ↓                 ↓                 ↓
     merge back        merge back        merge to main
                                          and tag

Complete GitFlow Implementation:

bash
#!/bin/bash
# gitflow-workflow.sh
# Complete GitFlow implementation

init_gitflow() {
    echo "=== Initializing GitFlow ==="
    
    # Create main branches
    git checkout -b develop main
    
    # Configure GitFlow
    git config gitflow.branch.main main
    git config gitflow.branch.develop develop
    git config gitflow.prefix.feature feature/
    git config gitflow.prefix.release release/
    git config gitflow.prefix.hotfix hotfix/
    git config gitflow.prefix.bugfix bugfix/
    
    echo "✅ GitFlow initialized"
}

start_feature() {
    local FEATURE_NAME=$1
    
    echo "=== Starting Feature: $FEATURE_NAME ==="
    
    # Ensure we're up to date
    git checkout develop
    git pull origin develop
    
    # Create feature branch
    git checkout -b feature/$FEATURE_NAME develop
    
    echo "✅ Feature branch created: feature/$FEATURE_NAME"
    echo "   Make your changes and commit them"
    echo "   When ready: git push -u origin feature/$FEATURE_NAME"
}

finish_feature() {
    local FEATURE_NAME=$1
    
    echo "=== Finishing Feature: $FEATURE_NAME ==="
    
    # Ensure we're on the feature branch
    git checkout feature/$FEATURE_NAME
    
    # Rebase on latest develop
    git fetch origin develop
    git rebase origin/develop
    
    # Update PR description with changes
    echo "✅ Feature ready for PR"
    echo "   1. Push feature branch: git push origin feature/$FEATURE_NAME"
    echo "   2. Create PR against develop"
    echo "   3. After approval, merge via squash"
}

start_release() {
    local VERSION=$1
    
    echo "=== Starting Release: $VERSION ==="
    
    # Create release branch from develop
    git checkout develop
    git pull origin develop
    git checkout -b release/$VERSION develop
    
    # Update version files
    echo "Updating version to $VERSION..."
    
    # Package.json
    if [ -f "package.json" ]; then
        sed -i "s/\"version\": .*/\"version\": \"$VERSION\",/" package.json
        git add package.json
        git commit -m "chore(release): bump version to $VERSION"
    fi
    
    # VERSION file
    echo "$VERSION" > VERSION
    git add VERSION
    git commit -m "chore(release): set version to $VERSION"
    
    # Push release branch
    git push origin release/$VERSION
    
    echo "✅ Release branch created: release/$VERSION"
    echo "   1. Test and fix bugs in this branch"
    echo "   2. Create PR against main"
    echo "   3. After merge, tag the release"
}

finish_release() {
    local VERSION=$1
    
    echo "=== Finishing Release: $VERSION ==="
    
    # Merge to main
    git checkout main
    git pull origin main
    git merge --no-ff release/$VERSION -m "chore(release): merge release $VERSION"
    
    # Tag release
    git tag -a "v$VERSION" -m "Release version $VERSION"
    
    # Merge back to develop
    git checkout develop
    git pull origin develop
    git merge --no-ff release/$VERSION -m "chore(release): merge release $VERSION back to develop"
    
    # Push everything
    git push origin main develop
    git push origin "v$VERSION"
    
    # Delete release branch
    git branch -d release/$VERSION
    git push origin --delete release/$VERSION
    
    echo "✅ Release $VERSION completed"
}

start_hotfix() {
    local VERSION=$1
    local DESCRIPTION=$2
    
    echo "=== Starting Hotfix: $VERSION ==="
    
    # Create hotfix branch from latest tag on main
    git checkout main
    git pull origin main
    git checkout -b hotfix/$DESCRIPTION main
    
    echo "✅ Hotfix branch created: hotfix/$DESCRIPTION"
    echo "   Fix the issue and commit changes"
    echo "   When ready: finish_hotfix $VERSION $DESCRIPTION"
}

finish_hotfix() {
    local VERSION=$1
    local DESCRIPTION=$2
    
    echo "=== Finishing Hotfix: $VERSION ==="
    
    # Commit hotfix if not already committed
    if [ -n "$(git status --porcelain)" ]; then
        git add .
        git commit -m "fix: $DESCRIPTION"
    fi
    
    # Merge to main
    git checkout main
    git pull origin main
    git merge --no-ff hotfix/$DESCRIPTION -m "fix: $DESCRIPTION"
    
    # Tag hotfix release
    git tag -a "v$VERSION" -m "Hotfix version $VERSION"
    
    # Merge back to develop
    git checkout develop
    git pull origin develop
    git merge --no-ff hotfix/$DESCRIPTION -m "chore: merge hotfix $VERSION to develop"
    
    # Push everything
    git push origin main develop
    git push origin "v$VERSION"
    
    # Delete hotfix branch
    git branch -d hotfix/$DESCRIPTION
    git push origin --delete hotfix/$DESCRIPTION
    
    echo "✅ Hotfix $VERSION completed"
}

# Usage examples:
# init_gitflow
# start_feature "user-dashboard"
# finish_feature "user-dashboard"
# start_release "2.1.0"
# finish_release "2.1.0"
# start_hotfix "2.0.1" "security-patch"
# finish_hotfix "2.0.1" "security-patch"

Trunk-Based Development: For High Velocity

Rules:

  1. Short-lived feature branches (hours, not days)

  2. Direct commits to main (for senior devs)

  3. Feature flags for incomplete work

  4. Continuous integration on every commit

bash
#!/bin/bash
# trunk-based.sh

echo "=== Trunk-Based Development ==="

# Create short-lived branch
git checkout main
git pull origin main
git checkout -b feat/add-logging

# Make small, focused change
echo "Adding request logging..."
git commit -am "feat(logging): add HTTP request logging"

# Push immediately
git push origin feat/add-logging

# Create PR (should be reviewed within minutes)
echo "✅ PR created - target merge time: < 1 hour"

# After merge, deploy immediately
echo "🚀 Deploying to production..."

Release Strategy Comparison

WorkflowBest ForBranch LifetimeComplexityRelease Frequency
GitHub FlowCI/CD, SaaSHoursLowMultiple times/day
GitFlowScheduled releasesDays/weeksHighWeekly/monthly
Trunk-BasedHigh-velocity teamsMinutes/hoursMediumContinuous

👥 Git for Teams: Collaboration at Scale

Code Review Culture

markdown
# PULL_REQUEST_TEMPLATE.md

## Description
<!-- Describe your changes in detail -->

## Type of Change
- [ ] feat: New feature
- [ ] fix: Bug fix
- [ ] docs: Documentation
- [ ] refactor: Code refactoring
- [ ] perf: Performance improvement
- [ ] test: Test addition/fix
- [ ] chore: Maintenance

## Testing
<!-- How did you test these changes? -->
- [ ] Unit tests
- [ ] Integration tests
- [ ] Manual testing

## Checklist
- [ ] My code follows the style guidelines
- [ ] I have performed a self-review
- [ ] I have commented complex code
- [ ] I have updated the documentation
- [ ] My changes generate no new warnings
- [ ] All tests pass locally

## Screenshots
<!-- If applicable, add screenshots -->

## Related Issues
Closes #<issue-number>

Automated PR Checks

yaml
# .github/workflows/pr-checks.yml
name: Pull Request Checks

on:
  pull_request:
    types: [opened, synchronize, reopened]

jobs:
  validate:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v2
    
    - name: Validate PR Title
      run: |
        TITLE="${{ github.event.pull_request.title }}"
        if ! echo "$TITLE" | grep -qE "^(feat|fix|docs|refactor|test|chore)(\([a-z]+\))?: .+"; then
          echo "❌ PR title must follow conventional commits"
          exit 1
        fi
    
    - name: Check Branch Name
      run: |
        BRANCH="${{ github.head_ref }}"
        if ! echo "$BRANCH" | grep -qE "^(feat|fix|hotfix|release|chore)/[a-z0-9-]+"; then
          echo "❌ Branch name must follow pattern: type/description"
          exit 1
        fi
    
    - name: Validate Commit Messages
      run: |
        git fetch origin ${{ github.base_ref }}
        COMMITS=$(git log origin/${{ github.base_ref }}..HEAD --format=%s)
        echo "$COMMITS" | while read line; do
          if ! echo "$line" | grep -qE "^(feat|fix|docs|refactor|test|chore|merge)"; then
            echo "❌ Commit message does not follow standard: $line"
            exit 1
          fi
        done
    
    - name: Check for Large Files
      run: |
        git ls-files | xargs -r git ls-files --error-unmatch | \
        xargs -r git cat-file --batch-check='%(objectsize) %(objectname)' | \
        awk '$1 > 5000000 {print "❌ Large file detected: " $2}' && exit 1 || exit 0

Team Git Configuration

bash
#!/bin/bash
# setup-team-git.sh
# Standardize Git configuration across the team

echo "=== Setting Up Team Git Configuration ==="

# Core settings
git config --global core.editor "code --wait"
git config --global core.autocrlf input
git config --global core.safecrlf warn
git config --global core.pager "less -FRX"

# Merge and diff tools
git config --global merge.tool vimdiff
git config --global merge.conflictstyle diff3
git config --global diff.colorMoved default
git config --global diff.algorithm histogram

# Push behavior
git config --global push.default simple
git config --global push.autoSetupRemote true
git config --global push.followTags true

# Pull behavior
git config --global pull.rebase true
git config --global rebase.autoStash true

# Aliases (team standard)
git config --global alias.co checkout
git config --global alias.br branch
git config --global alias.ci commit
git config --global alias.st status
git config --global alias.unstage 'reset HEAD --'
git config --global alias.last 'log -1 HEAD'
git config --global alias.visual '!gitk'
git config --global alias.graph 'log --graph --pretty=oneline --abbrev-commit'
git config --global alias.lg "log --color --graph --pretty=format:'%Cred%h%Creset -%C(yellow)%d%Creset %s %Cgreen(%cr) %C(bold blue)<%an>%Creset' --abbrev-commit"
git config --global alias.cleanup '!git branch --merged | grep -v "main\|develop" | xargs -r git branch -d'

# Commit template
git config --global commit.template ~/.gitmessage

# GPG signing (for teams requiring signed commits)
git config --global commit.gpgsign true
git config --global tag.gpgsign true

echo "✅ Team Git configuration applied"

# Verify setup
echo -e "\n=== Current Configuration ==="
git config --global --list | grep -E "(user|core|alias|push|pull|commit|rebase)"

Handling Merge Conflicts

bash
#!/bin/bash
# resolve-conflicts.sh
# Systematic approach to resolving merge conflicts

echo "=== Merge Conflict Resolution ==="
echo "File: $1"

# 1. Understand the conflict
echo -e "\n1. Understanding the conflict:"
echo "   <<<<<<< HEAD     - Your current changes"
echo "   =======          - Separator"
echo "   >>>>>>> branch   - Incoming changes"

# 2. Use visual merge tool
echo -e "\n2. Launching merge tool..."
git mergetool

# 3. After resolving, mark as resolved
echo -e "\n3. Marking as resolved..."
git add "$1"

# 4. Verify no conflicts remain
echo -e "\n4. Checking remaining conflicts..."
git diff --check

# 5. Continue merge
echo -e "\n5. Continuing merge..."
git commit --no-edit

# Conflict prevention tips:
# - Pull frequently: git pull --rebase
# - Break changes into smaller commits
# - Communicate with team about shared files
# - Use `.gitattributes` for binary files

Git Etiquette Guide

markdown
# TEAM_GIT_ETIQUETTE.md

## Daily Workflow
1. **Start fresh**: `git checkout main && git pull`
2. **Create branch**: `git checkout -b feat/ticket-description`
3. **Commit often**: Small, focused commits with clear messages
4. **Push early**: Don't wait days to push
5. **Rebase daily**: `git pull --rebase origin main`
6. **Clean up**: Delete branches after merge

## Commit Standards**Good**: "feat(auth): add password reset flow"
✅ **Good**: "fix(api): handle null response from payment gateway"
❌ **Bad**: "fix"
❌ **Bad**: "WIP"
❌ **Bad**: "asdf"

## PR Guidelines
- **Size**: < 400 lines changed
- **Duration**: < 24 hours from branch to merge
- **Reviewers**: 2 for critical changes
- **Response time**: < 4 working hours
- **Self-review**: Always review your own PR first

## Communication
- Mention PRs in team chat: `@team PR #123 ready for review`
- Use GitHub's suggestion feature for code changes
- Be kind: assume good intentions
- Explain _why_, not just _what_

## Emergency Procedures
1. **Accidental commit to main**: `git revert HEAD`
2. **Lost work**: Check `git reflog`
3. **Wrong branch**: `git cherry-pick` or `git reset`
4. **Need help**: Tag `@git-helpers` in Slack

## Branch Naming

feat/JIRA-123-short-description
fix/GH-456-bug-description
hotfix/JIRA-789-urgent-fix
release/v2.1.0
chore/update-dependencies
docs/api-usage-examples

text
## Code Review Philosophy
- Review code, not the person
- Ask questions, don't demand changes
- "Why" is more important than "What"
- Praise good solutions, not just catch bugs

Git Statistics and Reporting

bash
#!/bin/bash
# team-git-stats.sh
# Generate Git statistics for your team

echo "=== Team Git Statistics ==="
echo "Period: Last 30 days"
echo "Generated: $(date)"
echo

# 1. Top contributors
echo "1. Top Contributors (by commits):"
git shortlog -sn --since="30 days ago" | head -10
echo

# 2. Commit frequency by day
echo "2. Commit Activity by Day:"
git log --since="30 days ago" --format="%ad" --date=format:%a | \
    sort | uniq -c | sort -rn
echo

# 3. Most active files
echo "3. Most Frequently Changed Files:"
git log --since="30 days ago" --format=format: --name-only | \
    grep -v '^$' | sort | uniq -c | sort -rn | head -10
echo

# 4. PR metrics (requires GitHub CLI)
if command -v gh &> /dev/null; then
    echo "4. Pull Request Metrics:"
    echo "   Average time to merge: (requires API access)"
    echo "   Open PRs: $(gh pr list --state open --json number --jq 'length')"
    echo "   Merged PRs (30d): $(gh pr list --state merged --limit 100 --json mergedAt --jq 'length')"
fi
echo

# 5. Commit message quality
echo "5. Commit Message Quality:"
TOTAL_COMMITS=$(git rev-list --count HEAD --since="30 days ago")
CONVENTIONAL_COMMITS=$(git log --since="30 days ago" --format=%s | \
    grep -cE "^(feat|fix|docs|style|refactor|perf|test|chore|ci|build|revert)")
PERCENT=$((CONVENTIONAL_COMMITS * 100 / TOTAL_COMMITS))
echo "   Conventional commits: $PERCENT% ($CONVENTIONAL_COMMITS/$TOTAL_COMMITS)"

# 6. Branch hygiene
echo -e "\n6. Branch Hygiene:"
STALE_BRANCHES=$(git branch -r --merged origin/main | grep -v "main\|develop" | wc -l)
echo "   Stale remote branches: $STALE_BRANCHES"
LOCAL_MERGED=$(git branch --merged main | grep -v "main\|develop" | wc -l)
echo "   Local branches to delete: $LOCAL_MERGED"

🎯 Real-World Team Scenarios

Scenario 1: Onboarding New Developer

bash
#!/bin/bash
# onboard-developer.sh
# Complete onboarding script for new team members

DEVELOPER_NAME=$1
DEVELOPER_EMAIL=$2

echo "=== Onboarding $DEVELOPER_NAME ==="

# 1. Clone repositories
echo "1. Cloning main repositories..."
REPOS=("backend" "frontend" "infrastructure" "docs")

for REPO in "${REPOS[@]}"; do
    git clone git@github.com:company/$REPO.git
    cd $REPO
    
    # Set user config
    git config user.name "$DEVELOPER_NAME"
    git config user.email "$DEVELOPER_EMAIL"
    
    # Install hooks
    if [ -f "scripts/install-hooks.sh" ]; then
        ./scripts/install-hooks.sh
    fi
    
    cd ..
done

# 2. Create README with team standards
cat > TEAM-GUIDE.md << 'EOF'
# Welcome to the Team! 🚀

## First Week Checklist
- [ ] Read team Git etiquette guide
- [ ] Set up Git config with your details
- [ ] Install pre-commit hooks
- [ ] Review last 5 PRs to understand review culture
- [ ] Make your first commit (even a typo fix!)
- [ ] Open your first PR

## Useful Commands
```bash
# Daily workflow
git checkout main
git pull
git checkout -b feat/ticket-description
# make changes
git commit -m "feat: add feature"
git push -u origin HEAD

# Before PR
git fetch origin
git rebase origin/main

Need Help?

  • Tag @mentors in your PR

  • Pair programming sessions: Tues/Thurs 2-4 PM

  • #git-help Slack channel
    EOF

echo "✅ Onboarding complete for $DEVELOPER_NAME"

text
### **Scenario 2: Emergency Hotfix Rotation**

```bash
#!/bin/bash
# hotfix-rotation.sh
# Managed hotfix process with on-call rotation

ON_CALL_ENGINEER=$1
SEVERITY=$2
DESCRIPTION=$3

# Generate hotfix branch
TIMESTAMP=$(date +%Y%m%d-%H%M%S)
BRANCH_NAME="hotfix/sev${SEVERITY}-${TIMESTAMP}"

echo "=== Hotfix Initiated ==="
echo "Engineer: $ON_CALL_ENGINEER"
echo "Severity: $SEVERITY"
echo "Description: $DESCRIPTION"
echo "Branch: $BRANCH_NAME"
echo

# Create hotfix branch from main
git checkout main
git pull origin main
git checkout -b "$BRANCH_NAME"

# Apply fix (developer works here)
echo "⏳ Hotfix in progress..."
echo "   When ready:"
echo "   1. Commit changes"
echo "   2. Push branch"
echo "   3. Emergency PR process"

# Emergency PR template
cat > .github/PULL_REQUEST_TEMPLATE/hotfix.md << 'EOF'
---
name: Hotfix
about: Emergency production fix

**Severity**: SEV-$SEVERITY
**Incident**: $INCIDENT_LINK
**Root Cause**: 
**Fix Description**: 
**Verification**: 
**Rollback Plan**: 

⚠️ **This PR requires 1 reviewer and expedited review**
EOF

# Notify team
echo "📢 NOTIFICATION: Hotfix in progress"
echo "   Channel: #incidents"
echo "   Message: SEV-$SEVERITY hotfix by $ON_CALL_ENGINEER - $DESCRIPTION"

Scenario 3: Release Coordination

bash
#!/bin/bash
# release-coordinator.sh
# Coordinate releases across multiple teams

RELEASE_VERSION=$1
TEAMS=("frontend" "backend" "mobile" "infrastructure")

echo "=== Release $RELEASE_VERSION Coordination ==="

# 1. Create release branch
git checkout develop
git pull origin develop
git checkout -b release/$RELEASE_VERSION

# 2. Update version across all services
for TEAM in "${TEAMS[@]}"; do
    if [ -d "$TEAM" ]; then
        cd $TEAM
        
        # Update version file
        echo $RELEASE_VERSION > VERSION
        
        # Update package.json if exists
        if [ -f "package.json" ]; then
            sed -i "s/\"version\": .*/\"version\": \"$RELEASE_VERSION\",/" package.json
        fi
        
        git add VERSION package.json 2>/dev/null
        git commit -m "chore(release): bump $TEAM version to $RELEASE_VERSION"
        
        cd ..
    fi
done

# 3. Generate release notes
echo -e "\n## Release $RELEASE_VERSION\n" > RELEASE_NOTES.md
echo "**Date**: $(date +%Y-%m-%d)" >> RELEASE_NOTES.md
echo "" >> RELEASE_NOTES.md

for TEAM in "${TEAMS[@]}"; do
    if [ -d "$TEAM" ]; then
        cd $TEAM
        echo "### $TEAM" >> ../RELEASE_NOTES.md
        git log --pretty=format:"- %s" $(git describe --tags --abbrev=0)..HEAD | \
            grep -E "feat|fix" >> ../RELEASE_NOTES.md
        echo "" >> ../RELEASE_NOTES.md
        cd ..
    fi
done

# 4. Tag all repositories
for TEAM in "${TEAMS[@]}"; do
    if [ -d "$TEAM" ]; then
        cd $TEAM
        git tag -a "v$RELEASE_VERSION" -m "Release $RELEASE_VERSION"
        git push origin "v$RELEASE_VERSION"
        cd ..
    fi
done

echo "✅ Release $RELEASE_VERSION prepared"

📋 Quick Reference Team Checklist

markdown
# ✅ Daily Git Checklist

## Morning
- [ ] `git checkout main && git pull`
- [ ] `git fetch --all --prune`
- [ ] `git branch --merged | xargs git branch -d`

## During Development
- [ ] Branch name follows convention: `feat/JIRA-123-description`
- [ ] Commit message follows conventional commits
- [ ] `git pull --rebase origin main` before PR
- [ ] Run tests locally
- [ ] Self-review PR before requesting reviewers

## Pull Request
- [ ] Title follows conventional commits
- [ ] Description explains WHY, not WHAT
- [ ] Screenshots for UI changes
- [ ] Links to related issues
- [ ] Requested appropriate reviewers
- [ ] Added to project board

## After Merge
- [ ] Delete branch locally: `git branch -d branch-name`
- [ ] Delete branch remotely: `git push origin --delete branch-name`
- [ ] Pull main: `git checkout main && git pull`

## Weekly
- [ ] Clean up local branches: `git branch --merged | grep -v "\*\|main\|develop" | xargs git branch -d`
- [ ] Update local tags: `git fetch --tags --prune-tags`
- [ ] Review team Git statistics

## Release Day
- [ ] Version bump committed
- [ ] Changelog updated
- [ ] Release notes generated
- [ ] Tags created and pushed
- [ ] Deployments verified

🚀 Practice Team Exercises

Exercise 1: Simulate Team Conflict Resolution

bash
# Pair up with another developer
# Person A:
git checkout -b exercise/feature-a
echo "function A() { return 'feature A'; }" >> app.js
git add app.js
git commit -m "feat: add feature A"
git push origin exercise/feature-a

# Person B:
git checkout -b exercise/feature-b
echo "function B() { return 'feature B'; }" >> app.js
git add app.js
git commit -m "feat: add feature B"
git push origin exercise/feature-b

# Both try to merge → conflict!
# Practice resolving together

Exercise 2: Implement Git Hooks Team-Wide

bash
# 1. Create hooks repository
mkdir git-hooks && cd git-hooks
git init

# 2. Add standard hooks
cp /path/to/team-hooks/* .git-hooks/
git add .git-hooks
git commit -m "chore(hooks): add team standard Git hooks"

# 3. Create installer script
cat > install-hooks.sh << 'EOF'
#!/bin/bash
cp .git-hooks/* .git/hooks/
chmod +x .git/hooks/*
echo "✅ Hooks installed"
EOF

chmod +x install-hooks.sh
git add install-hooks.sh
git commit -m "chore(hooks): add installer script"

# 4. Team members run:
./install-hooks.sh

Exercise 3: Release Simulation

bash
# 1. Create feature branches
git checkout -b feat/login-form develop
git commit -m "feat(auth): add login form component"

git checkout -b feat/api-integration develop
git commit -m "feat(api): integrate login endpoint"

# 2. Create release branch
git checkout -b release/1.2.0 develop

# 3. Merge features
git merge --no-ff feat/login-form
git merge --no-ff feat/api-integration

# 4. Tag release
git tag -a v1.2.0 -m "Release version 1.2.0"

# 5. Simulate deployment
echo "Deploying v1.2.0..."

🔗 Master Git Best Practices with Hands-on Labs

Git proficiency is the foundation of modern software development. Professional teams don't just know Git commands—they follow consistent workflows, standards, and practices.

👉 Practice team Git workflows and collaboration in our interactive labs at:
https://devops.trainwithsky.com/

Our platform provides:

  • Multi-user Git simulation

  • Pull request review exercises

  • Merge conflict resolution scenarios

  • Release management drills

  • Team workflow optimization


Frequently Asked Questions

Q: What's the most important Git practice for teams?
A: Consistent commit message formatting. Everything else becomes easier when you can read and understand the history.

Q: How often should we merge to main?
A: As often as possible. The longer a branch lives, the harder the merge.

Q: Should we squash commits when merging?
A: Yes for feature branches (clean history), no for release/hotfix branches (preserve context).

Q: How do we handle secrets accidentally committed?
A: Immediately rotate the secret, then use git filter-branch or BFG Repo-Cleaner to remove from history.

Q: What's the ideal PR size?
A: 200-400 lines maximum. If it's larger, break it into multiple PRs.

Q: Should we require signed commits?
A: For regulated industries, yes. For most teams, conventional commits with CI checks are sufficient.

Q: How do we onboard new developers to our Git workflow?
A: Document everything, provide starter scripts, pair on first few PRs, and maintain a blame-free culture.

Have questions about implementing Git best practices in your team? Share your challenges in the comments below! 💬

Comments

Popular posts from this blog

Introduction to Terraform – The Future of Infrastructure as Code

  Introduction to Terraform – The Future of Infrastructure as Code In today’s fast-paced DevOps world, managing infrastructure manually is outdated . This is where Terraform comes in—a powerful Infrastructure as Code (IaC) tool that allows you to define, provision, and manage cloud infrastructure efficiently . Whether you're working with AWS, Azure, Google Cloud, or on-premises servers , Terraform provides a declarative, automation-first approach to infrastructure deployment. Shape Your Future with AI & Infinite Knowledge...!! Read In-Depth Tech & Self-Improvement Blogs http://www.skyinfinitetech.com Watch Life-Changing Videos on YouTube https://www.youtube.com/@SkyInfinite-Learning Transform Your Skills, Business & Productivity – Join Us Today! In today’s digital-first world, agility and automation are no longer optional—they’re essential. Companies across the globe are rapidly shifting their operations to the cloud to keep up with the pace of innovatio...

📊 Monitoring & Logging in Kubernetes – Tools like Prometheus, Grafana, and Fluentd

  Monitoring & Logging in Kubernetes – Tools like Prometheus, Grafana, and Fluentd Monitoring and logging are essential for maintaining a healthy and well-performing Kubernetes cluster. In this guide, we’ll cover why monitoring is important, key monitoring tools like Prometheus and Grafana, and logging tools like Fluentd to help you gain visibility into your cluster’s performance and logs. Shape Your Future with AI & Infinite Knowledge...!! Want to Generate Text-to-Voice, Images & Videos? http://www.ai.skyinfinitetech.com Read In-Depth Tech & Self-Improvement Blogs http://www.skyinfinitetech.com Watch Life-Changing Videos on YouTube https://www.youtube.com/@SkyInfinite-Learning Transform Your Skills, Business & Productivity – Join Us Today! 🚀 Introduction In today’s fast-paced cloud-native environment, Kubernetes has emerged as the de-facto container orchestration platform. But deploying and managing applications in Kubernetes is just half the ba...

🔒 Kubernetes Security – RBAC, Network Policies, and Secrets Management

  Kubernetes Security – RBAC, Network Policies, and Secrets Management Security is a critical aspect of managing Kubernetes clusters. In this guide, we'll cover essential security mechanisms like Role-Based Access Control (RBAC) , Network Policies , and Secrets Management to help you secure your Kubernetes environment effectively. Shape Your Future with AI & Infinite Knowledge...!! Want to Generate Text-to-Voice, Images & Videos? http://www.ai.skyinfinitetech.com Read In-Depth Tech & Self-Improvement Blogs http://www.skyinfinitetech.com Watch Life-Changing Videos on YouTube https://www.youtube.com/@SkyInfinite-Learning Transform Your Skills, Business & Productivity – Join Us Today! 🚀 Introduction: Why Kubernetes Security Is Non-Negotiable As Kubernetes becomes the backbone of modern cloud-native infrastructure, security is no longer optional—it’s mission-critical . With multiple moving parts like containers, pods, services, nodes, and more, Kuberne...