GitHub Flow

Problemas com git-flow

Viajo por todo o lado ensinando Git às pessoas e quase todas as aulas e workshops que fiz recentemente me perguntaram o que eu penso sobre git-flow. Eu sempre respondo que eu acho que é ótimo – foi preciso um sistema (Git) que tem um milhão de fluxos de trabalho possíveis e documentou um fluxo de trabalho bem testado e flexível que funciona para muitos desenvolvedores de uma maneira bastante simples. Ele se tornou algo como um padrão para que os desenvolvedores possam se mover entre projetos ou empresas e estar familiarizados com este fluxo de trabalho padronizado.

No entanto, ele tem seus problemas. Ouvi uma série de opiniões de pessoas ao longo da linha de não gostar que novos ramos de recursos sejam iniciados de develop em vez de master, ou a maneira como ele lida com hotfixes, mas esses são bastante menores.

Um dos maiores problemas para mim é que é mais complicado do que eu acho que a maioria dos desenvolvedores e equipes de desenvolvimento realmente precisam. É complicado o suficiente que um grande script de ajuda tenha sido desenvolvido para ajudar a reforçar o fluxo. Embora isso seja legal, a questão é que ele não pode ser executado em uma GUI Git, apenas na linha de comando, então as únicas pessoas que têm que aprender o fluxo de trabalho complexo muito bem, porque eles têm que fazer todos os passos manualmente, são as mesmas pessoas que não estão confortáveis com o sistema o suficiente para usá-lo a partir da linha de comando. Isto pode ser um enorme problema.

Alguns destes problemas podem ser resolvidos facilmente apenas por ter um processo muito mais simplificado. No GitHub, nós não usamos o git-flow. Nós usamos, e sempre usamos, um fluxo de trabalho de Git muito mais simples.

A simplicidade do GitHub nos dá uma série de vantagens. Uma delas é que é fácil para as pessoas entenderem, o que significa que elas podem pegá-lo rapidamente e raramente, se alguma vez errarem ou tiverem que desfazer passos que fizeram errado. Outra é que nós não precisamos de um script wrapper para ajudar a aplicá-lo ou segui-lo, então usar GUIs e tais não são um problema.

GitHub Flow

Então, por que não usamos o git-flow no GitHub? Bem, a questão principal é que nós implantamos o tempo todo. O processo de git-flow é projetado em grande parte em torno do “release”. Nós realmente não temos “releases” porque nós implantamos para produção todos os dias – muitas vezes várias vezes ao dia. Nós podemos fazer isso através do nosso robô de chat room, que é o mesmo lugar onde os nossos resultados de CI são exibidos. Tentamos tornar o processo de teste e envio o mais simples possível para que todos os funcionários se sintam à vontade para fazê-lo.

Há uma série de vantagens em implantar tão regularmente. Se você implantar a cada poucas horas, é quase impossível introduzir um grande número de grandes bugs. Pequenos problemas podem ser introduzidos, mas então eles podem ser corrigidos e redistribuídos muito rapidamente. Normalmente você teria que fazer um ‘hotfix’ ou algo fora do processo normal, mas é simplesmente parte do nosso processo normal – não há diferença no fluxo do GitHub entre um hotfix e um recurso muito pequeno.

Uma outra vantagem de se implantar o tempo todo é a habilidade de resolver rapidamente problemas de todos os tipos. Podemos responder a questões de segurança que são trazidas à nossa atenção ou implementar pequenos mas interessantes pedidos de recursos incrivelmente rapidamente, ainda assim podemos usar exatamente o mesmo processo para lidar com essas mudanças como fazemos para lidar com o desenvolvimento normal ou mesmo de recursos grandes. É tudo o mesmo processo e é tudo muito simples.

How We Do It

Então, o que é o GitHub Flow?

  • Qualquer coisa no ramo master é implementável
  • Para trabalhar em algo novo, crie um ramo de nome descritivo de master (ou seja: new-oauth2-scopes)
  • Comprometa-se localmente com esse ramo e empurre regularmente seu trabalho para o mesmo ramo nomeado no servidor
  • Quando você precisar de feedback ou ajuda, ou você achar que o ramo está pronto para fusão, abra um pedido de puxar
  • Depois de alguém ter revisto e assinado a funcionalidade, você pode fundi-la em master
  • Após ser fundida e empurrada para ‘master’, você pode e deve implantar imediatamente

Esse é o fluxo inteiro. É muito simples, muito eficaz e funciona para equipes bastante grandes – GitHub tem 35 funcionários agora, talvez 15-20 dos quais trabalham no mesmo projeto (github.com) ao mesmo tempo. Eu acho que a maioria das equipes de desenvolvimento – grupos que trabalham no mesmo código lógico ao mesmo tempo, o que poderia produzir conflitos – estão em torno deste tamanho ou menores. Especialmente aqueles que são progressivos o suficiente para fazer implementações rápidas e consistentes.

Então, vamos olhar cada um destes passos por sua vez.

#1 – qualquer coisa no ramo mestre é implementável

Esta é basicamente a única regra difícil do sistema. Há apenas um branch que tem algum significado específico e consistente e nós o nomeamos master. Para nós, isto significa que ele foi implantado ou no pior dos casos será implantado em poucas horas. É incrivelmente raro que isto seja rebobinado (o ramo é movido de volta para um commit antigo para reverter o trabalho) – se houver um problema, commits serão revertidos ou novos commits serão introduzidos para corrigir o problema, mas o ramo em si quase nunca é rebobinado.

O ramo master é estável e é sempre, sempre seguro implantar a partir dele ou criar novos ramos fora dele. Se você empurrar algo para dominar que não é testado ou quebra a construção, você quebra o contrato social da equipe de desenvolvimento e você normalmente se sente muito mal com isso. Cada branch que empurramos tem testes executados nele e reportados na sala de chat, então se você não os executou localmente, você pode simplesmente empurrar para um branch tópico (mesmo um branch com um único commit) no servidor e esperar que Jenkins lhe diga se ele passa tudo.

Você poderia ter um branch deployed que é atualizado apenas quando você implanta, mas nós não fazemos isso. Nós simplesmente expomos o SHA atualmente implantado através do próprio webapp e curl ele se precisarmos de uma comparação feita.

#2 – criar ramos descritivos do master

Quando você quer começar a trabalhar em qualquer coisa, você cria um ramo de nome descritivo do estável master ramo. Alguns exemplos na base de código do GitHub neste momento seriam user-content-cache-key, submodules-init-task ou redis2-transition. Isto tem várias vantagens – uma é que quando você vai buscar, você pode ver os tópicos que todos os outros têm trabalhado. Outra é que se você abandonar um branch por um tempo e voltar a ele mais tarde, é bastante fácil lembrar o que foi.

Isso é bom porque quando vamos à página da lista de branches do GitHub podemos facilmente ver quais branches foram trabalhados recentemente e aproximadamente quanto trabalho eles têm neles.

github branch list

É quase como uma lista de funcionalidades futuras com o estado bruto atual. Esta página é fantástica se você não estiver usando-a – ela só mostra ramos que têm um trabalho único em relação ao seu ramo atualmente selecionado e os classifica de modo que os mais recentemente trabalhados estejam no topo. Se eu ficar realmente curioso, eu posso clicar no botão ‘Comparar’ para ver qual é a lista unificada de diff e commit que é única para aquele branch.

Então, a partir desta escrita, nós temos 44 branches no nosso repositório com trabalho não unificado neles, mas eu também posso ver que apenas 9 ou 10 deles foram empurrados na última semana.

#3 – empurrar para ramos nomeados constantemente

Outra grande diferença do git-flow é que nós empurramos para ramos nomeados no servidor constantemente. Como a única coisa com que realmente temos que nos preocupar é master do ponto de vista da implantação, empurrar para o servidor não atrapalha ninguém ou confunde as coisas – tudo o que não é master é simplesmente algo sendo trabalhado.

Também garante que nosso trabalho seja sempre feito o backup em caso de perda do laptop ou falha do disco rígido. Mais importante ainda, ele coloca todos em constante comunicação. Um simples ‘git fetch’ basicamente lhe dará uma lista TODO do que todos estão trabalhando no momento.

$ git fetchremote: Counting objects: 3032, done.remote: Compressing objects: 100% (947/947), done.remote: Total 2672 (delta 1993), reused 2328 (delta 1689)Receiving objects: 100% (2672/2672), 16.45 MiB | 1.04 MiB/s, done.Resolving deltas: 100% (1993/1993), completed with 213 local objects.From github.com:github/github * charlock-linguist -> origin/charlock-linguist * enterprise-non-config -> origin/enterprise-non-config * fi-signup -> origin/fi-signup 2647a42..4d6d2c2 git-http-server -> origin/git-http-server * knyle-style-commits -> origin/knyle-style-commits 157d2b0..d33e00d master -> origin/master * menu-behavior-act-i -> origin/menu-behavior-act-i ea1c5e2..dfd315a no-inline-js-config -> origin/no-inline-js-config * svg-tests -> origin/svg-tests 87bb870..9da23f3 view-modes -> origin/view-modes * wild-renaming -> origin/wild-renaming

Também permite que todos vejam, olhando para a página Lista de Ramificações do GitHub, o que todos estão trabalhando para que possam inspecioná-los e ver se querem ajudar com algo.

#4 – abra um pedido pull a qualquer momento

GitHub tem um incrível sistema de revisão de código chamado Pull Requests, que eu temo que as pessoas não saibam o suficiente. Muitas pessoas o usam para trabalhos open source – fork um projeto, atualiza o projeto, envia um pedido pull para o mantenedor. Entretanto, ele também pode ser facilmente usado como um sistema interno de revisão de código, que é o que fazemos.

Atualmente, nós o usamos mais como um branch conversation view do que um pull request. Você pode enviar pedidos pull de um branch para outro em um único projeto (público ou privado) no GitHub, então você pode usá-los para dizer “I need help or review on this”, além de “Please merge this in”.

early pr message

Aqui você pode ver Josh cc’ing Brian para revisão e Brian chegando com alguns conselhos sobre uma das linhas de código. Mais abaixo podemos ver Josh reconhecendo as preocupações de Brian e empurrando mais código para endereçá-las.

mais discussão

Finalmente você pode ver que ainda estamos na fase de teste – este ainda não é um ramo pronto para deployment, usamos os Pull Requests para revisar o código muito antes de realmente querermos fundi-lo em master para deployment.

Se você estiver preso no progresso do seu recurso ou ramo e precisar de ajuda ou conselho, ou se você for um desenvolvedor e precisar de um designer para revisar seu trabalho (ou vice-versa), ou mesmo se você tiver pouco ou nenhum código, mas alguns comps de screenshot ou idéias gerais, você abre um Pull Request. Você pode fazer um cc de pessoas no sistema GitHub adicionando um @username, então se você quiser a revisão ou feedback de pessoas específicas, você simplesmente os cc na mensagem PR (como você viu Josh fazer acima).

Isso é legal porque o recurso Pull Request permite que você comente linhas individuais na diff unificada, em single commits ou no próprio pull request e puxa tudo em linha para uma única visualização de conversa.Ele também permite que você continue empurrando para o branch, então se alguém comenta que você esqueceu de fazer algo ou há um bug no código, você pode corrigi-lo e empurrar para o branch, o GitHub irá mostrar os novos commits na visão de conversação e você pode continuar iterando em um branch como aquele.

Se o branch está aberto há muito tempo e você sente que está ficando fora de sincronia com o branch mestre, você pode mesclar o master no branch do seu tópico e continuar. Você pode facilmente ver na discussão de solicitação pull ou lista de commit quando o branch foi atualizado pela última vez com o ‘master’.

master merge

Quando tudo é realmente feito no branch e você sente que ele está pronto para ser implementado, você pode passar para o próximo passo.

#5 – fundir somente após puxar a revisão do pedido

Nós não simplesmente trabalhamos diretamente em master ou trabalhamos em um ramo tópico e fundimos quando pensamos que está feito – nós tentamos obter o sinal de outra pessoa na empresa. Este é geralmente um comentário de +1 ou emoji ou “:shipit:“, mas tentamos fazer com que alguém o veja.

shipit comment

Após conseguirmos isso, e o ramo passar CI, podemos fundi-lo em master para deployment, que fechará automaticamente o Pull Request quando o empurrarmos.

#6 – deploy imediatamente após a revisão

Finalmente, seu trabalho é feito e fundido no branch master. Isto significa que mesmo que você não o implemente agora, as pessoas irão basear um novo trabalho fora dele e o próximo deploy, que provavelmente irá acontecer em algumas horas, irá empurrá-lo para fora. Então como você realmente não quer que alguém empurre algo que você escreveu que quebra as coisas, as pessoas tendem a ter certeza de que ele realmente é estável quando ele é mesclado e as pessoas também tendem a empurrar suas próprias mudanças.

Nosso bot campfire, hubot, pode fazer deployments para qualquer um dos funcionários, então um simples:

hubot depoy github to production

irá implantar o código e zero-downtime reiniciará todos os processos necessários. Você pode ver como isso é comum no GitHub:

 nossos logs de campfire

Você pode ver 6 pessoas diferentes (incluindo um cara de suporte e um designer) implantando cerca de 24 vezes em um dia.

Eu fiz isso para ramos com um commit contendo uma mudança de linha. O processo é simples, direto, escalável e poderoso. Você pode fazê-lo com ramos de características com 50 commits que levaram 2 semanas, ou 1 commit que levou 10 minutos. É um processo tão simples e sem fricções que você não se aborrece a ponto de ter que fazê-lo mesmo para 1 commit, o que significa que as pessoas raramente tentam pular ou ignorar o processo a menos que a mudança seja tão pequena ou insignificante que simplesmente não importa.

Este é um processo incrivelmente simples e poderoso. Eu acho que a maioria das pessoas concordariam que o GitHub tem uma plataforma muito estável, que os problemas são abordados rapidamente se eles vierem à tona, e que novas funcionalidades são introduzidas em um ritmo rápido. Não há compromisso de qualidade ou estabilidade para que possamos obter mais velocidade ou simplicidade ou menos processo.

Conclusão

O GitHub em si é bastante complexo de entender, tornando o fluxo de trabalho que você usa com ele mais complexo do que o necessário é simplesmente adicionar mais sobrecarga mental ao dia-a-dia de todos. Eu sempre defenderia o uso do sistema mais simples possível que funcionará para sua equipe e fazer isso até que não funcione mais e depois adicionar complexidade apenas como absolutamente necessário.

Para equipes que têm que fazer lançamentos formais em um intervalo mais longo (algumas semanas a alguns meses entre os lançamentos), e serem capazes de fazer hot-fixes e manutenção de filiais e outras coisas que surgem do envio tão raramente, o git-flow faz sentido e eu defenderia altamente o seu uso.

Para as equipes que estabeleceram uma cultura de expedição, que empurram para a produção todos os dias, que estão constantemente testando e implantando, eu defenderia a escolha de algo mais simples como o GitHub Flow.

Leave a Reply