Automating Branch Management | Git Workflow Automation
Automate branch naming validation, stale branch cleanup, and protection rules. Reduce manual Git overhead with pre-push hooks and CI integration.
6 min read
Manual branch management is error-prone and time-consuming. Automated branch workflows ensure consistent naming, clean up stale branches, and enforce team standards. This guide covers practical automation strategies for branch management.
Branch Automation Types
| Automation | Benefit | Effort |
|---|---|---|
| Naming validation | Consistency | Low |
| Auto-delete merged | Clean repo | Low |
| Stale cleanup | Reduced clutter | Medium |
| Protection rules | Quality gates | Low |
| CI per branch type | Right tests | Medium |
Branch Naming
Enforcing Conventions
BRANCH NAMING AUTOMATION
ββββββββββββββββββββββββ
NAMING PATTERN:
βββββββββββββββββββββββββββββββββββββ
Standard format:
βββ type/ticket-description
βββ Examples:
β βββ feature/AUTH-123-login-flow
β βββ bugfix/BUG-456-null-pointer
β βββ hotfix/PROD-789-payment-fix
β βββ chore/DEP-001-update-deps
βββ Consistent, parseable
VALIDATION OPTIONS:
βββββββββββββββββββββββββββββββββββββ
1. Pre-commit hook:
#!/bin/bash
branch=$(git rev-parse --abbrev-ref HEAD)
pattern="^(feature|bugfix|hotfix|chore)\/[A-Z]+-[0-9]+-"
if [[ ! $branch =~ $pattern ]]; then
echo "Invalid branch name: $branch"
exit 1
fi
2. CI check:
- name: Validate branch name
run: |
if [[ ! "$GITHUB_HEAD_REF" =~ ^(feature|bugfix|hotfix)/ ]]; then
echo "Invalid branch name"
exit 1
fi
3. Pre-receive hook (server-side):
βββ Blocks invalid branches at push
βββ Strongest enforcement
LINK TO TASKS:
βββββββββββββββββββββββββββββββββββββ
Extract ticket from branch:
βββ Parse branch name
βββ Link PR to issue automatically
βββ Update task status
βββ Close task on merge
βββ Full traceability
Auto-Cleanup
Managing Branch Lifecycle
BRANCH CLEANUP AUTOMATION
βββββββββββββββββββββββββ
AUTO-DELETE ON MERGE:
βββββββββββββββββββββββββββββββββββββ
GitHub setting:
βββ Settings β General
βββ "Automatically delete head branches"
βββ Enable β
βββ Branch deleted when PR merged
βββ No manual cleanup
βββ Clean repository
GitLab:
βββ Settings β Repository
βββ "Enable auto-delete merged branches"
βββ Same behavior
STALE BRANCH CLEANUP:
βββββββββββββββββββββββββββββββββββββ
Script to find stale branches:
# Find branches older than 30 days
for branch in $(git branch -r --merged | grep -v main); do
last_commit=$(git log -1 --format=%ci "$branch")
days_old=$(( ($(date +%s) - $(date -d "$last_commit" +%s)) / 86400 ))
if [ $days_old -gt 30 ]; then
echo "Stale: $branch ($days_old days)"
fi
done
SCHEDULED CLEANUP:
βββββββββββββββββββββββββββββββββββββ
GitHub Action:
name: Branch Cleanup
on:
schedule:
- cron: '0 0 * * 0' # Weekly
jobs:
cleanup:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Delete stale branches
run: |
# Delete merged branches older than 14 days
for branch in $(git branch -r --merged origin/main); do
# Skip protected branches
if [[ ! "$branch" =~ (main|develop|release) ]]; then
git push origin --delete "${branch#origin/}"
fi
done
Branch Protection
Automated Quality Gates
BRANCH PROTECTION RULES
βββββββββββββββββββββββ
GITHUB PROTECTION SETTINGS:
βββββββββββββββββββββββββββββββββββββ
For main branch:
βββ Require pull request before merging β
βββ Require approvals: 1-2 β
βββ Dismiss stale reviews β
βββ Require status checks to pass β
β βββ CI build
β βββ Tests
β βββ Lint
βββ Require branches to be up to date β
βββ Require signed commits (optional)
βββ Restrict pushes β
βββ No force pushes β
RULESETS (NEWER):
βββββββββββββββββββββββββββββββββββββ
GitHub Rulesets:
βββ Apply to multiple branches
βββ Pattern matching (release/*)
βββ Bypass permissions
βββ More granular control
βββ Organization-wide
BENEFITS:
βββββββββββββββββββββββββββββββββββββ
βββ Consistent quality
βββ No accidental pushes to main
βββ Reviews enforced
βββ Tests must pass
βββ Team alignment
βββ Automated enforcement
CI Per Branch Type
Conditional Workflows
CONDITIONAL CI PIPELINES
ββββββββββββββββββββββββ
BRANCH-BASED CI:
βββββββββββββββββββββββββββββββββββββ
Different pipelines per branch:
on:
push:
branches:
- main
- 'release/**'
- 'feature/**'
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm test
# Only on main
deploy-staging:
if: github.ref == 'refs/heads/main'
needs: test
runs-on: ubuntu-latest
steps:
- run: deploy-to-staging
# Only on release branches
deploy-production:
if: startsWith(github.ref, 'refs/heads/release/')
needs: test
runs-on: ubuntu-latest
steps:
- run: deploy-to-prod
FEATURE BRANCH STRATEGY:
βββββββββββββββββββββββββββββββββββββ
Feature branches:
βββ Run: lint, unit tests
βββ Skip: integration tests, deploy
βββ Fast feedback
βββ Lower resource usage
Main branch:
βββ Run: all tests
βββ Run: security scan
βββ Deploy: staging
βββ Full validation
Release branches:
βββ Run: all tests + smoke
βββ Deploy: production
βββ Tag release
βββ Full production path
Notifications
Awareness Automation
BRANCH NOTIFICATIONS
ββββββββββββββββββββ
LONG-LIVED BRANCH ALERTS:
βββββββββββββββββββββββββββββββββββββ
Alert when branch is too old:
- name: Check branch age
run: |
branch="${{ github.head_ref }}"
created=$(gh pr view ${{ github.event.pull_request.number }} \
--json createdAt -q '.createdAt')
days_old=$(( ($(date +%s) - $(date -d "$created" +%s)) / 86400 ))
if [ $days_old -gt 7 ]; then
gh pr comment ${{ github.event.pull_request.number }} \
--body "β οΈ This branch is $days_old days old. Consider merging or splitting."
fi
MERGE CONFLICT DETECTION:
βββββββββββββββββββββββββββββββββββββ
Check for conflicts:
βββ Automated check against main
βββ Alert if conflicts detected
βββ PR labels for conflict status
βββ Slack notification
βββ Early conflict resolution
BRANCH SYNC REMINDERS:
βββββββββββββββββββββββββββββββββββββ
βββ Notify when behind main
βββ Suggest rebase/merge
βββ Prevent large drift
βββ Keep branches current
GitScrum Integration
Branch-Task Connection
GITSCRUM BRANCH FEATURES
ββββββββββββββββββββββββ
AUTOMATIC LINKING:
βββββββββββββββββββββββββββββββββββββ
Branch naming includes task ID:
βββ feature/GS-123-user-auth
βββ GitScrum detects GS-123
βββ PR linked to task
βββ Activity visible on task
βββ Full traceability
STATUS UPDATES:
βββββββββββββββββββββββββββββββββββββ
βββ Branch created β Task "In Progress"
βββ PR opened β Task "In Review"
βββ PR merged β Task "Done"
βββ Automatic status flow
βββ No manual updates needed
VISIBILITY:
βββββββββββββββββββββββββββββββββββββ
On task card:
βββ See active branches
βββ See PR status
βββ See merge status
βββ Development context
βββ Complete picture
Best Practices
For Branch Automation
Anti-Patterns
BRANCH AUTOMATION MISTAKES:
β No branch protection on main
β Manual cleanup only
β Inconsistent naming
β Long-lived branches (weeks)
β Same CI for all branches
β No task linkage
β Branches never cleaned up
β Force push allowed on main