Tutorial

Branches no Git: git branch para criar, trocar e excluir branches

Atualizado: · Skillaria.Top

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

TarefaComando
Listar branchesgit branch -vv
Criar branchgit branch nome
Criar e mudar para elagit switch -c nome
Trocar de branchgit switch nome
Voltar para a anteriorgit switch -
Renomeargit branch -m antigo novo
Excluir uma já mescladagit branch -d nome
Excluir à forçagit branch -D nome
Excluir no servidorgit push origin --delete nome
Branches que podem ser excluídasgit branch --merged
Recuperar uma excluídagit 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 o main ao estado do servidor: git reset --hard origin/main (confira antes se está tudo commitado).
  • Branch criada a partir de um main desatualizado. Rode git fetch primeiro e crie a branch a partir de origin/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 main com 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.

Aprenda este tema em vídeo

Este tema é abordado em profundidade, com prática, no curso “Git do zero ao desenvolvedor confiante”.

Ir para o curso