Proteção de branches no GitHub

1. Introdução à proteção de branches

Branches protegidas são um mecanismo de segurança essencial em repositórios Git hospedados no GitHub. Elas impedem que alterações não autorizadas ou não revisadas sejam aplicadas diretamente em branches críticas como main, production ou release. Sem essa proteção, qualquer colaborador com acesso de escrita poderia sobrescrever o histórico do projeto, introduzir código defeituoso ou até mesmo remover funcionalidades inteiras acidentalmente.

É importante diferenciar a proteção local da remota. No Git local, você pode usar hooks (scripts que disparam em eventos como pre-commit ou pre-push) para validar mudanças antes que saiam da sua máquina. Já a proteção remota, oferecida pelo GitHub, é aplicada no servidor, independentemente de quem faz o push. Enquanto hooks podem ser ignorados ou desativados localmente, as regras de proteção do GitHub são obrigatórias e garantem a integridade do repositório central.

O GitHub oferece um conjunto robusto de regras de proteção, que incluem desde a exigência de pull requests até a restrição de force push. A seguir, exploraremos cada uma dessas configurações.

2. Configurando regras básicas de proteção

Para acessar as configurações de proteção de branch, vá até o repositório desejado no GitHub e clique em Settings > Branches. Na seção "Branch protection rules", clique em Add rule.

Você pode especificar um padrão de nome de branch, como:

main
develop
release/*

Isso significa que a regra se aplicará exatamente à branch main, à branch develop e a todas as branches que começam com release/.

A regra mais fundamental é "Require a pull request before merging". Quando ativada, nenhum commit pode ser enviado diretamente para a branch protegida. Toda alteração deve passar por um pull request. Você pode ainda configurar quantas aprovações são necessárias, como veremos a seguir.

3. Exigência de revisões em pull requests

Dentro da opção "Require a pull request before merging", você define o número mínimo de revisores que devem aprovar o PR antes do merge. Por exemplo, para exigir duas aprovações:

Required number of approvals before merging: 2

Outra configuração poderosa é "Require review from Code Owners". O GitHub permite definir, em um arquivo CODEOWNERS na raiz do repositório, quem é responsável por partes específicas do código. Quando essa opção está ativa, qualquer PR que altere arquivos com code owners definidos precisa da aprovação dessas pessoas.

Exemplo de CODEOWNERS:

# Os donos do repositório são donos de tudo
* @joao @maria

# A equipe de segurança revisa todos os arquivos de configuração
/config/ @equipe-seguranca

Você também pode ativar "Dismiss stale pull request approvals when new commits are pushed". Isso garante que, se um revisor aprovou um PR e depois novos commits forem adicionados, a aprovação anterior é revogada — forçando uma nova revisão.

4. Restrições de merge e status checks

Uma prática comum é exigir que a branch do PR esteja atualizada em relação à branch base antes do merge. Isso evita que mudanças conflitantes sejam mescladas. A opção "Require branches to be up to date before merging" faz exatamente isso.

Além disso, você pode habilitar status checks obrigatórios. Esses checks são executados por serviços de CI/CD (como GitHub Actions, Jenkins ou CircleCI). Por exemplo, você pode exigir que todos os testes passem e que o lint não aponte erros antes de permitir o merge.

Status checks that are required:
- continuous-integration/tests (pass)
- lint/check (pass)

Outra proteção útil é "Require conversation resolution before merging". Quando ativada, qualquer comentário marcado como "conversa não resolvida" no PR impede o merge. Isso força a equipe a discutir e resolver todos os pontos levantados antes de integrar o código.

5. Proteções contra push direto e forçado

Branches protegidas, por padrão, já bloqueiam push direto. Mas você pode reforçar isso desabilitando explicitamente a opção "Allow force pushes". O git push --force é perigoso porque sobrescreve o histórico remoto, podendo causar perda de commits. Em branches como main, force push deve ser sempre bloqueado.

Para ambientes muito restritivos, você também pode desabilitar "Allow deletions", impedindo que a branch seja excluída por qualquer pessoa que não seja administrador. Isso é útil para branches de release ou produção.

Exemplo de configuração para uma branch production:

Protect matching branches: production
☑ Require a pull request before merging
☑ Require status checks
☐ Allow force pushes (desmarcado)
☐ Allow deletions (desmarcado)

6. Regras de proteção por equipe e usuário

O GitHub permite criar exceções nas regras de proteção. Na mesma tela de configuração, você pode definir "Allow specified actors to bypass required pull requests". Por exemplo, você pode permitir que administradores ou uma equipe específica de release managers façam push direto em emergências.

Para gerenciar isso de forma mais moderna, o GitHub introduziu os branch rulesets. Diferente das regras tradicionais, os rulesets permitem criar conjuntos de regras que podem ser aplicados a múltiplos repositórios, com bypass controlado por equipes. Exemplo de ruleset:

Ruleset name: Produção Restrita
Target branches: main, production
Rules:
- Require pull request (2 approvals)
- Require status checks
- Block force push
Bypass: Apenas equipe "release-managers"

Isso oferece um controle mais granular e centralizado, especialmente útil em organizações com dezenas de repositórios.

7. Monitoramento e melhores práticas

Após configurar as proteções, é importante monitorar seu uso. O GitHub oferece logs de auditoria (em Settings > Audit log) que registram quando regras são alteradas, quando alguém faz bypass ou quando um PR é mesclado fora das regras.

Ao atualizar regras de proteção, evite mudanças bruscas. Por exemplo, se você vai exigir status checks, primeiro adicione os checks como obrigatórios em uma branch de teste, notifique a equipe e só depois aplique à branch principal. Isso evita que PRs em andamento sejam bloqueados inesperadamente.

Boas práticas resumidas:

  • Para branches de feature ou desenvolvimento (develop, feature/*): proteção mínima — apenas exigir PR e status checks básicos.
  • Para branches de release (release/*, staging): exigir PR com 1 aprovação e code owners.
  • Para branches de produção (main, production): proteção rigorosa — 2 aprovações, code owners, status checks obrigatórios, bloqueio de force push e exclusão.

Lembre-se: a proteção de branches não substitui uma boa cultura de revisão de código. Ela é uma ferramenta para garantir que as regras acordadas pela equipe sejam seguidas, mesmo sob pressão.

Referências