Como facilitar a vida ao usar o Git (assim como uma seleção de materiais para imersão profunda)


Tree of Dragons II por surrealistguitarist

Para quem usa o Git todos os dias, mas se sente inseguro, a equipeMail.ru Cloud Solutions traduziu um artigo do desenvolvedor front-end Shane Hudson . Aqui você encontrará alguns truques e dicas que podem facilitar um pouco o trabalho com o Git, além de uma seleção de artigos e manuais de um nível mais avançado.

Git apareceu quase 15 anos atrás. Durante esse tempo, ele passou de um azarão a um campeão invencível. Hoje, novos projetos geralmente começam com uma equipe git init. Sem dúvida, essa é uma ferramenta importante que muitos de nós usamos diariamente, mas geralmente se assemelha a mágica - brilhante, mas perigosa.

Muitos artigos foram publicados no Habr, como começar com o Git, como o Git funciona sob o capô e descrições das melhores estratégias de ramificação. Aqui, o autor focou em como simplificar o trabalho com o Git.

Colocamos as coisas em ordem


O ponto de vista do Git é salvar seu trabalho, alternar o contexto - e fazer outra coisa. Pode ser um backup do código ou a capacidade de desenvolver de forma assíncrona várias funções diferentes. Seria terrível jogar fora a segunda versão apenas porque um erro foi encontrado na primeira. Não é menos embaraçoso salvar arquivos com nomes como v1_final_bug_fixed. Como você sabe, isso leva a uma bagunça completa.

Todos sabemos que a vida se torna muito mais fácil quando nossas atualizações são organizadas de maneira organizada nos ramos do Git que você pode compartilhar com os colegas. Mas muitas vezes surgem situações quando você muda o contexto e depois volta - e não consegue encontrar o ramo certo. Houve algum comprometimento? Talvez ele esteja escondido? Talvez o commit não tenha passado, agora todos foram para o ramo errado e tudo está ruim, e eu estou fazendo um trabalho terrivelmente ruim! Sim, todos estavam lá e sentiram essas dúvidas. Existem maneiras de lidar com essa situação.

Classificar ramificações por data


A classificação por data mostra todas as suas ramificações locais, começando pela última. Bastante comum, mas me ajudou muitas vezes:

# To sort branches by commit date
git branch --sort=-committerdate

Tópico anterior


E se você não confirmar, alterne a ramificação e deseje retornar à anterior? Provavelmente, você pode encontrá-lo na lista de ramificações, se tiver alguma idéia de seu nome. Mas e se não for um ramo, mas um detached HEADcommit específico?

Acontece que existe uma saída simples:

# Checkout previous branch
git checkout -

O operador -é uma abreviação de sintaxe @{-1}que permite alternar para qualquer número de check-out. Assim, se, por exemplo, você criou uma filial feature/thing-a, em seguida feature/thing-b, e, em seguida bugfix/thing-c, o parâmetro @{-2}irá voltar para feature/thing-a:

# Checkout branch N number of checkouts ago
git checkout @{-N}

Mostrar informações sobre todas as filiais


O sinalizador vmostra uma lista de todas as ramificações com o último identificador de confirmação e mensagem. O duplo vvtambém mostrará os ramos remotos a montante, seguidos pelos ramos locais:

# List branches along with commit ID, commit message and remote
git branch -vv

Achar arquivo


Todos caímos nessa situação: de alguma maneira, um arquivo foi deixado no ramo errado. O que fazer? Refazer todo o trabalho ou copiar código de uma ramificação para outra? Felizmente, existe uma maneira de encontrar um arquivo específico.

O método é um pouco estranho, pois git checkout -leva você ao ramo anterior. Em geral, se você especificar --após o nome da filial no checkout, isso permitirá que você especifique o arquivo específico que está procurando. Você não vai adivinhar essa função sem uma dica, mas é muito conveniente se você souber:

git checkout feature/my-other-branch -- thefile.txt

Limpar status


Tomasz Lacoma twittou sobre a redução da emissão git statuscom a ajuda de bandeiras -sbe acrescentou: "Por muitos anos eu uso o Git, mas ninguém me falou sobre isso". Não se trata apenas de encontrar arquivos perdidos. Há momentos em que a simplificação do problema facilita a visualização das alterações.

A maioria dos comandos do Git possui esses sinalizadores, então você deve aprender como usá-los para personalizar seu fluxo de trabalho:

# Usually we would use git status to check what files have changed
git status

# Outputs:
On branch master
Changes not staged for commit:
(use "git add <file>..." to update what will be committed)
(use "git checkout -- <file>..." to discard changes in working directory)

modified: README.md

Untracked files:
(use "git add <file>..." to include in what will be committed)

another-file
my-new-file

# Using the flags -sb we can shorten the output
git status -sb

# Outputs:
## master
M README.md
?? another-file
?? my-new-file

Toda a história


Há momentos em que algo deu completamente errado, por exemplo, você acidentalmente descartou as alterações preparadas (preparatórias) antes de cometer. Se isso git lognão permitir que você retorne ao estado anterior e nenhuma das dicas acima ajudar, é isso git reflog.

Todas as suas ações no Git que alteram o conteúdo por referência HEAD@{}(por exemplo push/pull/branch/checkout/commit) caem no reflog (registro de referência). De fato, esta é a história de todas as suas ações, independentemente de qual ramo você esteja. Essa é a diferença com git log, que mostra as alterações para um ramo específico.


Você pode fazer git showcom o ID de confirmação - e ver a alteração específica. Se é isso que você estava procurando, ele o git checkouttransferirá para a ramificação desejada ou até permitirá que você selecione um arquivo específico, como mostrado acima:

# See the reference log of your activity
git reflog --all

# Look at the HEAD at given point from reflog
git show HEAD@{2}

# Checkout the HEAD, to get back to that point
git checkout HEAD@{2}

Preparar arquivos que perderam a confirmação


Em casos extremos, se git reflognão ajudar a recuperar seus arquivos (por exemplo, você executou uma redefinição forçada com arquivos intermediários), há mais um truque.

Cada alteração é armazenada dentro de objetos .git/objectspreenchidos com arquivos no projeto ativo, por isso é quase impossível descobrir isso. No entanto, existe um comando Git chamado git fsck, que é usado para verificar a integridade (presença de arquivos danificados) no repositório. Podemos usá-lo com um sinalizador --lost-foundpara procurar todos os arquivos não relacionados a uma confirmação. Esses arquivos são chamados de "dangling blob".

Este comando também permite encontrar "árvores suspensas" e "confirmações suspensas". Se você quiser, pode usar a bandeira --dangling, mas a vantagem--lost-foundna medida em que extrai todos os arquivos relevantes em uma pasta .git/lost-found. Provavelmente, em um projeto ativo, você terá muitos desses arquivos "travados". O Git possui um comando de descarte de lixo que é executado regularmente e os remove.

Assim, --lost-foundmostrará todos os arquivos e a hora / data da criação, o que facilita muito a pesquisa. Observe que cada arquivo separado ainda estará separado, ou seja, você não pode usar o checkout. Além disso, todos os arquivos terão nomes incompreensíveis (hash), portanto, você deve copiar os arquivos necessários para outro local:

# This will find any change that was staged but is not attached to the git tree
git fsck --lost-found

# See the dates of the files
ls -lah .git/lost-found/other/

# Copy the relevant files to where you want them, for example:
cp .git/lost-found/other/73f60804ac20d5e417783a324517eba600976d30 index.html

Git no trabalho em equipe


Usar o Git sozinho é uma coisa, mas quando você trabalha em uma equipe de pessoas, geralmente com experiências, habilidades e ferramentas completamente diferentes, o Git pode ser uma bênção e uma maldição. Essa é uma ferramenta poderosa para compartilhar a mesma base de código, conduzindo uma revisão de código e monitorando o progresso de toda a equipe. Ao mesmo tempo, todos os funcionários precisam ter um entendimento comum de como usá-lo no trabalho em equipe. Independentemente do que seja: a convenção de nomear as ramificações, formatar a mensagem que acompanha a confirmação ou escolher quais arquivos incluir na confirmação, é importante garantir uma boa comunicação e concordar em como usar essa ferramenta.

É sempre importante garantir a simplicidade da integração para iniciantes e pensar no que acontecerá se eles começarem a se comprometer sem conhecer os princípios e convenções adotados pela empresa. Este não é o fim do mundo, mas pode causar alguma confusão e levar tempo para retornar a uma abordagem coordenada.

Esta seção contém algumas recomendações sobre como integrar os acordos aceitos diretamente no próprio repositório, automatizar e emitir o número máximo de tarefas nas declarações. No caso ideal, qualquer novo funcionário quase imediatamente começa a trabalhar no mesmo estilo que o resto da equipe.

As mesmas terminações de linha


Por padrão, o Windows usa terminações de linha do DOS \r\n(CRLF), enquanto o Mac e Linux usam as terminações de linha UNIX \n(LF), enquanto as versões mais antigas do Mac \r(CR). Assim, à medida que a equipe cresce, o problema de terminações incompatíveis de linha se torna mais provável. Isso é inconveniente, pois eles (geralmente) não quebram o código, mas por causa deles, as confirmações e solicitações de pool mostram várias alterações irrelevantes. Muitas vezes, as pessoas simplesmente as ignoram, porque é bastante problemático andar por aí e alterar todas as terminações de linhas erradas.

Existe uma solução - você pode pedir a todos os membros da equipe para definir suas configurações locais para o preenchimento automático da linha:

# This will let you configure line-endings on an individual basis
git config core.eol lf
git config core.autocrlf input

Obviamente, você precisa se inscrever para esta convenção e um iniciante, o que é fácil de esquecer. Como fazer isso para toda a equipe? De acordo com o algoritmo de trabalho, o Git verifica a presença de um arquivo de configuração no repositório .git / config, depois a configuração do usuário em todo o sistema ~/.gitconfige a configuração global /etc/gitconfig.

Tudo isso é bom, mas acontece que nenhum desses arquivos de configuração pode ser instalado através do próprio repositório. Você pode adicionar configurações específicas do repositório, mas elas não se estenderão a outros membros da equipe.

No entanto, há um arquivo que está realmente confirmado no repositório. É chamado de .gitattributes . Por padrão, você não o possui, então crie um novo arquivo e salve-o como*.gitattributes*. Ele define atributos para cada arquivo. Por exemplo, você pode forçar o git diff a usar cabeçalhos exif de arquivos de imagem em vez de tentar calcular a diferença em arquivos binários. Nesse caso, podemos usar um curinga para que a configuração funcione para todos os arquivos, agindo, de fato, como um arquivo de configuração comum para todo o comando:

# Adding this to your .gitattributes file will make it so all files
# are checked in using UNIX line endings while letting anyone on the team
# edit files using their local operating system’s default line endings.
* text=auto

Ocultar automaticamente


É habitual adicionar arquivos compilados (como node_modules/) ao .gitignore para que eles sejam armazenados localmente e não sejam carregados no repositório. No entanto, às vezes você ainda deseja fazer upload do arquivo, mas não deseja encontrá-lo mais tarde, sempre na solicitação de pool.

Nesta situação (pelo menos no GitHub), você pode adicionar caminhos marcados a .gitattributes linguist-generatede verifique se .gitattributes está na pasta raiz do repositório. Isso ocultará os arquivos na solicitação de pool. Eles serão "minimizados": você ainda pode ver o fato da alteração, mas sem o código completo.

Tudo o que reduz o estresse e a carga cognitiva no processo de revisão de código melhora sua qualidade e reduz o tempo.

Por exemplo, você deseja adicionar arquivos de recurso (ativo) ao repositório, mas não os modifica e rastreia posteriormente, para poder adicionar a seguinte linha ao arquivo com atributos:

*.asset linguist-generated

Use a culpa git com mais frequência


O artigo de Harry Roberts , “Pequenas coisas que eu gosto de fazer com o Git” recomenda git blame(atribuir git praisetradução ) para atribuir um apelido (traduzindo da tradução “inglês”) para sentir essa equipe como uma ação positiva. Evidentemente, renomear não altera o comportamento da equipe. Mas sempre que a discussão surge com o uso de uma função git blame, todo mundo fica tenso, e é claro que eu também. É natural perceber a palavra culpa (culpa) como algo negativo ... mas isso está completamente errado!

Uma função poderosa git blame (ou git praise, se você quiser) mostra quem foi o último a trabalhar com esse código. Não vamos culpá-lo ou elogiá-lo, apenas queremos esclarecer a situação. Torna-se mais claro quais perguntas fazer e para quem, o que economiza tempo.

Deve ser apresentado git blamenão apenas como algo bom, mas também como um meio de comunicação que ajuda toda a equipe a reduzir o caos e não perder tempo descobrindo quem sabe o quê. Alguns IDEs, como o Visual Studio, ativam esse recurso como anotações. Para cada função, você vê instantaneamente quem a alterou pela última vez (e, portanto, com quem falar sobre isso).

Culpa git analógica por arquivos ausentes


Recentemente, vi um desenvolvedor de nossa equipe tentando descobrir quem excluiu um arquivo, quando e por quê. Parece que pode ajudar aqui git blame, mas funciona com as linhas do arquivo e é inútil se o arquivo estiver ausente.

No entanto, existe outra solução. Velho fiel git log. Se você olhar o log sem argumentos, verá uma longa lista de todas as alterações no ramo atual. Você pode adicionar um identificador de confirmação para ver o log desse commit específico, mas se você especificar --(que usamos anteriormente para direcionar um arquivo específico), poderá obter um log para um arquivo - mesmo que não exista mais:

# By using -- for a specific file,
# git log can find logs for files that were deleted in past commits
git log -- missing_file.txt

Modelo de Mensagem de Confirmação


As mensagens de confirmação geralmente precisam ser aprimoradas. Mais cedo ou mais tarde, os desenvolvedores da equipe chegaram a essa conclusão. Existem muitas maneiras de melhorar. Por exemplo, você pode consultar identificadores de bug de uma ferramenta interna de gerenciamento de projetos ou talvez incentivar a escrita de pelo menos algum texto em vez de uma mensagem em branco.

Este comando precisa ser executado manualmente toda vez que alguém clona o repositório, pois os arquivos de configuração não são confirmados no repositório. No entanto, é conveniente porque você pode criar um arquivo comum com qualquer nome que atue como um modelo de mensagem de confirmação:

# This sets the commit template to the file given,
# this needs to be run for each contributor to the repository.
git config commit.template ./template-file

Git para automação


Git é uma poderosa ferramenta de automação. Isso não é imediatamente óbvio, mas pense por si mesmo: ele vê toda a sua atividade no repositório - mais a atividade de outros participantes - e ele possui muitas informações que podem ser muito úteis.

Ganchos Git


Com frequência, você vê que os membros da equipe realizam tarefas repetitivas enquanto trabalham. Pode ser um teste de aprovação nos testes e interconexão antes de enviar uma ramificação para o servidor (gancho antes de enviar) ou uma estratégia forçada para nomear ramificações (gancho antes de confirmar). Sobre esse assunto, Konstantinos Lamonis escreveu um artigo na Revista Smashing intitulado "Como simplificar o fluxo de trabalho usando Git Hooks" .

Automação manual


Um dos principais recursos de automação do Git é o git bisect. Muitos já ouviram falar, mas poucos o usam. A linha inferior está processando a árvore Git (histórico de consolidação) e descobrindo onde o erro foi inserido.

A maneira mais fácil de fazer isso é manualmente. Você inicia git bisect start, define os identificadores de confirmações boas e ruins (onde não há erro e onde existe um erro) e, em seguida, executa git bisect goodou git bisect badpara cada confirmação.

Esse é um recurso mais poderoso do que parece à primeira vista, porque não executa o log do Git linearmente, o que poderia ser feito manualmente como um processo iterativo. Em vez disso, ele usa uma pesquisa binária que efetivamente passa por confirmações com o menor número de etapas:

# Begin the bisect
git bisect start

# Tell git which commit does not have the bug
git bisect good c5ba734

# Tell git which commit does have the bug
git bisect bad 6c093f4

# Here, do your test for the bug.
# This could be running a script, doing a journey on a website, unit test etc.

# If the current commit has bug:
git bisect bad

# If the current commit does not have the bug
git bisect good

# This will repeat until it finds the first commit with the bug
# To exit the bisect, either:

# Go back to original branch:
git bisect reset

# Or stick with current HEAD
git bisect reset HEAD

# Or you can exit the bisect at a specific commit
git bisect reset <commit ID>

Seguindo em frente: Automação científica


Em seu relatório de depuração científica, Stuart Halloway explicou como usar o comando git bisectpara automatizar a depuração.
Ele se concentra em Clojure, mas não precisamos conhecer esse idioma para se beneficiar de sua palestra.

O Git bisect é parcialmente uma automação científica. Você escreve um pequeno programa que irá testar alguma coisa, e o Git pula para frente e para trás, cortando o mundo ao meio a cada salto, até encontrar a borda na qual seu teste muda de estado.
Stuart Halloway

No começo, git bisectpode parecer um recurso interessante e bastante interessante, mas no final não é muito útil. O desempenho de Stewart mostra, em grande medida, que é realmente contraproducente depurar como estamos acostumados. Se, em vez disso, você se concentrar em fatos empíricos, independentemente de o teste passar ou não, poderá executá-lo em todos os commits, começando com a versão de trabalho, e reduzir a sensação de "vagando no escuro" a que estamos acostumados.

Então, como automatizamosgit bisect? Você pode passar um script para cada confirmação correspondente. Anteriormente, eu disse que você pode executar manualmente o script em cada etapa da divisão, mas se você passar um comando para executar, ele executará automaticamente o script em cada etapa. Pode ser um script específico para depurar esse problema específico ou um teste (modular, funcional, integração, qualquer tipo de teste). Portanto, você pode escrever um teste para verificar se a regressão não se repete e executar esse teste nas confirmações anteriores:

# Begin the bisect
git bisect start

# Tell git which commit does not have the bug
git bisect good c5ba734

# Tell git which commit does have the bug
git bisect bad 6c093f4

# Tell git to run a specific script on each commit
# For example you could run a specific script:
git bisect run ./test-bug

# Or use a test runner
git bisect run jest

Em todo commit passado


Um dos pontos fortes git bisecté o uso eficaz da pesquisa binária para ignorar todos os eventos da história de maneira não linear. Mas, às vezes, é necessário um desvio linear. Você pode escrever um script que leia o log do Git e percorra o código em todas as confirmações. Mas há um amigo, que vai fazer isso por você: git rebase.

Kamran Ahmed, em um tweet escrito como rebaseestá, qual commit não passa no teste:

Encontre uma confirmação que falha no teste:

$ git rebase -i --exec "yarn test" d294ae9

O comando executa o teste do fio em todas as confirmações entre d294ae9 e HEAD e para na confirmação em que o teste falha.

Já consideramos git bisectessa tarefa, que pode ser mais eficiente, mas, neste caso, não estamos limitados a um caso de uso.

Há um lugar para a criatividade. Talvez você queira gerar um relatório sobre como o código mudou ao longo do tempo (ou mostrar o histórico dos testes), e apenas analisar o log do Git não é suficiente. Talvez este não seja o truque mais útil deste artigo, mas é interessante e mostra uma tarefa, cuja realidade não acreditávamos antes:

# This will run for every commit between current and the given commit ID
git rebase -i --exec ./my-script

Uma seleção de artigos e manuais para ajudá-lo a se aprofundar no Git


Nesse artigo, é impossível aprofundar o assunto, caso contrário, você receberá um livro inteiro. Eu escolhi alguns pequenos truques que até usuários experientes podem não conhecer. Mas o Git tem muito mais recursos: de funções básicas a scripts complexos, configurações precisas e integração de console. Portanto, aqui estão alguns recursos que podem ser do seu interesse:

  1. Explorer git . Um site interativo que ajuda você a entender facilmente como alcançar o que deseja.
  2. Dang it git! . Em algum momento, cada um de nós pode se perder no Git e não sabe como resolver nenhum problema. Este site fornece soluções para muitos dos problemas mais comuns.
  3. Pro git . Este livro gratuito é um recurso inestimável para entender o Git.
  4. Git Docs. — . , Git Docs, Git (, man git-commit) Git .
  5. Thoughtbot. Git Thoughtbot .
  6. Git. Git.
  7. Git. , … . Git, .
  8. Git: do iniciante ao avançado . Mike Ritmüller escreveu este artigo útil, ideal para usuários iniciantes do Git.
  9. Pequenas coisas que eu amo fazer com o Git . Foi este artigo de Harry Roberts que me fez perceber quantas possibilidades ainda existem no Git, além de mover o código entre as filiais.
  10. Guias Atlitian Advanced Git . Esses tutoriais detalham muitos dos tópicos mencionados neste artigo.
  11. Folha de dicas do Git no Github . É sempre conveniente ter uma boa folha de dicas para ferramentas como o Git.
  12. Redução de Git . Este artigo detalha vários sinalizadores de comando Git e recomenda vários aliases.

Mas o que mais você pode ler :

  1. Git. №1: , .git
  2. Git. №2: rebase.
  3. .

All Articles