Introdução ao controle de versão Git
Tags: braziliandevs, git, iniciante
Published: 2021-08-27 14:03:26

## O que é o git?

O Git é um sistema distribuído e open-source de controle de versão utilizado pela grande maioria dos desenvolvedores atualmente. Com ele podemos criar todo histórico de alterações no código do nosso projeto e facilmente voltar para qualquer ponto para saber como o código estava naquela data.

O Git nos auxilia a controlar o fluxo de novas features (funcionalidades) entre múltiplos desenvolvedores no mesmo projeto e facilita a gestão, análise e resolução de conflitos quando um mesmo arquivo é editado por mais de uma pessoa.

## Os três estados do GIT e o ciclo de vida dos arquivos

![Os três estados do GIT e o ciclo de vida dos arquivos](https://dev-to-uploads.s3.amazonaws.com/uploads/articles/ee99d2fulptxuepsc50o.png)

Entender o conceito dos três estados é essencial para a compreensão e uso do Git.

Um arquivo sempre estará em um dos estados fundamentais: 

- **Não rastreado (untracked)**

    O arquivo foi criado, modificado ou removido porém não foi rastreado pelo GIT, ou seja, seria como se o GIT não soubesse do estado exato desse arquivo e não tem controle do versionamento.

- **Modificado (modified)**

    Uma vez no repositório, qualquer arquivo que é adicionado, modificado ou removido é marcado como modificado. Significa que o arquivo sofreu alterações, mas ainda não foi dito que ele fará parte do próximo commit, ou seja, da próxima versão que será consolidada.
    Significa também que esses arquivos estão diferentes quando comparados com a última versão disponível no histórico.

- **Preparado (staged)**

    A partir do momento que o comando git add é executado em algum arquivo, ele assume o estado de preparado. Neste momento, o Git sabe que o arquivo foi modificado e agora está na área de preparação para ser consolidado.
    A área de preparação pode ser pensada como a parte de trás das cortinas de uma apresentação. Pode ser que entre ou não entre no palco, é o momento da decisão.

- **Consolidado (committed)**

    *Após toda a preparação, os arquivos são finalmente salvos quando o comando **git commit** é executado. É importantíssimo destacar que se algum arquivo se encontra no estado modificado e é feito um **git commit**, estes arquivos continuarão como modificados, eles não farão parte do commit, pois nunca foram preparados.*

    *Pensando no cenário do palco novamente, os arquivos modificados não estavam prontos para entrar no palco, eles ainda estavam em um estágio muito inicial, antes ainda da preparação.*

    *Assim, uma vez que um commit é executado, uma nova imagem é salva no histórico e esta imagem contém o estado do arquivo ou arquivos que foram salvos. Além disso, os arquivos serão salvos se, e somente se, estiverem na área de preparação. É um fluxo que deve ser seguido.*

Toda vez que um arquivo é salvo no controle de versão, ou seja, é registrado uma versão, o Git armazena algo parecido com uma imagem do arquivo que representa seu estado atual.

As palavras em inglês estão exemplificadas para familiarização, pois o Git mostra as mensagens em inglês e tais termos aparecem frequentemente.

## Comandos básicos do GIT

Segue abaixo os comandos mais utilizados no Git:

### Configurações para o git

Segue os comandos para visualizar, editar ou definir dados de configurações:

- **Verificando as configurações locais**

    Quando trocamos de máquina podemos fazer um commit com um usuário ou email diferente, e isso pode estragar nosso histórico no Git.

    Para verificar as configurações locais podemos usar o comando:

    ```ruby
    git config --list
    ```

- **Visualizar o nome do usuário**

    Para visualizar o nome do usuário:

    ```ruby
    git config --global user.name
    ```

- **Visualizar o email do usuário**

    Para visualizar o email do usuário:

    ```ruby
    git config --global user.email
    ```

- **Definindo o nome do usuário**

    Para definir o nome do usuário:

    ```ruby
    git config --global user.name "nome do usuário"
    ```

- **Definindo o email do usuário**

    Para definir o email do usuário:

    ```ruby
    git config --global user.email "email do usuário"
    ```

### Trabalhando com o repositório remoto

- **Listando o caminho do servidor**

    Para sabermos para onde estão sendo enviadas nossas alterações ou de onde estamos baixando as coisas, rodamos:

    ```ruby
    git remote -v
    ```

- **Adicionando o caminho do servidor**

    Caso tenhamos criado o repositório localmente antes de criar no servidor, podemos adicionar o caminho com o comando set-url.

    ```ruby
    git remote set-url origin git://url
    ```

- **Alterando o servidor**

    Para alterar o servidor onde hospedamos nosso repositório, usamos o mesmo comando set-url.

    ```ruby
    git remote set-url origin git@github.com:dnovais/my_cv.git
    ```

### Trabalhando com repositórios

- **Iniciar um repositório**
Na pasta que será o novo repositório Git, execute o comando:

    ```ruby
    git init
    ```

- **Clonar ou “Baixar” um repositório**

    Para baixar um repositório do GitHub, Bitbucket, GitLab ou qualquer que seja o servidor do nosso projeto, devemos rodar o comando git clone com o link do repositório.

    ```ruby
    git clone <link>
    ```

### Comandos do fluxo de trabalho

Segue abaixo uma sequência de comandos que são bastante usados no dia a dia.

- **Baixar as últimas alterações do servidor**

    Quando algo estiver diferente no nosso repositório remoto (no servidor), podemos baixar para a nossa máquina com o comando pull.

    ```ruby
    git pull
    ```

- **Verificando o que foi alterado**

    Para sabermos se tem algo que foi modificado em nossa branch, rodamos o comando git status.

    ```ruby
    git status
    ```

    Será retornado uma lista de itens que foram alterados. Para saber o que exatamente aconteceu rodamos o comando git diff.

    ```ruby
    git diff
    ```

    Será retornada uma tela com o que foi adicionado escrito com um +.

    O que foi removido aparece com um -.

    Caso tenhamos mais de um arquivo alterados por vez, podemos analisar todo o histórico com git diff ou observar somente um arquivo com git diff nome_do_arquivo.

- **Adicionando alterações**

    Quando alteramos algo, devemos rodar o comando git add para adicionar ao index e depois fechar um commit.

    ```ruby
    git add nome_do_arquivo
    ```

- **Adicionando tudo de uma vez**

    Muitas vezes trabalhamos com mais 1 arquivo, e para adicionar todos de uma vez:

    ```ruby
    git add .
    ```

    OBS: Cuidado com esse comando, pois você pode adicionar algo que não queria.

- **Fazendo um commit**

    Quando adicionamos com o `git add` ainda não estamos persistindo os dados no histórico do Git, mas adicionando a uma área temporária onde podemos ficar levando e trazendo alterações até garantirmos que algo realmente deve ser salvo, então rodamos o `git commit`.

    Para fazer um commit, precisamos adicionar uma mensagem ao pacote, então rodamos com o parâmetro `-m "mensagem"`.

    Depois de ter adicionado as alterações com `git add`, rodamos:

    ```ruby
    git commit -m "mensagem"
    ```

- **Adicionando e fazendo um commit em tudo de uma vez**

    Também podemos rodar git commit com o parâmetro -am, onde adicionamos tudo de uma vez e já deixamos uma mensagem para o commit.

    ```ruby
    git commit -am "add tudo"
    ```

- **Removendo o arquivo do stage**

    Para remover um arquivo do stage rodamos o comando reset.

    ```ruby
    git reset nome_do_arquivo
    ```

    **Removendo tudo**

    ```ruby
    git reset HEAD .
    ```

- **Listando as branches existentes**

    Para listar todos os branchs presentes em sua maquina:

    ```ruby
    git branch
    ```

- **Criando uma nova branch**

    Para criar uma nova branch podemos rodar o comando:

    ```ruby
    git branch <nome>
    ```

- **Trocando de branch**

    Para trocar de branchs temos o comando:

    ```ruby
    git checkout <nome_da_branch>
    ```

- **Criando uma nova branch e já trocando para ela**

    É possível criar uma branch e já trocar diretamente para essa branch:

    ```ruby
    git checkout -b <nome_da_branch>
    ```

- **Enviando uma branch para o servidor**

    Caso tenhamos criado uma branch em nossa máquina, precisamos enviar ela para o servidor com o comando push, explicado mais abaixo neste texto, e passar alguns parâmetros que são o origin e nome da branch.

    ```ruby
    git push origin <nome_da_branch>
    ```

- **Deletando uma branch**

    Para deletar uma branch é necessário que tenha feito a troca para uma outra branch, pois não é possível deletar uma branch estando nela. Para isso temos o comando:

    ```ruby
    git branch -d nome
    ```

- **Juntando (mesclando) branches**

    Quando trabalhamos com branches, mais cedo ou mais tarde, vamos precisar juntar as nossas alterações com a branch master.

    Para isso usamos o comando `merge`.

    ```ruby
    git checkout master
    git merge nome_branch
    ```

- **Enviando as alterações para o branch master**

    Depois que finalizamos nossas alterações, fechamos nossos commits, então devemos enviar os commits para o servidor. Para isso rodamos o comando:

    ```ruby
    git push origin master
    ```

### Apagando, movendo ou renomeando arquivos ou pastas sem estragar nosso histórico Git

Quando deletamos algum arquivo, movemos de pastas, o Git fica com um histórico de deleção de arquivo e adição de outro.

Para que isso não aconteça, existem comandos do Git que salvam nossas vidas, o `git rm`, para deletar, e `git mv`, para movermos coisas.

- **Para remover um arquivo:**

    ```ruby
    git rm <nome_do_arquivo>
    ```

- **Para remover uma pasta:**

    Lembrando que, para remover pastas, é sempre necessário que ela esteja vazia ou que executemos o comando `rm` com o parâmetro -r para que a deleção seja recursiva.

    ```ruby
    git rm -r <pasta>
    ```

### Movendo ou renomeando arquivo ou pasta com Git

Em alguns momentos precisamos mover ou renomear alguns arquivos ou pastas com comandos do GIT, e para isso usamos o mesmo comando.

```ruby
git mv <nome_do_arquivo_ou_pasta> <destino>
```

### Revertendo alterações

Existem diversas maneiras de desfazer coisas com o Git e tudo depende do objetivo e cenário.

- **Desfazendo no stage**

    ```ruby
    git reset <nome_do_arquivo>
    ```

- **Desfazendo tudo no stage**

    ```ruby
    git reset nome_do_arquivo
    ```

- **Desfazendo tudo para o último commit**

    As vezes precisamos desfazer tudo e deixar como estava:

    ```ruby
    git checkout .
    ```

- **Desfazendo alterações em um arquivo para o último commit**

    Podemos desfazer alterações de um arquivo específico para o último commit:

    ```ruby
    git checkout nome_do_arquivo
    ```

- **Desfazendo uma alteração, mas colocando ela em stage**

    Para desfazer alguma alteração e colocar em stage, rode o comando:

    ```ruby
    git reset --soft HEAD~1
    ```

- **Desfazendo para o último commit sem colocar as alterações em stage**

    As vezes precisamos desfazer um commit sem colocar as alterações em stage, para isso rode o comando:

    ```ruby
    git reset --hard HEAD~1
    ```

- **Desfazendo para um commit específico**

    Devemos procurar o hash do commit no histórico do Git e então executar:

    ```ruby
    git revert <hash>
    ```

- **Desfazendo o último push**

    Para desfazer o último push, basta rodar o comando:

    ```ruby
    git reset --hard HEAD~1 && git push -f origin master
    ```

### Analisando o histórico (log)

Para ver todo o histórico podemos rodar o comando log.

```ruby
git log
```

### Utilizando tags

- **Criar uma tag Git**

    Rodamos o comando tag com o parâmetro que seria o nome da tag que queremos colocar.

    ```ruby
    git tag 0.0.1
    ```

- **Listando as tags Git**

    Para listar as tags existentes, rodamos o comando tag sem parâmetro.

    ```ruby
    git tag
    ```

- **Criar uma tag com mensagem (anotada)**

    Para adicionar uma mensagem ou descrição para a tag:

    ```ruby
    git tag -a 0.0.1 -m "versão 0.0.1"
    ```

- **Criar uma tag a partir de um commit**

    Podemos criar a tag referenciando um commit utilizando o hash do commit (que encontramos no histórico) com o comando -a.

    ```ruby
    git tag -a 0.0.1 b6120
    ```

- **Criando a tag no servidor**

    Para enviar uma tag para o servidor:

    ```ruby
    git push origin 0.0.1
    ```

- **Enviando todas as tags de uma vez no servidor**

    Para mandar todas as tags de uma só vez

    ```ruby
    git push origin --tags
    ```

### Utilizando stash

- **Salvar tudo no stash**

    Para armazenar algo no stash (uma área temporária onde guardamos o histórico sem realmente adicionar na master) podemos utilizar os seguintes comandos.

    ```ruby
    git stash
    ```

- **Salvando no stash com descrição**

    Quando precisamos salvar algo no stash para trocarmos de estado várias vezes e verificar como fica nesses estados, como em um protótipo, podemos fazer:

    ```ruby
    git stash save -u "mensagem"
    ```

- **Listando o que existe em stash**

    Para listar o que existe na stash:

    ```ruby
    git stash list
    ```

- **Revertendo para o stash e removendo da lista**

    Podemos reverter nossas alterações para o stash e ainda remover uma entrada do stash list fazendo o seguinte:

    Removendo a última entrada na lista.

    ```ruby
    git stash pop
    ```

- **Revertendo para o stash**

    Para remover a última entrada da lista e voltar o código, mas sem remover do stash:

    ```ruby
    git stash apply
    ```

- **Revertendo versão específica do stash**

    Devemos olhar na lista do stash qual o item do histórico que queremos reverter e então rodar o comando apply.

    ```ruby
    git stash apply stash@{numero}
    ```

### Ignorando arquivos

É extremamente normal ignorar arquivos no Git para não salvarmos arquivos de configuração dos nossos editores, arquivos temporários do nosso sistema operacional, dependências de repositório, etc.

Para isso criamos um arquivo chamado `.gitignore` e adicionamos os nomes dos arquivos nele.

Link de exemplo: 

[github/gitignore](https://github.com/github/gitignore/blob/master/Rails.gitignore)

Contato:
Email: contato@diegonovais.com.br
LinkedIn: https://www.linkedin.com/in/diegonovais/
Github: https://github.com/dnovais