Como (e por quê!) Manter seu histórico de commits Git limpo

Os commits são uma das partes principais de um repositório Git, e mais ainda, a mensagem de confirmação é um registro de vida para o repositório. Conforme o projeto / repositório evolui ao longo do tempo (novos recursos sendo adicionados, bugs sendo corrigidos, arquitetura sendo refatorada), as mensagens de commit são o lugar onde se pode ver o que foi alterado e como. Portanto, é importante que essas mensagens reflitam a mudança subjacente de uma maneira curta e precisa.

Por que um histórico de commit do Git significativo é importante

O que o commit do Git faz? Mensagens de commit do Git são as impressões digitais que você deixa no código em que toca. Qualquer código que você enviar hoje, daqui a um ano, quando olhar para a mesma mudança; você ficaria grato por uma mensagem de confirmação clara e significativa que escreveu, e também facilite a vida de seus colegas desenvolvedores. Quando os commits são isolados com base no contexto, um bug que foi introduzido por um certo commit se torna mais rápido de encontrar, e mais fácil é reverter o commit que causou o bug em primeiro lugar.

Ao trabalhar em um grande projeto, frequentemente lidamos com muitas partes móveis que são atualizadas, adicionadas ou removidas. Garantir que as mensagens de confirmação sejam mantidas em tais casos pode ser complicado, especialmente quando o desenvolvimento se estende por vários dias, semanas ou até meses. Para simplificar o esforço de manter No histórico de commits, este artigo usará algumas das situações comuns que um desenvolvedor pode enfrentar ao trabalhar em um repositório Git.

  • Situação 1: eu preciso alterar o commit mais recente
  • Situação 2: eu preciso alterar um commit específico
  • Situação 3: eu preciso adicionar, remover ou combinar commits
  • Situação 4: Meu histórico de commits não funciona sentido, eu preciso começar do zero!

Mas antes de começarmos, vejamos rapidamente como um fluxo de trabalho de desenvolvimento típico se parece em um nosso aplicativo Ruby hipotético.

Nota: Este artigo assume que você conhece os fundamentos do Git, como os branches funcionam, como adicionar mudanças não confirmadas de um branch ao estágio e como fazer o commit das mudanças. Se você não tiver certeza desses fluxos, nossa documentação é um ótimo ponto de partida.

Um dia na vida

Aqui, estamos trabalhando em um pequeno projeto Ruby on Rails, onde precisa adicionar uma visualização de navegação na página inicial e isso envolve atualizar e adicionar vários arquivos. A seguir está uma análise passo a passo de todo o fluxo:

  • Você começa a trabalhar em um recurso com a atualização de um arquivo ; vamos chamá-lo de application_controller.rb
  • Este recurso requer que você também atualize uma visualização: index.html.haml
  • Você adicionou uma parcial que é usada na página de índice: _navigation.html.haml
  • Os estilos da página também precisam ser atualizados para refletir a parcial que adicionamos: styles.css.scss
  • O recurso agora está pronto com as mudanças desejadas, é hora de também atualizar os testes; os arquivos a serem atualizados são os seguintes:
    • application_controller_spec.rb
    • navigation_spec.rb
  • Os testes estão atualizados e passando como esperado, agora é hora de confirmar as alterações!

Como todos os arquivos pertencem a diferentes territórios da arquitetura, nós nos comprometemos as alterações isoladas umas das outras para garantir que cada confirmação represente um determinado contexto e seja feita em uma determinada ordem. Eu geralmente prefiro back-end – > ordem de front-end em que a maioria das alterações centradas em backend é confirmada primeiro, seguida pela camada do meio e, em seguida, por alterações centradas em frontend nos commits da lista Git.

Agora que confirmamos nossas alterações, criamos uma solicitação de mesclagem com o branch. Depois de abrir a solicitação de mesclagem, ela normalmente é revisada por seu colega antes que as alterações sejam mescladas no branch repo “s master. Agora vamos aprender em que situações diferentes podemos acabar durante a revisão do código.

Situação 1: preciso alterar o commit mais recente

Imagine um caso em que o revisor olhou styles.css.scss e sugeriu uma mudança. Nesse caso, é muito simples fazer a mudança, pois as mudanças da folha de estilo são parte do último commit em seu branch. Veja como podemos lidar com isso;

  • Você faz diretamente as alterações necessárias em styles.css.scss em seu branch.
  • Uma vez você concluiu as alterações, adicione essas alterações ao palco; execute git add styles.css.scss.
  • Uma vez que as mudanças são testadas, precisamos adicionar essas mudanças ao nosso último commit; execute git commit --amend.
    • Divisão do comando: aqui, estamos pedindo ao comando git commit para corrigir quaisquer alterações presentes em estágio para o commit mais recente.
  • Isso abrirá seu último commit em seu editor de texto definido pelo Git, que tem a mensagem de commit Adicionar estilos para navegação.
  • Como apenas atualizamos a declaração CSS, não precisamos alterar a mensagem de confirmação.Neste ponto, você pode simplesmente salvar e sair do editor de texto que o Git abriu para você e suas mudanças serão refletidas no commit.

Já que você modificou um commit existente, essas mudanças são necessárias para ser enviado à força para seu repositório remoto usando git push --force-with-lease <remote_name> <branch_name>. Este comando substituirá o commit Add styles for navigation no repositório remoto com o commit atualizado que acabamos de fazer em nosso repositório local.

Uma coisa para manter em mente ao forçar o envio de branches é que se você está trabalhando no mesmo branch com várias pessoas, force push pode causar problemas para outros usuários quando eles tentam normalmente enviar por push suas alterações em um branch remoto que tem novos commits force enviados. Portanto, use esse recurso com sabedoria. Você pode aprender mais sobre as opções de push de força do Git aqui.

Situação 2: eu preciso alterar um commit específico

Na situação anterior, a correção era bastante simples porque tivemos que modificar apenas nosso último commit do Git, mas imagine se o revisor sugerisse mudar algo em _navigation.html.haml. Neste caso, é o segundo commit do topo, então alterá-lo não será tão direto quanto foi na primeira situação. Vamos ver como podemos lidar com isso:

Sempre que um commit é feito em uma ramificação, ele é identificado por uma string hash SHA1 exclusiva. Pense nisso como um ID único que separa um commit do outro. Você pode ver todos os commits, junto com seus hashes SHA1 em um branch executando git log. Com isso, você veria uma saída parecida com a seguinte, onde os commits mais recentes estão no topo;

É aqui que o comando git rebase entra em ação. Sempre que desejamos editar um commit específico com git rebase, precisamos primeiro realocar nosso branch movendo HEAD de volta ao ponto antes do commit que desejamos editar. Em nosso caso, precisamos alterar o commit que lê Page Navigation View.

Aqui, observe o hash do commit que está logo antes do commit que queremos modificar; copie o hash e execute as seguintes etapas:

  • Rebase o branch para mover para o commit antes de nosso commit de destino; execute o git rebase -i 8d74af102941aa0b51e1a35b8ad731284e4b5a20
    • Quebra do comando: aqui estamos executando o comando Git “s rebase com modo interativo com o hash SHA1 fornecido como commit para rebase para.
  • Isso executará o comando rebase para Git no modo interativo e abrirá seu editor de texto mostrando todos os seus commits que vieram após o commit para o qual você fez o rebase . Será mais ou menos assim:

Observe como cada commit tem uma palavra pick na frente dele, e no conteúdo abaixo, existem todas as palavras-chave possíveis que podemos usar. Visto que queremos editar um commit, precisamos mudar pick 4155df1cdc7 Page Navigation View para edit 4155df1cdc7 Page Navigation View. Salve as mudanças e saia do editor.

Agora seu branch foi realocado para o ponto no tempo antes do commit que você fez, que incluiu _navigation.html.haml. Abra o arquivo e execute as alterações desejadas de acordo com o feedback da revisão. Quando terminar de fazer as alterações, teste-as executando git add _navigation.html.haml.

Já que testamos as alterações, é hora de mover o branch HEAD de volta para o commit que tínhamos originalmente (enquanto também incluímos as novas alterações que adicionamos), execute git rebase --continue, isso abrirá seu editor padrão no terminal e mostrará a mensagem de commit que editamos durante o rebase; Page Navigation View. Você pode alterar esta mensagem se desejar, mas deixaríamos como está por enquanto, então salve e saia do editor. Neste ponto, o Git irá repetir todos os commits que seguiu após o commit que você acabou de editar e agora o branch HEAD está de volta ao commit principal que tínhamos originalmente, e também inclui as novas mudanças que você fez em um dos commits.

Uma vez que modificamos novamente um commit que já está presente no repo remoto, precisamos forçar o push deste branch novamente usando git push --force-with-lease <remote_name> <branch_name>.

Situação 3 : Eu preciso adicionar, remover ou combinar commits

Uma situação comum é quando você fez vários commits apenas para consertar algo previamente confirmado. Agora vamos reduzi-los o máximo que pudermos, combinando-os com os commits originais.

Tudo que você precisa fazer é iniciar o rebase interativo como faria nos outros cenários.

Agora imagine que você deseja combinar todas essas correções em c22a3fa0c5c Render navigation partial. Você só precisa:

  1. Mova as correções para cima para que fiquem logo abaixo do commit que você deseja manter no final.
  2. Altere pick para squash ou fixup para cada uma das correções.

Observação: squash mantém as mensagens de commits na descrição. fixup irá esquecer as mensagens de commit das correções e manter o original.

Você acabará com algo assim:

Salve as alterações e saia do editor , e pronto! Este é o histórico resultante:

Como antes, tudo que você precisa fazer agora é git push --force-with-lease <remote_name> <branch_name> e as mudanças estão acontecendo.

Se você deseja remover o commit do branch completamente, em vez de squash ou fixup, apenas escreva drop ou simplesmente exclua essa linha.

Evite conflitos

Para evitar conflitos, certifique-se de enviar seus commits “mover para cima na linha do tempo não está tocando nos mesmos arquivos tocados pelos commits deixados depois deles.

Dica profissional : Correções rápidas

Se você sabe exatamente qual commit deseja corrigir, ao fazer um commit não precisa desperdiçar ciclos cerebrais pensando em bons nomes temporários para “Correção 1”, “Correção 2”,…, “Fix 42”.

Etapa 1: Conheça --fixup

Depois de fazer as alterações corrigindo tudo o que precisa ser corrigido, apenas Git compromete todas as mudanças como esta:

(Observe que este é o hash para o commit c22a3fa0c5c Render navigation partial)

Isso irá gerar esta mensagem de commit: fixup! Render navigation partial.

Etapa 2: E o ajudante --autosquash

Rebase interativo fácil. Você pode git colocar os fixup s automaticamente no lugar certo.

git rebase -i 4155df1cdc7 --autosquash

A história será mostrada assim:

Pronto para você apenas revise e prossiga.

Se você estiver se sentindo aventureiro, pode fazer um rebase não interativo git rebase --autosquash, mas apenas se você gosta de viver perigosamente, pois ” não tenho oportunidade de revisar os squashes que estão sendo feitos antes de serem aplicados.

Situação 4: Meu histórico de commits do Git não faz sentido, eu preciso de um novo começo!

Se nós “Ao trabalhar em um grande recurso, é comum ter várias alterações de correção e feedback de revisão que estão sendo confirmadas com frequência. Em vez de rebasing constantemente o branch, podemos deixar a limpeza dos commits até o final do desenvolvimento.

É aqui que a criação de arquivos de patch é extremamente útil. Na verdade, os arquivos de patch eram a principal forma de compartilhar código por e-mail durante a colaboração em grandes projetos de código aberto antes que serviços baseados em Git como o GitLab estivessem disponíveis para desenvolvedores. Imagine que você tenha um tal branch (por exemplo; add-page-navigation) onde há toneladas de commits que não transmitem as mudanças subjacentes claramente. Veja como você pode criar um arquivo de patch para todos as mudanças que você fez neste branch:

  • A primeira etapa para criar o arquivo de patch é ter certeza de que seu branch possui todas as alterações presentes em master branch e não tem conflitos com o mesmo.
  • Você pode executar git rebase master ou git merge master enquanto você “verifica no add-page-navigation branch para obter todas as alterações de master em seu branch.
  • Agora crie o arquivo de patch ; execute git diff master add-page-navigation > ~/add_page_navigation.patch.
    • Quebra de comando: aqui, estamos usando o recurso diff do Git e pedindo uma diferença entre master branch e add-page-navigation branch, e redirecionando a saída (por meio do símbolo >) para um arquivo chamado add_page_navigation.patch em nosso nós er diretório inicial (normalmente ~/ em sistemas operacionais * nix).
  • Você pode especificar qualquer caminho que deseja manter este arquivo em e o nome do arquivo e a extensão podem ser o que você quiser.
  • Assim que o comando for executado e você não ver nenhum erro, o arquivo de patch é gerado.
  • Agora verifique master branch; execute git checkout master.
  • Exclua o branch add-page-navigation do repositório local; execute git branch -D add-page-navigation. Lembre-se, já temos mudanças deste branch em um arquivo de patch criado.
  • Agora crie um novo branch com o mesmo nome (enquanto master é retirado); execute git checkout -b add-page-navigation.
  • Neste ponto, este é um novo branch e não tem nenhuma de suas alterações.
  • Por fim, aplique suas alterações do arquivo de patch; git apply ~/add_page_navigation.patch.
  • Aqui, todas as suas alterações são aplicadas em um branch e elas aparecerão como não confirmadas, como se todas as suas modificações onde feito, mas nenhuma das modificações foi realmente confirmada no branch.
  • Agora você pode prosseguir e enviar arquivos individuais ou arquivos agrupados por área de impacto na ordem que você deseja com mensagens de confirmação concisas.

Assim como nas situações anteriores, basicamente modificamos todo o branch, então é hora de forçar o push!

Conclusão

Embora tenhamos coberto as situações mais comuns e básicas que surgem em um fluxo de trabalho diário com Git, reescrever a história do Git é um tópico vasto e conforme você se familiariza com dicas acima, você pode aprender conceitos mais avançados sobre o assunto na documentação oficial do Git. Feliz git “ing!

Foto de pan xiaozhen no Unsplash

Deixe uma resposta

O seu endereço de email não será publicado. Campos obrigatórios marcados com *