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:
| lugar | o que é |
|---|---|
| diretório de trabalho | os arquivos como você os vê e edita |
| índice (staging area) | o que já foi marcado para entrar no próximo commit |
| repositório local | o grafo de commits dentro de .git, com HEAD apontando para um deles |
| repositório remoto | a 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:
| comando | de onde | para onde |
|---|---|---|
git init | — | cria um repositório novo (ou reinicializa) no diretório |
git clone <url> | remoto | cria o repositório local completo |
git add | diretório de trabalho | índice |
git commit | índice | repositório local |
git commit --amend | índice | substitui o último commit local |
git push | repositório local | repositório remoto |
git fetch | remoto | repositório local, sem mexer no diretório de trabalho |
git pull | remoto | repositório local e diretório de trabalho (fetch + merge) |
git merge | outra branch | branch atual, com commit de mesclagem |
git rebase | commits da branch atual | reaplicados sobre outra base, com hashes novos |
git checkout / switch | repositório local | move o HEAD e atualiza o diretório de trabalho |
git stash | diretório de trabalho e índice | pilha de stash |
git cherry-pick | um commit de outra branch | commit novo na branch atual |
Pares que decidem itens:
| × | quem é quem |
|---|---|
| merge × rebase | merge preserva o histórico e cria commit de mesclagem; rebase reescreve, com hashes novos, e produz histórico linear |
| revert × reset | revert cria commit novo que desfaz; reset move o ponteiro para um commit anterior |
| fetch × pull | fetch só baixa; pull baixa e mescla |
| push × pull | push envia do local para o remoto; pull traz do remoto para o local |
| clone × pull | clone cria a cópia local; pull atualiza a que já existe |
| clone × checkout | clone 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 show | um guarda; o outro mostra o que está guardado |
| cherry-pick × merge | cherry-pick traz um commit; merge traz a branch inteira |
| merge × merge request | merge é comando local; MR é pedido de revisão na plataforma |
Comandos que não existem. A banca inventa nomes plausíveis: git historic
(é git log), git append --files (é git 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
add → commit → push. 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 Git | 3 locais (diretório de trabalho, índice, repositório local) + 1 remoto |
| pais de um commit de mesclagem | 2 |
branches combinadas por um merge | 2 |
| branches permanentes no GitFlow | 2: main e develop |
destinos de uma hotfix ao fechar | 2: main e develop |
modos do git reset | 3: --soft, --mixed (padrão), --hard |
git pull equivale a | 2 comandos: fetch + merge |
hash do commit exibido pelo blame | o 1º 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.
LidoPraticado