Por que o git executa mesclagens de avanço rápido por padrão?

641

Vindo de mercurial, eu uso ramos para organizar recursos. Naturalmente, também quero ver esse fluxo de trabalho na minha história.

Comecei meu novo projeto usando git e terminei meu primeiro recurso. Ao mesclar o recurso, percebi que o git usa o avanço rápido, ou seja, aplica minhas alterações diretamente ao ramo principal, se possível, e esquece sobre o meu ramo.

Então, para pensar no futuro: sou o único a trabalhar neste projeto. Se eu usar a abordagem padrão do git (mesclagem rápida), meu histórico resultará em um ramo principal gigante. Ninguém sabe que usei um ramo separado para cada recurso, porque no final terei apenas esse ramo mestre gigante. Isso não parecerá pouco profissional?

Por esse raciocínio, não quero mesclar rapidamente e não consigo entender por que é o padrão. O que há de tão bom nisso?

Florian Pilz
fonte
38
Nota: consulte também sandofsky.com/blog/git-workflow.html e evite o ' no-ff' com seus "pontos de verificação confirmados" que quebram a bissetriz ou a culpa.
VonC 01/08/19
15
Você se arrepende de usar o git em um projeto de um homem?
HaveAGuess 19/10/11
27
Absolutamente não! Na minha pasta de trabalho, tenho 7 projetos individuais onde uso o git. Deixe-me reformular o seguinte: iniciei muitos projetos desde que fiz essa pergunta e todos eles são versionados via git. Até onde eu sei, apenas o git e o mercurial suportam versões locais, o que é essencial para mim desde que me acostumei. É fácil configurá-lo e você sempre tem toda a história com você. Nos projetos em grupo, é ainda melhor, pois você pode confirmar sem interferir ninguém no seu código de trabalho em andamento. Além disso, eu uso o github para compartilhar alguns dos meus projetos (por exemplo, micro-optparse) onde o git é um requisito.
Florian Pilz
7
@Cawas é verdade, -no-ffraramente é uma boa ideia, mas ainda pode ajudar a manter um histórico interno do recurso enquanto grava apenas um commit no ramo principal. Isso faz sentido para o longo histórico de recursos, quando você mescla de tempos em tempos sua progressão no ramo principal.
VonC
12
A propósito, para sua pergunta de "Isso [um histórico de ramificação linear] não parece profissional?". Não há nada de pouco profissional em usar um sistema de código-fonte com seus padrões. Não se trata de profissionalismo. Trata-se de determinar qual filosofia de ramificação você assina. Por exemplo, @VonC vinculou ao artigo de sandofsky, onde ele defende o avanço rápido como uma abordagem superior. Não certo ou errado, apenas diferentes filosofias para diferentes contextos.
Marplesoft

Respostas:

718

A mesclagem de avanço rápido faz sentido para ramificações de vida curta, mas em um histórico mais complexo , a mesclagem sem avanço rápido pode facilitar a compreensão do histórico e reverter um grupo de confirmações.

Aviso : O avanço rápido não tem efeitos colaterais potenciais. Revise https://sandofsky.com/blog/git-workflow.html , evite o 'no-ff' com seus "pontos de verificação confirmados" que quebram a bissetriz ou a culpa e considere cuidadosamente se deve ser sua abordagem padrão master.

texto alternativo
(De nvie.com , Vincent Driessen , poste " Um modelo de ramificação Git bem-sucedido ")

Incorporando um recurso finalizado no desenvolvimento

Os recursos finalizados podem ser mesclados no ramo de desenvolvimento para adicioná-los ao próximo lançamento:

$ git checkout develop
Switched to branch 'develop'
$ git merge --no-ff myfeature
Updating ea1b82a..05e9557
(Summary of changes)
$ git branch -d myfeature
Deleted branch myfeature (was 05e9557).
$ git push origin develop

O --no-ffsinalizador faz com que a mesclagem sempre crie um novo objeto de confirmação, mesmo que a mesclagem possa ser executada com um avanço rápido. Isso evita a perda de informações sobre a existência histórica de uma ramificação de recurso e agrupa todas as confirmações que adicionaram o recurso.

Jakub Narębski também menciona a configuraçãomerge.ff :

Por padrão, o Git não cria uma confirmação de mesclagem extra ao mesclar uma confirmação que é descendente da confirmação atual. Em vez disso, a ponta da ramificação atual é encaminhada rapidamente.
Quando definida como false, essa variável diz ao Git para criar um commit de mesclagem extra nesse caso (equivalente a dar a --no-ffopção na linha de comando).
Quando definido como ' only', apenas essas mesclagens de avanço rápido são permitidas (equivalente a dar a --ff-onlyopção na linha de comando).


O avanço rápido é o padrão porque:

  • ramificações de vida curta são muito fáceis de criar e usar no Git
  • ramificações de vida curta freqüentemente isolam muitos commits que podem ser reorganizados livremente dentro dessa ramificação
  • esses commits fazem parte da ramificação principal: uma vez reorganizados, a ramificação principal é encaminhada rapidamente para incluí-los.

Mas se você antecipar um fluxo de trabalho iterativo em uma ramificação de tópico / recurso (por exemplo, mesclo, voltarei a essa ramificação de recurso e adicionarei mais confirmações), será útil incluir apenas a mesclagem na ramificação principal, em vez de todo o intermediário confirma a ramificação do recurso.

Nesse caso, você pode acabar configurando esse tipo de arquivo de configuração :

[branch "master"]
# This is the list of cmdline options that should be added to git-merge 
# when I merge commits into the master branch.

# The option --no-commit instructs git not to commit the merge
# by default. This allows me to do some final adjustment to the commit log
# message before it gets commited. I often use this to add extra info to
# the merge message or rewrite my local branch names in the commit message
# to branch names that are more understandable to the casual reader of the git log.

# Option --no-ff instructs git to always record a merge commit, even if
# the branch being merged into can be fast-forwarded. This is often the
# case when you create a short-lived topic branch which tracks master, do
# some changes on the topic branch and then merge the changes into the
# master which remained unchanged while you were doing your work on the
# topic branch. In this case the master branch can be fast-forwarded (that
# is the tip of the master branch can be updated to point to the tip of
# the topic branch) and this is what git does by default. With --no-ff
# option set, git creates a real merge commit which records the fact that
# another branch was merged. I find this easier to understand and read in
# the log.

mergeoptions = --no-commit --no-ff

O PO acrescenta nos comentários:

Eu vejo algum sentido em avançar rapidamente para ramificações [de curta duração], mas torná-la a ação padrão significa que o git assume que você ... geralmente tem ramificações [de curta duração]. Razoável?

Jefromi responde:

Eu acho que a vida útil dos ramos varia muito de usuário para usuário. Entre os usuários experientes, porém, provavelmente há uma tendência a ter muito mais ramificações de vida curta.

Para mim, uma ramificação de vida curta é a que eu crio para facilitar uma determinada operação (rebasing, provável ou rápida correção e teste) e, em seguida, exclua imediatamente assim que terminar.
Isso significa que provavelmente deve ser absorvido pelo ramo de tópicos do qual foi bifurcado e o ramo de tópicos será mesclado como um ramo. Ninguém precisa saber o que eu fiz internamente para criar a série de confirmações implementando esse recurso.

De maneira mais geral, eu adiciono:

isso realmente depende do seu fluxo de trabalho de desenvolvimento :

  • se for linear, um ramo faz sentido.
  • Se você precisar isolar recursos e trabalhar neles por um longo período de tempo e mesclá-los repetidamente, vários ramos farão sentido.

Consulte " Quando você deve ramificar? "

Na verdade, quando você considera o modelo de ramificação do Mercurial, ele é basicamente um ramo por repositório (mesmo que você possa criar cabeças anônimas, marcadores e até ramificações nomeadas )
Consulte "Git e Mercurial - Compare e Contraste" .

Mercurial, por padrão, usa linhas de código leves anônimas, que em sua terminologia são chamadas de "cabeças".
O Git usa ramificações nomeadas leves, com mapeamento injetivo para mapear nomes de ramificações no repositório remoto para nomes de ramificações de rastreamento remoto.
O Git "força" você a nomear ramificações (bem, com exceção de uma única ramificação sem nome, que é uma situação chamada " HEAD desanexada "), mas acho que isso funciona melhor com fluxos de trabalho pesados, como fluxo de tópicos, significando várias ramificações em um único paradigma de repositório.

VonC
fonte
Uau, isso foi rápido. ;) Conheço a opção --no-ff, mas só descobri o avanço rápido depois que estraguei meu recurso. Eu vejo algum sentido em avançar rapidamente para galhos de vida curta, mas torná-la a ação padrão significa que o git assume que você tem mais frequentemente galhos de vida curta. Razoável?
Florian Pilz
@ Florian: Eu acredito que esta é uma visão razoável do processo. Eu adicionei um exemplo de uma configuração que definirá a maneira que você deseja gerenciar a mesclagem para dominar.
VonC
Obrigado, o arquivo de configuração deve ajudar a evitar tais truques. :) Somente aplicou essa configuração localmente com "git config branch.master.mergeoptions '--no-ff'"
Florian Pilz
2
@BehrangSaeedzadeh: rebasing é outro tópico (que não foi mencionado nesta página): contanto que você não tenha enviado seu featureramo a um repositório público, você pode restaurá-lo masterquantas vezes quiser. Veja stackoverflow.com/questions/5250817/…
VonC
4
@BehrangSaeedzadeh: uma recuperação por si só não tornará a história linear. É como você integra as mudanças de sua featureramificação de volta ao masterque torna a dita história linear ou não. Uma mesclagem simples de avanço rápido a tornará linear. O que faz sentido se você limpou o histórico desse featureramo antes da mesclagem de avanço rápido, deixando apenas confirmações significativas, conforme mencionado em stackoverflow.com/questions/7425541/… .
VonC 28/10/11
42

Deixe-me expandir um pouco em um VonC 's resposta muito abrangente :


Primeiro, se bem me lembro, o fato de o Git por padrão não criar confirmações de mesclagem no caso de avanço rápido veio da consideração de "repositórios iguais" de ramificação única, onde a atração mútua é usada para sincronizar esses dois repositórios (um você pode encontrar o primeiro exemplo na documentação da maioria dos usuários, incluindo "O Manual do Usuário do Git" e "Controle de versão por exemplo"). Nesse caso, você não usa pull para mesclar ramificação totalmente realizada, usa-o para acompanhar outros trabalhos. Você não quer ter fatos efêmeros e sem importância quando faz uma sincronização salva e armazenada no repositório, salva para o futuro.

Observe que a utilidade das ramificações de recursos e de ter várias ramificações no repositório único veio apenas mais tarde, com um uso mais disseminado do VCS com bom suporte de mesclagem e com a tentativa de vários fluxos de trabalho baseados em mesclagem. É por isso que, por exemplo, o Mercurial originalmente suportava apenas uma ramificação por repositório (além de dicas anônimas para rastrear ramificações remotas), como visto nas revisões anteriores do "Mercurial: The Definitive Guide".


Em segundo lugar, ao seguir as melhores práticas de usar ramos de novos recursos , ou seja, que as sucursais recurso deve tudo início a partir da versão estável (geralmente de última release), para ser capaz de cherry-pick and selecionar quais recursos para incluir selecionando quais ramos de novos recursos para mesclar, você geralmente não estão em uma situação de avanço rápido ... o que torna esse problema discutível. Você precisa se preocupar em criar uma mesclagem verdadeira e não avançar rapidamente ao mesclar uma primeira ramificação (supondo que você não coloque alterações de confirmação única diretamente no 'master'); todas as outras mesclagens posteriores estão, obviamente, em situações de não avanço rápido.

HTH

Jakub Narębski
fonte
Com relação às ramificações de recursos de versões estáveis: E se um recurso que estou desenvolvendo para a próxima versão depender das alterações de outro recurso que eu já desenvolvi e mesclei no master? Certamente isso significa que eu tenho que criar esse segundo ramo de recursos do mestre?
dOxxx 31/05
1
@dOxxx: Sim, existem exceções, como por exemplo, onde um ramo se baseia no outro (diretamente, ou após a fusão anterior no mestre).
Jakub Narębski