Arquivo

Posts Tagged ‘tutoriais’

Tutorial Controle de Versão Distribuído: GIT – Parte 2

29 de março de 2010 Deixe um comentário

No último post  da série controle de versão distribuído com GIT, falamos sobre a filosofia dos controles de versões e as modificações na forma de pensar e trabalhar a partir do git. Neste post será feita uma abordagem mais técnica apresentando o processo de instalação e as primeiras interações com o ambiente git.

Instalação

O git possui pacotes de instalação para diversas plataformas. Podemos instalar o git nos principais sistemas operacionais de duas formas: Utilizando um pacote de instalação pré-compilado para uma determinada plataforma e a segunda obtendo o código fonte e efetuando a compilação. Considero a primeira opção a mais prática aconselhando utilizar o processo de compilação apenas para quando se queira instalar uma versão em especifico que não tenha um pacote compilador.

Para este tutorial, iremos apresentar as instalações nas principais plataformas de mercado (linux, mac os e windows).

Instalando no linux

A forma de instalação no linux vai depender apenas de qual gerenciador de pacotes você está utilizando. O nome do pacote de instalação do git constuma se chamar git-core.

Se estiver utilizando distribuições baseadas no debian, utilizando o comando apt-get é possível rapidamente instalar.

$ sudo apt-get install git-core

Para os usuário de distros baseadas na estrutura fedora, pode-se utilizar o comando yum.

$ sudo yum install git-core

Instalando no mac

No linux podemos instalar o git via instalador gráfico git4osx ou através do macports via linha de comando.

$ sudo port install git-core +svn +doc +bash_completion +gitweb

Note que não é preciso instalar todos os complementos.

Instalando no windows

A instalação no windows é bastante simplificada. O projeto msysGit possui um instalador com procedimentos fáceis para a instalação do git.

Você pode obter o instalador a partir da página do projeto no google code

$ http://code.google.com/p/msysgit

Primeiras configurações

Após concluída a instalação, vamos realizar algumas configurações básicas no git antes de partir para sua utilização. Você vai observar que todos os procedimentos feitos neste tutorial, são realizados na própria linha de comando do SO. Existem algumas ferramentas gráficas que podem atuar como GUI do git. Experimentei algumas e cheguei a conclusão que pela falta de maturidade e muitas vezes simplicidade do git, as vezes se torna mais prático utilizar o core na linha de comando.

Definindo a sua identificação

É importante definir o seu nome de usuário e email pois estas informações sempre serão anexadas aos comandos de commit feitos nos repositórios.

Para configurar estas variáveis, na linha de comando digite o seguinte:

$ git config --global user.name "Rafael Soto"
$ git config --global user.email rafael.soto@gmail.com

Definindo o editor de texto padrão

Sempre que o git precisar de uma entrada de dados do usuário o mesmo vai chamar o editor de texto padrão definido.

Para definir um editor de texto padrão, digite a linha de comando abaixo no seu console:

$ git config --global core.editor smultron

Definindo a ferramenta para realizar diff

Ferramentas de diff  são solicitadas pelo git em momentos de conflitos nas operações de merge. Apesar destes conflitos serem raros no git, é importante ter uma boa ferramenta gráfica definida para solucionar o problema da melhor forma possível. Abaixo segue a linha de comando para definir qual diff utilizar.

$ git config --global merge.tool vimdiff

Verificando as configurações

Você pode verificar todas as suas configurações executando o comando config –list

$ git config --list
user.name=Rafael Soto
user.email=rafael.soto@gmail.com
core.repositoryformatversion=0
filemode=true
bare=false
logallrefupdates=true
...

Iniciando os trabalhos no GIT

Repositórios

Para se criar ou obter um repositório git existem duas possíveis abordagens. A primeira utilizamos quando se deseja criar um novo repositório, neste caso de forma local criamos um novo repositório em branco ou um repositório a partir de um sistemas de arquivos existente. A segunda abordagem é feita através da importação de um repositório em uma máquina remota, no caso do git , chamamos este procedimento de clone.

Para iniciar o aprendizado dos comandos iniciais vamos trabalhar com a abordagem do repositório local. Em um outro momento iremos explorar a forma de trabalho publicando as ações em repositórios remotos através de um exemplo prático utilizando repositórios remotos como o git-hub.

Iniciando o repositório local

Inicialmente vamos criar uma pasta para o repositório

$ mkdir meurepo
$ cd meurepo

Logo em seguida vamos inicializar um novo repositório git a partir do diretório corrente

:/meurepo $ git init

Note que uma pasta .git foi criada no local onde o comando foi executado. Esta é a única pasta criada e utilizada pelo git dentro de todo o seu projeto. De uma forma simplificada, ele realiza a “mágica” de estruturar toda a base de versões do seu projeto nesta pasta. Pronto! Já temos o nosso repositório de controle de versões com todos os serviços fornecidos pelo git disponíveis de forma local.

Executando operações no repositório

Vamos iniciar os trabalhos criando 2 arquivos para explicarmos exemplos de operações no repositório.

:/meurepo $ touch README
:/meurepo $ touch INSTALL

Arquivos criados no diretório de trabalho(working directory) podem estar em dois estados: Tracked ou Untracked. O estado Untracked corresponde a arquivos que foram recentemente criados e estão fora do repositório git. Estes arquivos são vistos pelo git como arquivos não presentes na ultima snapshot de versão e suas modificações não são tratadas pelo mesmo. Arquivos Tracked representam exatamente o oposto, são arquivos que já estão presentes no repositório e suas modificações são rastreadas pelo git.

Para verificar o estado de um arquivo no repositório utilizamos o comando git status, este comando apresenta a situação dos arquivos em relação ao repositório naquele dado momento. Como exemplo vamos verificar o status dos arquivos que acabamos de criar.

:/meurepo $ git status
# On branch master
#
# Initial commit
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    INSTALL
#    README
nothing added to commit but untracked files present (use "git add" to track)

Os dois arquivos (README e INSTALL) se encontram no estado Untracked, ou seja, como apenas criamos eles e não adicionamos no repositório qualquer modificação feita nos mesmos não vai efetuar nenhuma mudança no estado do repositório.

Para que um arquivo seja inserido no repositório e na próxima versão, o mesmo precisa estar marcado como staged(o detalhamento deste fluxo de trabalho foi tratado na parte 1 deste tutorial). Para adicionar um arquivo na área staged utilizamos o comando git add <arquivo/diretorio>. Vamos adicionar no nosso exemplo apenas o arquivo INSTALL e em seguida vamos verificar o status do repositório.

:/meurepo $ git add INSTALL
:/meurepo $ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#    new file: INSTALL
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    README

Note que o arquivo INSTALL passa a estar disponível para entrar no próximo commit do repositório e o seu estado é de novo arquivo (new file). Vale observar que o fato de termos adicionado o arquivo, o mesmo não se encontra no repositório apenas pronto para ser realizado o commit. Ao se utilizar o comando add o git congela a situação do arquivo e o deixa pronto para o commit, se modificarmos novamente este arquivo, teremos duas versões para este arquivo, uma que já está pronta para commit e outra que foi modificada depois de já ter marcado o arquivo para o commit. Como exemplo vamos modificar o mesmo arquivo INSTALL antes de realizar o commit e verificar o status do repositório ao final da operação.

:/meurepo $ git echo "CONTEUDO 1" >> INSTALL
:/meurepo $ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#    new file: INSTALL
#
# Changed but not updated:
#   (use "git add <file>..." to update what will be committed)
#
#    modified:   INSTALL
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    README

Observe que agora temos o mesmo arquivo INSTALL com dois estados no repositório. O primeiro representa o arquivo recém criado que foi marcado a ser inserido no repositório e o segundo o arquivo que foi modificado. Mas se nem se quer efetuamos o commit porque o arquivo já possui estado modified ? Ao executar o comando add, o git congelou o estado do arquivo INSTALL e copiou ele para área de staged. A área de staged é o local onde fica armazenado todos os arquivos que irão compor o próximo commit, snapshot ou versão do repositório. Logo em seguida, fizemos uma alteração no arquivo inserindo um conteúdo nele. Como o estado do arquivo foi modificado e ficou diferente do estado do arquivo que foi congelado na área staged do repositório, o git já identificou a mudança e deixou o novo estado do arquivo marcado para inclusão. Podemos adicionar novamente o arquivo a área de staged e a versão que passa a contar do arquivo é a ultima modificada.

:/meurepo $ git add INSTALL
:/meurepo $ git status
# On branch master
#
# Initial commit
#
# Changes to be committed:
#   (use "git rm --cached <file>..." to unstage)
#
#    new file: INSTALL
#
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    README

O próximo passo seria gerar uma nova versão ou snapshot do projeto a partir da operação commit. O commit é a operação responsável por gerar uma nova versão do projeto a partir dos arquivos que foram marcados como staged. Ao executar o comando, o git efetua uma copia de toda a situação dos arquivos incluindo as modificações e as armazena na base de dados com uma versão.

:/meurepo $ git commit -m "Meu primeiro commit"
Created initial commit fd7a2de: Meu primeiro commit
 1 files changed, 1 insertions(+), 0 deletions(-)
 create mode 100644 INSTALL

:/meurepo $ git status
# On branch master
# Untracked files:
#   (use "git add <file>..." to include in what will be committed)
#
#    README
nothing added to commit but untracked files present (use "git add" to track)

Podemos notar que após efetuar o commit, o arquivo que estava marcado como staged foi enviado para o repositório e a área de staged limpa, restando apenas o arquivo README que se encontra no estado Untracked por não ter sido adicionado ainda.
Mas podemos nos perguntar: Sempre que eu alterar um arquivo ou criar um novo preciso ficar adicionando o mesmo a área de stag? Para responder a esta pergunta o git implementou um parâmetro para o comando commit que permite pular a etapa de adicionar os arquivos a área de staged. Ao se utilizar do argumento -a o próprio git se encarrega de adicionar e realizar o commit automaticamente.
Note que o recurso de staged de arquivos permite um controle maior do que será feito no commit.


:/meurepo $ git add README
:/meurepo $ cat "CONTEUDO 2" >> README
:/meurepo $ git commit -a -m "Meu segundo commit"</pre>

Created commit 4a2fd75: Meu segundo commit
 1 files changed, 1 insertions(+), 0 deletions(-)

:/meurepo $ git status
# On branch master
nothing to commit (working directory clean)

Observe que adicionamos o arquivo README e logo em seguida modificamos ele. No momento em que realizamos o commit com o parametro -a, o git coloca todos os arquivos modicados na área de staged e depois submete eles para o repositório.

Abaixo segue o resumo do fluxo de trabalho apresentado

Para remover o arquivo do repositório utilizamos o comando git rm <arquivo> e em seguida a confirmação da ação com o commit. Note que enquanto o commit da remoção não for feito, o arquivo permanece existente no repositório na sua ultima versão. Podemos por exemplo restaurar ele para o diretório de trabalho. Como exemplo vamos remover o arquivo README.


:/meurepo $ git rm README
:/meurepo $ git status

# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    deleted:    README
#

:/meurepo $ git commit -m "removendo arquivo README"</pre>
Created commit b1800eb: removendo arquivo README
 1 files changed, 0 insertions(+), 1 deletions(-)
 delete mode 100644 README

:/meurepo $ git status
# On branch master
nothing to commit (working directory clean)

Para mover ou renomear os arquivos do repositório utilizamos o comando git mv <arquivo origem> <arquivo destino> e em seguida a confirmação da ação com o commit.
Como exemplo vamos modificar o nome do arquivo INSTALL.

:/meurepo $ git mv INSTALL INSTALL.txt
:/meurepo $ git status

# On branch master
nothing to commit (working directory clean)
~/repositorios/meurepo$ git mv INSTALL INSTALL.txt
~/repositorios/meurepo$ git status
# On branch master
# Changes to be committed:
#   (use "git reset HEAD <file>..." to unstage)
#
#    renamed:    INSTALL -> INSTALL.txt
#

:/meurepo $ git commit -m "modificando nome arquivo INSTALL"

Created commit 27f465e: modificando nome arquivo INSTALL
 1 files changed, 0 insertions(+), 0 deletions(-)
 rename INSTALL => INSTALL.txt (100%)

:/meurepo $ git status
# On branch master
nothing to commit (working directory clean)

O fluxo executado acima corresponde ao fluxo abaixo


$ mv INSTALL INSTALL.txt
$ git rm INSTALL.txt
$ git add INSTALL
$ git commit -m ""

Chegamos ao final de mais um post. No próximo post iremos abordar o tema BRANCH, apresentando a forma de trabalho a partir de multiplas linhas de desenvolvimento.

Anúncios
Categorias:Tutorial Tags:,

Tutorial Controle de Versão Distribuído: GIT – Parte 1

28 de março de 2010 1 comentário

Olá amigos.

Estamos iniciando as atividades deste novo blog com uma série de tutoriais sobre o controle de versão distribuído GIT.

A algumas semanas atrás tive o primeiro contato com o git e posso confessar que fiquei impressionado com a sua filosofia de trabalho e principalmente a qualidade dos resultados ao se realizar trabalhos complexos com gerência de branchs de desenvolvimento e merge de versões.

Nesta primeira parte da série de tutoriais sobre o git iremos falar rapidamente sobre ferramentas para controle de versão e nova filosofia de trabalho proposta. Vamos ao que interessa!

O que é um controle de versão ?

Controle de versão é um sistema com a capacidade de armazenar todas as modificações aplicadas a um arquivo ou a um conjunto de arquivo ao longo do tempo sendo possível a qualquer instante obter uma determinada versão anterior dos dados.  A partir de uma ferramenta como esta, é possível recuperar a situação de um determinado sistema em um determinado instante no tempo, garantir a harmonia no desenvolvimento colaborativo com diversos desenvolvedores codificando simultaneamente, gerenciar baselines e releases de produtos dentre muitas outras facilidades ou necessidades existentes na atual situação do desenvolvimento de software.

Abaixo iremos descrever 3 paradigmas de controle de versão finalizando no conceito do controle de versão distribuído.

Controle de versão local

Muitas pessoas já tinham o habito de versionar as versões dos seus arquivos em um procedimento manual localmente nas suas máquinas. Para cada modificação feita no projeto uma nova pasta com o timestamp era criada contendo a copia de todo o conteúdo para ser modificado. Este procedimento é super comum porque ele é bastante simples e fácil de se realizar mas muito complicado de se manter e garantir integridade, além é claro de não permitir o trabalho simultâneo de várias pessoas. Imaginem se o usuário por algum motivo se distrai e executa uma alteração na pasta errada? Seria abusar demais da sorte visto que é um ser humano que está realizando o versionamento.

Controle de versão centralizado

Os desenvolvedores precisavam encontrar uma forma de trabalhar juntos no mesmo conjunto de arquivos. Este desafio originou o que chamamos de controle de versão centralizado, bastante popular até os dias atuais no mercado de desenvolvimento de software. Sistemas para controle de versão centralizados como CVS, SVN possuem na figura do servidor um local central onde estão presentes todos os arquivos de um determinado projeto. Conectados a estes servidores estão os desenvolvedores que a partir de um processo denominado check-in e check-out conseguem realizar sincronismo com o repositório que versiona toda a operação.

Este modelo oferece uma série de vantagens em relação ao modelo local de versionamento.  Por exemplo, todo desenvolvedor possui a visão global em relação ao que os demais desenvolvedores estão produzindo sem nenhum tipo de coordenação entre eles.  Como tudo está centralizado é possível realizar trabalhamos simultâneos estando os desenvolvedores em locais geográficos distintos sem a preocupação individual com a integridade dos dados.

Mesmo parecendo ser um modelo bastante interessante o mesmo possui uma série de deficiências. A primeira e obvia seria possuir um único ponto de falha. Se o servidor de versão ficar fora do ar por algumas horas, nenhum integrante da equipe poderá colaborar com o desenvolvimento estando os mesmos dependentes deles para prosseguir o trabalho. Mesmo trabalhando de forma local e depois enviando os arquivos, muitas vezes se faz necessário realizar a necessidade de versões para garantir pontos de controles nos trabalhos. E no pior caso se os dados do servidor for corrompido por algum motivo aleatório mesmo tendo copias locais em cada máquina dos desenvolvedores, concordo que os dados serão recuperados mas pergunto. E as versões? Se as mesmas não fossem importantes não precisaríamos de um sistema para controle de versão e sim um grande servidor de backup de arquivos.

Os dois modelos descritos acima sofrem do mesmo problema. Se os dados no servidor de controle de versão for corrompido todas as versões serão perdidas.

Controle de versão distribuído

O grande diferencial aplicado pelos sistemas de versão distribuído é a ausência da figura central do servidor como ponto concentrador. No sistema de versão distribuído os clientes não efetuam check-out para obter a ultima revisão do conjunto de arquivos para sua máquina e sim para obter todo o repositório com todas as suas revisões. Caso todos os servidores apresentem falha e todo o repositório seja perdido, como todos os clientes possuem uma cópia do repositório qualquer um deles pode restaurar o repositório no servidor pois os mesmos possuem nas suas máquinas todo o histórico de revisão. É como se cada estação cliente se tornasse um nó de uma grande rede da ferramenta de controle de versão. Como todos os clientes se tornam nós da rede não se faz preciso a todo momento possuir conectividade com o servidor para trabalhar. Todo o versionamento é feito na sua própria máquina e futuramente é possível sincronizar com um nó servidor. Imagine, fazer commit na sua própria máquina sem ter internet dentro de um avião?

Outro ponto bastante positivo é que pelo fato de possuir todas as revisões na máquina local se torna possível realizar o processo de merge revisão por revisão com a tranquilidade de não sobrecarregar o servidor e reduzir a probabilidade de conflitos.  Mais a frente, nos próximos tutoriais, iremos ver na prática como isso funciona. Por hora acreditem, o merge no git é algo bastante evoluído em comparação as ferramentas anteriores.

História do GIT?

O git nasceu a partir de uma motivação do projeto do kernel  do linux a partir das deficiências apresentadas pela ferramenta que estava em uso antes da sua substituição pelo git.  O projeto do kernel do linux tem como principal característica um extenso escopo de tarefas e um processo de colaboração extremo visto que é um dos mais antigo projeto de software livre. No inicio(1991 – 2002) o projeto era mantido a partir de arquivos de patch e compactações. A partir de 2002, o projeto começou a utilizar um sistema de controle de versão distribuído chamado BitKeeper.

Em 2005, a relação entre os desenvolvedores do projeto kernel do linux e a empresa desenvolvedora do BitKeeper foi quebrada e o sistema passou a não ser mais utilizado pela comunidade.  Este evento motivou a comunidade desenvolvedora(em especial Linus Torvalds, pai do linux) a desenvolver o seu próprio sistema de controle de versão baseado em lições aprendidas com a ferramenta anterior. Este novo projeto tinha como requisitos: Velocidades, Simplicidade, Suporte robusto ao desenvolvimento paralelo(projetos com milhares de branchs), totalmente distribuído, capaz de tratar projetos de largas dimensões como por exemplo o projeto do kernel do linux dentro outros.

Em 2005 o projeto atingiu um nível de maturidade aceitável e foi lançado como livre distribuição. Apesar de ser um sistema com uma idade considerável, o GIT começou a se popularizar nos últimos anos principalmente em projetos de software livre. Em destaque podemos destacar o portal git-hub que assume o papel de repositório de projetos de código abertos baseado no git. Para quem não possui um servidor git disponível uma das melhores opções para trabalhar com o mesmo seria criar um projeto no git-hub.

Como o git funciona?

Então como o git funciona? O que muda para a forma tradicional de trabalhar com sistemas de controle de versão?  Para aprendermos a trabalhar com o git, devemos primeiramente esquecer de tudo que aprendemos com controles de versões subversion, cvs, source safe e outros. Apesar das interfaces de administração serem bastante parecidas com as dos outros sistema, o git trabalhar dentro de um paradigma diferente. Entendendo essas diferenças iremos poupar bastante tempo com enganos futuros ao se utilizar do git.

Snapshots e não diff

Uma das grandes diferenças entre o git e os demais sistemas de controle de versão é a forma como o git trata os arquivos. Conceitualmente, todos os sistemas de controle de versão armazenam o arquivos e todas as modificações aplicadas a este arquivo durante o tempo.

O git não trabalha dentro deste conceito, ao invés de armazenar apenas as mudanças, ele armazena um snapshot ou fotografia da situação de todo o sistema de arquivo criando uma espécie de mini-sistemas de arquivos. Todas vez que efetuamos uma operação no git o mesmo obtém uma fotografia de como todos os seus arquivos eram naquele instante e armazena a referência para esta fotografia. Para ser eficiente,  se um determinado arquivo não sofreu modificação, o git não armazena ele novamente, o mesmo cria um link para o arquivo não modificado numa fotografia anterior. Por estas características o git é considerado um mini sistema de arquivos capaz de armazenar diversas versões ou fotografias.

Trabalhe localmente sem stress

A maioria das operações no git são realizadas localmente na estação de trabalho sem necessidade de recuperar informações de uma outra estação ou servidor. Esta é uma grande diferença do git, como o usuário possui todas as versões do repositório localmente, a maioria das operações são realizadas de forma instantânea na própria estação poupando bastante tempo e consumo de recursos de rede visto que os tradicionais sistemas precisam se comunicar constantemente a cada operação.

Vamos ao exemplo, para visualizar o histórico do projeto ou até mesmo as diferenças entre duas versões, o git não precisa ir no servidor para obter e apresentar o histórico. A informação sempre é obtida a partir do repositório local tendo os resultados de forma instantânea sem consumo de recursos do servidor e nem da rede.  Sem contar nos momentos onde não temos conectividade mas precisamos adiantar o trabalho! Com os servidores tradicionais teríamos que esperar uma oportunidade de conexão com a internet ou VPN para podermos dar prosseguimento aos trabalhos.

Git é integro

Tudo no git é aplicado a processos de check-sum, ou seja, não é possível realizar modificações ou até mesmo corromper arquivos sem que o git perceba.  Toda referencia entre arquivos e versões tem como chave o hash do arquivo referenciado, ou seja, qualquer modificação é percebida e a integridade é garantida.

Os 3 estados fundamentais

Este é o principal conceito que deve ser entendido para se aprender a trabalhar com o git corretamente.  O git possui 3 principais estados os quais os arquivos pertencentes ao projeto podem estar marcados: commited, modified, staged. Arquivos no estado commited indicam que o mesmo está armazenado devidamente no repositório local; Modified são arquivos modificados mas que ainda não foram enviados para o repositório local; staged corresponde a arquivos que foram modificados e marcados(stag) para serem enviados no próximo snapshot do repositório ou próximo commit. Abaixo segue o esquema dos estados e locais onde são armazenados os arquivos.

O diretório git é o local onde o git armazena todos os metadados e objetos da base de dados do repositório. Esta é a parte mais importante de um projeto git e é criado no momento onde se inicializa um novo repositório ou efetua uma operação de clone de um outro computador. O diretório de trabalho possui uma estrutura de arquivos de uma determinada versão ou snapshot. Esta estrutura é descompactada do diretório git para o diretório de trabalho e é o local que será utilizado para modificar os arquivos do repositório. A área de stag é representada por um arquivo dentro do diretório git e possui uma relação de arquivos modificados e marcados para serem inseridos na próxima versão(commit).

Em resumo o fluxo de trabalho do git é simplificado e trabalha através do seguinte processo:

1- Usuário modifica um arquivo no diretório de trabalho local;

2- Usuário efetua o stag dos arquivos que deseja inserir no próximo snapshot ou versão;

3- Usuário efetua o commit transferindo os arquivos presentes na área de stag para o repositório local do git. Neste momento um novo snapshot é criado verificando as modificações na lista de arquivos taged.

Note que diferente dos sistemas sistemas tradicionais, apenas é feito o commit de arquivos que estiverem na área taged do repositório git local.

Chegamos ao final do primeiro post da série de tutoriais sobre o sistema para controle de versão git. No próximo post iremos abordar a parte prática como instalação e utilizações básicas.

* Este post foi baseado no livro pro-git.

Categorias:Tutorial Tags:,