Git – um tutorial prático

Publicado: 25/06/2013 em Programação
Tags:,

Git é um sistema de controle de versão distribuído e um sistema de gerenciamento de código fonte. O Git foi inicialmente projetado e desenvolvido por Linus Torvalds para o desenvolvimento do kernel Linux, mas foi adotado por muitos outros projetos. O Git é um software livre, distribuído sob os termos da versão 2 da GNU General Public License.

1) Primeiros passos: instalação, configuração, iniciar o uso e help
1.1) Instalação
# apt-get install git gitk
$ git --version // verificar a versao do git após a instalação.
$ ssh-keygen -t rsa // Gerar par de chaves:

Chave privada: ~/.ssh/id_rsa
Chave pública: ~/.ssh/id_rsa.pub

1.2) Configuração
O Git possui 3 arquivos de configuração:

  • system: altera a configuração de todos os usuários da máquina. Este arquivo é o /etc/gitconfig
  • global: é o arquivo padrão, e suas diretivas abrangerá todos os repositórios Git do usuário. Este arquivo é o ~/.gitconfig
  • local: conterá as configurações apenas para o repositório Git corrente. Este arquivo é o .git/config

O Git lê estas três configurações na seguinte ordem: system, global e local. Diretivas presentes em configurações posteriores sobrescrevem as anteriores. É possível alterar as configurações através de comandos ou editando o arquivo diretamente. Através da linha de comando, para alterar um parâmetro deve-se utilizar a seguinte forma:
$git config --{system,global,local} parametro valor

Obs: Quer mais detalhes? Consultar o manual através de "$ man git-config"

a) Alterar a configuração “global” do Git por linha de comando:

$ git config --global user.name "Fulano Cintra"
$ git config --global user.email "fulano.cintra@provedor.com"

$ git config –global core.editor “mcedit”

b) Alterar a configuração “global” do Git editando seu arquivo diretamente:
$ mcedit ~/.gitconfig

[user]
	name = Fulano Cintra
	email = fulano.cintra@provedor.com
[color]
    status = auto
    branch = auto
    interactive = auto
    diff = auto
[core]
    editor = mcedit

c) Listar as configurações do Git (de todos os 3 arquivos de configuraçâo):
$ git config --list

user.name=Fulano Cintra
user.email=fulano.cintra@provedor.com
color.status=auto
color.branch=auto
color.interactive=auto
color.diff=auto
core.editor=mcedit
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true

d) Ignorando arquivos
No diretório de trabalho podem existir arquivos que se queira que o Git simplesmente os ignore. Existem basicamente duas formas de fazer isto:

  • através do arquivo .gitignoreEsse arquivo deve ser colocado na mesma pasta que contém o arquivo .git. Nele constará a lista de arquivos e pastas a serem ignorados pelo git. Se o projeto que está sendo desenvolvido é compartilhado por outras pessoas, este arquivo influenciará toda a equipe.
    Exemplo de conteúdos:

    # ignora este arquivo específico neste diretório específico
    results/abc.log
    # ignora este arquivo específico no diretório corrente
    /programa.um
    ## indicações sem barras se aplicam ao diretório corrente e abaixo
    # ignora os arquivos com extensões .c e .h nos diretórios corrente e abaixo
    *.[ch]
    # ignora quaisquer diretórios chamados "temp"
    temp/
  • através do arquivo .git/info/excludeA diferença essencial é que esse arquivo influencia apenas a configuração pessoal do usuário, e não os outros usuários do projeto. Esse arquivo faz parte da configuração do repositório do usuário, mas não é parte do conteúdo do repositório.

OBS:
– arquivos já registrados (“tracked”) pelo Git não serão afetados.
– mais detalhes, utilize o manual em $ man gitignore.

1.3) Melhorar o prompt para trabalhar com Git
$ export PS1='${debian_chroot:+($debian_chroot)}\u@\h:\w\[\e[33m\]$(__git_ps1 "(%s)")\[\e[0m\]\$ '

O comando acima produzirá o seguinte formato de prompt quando o usuário estiver na pasta ~/tmp/demo: albuquerque@maquina:~/tmp/demo(master)$
Para ficar automático, colocar no arquivo ~/.bashrc
Mais opções é só dar uma olhada nas referencias deste post ou procurar “PS1 git prompt” através dos buscadores da internet.

1.4) Iniciar o uso
// criar um novo repositório Git vazio na pasta corrente (criará uma nova pasta .git dentro da pasta corrente).
teste$ git init

O comando acima criará uma pasta .git dentro da pasta corrente “teste”.

1.5) Help
Duas formas de pedir help:

  • $ git help nome_comando
  • $ man git-nome_comando

Exemplos:
$ git help commit
$ git help log
$ man git-commit
$ man git-log

2) Para entender um pouco mais o Git

Um projeto Git é representado por um “repositório”, que contém o histórico completo do projeto desde a sua concepção. O repositório contém o conteúdo do projeto (arquivos e diretórios, chamados de “commits”). Um repositório contém um ou mais “branches”, onde o primeiro branch é chamado “master”.

Quando se utiliza o comando “git status”, é importante perceber que a resposta está dividida basicamente em três partes:

  • Arquivos no INDICE “changes to be committed” (mudanças aguardando commit): arquivos com status “modified” ou “new file”.
  • Arquivos na WORKING AREA “changes not staged for commit”: arquivos com status “modified”.
  • Arquivos na WORKING AREA “untracked files”: são arquivos novos que não pertencem ainda ao repositório.

3) Status

$ git status avalia estado dos arquivos no WORKING AREA e no INDICE.
$ git log Mostrar o histórico de comandos commits (do branch ativo).
$ git log --pretty=oneline Comando log resumido: 1 linha para cada commit.
$ git log --stat Comando log, detalhando as diffs em cada arquivo do commit.
$ git log --graph Comando log, desenhando uma representação gráfica textual do histórico dos commits.
Obs: melhor usar o aplicativo “gitk” que trará mais clareza.
$ git log --pretty=format:"[%an %ad] %h - %s" Autor, data, abreviação do hash e assunto.
$ git log --pretty=format:"%h %s" --graph Abreviação do hash e assunto, com formato graph.
$ git log --since=30.minutes Mostrar as atividades dos últimas 30 minutos. Outro exemplo: since=1.hour.
$ git log --since=4.hours --until=2.hours
$ git log --before="2013-08-08"
$ git reflog lista as últimas operações sobre o REPOSITORIO. Ou de outra forma, mostra os commits que não estão mais acessíveis no histórico.
$ gitk --all & Aplicativo com interface gráfica para visualizar os commits
$ git show Mostrar as alterações realizadas no último commit.
$ git show tag_name Mostra os detalhes do commit onde fora marcado o tag.
$ git tag Lista as tags existentes.

 
4) Ações sobre arquivos na WORKING AREA (cor vermelha)

$ git add nome_arquivo Adicionar o arquivo mencionado da WORKING AREA ao INDICE.
$ git add . Adicionar todos os arquivos e subpastas da WORKING AREA ao INDICE
$ git add -i Adicionar arquivos e subpastas da WORKING AREA ao INDICE, de forma interativa.
$ git checkout nome_arquivo Arquivo presente na WORKING AREA como “changes not staged for commit” (status de “modified”) será descartado. A versão original do arquivo do REPOSITÓRIO é copiada de volta para a WORKING AREA, perdendo-se as alterações realizadas no arquivo.
$ git clean -fd Remover fisicamente os arquivos da WORKING AREA (pasta raiz e subpastas) que não pertencem ao REPOSITORIO. Ótimo para limpezas! Chave “-d”: remover também diretórios.
$ git clean -n Listar os arquivos que serão removidos fisicamente quando “git clean” for executado. Ótimo para um primeiro passo antes fazer a limpeza!!

 

5) Ações sobre os arquivos no INDICE (ou “STAGING AREA”) (cor verde)

$ git rm --cached nome_arquivo
  1. Caso o status do arquivo for “new file” (portanto ele ainda não está no REPOSITORIO), o arquivo passa a ser listado em “untracked files” na WORKING AREA.
  2. Caso o arquivo já exista no REPOSITÓRIO (podendo até estar sendo listado em INDICE como “modified”), este passa a ser listado no INDICE como “deleted”. Aí o usuário tem duas possibilidades:
    • usar o comando de commit (veja abaixo as consequências).
    • usar o comando de “reset HEAD”, onde o arquivo aparecerá como “modified” na WORKING AREA.
$ git reset HEAD Retira TODOS os arquivos da lista do INDICE (em verde), retornando para a WORKING AREA (em vermelho):
– se arquivo JÁ EXISTE no REPOSITORIO, este passa a ser listado em “modified” da WORKING AREA.
– se arquivo NÃO EXISTE no REPOSITORIO, este passa a ser listado em “Untracked files” da WORKING AREA.
$ git reset HEAD nome_arquivo Idem anterior, valendo para apenas o arquivo citado.
$ git commit -m "meu comentario" Retira TODOS os arquivos da lista do INDICE (em verde), podendo fazer 3 tratamentos diferentes:

  • se o arquivo está listado como “new file”, quando do commit ele passa a pertencer ao REPOSITORIO;
  • se arquivo está listado como “modified”, quando do commit esta nova versão é atualizada no REPOSITÓRIO;
  • se o arquivo está listado como “deleted”, quando do commit ele é removido do REPOSITORIO e fisicamente deixa de existir.
$ git commit -m "meu comentario" --amend Apenas para desenvolvimento local (não usar para servidor remoto), refaz o último commit, incorporando naquela ação os arquivos presentes neste momento no INDEX

 
6) Ações sobre os commits realizados

$ git rm nome-arquivo Este comando realiza duas ações:

  • passará o arquivo a ser listado no INDICE em “changes to be committed” com status “deleted”.
  • fisicamente o arquivo será removido da WORKING AREA (como se o usuário fizesse um comando "$ rm nome_arquivo").
  • OBS: comando prático: git rm $(git ls-files --deleted)

$ git reset HEAD~1 --soft 1 commit para trás:
– se no instante deste comando existiam arquivos no INDICE, estes permanecerão por lá.
– se no último commit foram colocados arquivos no REPOSITORIO, estes voltam para o INDICE. As modificações no conteúdo destes
arquivos permanecem.
$ git reset HEAD~1 --hard 1 commit para trás. Apaga o commit mais recente (do branch que está ativo). O HEAD aponta para o penúltimo commit.
Se no último commit foram para REPOSITORIO, estes são retirados do REPOSITORIO, bem como apagados fisicamente da WORKING AREA.
Se existia no momento deste comando arquivos no INDEX, estes são retirados desta área bem como apagados fisicamente da WORKING AREA.
!! Prudência !!
$ git reset HEAD~3 --hard 3 commits para trás. Apaga os 3 últimos commits (do branch que está ativo).
$ git reflog Listar as últimas operações commit sobre o REPOSITORIO, mesmo aquelas que não estão mais acessíveis por “git log”. Agora pode-se restaurar um commit anterior identificando o hash: “git merge 00b74a6”
$ git merge hash Refazer o HEAD, apontando o HEAD para um commit anterior. O hash da versão anterior é obtida com “git reflog”. Exemplo: “git merge 00b74a6”
$ git revert commit_id Reverte um commit. O arquivo novo que fora adicionado ao REPOSITORIO no commit anterior é retirado fisicamente da WORKING AREA. OBS: commit_id é obtido via comando “git log”.

 
7) Branches (ramos)
Vale enfatizar que não é uma boa política trabalhar no branch “master”.

7.1) Comandos usando branch

$ git branch Listar os branches existentes da máquina local. OBS: o asterisco na frente indica o branche que está ativo.
$ git branch -a Listar os branches existentes da máquina local e remotos (chave “-a” = all).
$ git checkout -b desenvolvimento Criar um novo branch chamado “desenvolvimento” e ao mesmo tempo tornar o novo como branch ativo.
O branch criado neste momento conterá uma cópia do branch ativo.
$ git branch teste desenvolvimento Criar um novo branch ‘teste’ baseado em um outro branch “desenvolvimento”, mantendo-se no branch atual.
$ git checkout master Ativar o branch “master”
$ git branch -d desenvolvimento Deletar o branch “desenvolvimento”. OBS: não se pode apagar o branch corrente.
$ git branch -D desenvolvimento Deletar o branch “desenvolvimento”. Apaga forçado, mesmo sabendo que arquivos do branch “desenvolvimento” não estão no branch “master”.
$ git merge desenvolvimento Faz mescla no branch ativo com os commits realizados no branch “desenvolvimento”, atualizando o branch ativo. O branch “desenvolvimento” fica inalterado.
Caso ocorra conflito de versões de arquivos, editar cada arquivo e usar comando “git add” e posteriormente “git commit”.
$ git merge desenvolvimento --squash Faz a mescla do branch ativo com o branch “desenvolvimento”, sem gerar commit. Os arquivos são referenciados em INDICE do branch ativo, pronto para um commit.
$ git branch -D desenvolvimento Deleta forçado o branch “desenvolvimento”, mesmo sabendo que arquivos do seu repositório não estão no branch ativo.

7.2) Comandos usando rebase
Todo branch possui um branch pai, que é a sua base. Daí o nome “rebase”. Realizar um “rebase”: pegar o último commit do “master”, que é a base do branch “desenvolvimento”, trazer para a área working e aplicar todos os seus commits (na mesma ordem de criação). Com isto, o branch “desenvolvimento” estará sincronizado com a última versão do branch “master” mais a apliação dos commits próprios do “desenvolvimento”.

$ git checkout desenvolvimento
$ git rebase master
Desfaz commits atuais do branch “desenvolvimento”, traz os commits do branch “master” e, por último, reaplica os commits do branch “desenvolvimento”. Assim, obtem-se o branch “desenvolvimento” atualizado com o branch “master”. Na prática, é trazer o branch “master” para o branch “desenvolvimento” e aplicar por cima os commits posteriores do próprio branch “desenvolvimento”.
Podem ocorrer conflitos se um mesmo arquivo estando no “master” e no “desenvolvimento” tiver sido alterados concomitantemente. Neste caso, existem 3 opções de encaminhamento:
– solução 1) git rebase --skip : não aplicar o commit do “desenvolvimento”;
– solução 2) git rebase --abort : abortar esta tentativa de rebase que estava em curso;
– solução 3) git rebase --continue : só quando resolver o problema. Para resolver o problema, editar o arquivo e escolher qual modificação que permancerá no arquivo.
OBS: antes de editar, veja que a indicação de branch ativo referencia “no branch”. Ou seja, não se está em nenhum branch especificamente até que se encaminhe a decisão do conflito. Fazer o seguinte para resolver o conflito:
a) com um editor de texto, editar o arquivo_com_conflito (e escolher a modificação que fica);
b) comando: git add index.html;
c) comando: git rebase --continue
Pronto. Observe agora que o branch ativo voltou a ser “desenvolvimento”.

7.3) Atualizando branches

(master)$ git pull . desenvolvimento Estando no branch “master”, atualiza o REPOSITORIO deste branch a partir do REPOSITORIO do branch “desenvolvimento”.

 
8) Stashes (esconderijos)
STASH é uma quarta área (complementando WORKING AREA, INDICE e REPOSITORIO).

8.1) Comandos STASH básicos

$ git stash Retira TODOS os arquivos da lista do INDICE (em verde) e os arquivos da WORKING AREA marcados “modified”, guardando-os na área anônima STASH.
Área INDICE é limpa e não há mais informações de arquivos “modified”. Fisicamente, teremos:
– se arquivo JÁ EXISTE no REPOSITORIO, este permanece fisicamente na WORKING AREA.
– se arquivo NÃO EXISTE no REPOSITORIO, este é fisicamente retirado da WORKING AREA.
Forma alternativa: git stash save “comentario para stash”
$ git stash list Listar os stashes gravados.
$ git stash apply Trazer de volta arquivos da área STASH, referentes ao último comando STASH:
– se arquivo JÁ EXISTE no REPOSITORIO, este é listado em “modificados” na WORKING AREA.
– se arquivo NÃO EXISTE no REPOSITORIO, este é listado novamente em INDICE.
– mas em ambas as situações, os arquivos aparecem fisicamente novamente na WORKING AREA.
$ git stash clear Apagar todos os stashes gravados. Agora o comando “git stash list” não indicará mais nada.

8.2) Formas alternativas para stash apply

$ git stash apply stash@{1} obs: a) stash-ID através comando “git stash list”;
b) stash@{0} é sempre o mais recente, pois cada comando git empurra para trás os stashs anteriores.
$ git stash pop Executa o comando stash apply, e já simultaneamente apaga o stash.
$ git stash drop stash@{1} ! Prudência ! Apaga stash designado. PERDERÁ os arquivos da área STASH do referido stash.

 
9) Tags
Tags são muito úteis quando lidando com diferentes “releases” de projetos.

$ git tag Lista os tags existentes.
$ git tag -a nome_tag -m "mensagem ou comentário" Criar tag no branch ativo, apontando para o seu último commit.
$ git tag -d nome Deletar o tag referenciado. OBS: busca em todos os branches, sobre todos os commits.
$ git tag -l Listar todos os tags. OBS: busca em todos os branches, sobre todos os commits.
$ git show tag_name Mostra os detalhes do commit onde fora marcado o tag.
$ git push origin --tags Enviar todas as tags ao repo remoto.
$ git push origin tag tag_name Enviar apenas a tag especificada ao repo remoto.

 
10) Clone de repositórios

tmp$ git clone demo/.git demo2 Com branch “master” ativo, fazer um clone do REPOSITORIO .git da pasta demo dentro da pasta demo2.
A pasta demo2 será criada automaticamente.
tmp$ cd demo2 && ls Vê-se que os arquivos pertencentes ao REPOSITORIO clonado estão disponíveis também nesta pasta.
demo2$ git remote Informa que existe uma origin.
demo2$ git remote show origin Informa o local de onde fora feito o clone.
demo2$ git branch -a Mostrar os branches remotos.
demo2$ git checkout -b desenvolvimento origin/desenvolvimento Criar branch “desenvolvimento” em demo2 apontando para origin/desenvolvimento.
demo2$ git branch Mostrará 2 branches: master e desenvolvimento.
demo2$ git push origin desenvolvimento Arquivos alterados no branch desenvolvimento do demo2 (após commit) são enviados de volta ao remote origin desenvolvimento (em /demo), depositado em seu REPOSITORIO.
demo$ git remote add origin ../demo2/.git Apontar o origin para o outro clone (mão dupla de troca de arquivos entre clones).
demo$ git pull origin desenvolvimento Puxar do remote chamado origin do branch desenvolvimento que tem no demo2, tudo que tem diferente.
demo2$ git branch -a
demo$ git remote rm origin Remover o clone.

 
11) Repositório Remoto: modelo centralizado
É facilitador se trabalhar com pares de chaves.

$ mkdir -p repos/demo.git && cd repos/demo.git && git init --bare Executar no servidor remoto: cria um servidor remoto vazio, sem área de trabalho.
$ git remote add origin ssh://albuquerque@192.168.1.104:8000/home/albuquerque/repos/demo.git Apontar o repositorio local para o repositorio criado no servidor remoto. Este apontamento é guardado em .git/config
$ git remote show origin Verificar se o apontamento para o remoto está funcionando.
$ git checkout master && git push origin master Enviar os objetos do branch ativo do “remote/origin” para o branch “master” do servidor. Ou seja, mapeando o “master” local com o “master” remoto.
$ git branch -a Listar branches, inclusive os remotes.
$ git fetch origin master Puxar do servidor remoto para dentro do “origin/master”.
$ git checkout desenvolvimento && git push origin desenvolvimento Enviar os objetos do branch desenvolvimento do “remote/origin” para o branch “desenvolvimento” do servidor. Mapeando o “desenvolvimento” local com o “desenvolvimento” remoto.
Um outro usuário poderia trabalhar no mesmo projeto. Este faria os seguintes procedimentos em sua máquina:
$ git clone ssh://joao@192.168.1.104:8000/home/albuquerque/repos/demo.git demo_clone Criar um repositorio local identico, apontando para o servidor remoto.
$ git pull
$ git branch -a
$ git checkout -b desenvolvimento origin/desenvolvimento
$ git push origin desenvolvimento Enviar os commits locais para o servidor. OBS: para evitar conflitos, é melhor fazer antes fetch e rebase. (git fetch origin/master)(git merge origin/master)(git rebase origin/master)
Obs: é uma boa política nunca fazer merge no master. Recomenda-se criar um outro branch transitório e usar rebase.
$ git pull origin desenvolvimento Buscar os commits do repositorio do servidor para o repositorio local.
Obs: notar que “git pull” é o mesmo que “git fetch” seguido de “git merge”.
$ git remote rm origin Desconectar servidor remoto.
$ git branch -a Verificar que não existe mais a conexão remota

 
12) Repositório Remoto: modelo distribuído (usando GitHub)
/* no github, criar um novo repositório */

Referências:
1- Vídeo Tutorial
2- Git Tutorial
3- Magia Git
4- 16 tutoriais sobre Git/GitHub
5- Customize your Bash prompt
6- Color Bash Prompt
7- Bash Prompt Escape Sequences
8- why Git is Better than X
9- Tech Talk: Linus Torvalds on git

Anúncios
comentários
  1. rafaelfii disse:

    Este tutorial é um excelente material de apoio, organizado e muito didático. Obrigado e parabéns!

  2. Excelente material sobre o git. Parabéns. Obrigado por compartilhar! ;)

Deixe um comentário, pois isto é muito motivante para continuarmos este trabalho

Preencha os seus dados abaixo ou clique em um ícone para log in:

Logotipo do WordPress.com

Você está comentando utilizando sua conta WordPress.com. Sair / Alterar )

Imagem do Twitter

Você está comentando utilizando sua conta Twitter. Sair / Alterar )

Foto do Facebook

Você está comentando utilizando sua conta Facebook. Sair / Alterar )

Foto do Google+

Você está comentando utilizando sua conta Google+. Sair / Alterar )

Conectando a %s