Git básico: commit, branch e merge
1. Visão geral
Git é a ferramenta de gerenciamento de versões que quase todo projeto usa, mas muitos iniciantes apenas memorizam alguns comandos sem entender a essência. Este artigo passa por três conceitos fundamentais: commit (salvar um snapshot), branch (uma ramificação de trabalho independente) e merge (mesclar ramificações). Após ler, você terá confiança para criar uma nova ramificação, fazer commit corretamente, lidar com conflitos ao fazer merge e saber quando usar merge em vez de rebase.
2. Commit – salvar um snapshot
2.1. O que é commit
Cada commit é um “snapshot” completo do estado de todos os arquivos em um ponto no tempo, junto com um ponteiro para o commit pai. Git não armazena diffs, mas snapshots — isso torna branch/merge rápido e eficiente.
# Inicializar repo e fazer o primeiro commit
git init order-service
cd order-service
echo "# Order Service" > README.md
git add README.md
git commit -m "docs: adicionar README para Order Service"
Explicação:
git initcria um novo repositório, gerando o diretório oculto.git.git add README.mdcoloca o arquivo na staging area (área de preparação).git commit -m "..."cria um snapshot com uma mensagem descrevendo a mudança.
Verificar o histórico:
git log --oneline
a1b2c3d docs: adicionar README para Order Service
2.2. Escrever boas mensagens de commit
Um commit deve responder a pergunta “o que essa mudança faz e por quê”. A convenção comum (conventional commits):
feat: adicionar API para criar pedido
fix: corrigir cálculo incorreto do total ao aplicar cupom
refactor: extrair OrderValidator de OrderService
Nota: Evite mensagens de commit vagas como
"update"ou"fix bug". Meses depois, ao olhargit log, você não saberá o que esse commit corrigiu.
2.3. Commit de partes com git add -p
Quando um arquivo tem várias mudanças não relacionadas, não faça commit de tudo de uma vez.
git add -p src/main/java/com/nonladev/OrderService.java
Git perguntará qual “hunk” (seção de mudança) você deseja preparar, permitindo separar em commits menores, fáceis de revisar e reverter se necessário.
3. Branch – trabalhar independentemente em várias ramificações
3.1. Criar e alternar entre branches
Uma branch é apenas um ponteiro leve para um commit específico. Criar uma branch não copia todo o código, apenas cria um novo ponteiro.
# Criar uma nova branch e alternar para ela
git branch feature/add-payment
git checkout feature/add-payment
# Ou combinar os dois comandos acima em um (Git ≥ 2.23)
git switch -c feature/add-payment
Explicação:
git branch <nome>cria uma branch, mas você continua na branch atual.git checkout <nome>ougit switch <nome>moveHEADpara essa branch.-cemgit switché um atalho para criar e alternar ao mesmo tempo.
3.2. Listar branches
git branch -v
* feature/add-payment d4e5f6a adicionar esqueleto do PaymentService
main a1b2c3d docs: adicionar README para Order Service
O asterisco * indica a branch atual (onde HEAD está).
3.3. Nomear branches com convenção
Nomear branches claramente ajuda todo o time a saber o que a ramificação faz:
feature/add-payment # adicionar nova funcionalidade
fix/order-total-wrong # corrigir erro
refactor/extract-validator
hotfix/prod-null-pointer
3.4. Deletar branch após conclusão
# Deletar branch local que foi mesclada
git branch -d feature/add-payment
# Deletar branch não mesclada (forçar, cuidado com perda de commits)
git branch -D feature/add-payment
-d (minúscula) é mais seguro porque Git avisará se a branch ainda não foi mesclada.
4. Merge – mesclar ramificações
4.1. Merge de avanço rápido
Se main não tem nenhum novo commit desde que você criou a branch, Git apenas move o ponteiro main para o último commit da branch feature — chamado fast-forward.
git switch main
git merge feature/add-payment
Updating a1b2c3d..d4e5f6a
Fast-forward
PaymentService.java | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
Nenhum novo commit de merge é criado, o histórico permanece linear.
4.2. Merge commit (merge de 3 vias)
Se ambas as branches têm commits próprios desde o ponto de divergência, Git cria um merge commit com dois pais, mesclando o conteúdo de ambas.
git switch main
git commit -am "fix: corrigir validação de quantidade de item" # main tem novo commit
git switch feature/add-payment
git switch main
git merge feature/add-payment
Merge made by the 'recursive' strategy.
PaymentService.java | 20 ++++++++++++++++++++
1 file changed, 20 insertions(+)
Git cria automaticamente um commit de merge com a mensagem padrão Merge branch 'feature/add-payment'.
4.3. Resolver conflitos ao fazer merge
Conflitos ocorrem quando duas branches modificam a mesma região de código. Por exemplo, a classe OrderService:
// Em main
public class OrderService {
public BigDecimal calculateTotal(Order order) {
return order.getSubtotal().multiply(BigDecimal.valueOf(1.1)); // adicionar imposto de 10%
}
}
// Em feature/add-payment
public class OrderService {
public BigDecimal calculateTotal(Order order) {
return order.getSubtotal().subtract(order.getDiscount()); // subtrair desconto
}
}
Ao fazer merge, Git não consegue decidir qual linha manter, e o arquivo mostrará marcadores:
public class OrderService {
public BigDecimal calculateTotal(Order order) {
<<<<<<< HEAD
return order.getSubtotal().multiply(BigDecimal.valueOf(1.1));
=======
return order.getSubtotal().subtract(order.getDiscount());
>>>>>>> feature/add-payment
}
}
Você precisa editar manualmente para combinar a lógica corretamente (por exemplo: subtrair o desconto primeiro, depois adicionar o imposto), deletar os marcadores <<<<<<<, =======, >>>>>>>, depois:
git add OrderService.java
git commit
Nota: Ao fazer commit após resolver um conflito, você não precisa de
-m, Git abrirá um editor com uma mensagem padrão deixando claro que é um merge commit — manter essa mensagem é suficiente, a menos que queira adicionar uma observação.
4.4. Merge vs Rebase
| Critério | merge |
rebase |
|---|---|---|
| Histórico | Mantém, tem commit de merge | Reescreve histórico, branch linear |
| Segurança | Não modifica commits antigos | Modifica commits antigos (muda hash) |
| Usar quando | Branch compartilhada pública (main, develop) |
Branch pessoal, quer histórico limpo antes de criar PR |
# Rebase da branch feature sobre main mais recente
git switch feature/add-payment
git rebase main
Nota: Não faça
rebaseem uma branch que já foi pushed e outras pessoas estão puxando — você vai desalinhar o histórico deles, causando conflitos em massa quando puxarem novamente.
5. Testar um cenário de merge com JUnit
Embora Git não seja código Java, você pode escrever testes para confirmar que a lógica de negócio após fazer merge de duas branches não quebrou — é por isso que CI sempre executa testes no merge commit. Exemplo de OrderService após resolver o conflito na seção 4.3:
public class OrderService {
public BigDecimal calculateTotal(Order order) {
BigDecimal afterDiscount = order.getSubtotal().subtract(order.getDiscount());
return afterDiscount.multiply(BigDecimal.valueOf(1.1));
}
}
class OrderServiceTest {
private final OrderService orderService = new OrderService();
@Test
void shouldApplyDiscountThenTax() {
Order order = new Order(
BigDecimal.valueOf(100), // subtotal
BigDecimal.valueOf(10) // desconto
);
BigDecimal total = orderService.calculateTotal(order);
assertThat(total).isEqualByComparingTo(BigDecimal.valueOf(99.0));
}
}
Explicação: subtotal 100 menos desconto 10 restam 90, multiplicado por imposto de 10% resulta em 99. Este teste é exatamente a “rede de segurança” que garante que mesclar duas lógicas (imposto e desconto) não se cancelem.
✓ shouldApplyDiscountThenTax()
6. Fluxo de trabalho recomendado para equipe pequena
- Sempre crie uma nova branch a partir de
mainpara cada tarefa:git switch -c feature/xxx. - Commits pequenos, frequentes, mensagens claras.
- Antes de criar um Pull Request, atualize a branch com o
mainmais recente:git switch feature/add-payment git fetch origin git merge origin/main - Resolva conflitos (se houver) localmente, execute os testes novamente.
- Faça push e crie um PR, deixe CI executar os testes no merge commit antes de mesclar em
main.
Nota: Não faça commit diretamente em
mainem uma equipe com várias pessoas — sempre passe por branch + PR para ter revisão e verificação de CI primeiro.
7. Erros comuns
- Esquecer
git addantes do commit: Git reportanothing to commit, working tree cleanmesmo que você tenha modificado o arquivo — porque o arquivo ainda não foi preparado (staged). - Mesclar a branch errada: sempre use
git statusegit branchpara verificar onde você está antes de fazermerge. - Marcadores de conflito deixados no código: esquecer de deletar
<<<<<<<fará o código não compilar — sempre compile/teste imediatamente após resolver um conflito. - Force push em branch compartilhada:
git push --forceapós rebase de uma branch compartilhada deletará o histórico de seus colegas. Use apenas--force-with-leasee apenas em branches pessoais.
8. Conclusão
Commit, branch e merge são as três operações que você usa diariamente com Git. Dominar commit deixa o histórico do código claro, branch permite trabalho paralelo sem se afetar, e entender merge (junto com como resolver conflitos) constrói confiança ao integrar código de várias pessoas. Pratique commits pequenos, nomeie branches com convenção e sempre execute testes antes de mesclar em main.