Por que o squash git se compromete com solicitações pull?

159

Por que todo repositório sério do Github eu faço pedidos para que eu faça meus commits em um único commit?

Eu achei que o log do git estava lá, então você poderia inspecionar todo o seu histórico e ver exatamente quais mudanças aconteceram, mas, esmagando, ele puxa para fora do histórico e coloca tudo em um commit. Qual é o ponto?

Isso também parece ir contra o mantra "comprometer-se cedo e cometer muitas vezes".

    
por hamstar 18.11.2014 / 23:41
fonte

5 respostas

140

Para que você tenha um histórico claro e conciso do git que documenta de maneira clara e fácil as alterações feitas e os motivos.

Por exemplo, um típico log do Git 'não confinado' pode ser parecido com o seguinte:

7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
787g8fgf78... hotfix for #5849564648
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Que bagunça!

Considerando que um log git mais cuidadosamente gerenciado e mesclado com um pouco de foco adicional nas mensagens para isso pode parecer:

7hgf8978g9... 8483948393 Added new slideshow feature
787g8fgf78... 5849564648 Hotfix for android display issue
9080gf6567... 6589685988 Implemented pop-up to select language

Eu acho que você pode ver o ponto de esmagar commits geralmente e o mesmo princípio se aplica a pull requests - Readability of the History. Você também pode estar adicionando a um log de commit que já tem centenas ou até mesmo milhares de commits e isso ajudará a manter a história crescente curta e concisa.

Você quer se comprometer com antecedência e com frequência. É uma prática recomendada por vários motivos. Eu acho que isso me leva a freqüentemente ter commits que são "wip" (trabalho em andamento) ou "parte A done" ou "typo, minor fix" onde estou usando o git para me ajudar a trabalhar e me dar pontos de trabalho que Eu posso voltar se o seguinte código não estiver funcionando enquanto eu progrido para fazer as coisas funcionarem. No entanto, eu não preciso ou quero esse histórico como parte do histórico final do git para que eu possa esmagar meus commits - mas veja as notas abaixo sobre o que isso significa em um branch de desenvolvimento vs. master.

Se houver marcos importantes que representem estágios de trabalho distintos, ainda é aceitável ter mais de um commit por recurso / tarefa / bug. No entanto, isso pode destacar o fato de que o ticket em desenvolvimento é 'muito grande' e precisa ser dividido em partes menores que podem ser autônomas, por exemplo:

8754390gf87... Implement feature switches

parece "1 trabalho". Ou eles existem ou não! Parece que não faz sentido quebrá-lo. No entanto, a experiência me mostrou que (dependendo do tamanho e da complexidade da organização) um caminho mais granular poderia ser:

fgfd7897899... Add field to database, add indexes and a trigger for the dw group
9458947548g... Add 'backend' code in controller for when id is passed in url.
6256ac24426... Add 'backend' code to make field available for views.
402c476edf6... Add feature to UI

Pequenas peças significam revisões de código mais fáceis, testes de unidade mais fáceis, melhor oportunidade para qa, melhor alinhamento ao Princípio de Responsabilidade Única, etc.

Para os aspectos práticos de quando realmente fazer tais abóboras, há basicamente dois estágios distintos que têm seu próprio fluxo de trabalho

  • seu desenvolvimento, por exemplo puxar pedidos
  • seu trabalho adicionado à ramificação da linha principal, por exemplo mestre

Durante o seu desenvolvimento você se compromete 'cedo e freqüentemente' e com mensagens rápidas 'descartáveis'. Você pode querer esmagar aqui às vezes, por exemplo squashing em wip e todo commit de mensagens. Está tudo bem, dentro do ramo, manter vários commits que representam etapas distintas feitas no desenvolvimento. A maioria das abóboras que você escolhe fazer deve estar dentro dessas ramificações de recursos, enquanto elas estão sendo desenvolvidas e antes de mesclar para mestre. Ao adicionar à ramificação da linha principal, você deseja que as confirmações sejam concisas e formatadas corretamente de acordo com o histórico da linha principal existente. Isso pode incluir o ID do sistema do Ticket Tracker, por exemplo, JIRA como mostrado nos exemplos. A prática de squashing não se aplica realmente a menos que você queira 'fazer roll-up' de vários commits distintos no master. Normalmente você não faz.

Usar --no-ff ao mesclar para o mestre usará uma confirmação para a mesclagem e também preservará o histórico (na ramificação). Algumas organizações consideram isso uma boa prática. Veja mais em link Você também verá o efeito prático em git log , em que --no-ff commit será o último commit , no topo da HEAD (quando acabou de fazer), enquanto que sem --no-ff pode estar mais abaixo na história, dependendo das datas e outros commits.

    
por 19.11.2014 / 01:26
fonte
21

Porque muitas vezes a pessoa que puxa um PR se preocupa com o efeito final dos commits "recurso adicionado X", não sobre os "templates base, função bugfix X, adicionar função Y, erros de digitação nos comentários, parâmetros ajustados de escala de dados, hashmap executa melhor que a lista "... nível de detalhe

Se você acha que seus 16 commits são melhor representados por 2 commits ao invés de 1 "Adicionado o recurso X, re-fatorado Z para usar X" então provavelmente é bom propor um pr com 2 commits, mas então pode ser É melhor propor 2 prs separados nesse caso (se o repo ainda insistir em um commit único)

Isso não vai contra o mantra "comprometer-se cedo e comprometer-se com frequência", como em seu repo, enquanto você está desenvolvendo, ainda tem detalhes granulares, então você tem poucas chances de perder o trabalho e outras pessoas podem revisar / puxar / propor pr's contra o seu trabalho enquanto o novo pr está sendo desenvolvido.

    
por 19.11.2014 / 00:25
fonte
13

A principal razão do que eu vejo é a seguinte:

  • A IU do GitHub para mesclar solicitações de recebimento atualmente (outubro de 2015) não permite editar a primeira linha da mensagem de confirmação, forçando-a a ser Merge pull request #123 from joebloggs/fix-snafoo
  • A interface do usuário do GitHub para navegar no histórico de confirmações no momento não permite que você visualize o histórico da ramificação do ponto de vista --first-parent
  • A interface do usuário do GitHub para ver a culpa em um arquivo no momento não permite que você veja a culpa do arquivo com o ponto de vista --first-parent (observe que isso só foi corrigido no Git 2.6.2, então poderíamos perdoe o GitHub por não ter isso disponível)

Então, quando você combina todas as três situações acima, você obtém uma situação em que os commits não-confinados sendo mesclados ficam feios na interface do usuário do GitHub.

Seu histórico com commits squashed será parecido com

1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... Hotfix for android display issue
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... Implemented pop-up to select language

Considerando que, sem que o squashed cometa, o histórico será parecido com

1256556316... Merge pull request #423 from jrandom/add-slideshows
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... Merge pull request #324 from ahacker/fix-android-display
787g8fgf78... hotfix for #5849564648
f56556316e... Merge pull request #28 from somwhere/select-lang-popup
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Quando você tem muitos commits em um rastreio de RP onde uma mudança chegou, pode se tornar um pesadelo se você se restringir a usar a interface do GitHub .

Por exemplo, você encontra um ponteiro nulo sendo des-referenciado em algum lugar em um arquivo ... então você diz "quem fez isto e quando? que versões de lançamento são afetadas?". Então você perambula para a visão de culpa na interface do GitHub e vê que a linha foi alterada em 789fdfffdf ... "oh, mas espere um segundo, essa linha estava apenas tendo seu recuo alterado para se ajustar ao restante do código ", então agora você precisa navegar para o estado da árvore para o arquivo no commit pai e visitar novamente a página de culpa ... eventualmente você encontra o commit ... é um commit de 6 meses atrás ..." oh **** isso pode estar afetando os usuários por 6 meses "você diz ... ah, mas espere, esse commit foi na verdade em um Pull Request e só foi fundido ontem e ninguém cortou um release ainda ..." Maldito povo por fusão de commits sem squashing history "é o choro que geralmente pode ser ouvido após cerca de 2 ou 3 expedições de arqueologia de código através da interface do usuário do GitHub

Agora vamos considerar como isso funciona se você usar a linha de comando do Git (e super incrível 2.6.2 que tem a correção para git blame --first-parent )

  • Se você estivesse usando a linha de comando do Git, seria capaz de controlar completamente a mensagem de consolidação de mesclagem e, assim, a consolidação de mesclagem poderia ter uma boa linha de resumo.

Nosso histórico de commits seria

$ git log
1256556316... #423 Added new slideshow feature
7hgf8978g9... Added new slideshow feature, JIRA # 848394839
85493g2458... Fixed slideshow display issue in ie
gh354354gh... wip, done for the week
789fdfffdf... minor alignment issue
56556316ad... #324 Hotfix for android display issue
787g8fgf78... hotfix for #5849564648
f56556316e... #28 Implemented pop-up to select language
9080gf6567... implemented feature # 65896859
gh34839843... minor fix (typo) for 3rd test

Mas também podemos fazer

$ git log --first-parent
1256556316... #423 Added new slideshow feature
56556316ad... #324 Hotfix for android display issue
f56556316e... #28 Implemented pop-up to select language

(Em outras palavras: o Git CLI permite que você tenha seu bolo e coma também)

Agora, quando atingimos o problema de ponteiro nulo ... bem, usamos apenas git blame --first-parent -w dodgy-file.c e recebemos imediatamente a confirmação exata em que a referência de ponteiro nulo foi introduzida na ramificação principal, ignorando alterações simples de espaço em branco.

É claro que se você estiver fazendo mesclagens usando a interface do usuário do GitHub, então git log --first-parent é realmente ruim graças ao GitHub forçando a primeira linha da mensagem de consolidação de mesclagem:

1256556316... Merge pull request #423 from jrandom/add-slideshows
56556316ad... Merge pull request #324 from ahacker/fix-android-display
f56556316e... Merge pull request #28 from somwhere/select-lang-popup

Então, para encurtar uma longa história:

A interface do usuário do GitHub (outubro de 2015) tem várias deficiências em como ela mescla as solicitações de recebimento, como apresenta o histórico de confirmações e como ele atribui informações sobre culpas. A melhor maneira atual de contornar esses defeitos na interface do GitHub é solicitar que as pessoas cancelem seus commits antes da fusão.

O Git CLI não tem esses problemas e você pode facilmente escolher qual visualização você quer ver para que você possa descobrir o motivo pelo qual uma mudança em particular foi feita dessa forma (observando o histórico dos commits sem restrições) bem como ver os commits efetivamente esmagados.

Post Script

A razão final frequentemente citada para commits de squash é tornar o backport mais fácil ... se você tiver apenas um commit para backport (ou seja, o commit esmagado) então é fácil escolher ...

Bem, se você está olhando para o histórico do git com git log --first-parent , você pode simplesmente selecionar os commits de mesclagem. A maioria das pessoas se confunde com commits porque você tem que especificar a opção -m N mas se você obteve o commit de git log --first-parent então você sabe que é o primeiro pai que você quer seguir será git cherry-pick -m 1 ...

    
por 20.10.2015 / 11:18
fonte
1

Concordo com os sentimentos expressos em outras respostas neste tópico sobre como mostrar um histórico claro e conciso dos recursos adicionados e dos bugs corrigidos. No entanto, quis abordar outro aspecto ao qual sua pergunta escapou, mas não declarou explicitamente. Parte do hangup que você pode ter sobre alguns dos métodos de trabalho do git é que o git permite que você reescreva o histórico que parece estranho ao ser introduzido no git depois de usar outras formas de controle de origem onde tais ações são impossíveis. Além disso, isso também vai contra o princípio geralmente aceito de controle de origem de que, uma vez que algo é confirmado / registrado no controle de origem, você deve ser capaz de reverter para esse estado, não importando as alterações feitas após o commit. Como você insinua em sua pergunta, esta é uma daquelas situações. Eu acho que o git é um ótimo sistema de controle de versão; no entanto, para entendê-lo, você deve entender alguns detalhes de implementação e decisões de design por trás dele e, como resultado, ele tem uma curva de aprendizado mais acentuada. Tenha em mente que o git deveria ser um sistema de controle de versão distribuído e isso ajudará a explicar por que os designers permitem que o histórico do git seja reescrito, com commits de squash sendo um exemplo disso.

    
por 22.11.2014 / 21:21
fonte
0

Por causa da perspectiva ... A melhor prática é ter um único commit por single <<issue-management-system>> issue, se possível.

Você pode ter quantos commits quiser em sua própria feature branch / repo, mas é seu histórico relevante para o que você está fazendo agora para a sua perspectiva ... não é ele HISTORY para toda a TEAM / PROJECT ou aplicação de sua perspectiva para ser mantida daqui a vários meses ...

Então, sempre que você quiser enviar uma correção de bug ou um recurso para um repositório comum (este exemplo é com o ramo de desenvolvimento), o que você poderia fazer da seguinte maneira:

como redefinir seu ramo de recursos para desenvolver rapidamente

    # set your current branch , make a backup of it , caveat minute precision
    curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr

    # squash all your changes at once 
    git reset $(git merge-base develop $curr_branch)

    # check the modified files to add 
    git status

    # add the modified files dir by dir, or file by file or all as shown
    git add --all 

    # check once again 
    git log --format='%h %ai %an %m%m %s'  | less

    # add the single message of your commit for the stuff you did 
    git commit -m "<<MY-ISSUE-ID>>: add my very important feature"

    # check once again 
    git log --format='%h %ai %an %m%m %s'  | less

    # make a backup once again , use seconds precision if you were too fast ... 
    curr_branch=$(git rev-parse --abbrev-ref HEAD); git branch "$curr_branch"--$(date "+%Y%m%d_%H%M"); git branch -a | grep $curr_branch | sort -nr

    # compare the old backup with the new backup , should not have any differences 
    git diff <<old-backup>>..<<new-backup-branch>>


    # you would have to git push force to your feature branch 
    git push --force 
    
por 10.04.2018 / 11:14
fonte