mesclar vs. rebase: escolhendo a ferramenta certa

Eu vi alguns protips aqui alegando que git pullé mau ou morto ou algo assim. É um pouco mais complicado do que isso. Vou tentar explicar o que é, por que e o que isso significa para você.

Primeiro: nãogit pull está morto – mesmo se você geralmente não gosta de commits de mesclagem. Por padrão, mescla seus commits, mas pode ser configurado para rebase em vez disso (configurações de configuração egit pullbranch.autosetuprebasebranch.yourbranch.rebase</code>). Even then, there are good reasons to use or not use either of the two.

Vamos precisar destes termos:

  • Filial local: uma filial em que você está trabalhando.
  • Branch upstream: um branch em que seu branch local é baseado e do qual você gostaria de obter atualizações.

Rebasing

O bom: em resumo, o rebase pega seus commits e os coloca “no topo” da história do upstream, ou seja, finge que você fez seus commits depois de todos os novos. Isso tende a ter uma boa aparência e pode tornar mais fácil para o mantenedor de um repositório fork / upstream integrar suas mudanças. Ambos são coisas boas, é claro.

O ruim: se você rebasear commits que já compartilhou com outros (por exemplo, rebaseing coisas que você já fez push anteriormente e então usando git push -f), as coisas azedam rápido. Aqui está seu histórico antes de rebase:

sua mudança → histórico de upstream [1]

E aqui está sua história após a rebase:

sua mudança com base no rebase → histórico de upstream mais recente [2]

Suponha que outra pessoa tenha uma cópia do histórico em [1] e use git pull(sim, as pessoas ainda fazem isso) … então eles obtêm isto:

mesclar commit → (sua alteração, uma vez com base em rebase e uma vez não) → histórico de upstream mais recente [3]

Ai!

Mas tudo bem, talvez o rebase seja mais incrível. E, de fato, em alguns casos simples, ele fará magicamente a coisa certa … mas se as novas mudanças upstream estiverem intimamente relacionadas às suas próprias mudanças, alguém pode conseguir isso depois de :git pull --rebase

sua mudança → sua mudança com base no rebase → histórico de upstream mais recente [4]

Woah, o que aconteceu lá? git rebasenão conseguiu mais detectar que os dois commits (rebased e não) são equivalentes, então colocou o não rebased (que só existe localmente para este usuário agora, porque você rebased no repositório upstream) no topo do rebased (que ele considera o upstream porque o branch upstream o possui e o branch local do usuário não). Ai de novo!

Finalmente, o rebase lineariza o commit de mesclagem por padrão. Isso significa que se um de seus commits locais for um commit de mesclagem, não será depois que o rebase for feito – ele se tornará uma série estranhamente ordenada de todos os commits introduzidos pela mesclagem original. Rebase tem um modo para preservar as mesclagens, mas você deve se lembrar de usá-lo. Portanto, rebase e mesclagem são um pouco como óleo e água – eles não se misturam sem um emulsificante (a bandeira extra).

Mesclando

O bom: as mesclagens funcionam espetacularmente bem até mesmo para os cenários de colaboração distribuídos mais selvagens . Você pode mesclar para frente e para trás para o conteúdo do seu coração e Git quase sempre descobrirá isso.

Além disso, vale a pena apontar que os commits de mesclagem podem servir como um registro valioso do fato de que uma pessoa específica integrou um conjunto específico de mudanças em um branch. Se você quiser rastrear qual trabalho de integração aconteceu e quando, o rebase realmente tornará sua vida mais difícil.

O ruim: como outros observaram, a fusão excessiva torna sua história muito complicada . As ferramentas de visualização de histórico do Git podem simplificar o histórico (por exemplo – funciona particularmente bem se você escrever boas mensagens de commit para seus commits de mesclagem), mas freqüentemente uma série direta de commits simplesmente funciona melhor.git log --first-parent

Outro grande problema com mesclagens é que não é possível desfazê- los depois de publicá-los – da mesma forma que é uma má ideia realocar commits publicados. Você pode ficar tentado a pensar que git revertcom a opção desfaz as mesclagens, mas isso não acontece: ela apenas desfaz as alterações . Se você fizer uma mesclagem subsequente dos mesmos branches, git não notará que o antigo commit de mesclagem foi revertido (porque uma reversão é tecnicamente um commit completamente independente), então ele nunca mesclará os commits previamente mesclados novamente. Em vez disso, ele irá mesclar apenas os commits mais recentes no branch upstream. Eu realmente não consigo pensar em um cenário em que isso seja lógico.-m

Avanço rápido

Há uma classe de mudanças em que merge e rebase fazem exatamente a mesma coisa (por padrão): quando você não tem nenhuma mudança local, ambos merge e rebase irão simplesmente trazê-lo atualizado “fast-forward” seu branch local para o mesmo estado do branch upstream. Você pode forçar git mergea criação de um commit de mesclagem, entretanto, com a opção – desta forma, você ainda obterá um registro explícito da mesclagem.--no-ff

Squashing

Você pode usar para criar um “grande commit de tudo” em vez de um commit de mesclagem. Isso vai rolar todas as mudanças upstream em um único grande commit. Isso geralmente não é útil porque se os commits foram bem elaborados, agora você tem menos informações e estrutura em seu histórico do que antes. Pode ser conveniente se você deseja integrar a versão final de uma pequena mudança.git merge --squash

O que escolher

  • Se você é um contribuidor , use rebase sempre que puder. Tente evitar contribuir com algo em que você fez merge commits – isso tornará as coisas mais difíceis para o mantenedor / integrador.
  • Se você é um mantenedor , realmente depende do escopo do conjunto de commits que você está integrando e do gosto pessoal. Eu gosto de rebase ou selecionar pequenas mudanças, mas mesclar séries interdependentes de commits, especialmente se eles foram desenvolvidos amplamente independentemente do trabalho de desenvolvimento “oficial” no projeto.

O que evitar

  • Evite mesclagens “experimentais”. Se você enviar / publicar uma mesclagem, é melhor ter certeza de que a mesclagem é boa.
  • Não use mesclagem e rebase na mesma parte do histórico (isto é, commits somente locais).
  • Não use o squash merge se quiser fundir / rebase os mesmos branches novamente mais tarde.
  • Não altere seu histórico depois de publicado. Tanto a fusão quanto o rebase irão bagunçar as coisas. Qualquer pessoa que tentar combinar a velha e a nova história terá que fazer um trabalho manual extra.
  • Se você acidentalmente combinar duas versões da história, pelo amor de tudo, não inflija a abominação resultante a ninguém. Apenas comece de novo.

Respostas relacionadas:

fatal: recusar-se a mesclar histórias não relacionadas