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):
update fix changes WIP asdf
Good commit messages (aim for these):
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.
<type>(<scope>): <subject> <BLANK LINE> <body> <BLANK LINE> <footer>
Types:
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:
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
# 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
#!/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
# 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
<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:
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
#!/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
#!/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.
main ────────────────────────────────────────────
\ \ \
feature/A feature/B hotfix
↓ ↓ ↓
PR to main PR to main PR to mainRules:
mainis always deployableCreate feature branches from
mainOpen pull requests for code review
Merge via squash or rebase
Deploy immediately after merge
#!/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.
develop ──────────────────────────────────────────────
\ \ \
feature/A feature/B release/v2.0
↓ ↓ ↓
merge back merge back merge to main
and tagComplete GitFlow Implementation:
#!/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:
Short-lived feature branches (hours, not days)
Direct commits to main (for senior devs)
Feature flags for incomplete work
Continuous integration on every commit
#!/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
| Workflow | Best For | Branch Lifetime | Complexity | Release Frequency |
|---|---|---|---|---|
| GitHub Flow | CI/CD, SaaS | Hours | Low | Multiple times/day |
| GitFlow | Scheduled releases | Days/weeks | High | Weekly/monthly |
| Trunk-Based | High-velocity teams | Minutes/hours | Medium | Continuous |
👥 Git for Teams: Collaboration at Scale
Code Review Culture
# 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
# .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
#!/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
#!/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
# 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
## 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
#!/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
#!/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
@mentorsin your PRPair programming sessions: Tues/Thurs 2-4 PM
#git-help Slack channel
EOF
echo "✅ Onboarding complete for $DEVELOPER_NAME"
### **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
#!/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
# ✅ 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
# 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
# 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
# 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
Post a Comment