Ignorar ficheiros e pastas com o .gitignore
Por padrão, o Git permite controlar as versões de qualquer tipo de ficheiro que existir dentro da pasta (ou sub-pastas) onde está o repositório, mas nem sempre queremos controlar as versões de todos os tipos de ficheiro.
Ficheiros temporários que são criados pelo sistema operativo ou pela ferramenta de desenvolvimento, não devem fazer parte do repositório, ou seja, nunca devem adicionados aos commits. No entanto, poderão existir na working folder enquanto trabalha, mas devem ser ignorados pelo Git quando adicionamos alterações a staging area e efectuamos commits.
Por exemplo, o Windows costuma criar ficheiros com o nome Thumbs.db
em pastas que possuem imagens, onde armazena uma espécie de cache das miniaturas das imagens contidas na pasta. Esses ficheiros Thumbs.db
jamais devem ser guardados no repositório, pois podem ser recriados pelo Windows conforme o conteúdo da pasta muda.
Ainda, num projecto .NET, o Visual Studio cria ficheiros do tipo NomeProjecto.suo
, NomeProjecto.user
, NomeProjecto.sln.cache
, e outros tipos de ficheiros temporários que estão relacionados com o utilizador actual e podem ser recriados pelo Visual Studio a qualquer momento. Estes ficheiros também não devem ser armazenados no repositório Git, e portanto devem ser ignorados.
Além disso, é uma prática comum não guardar ficheiros executáveis, e outros ficheiros que podem ser gerados (compilados) a partir do código que está a ser controlado pelo repositório Git, ou seja, deve-se guardar apenas o código-fonte e as dependências necessárias para que seja possível compilar o código-fonte. Por exemplo, num projecto .NET, normalmente temos as pastas bin
e obj
que possuem o resultado da compilação de cada projecto do Visual Studio. Estas pastas também não devem ser armazenadas no repositório Git, pois deve ser possível recriá-las a qualquer momento, a partir do código-fonte do projecto.
Para poder ignorar determinados tipos de ficheiros ou pastas, criamos um ficheiro chamado .gitignore
na pasta onde criamos o repositório. O Windows por padrão não permite criar ficheiros que não tenham nome e apenas uma extensão, como é o caso do .gitignore
, por isso uma alternativa simples é criar o ficheiro a partir do Git Bash, executando o Bloco de Notas para criar o ficheiro:
$ notepad .gitignore
No conteúdo do ficheiro .gitignore
, pode inserir comentários (linhas que começam com #
), definir os tipos de ficheiros que pretende ignorar e as pastas que pretende ignorar por completo, independente do conteúdo. Neste exemplo:
# Ignorar ficheiros temporários do Windows Thumbs.db # Ignorar pacotes de ficheiros *.zip *.rar # Ignorar ficheiros temporários do Visual Studio *.suo *.user *.userprefs # Ignorar as pastas com ficheiros binários gerados via compilação [Oo]bj/ [Bb]in/
A sintaxe é bastante intuitiva, e pode utilizar *.extensão
dos ficheiros que pretende ignorar, e informar o nome das pastas com uma barra /
no final para indicar que trata-se de uma pasta. O Git faz diferença entre letras maiúsculas e minúsculas, por isso pode utilizar expressões como [Oo]bj/
que permite indicar que tanto as pastas obj/
quanto Obj/
devem ser ignoradas.
Ao criar o ficheiro .gitgnore
, os ficheiros e pastas definidos no conteúdo deste ficheiro serão ignorados pelo Git, e deixarão de aparecer, por exemplo, quando visualizar o estado do repositório com o comando git status
, no entanto é importante adicionar o ficheiro .gitignore
ao repositório para garantir que continuará a ignorar os ficheiros desejados nos próximos commits, e também para que todos os membros da equipa estejam a ignorar os mesmos tipos de ficheiros e pastas.
$ git add .gitignore $ git commit -m "Adiciona o ficheiro .gitignore ao repositorio"
Consulta do Histórico de Commits
Conforme efectuamos commits, é muito comum necessitarmos consultar a história do projecto para, por exemplo, perceber quando foi introduzida uma determinada alteração. Para este efeito, o Git possui um comando chamado git log
, que permite visualizar os commits que estão armazenados no repositório, incluindo informações como a data e hora, nome e e-mail do utilizador que efectuou cada commit, e também o identificador único de cada commit (ex: 5944d4c5c92c89766ac77de221b1b36b803ee37b
), que podemos utilizar quando necessitamos efectuar operações específicas em determinados commits.
$ git log
O comando git log
pode receber diferentes parâmetros que permitem visualizar mais, ou menos informação sobre os commits, algumas opções de formatação, entre outros recursos.
Uma outra forma de consultar o histórico de commits é utilizar um utilitário instalado juntamente com o msysGit chamado gitk, que permite consultar os commits de forma gráfica.
$ gitk
Desenvolvimento em Paralelo
Ao trabalharmos no desenvolvimento de software profissional, é muito comum termos um ambiente de desenvolvimento onde efectuamos testes de novas funcionalidades que estão a ser desenvolvidas, separado do ambiente de produção onde a aplicação está a ser executada pelos utilizadores finais. Em realidade, é também muito comum termos um ambiente intermédio de controlo de qualidade (também conhecido como ambiente de qualificação, de qa ou de testes), que geralmente possui as mesmas características do ambiente de produção, e possui uma versão da aplicação com funcionalidades que ainda precisam ser testadas antes de serem promovidas para o ambiente de produção.
Desta forma, o ambiente de produção possui sempre a versão mais antiga do projecto, mas também a mais estável e que passou pelos testes de controlo de qualidade, enquanto o ambiente de qualificação (se houver) possui uma versão mais nova do projecto, mas que ainda necessita ser testado antes de evoluir para o ambiente de produção, e por fim o ambiente de desenvolvimento possui uma versão ainda mais nova do projecto, com as funcionalidades que estão a ser desenvolvidas e que após testes dos developers poderão ser enviadas para o ambiente de qualificação, para serem efectuados mais testes.
Uma vez que temos ambientes separados, podemos utilizar a ferramenta de controlo de versões para manter diferentes as versões dos nossos projectos em paralelo de forma a conseguirmos enviar uma nova versão para qualquer um dos ambientes o mais rápido possível e idealmente a qualquer momento.
Para este efeito, o Git e a grande maioria de sistemas de controlo de versões oferece um recurso chamado branch, que no Git é representado por um conjunto de commits é identificado por um nome escolhido pelo developer que efectua criação do branch.
Ao criar um novo repositório Git, automaticamente é criada um primeiro branch chamado master
, que irá agregar todos os commits que fizer neste branch. Pode identificar a qualquer momento em qual branch encontra-se posicionado através do nome entre parênteses após o caminho da pasta:
Para criar um novo branch, pode utilizar o comando git branch
, e informar o nome do branch a ser criado:
$ git branch desenvolvimento $ git branch qualificacao
Estes comandos efectuam a criação de dois novos branches chamados desenvolvimento
e qualificacao
respectivamente, mas que estão a apontar para o mesmo commit do branch actual (master
), que neste exemplo, é o commit que adiciona o ficheiro .gitignore
.
O branch master
, neste exemplo, está a ser usado como sendo o branch com a versão de produção, enquanto os outros branches representam as versões dos outros ambientes. Isto pode variar de acordo com a preferência pessoal da equipa. Em alguns casos, o branch master
será utilizada como branch de desenvolvimento, por exemplo, e são criados outros branches para os outros ambientes.
Para mudar para um novo branch, deve utilizar o comando git checkout
e informar o nome do branch para onde deseja ir:
$ git checkout desenvolvimento
A partir de agora todos os commits efectuados serão armazenados no branch desenvolvimento
, de forma isolada da branch master
criado inicialmente, e também de forma isolada do branch qualificacao
.
Para este exemplo, pode criar um ficheiro chamado NovaFuncionalidade.txt
e efectuar o commit:
$ echo " Conteudo" >> NovaFuncionalidade.txt $ git add . $ git commit -m "Adiciona o NovaFuncionalidade.txt"
E neste momento, o repositório possui quatro commits diferentes:
- Commit 4 | Adiciona o NovaFuncionalidade.txt
- Commit 3 | Adiciona o ficheiro .gitignore ao repositorio
- Commit 2 | Adiciona funcionalidade Y
- Commit 1 | Adiciona funcionalidade X
No entanto, o commit 4 está presente apenas no branch desenvolvimento
, enquanto a branch master
e qualificacao
continuam a apontar para o commit 3, como pode visualizar através do utilitário gitk:
Desta forma, é possível continuar a efectuar commits neste branch sem comprometer as versões que estão em paralelo e que correspondem aos outros ambientes, e apenas quando for apropriado, poderá juntar os commits efectuados em um branch, com outro.
A utilização de branches no Git é tão simples e tão rápida, que muitos developers adoptam uma convenção conhecida como branch-per-feature, onde criam novas branches para cada nova funcionalidade que pretendem implementar num projecto, e depois decidem que funcionalidade/branch deve ser adicionada nos branches principais de cada ambiente.
A operação de juntar os commits de uma branch com os commits de outro branch é chamada de merge e para este efeito o Git possui o comando git merge
que permite juntar o branch informado como parâmetro, no branch onde está posicionado.
Por exemplo, para juntar as alterações do branch desenvolvimento
com o branch master
, em primeiro lugar é preciso ir para o branch master
(com o comando git checkout
) e então executar o comando git merge
e informar que deve ser efectuado o merge do branch desenvolvimento
com o branch actual:
$ git checkout master $ git merge desenvolvimento
Como pode reparar na imagem acima, o Git efectuou um fast-forward que é o tipo de merge mais simples que existe, onde apenas o apontador do branch actual move-se para apontar para o novo commit, que neste caso é mais novo.
Existem outros tipos de merge, e em alguns casos um merge pode causar conflitos, por exemplo, caso as mesmas linhas de um ficheiro tenham sido alteradas por commits diferentes, e pode necessitar de intervenção manual do developer, e que normalmente utiliza uma ferramenta para auxiliar a resolução de conflitos. Este é um assunto que merece um artigo próprio, que ficará para uma próxima edição desta revista.
Partilha de Alterações em Equipa
A partilha de commits entre os membros da equipa pode ser feita directamente entre os repositórios dos developers envolvidos, pode ser utilizado um repositório partilhado, ou outras formas de acordo com o fluxo de trabalho da equipa. Na próxima secção irá encontrar breve explicação sobre os workflows mais comuns para controlo de versões em sistemas distribuídos.
Os principais comandos para a utilização do Git em equipa são o git clone
, git pull
e o git push
.
O comando git clone
serve para criar uma cópia integral de um repositório Git. Este é o comando utilizado quando desejamos participar de um projecto, e para isso precisamos ter uma cópia do repositório em nosso computador. O git clone
automaticamente guarda uma referência para o repositório original, de forma a facilitar obter actualizações desse repositório, bem como enviar as actualizações feitas localmente.
Já o comando git pull
permite receber novos commits que tenham sido adicionados num repositório de origem. É tipicamente utilizado para receber as alterações enviadas por outros membros da equipa para um repositório partilhado, ou ainda para receber novos commits de um repositório específico de um membro da equipa.
E por fim, o comando git push
, como o nome indica, faz exactamente o inverso do git pull
, e serve para enviar as alterações efectuadas localmente no repositório, para um repositório de origem, tipicamente um repositório remoto partilhado com os membros da equipa.
Criação de um Repositorio Partilhado
Um repositório partilhado pode estar no mesmo computador, ou em um computador remoto que pode estar na mesma rede, em uma rede separada, ou ainda em um servidor que pode aceder via internet. A comunicação entre repositórios pode ser feita de diferentes formas, via rede (partilha de pastas), SSH, HTTP, HTTPS, entre outras formas. Para efeitos de exemplo, todos os repositórios mostrados abaixo são criados no mesmo computador, em pastas diferentes.
Como explicado no início desta secção, a criação de repositórios é feita através do comando git init
. No entanto, para a criação de repositórios partilhados que poderão receber actualizações (push
) de outros utilizadores, é necessário indicar que trata-se de um repositório partilhado através dos parâmetros --shared
e --bare
.
$ cd .. $ mkdir RepositorioPartilhado $ cd RepositorioPartilhado $ git init --shared --bare
Após a execução das instruções acima, é criado um repositório chamado RepositorioPartilhado
que irá servir como um repositório intermédio para dois membros da equipa, o Tiago
e o Carlos
, que terão cada um os seus próprios repositórios.
Criação de Clones de Repositórios
Para criar um clone de um repositório, como referido acima, utilizamos o comando git clone
, informando o nome do repositório a ser clonado:
$ cd .. $ git clone RepositorioPartilhado Tiago $ git clone RepositorioPartilhado Carlos
As instruções acima permitiram criar dois clones do repositório RepositorioPartilhado
, um para o Tiago
ou outro para o Carlos
, criados e pastas separada, e neste momento estão vazios (sem qualquer commit armazenado).
Para este exemplo, é criado um ficheiro no repositório do Tiago
que será então armazenado em um commit. Em seguida este commit será enviado (push) para o repositório partilhado RepositorioPartilhado
, e a partir daí o Carlos
pode obter as actualizações (pull) do repositório RepositorioPartilhado
e consequentemente irá obter o commit efectuado inicialmente no repositório do Tiago
e que foi partilhado no repositório RepositorioPartilhado
.
Passo 1 : Efectuar as alterações no repositório do Tiago
$ cd Tiago/ $ echo "Alteracao Tiago" >> NovaFuncionalidade. txt $ git add . $ git commit -m "Adiciona nova funcionalidade (Tiago)"
É importante reparar que o commit foi efectuado no branch master
deste repositório.
Passo 2: Enviar as alterações para o repositório partilhado (push)
Como referido acima, para enviar as alterações efectuadas no repositório local para o repositório de origem, deve utilizar o comando git push
, e para isto deve informar o nome da referência do repositório de origem, e o nome do branch que deve ser considerada para o envio.
Ao efectuar um clone de um repositório, o Git automaticamente cria uma referência para o repositório de origem com o nome origin
. É possível alterar este nome se desejar, e também é possível criar outras referências para outros repositórios remotos.
Assim, para enviar as alterações para o repositório partilhado, basta informar origin
como referência para o repositório partilhado, e master
como nome do branch, uma vez que o commit que deve ser enviado está neste branch.
$ git push origin master
Passo 3: Receber as alterações enviadas para o repositório partilhado no repositório do “Carlos”
Para receber as alterações existentes no repositório partilhado, deve utilizar o comando git pull
, e para isto deve informar o nome da referência do repositório de origem, e o nome do branch que deve ser considerada para o recebimento.
Dessa forma, assim como o comando git push
basta informar origin
como referência para o repositório partilhado, e master
como nome do branch.
$ cd .. $ cd Carlos/ $ git pull origin master
E a partir de agora, os três repositórios estão sincronizados e possuem os mesmos commits.
Assim, o fluxo de trabalho comum no dia-a-dia do Git em equipa é algo como:
- início
- Efectuar alterações/novos commits (
git commit
) - Juntar actualizações do repositório partilhado com o repositório local (
git pull
) - Enviar as actualizações do repositório local para o repositório partilhado (
git push
)
- Efectuar alterações/novos commits (
- loop
Workflows Comuns para Controlo de Versões Distribuído
Subversion-style
Este é o workflow mais simples, e normalmente utilizado em equipas que estão a utilizar o Git pela primeira vez. Neste workflow, utiliza-se o Git como se fosse um sistema de controlo de versões centralizado, mas com as vantagens de um sistema distribuído, onde pode-se efectuar commits localmente, de forma desconectada, e enviar para o repositório partilhado apenas quando for apropriado. Todas as alterações são partilhadas num repositório partilhado e não há comunicação directa entre os membros da equipa.
Decentralized but Centralized
Este é o workflow mais comum para pequenos e médios projectos em equipas com alguma experiência com o Git. Os membros da equipa acordam entre si que todas as alterações que devem ser consideradas para as futuras versões do projecto serão armazenadas em um repositório partilhado principal, conhecido por blessed repository (repositório abençoado).
Os membros da equipa podem então partilhar commits entre eles directamente enquanto trabalham em determinadas tarefas, e quando for apropriado, podem enviar os commits para o blessed repository.
Integration Manager
Este é um workflow mais sofisticado e indicado para projectos médios e grandes, onde cada membro da equipa possui dois repositórios, um público e outro privado (que podem estar no mesmo computador). Cada developer trabalha em seu repositório privado, e quando apropriado pode partilhar (push) as alterações que efectuou em seu repositório privado no repositório público.
Existe então uma pessoa da equipa que assume o papel de integration manager que é a pessoa responsável em obter (pull) as alterações do repositório público de cada developer, validar, e então enviar (push) para o blessed repository.
Dictator and Lieutenants
Este é um workflow ainda mais sofisticado que o anterior e indicado para projectos extremamente grandes e com muitas pessoas a participar no desenvolvimento. Cada developer possui um repositório público onde pode partilhar as alterações que posteriormente serão validadas por pessoas na equipa que assumem o papel de lieutenant (tenente) e normalmente são responsáveis por módulos específicos do projecto.
Após a validação das alterações pelos lieutenants, estas são enviadas para outra pessoa que assume o papel de dictator (ditador) e que efectua uma validação final, antes de enviar para o blessed repository.
Por curiosidade, este é o workflow utilizado actualmente para controlar as versões do kernel do Linux. Existem pessoas consideradas como sendo pessoas “de confiança” e que são responsáveis por diferentes módulos do kernel e validam as alterações enviadas pelas centenas de pessoas que contribuem para o projecto, e por fim são enviadas para o “ditador” que as valida e escolhe quais alterações farão parte do repositório principal e que eventualmente irão fazer parte de uma futura versão do sistema operativo.
Serviços de Alojamento de Repositórios Git na Internet
Existem dezenas de empresas que fornecem serviços de alojamento de repositórios Git na internet, permitindo desenvolver projectos (open-source ou não) com equipas distribuídas sem precisar criar e manter uma infra-estrutura própria.
O serviço mais popular e provavelmente o mais utilizado em todo o mundo é o GitHub (http://github.com) que oferece a possibilidade de criar repositórios públicos gratuitos com até 300 MB, para quem pretende desenvolver software open-source, e oferece também a possibilidade de criar repositórios privados para empresas que queiram ter repositórios privados partilhados e não possui infra-estrutura própria com preços que variam entre os 7 e 22 dólares americanos por mês no momento em que escrevo este artigo. Em Abril de 201 1 , o GitHub ultrapassava os 2 milhões de repositórios.
Outros exemplos serviços que oferecem serviços semelhantes são:
- Gitorious (http://gitorious.org)
- Unfuddle (http://unfuddle.com)
- ProjectLocker (http://www.projectlocker.com)
- RepositoryHosting (http://repositoryhosting.com)
- Assembla (http://www.assembla.com)
Exemplos de Grandes Projectos que Utilizam o Git
O Git é amplamente utilizado em projectos open-source em todo o mundo, em pequenos, médios e grandes projectos, e foi originalmente desenvolvido para controlar as versões do kernel do Linux e desde a sua primeira versão continua a ser utilizado para tal.
Alguns projectos populares que utilizam Git para controlo de versões, além do kernel Linux, são: Ruby on Rails, Node.js, jQuery, Modernizr, Scriptaculous, Android, CakePHP, Sinatra, VLC, entre muitos outros, e o próprio Git. Exacto! O controlo de versões do código-fonte do Git é feito através do próprio Git.
Uma lista mais detalhada de projectos que utilizam o Git está disponível no wiki do Git em https://git.wiki.kernel.org/index.php/GitProjects, e pode acompanhar os projectos open-source mais populares no GitHub em https://github.com/popular/watched.
Links para Referência
- Git Scm – Site oficial do Git
http://git-scm.com - Posts sobre Git em meu blog
http://caioproiete.net/pt/tag/git/ - Vídeo: Controlo de Versões Distribuído com Git
http://vimeo.com/20652754 - Pro Git (e-book)
http://progit.org - Git Ready (tutorial / tips)
http://www.gitready.com - Git Magic (e-book)
http://www-cs-students.stanford.edu/~blynn/gitmagic - Git for Beginners
http://stackoverflow.com/questions/315911/git-for-beginners-the-definitive-practical-guide - Why Git is Better than X
http://whygitisbetterthanx.com - Git Is Your Friend not a Foe
http://hades.name/blog/2010/01/17/git-your-friend-not-foe - A successful Git branching model
http://nvie.com/posts/a-successful-git-branching-model - Use Git For What It Is Not Intended (UGFWIINI)
http://thread.gmane.org/gmane.comp.version-control.git/110411