Capítulo 4 de 5

Tutorial Git: trabalhar em equipa com branches e merge

verificado a 7 Setembro 2026 · 10 min

Resposta rápida

Cria uma branch com git switch -c nom, trabalha, e depois funde-a com git merge a partir da branch de destino. Em caso de conflito, o Git insere marcadores no ficheiro: escreve o conteúdo certo, apaga os marcadores e faz git add e git commit. O git merge --abort anula tudo a qualquer momento.

Uma branch é uma linha de desenvolvimento paralela. Permite-te trabalhar numa funcionalidade sem tocar na versão estável, e ao teu colega fazer o mesmo do lado dele. Este capítulo cobre o ciclo completo: criar uma branch, fundi-la, resolver um conflito à mão e escolher entre merge e rebase.

git switch em vez de git checkout

Historicamente, o git checkout servia para tudo: mudar de branch, criar uma, restaurar um ficheiro, colocar-te num commit preciso. Esta acumulação de papéis é a primeira fonte de confusão para quem começa, e uma fonte de acidentes para os outros.

O Git 2.23, lançado em agosto de 2019, dividiu o comando em dois: git switch para te deslocares entre branches, git restore para anular alterações. Saíram marcados como experimentais, já não o são na documentação oficial. Este capítulo usa-os e dá sempre o equivalente em checkout, que ainda vais encontrar durante muito tempo nos tutoriais e no Stack Overflow.

Intenção Comando moderno Forma antiga
Mudar de branch git switch nom git checkout nom
Criar uma branch e passar para ela git switch -c nom git checkout -b nom
Voltar à branch anterior git switch - git checkout -
Anular a alteração de um ficheiro git restore fichier git checkout -- fichier
Tirar um ficheiro do índice git restore --staged fichier git reset HEAD fichier

Criar uma branch e trabalhar nela

bash
git switch -c feature/panier
Sortie réelle · git switch -c
Switched to a new branch 'feature/panier'

A branch parte do commit onde estavas. Podes agora modificar, adicionar e fazer commit normalmente: nada disso vai aparecer na main enquanto não a fundires.

Quanto aos nomes das branches, o Git não impõe qualquer regra, mas os prefixos feature/, fix/ e hotfix/ são uma convenção bem difundida e as interfaces dos alojamentos agrupam-nas visualmente.

Para veres em que ponto estás:

bash
git branch              # as branches locais
git branch -vv          # com o último commit e a branch remota seguida
git branch -a           # locais e remotas
git switch -            # voltar à branch anterior

Para publicares a branch e a tornares visível para a equipa:

bash
git push -u origin feature/panier

Trazer a branch de um colega

No sentido inverso, o git fetch atualiza o que sabes do servidor sem alterar nada nas tuas branches:

bash
git fetch origin feature/collegue   # uma branch específica
git fetch --all                     # todos os repositórios remotos
git branch -r                       # o que já conheces do servidor
Sortie réelle · git branch -r après un fetch
  origin/HEAD -> origin/main
  origin/feature/collegue
  origin/main

Só falta passar para ela. O Git cria automaticamente a branch local e liga-a à do servidor:

bash
git switch feature/collegue
Sortie réelle · git switch sur une branche distante
branch 'feature/collegue' set up to track 'origin/feature/collegue'.
Switched to a new branch 'feature/collegue'

Quando o Git recusa mudar de branch

É um dos primeiros erros que vais encontrar:

Sortie réelle · git switch avec des modifications non committées
error: Your local changes to the following files would be overwritten by checkout:
	index.html
Please commit your changes or stash them before you switch branches.
Aborting

O Git protege o teu trabalho: o ficheiro que modificaste não tem o mesmo conteúdo na outra branch, e mudar de branch iria sobrescrevê-lo. Três soluções, por ordem de preferência.

Fazer commit, se o trabalho estiver coerente. É quase sempre a resposta certa, um commit imperfeito numa branch de trabalho não custa nada e corrige-se mais tarde com os comandos de anulação vistos no capítulo anterior.

Pôr de parte, se o trabalho estiver a meio:

bash
git stash          # põe as alterações de parte
git switch main    # …fazes o que tinhas a fazer…
git switch -
git stash pop      # traz de volta as alterações
Sortie réelle · git stash
Saved working directory and index state WIP on main: 6d495d9 Page d accueil

Deitar fora, com git restore ., se as alterações não valiam nada. Sem volta atrás.

Fundir uma branch

Assim que a funcionalidade estiver terminada, passa para a branch de destino e funde:

bash
git switch main
git merge feature/panier

Quando as duas branches mexeram em ficheiros diferentes, o Git funde sozinho e não tem nada a perguntar-te. O caso interessante é o outro.

Resolver um conflito

Eis a situação reproduzida para este capítulo. Na feature/panier, a segunda linha do index.html foi substituída por uma mensagem de carrinho vazio. Na main, a primeira linha foi alterada para acrescentar o nome da marca. As duas branches mexeram no mesmo ficheiro.

Sortie réelle · git merge feature/panier
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
Automatic merge failed; fix conflicts and then commit the result.

Nada está partido. O Git fundiu o que conseguiu e deixa-te decidir o resto. Primeira coisa a fazer, perguntar em que ponto estás:

bash
git status
Sortie réelle · git status pendant un conflit
On branch main
Your branch is ahead of 'origin/main' by 1 commit.
  (use "git push" to publish your local commits)

You have unmerged paths.
  (fix conflicts and run "git commit")
  (use "git merge --abort" to abort the merge)

Unmerged paths:
  (use "git add <file>..." to mark resolution)
	both modified:   index.html

no changes added to commit (use "git add" and/or "git commit -a")

Para obteres apenas a lista dos ficheiros a tratar:

bash
git diff --name-only --diff-filter=U

Abre o ficheiro. O Git inseriu-lhe marcadores:

index.html pendant le conflit
<<<<<<< HEAD
<h1>Boutique Gekkode</h1>
<p>Bienvenue sur la boutique.</p>
=======
<h1>Boutique</h1>
<p>Votre panier est vide.</p>
>>>>>>> feature/panier

A leitura é mecânica. Entre <<<<<<< HEAD e ======= está a versão da branch onde estás, aqui a main. Entre ======= e >>>>>>> está a versão da branch que estás a fundir.

Cabe-te a ti escrever o resultado correto. Não é forçosamente uma ou outra: aqui, as duas alterações estão certas e devem coexistir.

index.html après résolution
<h1>Boutique Gekkode</h1>
<p>Votre panier est vide.</p>

Apaga os três marcadores, não podem ficar no ficheiro. Depois avisa o Git de que está resolvido e termina a fusão:

bash
git add index.html
git commit -m "Fusionne feature/panier dans main"
Sortie réelle · git log --oneline --graph après la fusion
*   0899b0c Fusionne feature/panier dans main
|  
| * aacf4c0 Panier : message quand le panier est vide
* | 11ff16b Ajoute le nom de la marque au titre
|/  
* 6d495d9 Page d accueil

O commit de fusão tem dois pais, o que o grafo torna visível.

Anular tudo e recomeçar do zero

Se o conflito te ultrapassar, não és obrigado a nada:

bash
git merge --abort

O repositório volta exatamente ao estado anterior ao comando merge. Nada se perde, podes recomeçar mais tarde ou falar com o autor da outra branch.

merge ou rebase

Ambos integram o trabalho de uma branch noutra, mas não da mesma maneira.

git merge cria um commit de fusão que liga os dois históricos. O histórico guarda o rasto exato do que aconteceu, incluindo o facto de terem existido duas branches em paralelo. O grafo é fiel, mas ramifica-se.

git rebase volta a aplicar os teus commits por cima da branch de destino, como se tivesses trabalhado a partir da última versão dela. O histórico continua uma linha reta, mais fácil de ler, mas foi reescrito: os teus commits mudam de identificador.

bash
git switch feature/panier
git rebase main

Um rebase pode encontrar os mesmos conflitos que uma fusão, commit a commit. A resolução é idêntica, só muda o comando para continuar:

Sortie réelle · conflit pendant un rebase
Auto-merging index.html
CONFLICT (content): Merge conflict in index.html
error: could not apply 4937109... Promo
hint: Resolve all conflicts manually, mark them as resolved with
hint: "git add/rm <conflicted_files>", then run "git rebase --continue".
hint: You can instead skip this commit: run "git rebase --skip".
hint: To abort and get back to the state before "git rebase", run "git rebase --abort".
hint: Disable this message with "git config set advice.mergeConflict false"
Could not apply 4937109... Promo
bash
git add index.html
git rebase --continue
# ou, para anular tudo
git rebase --abort

A regra de ouro cabe numa frase: nunca faças rebase de uma branch que outras pessoas já trouxeram. Reescrever um histórico partilhado obriga os teus colegas a reparar o deles à mão. Já na tua própria branch de trabalho, antes de a propores, o rebase é perfeitamente legítimo e dá um histórico bem mais legível.

O caso do dia a dia: alguém fez push antes de ti

Queres fazer push e o Git recusa:

Sortie réelle · git push refusé
To /root/o.git
 ! [rejected]        main -> main (fetch first)
error: failed to push some refs to '/root/o.git'
hint: Updates were rejected because the remote contains work that you do not

O servidor tem commits que tu não tens. Tens de os integrar primeiro. E aí, num repositório novo, o Git faz-te uma pergunta em vez de agir:

Sortie réelle · git pull sans stratégie configurée
hint: You have divergent branches and need to specify how to reconcile them.
hint: You can do so by running one of the following commands sometime before
hint: your next pull:
hint:
hint:   git config pull.rebase false  # merge
hint:   git config pull.rebase true   # rebase
hint:   git config pull.ff only       # fast-forward only
hint:

O Git recusa-se a escolher por ti desde a versão 2.27. Responde de uma vez por todas, como proposto no capítulo de instalação:

bash
git config --global pull.rebase true

O desenrolar passa então a ser este:

bash
git pull --rebase
git push
Sortie réelle · git pull --rebase puis git log
From /root/o
   622a60b..38b7dc5  main       -> origin/main
Rebasing (1/1)Successfully rebased and updated refs/heads/main.

* 5b45117 Ajoute app.js
* 38b7dc5 Ajoute la doc
* 622a60b Depart

O teu commit foi recolocado por cima do do colega e o histórico manteve-se linear, sem commit de fusão parasita. É a configuração a recomendar a uma equipa que está a começar.

Um aviso para terminar: nunca tentes desbloquear um push recusado com git push --force. Esse comando apaga o trabalho que está no servidor. Se tiveres mesmo de forçar, depois de um rebase da tua própria branch, usa o git push --force-with-lease, que se recusa a apagar commits que ainda não tinhas visto.

Fazer limpeza

Um ramo fundido já não tem razão de existir. Se foi publicado com -u, envie primeiro os seus últimos commits: o Git recusa-se a apagar um ramo local adiantado em relação ao ramo remoto, mesmo fundido em main.

bash
git push origin feature/panier
git branch -d feature/panier
Sortie réelle · suppression d'une branche fusionnée
Deleted branch feature/panier (was bc2203a).

Sem esse push prévio, a mensagem é explícita:

Sortie réelle · branche locale en avance sur origin
warning: not deleting branch 'feature/panier' that is not yet merged to
         'refs/remotes/origin/feature/panier', even though it is merged to HEAD
error: the branch 'feature/panier' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/panier'
hint: Disable this message with "git config set advice.forceDeleteBranch false"

Se a branch não tiver sido fundida, o Git trava-te, o que é uma rede de segurança útil:

Sortie réelle · suppression d'une branche non fusionnée
error: the branch 'feature/promo' is not fully merged
hint: If you are sure you want to delete it, run 'git branch -D feature/promo'
hint: Disable this message with "git config set advice.forceDeleteBranch false"

Para apagares também a branch no servidor e limpares as referências locais que ficaram obsoletas:

bash
git push origin --delete feature/panier
git fetch --prune

O git fetch traz o estado do servidor sem fundir nada nas tuas branches, ao contrário do git pull. A opção --prune aproveita para apagar as branches remotas que já não existem, aquelas que os teus colegas fundiram e eliminaram.

Já sabes colaborar. O último capítulo trata da organização: que modelo de branches adotar consoante a tua equipa.

Erros frequentes

Your local changes would be overwritten by checkout Faz commit das tuas alterações, ou põe-nas de parte com git stash, antes de mudares de branch.
You have divergent branches Desde o Git 2.27, o git pull recusa-se a escolher sozinho entre fusão e rebase. Resolve a questão com git config --global pull.rebase true.
! [rejected] non-fast-forward O servidor tem commits que tu não tens. Integra-os com git pull --rebase. Nunca uses git push --force para passar por cima: apaga o trabalho dos outros.
Marcadores de conflito esquecidos As linhas começadas por <<<<<<<, ======= e >>>>>>> têm de desaparecer do ficheiro antes do git add.
Rebase de uma branch partilhada Reescrever um histórico que outros já trouxeram obriga-os a reparar o deles à mão. Só faças rebase das tuas próprias branches não publicadas.
Newsletter

Os novos testes, tutoriais e projetos, por e-mail.

Testes reproduzíveis, código versionado, resultados datados. Nunca spam.