Pages

Thursday, August 4, 2011

Criando um Servidor Git usando Gitweb, Gitosis e o próprio Git

Todos nós desenvolvedores, um dia, utilizaremos ou, senão, já usamos Controles de Versões de projetos. Nesse post, eu comentarei um pouco sobre a criação de um servidor Git particular para ser usado como repositório. Além disso, indicarei possíveis erros que possam ocorrer durante a criação do mesmo.

Primeiramente devemos instalar no servidor os pacotes necessários.

$ sudo apt-get install git-core gitosis gitweb


Aplicando o Gitosis

Com os pacotes já instalados, recomendamos que seja criado um usuário no servidor chamado 'git' exclusivo e sem senha,

$ sudo adduser \
  --system \
  --shell /bin/bash \
  --gecos 'Git Version Control' \
  --group \
  --disabled-password \
  --home /home/git \
  git

 Criado o usuário, vamos ter como resposta,

Adding system user 'git'...
Adding new group 'git' (211).
Adding new user 'git' (211) with group 'git'.
Creating home directory '/home/git'.

Como queremos acessar o usuário 'git' sem senha, criaremos uma chave RSA pública em nossa própria máquina e não no servidor. Primeiramente, devemos criar (se ela ainda não existir) uma pasta chamada .ssh em /home/git/ com,

$ mkdir .ssh

Já em nossa máquina devemos criar a chave pública fazendo,

$ ssh-keygen -t rsa

e compiamos ela para a pasta /tmp/ do servidor,

$ scp ~/.ssh/id_rsa.pub seu_login@servidor_hostname:/tmp/

Feito isso, liberamos o acesso com,

$ sudo cat /tmp/id_rsa.pub >> /home/git/.ssh/authorized_keys

Agora podemos acessar via SSH nosso usuário Git sem senha. Para começarmos a utilizar o Gitosis, devemos efetuar o seguinte comando no home folder do usuário git,

$ sudo -H -u git gitosis-init < id_rsa.pub

Sendo a saída esperada justamente duas vezes a mesma mensagem,

Initialized empty Git repository in ./
Initialized empty Git repository in ./

Devemos habilitar o script para execução do git update-server-info com,

$ sudo chmod 755 /home/git/repositories/gitosis-admin.git/hooks/post-update

Na sua máquina agora será possível realizar um git clone via SSH.

$ git clone git@servidor_hostname:~/repositories/gitosis-admin.git
$ cd gitosis-admin.git

Você, primeiramente, irá clonar um repositório vazio e, posteriormente, poderá inserir arquivos a serem adicionados ao commit.

Para adicionar permissões, é possível editar o arquivo encontrado em /home/git/repositories/gitosis-admin.git/gitosis.conf no servidor. Editando-o da seguinte maneira,

[gitosis]

[group gitosis-admin]
writable = giosis-admin
members = nome_do_usuário

Para adicionar mais grupos, repositórios ou membros, podemos exemplificar com o modelo abaixo,

[group laboratório]
writable = projeto
members = usuário1 usuário2 usuário3

* Importante: Se optarmos por garantir o acesso público utilizando o protocolo Git, devemos efetuar,

$ touch ~/repositories/gitosis-admin.git/git-daemon-export-ok

e iniciaremos o daemon com,

$ sudo -u git git daemon --base-path=/home/git/repositories --export-all

Assim, podemos usar o git clone efetuando,

$ git clone git://servidor_hostname/gitosis-admin.git

Devemos lembrar que o protocolo Git é usado somente leitura. Portanto em casos de git push essa URL não será válida levando a erros que serão reportados em outros posts.


Criando outros Repositórios de Projetos

Podemos criar pastas no mesmo diretório que o gitosis-admin. No meu caso, como utilizarei o Gitweb criarei uma outra pasta dentro de /home/git/repositories/, chamada de "projects" e dentro de "projects" criarei o "meuprojeto".

$ cd /home/git/repositories/
$ mkdir projects
$ cd projects
$ mkdir meuprojeto

Para fazer com que "meuprojeto" seja um repositório git, devemos realizar os seguintes comandos,

$ cd meuprojeto
$ git --bare init
$ cp ~/repositories/gitosis-admin.git/hooks/post-update /hooks/
$ touch ~/repositories/projects/meuprojeto/git-daemon-export-ok

Voltando a máquina local, podemos cloná-lo para adicionar os arquivos referentes ao projeto. Obviamente, temos a liberdade de fazer isso diretamente no servidor, entretanto, essa é uma forma que eu acredito ser mais organizada e mais lógica. Portanto, efetuaremos o seguinte comando,

$ git clone git://servidor_hostname/projects/meuprojeto

Uma mensagem de alerta aparecerá, informando que o repositório git clonado está vazio. Uma mensagem absolutamente normal.

Podemos copiar todos os arquivos referentes, efetuando, por exemplo,

$ cd meuprojeto
$ git add .
$ git commit -a -m "Qualquer informação válida sobre o commit"
$ git push origin master

O git push origin master irá realizar um commit inicial no branch master da origem que é o servidor. É muito importante realizar esse primeiro comando no primeiro push.

* Importante: Após realizarmos essas alterações no projeto, o mais lógico seria enviá-las ao servidor como forma de atualização do repositório do projeto, mas quando efetuamos o comando acima,

$ git push origin master

Uma mensagem como essa aparecerá,

fatal: The remote end hung up unexpectedly

Isso acontece graças ao clone realizado com o protocolo git, na qual, é um protocolo usado somente para leitura e não para a escrita de dados vindos do servidor. Então, quando efetuamos um push ele tentará acessar a URL usada no clone que será git://servidor_hostname/projects/meuprojeto, não obtendo sucesso. Para corrigirmos essa situação, temos a opção de atualizar as configurações do nosso projeto verificadas em,

$ git config --list

podemos observar o campo remote.origin.url="..." como sendo igual a URL clonada. Para alterarmos, basta executar um editor e alterar esse campo com a URL destinada ao SSH.

$ vim .git/config

e editarmos o campo,

...
[remote "origin"]
fetch = +refs/heads/*:refs/remotes/origin/*
url = git@servidor_hostname:~/repositories/projects/meuprojeto
...

Agora, podemos executar o git push,

$ git push origin master

Não iremos cobrir nesse post a configuração do Apache para assim usarmos o protocolo HTTP em clones de repositórios. Futuramente, iremos abordar melhor como fazer tal procedimento.

Finalizando, por questões de segurança, podemos limitar o acesso via SSH ao usuário Git fazendo,

$ chsh -s /usr/bin/git-shell

Terminamos aqui uma configuração básica e essencial de um servidor Git utilizado para hospedar projetos e trabalhos.


Configurando o Gitweb

A configuração do Gitweb é relativamente fácil. Procedemos,

$ sudo mkdir /var/www/git

Criada a pasta, configuremos o Git no Apache,

$ sudo vim /etc/apache2/conf.d/git

preenchendo, então, o arquivo com os seguinte dados:

<Directory /var/www/git>
        Allow from all
        AllowOverride all
        Order allow,deny
        Options ExecCGI
        <Files gitweb.cgi>
                SetHandler cgi-script
        </Files>
</Directory>

O Próximo passo é mover todos os arquivos provenientes do Gitweb para a nova pasta criada.

$ sudo mv /usr/share/gitweb/* /var/www/git/
$ sudo mv /usr/lib/cgi-bin/gitweb.cgi /var/www/git/

Para terminarmos a configuração, editemos o arquivo de configuração do Gitweb,

$ sudo vim /etc/gitweb.conf

como o exemplo abaixo (que segue o exemplo da criação do repositório "meuprojeto"),

# path to git projects (<project>.git)
$projectroot = "/home/git/repositories/projects/";

# directory to use for temp files
$git_temp = "/tmp";

# target of the home link on top of all pages
#$home_link = $my_uri || "/";

# html text to include at home page
$home_text = "indextext.html";

# file with project list; by default, simply scan the projectroot dir.
$projects_list = $projectroot;

# stylesheet to use
$stylesheet = "gitweb.css";

# javascript code for gitweb
$javascript = "gitweb.js";

# logo to use
$logo = "git-logo.png";

# the 'favicon'
$favicon = "git-favicon.png";

Terminamos assim a configuração do Gitweb e podemos acessar nossos projetos, seus commits, diffs via página HTML.


Problemas que podem ocorrer durante a configuração do Servidor

Alguns problemas já foram descritos acima, como problemas decorrentes do protocolo Git que se comporta como somente leitura sendo corrigida.

Um problema enfrentado quando eu solicitei um git clone foi o bloqueio da porta 9418 (utilizada pelo git daemon) recebendo um,

fatal: unable to connect a socket (Connection timed out)

Para liberarmos o firewall para utilizarmos o Git, no meu caso eu abilitei a porta 9418, no iptables, da seguinte maneira,

$ sudo vim /etc/init.d/iptables

Adicinando a seguinte linha ao Documento,

# git
iptables -A INPUT -p tcp -s 0/0 -d 0/0 --destination-port 9418 -j ACCEPT

É sempre bom documentarmos para quem estamos adicionando uma liberação, isso ajuda outros utilizadores do servidor em caso de alguma manutenção ou outros usos. Documentação é essencial pra qualquer prática de programação.

Por fim reiniciaremos o firewall aplicando as mudanças com,

$ sudo /etc/init.d/iptables restart

Quem seguiu as práticas citadas acima, verificou exatamente tudo, prestou a atenção em cada linha de comando, mas ainda não consegue realizar um clone ou um push, pode analisar os logs mantidos pelo git daemon. Esse arquivo, para mim, foi uma peça chave para identificar problemas relacionados a localização dos repositórios e a erros relacionados a conexão. Para analisarmos esse arquivo, realizemos um,

$ sudo cat /var/log/git-daemon/current

Na qual a minha saída no shell foi,

2011-08-01_12:36:40.42770 git-daemon starting.

Mas há todo o tipo de mensagem que envolva o git-daemon.


Considerações Finais

Não há muita complexidade para criarmos um servidor de repositórios Git em um servidor pessoal, entretanto algumas dificuldades são providas com base em outros serviços que podem influenciar na conexão, ou os próprios protocolos muitas vezes merecem um estudo antes de serem usados como o protocolo Git. Erros também aparecem devido a erros de sintaxe no momento da configuração do servidor, por isso, é sempre bom estarmos atentos aos procedimentos.

As referências usadas no auxílio da elaboração desse post são listadas a seguir, bem como um tutorial básico da utilização do Git:

[Tutorial de Git] - Tutorial elaborado por mim que abrange o essencial de Git.

[scie.nti.st] - Tutorial bem bacana sobre Git Server.
[noroyalties.org] - Um outro tutorial usado na referência.
Pro Git - Professional Version Control - Livro on-line interessante a respeito de Git.

2 comments:

  1. Interessante seu tutorial. No entanto devido executar operações em locais diferentes, não fica claro o suficiente, na sequência de execução de comandos, que usuário deve ser usado e onde. Por exemplo, seguindo os passos, fui executar sudo -H -u git gitosis-init < id_rsa.pub dentro do diretório /home/git, como você indicou, mas recebi erro de file not found.

    ReplyDelete
    Replies
    1. Olá!
      Obrigado pela observação e pela dúvida! Realmente há um erro no comando citado! O correto seria "sudo -H -u git gitosis-init < /tmp/id_rsa.pub", executado no servidor. Caso o erro continue, estamos prontos a ajudar.

      Delete