title: "Repositório Local"
author: "Gabriel Sartori"
date: "29/10/2015"
output:
html_document:
highlight: pygments
theme: flatly
keep_md: yes
INCLUIR INTRODUÇÃO AO CAPÍTULO
Instruções do Git
Neste capítulo, as instruções serão todas feitas no terminal mesmo que existam alternativas gráficas para as mesmas. Isso enfatiza no que está sendo feito além do fato de que no terminal todos devem ter os mesmos recursos e os comandos irão produzir os mesmos resultados, o que faz esse tutorial algo reproduzível. Algumas ferramentas gráficas para uso do Git serão abordadas no capítulo 6.
Já temos o Git devidamente configurado, com credenciais (nome e e-mail) e configurações aplicadas. Vamos então ver como o sistema de controle de versão acontece.
Todas as instruções do Git são sinalizadas por começar com git
seguido
da instrução/comando e seus argumentos complementares, se
existirem/necessários.
if [ -d meu1repo ] # Script para verificação da pasta meurepo1, retorna pasta limpa.
then
echo "Diretório existe. Então apagar pasta .git"
cd meu1repo
ls -a
if [ -d .git ]
then
echo "Já existe projeto git aqui. Apagar."
rm -rf .git/
rm -rf *
fi
else
echo "Diretório não existe."
mkdir meu1repo
fi
```{r, engine="sh"}
cd meu1repo ## Diretório de teste de comandos
## Padrão de instruções Git.
git <instrução> <complementos ...>
Antes de iniciarmos o repositório, vamos só verificar o cadastro. Se você já usa o Git ou fez os procedimento apresentados na primeira sessão, o comando abaixo vai retornar o nome e e-mail usados e alguns definições adicionais, caso existam. Em caso de ainda não ter configurado o seu Git, informe o nome e e-mail conforme apresentado na sessão anterior.
## Mostra as informações/definições do usuário.
git config --list
Initialized empty Git repository in /home/gabriel/Suporte/PET/Projeto/Apostila/Git/.git/
user.name=Knight Rider
user.email=batman@justiceleague.org
Temos um diretório destinado ao projeto que será mantido sobre
versionamento, então vamos iniciar um repositório Git nele.
O Git retorna a mensagem de inicilização do repositório. Nesse momento
ele cria um diretório oculto .git/
com subdiretórios que são o coração
do sistema de versionamento. Você não deve modificar nada nesse
diretório. É por essa razão que ele é oculto. Alterar o conteúdo pode
prejudicar ou interromper o funcionamento do Git. Se você quiser
encerrar o processo de versionamento fazendo com que esse diretório seja
como qualquer outro diretório, é só excluir a diretório .git/
. Cada
subdiretório do .git/
tem um propósito mas deixaremos os
esclarecimentos para o futuro.
Por agora vamos apenas estrutur a minha primeira sessão.
cd meu1repo/
## Inicia um repositório sob versionamento Git.
git init
```{r, engine ="bash", eval = FALSE}
tree -a
.
└── .git
├── branches
├── config
├── description
├── HEAD
├── hooks
│ ├── applypatch-msg.sample
│ ├── commit-msg.sample
│ ├── post-update.sample
│ ├── pre-applypatch.sample
│ ├── pre-commit.sample
│ ├── prepare-commit-msg.sample
│ ├── pre-push.sample
│ ├── pre-rebase.sample
│ └── update.sample
├── info
│ └── exclude
├── objects
│ ├── info
│ └── pack
└── refs
├── heads
└── tags
10 directories, 13 files
NOTA: o tree
é um programa instalado a parte (third party
software) que retorna arte ASCII representado a estrutura de
diretórios. Se você usa distribuição Debian, instale com sudo apt-get install tree
. Windows: [tree][].
Minha Primeira Sessão
Vamos começar da maneira mais simples, criando um arquivo com uma linha de texto apenas. Bem, vale avisar que ao longo desse capítulo, os arquivos serão sempre bem pequenos e dificilmente realistas, mas como o enfoque está no funcionamento, não haverá prejuízo.
Vamos criar o arquivo com conteúdo também pelo terminal. Se você preferir, abra um editor de texto favorito (Emacs, Gedit, Geany, RStudio, Bloco de Notas, etc) e faça algo mais elaborado.
cd meu1repo
## Cria o arquivo README.txt com a linha - Meu primeiro repositório Git.
echo "Meu primeiro repositório Git" > README.txt
## Lista os arquivos do diretório.
tree
Este diretório agora é um diretório sob versionamento Git, portanto todas as alterações realizadas serão observadas pelo sistema. Ao criarmos o arquivo e pedirmos a situação (status), o Git indica que existe um arquivo não rastreado (untracked) no diretório. Inclusive sugere uma ação que seria adicionar o aquivo (add). Se o seu sistema operacional está em português, parte dos outputs do Git podem estar traduzidos.
cd meu1repo
## Reconhecimento do Git sobre aquivo criado.
git status
De forma geral temos 3 estágios de arquivos considerados no sistema de
controle de versionamento Git. São eles working directory, Staged
Area e Committed, os discutiremos ao logo do texto. Todo arquivo
criado em um diretório versionado deve necessariamente passar pelos três
estágios. Voltando para a nossa situação temos o arquivo README.txt
criado e atualmente ele está no estágio working directory, faremos
todo o procedimento para que chegue ao estágio committed.
Alterações em arquivos no working directory não são armazenadas, por
isso o sugestivo nome "diretório de trabalho". Portanto, para que o
arquivo seja incluído no monitoramento é necessário que ele receba o
primeiro comando add
. Isso marca a entrada dele no projeto como um
arquivo que a partir de então será versionado.
O status
agora não indica mais que ele está untracked mas sim que
existem mudanças para serem registradas (changes to be commited). A
melhor tradução de commit, pensando no seu uso em Git, é fechar sob
segurança. Quando um commit é feito, cria-se um instante na linha do
tempo que salva o estado do projeto. Para esse instante o projeto pode
ser retrocedido, voltando o condição/conteúdo de todos os arquivos para
o momento no qual o mencionado commit foi feito. Você pode voltar para
um commit de semanas e até anos atrás.
O controle de versão não é apenas voltar os arquivos para o conteúdo que eles tinham no passado. Arquivos rastreados que foram deletados ou renomeados são recuperados. Até mesmo as permissões de leitura/escrita/execução dos arquivos são contempladas no versionamento.
cd meu1repo
## O primeiro `add` submete o arquivo ao versionamento.
git add README.txt
git status
O arquivo README.txt
já é visto pelo Git como um arquivo com o qual
ele deve se "preocupar", pois está sob versionamento. Vamos agora fazer
um registro definitivo sobre o estado desse arquivo (commit). É de
fundamental importância que a mensagem de notificação, ou mensagem de
commit, reflita as modificações feitas. São as mensagens que serão
consultadas quando você precisar desfazer ou voltar para um estado do
seu projeto. Ela deve ser curta (<= 72 caracteres) e ao mesmo tempo
informativa. A minha primeira mensagem não será, todavia.
Boas Práticas de commit:
- Verbo no indicativo
- Frases curtas
- Dizer o que fez e não como fez
Evite mensagens de commit como:
- "Modificações realizadas"
- "Trabalhei muito hoje"
- "Terminando este trabalho na madruga"
cd meu1repo
git config user.name "Knight Rider"
git config user.email "batman@justiceleague.org"
## Registro de versão.
git commit -m "Cria arquivo com título"
O retorno da instrução de commit indica o número de arquivos incluídos no commit e o número de inserções e deleções de linhas. O mais importante está na primeira linha que informa o ramo de trabalho atual (branch) e o sha1 do commit. O sha1 é uma sequência hexadecimal de 40 dígitos que representa unicamente o commit, então são
Para o registro do desenvolvimento, existe uma outra marcação de projeto que são as tags, que tem o caráter de destacar pontos de destaque da ati vidade como por exemplo versão versão alfa, beta.
git tag versao1
git status
# Podemos marcar uma tag com um commit
git tag -a versao2 -m "Versão 2 está pronta"
# Ver todas as tags
git tag
# Excluir tags
git tag -d versao1
Caso haja mudança de nome no arquivo o novo arquivo não estará na mesma etapa, portanto o ideal é alterar o nome do arquivo pelo GIT.
# git mv antigo novo
git mv README LEIAME
Caso você queira excluir o arquivo
git rm README
Aperfeiçoando
Vamos criar mais arquivos e acrescentar conteúdo ao já rastreado pelo Git para percebermos o funcionamento. Escrever uma lista de razões para usar o Linux. A lista é curta poder ampliar no futuro e com erros de português para serem corrigidos posteriormente.
cd meu1repo
## Adiciona mais linhas ao README.txt
echo "
A filosofia do Linux é 'Ria na face do perigo'.
Ôpa. Errado. 'Faça você mesmo'. É, é essa.
-- Lunus Torvalds" >> README.txt
## Cria uma lista de pontos sobre o porquê de usar o Linux.
echo "Por que usar o Linux?
* É livre
* É seguro
* É customizavel" > porqueLinux.txt
Saída
cd meu1repo
## Mostra o conteúdo do arquivo.
less README.txt
cd meu1repo
## Mostra o conteúdo do arquivo.
less porqueLinux.txt
E o que o Git "acha" de tudo isso? O comando status é o mais usado do Git, principalmente nas etapas de aprendizado. Uma característica diferente do Git, se comparado a outras aplicações de uso por terminal, é que ele é realmente camarada. Nas mensagens de output, o Git informa o que aconteceu e também sugere o que fazer.
cd meu1repo
git status
O Git retornou dois campos. No primeiro ele diz que existem mudanças no
README.txt
não encaminhadas para receber registro (not staged for
commit) e no segundo ele aponta que o porqueLinux.txt
é um arquivo
não rastreado (fora de monitoramento).
Vamos explorar um pouco mais os recursos do Git antes de adicionar as
recentes mudanças. Até o momento, temos apenas um commit feito. Para
acessar o histórico de registros usamos git log
. O histórico mostra o
sha1, o autor, data e mensagem de commit. Uma saída mais enxuta é
obtida com git log --oneline
, útil quando o histórico é longo. É
possível fazer restrição no git log
, como mostrar os commits a
partir de certa data, certo intervalo de datas, para um único autor ou
único arquivo. Visite: [git-log][].
cd meu1repo
## Mostra o histórico de commits.
git log
O comando diff mostra as diferenças no conteúdo dos
arquivos/diretório. No caso, apenas o README.txt
está sendo rastreado,
por isso o output indica a adição (+
) de novas linhas. Na saída
tem-se os sha1 das versões comparadas e o intervalo de linhas
envolvido na porção modificada (@@
). Visite: [git-diffs][].
cd meu1repo
## Diferença nos arquivos versionados.
git diff
Vamos aplicar o primeiro add ao porqueLinux.txt
para que ele comece
a ser versionado. Perceba que ao adicioná-lo, as mudanças, no caso a
criação do arquivo com conteúdo, já são separadas para receber registro
(changes to be commited).
cd meu1repo
## Adiciona o arquivo ao processo de reastreamento.
git add porqueLinux.txt
git status
No ramo master
Changes not staged for commit:
(utilize "git add <arquivo>..." para atualizar o que será submetido)
(utilize "git checkout -- <arquivo>..." para descartar mudanças no diretório de trabalho)
modificado: porqueLinux.txt
nenhuma modificação adicionada à submissão (utilize "git add" e/ou "git commit -a")
Na 1° linha diz que estamos no ramo master porém não vem esclarecer com muitos detalhes agora,
Na 2 ° linha diz que mudanças foram feitas no arquivo, e não estão sendo rastreadas. Logo abaixo é citado os comandos que utilizamos na seção anterior para o arquivo se tornar rastreado.
O comando git status
é recomendado que se utilize sempre após algum outro comando git quando você está na fase inicial de aprendizagem.
cd meu1repo
git log --oneline
Por meio dos sha1, podemos aplicar o diff
para visitarmos as
modificações entre dois commits, não necessariamente consecutivos, por
exemplo. Também podemos retroceder (checkout, reset, revert) o
projeto para alguns desses pontos.
Abaixo instruímos o Git mostrar as diferenças para um commit atrás. A
cabeça (HEAD) é o que se entende como estado mais recente. Usa-se o
termo HEAD (cabeça) pois considera-se um crescimento do histórico
debaixo para cima no qual um novo commit é colocado em cima dos demais
(empilhado). O HEAD@{0}
ou apenas HEAD
representa o último registro
feito. Não é necessário escrever o último HEAD
na instrução abaixo.
cd meu1repo
git diff HEAD@{1}
Agora inspecionado uma distância de 2 commits a partir do último. Aqui
tem-se os dois arquivos envolvidos nesse intervalo de 2 commits. Com
--name-only
retorna-se só o nome dos arquivos.
cd meu1repo
git diff HEAD@{2} HEAD@{0}
cd meu1repo
git diff --name-only HEAD@{2} HEAD@{0}
Vamos resolver logo o caso da palavra sem acento em
porqueLinux.txt
. Você abre o arquivo no seu editor de texto e modifica
conforme necessário. A modificação compreende um linha apenas mas aí
lembrei de mais coisas e acrescentei. O git diff
mostra as
diferenças. Epa! As diferenças não eram entre commits? O conteúdo
adicionado ainda não recebeu notificação!
cd meu1repo
echo "Por que usar o Linux?
* É livre
* É seguro
* É customizável
* Tem repositórios de software
* Atualização constante
* Desempenho" > porqueLinux.txt
cd meu1repo
## Depois de corrigir palavras e adicionar conteúdo.
git status
O Git sugere você aplicar *add* para preparar para *commit*. Caso as
modificações sejam um engano e não mais desejadas, você pode
desfazê-las, abandonar a correção/inclusão das palavras usando
`checkout`. Vamos aplicá-lo para ver como funciona.
```{r, engine="bash", echo=-c(1:2)}
cd meu1repo
## Palavras corrigidas e mais itens adicionados.
less porqueLinux.txt
cd meu1repo
## Abandona modificações feitas presentes no arquivo.
git checkout -- porqueLinux.txt
No ramo master Mudanças a serem submetidas: (use "git reset HEAD ..." to unstage)
cd meu1repo
less porqueLinux.txt
2° linha diz que mudanças foram submetidas, e logo abaixo diz caso eu queria retornar esta execução utilizando o comando git reset
,mais pra frente veremos com detalhes.
Vamos commitar
Bateu o arrependimento? Tem formas de poder retroceder com mudanças ainda não registradas mas mantendo a possibilidade de recuperá-las. Mostraremos em breve.
NOTA: sempre que quiser testar um comando novo e não está seguro do que ele faz ou da extensão dos seus efeitos, faça uma cópia do projeto em outro diretório e experimente ele lá. Isso previne sabores amargos, pois algumas ações podem ser irreversíveis.
cd meu1repo
## Depois de desfazer as modificações no porqueLinux.txt
git status
Vamos seguir com as modificações em porqueLinux.txt
que corrigem o
texto e acrescentam itens novos.
cd meu1repo
echo "Por que usar o Linux?
* É livre
* É seguro
* É customizável
* Tem repositórios de software
* Atualização constante
* Desempenho" > porqueLinux.txt
cd meu1repo
git status
O diff
vazio compara o diretório de trabalho com o último registro
(último commit). Quando você usa explicitamente na instrução HEAD@{ }
seguido de número, então estão sendo comparadas versões
"commitadas". Existem variantes de sufixo para usar no HEAD
que são:
HEAD@{n}
HEAD^n
HEAD~n
em que n
é um número inteiro não negativo. Cada sufixo tem uma
finalidade que não detalharemos agora. Visite: [git-caret-and-tilde][].
cd meu1repo
## Modificações no diretório vs último commit.
git diff
cd meu1repo
## Último commit vs dois ancestrais, usando ~.
git diff HEAD~1 HEAD~0
cd meu1repo
## Último commit vs seu ancestral, usando @{}.
git diff HEAD@{1} HEAD@{0}
cd meu1repo
## Último commit vs dois ancestrais.
## git diff HEAD~2 HEAD~0
git diff HEAD@{2} HEAD@{0}
Para ficar claro daqui em diante, você pode ao invés de pedir log
,
pedir o reflog
que incluí as referências em termos da sequência do
mais recente para os seus ancestrais.
cd meu1repo
## Mostra referências para commits os ancentrais.
git reflog
cd meu1repo
## Adiciona e commita.
git add porqueLinux.txt
git commit -m "Novos argumentos."
O Git permite um nível de rastreabilidade bem fino. Veja por exemplo que é possível saber quem modificou e quando cada linha do arquivo e qual o correspondente sha1 do commit.
cd meu1repo
## Mostra quem, onde e o que fez em cada arquivo.
git blame README.txt
Fazendo cópias e trabalhando com ramos
Existem várias formas de se trabalham com ramos. Geralmente os ramos são feitos sob demandas para adicionar uma característica ao projeto (feature) ou corrigir um bug. Alguns ramos, por outro lado, são ramos fixos destinados a receber o desenvolvimento dos ramos de demanda. Esses ramos são geralmente chamados de devel (development) e release. O ramo master é o default e em geral, para projetos grandes, o master só recebe versões funcionais do projeito, livre de bugs.
Para criar um ramo, usamos git branch
seguido do nome que se
deseja. Vamos criar um ramo para adicionar mais arquivos ou modificações
ao projeto.
cd meu1repo
## Lista ramos (all), locais e remotos.
## git branch ## Só ramos locais
## git branch -r ## Só ramos remotos
git branch -a ## Todos os ramos.
cd meu1repo
## Cria um ramo para adição de conteúdo, novo segmento.
git branch feature01
cd meu1repo
## Novo ramo criado aparece.
git branch
cd meu1repo
## Muda o HEAD de ramo.
git checkout feature01
cd meu1repo
## Situação no novo ramo.
git status
cd meu1repo
## Histórico de commits.
git log --oneline
Veja que o novo ramo não começa no zero ou vazio (sem arquivos) e sim a
partir do ramo que é seu ancestral, ou seja, ele começa a partir do
último commit existente, por padrão. Vamos adicionar um arquivo e
commitar. O comando wget
permite baixar arquivos pelo terminal. Será
baixado um arquivo com um função para calcular o fator de inflação de
variância (vif, variance inflation factor) usado em modelos de
regressão, disponível na página da [Professora Suely Giolo][].
## Tenta ir para o diretório downloads, se não conseguir é porque não
## existe então cria um diretório download para então entrar nele.
if [ -d downloads ]
then
echo "Diretório existe."
cd downloads
else
echo "Diretório não existe."
mkdir downloads
cd downloads
fi
## Se não existir o aquivo vif.R, então baixar da internet.
if [ ! -f vif.R ]
then
echo "Arquivo vif.R não existe. Baixando..."
wget 'http://people.ufpr.br/~giolo/CE071/Exemplos/vif.R'
else
echo "Arquivo vif.R já existe."
fi
## Copiar o arquivo vif.R para o meu1repo (-v: verbose).
cp -v vif.R ../meu1repo/
cd meu1repo
## Baixando arquivo da internet. Uma função do R.
wget 'http://people.ufpr.br/~giolo/CE071/Exemplos/vif.R'
## Printa o seria o output da wget mas sem usar a wget para não
## encarecer a compilação. Insere o instante da compilação. Esconde
## também o IP da máquina com ???.??.???.??.
cat << EOF
--$(date +"%Y-%m-%d %H:%M:%S")-- http://people.ufpr.br/~giolo/CE071/Exemplos/vif.R
Resolving people.ufpr.br (people.ufpr.br)... ???.??.???.??, 2801:82:8020:0:8377:0:100:20
Connecting to people.ufpr.br (people.ufpr.br)|???.??.???.??|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 560
Saving to: ‘vif.R’
0K 100% 44,0M=0s
$(date +"%Y-%m-%d %H:%M:%S") (44,0 MB/s) - ‘vif.R’ saved [560/560]
EOF
cd meu1repo
## Situação do repositório após o download.
git status
cd meu1repo
git add vif.R
git commit -m "Adiciona função R para VIF."
cd meu1repo
## Estrutura do diretório.
tree
cd meu1repo
## Histórico de commits.
git reflog
cd meu1repo
git status
Então acabamos de acrescentar um novo aquivo ao projeto. Agora que as modificações foram salvas (commit feito) podemos trocar de ramo. Você vai ver que ao voltarmos para o ramo master o arquivo baixado da internet vai "desaparecer".
cd meu1repo
## Volta para o ramo master.
git checkout master
cd meu1repo
## Estrutura do diretório.
tree
O arquivo vif.R
não sumiu. Ele está no ramo feature01
e só passará
para o ramo master quando mesclarmos o que existe no feature01
ao
master
. Então é assim: mudou de ramo, muda o conteúdo do
diretório. Fazer isso é bem simples, basta dar um git merge
. Antes
vamos aprender como saber as diferenças que existem entre ramos.
cd meu1repo
## Mostra todas as modificações, cada linha modificada de cada arquivo.
git diff master feature01
cd meu1repo
## Mostra só os arquivos modificados.
git diff --name-only master feature01
Como você já havia antecipado, a única diferença entre os ramos master
e feature01
é o arquivo vif.R
. Agora é só pedir o git merge
.
cd meu1repo
## Mesclando as modificações em feature01 no master.
git merge feature01 master
cd meu1repo
git log --oneline
É possível criar um ramo a partir de um commit ancestral ao atual. Isso é extremamente útil para resolver os bugs. Vamos fazer um segundo ramo a partir do commit anterior a inclusão do arquivo R.
cd meu1repo
## Referencias aos commits.
git reflog
cd meu1repo
## Volta para antes do arquivo de baixar o vif.R.
git checkout HEAD@{4}
cd meu1repo
## Qual a situação.
git status
cd meu1repo
## O histório existente nesse ponto.
git log --name-only --oneline
Já que o commit mais recente dessa história aponta para o arquivo compras, vamos checar o seu conteúdo apenas por medida de segurança.
cd meu1repo
## Mostra o conteúdo do arquivo.
less porqueLinux.txt
Dito e feito! Voltamos no tempo para o instante logo após o commit que incluí novos itens na lista. Podemos voltar para o presente se estivermos satisfeitos com o passeio mas também podemos criar um ramo aqui, caso isso seja necessário. Primeiro vamos voltar para o presente depois mostramos como criar o ramo.
cd meu1repo
## Mostra onde estamos.
git branch
Se não fizemos nenhuma modificação, voltar é bem simples. Se modificações foram feitas é necessário saber se precisam ser mantidas e onde ou se devem ser descartadas.
cd meu1repo
## Volta para o presente.
git checkout master
cd meu1repo
git status
cd meu1repo
git log --oneline
cd meu1repo
## Fenda no tempo fechada. Sem sinal do detached HEAD.
git branch
cd meu1repo
## Sinal do passeio no tempo.
git reflog
Vamos começar a ser ousados. Vamos voltar no passado, adicionar um arquivo, commitar e ver o que acontece, como o histórico é representado.
cd meu1repo
## Volta no tempo, após commit que aumenta porqueLinux.txt.
git checkout HEAD@{6}
## Tenta ir para o diretório downloads, se não conseguir é porque não
## existe então cria um diretório download para então entrar nele.
if [ -d downloads ]
then
echo "Diretório existe."
cd downloads
else
echo "Diretório não existe."
mkdir downloads
cd downloads
fi
## Se não existir o aquivo pimentel_racoes.txt, então baixar da internet.
if [ ! -f pimentel_racoes.txt ]
then
echo "Arquivo pimentel_racoes.txt não existe. Baixando..."
wget 'http://www.leg.ufpr.br/~walmes/data/pimentel_racoes.txt'
else
echo "Arquivo pimentel_racoes.txt já existe."
fi
## Copiar o arquivo pimentel_racoes.txt para o meu1repo (-v: verbose).
cp -v pimentel_racoes.txt ../meu1repo/
cd meu1repo
## Baixa arquivo de dados da internet.
wget 'http://www.leg.ufpr.br/~walmes/data/pimentel_racoes.txt'
## Printa o seria o output da wget mas sem usar a wget para não
## encarecer a compilação. Insere o instante da compilação. Esconde
## também o IP da máquina com ???.??.???.??.
cat << EOF
--(date +"%Y-%m-%d %H:%M:%S")-- http://www.leg.ufpr.br/~walmes/data/pimentel_racoes.txt
Resolving www.leg.ufpr.br (www.leg.ufpr.br)... ???.??.???.??
Connecting to www.leg.ufpr.br (www.leg.ufpr.br)|???.??.???.??|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 217 [text/plain]
Saving to: ‘pimentel_racoes.txt’
0K 100% 68,9M=0s
(date +"%Y-%m-%d %H:%M:%S") (68,9 MB/s) - ‘pimentel_racoes.txt’ saved [217/217]
‘pimentel_racoes.txt’ -> ‘../meu1repo/pimentel_racoes.txt’
EOF
cd meu1repo
git status
cd meu1repo
## Adiciona para registrar a inclusão do arquivo.
git add pimentel_racoes.txt
git commit -m "Adiciona aquivo de dados de experimento com rações."
cd meu1repo
git status
cd meu1repo
## Log num formato gráfico ASCII para mostrar o novo ramo.
git log --graph --oneline --decorate --date=relative --all
No nosso projeto temos o master e o feature01 em igual condição, sem nenhuma diferença. O commit recém feito indica um novo seguimento a partir daquele onde adicionamos novos itens na lista. Vamos criar um novo ramo porque atualmente estamos em um ramos suspenso (detached HEAD) que não é persistente.
cd meu1repo
git branch
cd meu1repo
## Um novo ramo a partir do atual HEAD.
git checkout -b feature02
cd meu1repo
git branch
cd meu1repo
git log --graph --oneline --decorate --date=relative --all
Vamos explorar bem a funcionalidade. Vamos voltar para o feature01
e
criar mais coisas lá. Você já deve estar pensando que tudo isso é
absurdo e jamais alguém ficaria indo e voltando assim. Você está certo,
porém, quando o projeto envolve mais pessoas, certamente as coisas irão
bifurcar em algum ponto.
cd meu1repo
git checkout feature01
## Tenta ir para o diretório downloads, se não conseguir é porque não
## existe então cria um diretório download para então entrar nele.
if [ -d downloads ]
then
echo "Diretório existe."
cd downloads
else
echo "Diretório não existe."
mkdir downloads
cd downloads
fi
## Se não existir o aquivo brasilCopa2014.txt, então baixar da internet.
if [ ! -f brasilCopa2014.txt ]
then
echo "Arquivo brasilCopa2014.txt não existe. Baixando..."
wget 'http://www.leg.ufpr.br/~walmes/cursoR/geneticaEsalq/brasilCopa2014.txt'
else
echo "Arquivo brasilCopa2014.txt já existe."
fi
## Copiar o arquivo brasilCopa2014.txt para o meu1repo (-v: verbose).
cp -v brasilCopa2014.txt ../meu1repo/
cd meu1repo
wget 'http://www.leg.ufpr.br/~walmes/cursoR/geneticaEsalq/brasilCopa2014.txt'
## Printa o seria o output da wget mas sem usar a wget para não
## encarecer a compilação. Insere o instante da compilação. Esconde
## também o IP da máquina com ???.??.???.??.
cat << EOF
--$(date +"%Y-%m-%d %H:%M:%S")-- http://www.leg.ufpr.br/~walmes/cursoR/geneticaEsalq/brasilCopa2014.txt
Resolving www.leg.ufpr.br (www.leg.ufpr.br)... ???.??.???.??
Connecting to www.leg.ufpr.br (www.leg.ufpr.br)|???.??.???.??|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 1254 (1,2K) [text/plain]
Saving to: ‘brasilCopa2014.txt’
0K . 100% 69,6M=0s
$(date +"%Y-%m-%d %H:%M:%S") (69,6 MB/s) - ‘brasilCopa2014.txt’ saved [1254/1254]
EOF
cd meu1repo
git add brasilCopa2014.txt
git commit -m "Arquivo sobre copa 2014 celeção brasileira."
cd meu1repo
git log --graph --oneline --decorate --date=relative --all
Agora nos temos o feature01 na frente do master e o feature02 ao lado. O conteúdo dos dois ramos terá que ser incorporado ao master em algum momento porque é assim que funciona. Mas não há razões para preocupação pois o propósito do Git é justamente facilitar esse processo. Nesse caso, por exemplo, como as diferenças nos ramos consiste na adição de arquivos diferentes, incorporar as modificações no master será uma tarefa simples para o Git. O agravante é quando em dois ramos (ou duas pessoas) o mesmo arquivo é modificado no mesmo intervalo de linhas. Nessa situação o merge nos arquivos deve ser supervisionado e não automático. Vamos incorporar as modificações dos ramos ao master então.
cd meu1repo
## Volta para o master.
git checkout master
cd meu1repo
## Mescla o feature01.
git merge feature01 master
cd meu1repo
## Mescla o feature02.
git merge feature02 master
cd meu1repo
git log --graph --oneline --decorate --date=relative --all
cd meu1repo
tree
Resolvendo conflitos
Agora vamos de propósito mostrar uma situação em que não é possível fazer o merge automaticamente. Vamos criar um conflito. Para isso vou criar um ramo novo, modificar o arquivo na última linha e commitar. Vou voltar par ao master e fazer o mesmo mas vou usar um texto diferente para incluir no arquivo. Já que os ramos feature01 e feature02 não são mais necessários, podemos removê-los. No entanto, eles permanecem na história do projeto e poder ressurgir se você voltar no tempo.
cd meu1repo
## Remove ramos.
git branch -d feature01
git branch -d feature02
git branch
cd meu1repo
git log --graph --oneline --decorate --date=relative --all
Agora vou criar um novo ramo, adicionar um arquivo e encurtar o nome das colunas no cabeçalho.
cd meu1repo
## Muda para um ramo criado na hora.
git checkout -b feature03
## Tenta ir para o diretório downloads, se não conseguir é porque não
## existe então cria um diretório download para então entrar nele.
if [ -d downloads ]
then
echo "Diretório existe."
cd downloads
else
echo "Diretório não existe."
mkdir downloads
cd downloads
fi
## Se não existir o aquivo bib1.txt, então baixar da internet.
if [ ! -f bib1.txt ]
then
echo "Arquivo bib1.txt não existe. Baixando..."
wget 'http://www.leg.ufpr.br/~walmes/data/bib1.txt'
else
echo "Arquivo bib1.txt já existe."
fi
## Copiar o arquivo bib1.txt para o meu1repo (-v: verbose).
cp -v bib1.txt ../meu1repo/
cd meu1repo
## Baixa o arquivo.
wget 'http://www.leg.ufpr.br/~walmes/data/bib1.txt'
## Printa o seria o output da wget mas sem usar a wget para não
## encarecer a compilação. Insere o instante da compilação. Esconde
## também o IP da máquina com ???.??.???.??.
cat << EOF
--$(date +"%Y-%m-%d %H:%M:%S")-- http://www.leg.ufpr.br/~walmes/data/bib1.txt
Resolving www.leg.ufpr.br (www.leg.ufpr.br)... ???.??.???.??
Connecting to www.leg.ufpr.br (www.leg.ufpr.br)|???.??.???.??|:80... connected.
HTTP request sent, awaiting response... 200 OK
Length: 535 [text/plain]
Saving to: ‘bib1.txt’
0K 100% 35,0M=0s
$(date +"%Y-%m-%d %H:%M:%S") (35,0 MB/s) - ‘bib1.txt’ saved [535/535]
EOF
cd meu1repo
## Mostra as 4 primeiras linhas.
head -4 bib1.txt
Ao encurtar o nome para quatro dígitos, fica assim.
cd meu1repo
## Substitui o conteúdo da primeira linha pelos nomes truncados em 4
## dígidos e separados por tabulação. Etapa que você pode fazer no seu
## editor de texto.
sed -i "1s/.*/rept\tvari\tbloc\ty/" bib1.txt
head -4 bib1.txt
cd meu1repo
git add bib1.txt
git commit -m "Arquivo de experimento em BIB. Trunca cabeçalho 4 digitos."
Baixamos e modificamos o arquivo. Adicionamos e fizemos o registro das modificações. Agora vamos voltar ao master e baixar o arquivo também, fazendo de conta que é outra pessoa trabalhando no mesmo projeto, mas essa pessoa vai passar a cabeçalho para caixa alta.
cd meu1repo
git checkout master
## Copiar o arquivo bib1.txt para o meu1repo (-v: verbose).
cd downloads
cp -v bib1.txt ../meu1repo/
cd meu1repo
## Baixa o arquivo.
wget 'http://www.leg.ufpr.br/~walmes/data/bib1.txt'
Ao encurtar o nome para quatro dígitos, fica assim.
cd meu1repo
## Substitui o conteúdo da primeira linha pelo mesmo em caixa alta. Faça
## isso no seu editor de texto de preferido.
sed -i '1s/.*/\U&/' bib1.txt
head -4 bib1.txt
cd meu1repo
git add bib1.txt
git commit -m "Arquivo de experimento em BIB. Cabeçalho em caixa alta."
cd meu1repo
git diff master feature03
cd meu1repo
git log --graph --oneline --decorate --date=relative --all
cd meu1repo
## Dá mensagem de erro que informa o conflito.
git merge feature03 master
x <- system("cd meu1repo && git merge feature03 master", intern=TRUE)
cat(paste(x, collapse="\n"))
cd meu1repo
git status
cd meu1repo
## `less` printa o conteúdo do arquivo mas `head` limita para 10 linhas.
less bib1.txt | head -10
Então deu conflito e o Git informa que ele deve ser resolvido. Resolver
o conflito aqui significa abrir os arquivos com problema listados no git
status e editar de tal forma a "desconflitar". Nas regiões de conflito o
Git sinaliza de forma especial, indicando por divisórias (<<<<<<<
,
=======
e >>>>>>>
) as versões no HEAD (ramo master) e no ramos a
ser incorporado (feature03). Então vamos resolver o conflito sem
favorecer ninguém, ou seja, vamos encurtar para 4 dígitos e manter caixa
alta. Dessa forma o aquivo fica assim.
cd meu1repo
sed -i '1,3d;5d' bib1.txt
sed -i '1s/.*/\U&/' bib1.txt
cd meu1repo
## Arquivo depois da edição que resolve o conflito.
head -6 bib1.txt
cd meu1repo
git status
cd meu1repo
git add bib1.txt
git commit -m "Resolve conflito, trunca com caixa alta."
cd meu1repo
git status
cd meu1repo
git log --graph --oneline --decorate --date=relative --all
cd meu1repo
git reflog