O GIT é um controlador de versão criado por Linus Torvalds, na minha opinião um dos maiores ‘integradores’ de código do mundo, afinal ele tee que fazer merge de milhões de linhas de código durante vários anos, então rapaziada o GIT é fera mesmo. Depois de anos usando o Subversion como alternativa ao CVS me rendi a simplicidade e facilidade de uso do git por uma série de razões, então abaixo mostro o meu dia a dia usando o GIT em várias situações diferentes afim de mostrar para vocês como é fácil de resolver seus problemas de versionamento.

Clona (faz checkout ou baixa) um repositório remoto para a máquina local:

$ git clone https://github.com/mulatinho/sfm.git

Verifica e informa as mudanças feitas no diretório local:

$ git status

Atualiza repositório local com as modificações do repositório original:

$ git pull

Mostra todas as diferenças feitas no arquivo “libsmb.c”:

$ git diff libsmb.c

Faz commit (atualiza arquivo no repositório) com uma mensagem, entre aspas, do arquivo “libsmb.c”:

$ git commit -m 'Adicionando funcao principal para DEBUG enquanto biblioteca nao esta pronta' libsmb.c

Envia suas modificações ao repositório remoto (por padrão “origin” no Git):

$ git push origin master

Lista branchs criadas:

$ git branch

Cria branch “cpp-list” com base na branch “fix2”:

$ git checkout -b cpp-list fix2

Lista todas as tags do repositório:

$ git tag -l

Baixa a tag “v3.8.8” do repositório e cria um arquivo “../linux-3.8.8” com seu conteúdo localmente:

$ git archive --format=tar --prefix=linux-3.8.8/ -o ../linux-3.8.8.tar v3.8.8

Faz merge do branch “fix2” na linha base raiz

$ git checkout master
$ git merge fix2

Gostou!? Que tal vermos um exemplo prático? Primeiro vamos baixar um repositório, no caso o repositório aqui vai ser o do SFM que estamos desenvolvendo para exemplificar o uso de C e a biblioteca GTK:$ cd $HOME/repo/github

$ git clone https://github.com/mulatinho/sfm.git
Cloning into 'sfm'...
remote: Counting objects: 74, done.
remote: Compressing objects: 100% (58/58), done.
remote: Total 74 (delta 35), reused 51 (delta 14)
Unpacking objects: 100% (74/74), done.
$ cd sfm && ls -lh
total 72K
-rw-r--r-- 1 mulatinho mulatinho 2.4K May  9 16:48 ChangeLog
-rw-r--r-- 1 mulatinho mulatinho  397 May  9 16:48 INSTALL
-rw-r--r-- 1 mulatinho mulatinho  753 May  9 16:48 LICENSE
-rw-r--r-- 1 mulatinho mulatinho  945 May  9 16:48 Makefile
-rw-r--r-- 1 mulatinho mulatinho  296 May  9 16:48 README.md
-rw-r--r-- 1 mulatinho mulatinho  319 May  9 16:48 TODO
-rw-r--r-- 1 mulatinho mulatinho 5.9K May  9 16:48 action.c
-rw-r--r-- 1 mulatinho mulatinho 3.6K May  9 16:48 libsmb.c
-rw-r--r-- 1 mulatinho mulatinho 4.3K May  9 16:48 main-list.c
-rw-r--r-- 1 mulatinho mulatinho 4.3K May  9 16:48 main.c
-rw-r--r-- 1 mulatinho mulatinho 3.2K May  9 16:48 main.h
drwxr-xr-x 2 mulatinho mulatinho 4.0K May  9 16:48 picz/
-rw-r--r-- 1 mulatinho mulatinho 1.5K May  9 16:48 strkey.c
-rw-r--r-- 1 mulatinho mulatinho 5.8K May  9 16:48 util.c

Pronto! Note que o que eu fiz acima foi uma clonagem (uma cópia do estado mais atual) do repositório criado no GitHub. Agora vamos modificar algumas linhas de código e pedir ao git para mostrar o que foi modificado.

.... algumas edições nos códigos ...
$ git status
# On branch master
# Changes not staged for commit:
#   (use "git add ..." to update what will be committed)
#   (use "git checkout -- ..." to discard changes in working directory)
#
#	modified:   libsmb.c
#	modified:   util.c
#
# Untracked files:
#   (use "git add ..." to include in what will be committed)
#
#	libsmb
no changes added to commit (use "git add" and/or "git commit -a")

Hummm! Atente para a mensagem, o GIT está te informando que existem três mudanças: os arquivos ‘libsmb.c’, ‘util.c’ foram modificados e o arquivo ‘libsmb’ não está sendo versionado. Vamos ver o que mudou no arquivo ‘libsmb.c’:

    $ git diff libsmb.c
    diff --git a/libsmb.c b/libsmb.c
    index c9a3662..bc93ede 100644
    --- a/libsmb.c
    +++ b/libsmb.c
    @@ -140,3 +140,18 @@ int sfm_smb_exec(char *line)

            return 0;
     }
    +
    +#ifdef DEBUG
    +int main(void) {
    +       sfm_smb_exec("list smb://");
    +       fprintf(stdout, "nn");
    +       sfm_smb_exec("list smb://MULATINHO");
    +       fprintf(stdout, "nn");
    +       sfm_smb_exec("list smb://FORREST");
    +       fprintf(stdout, "nn");
    +       sfm_smb_exec("list smb://FORREST/multimedia");
    +       fprintf(stdout, "nn");
    +       sfm_smb_exec("recv smb://FORREST/multimedia/psig-ted.2012.dvdrip.xvid.ac3.srt");
    +       return 0;
    +}
    +#endif

Notemos que só as linhas que começam com ‘-‘ e ‘+’ significam respectivamente uma remoção ou modificação numa linha, podemos ver aí então que a função principal da biblioteca foi adicionado ao código (afim de testar a biblioteca enquanto não está completamente pronta).

Certo!! E se quisermos fazer um commit (enviar as modificações para o repositório) das nossas alterações para todo mundo do repositório vêr?

$ git commit -m 'Adicionando funcao principal para DEBUG enquanto biblioteca nao esta pronta' libsmb.c
[master c577a9c] Adicionando funcao principal para DEBUG enquanto biblioteca nao esta pronta
 1 file changed, 15 insertions(+)

Note que o GIT está dizendo a você que o seu arquivo foi modificado no seu repositório local (o master acima), você precisa ainda dizer que o que estiver no seu repositório deve ir para o repositório remoto.

$ git push origin master
Counting objects: 5, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (3/3), done.
Writing objects: 100% (3/3), 528 bytes, done.
Total 3 (delta 2), reused 0 (delta 0)
To git@github.com:mulatinho/sfm.git
   3fb2123..c577a9c  master -> master

A sintaxe do push é simples, o primeiro argumento após o comando push é a origem (por padrão o GIT utiliza a palavra ‘origin’ como sendo o repositório clonado) e a segunda opção o branch que você quer enviar (no nosso caso o ‘master’ mas poderia ser qualquer outro).

O GIT é roots porque é muito dinâmico, você não tem mais aqueles conceitos de seguir um único baseline, você pode seguir vários! Veja como listar branchs é fácil:

$ git branch
* master
  v0.0.5

Vêmos que estamos trabalhando aí com duas branches diferente, um desenvolvedor colocou sua branch com o nome ‘v0.0.5’, E como faz para podermos criar uma nossa?

$ git branch cpp-list # cria branch 'cpp-list'
$ git branch
* master
  v0.0.5
  cpp-list

Difícil para caramba né? Mas vêmos que o ‘*’ (asterisco) está na branch master, isso significa que ainda estamos trabalhando no nosso repositório principal e quando fazermos modificações elas vão estar no master, então como mudamos para outro repositório?

$ git checkout cpp-list
Switched to branch 'cpp-list'

Muito difícil né? Agora vamos terminando por aqui mostrando só mais algumas coisas legais que podem ser feitas utilizando o GIT, eu por exemplo gosto de acompanhar o desenvolvimento do GCC (GNU C Compiler), então vamos vêr se existe alguma atualização no repositório e copia-la para a nossa máquina local

$ cd $HOME/repo/gcc
$ git pull
From git://gcc.gnu.org/git/gcc
   43bf72f..b6de2ea  master     -> origin/master
   43bf72f..b6de2ea  trunk      -> origin/trunk
Updating 43bf72f..b6de2ea
Fast-forward
 gcc/cp/ChangeLog                                   | 20 +++++
 gcc/cp/call.c                                      |  9 ++-
 gcc/cp/cp-tree.h                                   |  1 +
 gcc/cp/decl.c                                      |  1 +
 gcc/cp/error.c                                     | 28 ++++---
 gcc/cp/except.c                                    | 11 +++
 gcc/cp/init.c                                      | 46 +++++++++--
 gcc/cp/parser.c                                    |  3 -
 gcc/cp/semantics.c                                 |  2 -
 gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C        | 20 +++++
 gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C        | 21 ++++++
 gcc/testsuite/g++.dg/cpp0x/initlist21.C            |  1 -
 gcc/testsuite/g++.dg/ext/vla4.C                    |  2 +-
 gcc/testsuite/g++.dg/init/new40.C                  |  2 +
 gcc/testsuite/g++.dg/parse/ref-qual1.C             | 29 +++++++
 libstdc++-v3/ChangeLog                             | 20 +++++
 .../config/abi/pre/gnu-versioned-namespace.ver     |  3 +
 libstdc++-v3/config/abi/pre/gnu.ver                |  4 +                                                   
 libstdc++-v3/include/bits/atomic_base.h            | 88 +++++++++++-----------
 libstdc++-v3/libsupc++/Makefile.in                 | 14 +++-
 libstdc++-v3/libsupc++/bad_array_new.cc            | 36 +++++++++
 libstdc++-v3/libsupc++/cxxabi.h                    |  3 +
 libstdc++-v3/libsupc++/eh_aux_runtime.cc           |  4 +
 libstdc++-v3/libsupc++/new                         | 15 ++++
 24 files changed, 315 insertions(+), 68 deletions(-)
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/bad_array_new1.C
 create mode 100644 gcc/testsuite/g++.dg/cpp0x/bad_array_new2.C
 create mode 100644 gcc/testsuite/g++.dg/parse/ref-qual1.C
 create mode 100644 libstdc++-v3/libsupc++/bad_array_new.cc

Alguns arquivos foram modificados e baixados para o nosso computador local! E se quisessemos listar as tags de um repositório linux afim de baixar versões!?

$ cd $HOME/repo/linux-stable
$ git tag -l
..........
v3.8.7
v3.8.8
v3.8.9
v3.9
v3.9-rc1
v3.9-rc2
v3.9-rc3
v3.9-rc4
v3.9-rc5
v3.9-rc6
v3.9-rc7
v3.9-rc8
v3.9.1

Ainda omiti bastante coisa pois senão ficaria extenso! Veja aí que todas as baselines da versão estável do Linux estão aí, agora o pulo do gato, e tem como baixar uma versão de uma tag dessa em específico? Com certeza! Veja abaixo:

$ git archive --format=tar --prefix=linux-3.8.8/ -o ../linux-3.8.8.tar v3.8.8
$ cd .. && ls -l linux*tar
-rw-r--r--  1 mulatinho mulatinho 505743360 May  9 17:19 linux-3.8.8.tar

É isso rapaziada! O GIT é fera!!!