Como usar o Git – básico

Git é uma ferramenta indispensável para os desenvolvedores e saber utilizá-lo pode aumentar sua produtividade e até mesmo melhorar a qualidade do seu código. Este post explica conceitos, as principais funcionalidades do git e os comandos básicos que você utilizará no seu dia-a-dia:

  • como instalar o git no windows
  • clone
  • push
  • branch
  • merge
  • checkout

Vamos aprender a o git pela linha de comando que eu considero a maneira mais produtiva de trabalhar com Git. Há, no entanto, uma tarefa que prefiro fazer utilizando uma interface gráfica: resolução de conflitos. Vamos aprender a utilizar o VS Code para resolver conflitos no Git e também aprender a fazer isto utilizando a linha de comando.

Se você nunca trabalhou na área de desenvolvimento vai ver aqui um passo a passo básico do git com tudo que você vai usar no seu dia-a-dia. Se você já trabalhou com git poderá encontrar aqui dicas que podem te ajudar a ser mais produtiva.

O que é Git?

Git é uma sistema de controle de versão criado pelo Linus Torvalds o criador do Linux. Tanto software comerciais como open source (código aberto) utilizam Git, é o sistema de controle de versão mais utilizado no mundo.

Este sistema permite que diversos desenvolvedores trabalhem sobre o mesmo código sem que um atrapalhe o outro. Ele permite você “voltar ao passado” e analisar uma versão de código antiga.

Um dos grandes diferenciais dele é que é um sistema distribuído. Isto quer dizer que há uma cópia do repositório completo com todo o histórico de mudanças no computador do desenvolvedor. Os sistemas de versionamento que existiam antes do Git mantinham todo o histórico de versões no servidor e o usuário apenas tinha uma cópia dos arquivos em sua máquina.

Outra grande vantagem que ele tem sobre os concorrentes é a velocidade, é muito rápido comitar código, mudar para outro branch, fazer merge e comparar versões anteriores.

O que é Github?

O Github é um site que disponibiliza o Git na nuvem. Ele é gratuito para quem quer guardar seu código fonte aberto. Se você quiser deixar seu código fonte fechado para que ninguém mais possa ter acesso, você precisará pagar uma mensalidade ao Github. É este modelo que muitas empresas de tecnologia adotam.

O Github ficou famoso pois muitos projetos código aberto (open source) foram migrados para lá. Além do que, ele é extremamente amigável e tem muitas funcionalidades que auxiliam o desenvolvedor.

O Github tem dois concorrentes fortes: Gitlab e Bitbucket. Ambos com opções gratuitas para guardar seus códigos. A vantagem do Bitbucket é que você pode deixar seu código privado mesmo na versão gratuita.

Conceitos básicos do git

Repositório – é o agrupamento lógico do arquivos de um projeto. Imagine que você tem dois projetos diferentes um de e-commerce e um de blog, o código fonte de cada um deles ficará separado em repositório diferentes.

Origin – se refere ao repositório original, a fonte principal. É o repositório remoto que sincroniza o código de todos os desenvolvedores do projeto. O Github é um repositório origin por exemplo.

Branch – o git trabalha com “ramos”, e o termo branch se refere a um ramo de código. Quando você cria um branch, você herda todo o código na versão atual. O seu branch fica isolado, quando você terminar suas modificações, você une seu ramo de volta ao código original. Deste ponto em diante, todos que atualizarem o código terão sua versão.  

Master – master é o ramo principal, normalmente é onde o código mais atual ou seja, a versão que está rodando em produção fica guardado.

Commit – o commit representa uma versão. O usual é fazer alterações no código, em diversos arquivos separados e assim que tivermos uma versão funcional, fazemos um commit incluindo todas as modificações que foram feitas até então. Esse commit vira um ponto na história que podemos resgatar quando quisermos.

Checkout – ação de apontar o repositório para uma certa versão ou branch.

Git básico – passo a passo

Como instalar no windows

O site https://git-scm.com/ possui a versão de windows e mac para baixar.

Baixe a versão de windows

Execute o instalável e mantenhas as configurações padrão:

Agora vou dar uma dica legal para vocês que utilizam windows, que é utilizar o ConEmu como substituto do console padrão do Windows. Você pode baixá-lo aqui. Siga os passos da instalação padrão, mas se disponível, escolha a versão x64 bits:

Instale a versão 64 bit do conemu.
Instale a versão 64 bit do conemu.

A segunda dica é instalar o posh-git, ele mostra algumas informações sobre o repositório no direto no console. Use os seguintes comandos para instalar:

Import-Module posh-git
Add-PoshGitToProfile -AllUsers -AllHosts

Feito isso você conseguirá ver o nome do branch diretamente no ConEmu:

poshgit no conemu
poshgit

Como criar um repositório

Você precisa ter um login no Github para fazer esta operação, depois que estiver logado na home page clique no botão New para criar um novo repositório:

criar repositório Github
criar repositório Github

Dê um nome ao seu repositório:

crie um repositório no git
crie um repositório no git

Clonando um repositório remoto

A tela seguinte mostra algumas opções para iniciar o repositório. Vamos utilizar a versão HTTPS pela facilidade.

git setup
setup do git

Copie o endereço HTTPS do repositório. Vá no seu console, na pasta onde quer criar o repositório e digite o comando git clone [endereço].

git clone
git clone

Pronto! Agora a pasta academia_hopper é um repositório do git.

Configurando o seu usuario e email no Git

Antes de começarmos a adicionar arquivos, precisaremos configurar nosso nome e mail no git.

git config --global user.name "Nome"
git config --global user.email "[email protected]"

Comitando um arquivo

Iremos simular o desenvolvimento do programa de contatos que fizemos no post sobre dicionários. Então criaremos o primeiro arquivo main.py apenas com o cabeçalho:

main.py:

print("--------------------------------")
print("----------CONTATOS--------------")
print("--------------------------------")

Quando você cria este arquivo você já consegue ver no console algumas informações. Vamos usar o comando git status para ver todas as alterações que não foram comitadas:

git status
git status

Como pode ver, o posh git que instalamos anteriormente mostra que há mudanças. o sinal +1 indica que há um novo arquivo criado que não foi comitado. O primeiro passo para comitar é fazer um add. Este comando adiciona os arquivos modificados em uma área temporária chamada stage para ser comitada. Você deve adicionar todos os arquivos e depois fazer o commit:

git commit
git commit

Note que o comando comit recebe um parametro -m que é a mensagem. Esta mensagem servirá para identificar o que havia neste commit.

Comitando vários arquivos

Vamos aprender agora como comitar mais de um arquivo por vez. Crie um novo arquivo funcoes.py onde vamos criar a função procura_chaves e também faça uma alteração no arquivo main.py:

funcoes.py:

def procura_chaves(dicionario, nome):
  chaves = []
  for chave in dicionario:
    if chave.startswith(nome):
      chaves.append(chave)
  return chaves
  
##############################
main.py:

contatos = {}

comando = "continue"

while comando != "sair": 
  print("                     ")
  comando = input("Digite o comando: (novo, pes, sair):")

  if comando == "novo":
    print("comando novo selecionado")

  if comando == "pes":
    print("comando pes selecionado")

O git status agora mostra que temos um arquivo modificado e um arquivo novo que não foram comitados ainda:

git status com 2 arquivos alterados
git status com 2 arquivos alterados

Note que o posh git mostra agora também o simbolo ~1 que indica que há um arquivo modificado.

O jeito mais fácil de adicionar mais de um arquivo para ser comitado é passar “.” como nome do arquivo. O git vai identificar todos os arquivos que foram alterados e arquivos novos e adicioná-los na área de stage.

git add múltiplos arquivos
git add múltiplos arquivos

Agora é só comitar novamente.

git commit com múltiplos arquivos
git commit com múltiplos arquivos

Git log

Este comando permite ver todo o histórico de alterações feito no repositório, ele mostra as versões mais atuais primeiro.

comando git log
comando git log

Criando um branch

Vamos imaginar que agora existe dois programadores trabalhando neste repositório. Então vamos criar um branch para trabalhar em uma versão isolada e adicionar a funcionalidade de criação de novo contato.

Criamos um branch fazendo um checkout passando um parâmetro -b que indica o nome do branch. Quando fazemos isto e o branch não existe, ele é criado na hora, baseado na versão do código atual.

git checkout para novo branch
git checkout para novo branch

Agora implementamos a funcionalidade de criação de novo contato:

main.py:

if comando == "novo":
    nome = input("Nome: ").strip()
    telefone = input("Telefone: ").strip()
    email = input("E-mail: ").strip()

Vamos adicionar e comitar as alterações deste arquivo utilizando os comando add e commit que vimos anterioremente. Veja que agora o comando status mostra 3 commits, pois esse branch também inclui os primeiros commits que fizemos.

git log em um branch
git log em um branch

Merge de um branch no master

Para simular uma situação real, vamos voltar ao branch master e comitar um código que vai conflitar com a mudança feita no branch. Faça um checkout de volta para o branch master:

git checkout master

Iniciamos alterarando o arquivo main.py fazendo uma pequena mudança, alterando a mensagem que é impressa para cada comando, alterando apenas a primeira letra para maiúscula:

while comando != "sair": 
  print("                     ")
  comando = input("Digite o comando: (novo, pes, sair):")

  if comando == "novo":
    print("Comando novo selecionado")

  if comando == "pes":
    print("Comando pes selecionado")

Em seguida temos que comitar esta alteração diretamente no master, simulando um outro programador alterando um código que estamos alterando no nosso branch.

git log no master
git log no master

Agora o master tem um commit a mais que o branch não tem. Vamos voltar para o branch e olhar novamente o log de commits dele:

git log no branch
git log no branch

Note que o primeiro item do log é diferente, pois o branch divergiu do master. Agora vamos trazer as mudanças feitas no branch para o master. Para isto utilizaremos o comando merge. Este comando deve ser rodado no branch que vai receber as atualizações, que neste caso é o master.

O próximo passo é fazer checkout para o master novamente e executar o comando merge passando o nome do branch que queremos trazer.

comando git merge
comando git merge

Há um conflito, isto ocorreu pois houve uma mudança na mesma linha de arquivo. Vamos ver na próxima sessão como resolver este conflito.

Resolvendo conflitos no de merge no git com linha de comando

Ao executar o comando git status, você spoderá ver que há um conflito.

git status com conflito
git status com conflito

Se você abrir o arquivo main.py verá umas marcações indicando o conflito:

while comando != "sair": 
  print("                     ")
  comando = input("Digite o comando: (novo, pes, sair):")

  if comando == "novo":
<<<<<<< HEAD
    print("Comando novo selecionado")
=======
    nome = input("Nome: ").strip()
    telefone = input("Telefone: ").strip()
    email = input("E-mail: ").strip()
        
>>>>>>> criar_novo_contato

  if comando == "pes":
    print("Comando pes selecionado")

A marcação <<<<<<< HEAD indica a versão do master. O texto entre as marcações ======= e >>>>>>>> criar_novo_contato é a versão que está vindo do branch que estamos fazendo merge. Como queremos manter a versão que veio do branch, basta remover a parte do HEAD e manter o texto que veio do branch:

while comando != "sair": 
  print("                     ")
  comando = input("Digite o comando: (novo, pes, sair):")

  if comando == "novo":
	nome = input("Nome: ").strip()
	telefone = input("Telefone: ").strip()
	email = input("E-mail: ").strip()

  if comando == "pes":
    print("Comando pes selecionado")

Após corrigir o conflito do arquivo, é preciso sinalizar para o git que o conflito foi resolvido, adicionando o arquivo à area de stage e depois é só fazer o merge:

git commit com conflito
git commit com conflito

Resolvendo conflitos de merge not git com interface gráfica

Todo programador utiliza uma IDE (Integrated Development Environment) de sua preferência. Uma IDE nada mais é que um programa especial para edição de código. Eu gosto bastante do Visual Studio Code pois ele é gratuito, a versão pura dele é bem simples, para utilizá-lo no dia-a-dia é preciso instalar extensões específicas que te ajudam na linguagem que você está utilizando, mas isto é assunto para outro post.

Se você prefere uma IDE mais completa e feita especialmente para a linguagem que vai trabalhar, pode dar uma olhada nas ferramentas da JetBrains.

Ambas tem suporte a resolução de conflitos, vou mostrar aqui como funciona no VS Code. Acesse a ferramenta de source control:

botão de controle de versão do VS Code
botão de controle de versão do VS Code

Você verá esta tela:

resolução de conflito de merge no VS Code
resolução de conflito de merge no VS Code

Ao lado do nome do arquivo há um ícone “C” que indica que o arquivo está com conflito. E então o VS Code apresenta o texto em uma maneira mais amigável pois separa em cores diferentes a versão do master (Current Change) e a versão do branch (Incoming Change). Acima ele te dá algumas opções que você pode escolher e ele já resolve o conflito para você, as opções são:

  • Accept Current Change: mantém a versão do master e ignora o que está vindo do branch
  • Accept Incoming Change: mantém a versão que está vindo do branch e ignora a do master
  • Accept Both Changes: mantém as duas versões, uma em seguida da outra.
  • Compare Changes: mostra as diferenças lado a lado, dependendo do conflito, fica mais fácil identificar o que fazer olhando nesta tela.
compare changes VS Code
compare changes VS Code

Para o nosso caso, como queremos manter a versão do branch, então escolhemos a opção Accept Incoming Change. O VS Code ira alterar o arquivo, mas você precisará salvá-lo manualmente. Ele ficará assim:

VS Code conflito resolvido
VS Code conflito resolvido

Note que o ícone “C” ainda aparece no nome do arquivo, é por que não sinalizamos para o Git que o conflito foi resolvido e o arquivo está ok. Para fazer isto, é necessário adicionar o arquivo na área de stage e depois podemos fazer o commit.

git conflito resolvido
git conflito resolvido

Analisando a árvore do git

Com o objetivo de entendermos melhor o que aconteceu dentro do git em todas estas operações que fizemos, vamos analisar a árvore de branches dele.

árvore de branches do git
árvore de branches do git

Na figura, o branch master está representado pela linha azul. Dá para ver que o branch “criar_novo_contato” foi criado a partir do segundo commit do master. O branch recebeu um commit. Depois o branch foi integrado no master com um commit chamado “Merge branch ‘criar_novo_contato'”.

Este é o padrão de trabalho nas empresas de tecnologia modernas, todo o trabalho é feito em branches, e quando o programador considera que o trabalho está terminando, ele faz um merge para o master. O que ocorre é que é normal o branch durar mais de um dia, pois as mudanças mais complexas podem resultar em vários commits.

Fazendo push para o repositório remoto

Como comentamos anteriormente o Git é um sistema distribuído que mantém uma cópia completa do repositório na máquina do desenvolvedor. Tudo que fizemos até agora está na sua máquina, está na hora de subir isto para o servidor do Github para garantir que seus dados não serão perdidos.

Como o repositorio do Github está vazio precisamos configurar ele pela primeira vez executando o comando git push com a opção –set-upstream origin master.

git push inicial
git push inicial

O seu repositório do Github agora tem os dois arquivos que criamos e também os 5 commits que fizemos até agora:

repositório inicial no Github
repositório inicial no Github

As próximas vezes que quiser sincronizar seu repositório local com o Github, basta usar o comando git push sem precisar passar outras opções.