← tópicos

Específicos · Engenharia de Software

Git: estados, merge × rebase, revert × reset, fetch × pull, Git Flow × trunk-based

Todo comando do Git se resolve por duas perguntas — que área ele move (diretório de trabalho, índice, repositório local, repositório remoto) e em que sentido —, e o item errado típico descreve…

Altíssima26 itens no tópico

A ideia que organiza o assunto

O Git não guarda diferenças entre versões: guarda fotografias completas do projeto, cada uma identificada pelo hash do seu conteúdo, e encadeadas pelo ponteiro que cada commit mantém para o anterior. Dessa decisão nasce tudo o mais — branch é barata porque é só um ponteiro, o histórico é imutável porque mudar um commit muda o hash, e trabalhar sem rede é possível porque o repositório inteiro está no seu disco.

O modelo que resolve os itens tem quatro lugares onde um arquivo pode estar:

lugaro que é
diretório de trabalhoos arquivos como você os vê e edita
índice (staging area)o que já foi marcado para entrar no próximo commit
repositório localo grafo de commits dentro de .git, com HEAD apontando para um deles
repositório remotoa cópia compartilhada, em outro servidor

Cada comando é uma seta entre esses lugares, e é essa seta que o item testa: add leva do diretório de trabalho para o índice; commit leva do índice para o repositório local; push leva do repositório local para o remoto; fetch traz do remoto para o local sem tocar no seu trabalho; merge integra o que foi trazido; pull é fetch seguido de merge; clone cria o repositório local inteiro a partir de um remoto. Uma sequência que termina em commit não chegou ao servidor, por mais completa que pareça.

O método de prova é mecânico: leia o que o item diz que acontece, decida qual comando faz aquilo, e só então olhe o nome escrito. A CEBRASPE descreve a ação de um comando com precisão e assina outro — “o comando git checkout é capaz de copiar completamente um repositório para um diretório local” é a definição de clone.

Como funciona

HEAD, branch e commit. Um commit é uma fotografia mais metadados (autor, data, mensagem, pai). Uma branch é apenas um ponteiro móvel para um commit — não é cópia de arquivos, não é diretório, não é cópia do repositório remoto. HEAD aponta para a branch em que você está. git branch <nome> cria o ponteiro; git checkout/git switch move o HEAD e atualiza o diretório de trabalho. git branch -d recusa apagar uma branch com trabalho não integrado; git branch -D apaga à força — mas nenhum dos dois apaga a branch que está em check-out.

Integrar trabalho: merge × rebase. O merge toma duas branches, procura o ancestral comum e combina as duas linhas; quando as duas divergiram, o resultado é um novo commit de mesclagem com dois pais, e o histórico anterior permanece intacto. O rebase faz outra coisa: retira os commits da sua branch, reaplica-os um a um sobre a ponta da outra e reescreve o histórico — os commits reaplicados são novos, com hashes novos. O ganho é histórico linear; o custo é que reescrever o que já foi publicado quebra o repositório dos outros. Em ambos os casos podem surgir conflitos, que o Git marca no arquivo e que o desenvolvedor resolve manualmente antes de concluir.

Desfazer: revert × reset. O git revert cria um commit novo que aplica o inverso de um commit anterior: o histórico cresce, nada é apagado, e por isso é a forma segura de desfazer algo já publicado. O git reset move o ponteiro da branch para um commit anterior e, conforme o modo, mexe nas outras áreas: --soft só move HEAD e preserva índice e diretório de trabalho; --mixed, o padrão, também limpa o índice; --hard descarta ainda as alterações do diretório de trabalho. Reescrever commits já enviados é o que se evita; por isso o git commit --amend, que substitui o último commit local por outro, é recomendado antes do push.

Trazer um commit isolado. O git cherry-pick <hash> reaplica a mudança de um commit específico sobre a branch em que você está, gerando um commit novo, com hash diferente do original, sem arrastar o resto da branch de origem.

Guardar trabalho temporariamente. git stash, sem argumentos, equivale a git stash push: guarda as alterações do diretório de trabalho e do índice e devolve a árvore limpa. Quem mostra o que foi guardado é git stash show, e git stash list enumera as entradas.

Inspecionar. git log lista os commits; git status mostra o estado das áreas; git diff compara; git blame mostra, linha a linha, o hash do commit que a introduziu, seguido do autor e da data. O primeiro campo do blame é commit, nunca identificador de usuário.

GitFlow e os fluxos. No GitFlow há duas branches permanentes — main (produção) e develop (integração) — e temporárias: feature, saída de develop e de volta a develop; release, saída de develop, que ao fim vai para main e develop; e hotfix, que nasce de main, porque corrige o que está em produção, e ao terminar é mesclada em main e develop, para que a correção não se perca na próxima entrega. Nas plataformas, o merge request do GitLab (o pull request do GitHub) é o pedido de mesclagem de uma branch de origem em uma branch alvo, com revisão antes da integração.

O que o Git não faz. Ele versiona código e coordena colaboração. Ele não constrói, não implanta, não monitora e não reinicia contêiner: isso é servidor de integração contínua e orquestrador.

O que decide os itens

Comando → área que ele move:

comandode ondepara onde
git initcria um repositório novo (ou reinicializa) no diretório
git clone <url>remotocria o repositório local completo
git adddiretório de trabalhoíndice
git commitíndicerepositório local
git commit --amendíndicesubstitui o último commit local
git pushrepositório localrepositório remoto
git fetchremotorepositório local, sem mexer no diretório de trabalho
git pullremotorepositório local e diretório de trabalho (fetch + merge)
git mergeoutra branchbranch atual, com commit de mesclagem
git rebasecommits da branch atualreaplicados sobre outra base, com hashes novos
git checkout / switchrepositório localmove o HEAD e atualiza o diretório de trabalho
git stashdiretório de trabalho e índicepilha de stash
git cherry-pickum commit de outra branchcommit novo na branch atual

Pares que decidem itens:

×quem é quem
merge × rebasemerge preserva o histórico e cria commit de mesclagem; rebase reescreve, com hashes novos, e produz histórico linear
revert × resetrevert cria commit novo que desfaz; reset move o ponteiro para um commit anterior
fetch × pullfetch só baixa; pull baixa e mescla
push × pullpush envia do local para o remoto; pull traz do remoto para o local
clone × pullclone cria a cópia local; pull atualiza a que já existe
clone × checkoutclone copia o repositório; checkout troca a branch ou restaura arquivos
-d × -D-d recusa apagar branch não mesclada; -D apaga à força
git stash × git stash showum guarda; o outro mostra o que está guardado
cherry-pick × mergecherry-pick traz um commit; merge traz a branch inteira
merge × merge requestmerge é comando local; MR é pedido de revisão na plataforma

Comandos que não existem. A banca inventa nomes plausíveis: git historicgit log), git append --filesgit add), get clone (com get no lugar de git). Antes de julgar o efeito, confirme que o comando existe.

Sequência suficiente. Para que a alteração chegue ao remoto é preciso addcommitpush. Item que descreve status, add e commit e conclui que o arquivo foi enviado ao repositório remoto parou no repositório local.

Números que caem

áreas de um repositório Git3 locais (diretório de trabalho, índice, repositório local) + 1 remoto
pais de um commit de mesclagem2
branches combinadas por um merge2
branches permanentes no GitFlow2: main e develop
destinos de uma hotfix ao fechar2: main e develop
modos do git reset3: --soft, --mixed (padrão), --hard
git pull equivale a2 comandos: fetch + merge
hash do commit exibido pelo blameo campo da linha

Como a CEBRASPE derruba você aqui

Os 26 itens do tópico estão explicados. Sobre os 15 de gabarito Errado: troca de termo 67% (10 itens), inversão 13% (2), atribuição errada 13% (2) e escopo ampliado 7% (1). Onze itens são Certo.

Antes das famílias, um aviso que muda o que estudar: o título deste tópico descreve mal o que a prova cobra. Ele promete “merge × rebase, revert × reset” — e, nos 26 itens medidos, git revert e git reset não aparecem uma única vez no enunciado; rebase aparece uma vez só, e justamente num item cuja resposta certa é reset. O que aparece de verdade é branch, em 13 dos 26 enunciados (50%), seguida de commit (9), merge (5) e clone (4). Ou seja: o tópico é sobre branch e sobre os comandos que atravessam (ou não) a rede — clone, push, pull, fetch, add, commit —, não sobre a família de desfazer. A tabela de modos do reset é conhecimento legítimo do assunto, mas não é por ela que estes itens se decidem.

E há uma segunda regularidade, mais útil que qualquer rótulo: 6 dos 15 itens errados se decidem por uma pergunta só — que área o comando toca, e se ele atravessa a rede. init e checkout não falam com servidor nenhum; add e commit param no repositório local; só clone, fetch, pull e push cruzam a rede, e clone escreve no destino que você indicou, não no servidor. Desenhe as quatro áreas antes de ler o item.

A ação certa com o nome de outro comando — 67%, dois em cada três itens errados. A descrição está impecável e a assinatura é de outro comando. git checkout que “é capaz de copiar completamente um repositório para um diretório local” (é clone; checkout só existe dentro de um repositório). git init codigo1 “para atualizar e sincronizar os dados no repositório” (é pull; init não move nada entre local e remoto). git clone --bare que “copiará todo o conteúdo do repositório local para o repositório remoto, e, por padrão, fará a mesclagem com a branch master” (clone escreve no destino informado e não mescla nada; enviar ao remoto é push). git rebase que “remove commits recentes e reposiciona o ponteiro do branch para um commit anterior, sem que haja alterações no histórico” (isso é reset — e “sem alterar o histórico” nunca combina com rebase, cuja definição é reescrevê-lo). git stash sem argumentos apresentado como similar a git stash show (é similar a git stash push: um grava, o outro exibe). O cherry-pick que adicionaria um commit “ao último commit de outra branch” (ele reaplica na branch em que você está, gerando commit novo com hash próprio). E a branch definida como “uma cópia local de um repositório remoto, com todos os arquivos e as configurações iguais aos originais” — branch é um ponteiro móvel de poucos bytes, e é por isso que custa quase nada; cópia local de remoto é o que o clone produz.

Dentro dessa família, um caso que vale isolar: em 3 dos 10 itens o comando simplesmente não existe — 20% de tudo que é errado no tópico. “O comando git historic apresenta uma relação de todos os commits” (é git log); “O comando git append —files permite adicionar todos os arquivos […] ao ambiente de preparação” (é git add -A); “O comando get clone incorpora as alterações de um repositório remoto no ramo atual” (é git pull, e nem get é git). Os nomes soam certos porque descrevem bem a função pedida. Defesa: confirme que o comando existe antes de julgar o efeito — é a verificação mais barata do tópico e resolve um item errado em cada cinco.

A seta entre local e remoto girada — 13%. Duas inversões. A primeira é o par push/pull trocado por inteiro: “git push […] fará que a versão local do projeto seja sincronizada para a versão mais recente do repositório remoto; enquanto git pull […] fará que as alterações locais sejam enviadas para o repositório remoto”. A segunda troca a condição de uma exclusão: em git branch -D test, a exclusão seria cancelada “se a master estiver em estado de check-out” — o que impede apagar uma branch é ela própria estar em check-out; com a master em check-out, apagar test é o caso normal. E o -D maiúsculo apaga mesmo havendo commits não mesclados; quem recusa é o -d minúsculo. Defesa: push empurra para fora, pull puxa para dentro — desenhe a seta antes de ler o verbo; e, em opção de letra repetida, a maiúscula costuma ser a versão forçada da minúscula.

A função pendurada no dono errado — 13%. Duas vezes, e em escalas diferentes. No campo: na saída de git blame -L 5,5, o f4c2d3b1 apresentado como “o id do usuário que realizou o commit”, quando é o hash do commit — o usuário é o “John Doe” que vem logo em seguida, entre parênteses. Sequência hexadecimal curta no Git é sempre hash de objeto; usuário aparece como nome ou e-mail. Na ferramenta: equipes de DevOps que “utilizam o Git para reiniciar os contêineres automaticamente em caso de falha” — o Git versiona código; reiniciar contêiner é do orquestrador ou da política de reinício do runtime. Defesa: em item de cadeia DevOps, confira se a ferramenta citada está na etapa certa.

A sequência que para antes do fim — 7%. git status, git add app22.html, git commit -m "..." apresentados como “suficientes para enviar o arquivo […] para o repositório remoto”. A sequência é correta e completa até o repositório local: nada nela atravessa a rede, e falta o push. Defesa: percorra a sequência marcando a área que cada comando alcança; se nenhum fala com o servidor, qualquer conclusão sobre o remoto é falsa.

Erros clássicos

Achar que branch é cópia de arquivos ou do repositório remoto. Branch é um ponteiro para um commit. É por isso que criar uma custa quase nada e é por isso que apagá-la não apaga o trabalho já integrado.

Confundir fetch com pull. fetch é seguro: traz os objetos e atualiza as referências remotas sem tocar no que você está editando. pull faz isso e ainda mescla — e é aí que aparecem conflitos que você não pediu.

Usar reset onde cabia revert. Em histórico já publicado, reset reescreve o que os outros já têm. revert desfaz criando um commit novo, que se propaga normalmente.

Supor que o rebase preserva o histórico. Ele reaplica os commits e gera hashes novos. É exatamente por isso que a regra prática diz para não rebasear o que já foi enviado.

Achar que cherry-pick copia o commit com o mesmo hash. O conteúdo da mudança é o mesmo; o commit é outro, porque tem pai diferente.

Tratar o merge request como um comando do Git. MR e PR são recursos das plataformas (GitLab, GitHub), com revisão e aprovação. O merge propriamente dito é local.

Esquecer que conflito é resolvido por pessoa. O Git detecta a sobreposição e marca o arquivo; quem decide qual versão vale é o desenvolvedor.

Praticar26 itens