Pular para conteúdo

Git

TLDR: controle de versão distribuído; toda mudança vira commit rastreável; Conventional Commits padroniza a mensagem, proteção de branch impede push sem revisão.

Termo Vá pra
Padronizar mensagem de commit Conventional Commits
Impedir push sem revisão Proteção de branch
Centralizado vs. distribuído, branching, mono/polyrepo Pra ir além

Git é o que torna um repositório uma fonte da verdade de verdade: toda mudança passa por um commit, com autor, data e mensagem, antes de existir. Um servidor administrado por Git puro não tem edição direta que não deixe rastro em algum lugar, diferente de editar um arquivo de configuração direto na máquina.

Conventional Commits

Um padrão comum é seguir tipo(escopo): assunto, com tipos como feat (mudança nova), fix (correção de bug) e docs (só documentação), assunto curto (frequentemente até 50 caracteres), modo imperativo ("adicionar", não "adicionado"). Isso existe pra manter o git log legível como uma lista de decisões, não uma narração passo a passo do processo de chegar lá. A especificação formal está em conventionalcommits.org.

flowchart LR
    A["feat(auth): adicionar login via OAuth"] --> B[tipo: feat]
    A --> C[escopo: auth]
    A --> D["assunto: adicionar login via OAuth"]
    B --> E[gera changelog automático]
    C --> F[filtra histórico por área]
    D --> G[modo imperativo, até 50 caracteres]

Proteção de branch

GitHub (e a maioria das plataformas de hosting Git) permite exigir revisão antes de qualquer push chegar numa branch protegida, tipicamente main. Sem isso configurado, não existe trava técnica nenhuma impedindo um push direto sem revisão, e a disciplina de commits pequenos e mensagens claras passa a ser a única coisa sustentando a qualidade do histórico.

sequenceDiagram
    participant Dev as quem desenvolve
    participant Branch as branch protegida (main)
    participant Rev as revisor

    Dev->>Branch: push direto
    Branch--xDev: rejeitado, sem revisão
    Dev->>Rev: abre PR a partir de uma branch própria
    Rev->>Rev: revisa o diff
    Rev-->>Dev: aprova
    Dev->>Branch: merge do PR aprovado
    Branch->>Branch: histórico atualizado, com rastro

Pra ir além

Git é uma implementação específica de um controle de versão distribuído, uma categoria mais ampla que também inclui Mercurial (a alternativa mais próxima, perdeu adoção pra Git ao longo dos últimos quinze anos; o próprio Firefox usou Mercurial como fonte da verdade por quase duas décadas, até migrar de vez pro Git em 2025) e antecessores centralizados como Subversion e Perforce, onde só existe um repositório central e ninguém tem histórico completo localmente. A diferença não é só técnica: um controle centralizado exige rede pra praticamente qualquer operação (inclusive ver um log antigo), enquanto num distribuído como o Git quase tudo é local, e sincronizar com um remoto é um passo separado, deliberado. Perforce ainda domina em estúdios de jogos e outros times que versionam arquivo binário grande (textura, asset de áudio), onde o modelo distribuído do Git degrada mal.

flowchart TB
    subgraph Centralizado["Centralizado (Subversion, Perforce)"]
        S[servidor central] <--> C1[cliente 1, sem histórico completo]
        S <--> C2[cliente 2, sem histórico completo]
    end
    subgraph Distribuido["Distribuído (Git, Mercurial)"]
        R1[repositório 1, histórico completo] <-->|push/pull, passo deliberado| R2[repositório 2, histórico completo]
    end

Dentro do próprio Git, existem várias abordagens de branching, cada uma compensando um custo diferente: trunk-based development (só uma branch de longa duração, geralmente com feature flags pra código incompleto que ainda não deve ir pra produção), Git Flow (branches dedicadas pra release/hotfix/develop, mais burocrático, mais comum em software com ciclos de release formais e versionamento semântico rígido), e GitHub Flow (branch por feature, PR, merge, o que a maioria dos times de produto usa hoje no dia a dia).

gitGraph
    commit id: "main"
    branch feature/login
    checkout feature/login
    commit id: "adicionar OAuth"
    commit id: "adicionar testes"
    checkout main
    merge feature/login id: "PR revisado e mergeado"
    commit id: "main sempre deployável"

Dois conceitos que aparecem em repositórios maiores ou mais maduros: monorepo vs. polyrepo (um repositório por serviço, mais comum em organizações com times independentes; monorepo é a antítese, tudo num repositório só, prática de empresas como Google e Meta pra manter dependência interna sempre em sincronia, ao custo de tooling de build muito mais elaborado) e assinatura de commit (GPG ou SSH signing, pra provar quem de fato autorou cada commit).

flowchart LR
    subgraph Polyrepo
        RA[repositório serviço A]
        RB[repositório serviço B]
        RC[repositório serviço C]
    end
    subgraph Monorepo
        M[repositório único] --- MA[serviço A]
        M --- MB[serviço B]
        M --- MC[serviço C]
    end

Cheatsheet

Comando O que faz
git commit -m "feat(escopo): assunto" Commit no padrão Conventional Commits
git log --oneline Histórico compacto, uma linha por commit
git checkout -b feature/x Cria e muda pra uma branch nova
git push -u origin feature/x Publica a branch e associa o remoto
git commit -S Assina o commit com GPG
git commit --gpg-sign=ssh (ou -S com chave SSH configurada) Assina o commit com SSH signing

Onde aprofundar: a documentação oficial em git-scm.com/doc inclui o livro Pro Git na íntegra, de graça, e é o material de referência mais citado pra Git especificamente.