Mesmo que eu use o Git na linha de comando - eu tenho que concordar com seus colegas. Não é sensato espremer grandes alterações em um único commit. Você está perdendo a história dessa maneira, não apenas tornando-a menos visível.
O ponto de controle de origem é rastrear o histórico de todas as alterações. Quando o que mudou porque? Para esse fim, todo commit contém ponteiros para commits pai, um diff e metadados como uma mensagem de commit. Cada commit descreve o estado do código-fonte e o histórico completo de todas as mudanças que levaram a esse estado. O coletor de lixo pode excluir confirmações que não estão acessíveis.
Ações como rebasing, cherry picking ou squashing excluem ou reescrevem o histórico. Em particular, os commits resultantes não fazem mais referência aos commits originais. Considere isto:
- Você esmaga alguns commits e nota na mensagem de commit que o histórico esmagado está disponível no commit original abcd123.
- Você exclui [1] todas as ramificações ou tags que incluem abcd123, já que elas estão mescladas.
- Você permite que o coletor de lixo seja executado.
[1]: Alguns servidores do Git permitem que filiais sejam protegidas contra exclusão acidental, mas duvido que você queira manter todos os seus ramos de recursos por toda a eternidade.
Agora você não pode mais procurar esse commit - ele simplesmente não existe.
Fazer referência a um nome de ramificação em uma mensagem de confirmação é ainda pior, já que os nomes das ramificações são locais para um repo. O que é master+devFeature
no seu checkout local pode ser doodlediduh
no meu. As ramificações estão apenas movendo rótulos que apontam para algum objeto de confirmação.
De todas as técnicas de reescrita do histórico, o rebasing é o mais benigno porque duplica os commits completos com todo o seu histórico e apenas substitui um commit pai.
Que o histórico de master
inclui o histórico completo de todas as ramificações que foram mescladas nele é uma coisa boa, porque isso representa a realidade. [2] Se houvesse desenvolvimento paralelo, isso deveria ser visível no log.
[2]: Por esse motivo, também prefiro commits explícitos de mesclagem sobre a história linearizada, mas, em última análise, falsa, resultante da recomposição.
Na linha de comando, git log
tenta simplificar o histórico exibido e manter todos os itens exibidos comete relevante. Você pode ajustar a simplificação do histórico para atender às suas necessidades. Você pode ser tentado a escrever sua própria ferramenta de registro git que percorre o gráfico de commit, mas geralmente é impossível responder “este commit foi originalmente cometido neste ou naquele branch?”. O primeiro pai de uma consolidação de mesclagem é o HEAD
anterior, ou seja, o commit na ramificação na qual você está mesclando. Mas isso pressupõe que você não fez uma mesclagem reversa do mestre no ramo de feição, então redirecionou o mestre para a mesclagem.
A melhor solução para filiais de longo prazo que encontrei é evitar filiais que são mescladas após alguns meses. A fusão é mais fácil quando as alterações são recentes e pequenas. O ideal é que você se fundir pelo menos uma vez por semana. A integração contínua (como na Programação Extrema, não como em “configurar um servidor Jenkins”), sugere até várias mesclagens por dia, ou seja, não manter ramificações de recursos separadas, mas compartilhar uma ramificação de desenvolvimento como uma equipe. Mesclar antes de um recurso ser QA requer que o recurso esteja oculto atrás de um sinalizador de recurso.
Em troca, a integração frequente possibilita detectar possíveis problemas muito mais cedo e ajuda a manter uma arquitetura consistente: mudanças de longo alcance são possíveis porque essas mudanças são rapidamente incluídas em todas as filiais. Se uma alteração quebra algum código, apenas um par de dias de trabalho será interrompido, não um par de meses.A reescrita do histórico pode fazer sentido para projetos realmente grandes quando há milhões de linhas de código e centenas ou milhares de desenvolvedores ativos. É questionável por que um projeto tão grande teria que ser um único repositório do git em vez de ser dividido em bibliotecas separadas, mas nessa escala é mais conveniente que o repositório central contenha apenas “releases” dos componentes individuais. Por exemplo. o kernel do Linux emprega squash para manter o histórico principal gerenciável. Alguns projetos de código aberto exigem que os patches sejam enviados por e-mail, em vez de uma mesclagem no nível do git.