Controle de versão é algo muito importante para os desenvolvedores. Infelizmente, muita gente ainda desconhece ou ignora a existência desses sistemas e trabalha de forma amadora. Há alguns dias atrás, por exemplo, conheci uma empresa que usava arquivos .zip, criados pelos próprios funcionários e sem nenhum padrão, para fazer o controle de versão.
Meu primeiro contato de verdade (algo mais complexo que update e commit) com um controle de versão foi no Arch Linux, com o svn e o git. Com o HnTool cheguei a utilizar alguns dos principais sistemas (svn, git, bazaar) até chegar ao atual, o mercurial.
Notei que algumas das pessoas que estão tentando contribuir com o HnTool desconhecem, ou estão tendo dificuldades com o Mercurial. Sabendo disso, resolvi fazer este pequeno guia introdutório a ferramenta, que pode ser de grande ajuda para os novatos.
Primeiros passos
O primeiro passo a ser dado é clonar o repositório, que é basicamente baixar todo o código que está sob o controle de versão:
$ hg clone https://hntool.googlecode.com/hg/ hntool
Ao clonar um repositório você verá uma saída parecida com essa:
requesting all changesadding changesetsadding manifestsadding file changesadded 172 changesets with 289 changes to 61 files (+1 heads)updating to branch default29 files updated, 0 files merged, 0 files removed, 0 files unresolved
$ cd hntool/$ ls -a.hg AUTHORS doc hntool HnTool LICENSE NEWS po README setup.py TODO
Obtendo informações sobre o repositório
$ hg parents
A saída será parecida com essa:
changeset: 171:094fbddeb14d
tag: tip
parent: 169:4fd6ed215b13
parent: 170:7c24fb8c6685
user: Hugo Doria
date: Mon Apr 26 23:48:27 2010 -0300
summary: merging apache changes
Uma outra forma de obter informações sobre o último changeset é usando o tip:
$ hg tip
changeset: 171:094fbddeb14d
tag: tip
parent: 169:4fd6ed215b13
parent: 170:7c24fb8c6685
user: Hugo Doria
date: Mon Apr 26 23:48:27 2010 -0300
summary: merging apache changes
Se você quer saber o histórico das mudanças feitas no repositório use:
$ hg log
Exemplo de saída:
changeset: 171:094fbddeb14d
tag: tip
parent: 169:4fd6ed215b13
parent: 170:7c24fb8c6685
user: Hugo Doria
date: Mon Apr 26 23:48:27 2010 -0300
summary: merging apache changeschangeset: 170:7c24fb8c6685
parent: 166:56647cd76822
user: Filipe Rosset
date: Sun Apr 25 22:14:06 2010 -0300
summary: Fix ServerSignature commentschangeset: 169:4fd6ed215b13
user: Hugo Doria
date: Mon Apr 26 23:45:09 2010 -0300
summary: Checking the delay between failed login prompts
Cada grupo desse é referente a um changeset, que nada mais é que a mudança de um ou mais arquivos, agrupadas em uma unidade lógica. No caso acima existem três changesets. Entender cada campo do changeset é fácil:
- changeset: esse campo é composto por duas partes, separadas por um ":". A primeira das partes é o número da revisão, um identificador do changeset. A segunda parte é um hexadecimal referente ao ID do changeset.
- parent: esse campo geralmente aparece quando você faz um merge no repositório e identifica todos os changesets relacionados com ele.
- user: a pessoa que criou o changeset.
- date: a data que o changeset foi criado. Esta data é referente a timezone do criador do changeset.
- summary: é a descrição do changeset. Essa mensagem é passada na hora do commit.
Sabendo clonar o repositório e lidar com o histórico de mudanças já da para começar a fazer suas próprias modificações.
Modificando o código
Uma prática recomendada antes de fazer qualquer mudança é criar um novo repositório para isolar as mudanças que irá fazer. Isso previne que você misture código que está sendo testado com seu código real, permite que você teste certas partes do código, trabalhe em diversas tarefas ao mesmo (todas isoladas) etc.
Para criar um novo repositório e isolar nosso código é preciso clonar o atual. Dessa vez não vamos clonar o repositório remoto, mas sim o local. Sim, um clone do clone:
$ cd ../
$ hg clone hntool novo-hntool
updating to branch default
31 files updated, 0 files merged, 0 files removed, 0 files unresolved$ cd novo-hntool
Agora podemos fazer nossas mudanças. Vamos, por exemplo adicionar um novo teste ao módulo ftp:
# Checking if we chroot users into the ftp users' home directory if 'DefaultRoot' in lines: if lines['DefaultRoot'] != '~': check_results['medium'].append('ProFTPd does not chroot users') elif lines['DefaultRoot'] != '~': check_results['ok'].append('ProFTPd chroot users') else: check_results['medium'].append('ProFTPd does not chroot users')
Salve suas mudanças. Agora rode o comando abaixo:
$ hg status
M HnTool/modules/ftp.py
Este comando diz o que há de novo no seu repositório. É através dele que o mercurial diz o que sabe sobre seus arquivos. Se a linha começa com "M", então o mercurial está dizendo que aquele arquivo foi modificado. Seguem alguns possíveis status:
- M NEWS : o arquivo NEWS foi modificado
- ? NEWS : o arquivo NEWS é desconhecido pelo mercurial
- A NEWS : o arquivo NEWS será adicionado ao mercurial
- R NEWS : o arquivo NEWS será removido do mercurial
Além de saber que aquele arquivo foi modificado, também podemos saber quais foram as mudanças. Para isso é só usar o diff do mercurial:
$ hg diff
diff -r a7375e5e4599 HnTool/modules/ftp.py
--- a/HnTool/modules/ftp.py Mon May 17 21:13:35 2010 -0300
+++ b/HnTool/modules/ftp.py Mon May 17 21:33:15 2010 -0300@@ -81,7 +81,16 @@
else:
check_results['ok'].append('ProFTPd allows footprinting')
+ # Checking if we chroot users into the ftp users' home directory
+ if 'DefaultRoot' in lines:
+ if lines['DefaultRoot'] != '~':
+ check_results['medium'].append('ProFTPd does not chroot users')
+ elif lines['DefaultRoot'] != '~':
+ check_results['ok'].append('ProFTPd chroot users')
+ else:
+ check_results['medium'].append('ProFTPd does not chroot users')
+
if not proftpd_conf_file_found:
check_results['info'].append('Could not find a proftpd.conf file')
- return check_results\ No newline at end of file
+ return check_results
Apesar de você já poder visualizar suas mudanças, elas ainda não foram armazenadas de fato. Para confirmar suas mudanças você precisa fazer o commit:
$ hg commit
Ao chamar o commit o mercurial te leva a um editor de texto para que você possa escrever uma mensagem descrevendo o commit. Além de escrever a mensagem você também pode ver mais algumas informações deste commit.
Adding a new test on ftp module
HG: Enter commit message. Lines beginning with 'HG:' are removed.
HG: Leave message empty to abort commit.
HG: --
HG: user: Hugo Doria
HG: branch 'default'
HG: changed HnTool/modules/ftp.py
Se preferir, você pode fazer o commit e passar a mensagem no mesmo comando usando a opção "-m":
$ hg commit -m "Adding a new test on ftp module"
O resultado é o mesmo. Lembre-se que esta mensagem passada no commit ficará armazenada no log (hg log), então tente escrever uma mensagem curta, porém esclarecedora. Caso você deixe a mensagem em branco o commit será abortado.
Se você rodar o "hg status" agora verá que não há nada com um status diferente:
$ hg status
Isso acontece porque suas mudanças já foram "comitadas".
Compartilhando as mudanças
Como dito anteriormente, os repositórios "hntool" e "novo-hntool" são isolados e independentes. Por causa disso, as mudanças que acabamos de fazer só foram aplicadas ao "novo-hntool", que não é nosso repositório "principal".
Temos algumas maneiras de fazer com que as mudanças feitas sejam propagadas em outros repositórios. Para fazer os testes vamos criar um novo clone (sim, mais um) do repositório principal, aquele que não foi modificado:
$ cd ..
$ hg clone hntool hntool-compartilhado
updating to branch default
31 files updated, 0 files merged, 0 files removed, 0 files unresolved$ cd hntool-compartilhado
Com o comando pull podemos baixar todas as mudanças que estão em outro repositório, seja ele local, ou não. Porém, antes de fazer isso é bom saber quais as mudanças que serão baixadas ao rodar o pull. Para isso faça:
$ hg incoming ../novo-hntool
comparing with ../novo-hntool/
searching for changes
changeset: 202:52926d72b9e2
tag: tip
user: Hugo Doria
date: Mon May 17 21:45:21 2010 -0300
summary: Adding a new test on ftp module
Nesse caso ele só vai baixar uma mudança, que é exatamente a que fizemos anteriormente. Agora sim podemos rodar o pull sem medo:
$ hg pull ../novo-hntool
pulling from ../novo-hntool/
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
(run 'hg update' to get a working copy)
No caso acima baixamos as mudanças no repositório "novo-hntool", mas poderíamos baixar de um repositório remoto, por exemplo.
Apesar do comando pull ter trazido todas as mudanças para o atual repositório, elas ainda não foram aplicadas. Para aplicá-las de verdade é preciso rodar o comando update:
$ hg update
1 files updated, 0 files merged, 0 files removed, 0 files unresolved
Achou estranho o comando pull não atualizar de verdade os arquivos? Não se preocupe, eu também achei no começo. Mas no livro do mercurial há uma boa explicação para isso:
Quando rodamos o "pull", o mercurial só atualiza o diretório ".hg", aquele que possui os metadados do projeto, o histórico de revisões etc. Depois disso, o "update" aplica nos seus dados reais (sua cópia de trabalho) as mudanças que estão apenas nos metadados .
Rodar o pull e logo depois o update é algo bem comum no mercurial. Para facilitar a vida existe um atalho para fazer as duas operações ao mesmo tempo:
$ hg -u pull
Além de poder baixar as atualizações para um determinado repositório, também podemos enviá-las para outro repositório. Para isso usamos o comando push.
Assim como fizemos no passo anterior vamos clonar o nosso repositório principal:
$ cd ..
$ hg clone hntool hntool-push
updating to branch default
31 files updated, 0 files merged, 0 files removed, 0 files unresolved$ cd novo-hntool
Nós queremos enviar as mudanças feitas no "novo-hntool" para o "hntool-push". Antes, porém, vamos ver quais as mudanças que seriam enviadas:
$ hg outgoing ../hntool-push/
comparing with ../hntool-push/
searching for changes
changeset: 202:52926d72b9e2
tag: tip
user: Hugo Doria
date: Mon May 17 21:45:21 2010 -0300
summary: Adding a new test on ftp module
Confirmando que é isso mesmo que queremos, é só rodar o comando push:
$ hg push ../hntool-push/
pushing to ../hntool-push/
searching for changes
adding changesets
adding manifests
adding file changes
added 1 changesets with 1 changes to 1 files
Da mesma forma que acontece com o pull, também é preciso entrar no repositório hntool-push e rodar o update.
Quando não passamos o local para onde queremos realizar o push (ou pull), o mercurial assume o endereço padrão, que fica no arquivo .hg/hgrc, dentro do diretório do repositório. Por exemplo:
$ cat .hg/hgrc
[paths]
default = /meu/diretorio/hntool
Refertendo mudanças
Vamos supor que fizemos um mudança errada:
$ echo "lixo total" >> NEWs
Ao rodar o comando "hg status" veremos que o mercurial já reconheceu nossa mudança:
$ hg status
M NEWS
Esta mudança não é desejada. Felizmente, é muito fácil desfazê-la:
$ hg revert NEWS
$ hg status
? NEWS.orig
O que o mercurial fez foi reverter as mudanças do arquivo NEWS, deixando-o exatamente como era no último commit válido. Além disso, ele criou um arquivo NEWS.orig, que possui as mudanças erradas que fizemos. O NEWS.orig não está sob o controle do mercurial ainda. Por isso a "?" antes do seu nome. Se quiser, pode removê-lo.
Se você não especificar qual o arquivo que desejar reverter as mudanças, o mercurial irá reverter de todos os arquivos.
Alguém pode perguntar: mas e se eu já tivesse feito o commit? Mesmo assim daria para reverter? E a resposta é: sim, daria. Vamos a um exemplo:
Fazendo a mudança errada e o commit:
echo "novo lixo total" >> NEWS^C
$ hg status
M NEWS
$ hg commit -m "commit de lixo"
$ hg status
Como você ver a mudança foi confirmada. Para revertê-la podemos usar o rollback:
$ hg rollback
rolling back last transaction$ hg status
M NEWS
No caso, o mercurial desfez o commit. Entretanto, as mudanças feitas no arquivo NEWS ainda estão lá. Se quiser desfazer de vez será preciso rodar o revert novamente:
$ hg revert NEWS
$ hg status
? NEWS.orig
Adicionando e removendo arquivos
Quando criamos um novo arquivo na nossa cópia de trabalho ele não é reconhecido pelo mercurial. Por isso que ao rodar o comando "hg status" vemos um simbolo de "?" na frente do arquivo. Por exemplo:
$ > novoarquivo
$ hg status
? novoarquivo
Para que o mercurial reconheça este arquivo é preciso adicioná-lo ao repositório. Faça isso com:
$ hg add arquivo
Por exemplo:
$ hg add novoarquivo
$ hg status
A novoarquivo
Notem o "A" na frente do novo do arquivo. Isso significa que ele será adicionado ao nosso repositório no próximo commit.
Para remover um arquivo é só fazer:
$ hg remove arquivo
Por exemplo:
$ hg remove NEWS
$ hg status
A novoarquivo
R NEWS
O "R" na frente do arquivo significa que ele será removido do repositório no próximo commit.
Criando patches
Lembra que usando o comando "hg diff" é possível saber quais as mudanças que aconteceram nos arquivos? Com o mercurial também é possível gerar patches já formatados para ele. Para isso vamos usar o comando "export":
$ hg export NUMERO-DA-REVISAO
Por exemplo:
$ hg export 120
# HG changeset patch
# User Hugo Doria
# Date 1269294101 10800
# Node ID a945d6adad28ec20a81de9899e14d1edfa93cee9
# Parent 1bb54f09298ac7adebcc8ea992db24bfe16efcf5
Sorting the output by module alphabetical orderdiff -r 1bb54f09298a -r a945d6adad28 hntool
--- a/hntool Mon Mar 22 18:32:36 2010 -0300
+++ b/hntool Mon Mar 22 18:41:41 2010 -0300
@@ -108,7 +108,7 @@
# Run all the modules and its checks.
# The results of each module goes to "report"
report = []
-for m in rule_modules:
+for m in sorted(rule_modules):
report.append({'title': rule_modules[m].long_name(), \
'results': rule_modules[m].analyze(options)})
Para gerar um patch do último commit, por exemplo:
$ hg export tip
Se preferir é só jogar o output para um arquivo:
$ hg export tip > consertando-o-bug-115.patch
NOTA: Eu vou continuar atualizando este guia de acordo com as necessidades que for encontrando na hora de gerenciar o repositório do HnTool. Se for tiver alguma dúvida ou sugestão é só avisar.
Referências:
Essas e várias outras informações podem ser encontradas nos links abaixo:
- Mercurial book: http://hgbook.red-bean.com
- Hg Init: http://hginit.com/
- Mercurial Tutorial: http://mercurial.selenic.com/wiki/Tutorial
0sem comentários ainda