Para qualquer um que não esteja familiarizado com version control systems (VCSs) de software livre, o Subversion se tornou um VCS não comercial padrão, substituindo o antigo campeão, Concurrent Versions System (CVS). O CVS ainda é útil para uso limitado, mas o atrativo do Subversion é que ele requer apenas um pouco de configuração em um servidor da Web e não muito além disso. O Subversion possui alguns problemas, os quais discutirei aqui, mas em sua maior parte, ele funciona bem.
Portanto, por que precisamos de um outro? Git ("G" maiúsculo;
git é a ferramenta da linha de comandos) é,
em muitos aspectos, projetado para ser melhor que o Subversion. Ele é um
dos muitos VCSs distribuídos . Minha própria experiência inicial
com o Arch/tla, como também Mercurial, Bazaar, darcs, e alguns outros. Por
muitas razões, que discutirei quando forem relevantes, o Git se torna
popular e é frequentemente considerado, juntamente com o Subversion,
as duas melhores opções para um VCS pessoal ou corporativo.
Há duas razões importantes para estar interessado no Git se você for um usuário do Subversion.
- Você está querendo mudar para o Git porque o Subversion está limitando você de alguma forma.
- Você está curioso sobre o Git e deseja descobrir como ele se compara com o Subversion.
Bem, talvez haja uma terceira razão: o Git é uma tecnologia relativamente recente que você deseja incluir em seu currículo. Espero que esse não seja seu principal objetivo; aprender o Git é uma das coisas mais recompensadoras que um desenvolvedor pode fazer. Mesmo se você não usa o Git agora, os conceitos e o fluxo de trabalho incorporado neste VCS distribuído são, certamente, um conhecimento crucial para a maioria dos segmentos do mercado de TI nos próximos 10 anos enquanto o mercado passa por grandes mudanças em escopo e distribuição geográfica.
Finalmente, embora não seja uma razão convincente se você não for um desenvolvedor de kernel Linux, o kernel e uma série de outros projetos importantes são mantidos com o uso do Git, assim, você desejará se familiarizar com ele se planeja contribuir.
Este artigo é destinado a usuários do Subversion de nível iniciante a intermediário. Ele requer um conhecimento de nível iniciante do Subversion e algum conhecimento geral sobre os VCSs. As informações aqui são principalmente para usuários de sistemas com base em UNIX® (Linux® e Mac OS X), com alguma coisa destinada aos usuários do Windows® .
A Parte 2 desta série discutirá usos mais avançados do Git: mesclando ramificações, gerando diffs e outras tarefas comuns.
Conceitos Básicos do Subversion e do Git
De agora em diante, abreviarei "Subversion" como "SVN" para não desgastar as teclas U, B, E, R, S, I e O.
Portanto, para o que o SVN é bom? Você talvez já saiba disso, mas um VCS não está relacionado a arquivos; está relacionado a alterações. O SVN, em execução em um servidor central, inclui alterações em seu repositório de dados e pode fornecer a você uma captura instantânea após cada alteração. Essa captura instantânea possui um número revisão; o número de revisão é muito importante para o SVN e para as pessoas que o usam. Se sua alteração for realizada após a minha, você certamente terá um número de revisão mais alto.
O Git possui um objetivo semelhante—controlar alterações—mas não possui nenhum servidor centralizado. Esta diferença é crucial. Enquanto o SVN é centralizado, o Git é distribuído; portanto, o Git não consegue fornecer um número de revisão crescente, porque não há nenhuma "revisão mais recente". Ele ainda possui IDs de revisão exclusivos; eles simplesmente não são tão úteis sozinhos quanto os números de revisão do SVN.
Com o Git, a ação crucial não é mais a consolidação; é a mesclagem. Qualquer um pode clonar um repositório e consolidar o clone. O proprietário do repositório tem a opção de mesclar alterações de volta. Como alternativa, os desenvolvedores podem empurrar alterações de volta ao repositório. Explorarei apenas este último, o modelo de push autorizado.
mantendo um diretório sob o SVN
Vamos começar com um exemplo simples e comum: controlando o conteúdo de um diretório com o SVN. Precisarei de um servidor SVN e, obviamente, um diretório de arquivos, assim como uma conta nesse servidor com direitos de consolidação para pelo menos um caminho. Comece incluindo e consolidando o diretório:
Lista 1. Configurando um diretório sob SVN
% svn co http://svnserver/...some path here.../top % cd top % cp -r ~/my_directory . % svn add my_directory % svn commit -m 'added directory' |
O que isso permite que você faça? Agora você pode obter a versão mais recente de qualquer arquivo consolidado sob este diretório, excluir arquivos, renomeá-los, criar novos arquivos ou diretórios, consolidar alterações em arquivos existentes e mais:
Lista 2. Operações básicas de arquivo sob SVN
# get latest % svn up # what's the status? % svn st # delete files % svn delete # rename files (really a delete + add that keeps history) % svn rename # make directory % svn mkdir # add file % svn add # commit changes (everything above, plus any content changes) % svn commit |
Não examinarei esses comandos em detalhes aqui, mas mantenha-os em mente.
Para
obter ajuda sobre qualquer um desses comandos, apenas digite
svn help COMMAND, e o Subversion mostrará
uma ajuda básica; consulte o manual para obter ajuda mais detalhada.
Mantendo um diretório sob o Git
Seguirei o mesmo caminho que no exemplo do SVN. Como antes, estou assumindo que você já possui um diretório cheio de dados.
Para o servidor remoto, usarei o serviço github.com gratuito, mas, claro, você pode configurar seu próprio servidor se desejar. O GitHub é uma forma fácil de brincar com um repositório Git remoto. Até o momento da elaboração deste documento, uma conta gratuita é limitada a 300 MB de dados e seu repositório deve ser público. Inscrevi como usuário "tzz" e criei um repositório público chamado "datatest"; fique a vontade para usá-lo. Forneço minha chave pública SSH; você deve gerar se você ainda não possui uma. Você também talvez deseje experimentar o servidor Gitorious ou o repo.or.cz. Você encontrará uma longa lista de serviços de hospedagem do Git no git.or.cz Wiki (consulte Recursos para um link).
Uma coisa boa sobre o GitHub é que ele é fácil de usar. Ele informa exatamente quais comandos são necessários para configurar o Git e inicializar o repositório. Abordaremos isso mais adiante.
Primeiro, é necessário instalar o Git, que é diferente em cada plataforma
e, em seguida, inicializá-lo. A página de download do Git (consulte Recursos) lista uma série de opções, dependendo da plataforma. (No Mac OS X, usei o comando port install git-core ,
mas você precisa configurar o MacPorts primeiro. Há também um instalador independente do MacOS X Git com
link a partir da página de download do Git; isso provavelmente funcionará melhor para
a maioria das pessoas.)
Assim que tiver concluído a instalação, veja a seguir os comandos que usei para uma configuração básica (selecione seu próprio nome de usuário e endereço de e-mail, naturalmente):
Lista 3. Configuração básica do Git
% git config --global user.name "Ted Zlatanov" % git config --global user.email "tzz@bu.edu" |
Você já deve perceber uma diferença do SVN; lá, sua identidade de usuário era do lado do servidor e você era quem quer que o servidor dissesse que você fosse. No Git, você pode ser O Maravilhoso Macaco de Wittgenstein se desejar (eu resisti à tentação).
Em seguida, configuro os arquivos de dados e inicializo meu repositório com eles. (O GitHub também importará a partir de um repositório público do SVN, o que pode ser útil.)
Lista 4. Configuração de diretório e primeira consolidação
# grab some files % cp -rp ~/.gdbinit gdbinit % mkdir fortunes % cp -rp ~/.fortunes.db fortunes/data.txt # initialize % git init # "Initialized empty Git repository in /Users/tzz/datatest/.git/" # add the file and the directory % git add gdbinit fortunes % git commit -m 'initializing' #[master (root-commit) b238ddc] initializing # 2 files changed, 2371 insertions(+), 0 deletions(-) # create mode 100644 fortunes/data.txt # create mode 100644 gdbinit |
Na saída acima, o Git está nos informando sobre os modos de arquivos;
100644 refere-se à versão octal dos bits
de permissão nesses arquivos. Não é necessário se preocupar com isso,
mas as 2371 inserções são difíceis de entender. Ele
alterou apenas dois arquivos, certo? Esse número, na realidade, refere-se ao
número de linhas inseridas. Não incluímos nenhuma, claro.
Que tal colocarmos nossas novas alterações no servidor GitHub? Os documentos
nos instruem como incluir um servidor remoto chamado "origin" (você pode usar qualquer nome). Devo
mencionar aqui que, se você deseja aprender mais sobre qualquer comando do Git,
por exemplo, git remote, você digitaria
git remote --help ou
git help remote. Isso é típico para
ferramentas de linha de comandos, e o SVN faz algo bastante semelhante.
Lista 5. Coloque as alterações no repositório remoto
# remember the remote repository is called "datatest"? % git remote add origin git@github.com:tzz/datatest.git # push the changes % git push origin master #Warning: Permanently added 'github.com,65.74.177.129' (RSA) to the list of known hosts. #Counting objects: 5, done. #Delta compression using 2 threads. #Compressing objects: 100% (4/4), done. #Writing objects: 100% (5/5), 29.88 KiB, done. #Total 5 (delta 0), reused 0 (delta 0) #To git@github.com:tzz/datatest.git # * [new branch] master -> master |
O aviso é do OpenSSH, pois o github.com antes não era um host conhecido. Nada com o que se preocupar.
As mensagens do Git são, digamos, meticulosas. Diferentemente das mensagens do SVN, que são fáceis de compreender, o Git é escrito para mentats, por mentats. Se você for do universo Dune de Frank Herbert e estiver treinado como um computador humano, você provavelmente já escreveu sua própria versão do Git, simplesmente porque é possível. Para o restante de nós, a compactação delta e o número de encadeamentos usados por ele são simplesmente não muito relevantes (e eles nos causam muitas dores de cabeça).
O push foi realizado sobre SSH, mas você pode usar outros protocolos, tal como HTTP,
HTTPS, rsync e file. Consulte
git push --help.
A seguir temos a diferença crucial, mais importante e básica entre SVN e Git. A consolidação do SVN diz "coloque isso no servidor central". Até consolidar no SVN, suas alterações são de outro mundo. Com o Git, sua consolidação é local, e você possui um repositório local, não importando o que acontece no lado remoto. É possível reverter uma alteração, ramificação, consolidação na ramificação e assim por diante, sem qualquer interação com o servidor remoto. O push com o Git é, efetivamente, uma sincronização do estado de ser repositório com o servidor remoto.
Certo, então, finalmente, vamos ver o log do Git do que acabou de acontecer:
Lista 6. O log do Git
% git log #commit b238ddca99ee582e1a184658405e2a825f0815da #Author: Ted Zlatanov <tzz@lifelogs.com> #Date: ...commit date here... # # initializing |
Apenas a consolidação está no log (observe o longo e aparentemente aleatório
ID de consolidação comparado com o número de revisão do SVN). Não há nada
mencionando a sincronização via git push.
Até então, estivemos usando o Git em substituição ao SVN. Claro, para
torná-lo interessante, precisamos ter múltiplos usuários e conjuntos de alterações envolvidos. Farei
o registro de saída do repositório para uma outra máquina (executando Ubuntu GNU/Linux,
neste caso; você precisará instalar git-core e
não git):
Lista 7. Configurando uma outra identidade do Git e registrando a saída do repositório
% git config --global user.name "The Other Ted" % git config --global user.email "tzz@bu.edu" % git clone git@github.com:tzz/datatest.git #Initialized empty Git repository in /home/tzz/datatest/.git/ #Warning: Permanently added 'github.com,65.74.177.129' (RSA) to the list of known hosts. #remote: Counting objects: 5, done. #remote: Compressing objects: 100% (4/4), done. #Indexing 5 objects... #remote: Total 5 (delta 0), reused 0 (delta 0) # 100% (5/5) done % ls datatest #fortunes gdbinit % ls -a datatest/.git # . .. branches config description HEAD hooks index info logs objects refs % ls -a datatest/.git/hooks # . .. applypatch-msg commit-msg post-commit post-receive post-update # pre-applypatch pre-commit pre-rebase update |
Novamente, observe o aviso do OpenSSH indicando que não realizamos nenhuma
operação com o GitHub sobre SSH antes a partir desta máquina. O comando
git clone é como um registro de saída do SVN mas, em vez de de
obter a versão sintetizada do conteúdo (uma captura instantânea a partir
de uma determinada revisão ou da revisão mais recente), você está obtendo
todo o repositório.
Incluí o conteúdo do diretório datatest/.git e o subdiretório de ganchos sob ele para mostrar que você realmente obtém tudo. O Git, por padrão, não guarda nenhum segredo, diferentemente do SVN que, por padrão, mantém o repositório privado e permite acesso apenas às capturas instantâneas.
Eventualmente, se você deseja empregar algumas regras em seu repositório Git, seja em todas as consolidações ou em outros momentos, os ganchos são o local. Eles são shell scripts, como os ganchos SVN, e possuem a mesma convenção UNIX padrão de "retornar zero para êxito, qualquer outra coisa para falha". Não entrarei em mais detalhes sobre os ganchos aqui, mas se sua ambição é usar o Git em equipe, definitivamente você deverá estudá-los.
Certo, então "O Outro Ted" é brincalhão e deseja incluir um novo arquivo na ramificação principal (aproximadamente equivalente ao TRUNK do SVN) e também cria uma nova ramificação com algumas alterações no arquivo gdbinit.
Lista 8. Incluindo um arquivo e criando uma nova ramificação
# get a file to add... % cp ~/bin/encode.pl . % git add encode.pl % git commit -m 'adding encode.pl' #Created commit 6750342: adding encode.pl # 1 files changed, 1 insertions(+), 0 deletions(-) # create mode 100644 encode.pl % git log #commit 675034202629e5497ed10b319a9ba42fc72b33e9 #Author: The Other Ted <tzz@bu.edu> #Date: ...commit date here... # # adding encode.pl # #commit b238ddca99ee582e1a184658405e2a825f0815da #Author: Ted Zlatanov <tzz@lifelogs.com> #Date: ...commit date here... # # initializing % git branch empty-gdbinit % git branch # empty-gdbinit #* master % git checkout empty-gdbinit #Switched to branch "empty-gdbinit" % git branch #* empty-gdbinit # master % git add gdbinit % git commit -m 'empty gdbinit' #Created commit 5512d0a: empty gdbinit # 1 files changed, 0 insertions(+), 1005 deletions(-) % git push #updating 'refs/heads/master' # from b238ddca99ee582e1a184658405e2a825f0815da # to 675034202629e5497ed10b319a9ba42fc72b33e9 #Generating pack... #Done counting 4 objects. #Result has 3 objects. #Deltifying 3 objects... # 100% (3/3) done #Writing 3 objects... # 100% (3/3) done #Total 3 (delta 0), reused 0 (delta 0) |
Esse foi um longo exemplo e espero que não tenha dormido; se dormiu, espero que tenha sonhado com os repositórios do Git sincronizando em uma infinita valsa de conjuntos de alterações. (Oh, você terá esses sonhos, não se preocupe.)
Primeiro, incluí um arquivo (encode.pl, apenas uma linha) e o consolidei. Após
a consolidação, o repositório remoto no GitHub não tinha nenhuma ideia de que
fiz alterações. Então, criei uma nova ramificação chamada
empty-gdbinit e passei a usá-la (eu poderia
ter feito isso com git checkout -b empty-gdbinit
também). Nessa ramificação, esvaziei o arquivo gdbinit e consolidei aquela
alteração. Finalmente, coloquei no servidor remoto.
Se eu passar a usar para a ramificação principal, não verei o gdbinit vazio nos logs. Portanto, cada ramificação possui seu próprio log, o que faz sentido.
Lista 9. Consultando logs entre ramificações
# we are still in the empty-gdbinit branch % git log #commit 5512d0a4327416c499dcb5f72c3f4f6a257d209f #Author: The Other Ted <tzz@bu.edu> #Date: ...commit date here... # # empty gdbinit # #commit 675034202629e5497ed10b319a9ba42fc72b33e9 #Author: The Other Ted <tzz@bu.edu> #Date: ...commit date here... # # adding encode.pl # #commit b238ddca99ee582e1a184658405e2a825f0815da #Author: Ted Zlatanov <tzz@lifelogs.com> #Date: ...commit date here... # # initializing % git checkout master #Switched to branch "master" % git log #commit 675034202629e5497ed10b319a9ba42fc72b33e9 #Author: The Other Ted <tzz@bu.edu> #Date: ...commit date here... # # adding encode.pl # #commit b238ddca99ee582e1a184658405e2a825f0815da #Author: Ted Zlatanov <tzz@lifelogs.com> #Date: ...commit date here... # # initializing |
Quando realizei o push, o Git disse, "Ei, olhe isso, um novo arquivo chamado encode.pl" nos servidores do GitHub.
A interface da Web do GitHub agora exibirá o encode.pl. Mas ainda há apenas
uma ramificação no GitHub. Por que a ramificação empty-gdbinit
não foi sincronizada? É porque o Git não assume que você deseja realizar
o push de ramificações e suas alterações por padrão. Por isso, você precisa
realizar o push de tudo:
Lista 10. Realizando o push de tudo
% git push -a #updating 'refs/heads/empty-gdbinit' # from 0000000000000000000000000000000000000000 # to 5512d0a4327416c499dcb5f72c3f4f6a257d209f #updating 'refs/remotes/origin/HEAD' # from 0000000000000000000000000000000000000000 # to b238ddca99ee582e1a184658405e2a825f0815da #updating 'refs/remotes/origin/master' # from 0000000000000000000000000000000000000000 # to b238ddca99ee582e1a184658405e2a825f0815da #Generating pack... #Done counting 5 objects. #Result has 3 objects. #Deltifying 3 objects... # 100% (3/3) done #Writing 3 objects... # 100% (3/3) done #Total 3 (delta 1), reused 0 (delta 0) |
Novamente, a interface mentat está aqui completamente. Mas podemos
resolver as coisas, certo? Talvez não sejamos mentats, mas pelo menos
temos o senso comum para perceber que
0000000000000000000000000000000000000000 é
algum tipo de tag inicial especial. Também podemos perceber nos logs na
Lista 9 que a tag
5512d0a4327416c499dcb5f72c3f4f6a257d209f é a
última (e única) consolidação na ramificação empty-gdbinit
. O restante também pode estar em aramaico para a maioria dos usuários; eles
simplesmente não se importam. O GitHub mostrará agora a nova ramificação e as alterações nela.
Você pode usar git mv e
git rm para gerenciar arquivos, renomeando
e removendo-os, respectivamente.
Neste artigo, expliquei conceitos básicos do Git e usei o Git para manter um conteúdo de diretório simples sob o controle de versão, comparando o Git com o Subversion. Expliquei a ramificação usando um exemplo simples.
Na Parte 2, explorarei a mesclagem, geração de diffs e alguns outros comandos do Git. Recomendo a leitura do manual do Git de fácil compreensão ou, pelo menos, uma passada pelo tutorial. Tudo está disponível na página inicial do Git, portanto, gaste algum tempo explorando-a. (Consulte Recursos abaixo para obter os links.) A partir da perspectiva de um usuário SVN, você não precisa muito mais que isso.
Por outro lado, o Git é um DVCS bastante poderoso; aprender mais sobre seus recursos quase certamente o levará a usá-los para simplificar e melhorar seu fluxo de trabalho no VCS. Além disso, você pode até ter um ou dois sonhos com os repositórios Git.
Aprender
- O
Git - SVN Crash Course é uma
referência útil para aqueles já familiarizados com o SVN. Um outro
bom tutorial é o tutorial de Flavio Castelli, chamado
Howto use Git and SVN together.
- Para obter os recursos de hospedagem do Git, experimente
GitHub,
Gitorious,
repo.or.cz e esta
lista de sites de hospedagem pública do Git.
-
A visão sobre o Subversion
do Wikipedia
é bastante completa, como a introdução no
Git.
- Obtenha informações de Robby Russell,
que
migrou do Subversion para o Git
e sobreviveu para nos contar.
- Na
zona do Linux do developerWorks, encontre mais recursos para desenvolvedores do Linux e verifique nossos
artigos e tutoriais mais populares.
- Consulte todas as
dicas do Linux
e
tutoriais do Linux
no developerWorks.
- Permaneça atualizado com os
Eventos Técnicos e Webcasts do developerWorks.
Obter produtos e tecnologias
- Obtenha o Git e consulte a
página de download do Git, assim como as toneladas
de documentações e ferramentas.
- Com o
software de avaliação da IBM, disponível para download diretamente a partir do developerWorks, construa seu próximo projeto de desenvolvimento no Linux.
Discutir
- Envolva-se com a
comunidade My developerWorks; com seu perfil pessoal e página inicial customizada, é possível padronizar o developerWorks para seus interesses e interagir com outros usuários do developerWorks.
Teodor Zlatanov surgiu com um Mestrado em Ciências em engenharia da computação da Boston University em 1999. Trabalha como programador desde 1992, usando Perl, Java, C e C++. Seus interesses estão em trabalho em análise de textos de software livre, arquiteturas de banco de dados, interfaces com o usuário e administração do sistema UNIX.