Antes de começar
Este texto aborda o uso do Git para colaboração em projetos e pressupõe o conhecimento de informações abordadas na primeira parte deste artigo: Entendendo o funcionamento básico do git e o uso de branches, leia antes para facilitar o entendimento do texto adiante.
Começando
Neste artigo serão usados dois personagens fictícios: A Bruna, que iniciou um novo projeto com repositório Git localizado em /home/bruna/projeto, e o Andrei, que possui um usuário no mesmo sistema e deseja contribuir com o projeto usando o diretório /home/andrei/projeto-bruna.
Pressupondo que o repositório Git da Bruna já foi criado, Andrei começa clonando o projeto da Bruna em seu diretório de contribuição:
Andrei
cd /home/andrei/ git clone /home/bruna/projeto projeto-bruna
Depois o Andrei faz as suas alterações:
Andrei
# (Edita arquivos)
git commit -a
Ao final ele pede a Bruna para aplicar as atualizações no repositório original. Então a Bruna executa:
Bruna
cd /home/bruna/projeto git pull /home/andrei/projeto-bruna
Isso faz com que as atualização dos arquivos feitas no branch master do repositório do Andrei sejam aplicadas no branch em que a Bruna estava quando executou o comando. O comando git pull busca as alterações feitas do repositório remoto e depois mescla com o branch atual.
Caso ocorra um conflito, a Bruna terá que resolvê-los localmente em seu diretório, o Git ainda irá buscar as alterações porém se recusará a mescla-las até que as correções sejam feitas.
A Bruna pode verificar as alterações feitas pelo Andrei antes de aplicá-las usando o comando git fetch:
Bruna
git fetch /home/andrei/projeto-bruna git log -p HEAD..FETCH_HEAD
Para ver todas as alterações que o Andrei fez desde que o projeto foi clonado, ela pode usar o comando:
Bruna
gitk HEAD..FETCH_HEAD
Repare que esta notação com dois pontos .. pode ser usada tanto com o comando git log como com gitk. Se a Bruna quiser ver tanto as alterações que ela fez quanto as que o Andrei fez desde que o projeto foi clonado, ela pode usar a notação ... com 3 pontos.
Bruna
gitk HEAD...FETCH_HEAD
Se a Bruna decidir que não há nenhuma alteração relevante feita pelo Andrei, ela pode continuar a trabalhar normalmente, já se o histórico do Andrei mostre algo que ela realmente precise, ela pode executar o git pull e continuar trabalhando contando com as alterações recentes feitas pelo Andrei.
Dependendo do projeto pode haver a necessidade de interagir com o repositório remoto constantemente, para facilitar este processo é possível criar um apelido:
Bruna
git remote add andrei /home/andrei/projeto-bruna
# E então
git fetch andrei
A criação do apelido possibilita usar a forma andrei/master para acessar informações já buscadas com o commando git fetch, como no exemplo:
Bruna
git log -p master..andrei/master
O comando acima mostra uma lista de todas alterações feitas pelo Andrei desde que o primeiro clone foi feito. Depois de analisar estas alterações a Bruna poderia aplica-las com:
Bruna
git merge andrei/master
# ou buscar em seus branches remotos
git pull . remotes/andrei/master
Mais tarde o Andrei pode querer buscar as últimas atualizações da Bruna e ele o faz com o comando:
Andrei
git pull
Como o repositório do Andrei foi clonado a partir da Bruna, não precisa informar o caminho para o repositório, o Git já armazena esta informação e usa no comando git pull.
Andrei
# Pega o caminho do projeto original
git config --get remote.origin.url /home/bruna/projeto # Mostra as configurações criadas pelo git clone git config -l # Git guarda uma cópia do branch master da Bruna chamado origin/master git branch -r
# Andrei pode continuar trabalhando de outro pc usando ssh git clone bruna.org:/home/bruna/projeto projeto-bruna
Explorando o Histórico
O histórico do Git é representado como uma série de commits que podem ser visualizados com o comando:
git log commit 82407449e223ddfd0b8e9ef6df95c8cd156e82b1
Author: Andrei <andrei@email.org>
Date: Tue May 14 21:37:07 2024 -0300 merge: Adicionado comentário ao código
O código informado na linha commit pode ser usado com o comando git show para mostrar mais detalhes sobre este commit:
git show 82407449e223ddfd0b8e9ef6df95c8cd156e82b1
Usar o começo do código também funciona, desde que seja único, neste exemplo usando somente os números abaixo foram suficientes.
git show 82407
Todo commit possui um parente que representa o estado anterior do projeto.
# Mostra último commit do branch atual git show HEAD # Último commit do branch experimental git show experimental # Mostra parente de HEAD git show HEAD^ # Parente do parente de HEAD git show HEAD^^ # Mostra o quarto na hierarquia git show HEAD~4 # Commits mesclados com merge podem ter mais de um parente # Mostra o primeiro parente de HEAD git show HEAD^1 # Segundo parente de HEAD git show HEAD^2
Nomeando commits
Você pode nomear um commit com:
git tag v2.5 82407
Agora é possível se referir ao commit que começa com 82407 usando o nome v2.5. Para que este nome seja válido para outras pessoas é preciso criar um objeto tag e talvez assina-lo, procure detalhes sobre o comando git tag usando git help tag.
Os nomes podem ser usados nos comandos Git sempre que precisar se referir a um commit, exemplos:
# Compara HEAD com commit v2.5 git diff v2.5 HEAD # Inicia um novo branch chamado stable baseado no commit v2.5 git branch stable v2.5 # Restabelece o estado do branch e diretório atual para o estado no commit HEAD^ git reset --hard HEAD^
Usando intervalo com git log
# commits entre v2.5 e v2.6 git log v2.5..v2.6 # commits desde v2.5 git log v2.5.. # commits das últimas duas semanas git log --since="2 weeks ago" # commits desde v2.5 onde houve alterações no arquivo Makefile git log v2.5.. Makefile
Se os branches stable e master divergiram de um ponto em comum algum tempo atrás:
# Lista os commits feitos em master mas não no branch stable git log stable..master # Contrário do comando acima git log master..stable
O comando git log possui uma fraqueza: apresenta os commits em formato de lista. Quando o histórico possui linhas de desenvolvimento que divergiram e depois se mesclaram novamente, a ordem mostrada no comando é irrelevante.
Nestes casos o comando gitk é melhor para visualizar históricos.
# Commits das últimas semanas com alterações em arquivos na pasta drivers
gitk --since="2 weeks ago" drivers/
Usando a versão junto com arquivos:
# Compara arquivos em diferentes versões git diff v2.5:Makefile HEAD:Makefile.in # Visualiza o arquivo em uma versão específica git show v2.5:Makefile
Pesquisando
O comando git grep é usado para procurar textos(strings) nos arquivos do projeto:
# Procura recursivamente por "import" em arquivos do diretório atual git grep "import" # Procura por "import" na versão v2.5 git grep "import" v2.5
Concluindo
Somando este tutorial e sua primeira parte deve ser o suficiente para ter um controle básico de revisão distribuída para seus projetos. Duas ideias simples ajudam a entender a profundidade e o poder do Git:
- O banco de dados de objetos é o sistema usado para armazenar o histórico de seus projetos, arquivos, diretórios e commits.
- O arquivo index é um cache do estado da árvore de arquivos e diretórios e é usado nos commits, ele é responsável por verificar os diretórios de trabalho e manter as várias árvores envolvidas em uma mesclagem.