Como usar git hooks para automatizar validações antes do commit
1. Introdução aos Git Hooks: O que são e por que usar
Git hooks são scripts executados automaticamente quando eventos específicos ocorrem no ciclo de vida do Git, como commit, push ou merge. Eles funcionam como gatilhos que permitem automatizar validações e ações antes ou depois dessas operações.
Os principais benefícios do uso de hooks incluem:
- Padronização de código: Garantir que todo código commitado siga as mesmas regras de estilo e linting
- Prevenção de erros: Bloquear commits que contenham erros de sintaxe, testes quebrados ou vulnerabilidades
- Economia de tempo em revisões: Reduzir correções manuais em code reviews, já que problemas comuns são resolvidos automaticamente
Os hooks são armazenados no diretório .git/hooks de cada repositório. Existem dois tipos principais:
- Client-side: Executados na máquina do desenvolvedor (pre-commit, commit-msg, pre-push)
- Server-side: Executados no servidor remoto (pre-receive, update, post-receive)
2. Configuração do Ambiente e Hooks Básicos
Para começar a usar hooks, acesse o diretório .git/hooks do seu repositório. Você encontrará arquivos com sufixo .sample, como pre-commit.sample. Para ativar um hook, remova o sufixo:
cd .git/hooks
cp pre-commit.sample pre-commit
Hook pre-commit
Este hook é executado antes do snapshot ser criado. É ideal para validações rápidas:
#!/bin/sh
# .git/hooks/pre-commit
echo "Executando validações pré-commit..."
# Verificar se há arquivos staged
if git diff --cached --name-only | grep -q .; then
echo "Arquivos encontrados. Prosseguindo..."
else
echo "Nenhum arquivo staged. Abortando commit."
exit 1
fi
Hook commit-msg
Valida o formato da mensagem de commit. Exemplo usando Conventional Commits:
#!/bin/sh
# .git/hooks/commit-msg
commit_message=$(cat "$1")
# Regex para validar Conventional Commits
pattern="^(feat|fix|docs|style|refactor|perf|test|chore|ci)(\(.+\))?: .{1,72}$"
if ! echo "$commit_message" | grep -qE "$pattern"; then
echo "ERRO: Mensagem de commit inválida!"
echo "Formato esperado: tipo(escopo): descrição"
echo "Exemplo: feat(login): adiciona validação de email"
exit 1
fi
3. Automatizando Validações com Scripts Customizados
Linting automático com ESLint (JavaScript/TypeScript)
#!/bin/sh
# .git/hooks/pre-commit
echo "Executando ESLint nos arquivos staged..."
staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|jsx|ts|tsx)$')
if [ -n "$staged_files" ]; then
npx eslint $staged_files
if [ $? -ne 0 ]; then
echo "ERRO: ESLint encontrou problemas. Corrija antes de commitar."
exit 1
fi
fi
Formatação automática com Prettier
#!/bin/sh
# .git/hooks/pre-commit
echo "Formatando arquivos com Prettier..."
staged_files=$(git diff --cached --name-only --diff-filter=ACM | grep -E '\.(js|jsx|ts|tsx|json|css|md)$')
if [ -n "$staged_files" ]; then
npx prettier --write $staged_files
git add $staged_files
fi
Testes unitários rápidos
#!/bin/sh
# .git/hooks/pre-commit
echo "Executando testes unitários..."
# Executa apenas testes relacionados aos arquivos modificados
npx jest --findRelatedTests $(git diff --cached --name-only --diff-filter=ACM)
if [ $? -ne 0 ]; then
echo "ERRO: Testes falharam. Corrija antes de commitar."
exit 1
fi
4. Gerenciamento de Hooks com Ferramentas Modernas
Husky (Node.js)
Husky simplifica o gerenciamento de hooks em projetos JavaScript:
# Instalação
npm install husky --save-dev
# Ativação
npx husky install
# Adicionar hook
npx husky add .husky/pre-commit "npx lint-staged"
Configuração no package.json:
{
"scripts": {
"prepare": "husky install"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": ["eslint --fix", "prettier --write"],
"*.{json,css,md}": ["prettier --write"]
}
}
Pre-commit Framework (Python/Multi-linguagem)
Ideal para projetos Python ou multi-linguagem:
# Instalação
pip install pre-commit
# Criar arquivo de configuração
touch .pre-commit-config.yaml
Exemplo de .pre-commit-config.yaml:
repos:
- repo: https://github.com/pre-commit/pre-commit-hooks
rev: v4.4.0
hooks:
- id: trailing-whitespace
- id: end-of-file-fixer
- id: check-yaml
- repo: https://github.com/psf/black
rev: 23.3.0
hooks:
- id: black
- repo: https://github.com/PyCQA/flake8
rev: 6.0.0
hooks:
- id: flake8
5. Hooks Avançados e Integração com Workflows
Hook prepare-commit-msg
Gera automaticamente mensagens de commit baseadas em issues:
#!/bin/sh
# .git/hooks/prepare-commit-msg
branch_name=$(git rev-parse --abbrev-ref HEAD)
issue_number=$(echo $branch_name | grep -oE 'issue-[0-9]+')
if [ -n "$issue_number" ]; then
sed -i "1s/^/[$issue_number] /" "$1"
fi
Hook pre-push
Validações mais pesadas antes do push:
#!/bin/sh
# .git/hooks/pre-push
echo "Executando testes de integração..."
npm run test:integration
if [ $? -ne 0 ]; then
echo "ERRO: Testes de integração falharam. Push bloqueado."
exit 1
fi
echo "Verificando vulnerabilidades..."
npm audit
if [ $? -ne 0 ]; then
echo "ERRO: Vulnerabilidades encontradas. Push bloqueado."
exit 1
fi
6. Boas Práticas e Resolução de Problemas Comuns
Ignorar hooks temporariamente
Use a flag --no-verify para pular hooks em situações emergenciais:
git commit --no-verify -m "fix: correção crítica de segurança"
Tratamento de erros
Sempre forneça mensagens claras e use exit codes apropriados:
#!/bin/sh
# .git/hooks/pre-commit
run_linter() {
echo "Verificando lint..."
npx eslint src/
return $?
}
run_tests() {
echo "Executando testes..."
npm test
return $?
}
if ! run_linter; then
echo "❌ Lint falhou. Execute: npm run lint:fix"
exit 1
fi
if ! run_tests; then
echo "❌ Testes falharam. Verifique os erros acima."
exit 1
fi
echo "✅ Todas as verificações passaram!"
Versionamento de hooks
Mantenha os hooks em pasta dedicada e crie script de instalação:
# Estrutura de diretórios
scripts/
git-hooks/
pre-commit
commit-msg
pre-push
install-hooks.sh
Script de instalação:
#!/bin/sh
# scripts/install-hooks.sh
echo "Instalando hooks do Git..."
cp scripts/git-hooks/* .git/hooks/
chmod +x .git/hooks/*
echo "✅ Hooks instalados com sucesso!"
7. Exemplo Prático Completo: Pipeline de Validação Pré-Commit
Configuração completa com Husky + ESLint + Prettier + Testes
# 1. Inicializar projeto Node.js
npm init -y
# 2. Instalar dependências
npm install --save-dev husky lint-staged eslint prettier jest
# 3. Configurar Husky
npx husky install
npm pkg set scripts.prepare="husky install"
# 4. Adicionar hook pre-commit
npx husky add .husky/pre-commit "npx lint-staged"
# 5. Configurar lint-staged no package.json
package.json:
{
"scripts": {
"prepare": "husky install",
"test": "jest",
"lint": "eslint src/",
"format": "prettier --write src/"
},
"lint-staged": {
"*.{js,jsx,ts,tsx}": [
"eslint --fix",
"prettier --write",
"jest --findRelatedTests"
],
"*.{json,css,md}": ["prettier --write"]
}
}
Demonstração de fluxo
Commit bem-sucedido:
$ git add src/index.js
$ git commit -m "feat: adiciona função de validação"
✔ lint-staged executou com sucesso
✔ ESLint verificou e corrigiu
✔ Prettier formatou
✔ Testes relacionados passaram
✅ Commit criado com sucesso!
Commit bloqueado por erro:
$ git add src/broken.js
$ git commit -m "fix: correção temporária"
❌ ESLint encontrou erros:
src/broken.js:10:3 - Unexpected console statement (no-console)
❌ Testes falharam:
FAIL src/broken.test.js
● Teste de validação › deve retornar true para input válido
✖ Commit abortado. Corrija os erros e tente novamente.
Este pipeline garante que apenas código limpo, formatado e testado seja commitado, mantendo a qualidade do repositório e economizando tempo em revisões.
Referências
- Documentação oficial do Git - Git Hooks — Guia completo sobre todos os tipos de hooks e sua implementação
- Husky - Modern Git Hooks for JavaScript — Ferramenta moderna para gerenciar hooks em projetos Node.js
- Pre-commit Framework - Documentação — Framework multi-linguagem para gerenciamento de hooks com exemplos práticos
- Conventional Commits - Especificação — Padrão de mensagens de commit que pode ser validado via hooks
- ESLint - Integração com Git Hooks — Como configurar ESLint para executar automaticamente em hooks pre-commit
- Prettier - Pre-commit Hook — Guia oficial para integrar Prettier com hooks de formatação automática
- Atlassian - Guia Completo de Git Hooks — Tutorial detalhado com exemplos práticos e casos de uso avançados