Branches no Git: git branch para criar, trocar e excluir branches
Uma branch no Git é um ponteiro leve para um commit, e o HEAD indica em qual branch você está agora. O git branch lista, cria, renomeia e exclui branches, e o git switch troca entre elas; git switch -c nome cria a branch e já muda para ela.
O que é uma branch no Git
Uma branch no Git não é uma cópia do projeto, e sim um arquivinho com o hash de um commit. Criar uma branch leva frações de segundo e quase não ocupa espaço, porque o Git não duplica nada: todas as branches apontam para os mesmos objetos no banco do repositório. Quando você faz um commit, o ponteiro da branch atual simplesmente avança para o novo commit.
Isso muda a forma de encarar branches. Não há por que ter medo nem economizar: uma branch separada para cada tarefa, correção ou experimento é prática normal. Se o experimento não deu certo, a branch é excluída e o histórico principal continua limpo.
Dá para ver com os próprios olhos que uma branch é um arquivo:
$ cat .git/refs/heads/main
8b7d4e2a9f1c0d3e5b6a7c8d9e0f1a2b3c4d5e6f
(Em repositórios grandes, parte das referências fica compactada em .git/packed-refs, então o arquivo pode não existir — a essência não muda.)
HEAD no Git: onde você está agora
HEAD é o ponteiro para aquilo que está «extraído» no seu diretório de trabalho neste momento. Normalmente o HEAD não aponta para um commit, e sim para uma branch:
$ cat .git/HEAD
ref: refs/heads/main
A cadeia é esta: HEAD → main → commit. O novo commit terá como pai o commit para o qual o HEAD aponta, e depois o Git avança a branch indicada pelo HEAD. É por isso que os commits «caem» na branch atual.
Se você muda direto para um commit ou uma tag (git switch --detach v1.0 ou git checkout 3f2a1c9), o HEAD passa a apontar diretamente para o commit. Esse estado se chama detached HEAD. Olhar o código nele é seguro, mas os commits novos não ficam presos a nenhuma branch e se perdem facilmente depois de uma troca. Se começou a alterar algo, crie uma branch ali mesmo: git switch -c fix-from-old-version.
Em expressões, o HEAD é um ótimo ponto de referência: HEAD~1 é o commit anterior, HEAD~3 fica três commits atrás e HEAD^2 é o segundo pai de um commit de merge.
Como listar branches: git branch
git branch # branches locais; a atual vem marcada com *
git branch -v # mais o último commit de cada uma
git branch -vv # mais o upstream e quanto está à frente/atrás
git branch -r # branches remotas (origin/...)
git branch -a # todas as branches
git branch --show-current # só o nome da branch atual
Exemplo de saída do git branch -vv:
feature/login 4c1e2d7 [origin/feature/login: ahead 2] Formulário de login
* main 8b7d4e2 [origin/main] Atualizar README
old-spike 1a9b3c0 Experimento com cache
Dá para ver que feature/login tem dois commits não enviados, que main está igual ao servidor e que old-spike nem tem par no servidor.
Para filtrar branches, use git branch --merged (já mescladas na atual — candidatas à exclusão), git branch --no-merged (ainda não mescladas) e git branch --list 'feature/*' (por padrão de nome).
Como criar uma branch
Há dois caminhos. O git branch cria a branch, mas deixa você na atual:
git branch feature/login # a partir do commit atual
git branch hotfix v1.2.0 # a partir de uma tag
git branch review 3f2a1c9 # a partir de um commit específico
Na maioria das vezes você quer criar a branch e já ir para ela. Para isso existe o git switch -c (surgiu no Git 2.23) ou o equivalente antigo git checkout -b:
git switch -c feature/login
git switch -c hotfix origin/main # nova branch a partir do estado mais recente do servidor
Um bom hábito é atualizar a base antes de criar a branch da tarefa: git fetch e depois git switch -c feature/x origin/main. Assim a branch começa do código atual, e não do seu main local que não é atualizado há tempos.
Como nomear branches
Convenções consolidadas nas equipes: um prefixo pelo tipo de trabalho e uma descrição curta com hífens — feature/user-avatar, fix/login-timeout, chore/update-deps, às vezes com o número da tarefa: feature/SHOP-142-cart. Não são permitidos espaços, ~ ^ : ? * [, dois pontos seguidos nem terminar com .lock.
Como trocar de branch: git switch
git switch main # ir para uma branch existente
git switch - # voltar para a branch anterior
git switch feature/login # se não existe localmente, mas existe origin/feature/login,
# o Git cria a local e a vincula à remota
Ao trocar de branch, o Git substitui os arquivos do diretório de trabalho pela versão da branch de destino. Alterações não commitadas vão junto com você, desde que não conflitem com a branch de destino. Se conflitarem, o Git se recusa:
error: Your local changes to the following files would be overwritten by checkout:
app.js
Please commit your changes or stash them before you switch branches.
Soluções: fazer commit, guardar com git stash (e recuperar depois com git stash pop) ou levar as alterações conscientemente, tentando um merge: git switch -m main. A flag --discard-changes joga fora as alterações — use só se tiver certeza de que não precisa delas.
Por que git switch e não checkout? O checkout troca de branch e também sobrescreve arquivos, e por isso é fácil errar. O switch faz uma coisa só — lida com branches —, então é mais seguro. A comparação detalhada entre checkout, switch e restore está em um artigo à parte.
Como renomear uma branch
git branch -m new-name # renomear a atual
git branch -m old-name new-name # renomear qualquer uma
git branch -M main # o mesmo, sobrescrevendo uma branch existente
Se a branch já estava no servidor, a renomeação é só local. Envie a nova e apague a antiga:
git push -u origin new-name
git push origin --delete old-name
Como excluir uma branch
git branch -d feature/login # exclui só se a branch já foi mesclada
git branch -D old-spike # exclui à força
git push origin --delete feature/login # excluir no servidor
O -d protege contra perda de trabalho: se a branch tem commits que não estão na branch atual (ou no upstream dela), o Git se recusa com a mensagem «The branch 'x' is not fully merged». O -D exclui sem perguntar. A branch atual não pode ser excluída — mude para outra antes.
Apagou o que não devia? Os commits não somem na hora. Ache o hash do último commit da branch no git reflog e recrie-a: git branch old-spike 1a9b3c0.
Referências desatualizadas de branches remotas que já não existem no servidor são limpas com git fetch --prune.
Vinculando a branch local à remota
Uma branch local pode ter um upstream — a branch remota com a qual ela é comparada e sincronizada. Ele é necessário para que git push e git pull funcionem sem argumentos e para que o git status mostre «ahead/behind».
git push -u origin feature/login # no primeiro envio
git branch --set-upstream-to=origin/main main # para uma branch existente
git branch --unset-upstream # remover o vínculo
Merge de branches em poucas palavras
Branches são criadas para depois serem unidas. Quando o trabalho estiver pronto, mude para a branch de destino e faça o merge da sua:
git switch main
git merge feature/login
Se o main não avançou desde que a branch foi criada, o Git faz um fast-forward: só move o ponteiro do main para o último commit da branch, sem commit de merge. Se as duas branches receberam commits novos, acontece um merge de três vias: o Git encontra o ancestral comum, compara os dois lados e cria um commit de merge com dois pais. Em equipes, o merge normalmente acontece via pull request no servidor, e localmente só se puxa o main atualizado.
Cola de branches
| Tarefa | Comando |
|---|---|
| Listar branches | git branch -vv |
| Criar branch | git branch nome |
| Criar e mudar para ela | git switch -c nome |
| Trocar de branch | git switch nome |
| Voltar para a anterior | git switch - |
| Renomear | git branch -m antigo novo |
| Excluir uma já mesclada | git branch -d nome |
| Excluir à força | git branch -D nome |
| Excluir no servidor | git push origin --delete nome |
| Branches que podem ser excluídas | git branch --merged |
| Recuperar uma excluída | git reflog, depois git branch nome hash |
Erros comuns de iniciantes
- Trabalhar direto no main. Se os commits já foram feitos mas não enviados, crie uma branch no ponto atual (
git branch feature/x) e depois volte omainao estado do servidor:git reset --hard origin/main(confira antes se está tudo commitado). - Branch criada a partir de um main desatualizado. Rode
git fetchprimeiro e crie a branch a partir deorigin/main. - Commits em detached HEAD. Crie uma branch antes de trocar; se já trocou, procure os commits no
git reflog. - Branches de vida longa. Quanto mais tempo a branch vive separada, mais doloroso é o merge. Puxe o
maincom frequência e integre o trabalho em porções pequenas.
Branches no trabalho em equipe
Os processos variam de equipe para equipe, mas quase sempre aparece um destes dois esquemas. No GitHub Flow há uma única branch de vida longa, main, sempre pronta para deploy, e feature branches curtas que entram via pull request depois do review e das verificações de CI. No Git Flow entram também develop, branches de release e de hotfix; o esquema é mais pesado e serve a produtos com releases versionados e pouco frequentes.
Seja qual for o esquema, valem regras comuns: uma branch, uma tarefa; a branch vive dias, não meses; antes do pull request ela é atualizada com o main mais recente; depois do merge ela é excluída tanto localmente quanto no servidor. A branch principal é protegida nas configurações do repositório: push direto e force push nela são proibidos, e o merge só acontece via review.
Como ver o histórico das branches
O jeito mais fácil de entender como as branches se relacionam é pelo grafo: git log --oneline --graph --all desenha todas as branches e seus pontos de divergência direto no terminal. Para ver os commits que estão na branch mas ainda não chegaram ao main, use git log main..feature/login; para a diferença nos arquivos, git diff main...feature/login (os três pontos comparam com o ancestral comum, ou seja, mostram só as alterações da própria branch).
Resumo
Uma branch no Git é um ponteiro barato para um commit, e o HEAD é o ponteiro para a branch atual. O git branch gerencia as branches (listar, criar, renomear, excluir), o git switch troca entre elas e o git switch -c faz as duas coisas de uma vez. Branches, HEAD, fast-forward e merge de três vias são trabalhados com exemplos reais no curso de Git.
Perguntas frequentes
Quantas branches posso criar no Git?
Praticamente quantas quiser: cada branch é uma referência de algumas dezenas de bytes, então não há limite de espaço.
Os commits são apagados junto com a branch?
Não na hora. Commits que não são mais referenciados por nada ficam guardados por um tempo e acessíveis pelo git reflog até o coletor de lixo removê-los (por padrão, não antes de 30 dias para entradas do reflog inalcançáveis).
Como saber de qual branch a atual foi criada?
O Git não guarda essa informação: a branch só lembra do seu commit. O ancestral comum com o main pode ser encontrado com git merge-base HEAD main.
Qual a diferença entre branch e tag?
A branch avança a cada novo commit, enquanto a tag fica presa para sempre a um commit e é usada para marcar releases.
Por que main e não master?
É só o nome padrão da branch. Muitos serviços passaram a usar main; para definir o nome nos novos repositórios, use git config --global init.defaultBranch main.
Este tema é abordado em profundidade, com prática, no curso “Git do zero ao desenvolvedor confiante”.
Ir para o curso