# Git básico
### Introdução

Esta wiki procura introduzir alguns conceitos básicos do git e como utilizar algumas de suas funcionalidades. O Git é um sistema de controle de versão desenvolvido por Linus Torvalds para ser utilizado como ferramenta de versionamento do Linux. Ele possui uma série de vantagens, por exemplo:
* Suporte forte ao desenvolvimento não-linear: facilita a criação de múltiplas linhas de desenvolvimento e a integração entre elas.
* Desevolvimento distribuído (descentralizado): o Git permite que cada desenvolvedor possua um repositório local para realizar seu trabalho sobre o projeto.
* Compatível com diversos protocolos de comunicação: HTTP, SSH, FTP, etc.

### Gerenciamento de Arquivos

O primeiro passo para utilizar o git é a criação de um repositório no interior do diretório que será versionado, que basicamente cria todo o diretório de trabalho do git (o local que ele utilizará para realizar o versionamento de um conjunto de arquivos), o comando para isso é:
Após a criação do repositório Git, é possível versionar os arquivos à sua escolha que se encontram no diretório submetido à versionamento. O Git considera quatro estados possíveis para um arquivo:
* Untracked: o arquivo ainda não está sendo monitorado pelo git.
* Tracked: o arquivo está sendo versionado pelo git.
* Modified: o arquivo foi modificado desde a última versão registrada pelo git.
* Staged: o arquivo fará parte do próximo commit.
É possível visualizar o estado atual dos arquivos de um diretório utilizando o comando:
Para selecionar um arquivo para participar do próximo commit e para começar a ser versionado pelo git, basta utilizar o comando:
Para registrar uma versão de um arquivo, basta realizar um commit dos arquivos que estão no estado "staged" (já foram adicionados com o comando git add):
O editor padrão será aberto para que você escreva uma mensagem descrevendo o commit que acabou de ser feito.

### Gerenciamento de branches

Um projeto sendo submetido à controle de versão geralmente possuí múltiplas linhas de desenvolvimento, devido à existência de trabalhos paralelos e a criação de versões experimentais do projeto.
O Git facilita a criação de múltiplas linhas de desenvolvimento e o mecanismo básico para isso é a criação de branches. Uma branche é a abstração construída pelo git para representar uma linha de desenvolvimento. Geralmente, várias branches são criadas e cada uma está associada a um trabalho específico que agrega algum valor ao projeto. Em algum momento, quando estes trabalhos forem finalizados e estiverem estáveis, eles devem ser integrados. O git fornece dois mecanismos básicos para a integração de branches: o merge e o rebase. Seguem abaixo alguns comandos do git para utilizar as funcionalidades comentadas neste tópico:
Cria uma nova branch:
Seleciona uma branch para uso
Cria e acessa uma nova branch
Fornece uma lista de branches e a branch atual (apontada por um asterisco)
Integra a branch especificada com a branch atual
Integra a branch atual com a branch especificada

#### Merge vs Rebase

Para entender a diferença entre merge e rebase, é necessário compreender as estratégias de integração utilizadas pelo Git. Todas as versões de um projeto formam um grafo, que se ramifica à medida que vão sendo criadas novas linhas de desenvolvimento e que convergem quando uma integração é realizada. Quando uma integração é realizada, o Git seleciona uma de duas abordagens possíveis: Fast-forward e merge recursivo.
O Fast-forward é selecionado quando um dos commits é um descendente direto do commit sendo integrado, neste caso, o Git apenas avança a referência de uma das branches para o commit mais atual.
O merge recursivo ocorre quando existe uma divergência entre as linhas de desenvolvimento sendo integradas. Neste caso, o git identifica o primeiro ancestral em comum entre as branches e realiza a integração se baseando neste ancestral compartilhado pelas versões. Durante uma integração baseada na estratégia fast-forward, o resultado de um merge e um rebase são idênticos, porém, se o merge recursivo for selecionado, existem algumas diferenças.
O merge integra a última versão da branch especificada no comando com a última versão da branch atual gerando um novo commit dessa integração. O rebase aplica as versões distintas da branch atual sobre a pilha das versões da branch especificada, neste caso, não há um commit adicional de integração, o que faz aparentar que o histórico foi resultado de um trabalho linear (sequencial), ao invés de paralelo, como de fato ocorreu. O rebase fornece um histórico mais "limpo" do que o merge.

#### Conflitos

Durante a integração de linhas de desenvolvimentos distintas, é possível que alguns conflitos ocorram. Um conflito é uma situação em que duas versões distintas do projeto alteraram exatamente os mesmos trechos de um arquivo. Neste caso, não há como o git inferir qual versão deve ser selecionada e o desenvolvedor terá que analisar o arquivo manualmente para resolver o conflito.
O processo é bastante simples, basta que o desenvolvedor identifique quais arquivos possuem conflitos utilizando o comando git status. Uma mensagem será exibida indicando que um arquivo possui conflitos ("Both modified", ambas as versões modificaram o arquivo). Após a identificação, o desenvolvedor precisa abrir o arquivo e analisá-lo, o git terá inserido no arquivo as duas versões que conflitaram e o desenvolvedor terá que selecionar as partes que fizerem sentido de acordo com o contexto da situação.

### Gerenciamento de repositórios remotos

O git possui repositórios remotos e locais, os repositórios locais estão localizados nos computadores dos desenvolvedores e os repositórios remotos são hospedados por serviços de repositório como GitLab e o GitHub. É possível adicionar um repositório remoto e nomeá-lo com o seguinte comando:
Para baixar um repositório remoto para sua máquina local, é possível usar o seguinte comando:
Para listar os repositórios remotos já adicionados, utilize o seguinte comando:
O git mantêm branches locais que mantêm versões locais de uma determinada branch, por exemplo: master e branches remotas que espelham as branches hospedadas no repositório remoto, por exemplo: origin/master. Para atualizar as branches que espelham o repositório remoto, basta utilizar o comando:
Após a atualização das branches remotas, basta integrá-las às branches locais correspondentes (utilizando merge ou rebase) para que você possa trabalhar sobre a última versão do projeto mantida no repositório remoto. Existe um comando que automatiza este processo:
O git pull atualiza as branches remotas com a última versão mantida no repositório remoto e as integra automaticamente às branches locais. Ele utiliza por padrão o merge para realizar a integração, mas é possível utilizar o rebase passando uma flag como parâmetro para o comando:
Para atualizar o repositório remoto com a versão contida no seu repositório local, basta utilizar o comando git push para realizar o upload da sua versão para o remoto:

### Fork

Em casos que o desenvolvedor não é um contribuidor oficial do projeto e queira contribuir de forma colaborativa é necessário realizar um fork que funciona como uma cópia do repositório. No fork, é criado um repositório espelho do repositório original (upstream) e um repositório local para que seja possível o desenvolvimento de forma que os repositórios mantenham um relacionamento.
Para realizar um fork no GitLab, basta estar logado em seu usuário, entrar na página do projeto desejado e apertar o botão circulado em vermelho na imagem abaixo.

### Merge request

Após realizar o fork e alterações no projeto, para que essas alterações possam ser integradas no upstream é necessário realizar um merge request, ou seja, um pedido de contribuição para algum mantenedor do projeto original. Assim que o mantenedor receber o merge request, ele irá analisar as suas alterações e possivelmente integra-las ao projeto. Para realizar um merge request no GitLab, basta estar logado em seu usuário, apertar o botão circulado em vermelho na imagem abaixo e preencher as informações requeridas.