O Git é um sistema de controlo de versões usado para gerir o desenvolvimento de software. Parte do mesmo principio que o Subversion, em que alterações do código são gravadas incrementalmente, gerando assim um histórico de toda a aplicação. Um sistema destes (quer seja Subversion, Mercurial, Git ou outro qualquer) é essencial para quem desenvolve em equipa, tornando possível voltar atrás nas modificações e gerir eficazmente a alteração concorrente do código.
A grande diferença que separa o Git do Subversion é ser um sistema distribuído em vez de centralizado. O Subversion conta apenas com um repositório num servidor, enquanto que cada utilizador do Git tem um repositório local, para além de um repositório central. Assim, é possível fazer e gravar as alterações mais rapidamente “offline” e fazer o push para o repositório central mais tarde, obtendo mais eficiência e uma maior organização. Os pushes são menos frequentes mas continuamos com um sistema de versões local, onde podemos ir fazendo commit das alterações. Outra vantagem é um sistema de branches mais eficaz que encoraja os utilizadores a usar e abusar desta funcionalidade.
Esta ferramenta já existe há algum tempo mas apenas agora comecei a dar os meus primeiros passos com ela. Até hoje só tinha usado o Subversion num projecto académico e gostei bastante. A minha instalação do Git foi em Windows.
Basicamente temos uma shell ao nosso dispor com bastantes comandos do Linux a funcionar tal como seria de esperar. Também há um interface gráfico para quem não se sentir à vontade com a linha de comandos, apesar de não ter a mesma flexibilidade ou rapidez de uso.
Quem usar o Notepad++ pode alterar o editor default (o Vim!) com este comando:
git config --global core.editor "'C:/Program Files (x86)/Notepad++/notepad++.exe' -multiInst -notabbar -nosession -noPlugin"
Podem adaptar este comando a qualquer programa que queiram usar para fazer edições de texto. Normalmente estas edições são feitas aquando de um commit.
Agora que está tudo configurado, podemos experimentar alguns comandos.
Criar um Projecto e Repositório
Neste exemplo vou partir criar um projecto de raiz, mas podia-se aplicar o mesmo conceito para um que já tivesse alguns ficheiros.
MiKe@MIKE-PC ~
$ mkdir project1
MiKe@MIKE-PC ~
$ cd project1
MiKe@MIKE-PC ~/project1
$ git init
Initialized empty Git repository in c:/Users/MiKe/project1/.git/
MiKe@MIKE-PC ~/project1 (master)
$ touch readme file1 file2
MiKe@MIKE-PC ~/project1 (master)
$ ls
readme file1 file2
MiKe@MIKE-PC ~/project1 (master)
$ git add .
MiKe@MIKE-PC ~/project1 (master)
$ git status
# On branch master
#
# Initial commit
#
# Changes to be commited:
# (user "git rm --cached ..." to unstage)
#
# new file: file1
# new file: file2
# new file: readme
#
Com esta série de comandos criámos a pasta do projecto, criámos o repositório com git init, colocámos 3 ficheiros novos e adicionámos todos os ficheiros ao repositório (o ponto em git add . adiciona todos os ficheiros da pasta). O git status mostra-nos o estado actual do repositório.
Alterações e Commits
MiKe@MIKE-PC ~/project1 (master)
$ echo 'hello' > readme
MiKe@MIKE-PC ~/project1 (master)
$ git status
# On branch master
#
# Initial commit
#
# Changes to be commited:
# (user "git rm --cached ..." to unstage)
#
# new file: file1
# new file: file2
# new file: readme
#
# Changed but not updated:
# (use "git add ..." to update what will be commited)
# (use "git checkout -- ..." to discard changes in working directory)
#
# modified: readme
#
MiKe@MIKE-PC ~/project1 (master)
$ git commit -am 'first commit'
[master (root-commit) f734740] first commit
1 files changed, 1 insertions(+), 0 deletions (-)
create mode 100644 file1
create mode 100644 file2
create mode 100644 readme
Inserimos texto num dos ficheiros e podemos ver que esta alteração está por guardar através do git status. Se o commit for feito com o -m podemos inserir a descrição através da própria linha de comandos. Caso seja um commit importante devemos perder algum tempo a colocar uma descrição decente através de um editor de texto, de modo a podermos navegar o histórico das alterações com algum contexto.
Branches, Merges e Checkouts
Um branch deve ser criado cada vez que mudamos de contexto: cada programador na equipa deve trabalhar no seu branch, cada nova feature a ser implementada deve ter o seu branch e até se decidirmos caçar um bug devemos criar um branch. Isto permite separar a alteração de código por contextos tornando a nossa vida mais fácil se mais tarde quisermos saber qual foi o branch que introduziu um bug.
MiKe@MIKE-PC ~/project1 (master)
$ git branch new-feature
MiKe@MIKE-PC ~/project1 (master)
$ git branch
* master
new-feature
MiKe@MIKE-PC ~/project1 (master)
$ git checkout new-feature
Switched to branch new-feature
MiKe@MIKE-PC ~/project1 (new-feature)
$ echo 'new feature!' > file1
MiKe@MIKE-PC ~/project1 (new-feature)
$ less file1
new feature!
MiKe@MIKE-PC ~/project1 (new-feature)
$ git commit -am 'new feature added to file1'
1 files changed, 1 insertion(+), 0 deletions(-)
Mudámos de contexto para adicionarmos uma feature nova. Inserimos texto num ficheiro e fizemos commit apenas no branch new feature. Estas alterações não passam para o branch master:
MiKe@MIKE-PC ~/project1 (new-feature)
$ git checkout master
Switched to branch master
MiKe@MIKE-PC ~/project1 (master)
$ less file1
Como podemos observar, as alterações não se manifestam no branch principal. Caso estejamos contentes com as alterações que fizémos, podemos unir os 2 branches com um merge:
MiKe@MIKE-PC ~/project1 (master)
$ git merge new-feature
Updating f734740..789f572
Fast-forward
file1| 1 +
1 files changed, 1 insertion(+), 0 deletions(-)
MiKe@MIKE-PC ~/project1 (master)
$ less file1
new feature!
Se não houverem conflitos entre os 2 branches podemos dar por terminado o o processo de merge.
Não vou aprofundar mais as funcionalidades para já, visto que ainda estou a começar a usar o Git. Deixo alguns links úteis para quem esteja na mesma situação que eu:
- Site Oficial
- Tutorial Oficial
- Guia de Referência
- Github – Uma “rede social” para programadores que oferece, gratuitamente, repositórios públicos