git-workflow
Agent Skill: Git workflow best practices for teams and CI/CD. Use when establishing branching strategies, implementing Conventional Commits, configuring PRs, or integrating Git with CI/CD. By Netresearch.
Packaged view
This page reorganizes the original catalog entry around fit, installability, and workflow context first. The original raw source lives below.
Install command
npx @skill-hub/cli install netresearch-claude-code-marketplace-git-workflow
Repository
Skill path: skills/git-workflow/skills/git-workflow
Agent Skill: Git workflow best practices for teams and CI/CD. Use when establishing branching strategies, implementing Conventional Commits, configuring PRs, or integrating Git with CI/CD. By Netresearch.
Open repositoryBest for
Primary workflow: Run DevOps.
Technical facets: Full Stack, DevOps.
Target audience: everyone.
License: Unknown.
Original source
Catalog source: SkillHub Club.
Repository owner: netresearch.
This is still a mirrored public skill entry. Review the repository before installing into production workflows.
What it helps with
- Install git-workflow into Claude Code, Codex CLI, Gemini CLI, or OpenCode workflows
- Review https://github.com/netresearch/claude-code-marketplace before adding git-workflow to shared team environments
- Use git-workflow for development workflows
Works across
Favorites: 0.
Sub-skills: 0.
Aggregator: No.
Original source / Raw SKILL.md
---
name: git-workflow
description: "Agent Skill: Git workflow best practices for teams and CI/CD. Use when establishing branching strategies, implementing Conventional Commits, configuring PRs, or integrating Git with CI/CD. By Netresearch."
---
# Git Workflow Skill
Expert patterns for Git version control: branching, commits, collaboration, and CI/CD.
## Expertise Areas
- **Branching**: Git Flow, GitHub Flow, Trunk-based development
- **Commits**: Conventional Commits, semantic versioning
- **Collaboration**: PR workflows, code review, merge strategies
- **CI/CD**: GitHub Actions, GitLab CI, branch protection
## Reference Files
Detailed documentation for each area:
- `references/branching-strategies.md` - Branch management patterns
- `references/commit-conventions.md` - Commit message standards
- `references/pull-request-workflow.md` - PR and review processes
- `references/ci-cd-integration.md` - Automation patterns
- `references/advanced-git.md` - Advanced Git operations
- `references/github-releases.md` - Release management, immutable releases
## Conventional Commits (Quick Reference)
```
<type>[scope]: <description>
```
**Types**: `feat` (MINOR), `fix` (PATCH), `docs`, `style`, `refactor`, `perf`, `test`, `build`, `ci`, `chore`, `revert`
**Breaking change**: Add `!` after type or `BREAKING CHANGE:` in footer.
## Branch Naming
```bash
feature/TICKET-123-description
fix/TICKET-456-bug-name
release/1.2.0
hotfix/1.2.1-security-patch
```
## GitHub Flow (Default)
```bash
git checkout main && git pull
git checkout -b feature/my-feature
# ... work ...
git push -u origin HEAD
gh pr create && gh pr merge --squash
```
## Verification
```bash
./scripts/verify-git-workflow.sh /path/to/repository
```
## GitHub Immutable Releases
**CRITICAL**: Deleted releases block tag names PERMANENTLY. Get releases right first time.
See `references/github-releases.md` for prevention and recovery patterns.
---
> **Contributing:** https://github.com/netresearch/git-workflow-skill
---
## Referenced Files
> The following files are referenced in this skill and included for context.
### references/branching-strategies.md
```markdown
# Git Branching Strategies
## Git Flow
### Overview
Git Flow is a branching model designed for projects with scheduled releases.
```
main ─────●─────────────────●─────────────────●─────── (production)
│ │ │
│ release/1.0 │ release/1.1 │
│ ┌───●───●────┤ ┌───●───●────┤
│ │ │ │ │
develop ──●────●────●───●───●────●────●───●───●─────── (integration)
│ │ │ │ │
│ │ │ │ └── feature/C
│ └────────┴────┴─────── feature/B
└─────────────────────────── feature/A
```
### Branch Types
| Branch | Purpose | Created From | Merges To |
|--------|---------|--------------|-----------|
| `main` | Production code | - | - |
| `develop` | Integration | `main` | `release` |
| `feature/*` | New features | `develop` | `develop` |
| `release/*` | Release prep | `develop` | `main`, `develop` |
| `hotfix/*` | Emergency fixes | `main` | `main`, `develop` |
### Commands
```bash
# Initialize
git flow init
# Feature
git flow feature start user-auth
git flow feature publish user-auth # Push to remote
git flow feature finish user-auth
# Release
git flow release start 1.2.0
git flow release publish 1.2.0
git flow release finish 1.2.0
# Hotfix
git flow hotfix start 1.2.1
git flow hotfix finish 1.2.1
```
### When to Use
**Good for:**
- Scheduled release cycles
- Long-lived feature branches
- Multiple versions in production
- Teams with dedicated release managers
**Avoid when:**
- Continuous deployment
- Small teams
- Rapid iteration needed
## GitHub Flow
### Overview
Simplified workflow ideal for continuous deployment.
```
main ───●───●───────────●───────●───●─── (always deployable)
│ │ │ │ │
│ └── PR #2 ──┘ │ └── PR #4
│ │
└───── PR #1 ───────────┴─────── PR #3
```
### Rules
1. `main` is always deployable
2. Create descriptive feature branches from `main`
3. Push commits regularly
4. Open PR for discussion/review
5. Merge after review and CI passes
6. Deploy immediately after merge
### Workflow
```bash
# 1. Start feature
git checkout main
git pull origin main
git checkout -b add-user-notifications
# 2. Develop with regular commits
git add .
git commit -m "feat: add notification service"
git push -u origin add-user-notifications
# 3. Create PR
gh pr create --title "Add user notifications" \
--body "Implements email and push notifications for users"
# 4. Address review feedback
git add .
git commit -m "fix: address review comments"
git push
# 5. Merge (after approval and CI)
gh pr merge --squash --delete-branch
# 6. Deploy (automatic via CI/CD)
```
### When to Use
**Good for:**
- Continuous deployment
- Web applications
- Small to medium teams
- Fast iteration cycles
**Avoid when:**
- Multiple versions in production
- Scheduled releases required
## Trunk-Based Development
### Overview
All developers work on a single branch with short-lived feature branches.
```
main ───●───●───●───●───●───●───●───●───●───●─── (trunk)
│ │ │ │ │ │
└─┬─┘ └───┬───┘ └───┬───┘
│ │ │
small small small
feature feature feature
(< 1 day) (< 1 day) (< 1 day)
```
### Principles
1. **Single branch**: All code goes to `main`/`trunk`
2. **Short-lived branches**: Max 1-2 days
3. **Feature flags**: Hide incomplete features
4. **Continuous integration**: Merge multiple times per day
5. **No long-running branches**: Avoid merge conflicts
### Workflow
```bash
# Start small feature (should complete today)
git checkout main
git pull
git checkout -b small-feature
# Work in small increments
git add .
git commit -m "feat: add basic structure"
git push
# Merge quickly (within hours/day)
gh pr create --title "Small feature"
gh pr merge --rebase
# Feature flags for incomplete work
if (featureFlags.isEnabled('new-checkout')) {
// New checkout flow
} else {
// Existing checkout flow
}
```
### Release Strategies
```bash
# Option 1: Release from trunk
git tag v1.2.0
git push origin v1.2.0
# Option 2: Release branches (for fixes)
git checkout -b release/1.2 main
# Cherry-pick fixes if needed
git cherry-pick <fix-commit>
git tag v1.2.1
```
### When to Use
**Good for:**
- Mature CI/CD pipelines
- High test coverage
- Experienced teams
- Microservices
**Avoid when:**
- Junior-heavy teams
- Low test coverage
- Multiple long-term versions
## GitLab Flow
### Overview
Combines feature branches with environment branches.
```
main ─────●─────●─────●─────●─────●───── (development)
│ │ │ │ │
▼ ▼ ▼ ▼ ▼
staging ──●─────●─────●─────●─────●───── (staging env)
│ │ │
▼ ▼ ▼
production ─────●───────────●─────●───── (production env)
```
### Environment Branches
```bash
# Feature development
git checkout -b feature/new-api main
# ... develop ...
git checkout main
git merge feature/new-api
# Promote to staging
git checkout staging
git merge main
# Promote to production (after staging verification)
git checkout production
git merge staging
git tag v1.2.0
```
### With Release Branches
```bash
# Support multiple versions
main
├── release/1.x
│ ├── 1.0.0
│ ├── 1.0.1
│ └── 1.1.0
└── release/2.x
├── 2.0.0
└── 2.0.1
```
## Choosing a Strategy
### Decision Matrix
| Factor | Git Flow | GitHub Flow | Trunk-Based | GitLab Flow |
|--------|----------|-------------|-------------|-------------|
| Release frequency | Scheduled | Continuous | Continuous | Environment-based |
| Team size | Large | Small-Medium | Any | Any |
| Version support | Multiple | Single | Single | Multiple |
| Branch complexity | High | Low | Very Low | Medium |
| CI/CD maturity | Any | Medium | High | Medium |
| Merge conflicts | More | Less | Least | Medium |
### Quick Guide
```
Need scheduled releases?
├── Yes → Multiple versions in production?
│ ├── Yes → Git Flow
│ └── No → GitLab Flow (with releases)
└── No → Continuous deployment ready?
├── Yes → High test coverage?
│ ├── Yes → Trunk-Based
│ └── No → GitHub Flow
└── No → GitHub Flow
```
## Branch Protection
### GitHub Branch Protection Rules
```yaml
# Settings > Branches > Branch protection rules
main:
require_pull_request:
required_approving_reviews: 2
dismiss_stale_reviews: true
require_code_owner_reviews: true
require_status_checks:
strict: true
contexts:
- "ci/lint"
- "ci/test"
- "ci/build"
require_conversation_resolution: true
require_signed_commits: false
include_administrators: true
allow_force_pushes: false
allow_deletions: false
```
### GitLab Protected Branches
```yaml
# Settings > Repository > Protected branches
main:
allowed_to_push:
- role: maintainer
allowed_to_merge:
- role: developer
allowed_to_force_push: false
code_owner_approval_required: true
```
## Migration Between Strategies
### Git Flow → GitHub Flow
```bash
# 1. Merge develop to main
git checkout main
git merge develop
# 2. Delete develop branch
git branch -d develop
git push origin --delete develop
# 3. Update CI/CD to deploy from main
# 4. Communicate new workflow to team
# 5. Update branch protection rules
```
### GitHub Flow → Trunk-Based
```bash
# 1. Implement feature flags
# 2. Increase test coverage
# 3. Set up continuous deployment
# 4. Shorten PR review cycle
# 5. Enforce small, frequent merges
```
```
### references/commit-conventions.md
```markdown
# Commit Conventions
## Conventional Commits
### Specification
```
<type>[optional scope]: <description>
[optional body]
[optional footer(s)]
```
### Commit Types
| Type | Description | Version Bump |
|------|-------------|--------------|
| `feat` | New feature | MINOR |
| `fix` | Bug fix | PATCH |
| `docs` | Documentation only | - |
| `style` | Code style (formatting) | - |
| `refactor` | Code refactoring | - |
| `perf` | Performance improvement | PATCH |
| `test` | Adding/updating tests | - |
| `build` | Build system changes | - |
| `ci` | CI configuration | - |
| `chore` | Maintenance tasks | - |
| `revert` | Reverting changes | - |
### Examples
```bash
# Simple feature
feat: add user authentication
# Feature with scope
feat(auth): add OAuth2 login support
# Bug fix
fix: resolve null pointer in user service
# Bug fix with issue reference
fix(api): handle empty response from external service
Fixes #123
# Breaking change
feat!: remove deprecated v1 API endpoints
BREAKING CHANGE: The /api/v1/* endpoints have been removed.
Migrate to /api/v2/* before upgrading.
# Multiple footers
fix(security): patch XSS vulnerability in comment parser
Reviewed-by: John Doe
Refs: #456
```
### Scope Guidelines
Scopes should be consistent across the project:
```bash
# By feature area
feat(auth): ...
feat(payment): ...
feat(notification): ...
# By layer
fix(api): ...
fix(db): ...
fix(ui): ...
# By component
style(button): ...
refactor(modal): ...
```
## Commit Message Best Practices
### Subject Line
```bash
# ✅ Good: Imperative mood, present tense
feat: add password reset functionality
fix: prevent duplicate form submissions
# ❌ Bad: Past tense, not imperative
feat: added password reset functionality
fix: fixed duplicate form submissions
# ✅ Good: Specific and concise
feat: implement rate limiting for API endpoints
# ❌ Bad: Vague
feat: improve API
# ✅ Good: Under 72 characters
fix: resolve race condition in cache invalidation
# ❌ Bad: Too long
fix: resolve the race condition that was occurring in the cache invalidation process when multiple users were accessing the same resource simultaneously
```
### Body
```bash
# When to include a body:
# - Complex changes needing explanation
# - Non-obvious implementation choices
# - Context for future readers
fix: prevent race condition in order processing
The previous implementation allowed concurrent modifications to the
same order, leading to inconsistent state.
This change introduces optimistic locking using version numbers.
When a conflict is detected, the operation is retried with fresh data.
The retry limit is set to 3 attempts to prevent infinite loops.
```
### Footer
```bash
# Issue references
fix: resolve login timeout
Fixes #123
Closes #456
# Breaking changes
feat!: update authentication API
BREAKING CHANGE: The `authenticate()` method now returns a Promise
instead of using callbacks. Update all call sites to use async/await.
# Co-authors
feat: implement new dashboard
Co-authored-by: Jane Doe <[email protected]>
Co-authored-by: John Smith <[email protected]>
# Review references
fix: patch security vulnerability
Reviewed-by: Security Team
Approved-by: @security-lead
```
## Atomic Commits
### Principles
1. **One logical change per commit**
2. **Each commit should compile/pass tests**
3. **Related changes grouped together**
4. **Unrelated changes in separate commits**
### Examples
```bash
# ❌ Bad: Multiple unrelated changes
git add .
git commit -m "feat: add login page and fix typo in readme and update deps"
# ✅ Good: Separate commits
git add src/pages/Login.tsx src/components/LoginForm.tsx
git commit -m "feat(auth): add login page with form validation"
git add README.md
git commit -m "docs: fix typo in installation instructions"
git add package.json package-lock.json
git commit -m "build: update dependencies to latest versions"
```
### Interactive Staging
```bash
# Stage specific hunks
git add -p
# Options:
# y - stage this hunk
# n - skip this hunk
# s - split into smaller hunks
# e - manually edit hunk
# q - quit
# Stage specific files
git add src/feature/
git commit -m "feat: add feature files"
git add tests/feature/
git commit -m "test: add tests for feature"
```
## Commit Templates
### Setup
```bash
# Create template file
cat > ~/.gitmessage << 'EOF'
# <type>(<scope>): <subject>
# |<---- Using a Maximum Of 50 Characters ---->|
# Explain why this change is being made
# |<---- Try To Limit Each Line to a Maximum Of 72 Characters ---->|
# Provide links or keys to any relevant tickets, articles or other resources
# Example: Fixes #23
# --- COMMIT END ---
# Type can be:
# feat (new feature)
# fix (bug fix)
# docs (changes to documentation)
# style (formatting, missing semi colons, etc; no code change)
# refactor (refactoring production code)
# test (adding missing tests, refactoring tests; no production code change)
# chore (updating grunt tasks etc; no production code change)
# perf (performance improvements)
# ci (CI configuration)
# build (build system changes)
# --------------------
EOF
# Configure git to use template
git config --global commit.template ~/.gitmessage
```
### Project-Specific Template
```bash
# .gitmessage in project root
# <type>(<scope>): <subject>
# Body: Explain the motivation for the change
# Footer:
# Fixes #issue
# BREAKING CHANGE: description
# ---
# Remember:
# - Use present tense ("add" not "added")
# - Use imperative mood ("move" not "moves")
# - First line max 50 chars, body wrap at 72
# - Reference issues and PRs at the bottom
```
## Commit Message Validation
### Git Hook (commit-msg)
```bash
#!/bin/bash
# .git/hooks/commit-msg
commit_msg_file=$1
commit_msg=$(cat "$commit_msg_file")
# Skip merge commits
if echo "$commit_msg" | grep -qE "^Merge"; then
exit 0
fi
# Conventional commit pattern
pattern="^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\([a-z0-9-]+\))?(!)?: .{1,50}"
if ! echo "$commit_msg" | head -1 | grep -qE "$pattern"; then
echo "ERROR: Invalid commit message format"
echo ""
echo "Expected: <type>(<scope>): <subject>"
echo " type: feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert"
echo " scope: optional, lowercase with hyphens"
echo " subject: max 50 chars, imperative mood"
echo ""
echo "Your message:"
echo " $(head -1 "$commit_msg_file")"
exit 1
fi
# Check subject line length
subject=$(echo "$commit_msg" | head -1)
if [ ${#subject} -gt 72 ]; then
echo "ERROR: Subject line too long (${#subject} > 72 chars)"
exit 1
fi
# Check for trailing period
if echo "$subject" | grep -qE "\.$"; then
echo "ERROR: Subject line should not end with a period"
exit 1
fi
exit 0
```
### commitlint Configuration
```javascript
// commitlint.config.js
module.exports = {
extends: ['@commitlint/config-conventional'],
rules: {
'type-enum': [2, 'always', [
'feat', 'fix', 'docs', 'style', 'refactor',
'perf', 'test', 'build', 'ci', 'chore', 'revert'
]],
'scope-case': [2, 'always', 'kebab-case'],
'subject-case': [2, 'always', 'lower-case'],
'subject-max-length': [2, 'always', 72],
'body-max-line-length': [2, 'always', 100],
},
};
```
```json
// package.json
{
"husky": {
"hooks": {
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS"
}
}
}
```
## Semantic Release Integration
### Configuration
```json
// .releaserc
{
"branches": ["main"],
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "conventionalcommits",
"releaseRules": [
{"type": "feat", "release": "minor"},
{"type": "fix", "release": "patch"},
{"type": "perf", "release": "patch"},
{"type": "revert", "release": "patch"},
{"breaking": true, "release": "major"}
]
}],
["@semantic-release/release-notes-generator", {
"preset": "conventionalcommits"
}],
"@semantic-release/changelog",
"@semantic-release/npm",
"@semantic-release/github"
]
}
```
### Version Bumping
```bash
# These commits determine version bumps:
# PATCH (1.0.x)
fix: correct typo in error message
perf: optimize database query
# MINOR (1.x.0)
feat: add user profile page
feat(api): implement caching layer
# MAJOR (x.0.0)
feat!: redesign authentication system
fix!: change API response format
BREAKING CHANGE: Response format changed from XML to JSON
```
## Rewriting History
### Amending Commits
```bash
# Fix last commit message
git commit --amend -m "feat: correct commit message"
# Add files to last commit
git add forgotten-file.js
git commit --amend --no-edit
# Change author
git commit --amend --author="Name <[email protected]>"
```
### Interactive Rebase
```bash
# Rewrite last 5 commits
git rebase -i HEAD~5
# Commands in editor:
# pick - use commit
# reword - edit message
# edit - stop and amend
# squash - combine with previous
# fixup - combine, discard message
# drop - remove commit
# Example: Squash fixup commits
pick abc1234 feat: add user API
fixup def5678 fixup! feat: add user API
pick ghi9012 feat: add admin API
```
### Fixup Commits
```bash
# Create fixup commit
git add .
git commit --fixup=abc1234
# Auto-squash during rebase
git rebase -i --autosquash main
```
## Best Practices Summary
1. **Write meaningful messages**: Future you will thank present you
2. **Use conventional commits**: Enable automated versioning
3. **Keep commits atomic**: One logical change per commit
4. **Reference issues**: Link commits to project management
5. **Use scopes consistently**: Help with changelog generation
6. **Don't include generated files**: Keep commits focused on source changes
7. **Sign commits** (optional): Verify authorship with GPG
```
### references/pull-request-workflow.md
```markdown
# Pull Request Workflow
## PR Best Practices
### Size Guidelines
| Size | Lines Changed | Review Time | Defect Risk |
|------|--------------|-------------|-------------|
| XS | 0-10 | < 5 min | Very Low |
| S | 11-100 | 15-30 min | Low |
| M | 101-400 | 30-60 min | Medium |
| L | 401-1000 | 1-2 hours | High |
| XL | 1000+ | Multiple sessions | Very High |
**Target**: Keep PRs under 400 lines when possible.
### PR Structure
```markdown
## Summary
Brief description of changes and motivation.
## Type of Change
- [ ] Bug fix (non-breaking change fixing an issue)
- [ ] New feature (non-breaking change adding functionality)
- [ ] Breaking change (fix or feature causing existing functionality to change)
- [ ] Documentation update
- [ ] Refactoring (no functional changes)
## Changes Made
- Added user authentication service
- Implemented JWT token generation
- Added login/logout endpoints
## Testing
- [ ] Unit tests added/updated
- [ ] Integration tests added/updated
- [ ] Manual testing performed
## Screenshots (if applicable)
[Before/After screenshots for UI changes]
## Related Issues
Fixes #123
Related to #456
## Checklist
- [ ] Code follows project style guidelines
- [ ] Self-review performed
- [ ] Documentation updated
- [ ] No new warnings introduced
- [ ] Tests pass locally
```
## Creating PRs
### GitHub CLI
```bash
# Create PR with title and body
gh pr create \
--title "feat(auth): add user authentication" \
--body "## Summary
Implements JWT-based authentication.
## Changes
- Add AuthService
- Add login/logout endpoints
- Add auth middleware
Fixes #123"
# Create draft PR
gh pr create --draft
# Create PR and assign reviewers
gh pr create \
--title "fix: resolve memory leak" \
--reviewer "@team-lead,@senior-dev" \
--assignee "@me"
# Create PR from template
gh pr create --template .github/PULL_REQUEST_TEMPLATE.md
```
### PR Templates
```markdown
<!-- .github/PULL_REQUEST_TEMPLATE.md -->
## Description
<!-- Describe your changes in detail -->
## Motivation and Context
<!-- Why is this change required? What problem does it solve? -->
## How Has This Been Tested?
<!-- Describe how you tested your changes -->
## Types of Changes
- [ ] Bug fix
- [ ] New feature
- [ ] Breaking change
- [ ] Documentation
## Checklist
- [ ] My code follows the code style of this project
- [ ] I have updated the documentation accordingly
- [ ] I have added tests to cover my changes
- [ ] All new and existing tests passed
```
### Multiple Templates
```
.github/
├── PULL_REQUEST_TEMPLATE.md # Default
└── PULL_REQUEST_TEMPLATE/
├── feature.md
├── bugfix.md
└── documentation.md
```
## Code Review Process
### Reviewer Responsibilities
1. **Code Quality**
- Readability and maintainability
- Adherence to coding standards
- Appropriate error handling
2. **Functionality**
- Logic correctness
- Edge cases handled
- Requirements met
3. **Testing**
- Test coverage adequate
- Tests meaningful and correct
- Edge cases tested
4. **Security**
- No obvious vulnerabilities
- Sensitive data handling
- Input validation
5. **Performance**
- No obvious bottlenecks
- Resource usage appropriate
- Scaling considerations
### Review Comments
```markdown
# Levels of feedback
# 🔴 Blocking - Must be addressed
This introduces a security vulnerability. User input is not sanitized
before being used in the SQL query.
# 🟡 Suggestion - Should consider
Consider extracting this logic into a separate function for reusability
and testing.
# 🟢 Nit - Minor issue
Nit: This variable name could be more descriptive.
`data` → `userProfileData`
# 💡 Question - Seeking understanding
Question: What's the reasoning behind using a Map here instead of an Object?
# 👍 Praise - Positive feedback
Nice catch handling the edge case where the array might be empty!
```
### Review Checklist
```markdown
## Code Review Checklist
### Code Quality
- [ ] Code is readable and self-documenting
- [ ] No unnecessary complexity
- [ ] DRY principle followed
- [ ] SOLID principles followed
### Testing
- [ ] Unit tests present and passing
- [ ] Edge cases covered
- [ ] Integration tests if needed
- [ ] No flaky tests introduced
### Security
- [ ] No hardcoded credentials
- [ ] Input validation present
- [ ] No SQL injection risks
- [ ] No XSS vulnerabilities
### Performance
- [ ] No N+1 queries
- [ ] Appropriate data structures used
- [ ] No memory leaks
- [ ] Caching considered
### Documentation
- [ ] README updated if needed
- [ ] API documentation updated
- [ ] Comments for complex logic
- [ ] CHANGELOG entry added
```
## Merge Strategies
### Merge Commit
```bash
# Creates a merge commit, preserves all history
git checkout main
git merge --no-ff feature/my-feature
# Result:
# * Merge branch 'feature/my-feature'
# |\
# | * feat: add feature part 2
# | * feat: add feature part 1
# |/
# * Previous main commit
```
**Use when:**
- Want to preserve complete branch history
- Complex features with meaningful intermediate commits
- Audit trail required
### Squash and Merge
```bash
# Combines all commits into one
git checkout main
git merge --squash feature/my-feature
git commit -m "feat: complete feature implementation"
# Result:
# * feat: complete feature implementation
# * Previous main commit
```
**Use when:**
- Feature branch has messy history
- WIP commits, fixups, "oops" commits
- Want clean linear history
### Rebase and Merge
```bash
# Replays commits on top of main
git checkout feature/my-feature
git rebase main
git checkout main
git merge --ff-only feature/my-feature
# Result:
# * feat: add feature part 2
# * feat: add feature part 1
# * Previous main commit
```
**Use when:**
- Clean commit history in feature branch
- Each commit is meaningful and tested
- Want linear history without merge commits
### Comparison
| Strategy | History | Complexity | Traceability |
|----------|---------|------------|--------------|
| Merge | Preserved | High | High |
| Squash | Combined | Low | Medium |
| Rebase | Linear | Low | Medium |
## Automated Checks
### GitHub Actions for PRs
```yaml
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
branches: [main, develop]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test -- --coverage
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run build
pr-size:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check PR size
run: |
ADDITIONS=$(gh pr view ${{ github.event.pull_request.number }} --json additions -q '.additions')
if [ "$ADDITIONS" -gt 1000 ]; then
echo "::warning::Large PR detected ($ADDITIONS lines). Consider splitting."
fi
env:
GH_TOKEN: ${{ secrets.GITHUB_TOKEN }}
```
### Required Status Checks
```yaml
# Branch protection settings
required_status_checks:
strict: true
contexts:
- lint
- test
- build
- security-scan
```
### CODEOWNERS
```bash
# .github/CODEOWNERS
# Default owners for everything
* @default-team
# Frontend owners
/src/components/ @frontend-team
/src/styles/ @frontend-team @design-team
# Backend owners
/src/api/ @backend-team
/src/database/ @backend-team @dba-team
# DevOps owners
/.github/ @devops-team
/docker/ @devops-team
/terraform/ @devops-team
# Documentation
/docs/ @docs-team
*.md @docs-team
# Security-sensitive files
/src/auth/ @security-team @backend-team
/src/crypto/ @security-team
```
## PR Lifecycle
### States
```
Draft → Ready for Review → Changes Requested → Approved → Merged
↑_____________________|
```
### Commands
```bash
# Check PR status
gh pr status
gh pr view 123
# Request review
gh pr edit 123 --add-reviewer "@reviewer1,@reviewer2"
# Mark ready for review
gh pr ready 123
# Convert to draft
gh pr ready 123 --undo
# Approve PR
gh pr review 123 --approve
# Request changes
gh pr review 123 --request-changes --body "Please fix X"
# Merge PR
gh pr merge 123 --squash --delete-branch
# Close without merging
gh pr close 123
```
### Handling Stale PRs
```yaml
# .github/workflows/stale.yml
name: Mark Stale PRs
on:
schedule:
- cron: '0 0 * * *' # Daily
jobs:
stale:
runs-on: ubuntu-latest
steps:
- uses: actions/stale@v9
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
stale-pr-message: 'This PR has been inactive for 14 days. Please update or close.'
days-before-stale: 14
days-before-close: 7
stale-pr-label: 'stale'
```
## Conflict Resolution
### Before Merging
```bash
# Update feature branch with latest main
git checkout feature/my-feature
git fetch origin
git rebase origin/main
# If conflicts occur
# 1. Edit conflicting files
# 2. Stage resolved files
git add <resolved-file>
# 3. Continue rebase
git rebase --continue
# Force push (only on feature branches!)
git push --force-with-lease
```
### Merge Conflicts in PR
```bash
# Option 1: Rebase (preferred for clean history)
git checkout feature/my-feature
git fetch origin
git rebase origin/main
# Resolve conflicts
git push --force-with-lease
# Option 2: Merge main into feature
git checkout feature/my-feature
git merge origin/main
# Resolve conflicts
git commit
git push
```
### Complex Conflicts
```bash
# Use a merge tool
git mergetool
# Or use specific tool
git mergetool --tool=vscode
git mergetool --tool=meld
# Configure default tool
git config --global merge.tool vscode
git config --global mergetool.vscode.cmd 'code --wait $MERGED'
```
## PR Analytics
### Metrics to Track
1. **PR Size**: Average lines changed
2. **Review Time**: Time from creation to first review
3. **Time to Merge**: Creation to merge
4. **Review Rounds**: Number of change requests
5. **Throughput**: PRs merged per week
### GitHub Insights
```bash
# List PR stats
gh pr list --state merged --json number,title,createdAt,mergedAt,additions,deletions
# PR age analysis
gh pr list --state open --json number,createdAt | jq 'map({number, age: (now - (.createdAt | fromdateiso8601)) / 86400})'
```
```
### references/ci-cd-integration.md
```markdown
# CI/CD Integration
## GitHub Actions
### Basic Workflow Structure
```yaml
# .github/workflows/ci.yml
name: CI
on:
push:
branches: [main, develop]
pull_request:
branches: [main, develop]
workflow_dispatch: # Manual trigger
env:
NODE_VERSION: '20'
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run build
```
### Complete CI Pipeline
```yaml
name: CI/CD Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
needs: lint
strategy:
matrix:
node: [18, 20, 22]
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
cache: 'npm'
- run: npm ci
- run: npm test -- --coverage
- uses: codecov/codecov-action@v4
if: matrix.node == 20
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: build
path: dist/
security:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run security audit
run: npm audit --audit-level=high
- name: Run Snyk
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
deploy-staging:
runs-on: ubuntu-latest
needs: [build, security]
if: github.ref == 'refs/heads/develop'
environment: staging
steps:
- uses: actions/download-artifact@v4
with:
name: build
path: dist/
- name: Deploy to staging
run: |
# Deploy commands here
deploy-production:
runs-on: ubuntu-latest
needs: [build, security]
if: github.ref == 'refs/heads/main'
environment: production
steps:
- uses: actions/download-artifact@v4
with:
name: build
path: dist/
- name: Deploy to production
run: |
# Deploy commands here
```
### Reusable Workflows
```yaml
# .github/workflows/reusable-test.yml
name: Reusable Test Workflow
on:
workflow_call:
inputs:
node-version:
required: true
type: string
secrets:
npm-token:
required: false
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
- run: npm test
```
```yaml
# .github/workflows/ci.yml
name: CI
on: [push, pull_request]
jobs:
call-test:
uses: ./.github/workflows/reusable-test.yml
with:
node-version: '20'
secrets:
npm-token: ${{ secrets.NPM_TOKEN }}
```
### Matrix Builds
```yaml
jobs:
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node: [18, 20, 22]
exclude:
- os: windows-latest
node: 18
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node }}
- run: npm ci
- run: npm test
```
## GitLab CI
### Basic Pipeline
```yaml
# .gitlab-ci.yml
stages:
- build
- test
- deploy
variables:
NODE_VERSION: "20"
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
build:
stage: build
image: node:${NODE_VERSION}
script:
- npm ci
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 hour
test:
stage: test
image: node:${NODE_VERSION}
script:
- npm ci
- npm test
coverage: '/All files[^|]*\|[^|]*\s+([\d\.]+)/'
deploy_staging:
stage: deploy
script:
- ./deploy.sh staging
environment:
name: staging
url: https://staging.example.com
only:
- develop
deploy_production:
stage: deploy
script:
- ./deploy.sh production
environment:
name: production
url: https://example.com
only:
- main
when: manual
```
### Multi-Stage Pipeline
```yaml
stages:
- prepare
- build
- test
- security
- deploy
.node-base:
image: node:20
cache:
key: ${CI_COMMIT_REF_SLUG}
paths:
- node_modules/
install:
extends: .node-base
stage: prepare
script:
- npm ci
artifacts:
paths:
- node_modules/
expire_in: 1 hour
lint:
extends: .node-base
stage: build
needs: [install]
script:
- npm run lint
build:
extends: .node-base
stage: build
needs: [install]
script:
- npm run build
artifacts:
paths:
- dist/
expire_in: 1 day
unit-test:
extends: .node-base
stage: test
needs: [install]
script:
- npm run test:unit
coverage: '/Statements\s*:\s*(\d+\.?\d*)%/'
integration-test:
extends: .node-base
stage: test
needs: [build]
services:
- postgres:15
variables:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
script:
- npm run test:integration
security-audit:
stage: security
needs: [install]
script:
- npm audit --audit-level=high
allow_failure: true
sast:
stage: security
include:
- template: Security/SAST.gitlab-ci.yml
```
## Semantic Release
### Configuration
```json
// .releaserc.json
{
"branches": [
"main",
{"name": "beta", "prerelease": true},
{"name": "alpha", "prerelease": true}
],
"plugins": [
["@semantic-release/commit-analyzer", {
"preset": "conventionalcommits",
"releaseRules": [
{"type": "feat", "release": "minor"},
{"type": "fix", "release": "patch"},
{"type": "perf", "release": "patch"},
{"breaking": true, "release": "major"}
]
}],
["@semantic-release/release-notes-generator", {
"preset": "conventionalcommits",
"presetConfig": {
"types": [
{"type": "feat", "section": "Features"},
{"type": "fix", "section": "Bug Fixes"},
{"type": "perf", "section": "Performance"},
{"type": "revert", "section": "Reverts"}
]
}
}],
["@semantic-release/changelog", {
"changelogFile": "CHANGELOG.md"
}],
["@semantic-release/npm", {
"npmPublish": true
}],
["@semantic-release/git", {
"assets": ["CHANGELOG.md", "package.json"],
"message": "chore(release): ${nextRelease.version} [skip ci]"
}],
"@semantic-release/github"
]
}
```
### GitHub Actions Integration
```yaml
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'
- run: npm ci
- name: Release
env:
GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}
NPM_TOKEN: ${{ secrets.NPM_TOKEN }}
run: npx semantic-release
```
## Branch Protection
### GitHub Settings
```yaml
# Via GitHub API or settings UI
branch_protection:
main:
required_status_checks:
strict: true
contexts:
- lint
- test
- build
- security
required_pull_request_reviews:
required_approving_review_count: 2
dismiss_stale_reviews: true
require_code_owner_reviews: true
restrictions:
users: []
teams: [core-team]
enforce_admins: true
require_linear_history: true
allow_force_pushes: false
allow_deletions: false
```
### GitLab Settings
```yaml
# Via GitLab API or settings UI
protected_branches:
main:
push_access_level: maintainer
merge_access_level: developer
unprotect_access_level: admin
code_owner_approval_required: true
merge_request_approvals:
approvals_before_merge: 2
reset_approvals_on_push: true
```
## Automated Testing
### Pre-merge Checks
```yaml
# .github/workflows/pr-checks.yml
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
analyze:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Check PR size
run: |
LINES=$(git diff --numstat origin/main...HEAD | awk '{sum += $1 + $2} END {print sum}')
if [ "$LINES" -gt 1000 ]; then
echo "::warning::Large PR ($LINES lines). Consider splitting."
fi
- name: Check commit messages
run: |
git log origin/main..HEAD --pretty=format:"%s" | while read msg; do
if ! echo "$msg" | grep -qE "^(feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)"; then
echo "::error::Invalid commit message: $msg"
exit 1
fi
done
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm test -- --coverage --changedSince=origin/main
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- run: npm run lint -- --max-warnings 0
```
### E2E Testing
```yaml
name: E2E Tests
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
e2e:
runs-on: ubuntu-latest
services:
postgres:
image: postgres:15
env:
POSTGRES_DB: test
POSTGRES_USER: test
POSTGRES_PASSWORD: test
ports:
- 5432:5432
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
- run: npm ci
- name: Start application
run: npm start &
env:
DATABASE_URL: postgres://test:test@localhost:5432/test
- name: Wait for app
run: npx wait-on http://localhost:3000
- name: Run E2E tests
run: npm run test:e2e
- uses: actions/upload-artifact@v4
if: failure()
with:
name: e2e-screenshots
path: cypress/screenshots/
```
## Deployment Strategies
### Blue-Green Deployment
```yaml
name: Blue-Green Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy to green
run: |
kubectl apply -f k8s/green-deployment.yaml
kubectl rollout status deployment/app-green
- name: Run smoke tests
run: ./scripts/smoke-test.sh green
- name: Switch traffic
run: |
kubectl patch service app -p '{"spec":{"selector":{"version":"green"}}}'
- name: Cleanup blue
run: |
kubectl delete deployment app-blue || true
```
### Canary Deployment
```yaml
name: Canary Deploy
on:
push:
branches: [main]
jobs:
canary:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy canary (10%)
run: |
kubectl apply -f k8s/canary-deployment.yaml
kubectl set image deployment/app-canary app=${{ env.IMAGE }}
- name: Monitor canary
run: |
sleep 300 # 5 minutes
ERROR_RATE=$(./scripts/get-error-rate.sh canary)
if [ "$ERROR_RATE" -gt 5 ]; then
echo "High error rate, rolling back"
kubectl rollout undo deployment/app-canary
exit 1
fi
- name: Full rollout
run: |
kubectl set image deployment/app app=${{ env.IMAGE }}
kubectl rollout status deployment/app
```
## Notifications
### Slack Integration
```yaml
name: CI with Notifications
on: [push, pull_request]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm test
- name: Notify Slack on failure
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "Build failed on ${{ github.ref }}",
"blocks": [
{
"type": "section",
"text": {
"type": "mrkdwn",
"text": "*Build Failed* :x:\n*Branch:* ${{ github.ref }}\n*Commit:* ${{ github.sha }}\n<${{ github.server_url }}/${{ github.repository }}/actions/runs/${{ github.run_id }}|View Run>"
}
}
]
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
```
## Best Practices
1. **Fast Feedback**: Keep CI under 10 minutes
2. **Parallel Jobs**: Run independent jobs concurrently
3. **Caching**: Cache dependencies and build artifacts
4. **Fail Fast**: Stop on first failure in PR checks
5. **Environment Parity**: Match CI environment to production
6. **Secrets Management**: Use encrypted secrets, rotate regularly
7. **Artifact Retention**: Clean up old artifacts
8. **Status Checks**: Require all checks to pass before merge
```
### references/advanced-git.md
```markdown
# Advanced Git Operations
## Rewriting History
### Interactive Rebase
```bash
# Rebase last N commits
git rebase -i HEAD~5
# Rebase from a specific commit
git rebase -i abc1234^
# Commands available:
# p, pick - use commit
# r, reword - edit commit message
# e, edit - stop for amending
# s, squash - combine with previous (keep message)
# f, fixup - combine with previous (discard message)
# d, drop - remove commit
# x, exec - run shell command
```
### Squashing Commits
```bash
# Squash last 3 commits
git rebase -i HEAD~3
# Change 'pick' to 'squash' for commits to combine
# Squash into a specific commit
git rebase -i <commit-before-first-to-squash>^
# Auto-squash fixup commits
git commit --fixup=<commit-hash>
git rebase -i --autosquash main
```
### Splitting Commits
```bash
# Start interactive rebase
git rebase -i HEAD~3
# Mark commit to split with 'edit'
# When stopped at that commit:
git reset HEAD^
git add file1.js
git commit -m "feat: first change"
git add file2.js
git commit -m "feat: second change"
git rebase --continue
```
### Reordering Commits
```bash
# Interactive rebase
git rebase -i HEAD~5
# In editor, reorder lines to reorder commits
# Example:
# pick abc1234 feat: feature A
# pick def5678 feat: feature B
# Changes to:
# pick def5678 feat: feature B
# pick abc1234 feat: feature A
```
## Cherry-Picking
### Basic Cherry-Pick
```bash
# Pick a single commit
git cherry-pick abc1234
# Pick multiple commits
git cherry-pick abc1234 def5678 ghi9012
# Pick a range
git cherry-pick abc1234^..def5678
# Cherry-pick without committing
git cherry-pick -n abc1234
```
### Cherry-Pick Options
```bash
# Keep original author
git cherry-pick -x abc1234
# Sign off
git cherry-pick -s abc1234
# Edit commit message
git cherry-pick -e abc1234
# Continue after conflict
git cherry-pick --continue
# Abort cherry-pick
git cherry-pick --abort
```
### Cherry-Pick Workflow
```bash
# Backport fix to release branch
git checkout release/1.0
git cherry-pick abc1234 # Fix from main
git push origin release/1.0
# Apply multiple fixes
git cherry-pick abc1234 def5678
# Or create a cherry-pick branch
git checkout -b cherry-pick-fixes release/1.0
git cherry-pick abc1234 def5678
git checkout release/1.0
git merge --no-ff cherry-pick-fixes
```
## Stashing
### Basic Stash Operations
```bash
# Stash current changes
git stash
# Stash with message
git stash save "Work in progress on feature X"
# List stashes
git stash list
# Apply latest stash (keep in stash list)
git stash apply
# Apply and remove from stash list
git stash pop
# Apply specific stash
git stash apply stash@{2}
# Drop a stash
git stash drop stash@{1}
# Clear all stashes
git stash clear
```
### Advanced Stashing
```bash
# Stash including untracked files
git stash -u
# Stash including ignored files
git stash -a
# Stash specific files
git stash push -m "message" file1.js file2.js
# Create branch from stash
git stash branch new-branch stash@{0}
# Show stash contents
git stash show stash@{0}
git stash show -p stash@{0} # With diff
# Partial stash (interactive)
git stash -p
```
## Bisecting
### Finding Bug Introduction
```bash
# Start bisect
git bisect start
# Mark current as bad
git bisect bad
# Mark known good commit
git bisect good v1.0.0
# Git will checkout middle commit
# Test, then mark:
git bisect good # If bug not present
git bisect bad # If bug present
# Continue until found
# Git reports: "abc1234 is the first bad commit"
# End bisect
git bisect reset
```
### Automated Bisect
```bash
# Run script at each step
git bisect start HEAD v1.0.0
git bisect run npm test
# With custom script
git bisect run ./test-for-bug.sh
# Exit codes:
# 0 - good
# 1-124 - bad
# 125 - skip (can't test this commit)
# 126+ - abort bisect
```
### Bisect Log
```bash
# Show bisect log
git bisect log
# Save bisect log
git bisect log > bisect.log
# Replay bisect
git bisect replay bisect.log
```
## Reflog
### Understanding Reflog
```bash
# Show reflog
git reflog
# Show reflog for specific ref
git reflog show main
git reflog show HEAD
# Output:
# abc1234 HEAD@{0}: commit: feat: add feature
# def5678 HEAD@{1}: checkout: moving from main to feature
# ghi9012 HEAD@{2}: commit: fix: bug fix
```
### Recovering Lost Commits
```bash
# Find lost commit in reflog
git reflog
# Recover commit
git checkout abc1234
git checkout -b recovered-branch
# Or cherry-pick
git cherry-pick abc1234
# Recover after bad reset
git reflog
git reset --hard HEAD@{2}
```
### Reflog Expiration
```bash
# Default: 90 days for reachable, 30 for unreachable
git config gc.reflogExpire 90.days
git config gc.reflogExpireUnreachable 30.days
# Expire reflog manually
git reflog expire --expire=now --all
git gc --prune=now
```
## Worktrees
### Multiple Working Directories
```bash
# Add worktree
git worktree add ../project-feature feature-branch
# Add worktree with new branch
git worktree add -b new-feature ../project-new-feature main
# List worktrees
git worktree list
# Remove worktree
git worktree remove ../project-feature
# Prune stale worktree info
git worktree prune
```
### Use Cases
```bash
# Work on hotfix while keeping feature work
git worktree add ../project-hotfix hotfix/critical-bug
cd ../project-hotfix
# Fix bug
git commit -am "fix: critical bug"
cd ../project-main
# Review PR without stashing
git worktree add ../pr-review origin/feature-branch
cd ../pr-review
# Review code
```
## Submodules
### Adding Submodules
```bash
# Add submodule
git submodule add https://github.com/org/repo.git libs/repo
# Add at specific branch
git submodule add -b main https://github.com/org/repo.git libs/repo
# Initialize submodules after clone
git submodule init
git submodule update
# Clone with submodules
git clone --recurse-submodules https://github.com/org/main-repo.git
```
### Updating Submodules
```bash
# Update all submodules to latest
git submodule update --remote
# Update specific submodule
git submodule update --remote libs/repo
# Update and merge
git submodule update --remote --merge
# Pull in main repo and submodules
git pull --recurse-submodules
```
### Submodule Commands
```bash
# Run command in all submodules
git submodule foreach 'git pull origin main'
# Check status
git submodule status
# Remove submodule
git submodule deinit libs/repo
git rm libs/repo
rm -rf .git/modules/libs/repo
```
## Git Hooks
### Client-Side Hooks
```bash
# .git/hooks/pre-commit
#!/bin/bash
npm run lint
npm run test
# .git/hooks/commit-msg
#!/bin/bash
# Validate commit message format
# .git/hooks/pre-push
#!/bin/bash
npm run test:e2e
```
### Server-Side Hooks
```bash
# hooks/pre-receive
#!/bin/bash
# Validate pushes before accepting
# hooks/post-receive
#!/bin/bash
# Deploy after push accepted
# hooks/update
#!/bin/bash
# Per-branch validation
```
### Hook Management with Husky
```json
// package.json
{
"husky": {
"hooks": {
"pre-commit": "lint-staged",
"commit-msg": "commitlint -E HUSKY_GIT_PARAMS",
"pre-push": "npm test"
}
},
"lint-staged": {
"*.{js,ts}": ["eslint --fix", "prettier --write"]
}
}
```
## Advanced Merging
### Merge Strategies
```bash
# Recursive (default)
git merge feature
# Ours (keep our changes)
git merge -s ours feature
# Subtree (merge into subdirectory)
git merge -s subtree --allow-unrelated-histories other-repo/main
# Octopus (merge multiple branches)
git merge feature1 feature2 feature3
```
### Merge Options
```bash
# No fast-forward
git merge --no-ff feature
# Squash merge
git merge --squash feature
# Merge with message
git merge -m "Merge feature X" feature
# Abort merge
git merge --abort
```
### Rerere (Reuse Recorded Resolution)
```bash
# Enable rerere
git config rerere.enabled true
# After resolving conflict, it's recorded
# Next time same conflict occurs, auto-resolved
# View recorded resolutions
git rerere status
# Forget resolution
git rerere forget path/to/file
```
## Git Attributes
### Line Endings
```bash
# .gitattributes
* text=auto
*.sh text eol=lf
*.bat text eol=crlf
*.png binary
```
### Diff and Merge
```bash
# .gitattributes
*.min.js binary
*.lock -diff
*.pdf diff=pdf
# Custom diff driver
[diff "pdf"]
textconv = pdftotext -layout
```
### Export Ignore
```bash
# .gitattributes
.gitignore export-ignore
.github export-ignore
tests/ export-ignore
```
## Performance Optimization
### Large Repositories
```bash
# Shallow clone
git clone --depth 1 https://github.com/org/repo.git
# Sparse checkout
git clone --filter=blob:none --sparse https://github.com/org/repo.git
cd repo
git sparse-checkout set src/
# Partial clone
git clone --filter=blob:none https://github.com/org/repo.git
```
### Git LFS
```bash
# Install LFS
git lfs install
# Track large files
git lfs track "*.psd"
git lfs track "*.zip"
# View tracked patterns
git lfs track
# View LFS files
git lfs ls-files
# Pull LFS files
git lfs pull
```
### Repository Maintenance
```bash
# Garbage collection
git gc
# Aggressive gc
git gc --aggressive
# Prune unreachable objects
git prune
# Verify repository
git fsck
# Repack
git repack -a -d
```
## Troubleshooting
### Common Issues
```bash
# Fix "detached HEAD"
git checkout -b new-branch # If you want to keep changes
git checkout main # If you want to discard
# Fix "refusing to merge unrelated histories"
git merge --allow-unrelated-histories other-branch
# Fix corrupted repository
git fsck --full
git gc --prune=now
# Remove file from all history
git filter-branch --force --index-filter \
'git rm --cached --ignore-unmatch path/to/file' \
--prune-empty --tag-name-filter cat -- --all
```
### Recovery Operations
```bash
# Recover deleted branch
git reflog
git checkout -b recovered abc1234
# Recover deleted file
git checkout HEAD~1 -- path/to/file
# Undo hard reset
git reflog
git reset --hard HEAD@{1}
# Recover stash
git fsck --unreachable | grep commit | cut -d' ' -f3 | \
xargs git log --merges --no-walk --grep=WIP
```
```
### references/github-releases.md
```markdown
# GitHub Releases Reference
**Purpose:** Document GitHub release management, immutable releases security feature, and release sequence patterns.
---
## Immutable Releases Security Feature
### Overview
**GitHub Immutable Releases** (GA October 2024) is a permanent security feature that prevents tag name reuse after a release is deleted.
**Security Purpose:** Prevents supply chain attacks where an attacker could:
1. Delete a legitimate release
2. Create a new release with the same version containing malicious code
3. Users downloading "v1.2.3" would get the malicious version
### Behavior
| Action | Result |
|--------|--------|
| Create release v1.2.3 | ✅ Success |
| Delete release v1.2.3 | ✅ Allowed |
| Create NEW release v1.2.3 | ❌ PERMANENTLY BLOCKED |
| Create release v1.2.4 | ✅ Success (new version) |
### Key Facts
- **Cannot be disabled:** No repository setting, API call, or GitHub support request can bypass this
- **Permanent:** Once blocked, a tag name stays blocked forever
- **Per-repository:** Each repository has its own blocked tag list
- **Applies to:** Published releases only (not draft releases)
### Detection
```bash
# Attempt to create release - if blocked, you'll see:
# "tag_name was used by an immutable release"
gh release create v1.2.3 --notes "test" 2>&1 | grep -i "immutable"
```
---
## Release Sequence Patterns
### TYPO3 Extension Release
**Correct Sequence:**
```bash
# 1. Create release branch
git checkout -b release/v1.2.3
# 2. Update version in source files
# ext_emconf.php
sed -i "s/'version' => '.*'/'version' => '1.2.3'/" ext_emconf.php
# CHANGELOG.md - add new version section
# 3. Commit version bump
git add ext_emconf.php CHANGELOG.md
git commit -m "chore: bump version to 1.2.3"
# 4. Create PR and merge
git push -u origin release/v1.2.3
gh pr create --title "chore: bump version to 1.2.3"
# Wait for CI to pass
gh pr merge --squash
# 5. Switch to main and verify
git checkout main && git pull
grep "'version'" ext_emconf.php # MUST show 1.2.3
# 6. Create release ONLY after verification
gh release create v1.2.3 \
--title "v1.2.3" \
--notes "Release notes here"
```
**Common Mistakes:**
| Mistake | Consequence |
|---------|-------------|
| Create release before updating version | Version mismatch, TER/npm publish fails |
| Create release before merging PR | Tag points to wrong commit |
| Delete release to "fix" something | Tag name permanently blocked |
| Rush without verification | Multiple blocked versions |
### NPM Package Release
```bash
# 1. Update package.json version
npm version patch # or minor/major
# 2. Verify version
grep '"version"' package.json
# 3. Push changes
git push && git push --tags
# 4. Create GitHub release (if using GitHub releases)
gh release create v$(node -p "require('./package.json').version")
```
### Python Package Release
```bash
# 1. Update version in pyproject.toml or setup.py
# 2. Update CHANGELOG
# 3. Commit and push
git add pyproject.toml CHANGELOG.md
git commit -m "chore: bump version to 1.2.3"
git push
# 4. Create and push tag
git tag v1.2.3
git push --tags
# 5. Create release
gh release create v1.2.3
```
---
## Pre-Release Validation
### Automated Checks
Add to CI workflow:
```yaml
- name: Version Consistency Check
run: |
# Extract versions from different sources
EMCONF_VERSION=$(grep -oP "'version' => '\K[0-9]+\.[0-9]+\.[0-9]+" ext_emconf.php)
# For tagged builds, verify tag matches
if [[ "${GITHUB_REF}" =~ ^refs/tags/v ]]; then
TAG_VERSION="${GITHUB_REF#refs/tags/v}"
if [[ "${TAG_VERSION}" != "${EMCONF_VERSION}" ]]; then
echo "::error::Version mismatch! Tag: ${TAG_VERSION}, ext_emconf.php: ${EMCONF_VERSION}"
exit 1
fi
fi
echo "Version check passed: ${EMCONF_VERSION}"
```
### Manual Checklist
Before creating ANY release:
```
[ ] All code changes merged to main/master
[ ] CI pipeline passes on main branch
[ ] Version updated in ALL source files:
[ ] ext_emconf.php (TYPO3)
[ ] package.json (Node)
[ ] pyproject.toml / setup.py (Python)
[ ] composer.json (if version is tracked there)
[ ] CHANGELOG.md updated with new version
[ ] Local main is up to date: git pull origin main
[ ] Version verification: grep -r "version" | grep "1.2.3"
[ ] READY - No second chances after release creation!
```
---
## Recovery Procedures
### Scenario: TER/npm/PyPI Publish Failed After Release
**DO NOT DELETE THE RELEASE!**
Instead:
1. Identify the root cause of publish failure
2. Fix the issue in a new commit
3. Update version to NEXT number (skipping the broken version)
4. Create new release with new version
Example:
```bash
# v1.2.3 release created but TER publish failed
# DO NOT: gh release delete v1.2.3
# Fix the issue
vim ext_emconf.php # remove strict_types or fix other issues
# Bump to NEXT version
sed -i "s/'version' => '1.2.3'/'version' => '1.2.4'/" ext_emconf.php
# Update CHANGELOG
cat >> CHANGELOG.md << 'EOF'
## [1.2.4] - 2025-01-15
### Fixed
- Fixed TER publishing issue (strict_types in ext_emconf.php)
Note: v1.2.3 was skipped due to publish failure.
EOF
# Commit, merge, then create new release
git add -A && git commit -m "fix: resolve TER publish issue, bump to 1.2.4"
git push && gh pr create && gh pr merge
gh release create v1.2.4 --notes "..."
```
### Scenario: Multiple Versions Blocked
If you've blocked v1.2.3, v1.2.4, v1.2.5 through repeated failures:
1. **Stop and think** - don't create more releases
2. List what went wrong each time
3. Fix ALL issues before next attempt
4. Use next available version (v1.2.6)
5. Document skipped versions in CHANGELOG
```markdown
## [1.2.6] - 2025-01-15
Note: Versions 1.2.3-1.2.5 are unavailable due to GitHub's immutable
releases feature. These versions were blocked after release deletion
attempts during troubleshooting.
### Fixed
- Resolved TER compatibility issue with ext_emconf.php
```
---
## Best Practices
### Do
- ✅ Update version files BEFORE creating release
- ✅ Verify version with grep before release
- ✅ Use CI checks for version consistency
- ✅ Keep releases - never delete published releases
- ✅ Test publish process in staging first (if possible)
### Don't
- ❌ Create release before version is updated in source
- ❌ Delete releases to "fix" issues
- ❌ Rush releases without verification
- ❌ Assume you can recreate a deleted release
- ❌ Create multiple releases hoping one will work
---
## Resources
- **GitHub Blog:** Immutable Releases announcement
- **GitHub Docs:** Managing releases in a repository
- **TYPO3 TER:** Extension publishing requirements
```
### scripts/verify-git-workflow.sh
```bash
#!/bin/bash
# Git Workflow Verification Script
# Checks repository for git workflow best practices
set -e
REPO_DIR="${1:-.}"
ERRORS=0
WARNINGS=0
echo "=== Git Workflow Verification ==="
echo "Repository: $REPO_DIR"
echo ""
# Change to repo directory
cd "$REPO_DIR"
# Check if it's a git repository
if [[ ! -d ".git" ]]; then
echo "❌ Not a git repository"
exit 1
fi
# Check branch naming
echo "=== Branch Naming Convention ==="
BRANCHES=$(git branch -a 2>/dev/null | sed 's/^[* ]*//' | grep -v "HEAD" | sed 's/remotes\/origin\///' | sort -u)
VALID_PATTERN="^(main|master|develop|feature\/|fix\/|bugfix\/|hotfix\/|release\/|chore\/|docs\/|test\/|refactor\/)"
INVALID_BRANCHES=""
for branch in $BRANCHES; do
if ! echo "$branch" | grep -qE "$VALID_PATTERN"; then
INVALID_BRANCHES="$INVALID_BRANCHES $branch"
fi
done
if [[ -n "$INVALID_BRANCHES" ]]; then
echo "⚠️ Non-standard branch names found:"
echo " $INVALID_BRANCHES"
echo " Expected: main, develop, feature/*, fix/*, release/*, hotfix/*"
((WARNINGS++))
else
echo "✅ All branch names follow conventions"
fi
# Check commit message format
echo ""
echo "=== Commit Message Format ==="
RECENT_COMMITS=$(git log --oneline -20 2>/dev/null | head -20)
CONV_PATTERN="^[a-f0-9]+ (feat|fix|docs|style|refactor|perf|test|build|ci|chore|revert)(\(.+\))?(!)?: .+"
INVALID_COMMITS=0
VALID_COMMITS=0
while IFS= read -r commit; do
if echo "$commit" | grep -qE "$CONV_PATTERN"; then
((VALID_COMMITS++))
else
# Allow merge commits
if ! echo "$commit" | grep -qE "^[a-f0-9]+ Merge"; then
((INVALID_COMMITS++))
fi
fi
done <<< "$RECENT_COMMITS"
TOTAL_COMMITS=$((VALID_COMMITS + INVALID_COMMITS))
if [[ $TOTAL_COMMITS -gt 0 ]]; then
PERCENT=$((VALID_COMMITS * 100 / TOTAL_COMMITS))
if [[ $PERCENT -ge 80 ]]; then
echo "✅ $PERCENT% of commits follow Conventional Commits format"
elif [[ $PERCENT -ge 50 ]]; then
echo "⚠️ $PERCENT% of commits follow Conventional Commits format"
((WARNINGS++))
else
echo "⚠️ Only $PERCENT% of commits follow Conventional Commits format"
((WARNINGS++))
fi
fi
# Check for .gitignore
echo ""
echo "=== .gitignore Check ==="
if [[ -f ".gitignore" ]]; then
echo "✅ .gitignore exists"
# Check for common patterns
COMMON_IGNORES=("node_modules" ".env" "*.log" "dist" "build" ".DS_Store")
MISSING_IGNORES=""
for pattern in "${COMMON_IGNORES[@]}"; do
if ! grep -q "$pattern" .gitignore 2>/dev/null; then
MISSING_IGNORES="$MISSING_IGNORES $pattern"
fi
done
if [[ -n "$MISSING_IGNORES" ]]; then
echo " ℹ️ Consider adding:$MISSING_IGNORES"
fi
else
echo "⚠️ No .gitignore file found"
((WARNINGS++))
fi
# Check for hooks
echo ""
echo "=== Git Hooks ==="
if [[ -d ".git/hooks" ]]; then
ACTIVE_HOOKS=$(find .git/hooks -type f ! -name "*.sample" 2>/dev/null | wc -l)
if [[ $ACTIVE_HOOKS -gt 0 ]]; then
echo "✅ Found $ACTIVE_HOOKS active hook(s)"
find .git/hooks -type f ! -name "*.sample" -exec basename {} \; 2>/dev/null | sed 's/^/ /'
else
echo "ℹ️ No active git hooks"
fi
fi
# Check for husky
if [[ -d ".husky" ]]; then
echo "✅ Husky hooks directory found"
fi
# Check for commitlint
if [[ -f "commitlint.config.js" ]] || [[ -f ".commitlintrc" ]] || [[ -f ".commitlintrc.json" ]]; then
echo "✅ Commitlint configuration found"
fi
# Check for branch protection (via CODEOWNERS)
echo ""
echo "=== Code Ownership ==="
if [[ -f "CODEOWNERS" ]] || [[ -f ".github/CODEOWNERS" ]] || [[ -f "docs/CODEOWNERS" ]]; then
echo "✅ CODEOWNERS file found"
else
echo "ℹ️ No CODEOWNERS file (optional)"
fi
# Check for PR template
echo ""
echo "=== PR Templates ==="
if [[ -f ".github/PULL_REQUEST_TEMPLATE.md" ]] || [[ -d ".github/PULL_REQUEST_TEMPLATE" ]]; then
echo "✅ PR template(s) found"
else
echo "ℹ️ No PR template (recommended)"
fi
# Check for CI/CD configuration
echo ""
echo "=== CI/CD Configuration ==="
CI_FOUND=false
if [[ -d ".github/workflows" ]]; then
WORKFLOW_COUNT=$(find .github/workflows -name "*.yml" -o -name "*.yaml" 2>/dev/null | wc -l)
if [[ $WORKFLOW_COUNT -gt 0 ]]; then
echo "✅ GitHub Actions: $WORKFLOW_COUNT workflow(s)"
CI_FOUND=true
fi
fi
if [[ -f ".gitlab-ci.yml" ]]; then
echo "✅ GitLab CI configuration found"
CI_FOUND=true
fi
if [[ -f "Jenkinsfile" ]]; then
echo "✅ Jenkinsfile found"
CI_FOUND=true
fi
if [[ -f ".circleci/config.yml" ]]; then
echo "✅ CircleCI configuration found"
CI_FOUND=true
fi
if [[ -f "azure-pipelines.yml" ]]; then
echo "✅ Azure Pipelines configuration found"
CI_FOUND=true
fi
if [[ "$CI_FOUND" == "false" ]]; then
echo "⚠️ No CI/CD configuration found"
((WARNINGS++))
fi
# Check for semantic release
echo ""
echo "=== Release Configuration ==="
if [[ -f ".releaserc" ]] || [[ -f ".releaserc.json" ]] || [[ -f ".releaserc.yml" ]] || [[ -f "release.config.js" ]]; then
echo "✅ Semantic release configuration found"
fi
# Check for CHANGELOG
if [[ -f "CHANGELOG.md" ]] || [[ -f "CHANGELOG" ]]; then
echo "✅ CHANGELOG found"
else
echo "ℹ️ No CHANGELOG (recommended for releases)"
fi
# Check for versioning
if [[ -f "package.json" ]]; then
VERSION=$(grep '"version"' package.json | head -1 | sed 's/.*: *"\([^"]*\)".*/\1/')
if [[ -n "$VERSION" ]]; then
echo "✅ Package version: $VERSION"
fi
fi
# Check current branch
echo ""
echo "=== Current State ==="
CURRENT_BRANCH=$(git branch --show-current 2>/dev/null)
echo "Current branch: $CURRENT_BRANCH"
# Check for uncommitted changes
if git diff --quiet 2>/dev/null && git diff --cached --quiet 2>/dev/null; then
echo "✅ Working directory clean"
else
CHANGES=$(git status --porcelain 2>/dev/null | wc -l)
echo "⚠️ $CHANGES uncommitted change(s)"
fi
# Check if up to date with remote
if git remote | grep -q "origin" 2>/dev/null; then
git fetch origin --quiet 2>/dev/null || true
LOCAL=$(git rev-parse "$CURRENT_BRANCH" 2>/dev/null)
REMOTE=$(git rev-parse "origin/$CURRENT_BRANCH" 2>/dev/null) || true
if [[ -n "$REMOTE" ]]; then
if [[ "$LOCAL" == "$REMOTE" ]]; then
echo "✅ Up to date with origin/$CURRENT_BRANCH"
else
BEHIND=$(git rev-list --count "$LOCAL..$REMOTE" 2>/dev/null)
AHEAD=$(git rev-list --count "$REMOTE..$LOCAL" 2>/dev/null)
echo "ℹ️ Branch is $AHEAD ahead, $BEHIND behind origin/$CURRENT_BRANCH"
fi
fi
fi
# Check for merge conflicts markers
echo ""
echo "=== Conflict Markers ==="
CONFLICT_FILES=$(grep -rln "<<<<<<< \|======= \|>>>>>>> " --include="*.js" --include="*.ts" --include="*.php" --include="*.py" . 2>/dev/null | grep -v node_modules | grep -v vendor | head -5)
if [[ -n "$CONFLICT_FILES" ]]; then
echo "❌ Conflict markers found in files:"
echo "$CONFLICT_FILES" | sed 's/^/ /'
((ERRORS++))
else
echo "✅ No conflict markers found"
fi
# Summary
echo ""
echo "=== Summary ==="
echo "Errors: $ERRORS"
echo "Warnings: $WARNINGS"
if [[ $ERRORS -gt 0 ]]; then
echo "❌ Verification FAILED"
exit 1
elif [[ $WARNINGS -gt 3 ]]; then
echo "⚠️ Verification completed with warnings"
exit 0
else
echo "✅ Verification PASSED"
exit 0
fi
```