[Forking workflow] Contribuindo em projetos Open Source utilizando git [parte 2]

Ivan Santos
11 min readMar 4, 2016

Esta é a continuação do post Contribuindo em projetos Open Source utilizando git [parte 1].

Introdução

Existe uma gama de tipos de workflow (metodologias de fluxo de trabalho) que podem ser utilizadas para o desenvolvimento e versionamento de aplicações utilizando GIT em grupo. Inicialmente irei mostrar a metodologia principal utilizada pela maioria dos projetos Open Source, o Forking workflow.

Fork

Antes de apresentar este workflow interessante, é necessário compreender o que é um Fork. Fork nada mais é que uma cópia de um repositório. Esta cópia vira um clone do estado atual do repositório, fazendo assim com que você possa experimentar mudanças e feature novas sem precisar utilizar o repositório principal.

Pull Request

Outra coisa interessante antes de começar, é o fato de compreender o que é um Pull Request. Pull requests, geralmente são funcionalidades providas por Empresas de versionamento de código como Github e Bitbucket. Nada mais é que uma interface web amigável para você como desenvolvedor enviar/propor alterações em um repositório antes de integrar este código ao projeto oficial. Fazendo com que esta funcionalidade seja discutida previamente, e quando aprovada pela equipe que mantém o projeto, pode ser integrada ao código principal.

Forking Workflow

Diferente dos outros workflows, ou da forma que os desenvolvedores aprendem inicialmente, geralmente com repositório centralizado e onde todos os integrantes fazem commits direto no repositório principal, no Forking Workflow o usuário possui dois repositórios GIT no Github/Bitbucket: um privado (pessoal) e um publico (principal/central).

Sabe aquele conceito de “validação e aprovação” antes de aceitar contribuições em um projeto? Provavelmente como mantenedor de um projeto você não vai querer que a qualidade do projeto caia. O foco deste workflow é baseado nesta hipótese.

Colaboradores não precisam necessariamente de permissões para dar push no repositório oficial, assim podendo trabalhar paralelamente em seus Forks. Após terminar uma feature, você pode submeter esta alteração através de um Pull Request para o repositório principal, onde os mantenedores do projeto poderão validar se esta funcionalidade condiz com o projeto e se o código está consistente e bem escrito. E caso precise de alguma modificação, você pode continuar escrevendo em seu branch separado, fazendo com que alterações novas sejam agrupadas no mesmo pull request referente aquele branch.

O resultado de todo esse processo de workflow distribuído é um ambiente flexível e robusto, onde grandes e diferentes times (incluindo pessoas não confiáveis) podem colaborar com o projeto de forma segura. Forking Workflow é o workflow ideal para contribuição de projetos Open Source.

Repositório Oficial

É necessário salientar que o GIT não vê diferença entre os repositórios, na verdade tecnicamente você não tem como especificar quem é o repositório Oficial. Isso é questão de entendimento entre os integrantes do projeto. Geralmente é criado uma organization no Github/Bitbucket que abriga os repositórios referentes ao projeto. Tornando aqueles repositórios os “oficiais” em questão de organização.

Talk is cheap, show me the code!

Neste tutorial irei fugir do trivial, ao invés de mostrar apenas como contribuir vou iniciar o processo criando um repositório. Daqui pra frente irei utilizar GitHub para todo o processo, mas fique sabendo que é possível fazer isso tudo em outras plataformas como Bitbucket.

Criando seu projeto no Github

Inicialmente para criar um projeto você pode utilizar ou Github ou seu próprio server. Iniciar um projeto no Github é bem simples:

ou

Após isso é necessário preencher com os dados básicos.

Veja que além de criar o repositório para o seu usuário, caso você faça parte de um team e tenha permissões, você também pode criar um repositório para o team selecionando ele no select “Owner”.

Observe que eu selecionei para que seja criado um arquivo README. você pode optar por não fazer isso e criar seu próprio arquivo tranquilamente.

Clonando o repositório criado

Após criar seu repositório no Github é necessário copiar a URL para clonar o repositório:

Bom, se você chegou até aqui, espero que tenha uma básica noção de como funciona um clone por SSH ou HTTPS, a diferença básica é que o SSH utiliza suas chaves públicas para autorização de escrita (push) em um repositório. Com HTTPS sempre será necessário digitar suas credenciais no terminal. Caso queira utilizar SSH sugiro ler este post: Using SSH over the HTTPS port. Por fim digite os seguintes comandos no terminal:

Este exemplo descreve uma das formas de fazer clone, especificando o diretório no qual você quer fazer setup do diretório remoto. É a forma mas utilizada quanto você começa o repositório localmente com alguns arquivos e deseja enviar todas as alterações para o seu repositório no Github.

Na primeira e segunda linha, estou apenas criando um diretório e entrando no mesmo.

Na terceira linha estou iniciando um repositório, isso faz com que o GIT identifique que aquela pasta representa um projeto versionado.

Na quarta linha estou adicionando uma referência da pasta ao repositório que eu criei no Github através do Fork.

Por fim estou fazendo pull do repositório, fazendo com que o arquivo README criado pelo Github seja sincronizado na pasta. Bem simples não é?

Este segundo exemplo é o mais simples e comum, onde você apenas irá clonar o repositório no seu computador e simplesmente começar a trabalhar.

Na primeira linha é o tipo de clone simples, onde um diretório com o mesmo nome do repositório irá ser criado.

Na terceira linha você especifica o nome do diretório a ser criado como parâmetro.

Criando Fork de um repositório

Podemos dizer que é aqui que começa toda a “dificuldade” ou “falta de experiência” de quem almeja contribuir com projetos open source.

Vamos supor que queremos contribuir com o projeto Casts Brasil :

Criar um fork é trivial, basta clicar no botão fork, no lado direito alinhado ao nome do repositório:

Após clicar em Fork, você irá visualizar uma janela para escolher o destino do seu fork. É possível escolher o seu perfil do github ou até mesmo uma organização, em casos onde você tenha permissão administrativa:

Neste exemplo, irei utilizar meu perfil pessoal, clicando na imagem e usuário correspondente.

Pronto, o Fork foi criado com sucesso. Você será redirecionado para a página do fork do projeto em seu usuário. É possível ver que agora o projeto está sob meu usuário, com referência no usuário castbrasil, como você pode ver na imagem acima.

Especificando Repositório principal e dependente

Já se perguntou como funciona o sistema de sincronizar o seu Fork com todas as novas informações que estão acontecendo no repositório principal?

Especificando cada um localmente é a primeira etapa para conseguir suportar este sincronismo.

Observando a imagem acima existem 3 repositórios:

  • Github — Original:

O repositório Original é definido por ser o primeiro utilizado para se criar o Fork. Geralmente definimos este como upstream. Que significa “de onde todo o fluxo começa”.

  • Github — Fork

O repositório Fork é definido por ser gerado na sua conta de usuário após efetuar o fork de algum repositório é por padrão nomeado como origin pelo git no caso em que você irá clonar utilizando a URL fornecida no github.

  • Local Machine

O repositório local é definido por ser o environment no qual você irá trabalhar localmente em seu computador.

Definindo as responsabilidades:

1- Analisando que o Github Original por ser o principal, e já está criado. O repositório Fork é criado após efetuar um Fork pela interface do Github.

2- Após fazer clone do seu fork, automaticamente você define o repositório Fork como origin.

3- Após definir o origin é necessário definir o upstream, que neste caso será o repositório Original.

Submetendo features para o repositório principal

Uma das principais práticas onde muita gente se engana é na hora de submeter uma alteração para o repositório principal.

Muitas vezes o programador apenas altera algo, faz um commit e envia para o branch master do seu fork. Causando um problema, pois sua versão de master é a atualizada no momento, fazendo com que você fique sem opções para trabalhar em outras tarefas enquanto esta determinada alteração é aprovada.

Para resolver esse problema é bem simples, SEMPRE crie um branch para a sua feature, normalmente a partir de master. Supondo que estamos no diretório do nosso projeto clonado e atualmente utilizando o branch master:

git checkout -b feature-readme-update

O comando acima faz checkout criando um novo branch chamado feature-readme-update.

Após utilizar esta técnica, você pode desenvolver sua feature tranquilamente, sempre criando quantos commits forem necessários.

Após revistar o que foi feito, podemos criar uma “proposta” (Pull Request) para o repositório original.

Primeiro é preciso enviar seu branch para o seu repositório de Fork. Considerando que ao fazer checkout -b você está no branch da feature, agora é necessário dar push no branch:

git push origin feature-readme-update

O Github geralmente vai detectar que existe um novo branch no seu repositório e vai adicionar um botão na página principal do seu fork:

Caso não apareça, é só clicar na aba “Pull Requests” que você irá encontrar o botão New pull request:

Clique em Compare & pull request para iniciar o processo de sugestão de feature no repositório principal:

Repare que antes de criar o Pull Request, você pode atualizar a mensagem principal do commit e definir para onde esse branch irá ser mesclado caso o Pull Request seja aceito.

Ao clicar em “Create pull request”, seremos redirecionados para a URL do pull request criado no repositório original(principal):

Se você consegui chegar até esse ponto, parabéns! Foi uma grande vitória.

Supondo que você esqueceu de algo, ou fez algo que precisa ser alterado antes de ser aceito, é bem simples de resolver. Basta fazer a alteração no mesmo branch e dar push para o repositório do seu fork novamente:

git push origin feature-readme-update

Veja que agora existem 2 commits, um sobre o Update do README e outro sobre Update da versão do RVM.

Supondo que finalizamos a feature, “na maioria das vezes” é necessário que você “junte” os seus commits em um só.

Esta é uma prática adotada por Open Source. Geralmente alguém vai comentar que está tudo legal, e vai pedir para você dar “squash” em seus commits, combinando todos em um só, para no histórico todas as alterações serem representadas por um único commit.

Não é difícil resolver isso, a dica é, analisar quantos commits existem nesse branch e fazer um rebase do número de commits existentes no branch, executando o comando:

git rebase -i HEAD~2

Isso significa que você está executando um rebase interativo com 2 commits a partir da versão HEAD do seu branch.

Após executar o comando, você irá ver uma tela parecida com a tela acima. Tenha em mente que sempre tem que existir um primeiro commit na lista, no caso o dc01803 para que você consiga fazer o squash.

Para efetuar o squash, apenas edite a linha 2, alterando a palavra `pick` por `squash`:

Caso tenha mais commits, você irá repetir o mesmo para os commits no qual você deseja fazer squash.

Ao salvar o commit, você irá ser redirecionado para outra tela no terminal, no qual você irá poder nomear o commit e definir sua mensagem:

O que geralmente eu faço é definir um título geral para a mensagem e definir os tópicos de alteração da funcionalidade, como no exemplo abaixo:

Sempre deixando um espaçamento entre a primeira linha e os tópicos, isso ajuda a organizar a mensagem do commit no Github, é um padrão bem utilizado.

Ao salvar a mensagem do commit, se você tentar dar push novamente para o seu fork, isso não irá funcionar e você receberá um erro:

O que acontece é que nós fizemos um rebase do branch e sua estrutura já não é mais a mesma do branch remoto em seu fork.

Neste caso, você deve forçar o push com a flag `-f`:

Pronto, nosso rebase com squash foi enviado com sucesso! Se você voltar a url do Pull Request no repositório oficial, você irá ver que agora apenas temos 1 commit:

É neste momento que o manager do repositório que está fazendo review da sua proposta faz o merge da funcionalidade clicando em `Merge pull request`:

Se você conseguiu chegar até esse ponto em algum projeto Open Source, Parabéns! você fez seu primeiro Pull Request e está basicamente preparado para ajudar em vários projetos disponíveis na internet.

Atualizando branch com novas alterações enquanto você trabalha em sua funcionalidade

Muitas vezes (a maioria das vezes), um projeto tem vários contribuidores que trabalham em várias funcionalidades diferentes.

É preciso então manter sua branch atualizada com a versão mais recente do repositório oficial. Fazemos isso através de rebase.

Suponha que você está trabalhando atualmente no branch feature/new-readme e percebeu que existem atualizações no branch master do repositório oficial, é bem simples de resolver basta executar:

git rebase -i upstream/master

O comando acima faz rebase do seu branch local a partir de `upstream` no branch master que representa o repositório oficial, trazendo e reorganizando seus commits no branch incluindo as novas alterações ordenadamente.

Atualizando seu repositório com as alterações mais recentes do repositório principal

Esta é a última etapa de um longo ciclo de contribuições. Ao ter seu pull request aceito, ou ao perceber que mais contribuições foram feitas no repositório original, é preciso que você mantenha o seu repositório de Fork e também seu repositório local, para que você sempre tenha features baseadas na versão mais recente do branch master do repositório original.

E é aí que finalmente nós utilizamos do recurso de url remota do git, neste caso definimos `origin` e `upstream`.

Para pegar as alterações mais recentes, certifique-se que localmente você está no branch master e execute o comando:

git pull upstream master

Pronto! Agora você tem o seu repositório local atualizado com a versão mais recente do repositório original. Agora é a hora de atualizar o seu repositório Fork, executando o comando:

git push origin master

É isso aí, a partir de agora você tem conhecimento o suficiente para contribuir com vários projetos Open Source. O que você está esperando? Vários projetos precisam da sua ajuda, e agora você pode seguir o fluxo facilmente.

Quem não é visto, não é lembrado.

Contribua, aprenda e consequentemente seja reconhecido pelo seu esforço! Open Source vai lhe trazer muitos benefícios.

Espero que tenha gostado e até o próximo post!

--

--

Ivan Santos

@pragmaticivan, views expressed on this blog are solely mine, not those of present or past employers.