Git Workflow Skills Overview This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations. Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects. Core Principles 1. Clarity Over Cleverness : Commit messages and branch names shoul…

, r'docs/', r'documentation/'],\n 'test': [r'\\.test\\.', r'\\.spec\\.', r'test/', r'tests/', r'__tests__/'],\n 'ci': [r'\\.github/workflows/', r'\\.gitlab-ci', r'\\.travis', r'Jenkinsfile'],\n 'build': [r'package\\.json', r'package-lock\\.json', r'yarn\\.lock',\n r'webpack\\.', r'vite\\.', r'rollup\\.'],\n 'style': [r'\\.css

Git Workflow Skills Overview This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations. Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects. Core Principles 1. Clarity Over Cleverness : Commit messages and branch names shoul…

, r'\\.scss

Git Workflow Skills Overview This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations. Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects. Core Principles 1. Clarity Over Cleverness : Commit messages and branch names shoul…

, r'\\.less

Git Workflow Skills Overview This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations. Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects. Core Principles 1. Clarity Over Cleverness : Commit messages and branch names shoul…

],\n }\n\n for commit_type, patterns in file_patterns.items():\n for pattern in patterns:\n for file in self.files_changed:\n if re.search(pattern, file):\n return commit_type\n\n # Check diff content for keywords\n diff_lower = self.diff_content.lower()\n type_scores: Counter = Counter()\n\n for commit_type, keywords in self.TYPE_KEYWORDS.items():\n for keyword in keywords:\n # Count occurrences in added lines\n count = len(re.findall(r'^\\+.*\\b' + keyword + r'\\b', diff_lower, re.MULTILINE))\n type_scores[commit_type] += count\n\n # Check if mostly deletions (might be refactor or chore)\n if self.deletions > self.additions * 2:\n type_scores['refactor'] += 2\n\n # Default to feat for new files, fix for modifications\n new_files = [f for f in self.files_changed if self._is_new_file(f)]\n if new_files and not type_scores:\n return 'feat'\n\n if type_scores:\n return type_scores.most_common(1)[0][0]\n\n # Default to chore\n return 'chore'\n\n def _is_new_file(self, file_path: str) -> bool:\n \"\"\"Check if file is new (not in git history).\"\"\"\n try:\n result = subprocess.run(\n ['git', 'log', '--oneline', '--', file_path],\n capture_output=True,\n text=True,\n check=True\n )\n return not result.stdout.strip()\n except subprocess.CalledProcessError:\n return True\n\n def determine_scope(self) -> Optional[str]:\n \"\"\"\n Determine scope from file paths.\n\n Returns:\n Scope string or None\n \"\"\"\n # Extract common directory\n paths = [f for f in self.files_changed if '/' in f]\n if not paths:\n return None\n\n # Get first-level directories\n dirs: Set[str] = set()\n for path in paths:\n parts = path.split('/')\n if len(parts) > 1:\n # Skip common dirs like src, lib\n if parts[0] in ['src', 'lib']:\n if len(parts) > 2:\n dirs.add(parts[1])\n else:\n dirs.add(parts[0])\n\n # If single directory, use as scope\n if len(dirs) == 1:\n scope = list(dirs)[0]\n # Clean up scope\n scope = re.sub(r'[^a-z0-9-]', '', scope.lower())\n return scope if scope else None\n\n # If multiple dirs but similar, extract common prefix\n if len(dirs) \u003c= 3:\n # Find common prefix\n sorted_dirs = sorted(dirs)\n prefix = sorted_dirs[0]\n for d in sorted_dirs[1:]:\n while not d.startswith(prefix) and prefix:\n prefix = prefix[:-1]\n if len(prefix) >= 3:\n return prefix.lower()\n\n return None\n\n def generate_subject(self, commit_type: str, scope: Optional[str]) -> str:\n \"\"\"\n Generate commit subject line.\n\n Args:\n commit_type: The commit type\n scope: The scope (optional)\n\n Returns:\n Subject line\n \"\"\"\n # Analyze changes to create subject\n new_files = [f for f in self.files_changed if self._is_new_file(f)]\n modified_files = [f for f in self.files_changed if not self._is_new_file(f)]\n\n # Generate action verb\n if commit_type == 'feat':\n verb = 'add'\n elif commit_type == 'fix':\n verb = 'fix'\n elif commit_type == 'docs':\n verb = 'update' if modified_files else 'add'\n elif commit_type == 'test':\n verb = 'add' if new_files else 'update'\n elif commit_type == 'refactor':\n verb = 'refactor'\n elif commit_type == 'style':\n verb = 'format'\n elif commit_type == 'perf':\n verb = 'optimize'\n elif commit_type == 'chore':\n verb = 'update'\n else:\n verb = 'update'\n\n # Generate description\n if len(self.files_changed) == 1:\n file_name = self.files_changed[0].split('/')[-1]\n file_base = file_name.split('.')[0]\n description = file_base.replace('_', ' ').replace('-', ' ')\n elif scope:\n description = f\"{scope} module\"\n else:\n description = f\"{len(self.files_changed)} files\"\n\n subject = f\"{verb} {description}\"\n\n # Truncate if too long\n max_len = 50 - len(commit_type) - (len(scope) + 3 if scope else 2)\n if len(subject) > max_len:\n subject = subject[:max_len - 3] + '...'\n\n return subject\n\n def generate_body(self) -> Optional[str]:\n \"\"\"\n Generate commit body with details.\n\n Returns:\n Body text or None\n \"\"\"\n lines = []\n\n # Add file summary if many files\n if len(self.files_changed) > 3:\n lines.append(f\"Changes across {len(self.files_changed)} files:\")\n for file in self.files_changed[:5]:\n lines.append(f\"- {file}\")\n if len(self.files_changed) > 5:\n lines.append(f\"- ... and {len(self.files_changed) - 5} more\")\n\n # Add stats\n if self.additions or self.deletions:\n lines.append(\"\")\n lines.append(f\"Stats: +{self.additions} -{self.deletions}\")\n\n return '\\n'.join(lines) if lines else None\n\n def generate(self, include_body: bool = True, include_claude_footer: bool = False) -> str:\n \"\"\"\n Generate complete commit message.\n\n Args:\n include_body: Whether to include body\n include_claude_footer: Whether to include Claude Code attribution\n\n Returns:\n Complete commit message\n \"\"\"\n commit_type = self.determine_type()\n scope = self.determine_scope()\n subject = self.generate_subject(commit_type, scope)\n\n # Build header\n if scope:\n header = f\"{commit_type}({scope}): {subject}\"\n else:\n header = f\"{commit_type}: {subject}\"\n\n # Build message\n message_parts = [header]\n\n # Add body\n if include_body:\n body = self.generate_body()\n if body:\n message_parts.append(\"\")\n message_parts.append(body)\n\n # Add Claude footer\n if include_claude_footer:\n message_parts.append(\"\")\n message_parts.append(\"🤖 Generated with [Claude Code](https://claude.com/claude-code)\")\n message_parts.append(\"\")\n message_parts.append(\"Co-Authored-By: Claude \[email protected]>\")\n\n return '\\n'.join(message_parts)\n\n\ndef main():\n \"\"\"Main entry point.\"\"\"\n parser = argparse.ArgumentParser(\n description='Generate commit messages from staged changes'\n )\n parser.add_argument(\n '--no-body',\n action='store_true',\n help='Generate header only (no body)'\n )\n parser.add_argument(\n '--include-claude-footer',\n action='store_true',\n help='Include Claude Code attribution footer'\n )\n parser.add_argument(\n '--dry-run',\n action='store_true',\n help='Show generated message without committing'\n )\n\n args = parser.parse_args()\n\n # Generate message\n generator = CommitMessageGenerator()\n\n if not generator.get_staged_changes():\n sys.exit(1)\n\n message = generator.generate(\n include_body=not args.no_body,\n include_claude_footer=args.include_claude_footer\n )\n\n # Output\n print(\"Generated commit message:\")\n print(\"=\" * 60)\n print(message)\n print(\"=\" * 60)\n\n if not args.dry_run:\n print(\"\\nUse this message? (y/n): \", end='')\n response = input().strip().lower()\n if response == 'y':\n try:\n subprocess.run(\n ['git', 'commit', '-m', message],\n check=True\n )\n print(\"✅ Commit created successfully\")\n except subprocess.CalledProcessError as e:\n print(f\"❌ Commit failed: {e}\", file=sys.stderr)\n sys.exit(1)\n\n\nif __name__ == '__main__':\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":12424,"content_sha256":"accf6c17f6c1c0d222f3acd0e62a7a9e9b376bf6b9c2dc4190e9d3bf0762adfe"},{"filename":"scripts/README.md","content":"# Git Workflow Scripts\n\nThis directory contains utility scripts for git workflow automation.\n\n## Scripts\n\n### validate_commit_msg.py\n\nValidates commit messages against the Conventional Commits specification.\n\n**Usage**:\n```bash\n# Validate a commit message string\npython validate_commit_msg.py \"feat(auth): add OAuth login\"\n\n# Validate from file (useful for git hooks)\npython validate_commit_msg.py --file .git/COMMIT_EDITMSG\n\n# Validate from stdin\necho \"feat: add feature\" | python validate_commit_msg.py --stdin\n\n# Non-strict mode (warnings only)\npython validate_commit_msg.py --no-strict \"feat(auth): add OAuth login\"\n```\n\n**Validation Rules**:\n- ✅ Header matches format: `\u003ctype>(\u003cscope>): \u003csubject>`\n- ✅ Type is valid: feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert\n- ✅ Subject ≤50 characters\n- ✅ Subject doesn't end with period\n- ✅ Subject uses imperative mood (not past tense)\n- ✅ Body lines wrap at 72 characters\n\n**Example**:\n```bash\n$ python validate_commit_msg.py \"feat(auth): add OAuth2 login support\"\n✅ Commit message is valid\n\n$ python validate_commit_msg.py \"Added new feature\"\n❌ Validation failed:\n\n ERROR: Header does not match Conventional Commits format: 'Added new feature'\n Expected: \u003ctype>(\u003cscope>): \u003csubject>\n Example: feat(auth): add OAuth login\n```\n\n### generate_commit_msg.py\n\nGenerates commit messages from staged git changes.\n\n**Usage**:\n```bash\n# Generate commit message from staged changes\npython generate_commit_msg.py\n\n# Generate header only (no body)\npython generate_commit_msg.py --no-body\n\n# Include Claude Code attribution\npython generate_commit_msg.py --include-claude-footer\n\n# Show generated message without committing\npython generate_commit_msg.py --dry-run\n```\n\n**Features**:\n- Analyzes staged changes with `git diff --cached`\n- Determines commit type from file patterns and diff content\n- Extracts scope from directory structure\n- Generates appropriate subject line\n- Optionally includes body with file list and stats\n- Optionally includes Claude Code attribution footer\n\n**Example**:\n```bash\n$ git add src/auth/oauth.ts src/types/auth.ts\n$ python generate_commit_msg.py\n\nGenerated commit message:\n============================================================\nfeat(auth): add oauth module\n\nChanges across 2 files:\n- src/auth/oauth.ts\n- src/types/auth.ts\n\nStats: +156 -0\n============================================================\n\nUse this message? (y/n): y\n✅ Commit created successfully\n```\n\n## Integration with Git Hooks\n\n### commit-msg Hook\n\nValidate commit messages automatically:\n\n```bash\n# .git/hooks/commit-msg\n#!/bin/bash\npython3 /home/kim-asplund/.claude/skills/git-workflow-skills/scripts/validate_commit_msg.py \\\n --file \"$1\" || exit 1\n```\n\nMake executable:\n```bash\nchmod +x .git/hooks/commit-msg\n```\n\n### prepare-commit-msg Hook\n\nGenerate commit message template:\n\n```bash\n# .git/hooks/prepare-commit-msg\n#!/bin/bash\nif [ -z \"$2\" ]; then\n python3 /home/kim-asplund/.claude/skills/git-workflow-skills/scripts/generate_commit_msg.py \\\n --dry-run | grep -A 100 \"^=\" | tail -n +2 | head -n -1 > \"$1\"\nfi\n```\n\nMake executable:\n```bash\nchmod +x .git/hooks/prepare-commit-msg\n```\n\n## Requirements\n\n- Python 3.6+\n- Git installed and available in PATH\n\n## Development\n\nBoth scripts are standalone with no external dependencies beyond Python standard library and git.\n","content_type":"text/markdown; charset=utf-8","language":"markdown","size":3361,"content_sha256":"0ff2bb9fef17d2eef249339924949b969ed9c3e1ce245b0213f732e1985d7830"},{"filename":"scripts/validate_commit_msg.py","content":"#!/usr/bin/env python3\n\"\"\"\nValidate commit messages against Conventional Commits specification.\n\nUsage:\n python validate_commit_msg.py \"feat(auth): add OAuth login\"\n python validate_commit_msg.py --file .git/COMMIT_EDITMSG\n echo \"feat: add feature\" | python validate_commit_msg.py --stdin\n\"\"\"\n\nimport re\nimport sys\nimport argparse\nfrom typing import Tuple, List, Optional\n\n\nclass CommitMessageValidator:\n \"\"\"Validates commit messages against Conventional Commits spec.\"\"\"\n\n VALID_TYPES = [\n 'feat', 'fix', 'docs', 'style', 'refactor',\n 'test', 'chore', 'perf', 'ci', 'build', 'revert'\n ]\n\n SUBJECT_MAX_LENGTH = 50\n BODY_LINE_MAX_LENGTH = 72\n\n # Regex for conventional commit format\n PATTERN = re.compile(\n r'^(?P\u003ctype>\\w+)' # type\n r'(?:\\((?P\u003cscope>[\\w-]+)\\))?' # optional scope\n r'(?P\u003cbreaking>!)?' # optional breaking change indicator\n r': ' # colon-space separator\n r'(?P\u003csubject>.+)

Git Workflow Skills Overview This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations. Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects. Core Principles 1. Clarity Over Cleverness : Commit messages and branch names shoul…

# subject\n )\n\n def __init__(self, strict: bool = True):\n \"\"\"\n Initialize validator.\n\n Args:\n strict: If True, enforce all rules strictly\n \"\"\"\n self.strict = strict\n self.errors: List[str] = []\n self.warnings: List[str] = []\n\n def validate(self, message: str) -> Tuple[bool, List[str], List[str]]:\n \"\"\"\n Validate a commit message.\n\n Args:\n message: The commit message to validate\n\n Returns:\n Tuple of (is_valid, errors, warnings)\n \"\"\"\n self.errors = []\n self.warnings = []\n\n if not message or not message.strip():\n self.errors.append(\"Commit message is empty\")\n return False, self.errors, self.warnings\n\n lines = message.split('\\n')\n header = lines[0].strip()\n body_lines = lines[2:] if len(lines) > 2 else [] # Skip blank line\n\n # Validate header\n self._validate_header(header)\n\n # Validate body if present\n if body_lines:\n self._validate_body(body_lines)\n\n is_valid = len(self.errors) == 0\n return is_valid, self.errors, self.warnings\n\n def _validate_header(self, header: str) -> None:\n \"\"\"Validate the commit message header.\"\"\"\n match = self.PATTERN.match(header)\n\n if not match:\n self.errors.append(\n f\"Header does not match Conventional Commits format: '{header}'\\n\"\n f\"Expected: \u003ctype>(\u003cscope>): \u003csubject>\\n\"\n f\"Example: feat(auth): add OAuth login\"\n )\n return\n\n commit_type = match.group('type')\n scope = match.group('scope')\n breaking = match.group('breaking')\n subject = match.group('subject')\n\n # Validate type\n if commit_type not in self.VALID_TYPES:\n self.errors.append(\n f\"Invalid commit type: '{commit_type}'\\n\"\n f\"Valid types: {', '.join(self.VALID_TYPES)}\"\n )\n\n # Validate subject\n if len(subject) > self.SUBJECT_MAX_LENGTH:\n if self.strict:\n self.errors.append(\n f\"Subject exceeds {self.SUBJECT_MAX_LENGTH} characters: \"\n f\"{len(subject)} chars\"\n )\n else:\n self.warnings.append(\n f\"Subject should be ≤{self.SUBJECT_MAX_LENGTH} characters: \"\n f\"{len(subject)} chars\"\n )\n\n # Check subject ends with period\n if subject.endswith('.'):\n self.warnings.append(\"Subject should not end with a period\")\n\n # Check subject starts with lowercase (should be lowercase for imperative)\n if subject and subject[0].isupper():\n first_word = subject.split()[0] if subject.split() else subject\n # Allow uppercase if it's an acronym or proper noun\n if not first_word.isupper() and len(first_word) > 1:\n self.warnings.append(\n \"Subject should start with lowercase (imperative mood)\\n\"\n f\"Example: 'add' not 'Add', 'fix' not 'Fix'\"\n )\n\n # Check for past tense (common mistake)\n past_tense_words = ['added', 'fixed', 'updated', 'changed', 'removed']\n first_word = subject.split()[0].lower() if subject.split() else ''\n if first_word in past_tense_words:\n self.warnings.append(\n f\"Subject appears to use past tense: '{first_word}'\\n\"\n f\"Use imperative mood: '{first_word[:-1] if first_word.endswith('ed') else first_word}'\"\n )\n\n def _validate_body(self, body_lines: List[str]) -> None:\n \"\"\"Validate the commit message body.\"\"\"\n for i, line in enumerate(body_lines, start=3):\n if len(line) > self.BODY_LINE_MAX_LENGTH:\n if self.strict:\n self.errors.append(\n f\"Line {i} exceeds {self.BODY_LINE_MAX_LENGTH} characters: \"\n f\"{len(line)} chars\"\n )\n else:\n self.warnings.append(\n f\"Line {i} should wrap at {self.BODY_LINE_MAX_LENGTH} characters: \"\n f\"{len(line)} chars\"\n )\n\n\ndef main():\n \"\"\"Main entry point.\"\"\"\n parser = argparse.ArgumentParser(\n description='Validate commit messages against Conventional Commits spec'\n )\n parser.add_argument(\n 'message',\n nargs='?',\n help='Commit message to validate'\n )\n parser.add_argument(\n '--file',\n help='Read commit message from file (e.g., .git/COMMIT_EDITMSG)'\n )\n parser.add_argument(\n '--stdin',\n action='store_true',\n help='Read commit message from stdin'\n )\n parser.add_argument(\n '--strict',\n action='store_true',\n default=True,\n help='Strict validation mode (default: True)'\n )\n parser.add_argument(\n '--no-strict',\n dest='strict',\n action='store_false',\n help='Non-strict validation mode (warnings only)'\n )\n\n args = parser.parse_args()\n\n # Get commit message\n message: Optional[str] = None\n if args.file:\n try:\n with open(args.file, 'r') as f:\n message = f.read()\n except FileNotFoundError:\n print(f\"Error: File not found: {args.file}\", file=sys.stderr)\n sys.exit(1)\n elif args.stdin:\n message = sys.stdin.read()\n elif args.message:\n message = args.message\n else:\n parser.print_help()\n sys.exit(1)\n\n # Validate\n validator = CommitMessageValidator(strict=args.strict)\n is_valid, errors, warnings = validator.validate(message)\n\n # Print results\n if errors:\n print(\"❌ Validation failed:\\n\")\n for error in errors:\n print(f\" ERROR: {error}\\n\")\n\n if warnings:\n print(\"⚠️ Warnings:\\n\")\n for warning in warnings:\n print(f\" WARNING: {warning}\\n\")\n\n if is_valid and not warnings:\n print(\"✅ Commit message is valid\")\n sys.exit(0)\n elif is_valid and warnings:\n print(\"✅ Commit message is valid (with warnings)\")\n sys.exit(0)\n else:\n sys.exit(1)\n\n\nif __name__ == '__main__':\n main()\n","content_type":"text/x-python; charset=utf-8","language":"python","size":7338,"content_sha256":"9288317de6447054669df148d5f48e3760513db9df72b4c4abbc82ace9a1e7bf"}],"content_json":{"type":"doc","content":[{"type":"heading","attrs":{"level":1},"content":[{"text":"Git Workflow Skills","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Overview","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations.","type":"text"}]},{"type":"paragraph","content":[{"text":"Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Core Principles","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clarity Over Cleverness","type":"text","marks":[{"type":"strong"}]},{"text":": Commit messages and branch names should be immediately understandable","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Atomic Commits","type":"text","marks":[{"type":"strong"}]},{"text":": One logical change per commit (enables easy revert, clear history)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Safety First","type":"text","marks":[{"type":"strong"}]},{"text":": Never commit secrets, avoid force push to protected branches","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Team Consistency","type":"text","marks":[{"type":"strong"}]},{"text":": Follow project conventions, communicate through commits and PRs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"History Matters","type":"text","marks":[{"type":"strong"}]},{"text":": Clean, readable history is a project asset","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Commit Message Conventions","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Conventional Commits Format","type":"text"}]},{"type":"paragraph","content":[{"text":"Follow the Conventional Commits specification for all commit messages:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"\u003ctype>(\u003cscope>): \u003csubject>\n\n\u003cbody>\n\n\u003cfooter>","type":"text"}]},{"type":"paragraph","content":[{"text":"Components","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"type","type":"text","marks":[{"type":"strong"}]},{"text":" (required): feat, fix, docs, style, refactor, test, chore, perf, ci, build, revert","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"scope","type":"text","marks":[{"type":"strong"}]},{"text":" (optional): Component/module affected (e.g., auth, api, ui, database)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"subject","type":"text","marks":[{"type":"strong"}]},{"text":" (required): Brief description (50 chars max, imperative mood, no period)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"body","type":"text","marks":[{"type":"strong"}]},{"text":" (optional): Detailed explanation (wrap at 72 chars)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"footer","type":"text","marks":[{"type":"strong"}]},{"text":" (optional): Breaking changes, issue references","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Commit Types","type":"text"}]},{"type":"paragraph","content":[{"text":"feat","type":"text","marks":[{"type":"strong"}]},{"text":": New feature for the user","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feat(auth): add OAuth2 login support\n\nImplement OAuth2 authentication flow with Google and GitHub providers.\nIncludes token refresh mechanism and session management.\n\nCloses #142","type":"text"}]},{"type":"paragraph","content":[{"text":"fix","type":"text","marks":[{"type":"strong"}]},{"text":": Bug fix for the user","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"fix(api): prevent race condition in user creation\n\nAdd database transaction lock to prevent duplicate user records\nwhen multiple requests arrive simultaneously.\n\nFixes #238","type":"text"}]},{"type":"paragraph","content":[{"text":"docs","type":"text","marks":[{"type":"strong"}]},{"text":": Documentation changes only","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"docs(readme): add installation instructions for Windows\n\nInclude troubleshooting section for common Windows-specific issues.","type":"text"}]},{"type":"paragraph","content":[{"text":"style","type":"text","marks":[{"type":"strong"}]},{"text":": Code formatting, missing semicolons, whitespace (no logic change)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"style(components): format with prettier, remove trailing whitespace","type":"text"}]},{"type":"paragraph","content":[{"text":"refactor","type":"text","marks":[{"type":"strong"}]},{"text":": Code change that neither fixes bug nor adds feature","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"refactor(database): extract query builder into separate class\n\nImprove code organization and testability by separating query\nconstruction from execution logic.","type":"text"}]},{"type":"paragraph","content":[{"text":"test","type":"text","marks":[{"type":"strong"}]},{"text":": Adding or updating tests","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"test(auth): add integration tests for OAuth flow","type":"text"}]},{"type":"paragraph","content":[{"text":"chore","type":"text","marks":[{"type":"strong"}]},{"text":": Maintenance tasks, dependency updates, build configuration","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"chore(deps): upgrade React from 18.2.0 to 18.3.0","type":"text"}]},{"type":"paragraph","content":[{"text":"perf","type":"text","marks":[{"type":"strong"}]},{"text":": Performance improvement","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"perf(api): add database indexes for user queries\n\nReduce user lookup time from 250ms to 15ms by indexing email column.","type":"text"}]},{"type":"paragraph","content":[{"text":"ci","type":"text","marks":[{"type":"strong"}]},{"text":": CI/CD configuration changes","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"ci(github): add automated deployment to staging environment","type":"text"}]},{"type":"paragraph","content":[{"text":"build","type":"text","marks":[{"type":"strong"}]},{"text":": Build system or external dependency changes","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"build(webpack): optimize bundle size with code splitting","type":"text"}]},{"type":"paragraph","content":[{"text":"revert","type":"text","marks":[{"type":"strong"}]},{"text":": Reverts a previous commit","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"revert: feat(auth): add OAuth2 login support\n\nThis reverts commit a1b2c3d4. OAuth implementation needs rework\ndue to security concerns identified in code review.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Breaking Changes","type":"text"}]},{"type":"paragraph","content":[{"text":"Indicate breaking changes with ","type":"text"},{"text":"!","type":"text","marks":[{"type":"code_inline"}]},{"text":" after type/scope and in footer:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feat(api)!: change user endpoint response format\n\nBREAKING CHANGE: User API now returns `userId` instead of `id`.\nClients must update to use new field name.\n\nMigration guide: https://docs.example.com/migration-v2","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Good vs Bad Commit Messages","type":"text"}]},{"type":"paragraph","content":[{"text":"❌ Bad Examples","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Update files\nFix bug\nWIP\nasdf\nChanged some stuff\nFixed it","type":"text"}]},{"type":"paragraph","content":[{"text":"✅ Good Examples","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feat(search): add fuzzy matching for product queries\nfix(checkout): calculate tax correctly for international orders\ndocs(api): update authentication examples\nrefactor(utils): extract date formatting into helper function","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Multi-line Commit Messages","type":"text"}]},{"type":"paragraph","content":[{"text":"Use multi-line messages for non-trivial changes:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feat(notifications): implement real-time notification system\n\nAdd WebSocket-based notification delivery for user actions.\nIncludes:\n- WebSocket server with connection pooling\n- Client-side notification queue with retry logic\n- Notification preferences UI\n- Email fallback for offline users\n\nPerformance: Handles 10k concurrent connections with \u003c100ms latency.\n\nCloses #156, #187","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Integration with Claude Code","type":"text"}]},{"type":"paragraph","content":[{"text":"When agents create commits, always:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyze ","type":"text"},{"text":"git diff","type":"text","marks":[{"type":"code_inline"}]},{"text":" to understand changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Determine appropriate type (feat, fix, docs, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify scope from files changed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write clear subject line (imperative mood)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add body for non-trivial changes explaining \"why\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Include Claude Code footer:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude \[email protected]>","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Branching Strategies","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Strategy Selection Guide","type":"text"}]},{"type":"paragraph","content":[{"text":"Choose GitHub Flow","type":"text","marks":[{"type":"strong"}]},{"text":" (recommended for most projects):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Continuous deployment","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Small to medium teams","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Web applications","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Simple release process","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Choose Git Flow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Scheduled releases","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Multiple production versions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Enterprise software","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Complex release management","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Choose Trunk-based Development","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Very frequent deployments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Strong CI/CD pipeline","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Experienced team","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Feature flags in place","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"GitHub Flow (Recommended)","type":"text"}]},{"type":"paragraph","content":[{"text":"Branches","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":": Always deployable, protected","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"feature/*","type":"text","marks":[{"type":"code_inline"}]},{"text":": Short-lived feature branches","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create feature branch from ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":": ","type":"text"},{"text":"feature/add-user-search","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Commit changes with conventional commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Push to remote and create PR","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Code review and CI checks","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Merge to ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" (squash or merge commit)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" to production","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Delete feature branch","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Branch naming","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feature/add-oauth-login\nfeature/user-profile-page\nbugfix/fix-login-redirect\nhotfix/patch-security-vulnerability\ndocs/update-api-documentation","type":"text"}]},{"type":"paragraph","content":[{"text":"Example workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Start feature\ngit checkout main\ngit pull origin main\ngit checkout -b feature/add-search-filter\n\n# Work on feature\ngit add src/components/SearchFilter.tsx\ngit commit -m \"feat(search): add category filter to search UI\"\n\n# Push and create PR\ngit push -u origin feature/add-search-filter\ngh pr create --title \"Add category filter to search\" --body \"...\"\n\n# After PR approval\n# Merge via GitHub UI (squash recommended)\n# Delete branch\ngit checkout main\ngit pull origin main\ngit branch -d feature/add-search-filter","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Git Flow","type":"text"}]},{"type":"paragraph","content":[{"text":"Branches","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":": Production releases only","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"develop","type":"text","marks":[{"type":"code_inline"}]},{"text":": Integration branch","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"feature/*","type":"text","marks":[{"type":"code_inline"}]},{"text":": Feature development","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"release/*","type":"text","marks":[{"type":"code_inline"}]},{"text":": Release preparation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"hotfix/*","type":"text","marks":[{"type":"code_inline"}]},{"text":": Production hotfixes","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Feature: Branch from ","type":"text"},{"text":"develop","type":"text","marks":[{"type":"code_inline"}]},{"text":", merge back to ","type":"text"},{"text":"develop","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Release: Branch from ","type":"text"},{"text":"develop","type":"text","marks":[{"type":"code_inline"}]},{"text":", merge to ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"develop","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Hotfix: Branch from ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":", merge to ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" and ","type":"text"},{"text":"develop","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"paragraph","content":[{"text":"Use when","type":"text","marks":[{"type":"strong"}]},{"text":": Managing multiple release versions, scheduled releases, complex projects","type":"text"}]},{"type":"paragraph","content":[{"text":"Example","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Feature development\ngit checkout develop\ngit checkout -b feature/payment-integration\n# ... work ...\ngit checkout develop\ngit merge --no-ff feature/payment-integration\n\n# Release\ngit checkout -b release/1.2.0 develop\n# ... version bump, changelog ...\ngit checkout main\ngit merge --no-ff release/1.2.0\ngit tag -a v1.2.0\ngit checkout develop\ngit merge --no-ff release/1.2.0","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Trunk-based Development","type":"text"}]},{"type":"paragraph","content":[{"text":"Branches","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":": The trunk, always deployable","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"feature/*","type":"text","marks":[{"type":"code_inline"}]},{"text":": Very short-lived (\u003c 1 day)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create small feature branch","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Commit frequently","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Merge to ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" within hours/1 day","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use feature flags for incomplete features","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deploy ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" frequently (multiple times per day)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Requirements","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Strong automated testing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Feature flag system","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Mature CI/CD pipeline","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Team discipline","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"PR/MR Best Practices","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"PR Title Format","type":"text"}]},{"type":"paragraph","content":[{"text":"Use conventional commit format:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feat(auth): add OAuth2 login support\nfix(api): prevent race condition in user creation\ndocs(readme): add installation instructions","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"PR Description Template","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"markdown"},"content":[{"text":"## Summary\n\nBrief description of what this PR does and why.\n\n## Changes\n\n- Add OAuth2 authentication with Google and GitHub\n- Implement token refresh mechanism\n- Add session management\n- Update user model to store OAuth tokens\n\n## Type of Change\n\n- [ ] Bug fix (non-breaking change which fixes an issue)\n- [x] New feature (non-breaking change which adds functionality)\n- [ ] Breaking change (fix or feature that would cause existing functionality to not work as expected)\n- [ ] Documentation update\n\n## Testing\n\n- [x] Unit tests added/updated\n- [x] Integration tests added/updated\n- [x] Manual testing completed\n- [ ] Performance testing completed\n\n## Test Plan\n\n1. Test Google OAuth login flow\n2. Test GitHub OAuth login flow\n3. Verify token refresh after expiry\n4. Test session persistence across browser restarts\n\n## Screenshots (if applicable)\n\n[Add screenshots of UI changes]\n\n## Breaking Changes\n\nNone\n\n## Related Issues\n\nCloses #142\nRelated to #156\n\n## Checklist\n\n- [x] Code follows project style guidelines\n- [x] Self-review completed\n- [x] Comments added for complex logic\n- [x] Documentation updated\n- [x] No new warnings generated\n- [x] Tests pass locally\n- [x] Dependent changes merged","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"PR Size Guidelines","type":"text"}]},{"type":"paragraph","content":[{"text":"Optimal PR size","type":"text","marks":[{"type":"strong"}]},{"text":": 200-400 lines changed ","type":"text"},{"text":"Maximum recommended","type":"text","marks":[{"type":"strong"}]},{"text":": 800 lines changed","type":"text"}]},{"type":"paragraph","content":[{"text":"When PR is too large","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Split into multiple PRs (preferred)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add detailed description and comments","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Schedule synchronous review session","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Break into reviewable sections","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Draft PRs","type":"text"}]},{"type":"paragraph","content":[{"text":"Create draft PR when:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Seeking early feedback on approach","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Work in progress, not ready for review","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Demonstrating proof of concept","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Collaborating on complex feature","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Mark as \"Ready for review\" when:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"All tests pass","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Code is self-reviewed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Documentation is updated","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Ready for merge after approval","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Review Request Etiquette","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Self-review first","type":"text","marks":[{"type":"strong"}]},{"text":": Review your own PR before requesting review","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Provide context","type":"text","marks":[{"type":"strong"}]},{"text":": Explain the \"why\" in description","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Highlight concerns","type":"text","marks":[{"type":"strong"}]},{"text":": Point out areas needing special attention","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Request specific reviewers","type":"text","marks":[{"type":"strong"}]},{"text":": Tag domain experts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Be responsive","type":"text","marks":[{"type":"strong"}]},{"text":": Address feedback promptly","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Be respectful","type":"text","marks":[{"type":"strong"}]},{"text":": Thank reviewers, engage constructively","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Addressing Review Comments","type":"text"}]},{"type":"paragraph","content":[{"text":"When making changes","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Make requested changes\ngit add src/auth/oauth.ts\ngit commit -m \"refactor(auth): extract token validation per review feedback\"\ngit push origin feature/add-oauth-login","type":"text"}]},{"type":"paragraph","content":[{"text":"When resolving comments","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ \"Done, updated in commit abc123\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ \"Good point, refactored to use helper function\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ \"Created issue #245 to track this separately\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"❌ \"Done\" (without context)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"❌ Resolving without making changes","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Git Operations Patterns","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Merge vs Rebase vs Squash","type":"text"}]},{"type":"paragraph","content":[{"text":"Merge Commit","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"git merge --no-ff","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When","type":"text","marks":[{"type":"strong"}]},{"text":": Preserving complete feature branch history","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pros","type":"text","marks":[{"type":"strong"}]},{"text":": Full history preserved, clear feature boundaries","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cons","type":"text","marks":[{"type":"strong"}]},{"text":": Cluttered history with many merge commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use for","type":"text","marks":[{"type":"strong"}]},{"text":": Long-lived feature branches, collaborative branches","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git checkout main\ngit merge --no-ff feature/add-search\n# Creates merge commit","type":"text"}]},{"type":"paragraph","content":[{"text":"Rebase","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"git rebase","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When","type":"text","marks":[{"type":"strong"}]},{"text":": Keeping feature branch up to date with main","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pros","type":"text","marks":[{"type":"strong"}]},{"text":": Clean linear history, no merge commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cons","type":"text","marks":[{"type":"strong"}]},{"text":": Rewrites history (don't rebase public branches)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use for","type":"text","marks":[{"type":"strong"}]},{"text":": Updating feature branch, cleaning up local commits","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Update feature branch with latest main\ngit checkout feature/add-search\ngit rebase main\n\n# Interactive rebase to clean up commits\ngit rebase -i HEAD~5","type":"text"}]},{"type":"paragraph","content":[{"text":"Squash Merge","type":"text","marks":[{"type":"strong"}]},{"text":" (","type":"text"},{"text":"git merge --squash","type":"text","marks":[{"type":"code_inline"}]},{"text":"):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"When","type":"text","marks":[{"type":"strong"}]},{"text":": Merging feature branch with many commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pros","type":"text","marks":[{"type":"strong"}]},{"text":": Clean main history, one commit per feature","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Cons","type":"text","marks":[{"type":"strong"}]},{"text":": Loses detailed feature development history","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use for","type":"text","marks":[{"type":"strong"}]},{"text":": Feature branches with many WIP commits","type":"text"}]}]}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git checkout main\ngit merge --squash feature/add-search\ngit commit -m \"feat(search): add advanced search functionality\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Decision Matrix","type":"text"}]},{"type":"table","attrs":{"layout":null},"content":[{"type":"tr","content":[{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Scenario","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Operation","type":"text"}]}]},{"type":"th","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Reasoning","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Update feature branch with main","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Rebase","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Keep linear history","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Merge feature to main (GitHub Flow)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Squash","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Clean main history","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Merge feature to main (Git Flow)","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Merge commit","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Preserve feature history","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Clean up local commits before PR","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Interactive rebase","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Present clean history","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Integrate long-lived branch","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Merge commit","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Preserve collaboration history","type":"text"}]}]}]},{"type":"tr","content":[{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Apply single commit from another branch","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Cherry-pick","type":"text"}]}]},{"type":"td","attrs":{"colspan":1,"rowspan":1,"colwidth":null,"alignment":""},"content":[{"type":"paragraph","content":[{"text":"Selective integration","type":"text"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Keeping History Clean","type":"text"}]},{"type":"paragraph","content":[{"text":"Before creating PR","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Interactive rebase to clean up commits\ngit rebase -i main\n\n# In editor, squash/fixup WIP commits:\npick a1b2c3d feat(search): add search component\nfixup e4f5g6h WIP: fix typo\nfixup h7i8j9k WIP: update tests\npick k0l1m2n feat(search): add filters","type":"text"}]},{"type":"paragraph","content":[{"text":"Commit message guidelines for clean history","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Each commit should be self-contained and functional","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Commit message should describe the complete change","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Avoid \"WIP\", \"temp\", \"fix typo\" commits in final history","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Group related changes into logical commits","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Force Push Safety","type":"text"}]},{"type":"paragraph","content":[{"text":"❌ Never force push to","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"main","type":"text","marks":[{"type":"code_inline"}]},{"text":" / ","type":"text"},{"text":"master","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"develop","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Any protected branch","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Any branch others are working on","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"✅ Safe to force push to","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Your own feature branch (before PR review)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"After interactive rebase on personal branch","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"When force push is needed","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# After rebasing/amending on feature branch\ngit push --force-with-lease origin feature/add-search","type":"text"}]},{"type":"paragraph","content":[{"text":"--force-with-lease","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":": Safer than ","type":"text"},{"text":"--force","type":"text","marks":[{"type":"code_inline"}]},{"text":", prevents overwriting others' work","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Cherry-pick Use Cases","type":"text"}]},{"type":"paragraph","content":[{"text":"When to use cherry-pick","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Apply hotfix to multiple branches","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Selectively port features across branches","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Recover commits from abandoned branch","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Example","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Apply specific commit to current branch\ngit cherry-pick a1b2c3d\n\n# Apply multiple commits\ngit cherry-pick a1b2c3d..e4f5g6h\n\n# Cherry-pick without committing (for editing)\ngit cherry-pick -n a1b2c3d","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Collaboration Workflows","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Fork vs Branch Workflow","type":"text"}]},{"type":"paragraph","content":[{"text":"Branch Workflow","type":"text","marks":[{"type":"strong"}]},{"text":" (recommended for teams):","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Team members have write access to repository","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create feature branches directly in main repository","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use for: Internal team projects, trusted contributors","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Fork Workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Contributors fork repository to their account","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create feature branches in fork","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Submit PR from fork to upstream","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use for: Open source projects, external contributors","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Keeping Branch Up to Date","type":"text"}]},{"type":"paragraph","content":[{"text":"Method 1: Rebase","type":"text","marks":[{"type":"strong"}]},{"text":" (clean history):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git checkout feature/add-search\ngit fetch origin\ngit rebase origin/main\n\n# If conflicts, resolve and continue\ngit add .\ngit rebase --continue\n\n# Force push to update PR\ngit push --force-with-lease origin feature/add-search","type":"text"}]},{"type":"paragraph","content":[{"text":"Method 2: Merge","type":"text","marks":[{"type":"strong"}]},{"text":" (preserve history):","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git checkout feature/add-search\ngit fetch origin\ngit merge origin/main\n\n# Resolve conflicts if any\ngit add .\ngit commit -m \"merge: resolve conflicts with main\"\n\ngit push origin feature/add-search","type":"text"}]},{"type":"paragraph","content":[{"text":"Recommendation","type":"text","marks":[{"type":"strong"}]},{"text":": Use rebase for feature branches, merge for long-lived branches","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Resolving Merge Conflicts","type":"text"}]},{"type":"paragraph","content":[{"text":"Workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify conflicting files: ","type":"text"},{"text":"git status","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Open files and locate conflict markers:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"\u003c\u003c\u003c\u003c\u003c\u003c\u003c HEAD\nYour changes\n=======\nTheir changes\n>>>>>>> branch-name","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resolve conflicts by choosing correct code","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Remove conflict markers","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test the resolved code","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Stage and commit:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git add src/conflicted-file.ts\ngit commit -m \"merge: resolve conflicts in user authentication\"","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Best practices","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Understand both changes before resolving","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Test thoroughly after resolution","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Communicate with other developer if unclear","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Use merge tool if conflicts are complex: ","type":"text"},{"text":"git mergetool","type":"text","marks":[{"type":"code_inline"}]}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Co-authored Commits","type":"text"}]},{"type":"paragraph","content":[{"text":"When multiple people contribute to a commit","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"feat(auth): implement OAuth2 authentication\n\nAdd Google and GitHub OAuth providers with token refresh.\n\nCo-authored-by: Jane Developer \[email protected]>\nCo-authored-by: Bob Engineer \[email protected]>","type":"text"}]},{"type":"paragraph","content":[{"text":"Claude Code integration","type":"text","marks":[{"type":"strong"}]},{"text":": Always include Claude as co-author:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"Co-authored-by: Claude \[email protected]>","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Atomic Commits","type":"text"}]},{"type":"paragraph","content":[{"text":"Definition","type":"text","marks":[{"type":"strong"}]},{"text":": One logical change per commit","type":"text"}]},{"type":"paragraph","content":[{"text":"✅ Good (atomic)","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Commit 1: Add feature\ngit commit -m \"feat(search): add search bar component\"\n\n# Commit 2: Add tests\ngit commit -m \"test(search): add search bar component tests\"\n\n# Commit 3: Update docs\ngit commit -m \"docs(search): document search bar API\"","type":"text"}]},{"type":"paragraph","content":[{"text":"❌ Bad (non-atomic)","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# One commit with multiple unrelated changes\ngit commit -m \"Add search, fix login bug, update README\"","type":"text"}]},{"type":"paragraph","content":[{"text":"Benefits of atomic commits","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Easy to revert specific changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Clear history and blame","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Simpler code review","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Enables selective cherry-picking","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Git Hooks","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Hook Types","type":"text"}]},{"type":"paragraph","content":[{"text":"pre-commit","type":"text","marks":[{"type":"strong"}]},{"text":": Run before commit is created","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Linting (ESLint, Pylint)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Code formatting (Prettier, Black)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Type checking","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Unit tests (fast only)","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"commit-msg","type":"text","marks":[{"type":"strong"}]},{"text":": Validate commit message","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Conventional commit format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Message length","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Required patterns","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"pre-push","type":"text","marks":[{"type":"strong"}]},{"text":": Run before push to remote","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Full test suite","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Build verification","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Integration tests","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Pre-commit Hook Example","type":"text"}]},{"type":"paragraph","content":[{"text":"Using Husky (JavaScript projects)","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"json"},"content":[{"text":"{\n \"husky\": {\n \"hooks\": {\n \"pre-commit\": \"lint-staged\",\n \"commit-msg\": \"commitlint -E HUSKY_GIT_PARAMS\"\n }\n },\n \"lint-staged\": {\n \"*.{js,jsx,ts,tsx}\": [\"eslint --fix\", \"prettier --write\"],\n \"*.{json,md}\": [\"prettier --write\"]\n }\n}","type":"text"}]},{"type":"paragraph","content":[{"text":"Using pre-commit framework (Python projects)","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"yaml"},"content":[{"text":"# .pre-commit-config.yaml\nrepos:\n - repo: https://github.com/pre-commit/pre-commit-hooks\n rev: v4.4.0\n hooks:\n - id: trailing-whitespace\n - id: end-of-file-fixer\n - id: check-yaml\n - id: check-added-large-files\n\n - repo: https://github.com/psf/black\n rev: 23.1.0\n hooks:\n - id: black\n\n - repo: https://github.com/pycqa/flake8\n rev: 6.0.0\n hooks:\n - id: flake8","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Commit Message Validation Hook","type":"text"}]},{"type":"paragraph","content":[{"text":"Using commitlint","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"javascript"},"content":[{"text":"// commitlint.config.js\nmodule.exports = {\n extends: ['@commitlint/config-conventional'],\n rules: {\n 'type-enum': [\n 2,\n 'always',\n ['feat', 'fix', 'docs', 'style', 'refactor', 'test', 'chore', 'perf', 'ci', 'build', 'revert']\n ],\n 'subject-max-length': [2, 'always', 50],\n 'body-max-line-length': [2, 'always', 72]\n }\n};","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Hooks vs CI/CD","type":"text"}]},{"type":"paragraph","content":[{"text":"Use hooks for","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Fast checks (\u003c 10 seconds)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Formatting and linting","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Commit message validation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Pre-push quick tests","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Use CI/CD for","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Full test suite","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Integration tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Deployment","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security scans","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Performance tests","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Reason","type":"text","marks":[{"type":"strong"}]},{"text":": Hooks should be fast to not slow down development workflow","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Security and Safety","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Never Commit Secrets","type":"text"}]},{"type":"paragraph","content":[{"text":"Common secrets to avoid","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"API keys and tokens","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Database passwords","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Private keys (SSH, TLS, JWT)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"OAuth client secrets","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"AWS/cloud credentials","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":".env","type":"text","marks":[{"type":"code_inline"}]},{"text":" files with secrets","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Prevention with .gitignore","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"gitignore"},"content":[{"text":"# Environment files\n.env\n.env.local\n.env.*.local\n\n# Credentials\ncredentials.json\nsecrets.yaml\n*.key\n*.pem\n\n# Cloud provider\n.aws/credentials\n.gcloud/credentials\n\n# IDE\n.vscode/settings.json (if contains secrets)","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Removing Accidentally Committed Secrets","type":"text"}]},{"type":"paragraph","content":[{"text":"If secret committed but not pushed","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Remove file from staging\ngit reset HEAD secrets.env\n\n# Amend last commit\ngit commit --amend\n\n# Or reset to previous commit\ngit reset --soft HEAD~1","type":"text"}]},{"type":"paragraph","content":[{"text":"If secret already pushed","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Rotate the secret immediately","type":"text","marks":[{"type":"strong"}]},{"text":" (most important!)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Remove from history:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Using git filter-repo (recommended)\ngit filter-repo --path secrets.env --invert-paths\n\n# Or using BFG Repo-Cleaner\nbfg --delete-files secrets.env\n\n# Force push (coordinate with team!)\ngit push --force-with-lease origin main","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Verify secret removed: ","type":"text"},{"text":"git log --all --full-history -- secrets.env","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Notify team about force push","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Important","type":"text","marks":[{"type":"strong"}]},{"text":": Removing from git doesn't invalidate the secret. Always rotate!","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Signed Commits (GPG)","type":"text"}]},{"type":"paragraph","content":[{"text":"Why sign commits","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Verify commit author identity","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Prevent impersonation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Required for some organizations","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Setup GPG signing","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Generate GPG key\ngpg --full-generate-key\n\n# List keys\ngpg --list-secret-keys --keyid-format=long\n\n# Configure git\ngit config --global user.signingkey YOUR_KEY_ID\ngit config --global commit.gpgsign true\n\n# Sign individual commit\ngit commit -S -m \"feat(auth): add OAuth login\"","type":"text"}]},{"type":"paragraph","content":[{"text":"GitHub verification","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Export public key: ","type":"text"},{"text":"gpg --armor --export YOUR_KEY_ID","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add to GitHub: Settings → SSH and GPG keys → New GPG key","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Commits show \"Verified\" badge","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Protected Branches","type":"text"}]},{"type":"paragraph","content":[{"text":"Recommended protections for ","type":"text","marks":[{"type":"strong"}]},{"text":"main","type":"text","marks":[{"type":"code_inline"},{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Require pull request reviews (1-2 approvals)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Require status checks (CI tests pass)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Require signed commits (optional)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Require linear history (optional)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Include administrators (enforce for all)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Restrict who can push","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Require conversation resolution","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"GitHub branch protection setup","type":"text","marks":[{"type":"strong"}]},{"text":": Repository Settings → Branches → Add rule → ","type":"text"},{"text":"main","type":"text","marks":[{"type":"code_inline"}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Required Reviews","type":"text"}]},{"type":"paragraph","content":[{"text":"Review requirements","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimum 1 approval for small teams","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Minimum 2 approvals for production code","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Code owner approval for critical paths","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Dismiss stale reviews on new commits","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"CODEOWNERS file","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":""},"content":[{"text":"# .github/CODEOWNERS\n# Require review from team leads\n/src/auth/* @auth-team\n/src/api/* @backend-team\n/src/ui/* @frontend-team\n\n# Require multiple reviews for critical files\n/deploy/* @devops-team @tech-leads","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Workflow Examples","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 1: Feature Development Workflow (GitHub Flow)","type":"text"}]},{"type":"paragraph","content":[{"text":"Scenario","type":"text","marks":[{"type":"strong"}]},{"text":": Add user profile page","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. Start from updated main\ngit checkout main\ngit pull origin main\n\n# 2. Create feature branch\ngit checkout -b feature/user-profile-page\n\n# 3. Develop incrementally with atomic commits\ngit add src/pages/UserProfile.tsx\ngit commit -m \"feat(profile): add user profile page component\"\n\ngit add src/api/user.ts\ngit commit -m \"feat(profile): add API endpoint for user data\"\n\ngit add src/pages/UserProfile.test.tsx\ngit commit -m \"test(profile): add user profile component tests\"\n\ngit add docs/user-profile.md\ngit commit -m \"docs(profile): document user profile feature\"\n\n# 4. Keep branch updated with main\ngit fetch origin\ngit rebase origin/main\n\n# 5. Push and create PR\ngit push -u origin feature/user-profile-page\ngh pr create \\\n --title \"feat(profile): add user profile page\" \\\n --body \"$(cat \u003c\u003c'EOF'\n## Summary\nImplements user profile page with avatar, bio, and settings.\n\n## Changes\n- Add UserProfile component with responsive design\n- Add API endpoint for fetching user data\n- Add unit and integration tests\n- Update documentation\n\n## Test Plan\n1. Navigate to /profile\n2. Verify profile information displays correctly\n3. Test on mobile and desktop viewports\n4. Verify edit functionality\n\nCloses #156\nEOF\n)\"\n\n# 6. Address review feedback\ngit add src/pages/UserProfile.tsx\ngit commit -m \"refactor(profile): extract avatar component per review\"\ngit push origin feature/user-profile-page\n\n# 7. After PR approval and merge\ngit checkout main\ngit pull origin main\ngit branch -d feature/user-profile-page","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 2: Hotfix Workflow (Production Bug)","type":"text"}]},{"type":"paragraph","content":[{"text":"Scenario","type":"text","marks":[{"type":"strong"}]},{"text":": Critical security vulnerability in production","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. Create hotfix branch from main\ngit checkout main\ngit pull origin main\ngit checkout -b hotfix/patch-auth-vulnerability\n\n# 2. Fix the issue\ngit add src/auth/oauth.ts\ngit commit -m \"fix(auth)!: patch token validation vulnerability\n\nBREAKING CHANGE: OAuth tokens now require signature validation.\nInvalid tokens will be rejected immediately.\n\nSecurity: Prevents token forgery attack (CVE-2024-XXXXX)\nCloses #489\"\n\n# 3. Add tests for the fix\ngit add src/auth/oauth.test.ts\ngit commit -m \"test(auth): add security tests for token validation\"\n\n# 4. Push and create urgent PR\ngit push -u origin hotfix/patch-auth-vulnerability\ngh pr create \\\n --title \"fix(auth)!: patch token validation vulnerability [SECURITY]\" \\\n --label \"security,hotfix\" \\\n --body \"$(cat \u003c\u003c'EOF'\n## Summary\n🚨 SECURITY: Patches critical token validation vulnerability.\n\n## Vulnerability\nOAuth tokens were not properly validated, allowing token forgery.\n\n## Fix\n- Add signature validation for all OAuth tokens\n- Reject invalid tokens immediately\n- Add comprehensive security tests\n\n## Breaking Change\nInvalid tokens that were previously accepted will now be rejected.\n\n## Testing\n- [x] Security tests added\n- [x] Manual testing with valid tokens\n- [x] Manual testing with forged tokens\n- [x] Backward compatibility verified\n\n## Deployment\nRequires immediate deployment to production.\n\nFixes #489\nEOF\n)\"\n\n# 5. After expedited review and merge\ngit checkout main\ngit pull origin main\ngit branch -d hotfix/patch-auth-vulnerability\n\n# 6. Tag the release\ngit tag -a v1.2.1 -m \"Hotfix: patch auth vulnerability\"\ngit push origin v1.2.1","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 3: Refactoring Workflow (Large Code Changes)","type":"text"}]},{"type":"paragraph","content":[{"text":"Scenario","type":"text","marks":[{"type":"strong"}]},{"text":": Refactor database layer for better performance","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. Create refactoring branch\ngit checkout main\ngit pull origin main\ngit checkout -b refactor/database-layer-optimization\n\n# 2. Make incremental, atomic commits\ngit add src/db/connection.ts\ngit commit -m \"refactor(db): extract connection pool configuration\"\n\ngit add src/db/queries/user.ts\ngit commit -m \"refactor(db): optimize user queries with prepared statements\"\n\ngit add src/db/queries/product.ts\ngit commit -m \"refactor(db): add database indexes for product queries\n\nPerformance improvement: Product search reduced from 250ms to 15ms\"\n\ngit add src/db/transaction.ts\ngit commit -m \"refactor(db): implement transaction helper utility\"\n\n# 3. Keep tests passing after each commit\ngit add src/db/queries/user.test.ts\ngit commit -m \"test(db): update user query tests for new implementation\"\n\n# 4. Update integration tests\ngit add tests/integration/db.test.ts\ngit commit -m \"test(db): add integration tests for transaction handling\"\n\n# 5. Document performance improvements\ngit add docs/database-optimization.md\ngit commit -m \"docs(db): document database optimization approach and results\"\n\n# 6. Rebase onto main to stay current\ngit fetch origin\ngit rebase origin/main\n\n# 7. Review commits are atomic and well-organized\ngit log --oneline origin/main..HEAD\n\n# 8. Create PR with detailed context\ngit push -u origin refactor/database-layer-optimization\ngh pr create \\\n --title \"refactor(db): optimize database layer for performance\" \\\n --body \"$(cat \u003c\u003c'EOF'\n## Summary\nRefactors database layer to improve query performance and code organization.\n\n## Changes\n- Extract connection pool configuration for better reusability\n- Optimize user and product queries with prepared statements\n- Add database indexes for common query patterns\n- Implement transaction helper utility\n- Update all tests for new implementation\n\n## Performance Impact\n- User lookup: 180ms → 12ms (93% improvement)\n- Product search: 250ms → 15ms (94% improvement)\n- Checkout flow: 450ms → 85ms (81% improvement)\n\n## Testing\n- [x] All existing tests pass\n- [x] Added integration tests for transactions\n- [x] Performance benchmarks completed\n- [x] Load testing with 1000 concurrent users\n\n## Migration\nNo database migrations required. Changes are backward compatible.\n\n## Breaking Changes\nNone\n\nRelated to #234\nEOF\n)\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 4: Documentation Update Workflow","type":"text"}]},{"type":"paragraph","content":[{"text":"Scenario","type":"text","marks":[{"type":"strong"}]},{"text":": Update API documentation for new endpoints","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. Create docs branch\ngit checkout main\ngit pull origin main\ngit checkout -b docs/update-api-documentation\n\n# 2. Update documentation files\ngit add docs/api/authentication.md\ngit commit -m \"docs(api): update OAuth authentication examples\"\n\ngit add docs/api/users.md\ngit commit -m \"docs(api): add user profile endpoint documentation\"\n\ngit add docs/api/search.md\ngit commit -m \"docs(api): document new search filters API\"\n\ngit add README.md\ngit commit -m \"docs(readme): update API reference links\"\n\n# 3. Verify documentation builds correctly\nnpm run docs:build\n\n# 4. Push and create PR\ngit push -u origin docs/update-api-documentation\ngh pr create \\\n --title \"docs(api): update API documentation for v2.0\" \\\n --body \"$(cat \u003c\u003c'EOF'\n## Summary\nUpdates API documentation to reflect v2.0 changes.\n\n## Changes\n- Update OAuth authentication examples\n- Add user profile endpoint documentation\n- Document new search filters API\n- Update README with correct API reference links\n\n## Verification\n- [x] Documentation builds without errors\n- [x] All links are valid\n- [x] Code examples tested and working\n- [x] Screenshots updated\n\nRelated to #298\nEOF\n)\"\n\n# 5. After review and merge\ngit checkout main\ngit pull origin main\ngit branch -d docs/update-api-documentation","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Example 5: Multi-commit Feature Workflow","type":"text"}]},{"type":"paragraph","content":[{"text":"Scenario","type":"text","marks":[{"type":"strong"}]},{"text":": Implement search functionality (complex feature)","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# 1. Create feature branch\ngit checkout main\ngit pull origin main\ngit checkout -b feature/advanced-search\n\n# 2. Build feature incrementally with atomic commits\n\n# Add search infrastructure\ngit add src/search/index.ts src/search/types.ts\ngit commit -m \"feat(search): add search infrastructure and types\"\n\n# Add search parser\ngit add src/search/parser.ts\ngit commit -m \"feat(search): implement query parser with boolean operators\"\n\n# Add search indexer\ngit add src/search/indexer.ts\ngit commit -m \"feat(search): add document indexer with full-text support\"\n\n# Add search API\ngit add src/api/search.ts\ngit commit -m \"feat(search): add search API endpoints\"\n\n# Add search UI component\ngit add src/components/SearchBar.tsx\ngit commit -m \"feat(search): add search bar component\"\n\n# Add filters\ngit add src/components/SearchFilters.tsx\ngit commit -m \"feat(search): add category and date filters\"\n\n# Add tests for each component\ngit add src/search/parser.test.ts\ngit commit -m \"test(search): add query parser tests\"\n\ngit add src/search/indexer.test.ts\ngit commit -m \"test(search): add indexer tests\"\n\ngit add src/components/SearchBar.test.tsx\ngit commit -m \"test(search): add search bar component tests\"\n\n# Add integration tests\ngit add tests/integration/search.test.ts\ngit commit -m \"test(search): add end-to-end search integration tests\"\n\n# Add documentation\ngit add docs/search.md\ngit commit -m \"docs(search): document search API and query syntax\"\n\n# 3. Review commit history\ngit log --oneline origin/main..HEAD\n\n# 4. Optionally clean up history with interactive rebase\ngit rebase -i origin/main\n# Squash related commits if needed\n\n# 5. Create detailed PR\ngit push -u origin feature/advanced-search\ngh pr create \\\n --title \"feat(search): implement advanced search functionality\" \\\n --body \"$(cat \u003c\u003c'EOF'\n## Summary\nImplements advanced search with boolean operators, filters, and full-text indexing.\n\n## Features\n- Full-text search with boolean operators (AND, OR, NOT)\n- Category and date range filters\n- Real-time search suggestions\n- Search result highlighting\n- Performance: \u003c50ms for typical queries\n\n## Changes\n- Add search infrastructure (parser, indexer)\n- Add search API endpoints\n- Add search UI components (SearchBar, SearchFilters)\n- Add comprehensive test coverage (unit + integration)\n- Add documentation for search API\n\n## Testing\n- [x] Unit tests for all components\n- [x] Integration tests for search flow\n- [x] Performance benchmarks\n- [x] Manual testing with various queries\n\n## Screenshots\n[Add screenshots of search UI]\n\nCloses #187, #234\nEOF\n)\"","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Integration with Claude Code Workflows","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"When Agents Should Create Commits","type":"text"}]},{"type":"paragraph","content":[{"text":"Agents should create commits when:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User explicitly requests","type":"text","marks":[{"type":"strong"}]},{"text":": \"Create a commit\", \"Commit these changes\"","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"After completing task","type":"text","marks":[{"type":"strong"}]},{"text":": When deliverable is complete and tests pass","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Before creating PR","type":"text","marks":[{"type":"strong"}]},{"text":": When preparing to create pull request","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"After code review changes","type":"text","marks":[{"type":"strong"}]},{"text":": When addressing review feedback","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Agents should NOT automatically commit when:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Changes are incomplete or experimental","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tests are failing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"User hasn't reviewed the changes","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Working in interactive exploration mode","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"When to Use git-expert Agent","type":"text"}]},{"type":"paragraph","content":[{"text":"Delegate to ","type":"text"},{"text":"git-expert","type":"text","marks":[{"type":"code_inline"}]},{"text":" agent for:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Complex git history manipulation (rebasing, cherry-picking)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Resolving merge conflicts","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Git repository diagnostics","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Advanced branching strategy implementation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Git configuration and setup","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Repository migration or cleanup","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"Use ","type":"text"},{"text":"git-workflow-skills","type":"text","marks":[{"type":"code_inline"}]},{"text":" (this skill) for:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Standard commit creation","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Following commit conventions","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Creating PRs with proper format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Choosing merge strategy","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Applying collaboration workflows","type":"text"}]}]}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"Commit Message Generation from Changes","type":"text"}]},{"type":"paragraph","content":[{"text":"Workflow for agents creating commits","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyze changes","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git status\ngit diff --cached","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Determine commit type","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"New files/features → ","type":"text"},{"text":"feat","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Bug fixes → ","type":"text"},{"text":"fix","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Documentation → ","type":"text"},{"text":"docs","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Refactoring → ","type":"text"},{"text":"refactor","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Tests → ","type":"text"},{"text":"test","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify scope","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"From file paths: ","type":"text"},{"text":"src/auth/","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"auth","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Component name: ","type":"text"},{"text":"SearchBar.tsx","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"search","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Module name: ","type":"text"},{"text":"api/users.ts","type":"text","marks":[{"type":"code_inline"}]},{"text":" → ","type":"text"},{"text":"api","type":"text","marks":[{"type":"code_inline"}]}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Write subject line","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Imperative mood: \"add\", \"fix\", \"update\" (not \"added\", \"fixes\")","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"50 characters max","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"No period at end","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Describe what the code does (not what you did)","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add body if needed","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Why the change was made","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What problem it solves","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Any important context","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Wrap at 72 characters","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Add footer","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Issue references: ","type":"text"},{"text":"Closes #123","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Breaking changes: ","type":"text"},{"text":"BREAKING CHANGE: ...","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Co-authors: ","type":"text"},{"text":"Co-authored-by: Claude \[email protected]>","type":"text","marks":[{"type":"code_inline"}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Claude Code attribution","type":"text"}]}]}]}]}]},{"type":"paragraph","content":[{"text":"Example agent workflow","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"# Agent analyzes changes\ngit diff --cached\n\n# Changes show:\n# - New file: src/components/SearchBar.tsx\n# - Modified: src/api/search.ts\n# - Modified: src/types/search.ts\n\n# Agent determines:\n# Type: feat (new component)\n# Scope: search (from file paths)\n# Subject: add search bar component with autocomplete\n\n# Agent creates commit:\ngit commit -m \"$(cat \u003c\u003c'EOF'\nfeat(search): add search bar component with autocomplete\n\nImplement search bar with real-time autocomplete suggestions.\nIncludes debouncing for performance and keyboard navigation support.\n\n🤖 Generated with [Claude Code](https://claude.com/claude-code)\n\nCo-Authored-By: Claude \[email protected]>\nEOF\n)\"","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"PR Description Generation","type":"text"}]},{"type":"paragraph","content":[{"text":"Workflow for agents creating PRs","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Analyze all commits","type":"text","marks":[{"type":"strong"}]},{"text":" in branch:","type":"text"}]},{"type":"code_block","attrs":{"wrap":false,"language":"bash"},"content":[{"text":"git log origin/main..HEAD\ngit diff origin/main...HEAD","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Summarize changes","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What features were added?","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What bugs were fixed?","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What was refactored?","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"What documentation was updated?","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify related issues","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Look for issue references in commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Check commit messages for \"Closes\", \"Fixes\", \"Related to\"","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Create test plan","type":"text","marks":[{"type":"strong"}]},{"text":":","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"List manual testing steps","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Identify automated tests","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Highlight edge cases tested","type":"text"}]}]}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Generate PR using template","type":"text","marks":[{"type":"strong"}]},{"text":" (see PR/MR Best Practices section)","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Resources","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"scripts/","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill includes validation and generation scripts for git workflows:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"validate_commit_msg.py","type":"text","marks":[{"type":"strong"}]},{"text":": Validates commit messages against Conventional Commits specification","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"generate_commit_msg.py","type":"text","marks":[{"type":"strong"}]},{"text":": Generates commit messages from git diff output","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"See ","type":"text"},{"text":"scripts/README.md","type":"text","marks":[{"type":"code_inline"}]},{"text":" for usage details.","type":"text"}]},{"type":"heading","attrs":{"level":3},"content":[{"text":"references/","type":"text"}]},{"type":"paragraph","content":[{"text":"Additional reference documentation:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"conventional-commits-examples.md","type":"text","marks":[{"type":"strong"}]},{"text":": Extensive examples of good and bad commit messages","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"branching-strategy-comparison.md","type":"text","marks":[{"type":"strong"}]},{"text":": Detailed comparison of GitHub Flow, Git Flow, and Trunk-based Development","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"pr-templates.md","type":"text","marks":[{"type":"strong"}]},{"text":": PR description templates for different types of changes","type":"text"}]}]}]},{"type":"paragraph","content":[{"text":"These references provide additional context and examples without cluttering the main skill document.","type":"text"}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Quality Checklist","type":"text"}]},{"type":"paragraph","content":[{"text":"Before completing any git workflow operation, verify:","type":"text"}]},{"type":"bullet_list","content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Commit messages follow Conventional Commits format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Commit type is appropriate (feat, fix, docs, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Subject line is ≤50 characters, imperative mood","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Body wraps at 72 characters (if present)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Breaking changes are clearly indicated","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Commits are atomic (one logical change each)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ No secrets or sensitive data committed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Branch name follows convention (feature/, bugfix/, etc.)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ PR title follows commit message format","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ PR description is complete and clear","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Tests pass before committing","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Code is self-reviewed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Appropriate git operation chosen (merge vs rebase vs squash)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Protected branches are not force-pushed","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"✅ Claude Code attribution included in commits","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Summary","type":"text"}]},{"type":"paragraph","content":[{"text":"This skill provides comprehensive guidance for professional git workflows. Key takeaways:","type":"text"}]},{"type":"ordered_list","attrs":{"order":1,"listStyle":"number"},"content":[{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Commit Messages","type":"text","marks":[{"type":"strong"}]},{"text":": Always use Conventional Commits format with clear type, scope, and subject","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Branching","type":"text","marks":[{"type":"strong"}]},{"text":": Choose strategy based on project needs (GitHub Flow for most, Git Flow for complex releases)","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"PRs","type":"text","marks":[{"type":"strong"}]},{"text":": Write detailed descriptions with context, testing, and checklists","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Operations","type":"text","marks":[{"type":"strong"}]},{"text":": Understand merge vs rebase vs squash trade-offs","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Collaboration","type":"text","marks":[{"type":"strong"}]},{"text":": Keep branches updated, resolve conflicts carefully, use atomic commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Security","type":"text","marks":[{"type":"strong"}]},{"text":": Never commit secrets, use protected branches, consider signed commits","type":"text"}]}]},{"type":"list_item","content":[{"type":"paragraph","content":[{"text":"Integration","type":"text","marks":[{"type":"strong"}]},{"text":": Agents should create commits when requested or after completing tasks","type":"text"}]}]}]},{"type":"heading","attrs":{"level":2},"content":[{"text":"Refer to the reference documents for detailed examples and comparisons.","type":"text"}]}]},"metadata":{"date":"2026-06-05","name":"git-workflow-skills","author":"@skillopedia","source":{"stars":0,"repo_name":"clawdbot-skills-pack","origin_url":"https://github.com/kimasplund/clawdbot-skills-pack/blob/HEAD/development-skills/git-workflow/SKILL.md","repo_owner":"kimasplund","body_sha256":"c625ea8d64306fe6fac76e908064d4fb1930cca8518557dad9f594db8c270a1c","cluster_key":"72f8faef8e57e9a2714de2e80943221b1dc18cbc58f368b7ee7010e5600bcfe9","clean_bundle":{"format":"clean-skill-bundle-v1","source":"kimasplund/clawdbot-skills-pack/development-skills/git-workflow/SKILL.md","attachments":[{"id":"9527992a-4a02-585d-9047-3e81f4e10457","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/9527992a-4a02-585d-9047-3e81f4e10457/attachment.md","path":"references/branching-strategy-comparison.md","size":14174,"sha256":"4afd80408489d51da2f581be1ab272916650ffe664283da1486ca4c194e02730","contentType":"text/markdown; charset=utf-8"},{"id":"af2103f7-410a-59d4-89a5-02751875fe4c","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/af2103f7-410a-59d4-89a5-02751875fe4c/attachment.md","path":"references/conventional-commits-examples.md","size":13529,"sha256":"657f932140342bd06e8e2eb1ce3885b56f58efa75173dd991372131275b66ac0","contentType":"text/markdown; charset=utf-8"},{"id":"b2c24dc8-078c-53f4-94cf-62ac0b22d076","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/b2c24dc8-078c-53f4-94cf-62ac0b22d076/attachment.md","path":"references/pr-templates.md","size":13134,"sha256":"91204def42c491068cfc548a97d4da68408c849f3fe1556d26c00ab82938ae9d","contentType":"text/markdown; charset=utf-8"},{"id":"e043a8ba-c03c-56dd-b6b2-7bf3cd440f87","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/e043a8ba-c03c-56dd-b6b2-7bf3cd440f87/attachment.md","path":"scripts/README.md","size":3361,"sha256":"0ff2bb9fef17d2eef249339924949b969ed9c3e1ce245b0213f732e1985d7830","contentType":"text/markdown; charset=utf-8"},{"id":"ff48ff26-a891-5ab4-b46c-52a5c47cfa33","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/ff48ff26-a891-5ab4-b46c-52a5c47cfa33/attachment.py","path":"scripts/generate_commit_msg.py","size":12424,"sha256":"accf6c17f6c1c0d222f3acd0e62a7a9e9b376bf6b9c2dc4190e9d3bf0762adfe","contentType":"text/x-python; charset=utf-8"},{"id":"c0e6d594-13cc-590e-a958-9aa8a873f7c9","key":"uploads/10433ee7-ad12-4ae0-b34e-97553e46c6c8/c0e6d594-13cc-590e-a958-9aa8a873f7c9/attachment.py","path":"scripts/validate_commit_msg.py","size":7338,"sha256":"9288317de6447054669df148d5f48e3760513db9df72b4c4abbc82ace9a1e7bf","contentType":"text/x-python; charset=utf-8"}],"bundle_sha256":"ca357d1ec5f8a51ca741a472380a83437a081e2d2e87d01afcd8533d0bf142bb","attachment_count":6,"text_attachments":6,"attachment_storage":"skillopedia-attachments-v1","binary_attachments":0,"excluded_attachments":[]},"cluster_size":1,"skill_md_path":"development-skills/git-workflow/SKILL.md","import_metadata":{"date":"2026-06-05","author":"@skillopedia","version":"v1","category":"productivity-workflow","category_label":"Productivity"},"exact_dupes_collapsed_into_this":0},"license":"MIT","version":"v1","category":"productivity-workflow","import_tag":"clean-skills-v1","description":"Provides standardized Git workflows, commit message conventions, branching strategies, and collaboration patterns for all agents performing Git operations. Use when creating commits, choosing branching strategies, creating PRs, performing git operations (merge vs rebase), or handling git collaboration workflows."}},"renderedAt":1782980062451}

Git Workflow Skills Overview This skill provides comprehensive Git workflow guidance for agents performing version control operations. It covers commit message conventions (Conventional Commits), branching strategies (GitHub Flow, Git Flow, Trunk-based), PR best practices, git operation patterns (merge vs rebase vs squash), collaboration workflows, and security considerations. Use this skill whenever performing git operations to ensure consistency, maintainability, and professional quality across all projects. Core Principles 1. Clarity Over Cleverness : Commit messages and branch names shoul…