Uma das vantagens do uso de um DVCS é o fluxo de trabalho de edição-confirmação-mesclagem (sobre a edição-consolidação-mesclagem geralmente imposta por um CVCS). Permitir que cada alteração exclusiva seja registrada no repositório independente de mesclagens garante que o DAG reflita com precisão o verdadeiro pedigree do projeto.
Por que tantos sites falam sobre querer "evitar consolidação de mesclagem"? A mesclagem de pré-confirmação ou re-mesclagem não dificulta o isolamento de regressões, a reversão de alterações anteriores etc.?
Ponto de esclarecimento: O comportamento padrão de um DVCS é criar confirmações de mesclagem. Por que tantos lugares falam sobre o desejo de ver uma história de desenvolvimento linear que oculte esses compromissos de mesclagem?
fonte
git pull
)? Eu posso ver por que isso pode ser problemático, mas minha pergunta é sobre todos os commits de mesclagem.git pull --rebase == svn up
(soltas-iguais, não estrita-iguala)Respostas:
As pessoas querem evitar confirmações de mesclagem porque isso torna o log mais bonito. A sério. Parece que os logs centralizados com os quais cresceram e localmente podem fazer todo o seu desenvolvimento em uma única ramificação. Além desses aspectos estéticos, não há benefícios, além de vários inconvenientes, como tornar propenso a conflitos extrair diretamente de um colega sem passar pelo servidor "central".
fonte
Em duas palavras:
git bisect
Um histórico linear permite identificar a fonte real de um bug.
Um exemplo. Este é o nosso código inicial:
A ramificação 1 faz alguma refatoração que
arg
não é mais válida:A ramificação 2 possui um novo recurso que precisa ser usado
arg
:Não haverá conflitos de mesclagem, no entanto, um bug foi introduzido. Felizmente, este em particular será pego na etapa de compilação, mas nem sempre temos tanta sorte. Se o bug se manifestar como comportamento inesperado, em vez de um erro de compilação, talvez não o encontremos por uma semana ou duas. Nesse ponto,
git bisect
para o resgate!Oh droga. Isto é o que vê:
Portanto, quando enviamos
git bisect
para encontrar o commit que quebrou a compilação, ele identifica um commit de mesclagem. Bem, isso ajuda um pouco, mas está essencialmente apontando para um pacote de commits, não um único. Todos os antepassados são verdes. Por outro lado, com o rebase, você obtém um histórico linear:Agora,
git bisect
apontará o commit exato do recurso que interrompeu a compilação. Idealmente, a mensagem de confirmação explicará o que foi planejado o suficiente para fazer outro refator e corrigir o erro imediatamente.O efeito é composto apenas em grandes projetos quando os mantenedores não escrevem todo o código, portanto, eles não se lembram necessariamente do porquê de qualquer confirmação feita / para que serve cada ramificação. Portanto, identificar o commit exato (e, em seguida, poder examinar os commits em torno dele) é uma grande ajuda.
Dito isto, eu (atualmente) ainda prefiro a fusão. A reinicialização em uma ramificação de liberação fornecerá seu histórico linear para uso
git bisect
, mantendo o histórico verdadeiro para o trabalho diário.fonte
gitk --all
é extremamente útil ver o fluxo de confirmações entre filiais (especialmente porque geralmente tenho três filiais em um determinado momento, e alterno entre elas todos os dias, dependendo do meu humor em A Hora).bisect
resultado. É fácil encontrar o indivíduo confirmado com umblame
ou um diferente,bisect
se você quiser ir mais fundo. Com um histórico linear, a mesclagem é feita fora do livro, então você não pode mais dizer que uma mesclagem incorreta foi o problema. Parece apenas um idiota usando um argumento que não existe, especialmente se o argumento foi removido vários commits anteriores. Tentar descobrir por que ele faria isso é muito mais difícil quando você destrói a história.Em resumo, porque a fusão geralmente é outro lugar para algo dar errado, e ele só precisa dar errado uma vez para deixar as pessoas com muito medo de lidar com isso novamente (uma vez mordido duas vezes tímido, se quiser).
Então, digamos que estamos trabalhando em uma nova tela de gerenciamento de contas, e acontece que um bug foi descoberto no fluxo de trabalho Nova conta. OK, seguimos dois caminhos separados - você termina o Gerenciamento de contas e eu corrigo o erro com Novas contas. Como estamos lidando com contas, trabalhamos com códigos muito semelhantes - talvez tenhamos que ajustar os mesmos trechos de código.
Agora, neste momento, temos duas versões diferentes, mas totalmente funcionais, de software. Ambos executamos um commit em nossas alterações, testamos obedientemente nosso código e, independentemente, estamos muito confiantes de que fizemos um ótimo trabalho. O que agora?
Bem, é hora de fundir, mas ... merda, o que acontece agora? Poderíamos muito bem ir de dois conjuntos de software em funcionamento a um software unificado e horrivelmente quebrado de software com erros, em que o gerenciamento de contas não funciona e as novas contas estão quebradas e nem sei se o bug antigo ainda está lá .
Talvez o software fosse inteligente e dissesse que havia um conflito e insistia em dar orientação. Bem, droga - eu me sento para fazer isso e vejo que você adicionou um código complexo que não entendo imediatamente. Eu acho que está em conflito com as mudanças que fiz ... Eu pergunto, e quando você chegar um minuto você verifica e vê meu código que você não entende. Um de nós dois precisa dedicar algum tempo para se sentar, fazer uma fusão adequada e possivelmente testar novamente a coisa toda para garantir que não a quebremos.
Enquanto isso, oito outros caras estão cometendo códigos como os sádicos, fiz algumas pequenas correções e as enviei antes que soubéssemos que tínhamos um conflito de mesclagem, e, com certeza, parece um bom momento para fazer uma pausa, e talvez você estão de folga para a tarde ou presos em uma reunião ou o que quer. Talvez eu devesse tirar férias. Ou mude de carreira.
E assim, para escapar desse pesadelo, algumas pessoas ficaram com muito medo de se comprometer (o que mais há de novo, certo?). Naturalmente, somos avessos ao risco em cenários como este - a menos que pensemos que somos péssimos e que vamos estragar tudo, caso em que as pessoas começam a agir com abandono imprudente. suspiro
Então lá vai você. Sim, os sistemas modernos são projetados para aliviar essa dor, e é suposto ser capaz de voltar e rebocar, rebaixar, rebaixar e liberar bases e hanglide e tudo isso.
Mas é tudo mais trabalho, e nós apenas queremos apertar o botão no micro-ondas e fazer uma refeição de 4 pratos antes de termos tempo para encontrar um garfo, e tudo parece muito insatisfatório - código é trabalho, é produtivo, significativo, mas manipular graciosamente uma mesclagem simplesmente não conta.
Os programadores, em regra, precisam desenvolver uma ótima memória de trabalho e, em seguida, tendem a esquecer imediatamente todos esses nomes de lixo e variáveis e o escopo assim que terminam o problema, além de lidar com um conflito de mesclagem (ou pior, mesclagem incorreta) é um convite para ser lembrado de sua mortalidade.
fonte
O rebaseamento fornece um ponto de ramificação móvel que simplifica o processo de enviar as alterações de volta à linha de base. Isso permite que você trate um ramo de execução longa como se fosse uma alteração local. Sem rebasear, as ramificações acumulam alterações a partir da linha de base, que serão incluídas nas alterações que serão mescladas de volta à linha de base.
A mesclagem deixa sua linha de base no ponto de ramificação original. Se você mesclar algumas semanas de alterações a partir da linha em que você se ramificou, agora terá muitas alterações no ponto de ramificação, muitas das quais estarão em sua linha de base. Isso dificulta a identificação de suas alterações em sua filial. Enviar as alterações de volta à linha de base pode gerar conflitos não relacionados às suas alterações. No caso de conflitos, é possível fazer alterações inconsistentes. Mesclagens contínuas exigem esforço para gerenciar, e é relativamente fácil perder alterações.
Rebase move seu ponto de ramificação para a revisão mais recente em sua linha de base. Quaisquer conflitos que você encontrar serão apenas para as suas alterações. Pressionar as mudanças é muito mais simples. Os conflitos são tratados na ramificação local, fazendo uma nova rebase. No caso de envios conflitantes, o último a enviar suas alterações precisará resolver o problema com as alterações.
fonte
As ferramentas automatizadas estão melhorando para garantir que o código de mesclagem seja compilado e executado, evitando conflitos sintáticos , mas não podem garantir a ausência de conflitos lógicos que podem ser introduzidos por mesclagens. Portanto, uma mesclagem 'bem-sucedida' fornece uma sensação de falsa confiança, quando na realidade nada garante e você precisa refazer todos os seus testes.
O verdadeiro problema com ramificação e fusão, a meu ver, é que ele chuta a lata proverbial no futuro. Ele permite que você diga "Vou trabalhar no meu pequeno mundo" por uma semana e lide com os problemas que surgirem mais tarde. Mas corrigir bugs é sempre mais rápido / mais barato quando novos. No momento em que todas as ramificações de código começam a ser mescladas, você já pode esquecer algumas das nuances das coisas que foram feitas.
Reúna os dois problemas mencionados acima e você poderá se encontrar em uma situação em que é mais simples e fácil que todos trabalhem no mesmo tronco e resolvam continuamente conflitos à medida que surgem, mesmo que tornem o desenvolvimento ativo um pouco mais lento.
fonte
Um ponto adicional relevante é o seguinte: com o rebasing, posso facilmente escolher ou reverter um recurso no meu ramo de lançamento.
fonte
git cherry-pick -x <commit>
para aplicá-lo ao ramo de lançamento. Ou, podemos querer desfazer algo para o lançamento, comgit revert <commit>
. Se<commit>
é uma mesclagem, fica peludo. Ele é possível, tanto quanto eu sei, mas não é fácil de fazer. Ao usar o rebase, cada 'mesclagem' é um commit gigante, mas regular, facilmente selecionável e reversível.Três coisas não foram ditas em nenhuma das respostas:
Diferindo dentro de um galho:
Mesclando um item por vez:
Limpeza antes do envio:
fonte