Git e GitHub


Introdução: Git e GitHub

No desenvolvimento de software duas situações ocorrem com frequência:

  • na medida em que se escreve código é comum que uma alteração crie problemas que tornam importante voltar para um estágio anterior, onde o problema não existe;
  • vários programadores podem trabalhar em um mesmo projeto e nem sempre é fácil juntar as alterações feitas.

Além disso é comum se fazer uma bifurcação do projeto em algum ponto para fazer experimentações ou gerar novo projeto. O controle de versões facilita o fluxo de trabalho de quem necessita acrescentar características, corrigir erros ou voltar para etapas anteriores de um projeto.


O Git é uma ferramenta de controle de versão (um sistema de versionamento) que mantém um histórico do projeto, permitindo o retorno à qualquer ponto e facilitando as junções de códigos desenvolvidos separadamente. Ela é uma ferramenta usada na linha de comando (embora existam aplicativos GUI que podem ser encontrados na página Git – GUI clients). Ele não é o único aplicativo para o controle de versões mas tem se tornado o mais usado deles. Git é considerado a segunda criação mais famosa e usada de Linus Torvalds, o criador do Linux. Git é um sistema de controle de versão distribuído (distributed version control system, DVCS).

Além dos clientes GUI disponíveis para o controle do Git e integração com o GitHub existem diversas IDEs que facilitam esse controle de versão, como o PyCharm e o VSCode. As sessões do Jupyter Notebook também podem ser controladas com o Git.

GitHub é uma plataforma na internet que usa o Git para hospedar código e projetos, e controle de versão. Existem outras alternativas, como GitLab e BitBucket.

Git e GitHub são coisas diferentes! Git é uma ferramenta de controle de versão de código aberto criada em 2005. GitHub é uma empresa fundada em 2008 que criou um site que usa o Git. Você pode usar o Git apenas em sua máquina, mas isso torna mais difícil o compartilhamento de código.

Conceitos e definições:

Alguns conceitos e definições são importantes para o uso do Git e do GitHub. Todos eles serão desenvolvidos no texto do artigo.

Projeto: é qualquer conjunto de código destinado à realização de uma tarefa. Ele pode ser um texto em processo de construção, um aplicativo com seu código ou um conjunto de páginas da web.
Diretório de trabalho é aquele em que seu projeto é desenvolvido. Seus arquivos não são automaticamente rastreados pelo Git, que precisa ser informado de quais arquivos deve acompanhar.
Área de preparação
(staging area)
é o conjunto de arquivos marcados para acompanhamento pelo Git. Nenhum arquivo no diretório de trabalho é automaticamente marcado para acompanhamento pelo Git. Arquivos são colocados na staging area com o commando git add <arquivo> e no repositório com git commit.
Repositório local é uma área na máquina local dedicado ao armazenamento do Git para o estado do projeto nos momentos decididos pelo desenvolvedor. Ele armazena as diversas versões e ramificações feitas por um ou mais desenvolvedores. Repositórios são, às vezes, chamados de “repos”.
Repositório do GitHub é um repositório remoto, hospedado no site do GitHub. Podemos sincronizar nosso repositório local com o do GitHub ou vice-versa, baixando para a máquina local o repositório remoto.
HEAD é o ponteiro que marca o estado do código ativado no Git. Esse estado consiste nos branch e commit ativos.

Nem todas as alterações no projeto precisam ser armazenadas. Por isso apenas são guardadas as situações quando se faz um commit, por decisão do desenvolvedor. Estritamente dizendo, commit não necessita guardar sempre os arquivos inteiros no repositório. Ele tenta ser o mais leve possível, armazenando apenas as modificações feitas desde o último commit. Por isso alternar entre um e outro estado é uma operação bastante rápida.

A estrutura do Git dispensa o uso de um servidor centralizado para armazenar todas as modificações. Ele permite que vários desenvolvedores alterem seus repositóritos locamente em suas máquinas e depois o façam o upload de seus trabalhos. Ele também facilita o trabalho de juntar as diversas modificações feitas.

Instalando o Git

Muitos sistemas operacionais instalam e mantém atualizado o Git. Você pode verificar se tem o Git instalado em seu sistema abrindo um terminal e digitando:

$ git --version
git version 2.35.1

A versão será exibida, ou uma mensagem de erro caso ele não esteja instalado. É possível atualizar a versão do Git usando o próprio Git:

$ git clone https://github.com/git/git

Se necessária a instalação visite o site do Git – downloads. Alguns exemplos de instalação:

 Debian/Ubuntu
# PPA para Ubuntu da última versão estável
$ add-apt-repository ppa:git-core/ppa
$ apt update
$ apt install git

# Debian/Ubuntu
$ apt-get install git

Fedora (até versão 21, usando yum)
$ yum install git
Fedora (versão 22 ou posterior, usando dnf)
$ dnf install git

Para Windows faça download e instale os executáveis apropriados.

Configurando o Git

Vamos também configurar o nome e email associado ao repositório local, usando git config:

$ git config --global user.email "seu_email@example.com"
$ git config --global user.name "Seu nome"
# nenhuma resposta é exibida

Essas informações são usadas pelo Git para marcar quem foi o autor de cada alteração registrada. Além do nome podemos usar outros comandos para alterar o comportamento e aparência do Git no console.

# os seguintes comandos instruem git usar cores para realce de sintaxe no console
$ git config --global color.ui true
$ git config --global color.status auto
$ git config --global color.branch auto

# para definir um editor
$ git config --global core.editor nome_do_editor

# para definir a ferramenta default de merge (junção de versões)
$ git config --global merge.tool vimdiff

# para listar todas as configurações alteradas do git
$ git config --list

As configurações de config --global color tornam mais legíveis as linhas do console. Por default Git usa o editor padrão definido nas configurações do sistema. Esse padrão pode ser alterado aqui, por exemplo fazendo git config --global core.editor vim

Quando se trabalha simultaneamente com o GitHub podemos fazer alterações em qualquer um dos ambientes e depois se sincronizar com o outro. Alterações locais não alteram o repositório do GitHub, até que sejam a ele enviadas.

Usando o Git localmente

Na máquina local usamos um diretório de trabalho para desenvolver nosso projeto. Digamos que queremos iniciar um projeto que contenha código Python para manipulação de texto. Denominaremos esse projeto de PyTexto e criaremos um diretório com esse mesmo nome. Depois, usando o terminal, navegamos até este diretório e inicializamos o Git.

# cria pasta, inicializa git
$ mkdir ~/Projetos/PyTexto
$ cd ~/Projetos/PyTexto
$ git init
  hint: Using 'master' as the name for the initial branch. This default branch name
  hint: is subject to change.  (...)

# para renomear o branch ou ramo podemos usar git branch -m novo_nome

# vamos renomear para "main" 
$ git branch -m main
# para visualizar a situação do git
$ git status
  On branch main
  No commits yet
  nothing to commit (create/copy files and use "git add" to track)
  
# outras informações sobre o repositório local podem ser vistas com
$ git log  

) O Git cria um diretório oculto .git dentro do diretório de trabalho, e inicializa um branch (ramificação) original, chamada master, que renomearemos para main. Por default, até o Git 2.35, a inicialização cria um branch (ou ramo) principal chamado branch master. Tem sido uma prática adotada por desenvolvedores renomear esse ramo para branch main ou branch trunk (ou o nome que você preferir). É possível configurar o Git para que o branch inicial de seus novos repositórios se chame branch main:

# altera o nome default da branch inicial
$ git config --global init.defaultBranch main


Para inserir ou editar arquivos usarei o editor de código Geany, disponível para Linux, macOS e Windows. Qualquer editor ou IDE podem ser usados.

É uma boa prática criar um arquivo (usando o seu IDE preferido ou qualquer editor de texto) README.md (ou README.txt) onde o desenvolvedor coloca instruções de uso e instalação, comentários sobre o projeto, versão, etc. A extenção .md indica que o arquivo contém texto formatado com a marcação markdown. Você pode ler sobre markdown aqui!

Depois criamos outro arquivo no nosso diretório de trabalho. Nesse caso inserimos um arquivo do python com o nome palindromo.py. Os conteúdos podem ser, por exemplo:

# arquivo README.md
# Projeto de teste e aprendizado do Git
Consiste em testes de funcionamento do Git

e o arquivo do python:

# arquivo palindromo.py
# palindromo (testa se a palavra é um palíndromo)
def palindromo(palavra):
    palavra = palavra.upper()
    p = ("" if palavra == palavra[::-1] else "não")
    return (f"{palavra} {p} é um palíndromo")

Em princípio nenhum dos arquivos nesse diretório são rastreados pelo Git até que o informemos que deles devem fazer parte do repositório. Podemos ver isso com git status:

$ git status
  On branch main
  No commits yet
  Untracked files:
  (use "git add ..." to include in what will be committed)
    README.md
    palindromo.py
  nothing added to commit but untracked files present (use "git add" to track)

Vemos que o Git reconhece que dois arquivos foram inseridos na pasta de trabalho, mas nenhum deles foi marcado para acompanhamento (colocado em stage). Isso é feito com o comando:

$ git add nome_do_arquivo
# no nosso caso
$ git add README.md
$ git add palindromo.py

# caso existam vários arquivos, e todos devem ser marcados, usamos
$ git add -A

Com isso os arquivos são marcados como estando na área de preparação (staging area), e são atualizados pelo Git até que um commit seja executado. Vamos verificar novamente o status do repositório:

$ git status
  On branch main
  No commits yet
  Changes to be committed:
     (use "git rm --cached ..." to unstage)
     new file:   README.md
     new file:   palindromo.py

Esse comando informa que o branch main está ativo, que README.md e palindromo.py estão em stage, prontos para o commit. Para enviar arquivos em stage para o repositório fazemos o commit. A lista de todos os commits feitos naquele branch pode ser vista com git log.

$ git commit - m "Commit 1 com arquivos README.md e palindromo.py"

# para ver a lista de todos os commits naquele branch
$ git log
  commit 48c3f1f8fae05f87bd79f58b2d4f0cca42d8f8d5 (HEAD -> main)
  Author: Guilherme Santos Silva <gssilva57.gmail.com>
  Date:   Tue Mar 15 14:39:42 2022 -0300

    Commit 1 com arquivos README.md e palindromo.py
:

Se o output de git log for maior que a área disponível do console ele termina com o sinal :. Isso é uma indicação de que você pode rolar a tela do console para ler todo o texto. Para sair desse modo digite q ou CTRL-z. Uma forma compacta de adicionar arquivos e fazer commit ao mesmo tempo consiste em usar a marca commit -am:

$ git commit -am "descrição do commit"

O comando commit faz com todos os arquivos adicionados à área de preparação sejam enviados para o repositório. A chave -m "mensagem" adiciona uma mensagem junto a esse commit, que pode ser visualizado mais tarde. Ela deve ser um texto curto e explicativo de quais alterações estão sendo gravadas.
git
Esse comando falha se não tiver sido feita a configuração de git config --global user.email e git config --global user.name. Caso contrário a alteração pode ser verificada com git status.

$ git status
  On branch main
  nothing to commit, working tree clean

Dessa forma criamos, alteramos e inserimos todas as alterações no repositório.

A lista de todos os commits feitos naquele branch pode ser vista com git log.

# para ver a lista de todos os commits naquele branch
$ git log
  commit 48c3f1f8fae05f87bd79f58b2d4f0cca42d8f8d5 (HEAD -> main)
  Author: Guilherme Santos Silva <gssilva57.gmail.com>
  Date:   Tue Mar 15 14:39:42 2022 -0300
    Commit 1 com arquivos README.md e palindromo.py

O output desse comando mostra um hash identificador e mostra que o branch ativo é HEAD -> main, o autor e data e o texto atribuído ao commit.

Após ter feito um commit podemos voltar para a sitação anterior usando git reset. Existem três modos de ser fazer um reset.

# desfaz o commit sem modificar nenhum dos arquivos comitados
$ git reset --soft <numero de hash>

# desfaz o commit sem modificar arquivos comitados, mas desfazendo os adds
$ git reset --mixed <numero de hash>

# desfaz o commit e apaga tudo o que foi modificado após o commit prévio
$ git reset --hard <numero de hash>

Fazendo o reset --soft retornamos o projeto para um estado logo anterior ao commit. Desta forma podemos fazer os consertos necessários e voltar a dar commit. reset --hard deve ser usado com cuidado pois significa a perda de todas as alterações feitas após o último commit (principalmente quando se trabalha em grupo). O <numero de hash> é o código exibido em git log (48c3f1f8fae05f87bd79f58b2d4f0cca42d8f8d5 no último caso). Apenas os primeiros 7 dígitos podem ser usados (48c3f1f). Após o reset o estado ativo (indicado por HEAD -> main) será aquele indicado por esse número.

Retomando o projeto: Mais tarde, para retomar o trabalho no projeto local, basta voltar no mesmo diretório de trabalho (que contém a pasta oculta .git. Nesse diretório podemos continuar a edição dos arquivos existentes, inserindo novos arquivos, modificando ou apagando os existentes.

Agora editamos o arquivo README.md e inserimos o arquivo indesejado.py (com qualquer conteúdo) e o adicionamos à área de stage.

# volte para o diretório de trabalho    
$ cd ~/Projetos/PyTexto
# conteúdo do arquivos listado abaixo
$ geany README.md
# insere novo arquivo indesejado.py
$ geany indesejado.py

# para adicionar todos os arquivos de uma vez
$ git add -A

Use o seguinte conteúdo para README.md:

# arquivo README.md
# Projeto de teste e aprendizado do Git
Consiste em testes de funcionamento do Git
Inserimos um arquivo a ser removido

Se, mais tarde, verificamos que um arquivo qualquer <arquivo.ext> não deveria fazer parte do projeto podemos removê-lo de duas formas:

# rm --cached é usado para remover o arquivo de stage sem apagá-lo do diretório de trabalho
git rm --cached <arquivo.ext>

# rm -f para remover o arquivo de stage e forçar seu apagamento do diretório de trabalho
git rm -f <arquivo.ext>

# se o arquivo não está na pasta default
$ git rm --cached diretorio/<arquivo.ext>

# para remover todos os arquivos na pasta
$ git rm --cached diretorio/*

Para efeito de teste vamos remover o arquivo indesejado.py. Depois vamos restaurá-lo, criando outro arquivo com o mesmo nome, adicioná-lo e fazer um commit.

# removemos o arquivo
$ git rm -f indesejado.py

# gravamos novo arquivo, add e commit
$ echo "qualquer coisa" > indesejado.py
$ git add indesejado.py
$ git commit -m "3 commit, inserindo indesejado.py"

# para ver o estado do repositório commitado
$ git ls-tree -r main
  100644 blob 26bb6383445abf68be689e9724de464d1908bbcc   README.md
  100644 blob 6f16acbbc80d444145a09d897a93591cd806d3f8   indesejado.py
  100644 blob 1904a1ec5c3900cccbc80ae3b94e3debd34afb42   palindromo.py

# para remover do repertório (e do sistema de arquivos)   
$ git rm indesejado.py
  rm 'indesejado.py'

echo "qualquer coisa" > indesejado.py é uma linha de comando do bash que permite gravar um arquivo com o conteúdo da string.

Podemos navegar para qualquer commit, que terá o estado do projeto feito naquele momento. Vamos verificar isso. O comando cat do linux lista o conteúdo do arquivo. Use o comando equivalente para seu SO ou abra o arquivo com o editor. Para ver os commits feitos, juntamente com um código que os identificam, usamos git log ou git log --oneline (uma versão com output simplificado).

$ cat README.md
  # Projeto de teste e aprendizado do Git
  Consiste em testes de funcionamento do Git

# para listar todos os commits feitos
$ git log --oneline
48c3f1f (HEAD -> main) 3. insere indesejado.py
0073fc0 3. insere indesejado.py
6ce467f Commit 1 com arquivos README.md e palindromo.py

# podemos alternar entre diferentes commits. Vamos voltar para o 1º
$ git checkout 6ce467f
  Note: switching to '6ce467f'.
  HEAD is now at 6ce467f Commit 1 com arquivos README.md e palindromo.py

# nesse estado o arquivo README.md tem o seguinte conteúdo
$ cat README.md
  # Projeto de teste e aprendizado do Git
  Consiste em testes de funcionamento do Git  

Essa operação mostra como é importante inserir texto explicativos de cada situação quando fazemos o commit. O procedimento acima mostra que, voltando para um commit anterior o estado do projeto, incluindo todos os arquivos nele existentes, volta para o que foi gravado naquele commit.

Visualizando alterações

Uma funcionalidade importante do Git consiste na possibilidade de verificar quais alterações foram feitas em arquivos. Para ver isso vamos alterar o arquivo README.md de seguinte forma:

arquivo original arquivo modificado
# Projeto de teste e aprendizado do Git
Consiste em testes de funcionamento do Git
# Projeto de teste e aprendizado do Git

Linha inserida para testar o diff

Para ver as alterações desde o último estado gravado usamos git diff.

$ git diff
  diff --git a/README.md b/README.md
  index 26bb638..85818ef 100644
  --- a/README.md
  +++ b/README.md
  @@ -1,2 +1,3 @@
  # Projeto de teste e aprendizado do Git
  -Consiste em testes de funcionamento do Git
  +
  +Linha inserida para testar o diff

Os sinais significam: + linha inserida; linha removida.
Esse output indica que o arquivo README.md foi alterado: a 1ª linha foi mantida; a 2ª foi apagada (sinal ) e uma linha em branco inserida; uma 3ª linha foi inserida, (sinal +).
Se todas as linhas fossem removidas e uma nova linha inserida teríamos o output de diff:

$ git diff
-# Projeto de teste e aprendizado do Git
-Consiste em testes de funcionamento do Git
+# Novo linha inserida

Se mais de um arquivo foi modificado, todas as alterações aparecem em git diff. Para ver apenas o nome dos arquivos alterados, o que é útil quando houve muitas alterações, usamos a chave –name-only.

$ git diff --name-only
  README.md

Podemos também ver alterações de apenas um arquivo com git diff nome_arquivo.ext. Se, após examinar as modificações, desistimos de alterar um dos arquivos, voltamos atrás apenas na edição desse arquivo.

$ git checkout HEAD README.md

O README.md voltará para o estado anterior, usado na comparação por diff. HEAD é um atalho para o branch atual. Agora verificamos que git diff não exibirá nenhuma mensagem.

$ git checkout HEAD README.md
  Updated 1 path from 384f1f8
$ git diff

Conta do GitHub


GitHub é um serviço de hospedagem online para repositórios Git. Ele permite a sincronização entre repositórios na máquina local e no site remoto. Com esse repositório remoto você tem uma cópia atualizada de todas as suas versões do projeto.

Abra uma conta no GitHub. Dentro da página existem manuais e ajudas para o uso do site. Depois crie um novo repositório (veja figura), dando o nome desse repositório. Escolha o nível de acesso em Descrição -> acessibilidade (Público ou Privado). Quaisquer alterações feitas em um repositório ficam em suspenso até que uma ordem de commit seja emitida, o que faz com que o estado atual do projeto seja armazenado no repositório.

É sempre recomendado inserir um arquivo README junto com seu projeto. Ele serve para descrever o projeto ou adicionar instruções de instalação e seu conteúdo é exibido na primeira página do repositório. Assim como no Git local, toda alteração de arquivo de projeto só se torna parte do repositório após um commit (o que no GitHub é feito com um botão!)

Como veremos, sempre podemos sincronizar as alterações de um repositório local com o repositório do GitHub.

Clonagens

Quando nossas alterações locais estão terminadas podemos clonar nosso projeto para o GitHub. Isso significa que replicamos todo o repositório local para o GitHub. Para isso usamos git push:

O nome do repositório local é o nome de nosso projeto, PyTexto. Entre no GitHub e crie remotamente um repositório com o mesmo nome. (Isso é feito clicando no botão New na sua página inicial.) Quando isso é feito o GitHub fornece um endereço para https, no meu caso https://github.com/gssilva57/PyTexto.git. Agora os repos podem ser conectados:

# conecta repos
$ git remote add origin https://github.com/gssilva57/PyTexto.git

# abra o branch principal de seu repo
$ git branch -M main

# push repo local para o remoto
$ git push -u origin main


Dessa forma o repositório local para o projeto PyTexto estará espelhado no GitHub.

Se estamos na pasta de projeto onde um repositório Git foi definido, todas as alterações serão sincronizadas com o GitHub. Para ver essas alterações atualizamos o navegador aberto no GitHub e podemos ver nele, dentro desse projeto, os arquivos palindromo.py e README.md.

Se você fizer alterações remotas no GitHub de qualquer parte do projeto dê um commit no site. Em sua máquina local vá até o diretório do projeto e digite, na linha de comando:

# para fazer o download das alterações do github para o projeto local
$ git pull

Agora seu projeto local estará novament sincronizado com o remoto e exibirá as alterações feitas lá.

Sincronização com o GitHub

Clonar um repositório do GitHub significa fazer uma cópia do repositório para seu computador local com um download ( git pull). A clonagem faz uma cópia completa de todos os dados do repositório, incluindo todos os commits e branches que o GitHub possui naquele momento. Você pode clonar um projeto para o mesmo repositório junto com outros desenvolvedores para realizar a mesclagem (merge) e fazer correção de conflitos.

Repo Local com o GitHub

Se você tem conteúdo próprio no GitHub você pode reproduzir em sua máquina local o repositório remoto. Esse é um processo chamado clone. Para isso precisamos obter a URL da página do repositório do GitHub. Depois navegamos até o diretório onde queremos esse repositório duplicado e usamos:

$ git clone url_do_projeto_no_github
# o seguintes informações são pedidas
Username for 'https://github.com': seu_user_namer
Password for 'https://gssilva57@github.com':  token de acesso

Atualmente o GitHub não permite que essa operação seja feita apenas com a senha de acesso ao site. A melhor forma de autenticar o comando de linha é habilitando a autenticação em dois passos no GitHub e criando um token de acesso. Todas as informações para isso estão disponíveis no GitHub.

Clonando repositórios de terceiros


Você também pode clonar o repositório de outra pessoa que o tenha tornado público. Dessa forma você para contribuir com um projeto ou simplesmente usar o código de outro desenvolvedor (desde que ele assim o autorize). No GitHub existem livros, vídeos, áudios para treinamento de desenvolvedores, bancos de dados sobre temas variados, blocos de código para diversas finalidades, projetos de jogos, de aplicativos open-source abertos para a participação de devenvolvedores que desejam colaborar, e muito mais.

Você pode fazer uma busca no próprio GitHub ou procurar por sugestões com um mecanismo de busca. Uma lista de projetos interessantes pode ser vista no site Hackernoon.com, página: githubs top 100 most valuable repositories.

Clonando o Microsoft VSCode

Como um exemplo, vamos clonar o Microsoft VSCode. Na página citada acima, do Hackernoon.com encontramos a URL: https://github.com/Microsoft/vscode. Na página do projeto encontramos uma tabela com arquivos e pastas do projeto. Acima da tabela temos o botão code, como na figura, com as alternativas para se baixar todo o repositório. Uma delas consite em usar a própria url acima, como o comando git clone URL:

# criamos uma pasta para abrigar o repo
$ mkdir ~/Projetos/vscode
# navegamos até essa pasta
$ cd ~/Projetos/vscode

# executamos o comando git de clonagem
$ git clone https://github.com/Microsoft/vscode

Agora, se verificarmos o conteúdo da pasta, veremos que o projeto do vscode está lá. Nesse caso está incluído um arquivo README.md com instruções de uso do repositório e instalação do aplicativo.

O VSCode (ou Visual Studio Code) é um bom editor de código feito pela Microsoft para Windows, Linux e macOS. Ele pode ser usado com várias linguagens, inclusive o Python. VSCode é leve e inclui recursos para depuração, realce de sintaxe, conclusão de código inteligente, snippets, refatoração de código e Git incorporado. Usuários podem alterar tema, atalhos de teclado e instalar extensões que adicionam funcionalidades adicionais.

Gerenciando Conflitos

Quando mais de um desenvolvedor altera o projeto em locais diferentes as alterações são mescladas sem nenhuma mensagem de conflito. Um conflito de versões ocorre quando dois desenvolvedores alteram as mesmas linhas de código no mesmo arquivo. Nesse caso o Git lança uma mensagem de conflito de mesclagem e passa para o desenvolvedor a responsabilidade de resolver a situação.

Uma forma de visualizar a situação é a seguinte: em sua máquina local edite o arquivo palindromo.py alterando apenas a linha com o return:

# arquivo palindromo.py
...
    return ("Texto alterado no palíndromo")

Salve o arquivo e faça o commit. Agora no site do GitHub abra o mesmo arquivo e faça uma alteração diferente, na mesma linha:

...
return (f"A palavra {palavra} {p} é um palíndromo")

Faça o commit para que a alteração entre no repositório. Na prática essa seria uma alteração feita por um colega desenvolvedor. Temos agora alterações feitas localmente e no GitHub.

Agora, na máquina local, vamos fazer o push do arquivo modificado para o GitHub. Um mensagem de erro é exibida e o arquivo onde existe o conflito é listado.

# Um atalho (shortcut) para git add e git commit pode ser usado:
$ git pull

# em seu computador local, no terminal, uma mensagem de erro é emitida
  CONFLICT (content): Merge conflict in palindromo.py
  Automatic merge failed; fix conflicts and then commit the result

O arquivo palindromo.py em seu computador foi alterado para mostrar onde foi o conflito. Ele agora tem o seguinte conteúdo:

# arquivo palindromo.py
# palindromo (testa se a palavra é um palíndromo)
def palindromo(palavra):
    palavra= palavra.upper()
    p = ("" if palavra == palavra[::-1] else "não")
<<<<<<< HEAD
    return (f"{palavra} {p} é um palíndromo")
=======
    return ("Texto alterado no palíndromo")
>>>>>>> a986 ... (um código longo)

Como vemos as duas alterações foram exibidas, a primeira feita na máquina local, a segunda no GitHub. Para resolver o conflito apague as mensagens de erro, mantendo apenas a linha (ou linhas) considerada correta:

# exibindo só a linha alterada de palindromo.py
    return (f"{palavra} {p} é um palíndromo")

Em seguida refazemos as etapas add e commit, enviando arquivo palindromo.py atualizado para o GitHub:

# podemos usar atalho para git add e  git commit
$ git commit –am “commit resolvendo conflito em merge”

O arquivo correto, editado à mão pelo desenvolvedor, estará em ambos os repositórios, local e remoto.

Ramificações (ou branching )

É possível ramificar o código de um projeto com o Git de forma que o desenvolvedor possa trabalhar com um “ramo” sem alterar o código-fonte do projeto original. Isso é útil no caso de uma tentativa de variação do projeto que pode ser, mais tarde, definitivamente incorporada ou não. Se o novo ramo for bem sucedido ele pode ser mesclado com o original ou mesmo substituí-lo completamente. Um novo branch permite a alteração daquele estado sem alterar o estado original de onde foi ramificado. Quando um novo branch é criado ele é composto exatamente dos mesmos arquivos e commits de onde foi copiado.

Suponha, por exemplo, que o projeto esteja em uma fase que agrada ao seu cliente e você entrega a ele uma versão funcional. Pode ocorrer mas tarde que ele deseje acrescentar funcionalidades ao projeto. Nesse ponto será interessante criar novo branch ou ramificação. Uma ramificação pode ser criada à partir de qualquer estágio de commit.

Ramificando um projeto

À partir do branch main podemos criar uma ramificação com git checkout (ou git switch). Um novo branch é criado e ativado, com conteúdo idêntico ao do daquele usado como base. O comando git branch pode ser usado para verificar todas as ramificações criadas até agora.

# para ramificar o branch ativo
$ git checkout -b novo_branch
  Switched to a new branch 'novo_branch'

$ git branch
  main
* novo_branch

checkout
O parâmetro -b faz com que, além de criar um novo branch, ele também será selecionado. O prefixo * mostra que estamos agora com novo_branch ativado. O comando alternativo git switch para a troca de branchs é novo e está em fase experimental. Se estivermos com o branch main ativado podemos usar switch:

$ git branch
* main
  novo_branch
$ git switch novo_branch
  Switched to branch 'novo_branch'

Para alterar o nome de um branch ative aquele cujo nome você quer mudar. Depois use git branch -m nome_novo caso queira trocar o nome do branch.

$ git checkout nome_antigo
$ git branch -m nome_novo
$ git status
  On branch nome_novo

Também é possível renomear qualquer branch se você estiver com o branch raiz ativado (no nosso caso branch main) sem ativá-lo antes.

# vá para o branch raiz
$ git checkout main

# use parâmetro -m para renomear qualquer branch
git branch -m nome_antigo nome_novo

Verificando o significado das ramificações

Na mesma pasta de trabalho, edite o arquivo README.md.

# Projeto de teste e aprendizado do Git
Consiste em testes de funcionamento do Git
## Esse linha foi inserida no novo_branch

Use git add e git commit para inserir a nova versão no repositório.

$ git add palindromo.py
$ git commit -m "versão destruída do código"

O código deve ser atualizado, para esse branch. Depois podemos voltar para o branch main:

$ git checkout main
Switched to branch 'main'

# verifique a situação dos branches
$ git branch
* main
  novo_branch

# verifique o conteúdo de README.md
$ cat README.md  
  # Projeto de teste e aprendizado do Git
  Consiste em testes de funcionamento do Git

O branch main está novamente selecionado. Abrindo novamente o arquivo README.md vemos que ele está agora em sua versão anterior, antes que a última linha tenha sido inserida.

Caso as alterações feitas no branch ‘novo_branch’ sejam aprovadas e você queira incorporá-las no projeto principal, use git merge:

# estando branch main ativo faça
$ git merge novo_branch

Resumo de comandos

Podemos ver uma lista de comandos do Git usando:
$ git --help
Esses são os comandos do Git mais usados:

Para iniciar nova área de trabalho
clone clona um repositório para novo directório
init cria repositório vazio ou reinicializa um existente
Para atuar sobre modificações atuais
add adiciona um arquivo na área de preparação (staging)
mv move ou renomeia um arquivo, diretória ou symlink
restore restaura árvore de arquivos de trabalho
rm remove arquivos da árvore de trabalho
Para examinar histórico e estado
bisect use busca binária para encontrar o commit que introduziu um erro
diff exibe alterações entre commits e na árvore de trabalho
grep imprime linhas que satisfazem um padrão
log exibe logs de commits
show exibe diversos tipos de objetos
status exibe o status da árvore de trabalho
Para acrescentar, marcar e alterar seu histórico
branch lista, cria ou apaga ramificações (branches)
commit grava alterações no repositório
merge faz a junção de dois ou mais históricos de desenvolvimento
rebase reaplica commits sobre outra base
reset reset HEAD atual para um estado especificado
switch alterna entre ramos (branches)
tag cria, lista, apaga ou verifica um objeto tag assinado com GPG
Atividades de colaboração
fetch download objetos e referências de outro repositório
pull download de outro repositório e integra com branch local
push atualiza referências remotas com objetos associados

Bibliografia

Livros

  • Ahmad, Jawwad & Belanger, Chris: Advanced Git, The Raywenderlich Tutorail Team, 2021.
  • Chacon, Scott e Straub, Ben: Pro Git, Second Edition, Apress, disponível em git-scm.
  • Santacroce, Ferdinando: Git Essentials, Packt, Mumbai, 2017.
  • Umali, Rick: Learn Git in a Month of Lunches, Manning, Nova Iorque, 2015.

Sites

todos visualizados em março de 2022.