Git (1/3): controle de versões local

Git (1/3): controle de versões local

Aviso: Este post foi traduzido para o português usando um modelo de tradução automática. Por favor, me avise se encontrar algum erro.

📚 **Esta entrada faz parte da série _Guia de Git_**, dividida em três capítulos que se leem em ordem:

> * 👉 **Parte 1: Controle de versões local**

* Parte 2: Ramos

* Parte 3: Repositórios remotos, stash e tags

Introduçãolink image 85

Git é um software de controle de versões criado por Linus Torvalds, que o criou para poder ter um bom controle de versões quando desenvolveu o kernel do Linux.

As áreas do gitlink image 86

O Git tem três áreas, embora também se possa considerar uma quarta.

git states
  • A primeira é nosso espaço de trabalho, nele é onde temos todo o nosso código. Aqui, quando modificamos ou criamos um arquivo, ele passa a ficar como não rastreado, por isso temos que passá-lo para a área de staged
  • A segunda área é a de staged. Aqui os arquivos que havíamos modificado ou criado e que não estavam *trackeados* passam a estar trackeados, ou seja, o Git passa a acompanhá-los. Aqui enviaremos os arquivos para a próxima área de head
  • A terceira área é a de head. Nela gravamos uma versão do nosso código. Dessa forma, ao gravar versões, podemos voltar a versões anteriores se necessário. A versão gravada do nosso código pode ser enviada a um servidor de maneira que fique acessível para várias pessoas
  • As três áreas anteriores correspondem ao trabalho local, mas há mais uma área, que é a de remote server. Aqui, o que fazemos é enviar a versão salva do nosso código para um servidor, de forma que tenhamos acesso ao código de qualquer lugar, ou que mais pessoas tenham acesso.

Para fazer uma analogia, é como um cenário em que você vai tirar uma foto. Primeiro você tem seus arquivos modificados, de forma que aqueles que quer imortalizar você envia para a área de staged, ou seja, para o cenário. No momento em que você enviou todos os arquivos que considera, você tira a foto, então envia todos os arquivos para a área de head. Dessa forma, você pode ir tirando muitas fotos, conforme o código vai evoluindo, de modo que você pode ter em um álbum de fotos a evolução do código. Por último, você pode enviar essa foto para um servidor para que fique acessível por mais pessoas, ou seja, você os envia para a área de remote server

Instalar gitlink image 87

Na maioria das distribuições Linux, o git já vem instalado, podemos verificá-lo executando git --version

	
< > Input
Python
!git --version
Copied
>_ Output
			
git version 2.25.1

Se você não o tiver ou quiser atualizar a versão do git, basta executar sudo apt update e, em seguida, sudo apt install git

	
< > Input
Python
!sudo apt update && sudo apt install git
Copied
>_ Output
			
[sudo] password for maximo.fernandez@AEROESPACIAL.SENER:

Voltamos a verificar a versão

	
< > Input
Python
!git --version
Copied
>_ Output
			
git version 2.25.1

No meu caso, eu já tinha a última versão

Configuração iniciallink image 88

Configuração do nome e do e-maillink image 89

Antes de começar a usar o git é conveniente que faças algumas configurações mínimas como o nome de usuário e o e-mail, esta informação é a que aparecerá na hora de mostrar quem fez alterações no código. Para fazer isto é preciso executar

git config --global user.name "<nome de usuário>"
git config --global user.email "<email>"

No meu caso, eu colocaria

git config --global user.name "MaximoFN"
git config --global user.email "maximofn@gmail.com

Como se pode ver, a flag --global o que faz é alterar a configuração global do git, mas se em um repositório específico você precisar definir outros dados, simplesmente navega até o repositório e remove a flag --global dos comandos anteriores

git config user.name "<nome de usuário>"
git config user.email "<email>"

Configurar o editor padrãolink image 90

Quando mais adiante explicarmos o que são os commits, veremos que em uma das opções pode ser aberto um navegador para nós. Por padrão o git tentará usar vim, mas como não é um editor muito simples de usar, podemos modificá-lo. A seguir mostra-se como fazê-lo com alguns editores comuns

git config --global core.editor "code"  # vscode como editor
git config --global core.editor "atom" # Atom como editor
git config --global core.editor "subl" # Sublime Text como editor
git config --global core.editor "nano" # Nano como editor

Verificar configuração de gitlink image 91

Para revisar a configuração do git podemos usar git config --list

	
< > Input
Python
!git config --list
Copied
>_ Output
			
user.name=maximofn
user.email=maximofn@gmail.com
user.user=maximofn
http.sslverify=true
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=https://github.com/maximofn/portafolio.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.main.remote=origin
branch.main.merge=refs/heads/main

Podemos usar os flags --global, --local e --system para ver apenas a configuração global, local (se existir) e de sistema (se existir)

	
< > Input
Python
!git config --global --list
Copied
>_ Output
			
user.name=maximofn
user.email=maximofn@gmail.com
user.user=maximofn
http.sslverify=true
	
< > Input
Python
!git config --local --list
Copied
>_ Output
			
core.repositoryformatversion=0
core.filemode=true
core.bare=false
core.logallrefupdates=true
remote.origin.url=https://github.com/maximofn/portafolio.git
remote.origin.fetch=+refs/heads/*:refs/remotes/origin/*
branch.main.remote=origin
branch.main.merge=refs/heads/main
	
< > Input
Python
!git config --system --list
Copied
>_ Output
			
fatal: unable to read config file '/etc/gitconfig': No such file or directory

No meu caso, não existe configuração de sistema

Se quiser saber apenas o valor de um parâmetro da configuração, bastaria introduzir git config <parameter>

	
< > Input
Python
!git config user.name
Copied
>_ Output
			
maximofn

Controle de versões de forma locallink image 92

Inicializar um novo repositório (git init)link image 93

Há duas maneiras de inicializar um novo repositório fazendo

  • Uma é fazendo git init . Isso criará uma nova pasta com o nome do repositório
  • Outra é navegando até a pasta onde queremos criar um repositório e executando git init

Vou criar um novo repositório

	
< > Input
Python
!git init notebook_git
Copied
>_ Output
			
Inicializado repositorio Git vacío en /home/wallabot/Documentos/web/portafolio/posts/notebook_git/.git/

Se agora fizermos ls, veremos que foi criada uma nova pasta chamada notebook_git

	
< > Input
Python
!ls | grep notebook_git
Copied
>_ Output
			
notebook_git

Nós nos mudamos para ela

	
< > Input
Python
!cd notebook_git
Copied

Agora, dentro da pasta, temos duas maneiras de saber que o repositório foi criado: uma é fazendo ls -a, que mostrará todos os arquivos, e veremos que há uma pasta chamada .git. A outra maneira é fazendo git status, que nos dirá o estado do repositório

	
< > Input
Python
!cd notebook_git && ls -a
Copied
>_ Output
			
. .. .git
	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
No hay commits todavía
no hay nada para confirmar (crea/copia archivos y usa "git add" para hacerles seguimiento)

Como estamos em um notebook, cada célula tem seu path no path do notebook, por isso as duas vezes tive que fazer cd notebook_git &&, para que mude para a pasta com o repositório que acabamos de criar.

Se agora eu executar git status em outro path onde um repositório não tenha sido inicializado, isso nos dará um erro

	
< > Input
Python
!cd ~/ && git status
Copied
>_ Output
			
fatal: no es un repositorio git (ni ninguno de los directorios superiores): .git

Criar novos arquivoslink image 94

No momento em que inicializamos um repositório, podemos começar a criar novos arquivos, então criamos um e vemos o que acontece

	
< > Input
Python
!cd notebook_git && echo "print('Hello World')" &gt; hello.py
Copied

Se agora fizermos novamente git status, veremos que nos aparece

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
No hay commits todavía
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
hello.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Como se pode ver, agora está nos dizendo que o arquivo hello.py não está sendo rastreado. Ou seja, precisamos adicionar hello.py à área de staged, que, lembremos, era como o cenário onde íamos colocar tudo aquilo que mais tarde iremos fotografar.

Desfazer a criação de um novo arquivolink image 95

Neste caso, como são arquivos que o git ainda não está rastreando, ou seja, que ainda não estão na área de staged, teríamos três maneiras de fazer isso

  • Apagando-o simplesmente: Como o git ainda não rastreia o arquivo, poderíamos fazer rm hello.py e pronto
  • Eliminando-o por meio de um comando do Git: Antes o apagamos com rm, mas é possível que você esteja em um sistema que não tenha o comando rm. Nesse caso, pode-se usar o comando do Git git rm hello.py* Por último, podemos usar git clean. Isso é útil, por exemplo, quando há muitos arquivos novos e, assim, em um único comando, eliminamos todos.

git cleanlink image 96

Se executarmos git clean sem argumentos, ele nos dará um erro

	
< > Input
Python
!cd notebook_git && git clean
Copied
>_ Output
			
fatal: clean.requireForce default en true y ninguno de -i, -n, ni -f entregado; rehusando el clean

Ele está nos dizendo que é necessário adicionar um destes flags -n, -i ou -f. Além disso, vamos ver o flag -d

  • -n (dry run): Nos dirá qué arquivos serão excluídos, mas não os excluirá
  • -i: Nos perguntará por cada arquivo que será apagado* -f: Forçará a exclusão dos arquivos
  • -d: Também apagará pastas

Vamos testar, primeiro fazemos git clean -n para saber quais arquivos seriam apagados

	
< > Input
Python
!cd notebook_git && git clean -n
Copied
>_ Output
			
Será borrado hello.py

Agora fazemos git clean -f para que o apague, já que estamos de acordo em que o apague

	
< > Input
Python
!cd notebook_git && git clean -f
Copied
>_ Output
			
Borrando hello.py

Como vemos, ele apagou hello.py

Adicionar um arquivo à área de staging (git add)link image 97

Voltamos a criar um arquivo

	
< > Input
Python
!cd notebook_git && echo "print('Hola mundo')" &gt; hola.py
Copied

Voltamos a fazer um git status para verificar que temos o arquivo

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
No hay commits todavía
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
hola.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Vemos que temos o arquivo hola.py, mas o git não está fazendo seu acompanhamento. Além disso, vemos que ele nos ajuda e nos diz use "git add" para fazê-los acompanhar

A sintaxe é a seguinte git add <arquivo>, mas podemos fazê-lo de várias maneiras

  • Se quisermos adicionar mais de um arquivo, podemos fazê-lo colocando todos os arquivos que queremos adicionar à área de staged, separados por um espaço: git add
  • Se quisermos adicionar todos os arquivos de um mesmo formato, por exemplo, se quisermos adicionar todos os arquivos de Python, seria git add *.py
  • Se quisermos adicionar todos os arquivos de uma pasta git add /
  • Se quisermos adicionar todos os arquivos, temos três maneiras: git add --all, git add -A ou git add .

Vamos adicionar o novo arquivo criado

	
< > Input
Python
!cd notebook_git && git add hola.py
Copied

Fazemos um git status para ver o que aconteceu

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: hola.py

Como vemos, ele nos diz que temos um novo arquivo ao qual está fazendo acompanhamento e que está pendente de ser confirmado hola.py

Remover um arquivo da área de staged (git reset)link image 98

No caso de adicionarmos um arquivo à área de staged e quisermos removê-lo, temos que usar git reset <arquivo>, vamos ver isso

Criamos e adicionamos à área de stage um novo arquivo

	
< > Input
Python
!cd notebook_git && echo "print('Este no')" &gt; adios.py && git add adios.py
Copied

Fazemos git status para verificar que está na área de stage

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: adios.py
nuevos archivos: hola.py

Como vemos, estão hola.py e adios.py, então usamos git reset adios.py para tirá-lo da área de staging

	
< > Input
Python
!cd notebook_git && git reset adios.py
Copied

Fazemos um git status para verificar que saiu

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: hola.py
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
adios.py

Podemos ver que adios.py já não tem acompanhamento por parte do git, ele o tirou da área de stage

Fazemos git clean -f para apagá-lo

	
< > Input
Python
!cd notebook_git && git clean -f && git status
Copied
>_ Output
			
Borrando adios.py
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: hola.py

Commit (git commit)link image 99

Se voltarmos ao símile em que dissemos que a área de staged era o cenário onde enviávamos os arquivos aos quais queríamos tirar a foto, agora é hora de tirar a foto para imortalizar o estado atual. Isso é fazer um commit

Dessa maneira, registra-se o estado atual do código; assim, com cada commit, terá-se um registro da evolução do código. Assim como com um álbum de fotos, com cada foto vamos tendo um registro da evolução do que colocamos no cenário.

Como na hora de fazer o commit a alteração do código está sendo registrada, o git não nos deixa fazer o commit se não fizermos um comentário mínimo. Portanto, há duas maneiras de fazer commit

  • git commit dessa forma abrirá o editor que tenhamos definido na configuração do git. Se não tivermos configurado um editor padrão, será aberto vi. Se quisermos alterar a configuração do editor, podemos fazer, por exemplo, git config --global core.editor "code" ou git config core.editor "code" para definir o VSCode como editor padrão de forma global ou local.
  • git commit -m "Mensagem de commit". Desta maneira, adicionamos a mensagem diretamente

Ao fazer o commit da primeira forma, podemos ter uma primeira linha que será o título do commit e várias linhas a mais onde se explica em mais detalhe. Se quisermos poder fazer isso com a flag -m, bastará adicionar várias flags -m seguidas: git commit -m "Título do commit" -m "Primeira linha explicando mais" -m "Segunda linha explicando mais"

Uma vez que fizemos o commit, isso guardará um registro da alteração do nosso repositório de forma local. Ainda não nos conectamos a um servidor remoto

Vamos testar fazer o commit

	
< > Input
Python
!cd notebook_git && git commit -m "Primer commit, hola.py"
Copied
>_ Output
			
[master (commit-raíz) 1c95e4f] Primer commit, hola.py
1 file changed, 1 insertion(+)
create mode 100644 hola.py

Fazemos um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
nada para hacer commit, el árbol de trabajo está limpio

Vemos que ele nos diz que não há nada de novo, temos todo o nosso repositório totalmente controlado

Commit ignorando add (git commit -a -m ou git commit -am)link image 100

No caso em que queiramos levar todos os arquivos que modificamos para a área de staged e depois fazer um commit, podemos fazer tudo isso em um único passo por meio de git commit -a -m "mensaje", git commit --all -m "mensaje" ou git commit -am "mensaje"

Nota: Isso só é válido se um arquivo for modificado. Se o arquivo for novo e o git não estiver a segui-lo, isso não é válido

Vamos ver um exemplo, vamos modificar hola.py

	
< > Input
Python
!cd notebook_git && echo "print('He añadido una nueva linea')" &gt;&gt; hola.py
Copied

Vamos fazer um git status para nos certificarmos

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios no rastreados para el commit:
(usa "git add &lt;archivo&gt;..." para actualizar lo que será confirmado)
(usa "git restore &lt;archivo&gt;..." para descartar los cambios en el directorio de trabajo)
modificados: hola.py
sin cambios agregados al commit (usa "git add" y/o "git commit -a")

Podemos ver que na própria ajuda do git já nos sugere usar git commit -a, então vamos fazê-lo

	
< > Input
Python
!cd notebook_git && git commit -am "Segundo commit, hola.py"
Copied
>_ Output
			
[master 6e99e73] Segundo commit, hola.py
1 file changed, 1 insertion(+)

Vamos fazer novamente um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
nada para hacer commit, el árbol de trabajo está limpio

Não há nada para fazer commit, a alteração já foi commitada

Modificar um arquivo ao qual já havia sido feito commitlink image 101

Como enquanto desenvolvemos estamos modificando arquivos, pode ser que em algum arquivo ao qual já tínhamos feito commit o modifiquemos. No nosso caso vamos adicionar uma linha a hola.py

	
< > Input
Python
!cd notebook_git && echo "print('He añadido una tercera linea')" &gt;&gt; hola.py
Copied
	
< > Input
Python
!cd notebook_git && cat hola.py
Copied
>_ Output
			
print('Hola mundo')
print('He añadido una nueva linea')
print('He añadido una tercera linea')

Se fizermos git status, veremos que hola.py tem modificações

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios no rastreados para el commit:
(usa "git add &lt;archivo&gt;..." para actualizar lo que será confirmado)
(usa "git restore &lt;archivo&gt;..." para descartar los cambios en el directorio de trabajo)
modificados: hola.py
sin cambios agregados al commit (usa "git add" y/o "git commit -a")

Ver alterações em um arquivo (git diff <arquivo>)link image 102

Pode ser que já estejamos há algum tempo desenvolvendo desde o último commit e não saibamos quais modificações fizemos; para isso usamos git diff <archivo> que nos dirá as mudanças que fizemos

	
< > Input
Python
!cd notebook_git && git diff hola.py
Copied
>_ Output
			
diff --git a/hola.py b/hola.py
index 91dee80..fba0d22 100644
--- a/hola.py
+++ b/hola.py
@@ -1,2 +1,3 @@
print('Hola mundo')
print('He añadido una nueva linea')
+print('He añadido una tercera linea')

Embora não seja muito intuitivo, podemos ver que adicionámos a última linha em hola.py

Desfazer modificações em um arquivo (git restore <arquivo>)link image 103

Se as alterações que fizemos não nos agradarem e quisermos removê-las, o que podemos fazer é git restore <arquivo>

	
< > Input
Python
!cd notebook_git && git restore hola.py
Copied

Vamos ver o que aconteceu com um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
nada para hacer commit, el árbol de trabajo está limpio

Vemos que as alterações em hola.py foram descartadas desde o último commit

Histórico de alterações (git log)link image 104

Com o git podemos ver o histórico de todas as alterações que fomos commitando, para isso usamos git log. É como se fôssemos revisar nosso álbum de fotos

	
< > Input
Python
!cd notebook_git && git log
Copied
>_ Output
			
commit 6e99e73cf0c5474078cc9f328ee6a54fb9ffb169 (HEAD -&gt; master)
Author: maximofn &lt;maximofn@gmail.com&gt;
Date: Sun Apr 16 02:29:04 2023 +0200
Segundo commit, hola.py
commit 1c95e4fd8388ceedee368e0121c4b0ef4900c2ac
Author: maximofn &lt;maximofn@gmail.com&gt;
Date: Sun Apr 16 02:28:44 2023 +0200
Primer commit, hola.py

Podemos ver o histórico de alterações; é preciso lê-lo de baixo para cima.

Primeiro vemos o commit com a mensagem Primer commit, hola.py, podemos ver a data, o autor e o hash, que é seu identificador único

A seguir, vemos o segundo commit com a mensagem Segundo commit, hola.py, com sua data, autor e hash. Além disso, ele nos mostra onde está o HEAD e em qual ramo estamos

Se usarmos flags, podemos obter a informação de diferentes maneiras, mas, dependendo de quais flags usemos, uma opção pode ser mais conveniente. A seguir, são mostradas algumas flags úteis:

  • git log --oneline: Mostra os commits em uma única linha, com o hash abreviado e a mensagem do commit.
  • git log --graph: Mostra um gráfico de texto do histórico do repositório, incluindo ramificações e fusões.
  • git log --decorate: Mostra as referências (branches, tags, HEAD, etc.) no log junto com o commit ao qual apontam.
  • git log --author="": Filtra o histórico de commits para mostrar apenas aqueles realizados por um autor específico.
  • git log --since="": Mostra os commits realizados desde uma data específica. Você pode usar diferentes formatos de data, como "1 week ago" ou "2023-01-01".
  • git log --until="": Mostra os commits realizados até uma data específica.
  • git log : Mostra os commits de um ramo específico.* git log ..: Mostra os commits que estão no intervalo entre dois commits específicos.
  • git log --grep="": Busca nas mensagens de commit por uma palavra ou frase específica.
  • git log -p: Mostra as diferenças (na forma de patch) introduzidas em cada commit.
  • git log -n : Mostra os últimos números de commits. Por exemplo, git log -n 5 mostrará os últimos 5 commits.
  • git log --stat: Mostra as estatísticas de alterações em arquivos para cada commit, como o número de linhas adicionadas e removidas.

Por exemplo, uma maneira confortável de ver o histórico é usar git log --graph --oneline --decorate

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 6e99e73 (HEAD -&gt; master) Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Podemos ver que em vez de nos dar o hash inteiro, nos dá apenas alguns números; isso acontece porque, por enquanto, o repositório tem tão pouca história que com esses poucos números é suficiente. Se quiséssemos voltar ao ponto anterior, em vez de introduzir o hash inteiro (7c448f69e30ab1b5783f5cf9ee3ae5bc362ecd4d), bastaria introduzir apenas 7c448f6.

Mais adiante falaremos sobre os branches, mas agora vamos ver o que é o HEAD

CABEÇALHOlink image 105

Enquanto desenvolvíamos, conseguimos fazer alterações e commitá-las, ou seja, fomos preenchendo o álbum de fotos do nosso código. HEAD é a posição no álbum em que estamos.

Normalmente é a última posição de todos os commits.

Se queremos saber em que ponto estamos, podemos fazer isso com git rev-parse HEAD

	
< > Input
Python
!cd notebook_git && git rev-parse HEAD
Copied
>_ Output
			
6e99e73cf0c5474078cc9f328ee6a54fb9ffb169

Como se pode ver, o hash obtido coincide com o último obtido ao executar git log

	
< > Input
Python
!cd notebook_git && git log
Copied
>_ Output
			
commit 6e99e73cf0c5474078cc9f328ee6a54fb9ffb169 (HEAD -&gt; master)
Author: maximofn &lt;maximofn@gmail.com&gt;
Date: Sun Apr 16 02:29:04 2023 +0200
Segundo commit, hola.py
commit 1c95e4fd8388ceedee368e0121c4b0ef4900c2ac
Author: maximofn &lt;maximofn@gmail.com&gt;
Date: Sun Apr 16 02:28:44 2023 +0200
Primer commit, hola.py

Modificar um commit (git commit --amend)link image 106

Talvez queiramos modificar um commit, seja porque queremos alterar a mensagem, seja porque queremos adicionar mais arquivos ao commit, de modo que veremos os dois casos

Modificar a mensagem de commitlink image 107

Se apenas quiser modificar a mensagem, o que temos que fazer é git commit --amend -m "Nueva mensagem", vejamos um exemplo, vamos a modificar hola.py

	
< > Input
Python
!cd notebook_git && echo "print('Esta es la tercera linea')" &gt;&gt; hola.py
Copied

Fazemos um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios no rastreados para el commit:
(usa "git add &lt;archivo&gt;..." para actualizar lo que será confirmado)
(usa "git restore &lt;archivo&gt;..." para descartar los cambios en el directorio de trabajo)
modificados: hola.py
sin cambios agregados al commit (usa "git add" y/o "git commit -a")

De fato, vemos que hola.py tem modificações, de modo que fazemos um commit com essas modificações

	
< > Input
Python
!cd notebook_git && git commit -am "Tercer commot, hola.py"
Copied
>_ Output
			
[master 60e2ffd] Tercer commot, hola.py
1 file changed, 1 insertion(+)

Vamos ver o histórico de commits

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 60e2ffd (HEAD -&gt; master) Tercer commot, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

**Oh não!** escrevemos commot em vez de commit, então vamos modificar a mensagem

	
< > Input
Python
!cd notebook_git && git commit --amend -m "Tercer commit, hola.py"
Copied
>_ Output
			
[master c4930d7] Tercer commit, hola.py
Date: Sun Apr 16 02:29:59 2023 +0200
1 file changed, 1 insertion(+)

Vamos ver o histórico

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* c4930d7 (HEAD -&gt; master) Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Vemos que agora está bem

Adicionar arquivos ao último commitlink image 108

Suponha que tenhamos esquecido de adicionar um arquivo ao último commit; simplesmente fazemos um git add com esse arquivo e fazemos git commit --amend -m "mensaje"

Vamos criar dois novos arquivos

	
< > Input
Python
!cd notebook_git && echo "print('Este es el archivo 1')" &gt; archivo1.py
Copied
	
< > Input
Python
!cd notebook_git && echo "print('Este es el archivo 2')" &gt; archivo2.py
Copied

Agora fazemos commit apenas de um.

	
< > Input
Python
!cd notebook_git && git add archivo1.py && git commit -m "Commit con el archivo 1"
Copied
>_ Output
			
[master 285b243] Commit con el archivo 1
1 file changed, 1 insertion(+)
create mode 100644 archivo1.py
	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
archivo2.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 285b243 (HEAD -&gt; master) Commit con el archivo 1
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Como vemos, deixámos o ficheiro 2, de modo que modificamos o commit e adicionámos o ficheiro 2

	
< > Input
Python
!cd notebook_git && git add archivo2.py
Copied
	
< > Input
Python
!cd notebook_git && git commit --amend -m "Commit con los archivos 1 y 2"
Copied
>_ Output
			
[master 04ebd1f] Commit con los archivos 1 y 2
Date: Sun Apr 16 02:30:26 2023 +0200
2 files changed, 2 insertions(+)
create mode 100644 archivo1.py
create mode 100644 archivo2.py
	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
nada para hacer commit, el árbol de trabajo está limpio
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 04ebd1f (HEAD -&gt; master) Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Agora o último commit tem os dois novos arquivos

Desfazer um commit (git reset HEAD~1)link image 109

Com este comando dizemos ao git que retroceda uma posição no histórico de commits. Há duas opções --soft, que não apagarão as alterações que tenhamos feito, e --hard, que sim o fará.

Desfazer um commit mantendo as alterações (git reset --soft HEAD~1)link image 110

Vamos criar um novo arquivo

	
< > Input
Python
!cd notebook_git && echo "print('Este es el archivo 3')" &gt; archivo3.py
Copied

Fazemos um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
archivo3.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Fazemos um commit adicionando este arquivo

	
< > Input
Python
!cd notebook_git && git add archivo3.py && git commit -m "Commit con el archivos 3"
Copied
>_ Output
			
[master 6dc7be6] Commit con el archivos 3
1 file changed, 1 insertion(+)
create mode 100644 archivo3.py
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 6dc7be6 (HEAD -&gt; master) Commit con el archivos 3
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Vemos que no último commit está archivo3.py, vamos eliminar o commit mantendo archivo3.py

	
< > Input
Python
!cd notebook_git && git reset --soft HEAD~1
Copied

Fazemos agora um git log para ver se o último commit foi eliminado

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 04ebd1f (HEAD -&gt; master) Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

De fato, vemos que o último commit foi removido.

Fazemos um git status para ver se archivo3.py foi preservado

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: archivo3.py

Foi mantido

Desfazer um commit descartando as alterações (git reset --hard HEAD~1)link image 111

Temos archivo3.py que criámos e o temos na área de stage

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: archivo3.py

Portanto, fazemos um commit

	
< > Input
Python
!cd notebook_git && git commit -m "Commit con el archivo 3"
Copied
>_ Output
			
[master 0147d65] Commit con el archivo 3
1 file changed, 1 insertion(+)
create mode 100644 archivo3.py

Fazemos um git log para verificar que há um commit com este arquivo

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 0147d65 (HEAD -&gt; master) Commit con el archivo 3
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

De fato, há um commit adicionando arquivo3.py. Agora removemos esse commit descartando arquivo3.py

	
< > Input
Python
!cd notebook_git && git reset --hard HEAD~1
Copied
>_ Output
			
HEAD está ahora en 04ebd1f Commit con los archivos 1 y 2

Fazemos um git log para verificar que o último commit foi eliminado

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 04ebd1f (HEAD -&gt; master) Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

O commit com arquivo3.py foi eliminado, agora fazemos um git status para verificar o que aconteceu com arquivo3.py

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
nada para hacer commit, el árbol de trabajo está limpio

Não aparece archivo3.py como um arquivo que precise ser commitado, vamos ver se realmente foi eliminado completamente

	
< > Input
Python
!cd notebook_git && ls | grep archivo3
Copied

De fato, archivo3.py foi removido do sistema de arquivos

Modificar um commit remoto (git push --force)link image 112

Embora mais adiante veremos como sincronizar-nos com repositórios remotos, no caso de que tenhas feito um commit, o tenhas enviado para um repositório remoto (git push) e tenhas modificado o commit localmente (porque modificaste a mensagem ou desfizeste o commit), para reverter as alterações no repositório remoto tens de fazer git push --force

**Cuidado**: Este comando modifica o histórico do repositório remoto, por isso pode afetar o resto das pessoas que estejam trabalhando com esse repositório, então use este comando com muito cuidado e segurança. Vale mais a pena ter um histórico de commits, no qual primeiro está o commit em que você colocou a descrição errada e depois o novo commit com a nova descrição corretamente definida, do que ficar modificando o histórico.

Modificar um commit remoto (git push --force-with-lease)link image 113

Se você está convencido de alterar o histórico, pelo menos use git push --force-with-lease, que não modificará commits que tenham sido feitos posteriormente

Ignorar arquivos (.gitignore)link image 114

Suponha que temos um arquivo com API keys, esse arquivo na verdade não queremos que seja salvo no repositório, porque se depois compartilharmos esse repositório, qualquer pessoa teria acesso a essas chaves, por isso é preciso dizer ao git para não fazer o acompanhamento desse arquivo

Isto é feito com o arquivo .gitignore; nele, adiciona-se o caminho dos arquivos ou diretórios que não queremos que o Git acompanhe.

Vamos vê-lo

Criamos o arquivo com as chaves

	
< > Input
Python
!cd notebook_git && touch api_keys.py
Copied

Se fizermos git status, vemos que o Git o contempla

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
api_keys.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Se não fizermos nada, pode ser que um dia façamos um git add . e o incluamos no repositório, então, por segurança, precisamos dizer ao git que não siga este arquivo; para isso, o que fazemos é criar o .gitignore adicionando este arquivo

	
< > Input
Python
!cd notebook_git && echo "api_keys.py" &gt;&gt; .gitignore
Copied

Vejamos o que acontece se agora fizermos git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
.gitignore
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Vemos que o git deixou de levar em conta api_keys.py, mas leva em conta .gitignore, então fazemos um commit para adicionar .gitignore

	
< > Input
Python
!cd notebook_git && git add .gitignore && git commit -m "Añadido .gitignore"
Copied
>_ Output
			
[master 0b09cfa] Añadido .gitignore
1 file changed, 1 insertion(+)
create mode 100644 .gitignore

Quais arquivos adicionar ao .gitignore?link image 115

  • Arquivos que tenham credenciais ou chaves de API (você não deveria enviá-las ao repositório, simplesmente injetá-las por variáveis de ambiente)
  • Pastas de configuração do seu editor (/.vscode)
  • Arquivos de registro (log files)
  • Arquivos de sistema como .DS_Store* Pastas geradas com arquivos estáticos ou compilações como /dist ou /build
  • Dependências que podem ser baixadas (/node_modules)
  • Cobertura de testes (/coverage)

Como ignorar sempre os mesmos arquivos?link image 116

Se, por exemplo, o seu IDE sempre gera os mesmos arquivos de configuração, seria bom poder dizer ao git que sempre ignore esses arquivos; para isso criamos um .gitignore global

	
< > Input
Python
!touch ~/.gitignore_global
Copied

No meu caso, vou adicionar o diretório __pycache__/

	
< > Input
Python
!echo "__pycache__/" &gt;&gt; ~/.gitignore_global
Copied

Agora é preciso indicar ao Git que esse é o nosso .gitignore global

	
< > Input
Python
!git config --global core.excludesfile ~/.gitignore_global
Copied

Pronto, a partir de agora o diretório __pycache__/ sempre será ignorado

GitHub tem um repositório com .gitignores para muitas linguagens, eu me guiei por este para Python

Remover um arquivo de um commitlink image 117

Vamos ver como eliminar um arquivo de um commit que fizemos. Primeiro criamos dois arquivos e fazemos commit deles

	
< > Input
Python
!cd notebook_git && echo "print('Este es el archivo 4')" &gt; archivo4.py
Copied
	
< > Input
Python
!cd notebook_git && echo "print('Este es el archivo 5')" &gt; archivo5.py
Copied

Fazemos um commit com os dois arquivos

	
< > Input
Python
!cd notebook_git && git add archivo4.py archivo5.py && git commit -m "Commit con los archivos 4 y 5"
Copied
>_ Output
			
[master e3153a5] Commit con los archivos 4 y 5
2 files changed, 2 insertions(+)
create mode 100644 archivo4.py
create mode 100644 archivo5.py
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* e3153a5 (HEAD -&gt; master) Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

A partir daqui, há duas opções para eliminar um arquivo de um commit:

  • Excluir o arquivo e criar um novo commit* Desfazer o commit e criá-lo novamente sem o arquivo

Remover o arquivo e criar um novo commitlink image 118

Suponha que queremos eliminar o arquivo archivo5.py, então o excluímos com git rm archivo5.py

	
< > Input
Python
!cd notebook_git && git rm archivo5.py
Copied
>_ Output
			
rm 'archivo5.py'

Vamos fazer um git status para ver o que acontece

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged &lt;archivo&gt;..." para sacar del área de stage)
borrados: archivo5.py

Como vemos, arquivo5.py foi apagado. Agora criamos um novo commit

	
< > Input
Python
!cd notebook_git && git commit -m "Eliminado archivo5.py"
Copied
>_ Output
			
[master ea615a9] Eliminado archivo5.py
1 file changed, 1 deletion(-)
delete mode 100644 archivo5.py
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* ea615a9 (HEAD -&gt; master) Eliminado archivo5.py
* e3153a5 Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Desfazer o commit e criá-lo novamente sem o arquivolink image 119

Voltamos a criar dois arquivos e fazer um commit

	
< > Input
Python
!cd notebook_git && echo "print('Este es el archivo 6')" &gt; archivo6.py && echo "print('Este es el archivo 7')" &gt; archivo7.py
Copied
	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
archivo6.py
archivo7.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)
	
< > Input
Python
!cd notebook_git && git add archivo6.py archivo7.py && git commit -m "Commit con los archivos 6 y 7"
Copied
>_ Output
			
[master d6dc485] Commit con los archivos 6 y 7
2 files changed, 2 insertions(+)
create mode 100644 archivo6.py
create mode 100644 archivo7.py
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* d6dc485 (HEAD -&gt; master) Commit con los archivos 6 y 7
* ea615a9 Eliminado archivo5.py
* e3153a5 Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Primeiro desfazemos o último commit com git reset --soft HEAD~1

	
< > Input
Python
!cd notebook_git && git reset --soft HEAD~1
Copied

Fazemos um git status para ver o que aconteceu

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: archivo6.py
nuevos archivos: archivo7.py

Vemos que desfiz o commit, mas que os dois arquivos estão na área de staged, então para tirar do commit um dos arquivos, primeiro é preciso tirá-lo da área de staged; para isso fazemos git reset archivo6.py

	
< > Input
Python
!cd notebook_git && git reset archivo6.py
Copied

Voltamos a fazer um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: archivo7.py
Archivos sin seguimiento:
(usa "git add &lt;archivo&gt;..." para incluirlo a lo que se será confirmado)
archivo6.py

Vemos que arquivo7.py está na área de staged, enquanto arquivo6.py já não está. Agora podemos apagar o arquivo 6; para isso usamos git clean

	
< > Input
Python
!cd notebook_git && git clean -n
Copied
>_ Output
			
Será borrado archivo6.py
	
< > Input
Python
!cd notebook_git && git clean -f
Copied
>_ Output
			
Borrando archivo6.py

Vamos executar novamente um git status

	
< > Input
Python
!cd notebook_git && git status
Copied
>_ Output
			
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged &lt;archivo&gt;..." para sacar del área de stage)
nuevos archivos: archivo7.py

Como vemos archivo.py já não está, pelo que podemos fazer um novo commit

	
< > Input
Python
!cd notebook_git && git commit -m "Commit con el archivo 7"
Copied
>_ Output
			
[master 4bb9d75] Commit con el archivo 7
1 file changed, 1 insertion(+)
create mode 100644 archivo7.py
	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 4bb9d75 (HEAD -&gt; master) Commit con el archivo 7
* ea615a9 Eliminado archivo5.py
* e3153a5 Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Removemos o último commit e o sobrescrevemos com um novo, eliminando o arquivo que queríamos

Histórico de alterações de um arquivo (git log <arquivo>)link image 120

Embora antes tenhamos visto como podíamos ver o histórico do repositório com git log, pode ser que não nos interesse o histórico de todo o repositório. Pode ser que tenhamos um bug em um arquivo de código que no início não tínhamos, por isso é possível que queiramos ver apenas o histórico desse arquivo; para isso usamos git log <arquivo>

Primeiro, vemos os arquivos que temos

	
< > Input
Python
!cd notebook_git && ls
Copied
>_ Output
			
api_keys.py archivo1.py archivo2.py archivo4.py archivo7.py hola.py

Suponhamos que só queremos ver as mudanças em hola.py, então fazemos git log hola.py

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate hola.py
Copied
>_ Output
			
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Podemos ver que aparecem muitos menos resultados do que se tivéssemos feito git log

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 4bb9d75 (HEAD -&gt; master) Commit con el archivo 7
* ea615a9 Eliminado archivo5.py
* e3153a5 Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Ver modificações de um arquivo em um ponto específico do histórico (git show <hash> <arquivo> ou git diff <arquivo>)link image 121

Suponhamos que já sabemos em que ponto foi feita uma mudança no arquivo que contém um bug, então agora queremos saber quais mudanças foram realizadas para saber o que pode estar causando o bug; para isso podemos usar git show <hash> <archivo>

Vamos ver quais mudanças ocorreram em hola.py no hash c4930d7, ou seja, quando foi feito o terceiro commit

	
< > Input
Python
!cd notebook_git && git show c4930d7 hola.py
Copied
>_ Output
			
commit c4930d7267c3f8df389ab0cb1bda0b5fceabb5c2
Author: maximofn &lt;maximofn@gmail.com&gt;
Date: Sun Apr 16 02:29:59 2023 +0200
Tercer commit, hola.py
diff --git a/hola.py b/hola.py
index 91dee80..33bdb99 100644
--- a/hola.py
+++ b/hola.py
@@ -1,2 +1,3 @@
print('Hola mundo')
print('He añadido una nueva linea')
+print('Esta es la tercera linea')

A maneira de ver as mudanças no git não é muito intuitiva, mas podemos ver que foi adicionada a linha print('Esta es la tercera línea')

Outra maneira de ver alterações é com git diff, temos duas opções, podemos ver as alterações do ficheiro no momento atual com um ponto concreto do histórico, para isso fazemos git diff <hash> <arquivo.

Por exemplo, se quisermos ver as mudanças de hola.py desde o primeiro commit (hash 1c95e4f) até a situação atual, devemos introduzir (git diff 1c95e4f hola.py)

	
< > Input
Python
!cd notebook_git && git diff 1c95e4f hola.py
Copied
>_ Output
			
diff --git a/hola.py b/hola.py
index f140969..33bdb99 100644
--- a/hola.py
+++ b/hola.py
@@ -1 +1,3 @@
print('Hola mundo')
+print('He añadido una nueva linea')
+print('Esta es la tercera linea')

Mas se o que queremos é ver a diferença entre um ponto concreto do histórico e outro ponto concreto, é preciso introduzir os hashes dos dois momentos, isto é git diff <hash1> <hash2> <archivo>

Se queremos ver as mudanças de hola.py entre o segundo commit (hash 6e99e73) e o primeiro commit (hash 1c95e4f) teríamos que introduzir git diff 1c95e4f 6e99e73 hola.py

	
< > Input
Python
!cd notebook_git && git diff 1c95e4f 6e99e73 hola.py
Copied
>_ Output
			
diff --git a/hola.py b/hola.py
index f140969..91dee80 100644
--- a/hola.py
+++ b/hola.py
@@ -1 +1,2 @@
print('Hola mundo')
+print('He añadido una nueva linea')

O anterior nos mostra as mudanças do segundo commit em relação ao primeiro, mas se o que queremos são as mudanças do primeiro commit em relação ao segundo, basta colocar os hashes na ordem inversa de como os colocamos, ou seja git diff 6e99e73 1c95e4f hola.py

	
< > Input
Python
!cd notebook_git && git diff 6e99e73 1c95e4f hola.py
Copied
>_ Output
			
diff --git a/hola.py b/hola.py
index 91dee80..f140969 100644
--- a/hola.py
+++ b/hola.py
@@ -1,2 +1 @@
print('Hola mundo')
-print('He añadido una nueva linea')

Viagem ao passado (git reset --hard <hash> ou git reset --soft <hash>)link image 122

Imaginemos que encontramos que todo lo que hicimos depois de gerar o bug não serve e temos que voltar a trabalhar desde ese ponto, podemos voltar a uma posição do histórico mediante git reset --hard <hash> (isto não manterá as alterações) ou git reset --soft <hash> (isto sim manterá as alterações)

Primeiro, vamos ver o histórico

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 4bb9d75 (HEAD -&gt; master) Commit con el archivo 7
* ea615a9 Eliminado archivo5.py
* e3153a5 Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Suponhamos que queremos ir ao momento em que fizemos o terceiro commit (hash c4930d7), além disso, fazemos isso sem manter as alterações, ou seja, todas as modificações que fizemos depois serão apagadas, fazemos git reset --hard c4930d7

Primeiro fazemos ls para ver os arquivos que temos agora

	
< > Input
Python
!cd notebook_git && ls
Copied
>_ Output
			
api_keys.py archivo1.py archivo2.py archivo4.py archivo7.py hola.py

Vamos para o terceiro commit

	
< > Input
Python
!cd notebook_git && git reset --hard c4930d7
Copied
>_ Output
			
HEAD está ahora en c4930d7 Tercer commit, hola.py

Se fizermos ls veremos que já não temos nem archivo1.py, nem archivo2.py, nem archivo4.py, nem archivo7.py

	
< > Input
Python
!cd notebook_git && ls
Copied
>_ Output
			
api_keys.py hola.py

De volta ao futuro (git reflog)link image 123

Suponhamos que nos arrependemos e queremos voltar ao ponto em que estávamos, ao último ponto no histórico, uma maneira seria fazer novamente git reset --hard <hash>. Mas imaginemos que não sabemos o hash, porque não fizemos git log antes e, se fizermos agora, ele só nos dará informação do histórico até o terceiro commit

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* c4930d7 (HEAD -&gt; master) Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Aqui o que podemos fazer é git reflog, que nos dará um histórico incluindo os saltos

	
< > Input
Python
!cd notebook_git && git reflog
Copied
>_ Output
			
c4930d7 (HEAD -&gt; master) HEAD@{0}: reset: moving to c4930d7
4bb9d75 HEAD@{1}: commit: Commit con el archivo 7
ea615a9 HEAD@{2}: reset: moving to HEAD~1
d6dc485 HEAD@{3}: commit: Commit con los archivos 6 y 7
ea615a9 HEAD@{4}: commit: Eliminado archivo5.py
e3153a5 HEAD@{5}: commit: Commit con los archivos 4 y 5
0b09cfa HEAD@{6}: commit: Añadido .gitignore
04ebd1f HEAD@{7}: reset: moving to HEAD~1
0147d65 HEAD@{8}: commit: Commit con el archivo 3
04ebd1f HEAD@{9}: reset: moving to HEAD~1
6dc7be6 HEAD@{10}: commit: Commit con el archivos 3
04ebd1f HEAD@{11}: commit (amend): Commit con los archivos 1 y 2
285b243 HEAD@{12}: commit: Commit con el archivo 1
c4930d7 (HEAD -&gt; master) HEAD@{13}: commit (amend): Tercer commit, hola.py
60e2ffd HEAD@{14}: commit: Tercer commot, hola.py
6e99e73 HEAD@{15}: commit: Segundo commit, hola.py
1c95e4f HEAD@{16}: commit (initial): Primer commit, hola.py

Podemos ver que nos dice que estávamos no commit com hash 4bb9d75, isto é, o último commit que fizemos, e daí fomos até o commit com hash c4930d7, que, se você reparar, é o mesmo hash que o commit com a mensagem Tercer commit, hola.py. Portanto, já sabemos o hash do último commit, 4bb9d75, então para voltar à posição do último commit fazemos git reset --hard 4bb9d75

	
< > Input
Python
!cd notebook_git && git reset --hard 4bb9d75
Copied
>_ Output
			
HEAD está ahora en 4bb9d75 Commit con el archivo 7

Se agora voltarmos a fazer um log

	
< > Input
Python
!cd notebook_git && git log --graph --oneline --decorate
Copied
>_ Output
			
* 4bb9d75 (HEAD -&gt; master) Commit con el archivo 7
* ea615a9 Eliminado archivo5.py
* e3153a5 Commit con los archivos 4 y 5
* 0b09cfa Añadido .gitignore
* 04ebd1f Commit con los archivos 1 y 2
* c4930d7 Tercer commit, hola.py
* 6e99e73 Segundo commit, hola.py
* 1c95e4f Primer commit, hola.py

Vemos que, de fato, estamos na posição do último commit, *voltamos ao futuro*

Busca em arquivos (git grep <palavra>)link image 124

Se quisermos procurar em ficheiros, podemos fazê-lo com o comando git grep. Como o repositório que temos feito é muito pequeno e tem muito poucos ficheiros, vamos descarregar um novo através de um comando que veremos mais adiante em detalhe

	
< > Input
Python
!git clone https://github.com/facebookresearch/segment-anything.git
Copied
>_ Output
			
Clonando en 'segment-anything'...
remote: Enumerating objects: 279, done.
remote: Counting objects: 100% (181/181), done.
remote: Compressing objects: 100% (77/77), done.
remote: Total 279 (delta 116), reused 104 (delta 104), pack-reused 98
Recibiendo objetos: 100% (279/279), 18.31 MiB | 21.25 MiB/s, listo.
Resolviendo deltas: 100% (140/140), listo.

O repositório que baixamos é o do código-fonte do SAM, uma rede neural da Meta para segmentar qualquer objeto. Entramos na pasta do repositório e buscamos, por exemplo, quantas vezes a palavra softmax foi escrita

	
< > Input
Python
!cd segment-anything && git grep softmax
Copied
>_ Output
			
segment_anything/modeling/image_encoder.py: attn = attn.softmax(dim=-1)
segment_anything/modeling/transformer.py: attn = torch.softmax(attn, dim=-1)

Vemos que foi escrito nos arquivos segment_anything/modeling/image_encoder.py e segment_anything/modeling/transformer.py.

Se agora também queremos saber em quais linhas dos arquivos foi escrito, usamos o flag -n

	
< > Input
Python
!cd segment-anything && git grep -n softmax
Copied
>_ Output
			
segment_anything/modeling/image_encoder.py:236: attn = attn.softmax(dim=-1)
segment_anything/modeling/transformer.py:233: attn = torch.softmax(attn, dim=-1)

Se o que queremos é contar quantas vezes a palavra aparece, podemos usar a flag -c

	
< > Input
Python
!cd segment-anything && git grep -c softmax
Copied
>_ Output
			
segment_anything/modeling/image_encoder.py:1
segment_anything/modeling/transformer.py:1

E vemos que aparece uma vez em cada arquivo

E nos diz que estão nas linhas 236 e 233, respectivamente

Busca em commits (git log -S <palavra>)link image 125

Se o que queremos é buscar no histórico de commits, podemos usar o comando git log -S <palabra>. Por exemplo, vamos buscar no histórico de commits do repositório que baixamos antes a palavra fix

	
< > Input
Python
!cd segment-anything && git log -S "collab"
Copied
>_ Output
			
commit 2780a301de4483e5c46edb230ea781556159c658
Author: Eric Mintun &lt;eric.mintun@gmail.com&gt;
Date: Mon Apr 10 10:50:17 2023 -0700
Fix typo in notebook 'using_collab'-&gt;'using_colab' in other two notebooks.
commit 2c11ea23525970ac288f23dc74b203bcbfb4cc6a
Author: jp-x-g &lt;jpxg-dev@protonmail.com&gt;
Date: Thu Apr 6 20:00:04 2023 -0700
fix parameter name
"using_collab" does not appear in subsequent text, replacing with "using_colab"
commit b47d02d68c308672751be29742fcef02a86e2f02
Author: Eric Mintun &lt;eric.mintun@gmail.com&gt;
Date: Wed Apr 5 06:13:09 2023 -0700
Fix broken links in notebook Colab setup.
commit 571794162e0887c15d12b809505b902c7bf8b4db
Author: Eric Mintun &lt;eric.mintun@gmail.com&gt;
Date: Tue Apr 4 22:25:49 2023 -0700
Initial commit

Apagamos a pasta de SAM

	
< > Input
Python
!rm -r segment-anything
Copied

---

➡️ **Continue na Parte 2: ramas**, onde aprenderás a trabalhar com várias linhas de desenvolvimento em paralelo.

Posts relacionados

Perguntas frequentes

Erro "fatal: clean.requireForce" ao rodar git clean sem flags — o que significam -n, -i, -f e -d?

Rodar git clean sem nenhuma flag dá erro porque o Git exige, por segurança, que você indique uma flag: -n (dry run) mostra quais arquivos seriam removidos sem apagar nada, -i pergunta arquivo por arquivo, -f força a remoção de fato e -d estende a limpeza também para diretórios não rastreados, além dos arquivos. O fluxo seguro é rodar primeiro git clean -n para revisar a lista e depois git clean -f (ou git clean -df se houver pastas) para executar a remoção.

Depois de um git reset --hard <hash> para "viajar no tempo", como volto para o último commit se não lembro o hash dele?

Use git reflog, que, diferente do git log, também registra os movimentos do HEAD (incluindo resets), não só os commits alcançáveis a partir da posição atual. Ele mostra o hash em que você estava antes do salto (no exemplo do post, 4bb9d75), então basta rodar git reset --hard 4bb9d75 para voltar exatamente a esse ponto.

Continuar lendo

Últimos posts -->

Você viu esses projetos?

Gymnasia

Gymnasia Gymnasia
React Native
Expo
TypeScript
FastAPI
Next.js
OpenAI
Anthropic

Aplicativo móvel de treino pessoal com assistente de IA, biblioteca de exercícios, acompanhamento de rotinas, dieta e medidas corporais

Horeca chatbot

Horeca chatbot Horeca chatbot
Python
LangChain
PostgreSQL
PGVector
React
Kubernetes
Docker
GitHub Actions

Chatbot conversacional para cozinheiros de hotéis e restaurantes. Um cozinheiro, gerente de cozinha ou serviço de quarto de um hotel ou restaurante pode falar com o chatbot para obter informações sobre receitas e menus. Mas também implementa agentes, com os quais pode editar ou criar novas receitas ou menus

Naviground

Naviground Naviground
Ver todos os projetos -->
>_ Disponível para projetos

Tem um projeto com IA?

Vamos conversar.

maximofn@gmail.com

Especialista em Machine Learning e Inteligência Artificial. Desenvolvo soluções com IA generativa, agentes inteligentes e modelos personalizados.

Quer assistir alguma palestra?

Últimas palestras -->

Quer melhorar com essas dicas?

Últimos tips -->

Use isso localmente

Os espaços do Hugging Face nos permitem executar modelos com demos muito simples, mas e se a demo quebrar? Ou se o usuário a deletar? Por isso, criei contêineres docker com alguns espaços interessantes, para poder usá-los localmente, aconteça o que acontecer. Na verdade, se você clicar em qualquer botão de visualização de projeto, ele pode levá-lo a um espaço que não funciona.

Flow edit

Flow edit Flow edit

Edite imagens com este modelo de Flow. Baseado em SD3 ou FLUX, você pode editar qualquer imagem e gerar novas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos os contêineres -->
>_ Disponível para projetos

Tem um projeto com IA?

Vamos conversar.

maximofn@gmail.com

Especialista em Machine Learning e Inteligência Artificial. Desenvolvo soluções com IA generativa, agentes inteligentes e modelos personalizados.

Você quer treinar seu modelo com esses datasets?

short-jokes-dataset

HuggingFace

Dataset com piadas em inglês

Uso: Fine-tuning de modelos de geração de texto humorístico

231K linhas 2 colunas 45 MB
Ver no HuggingFace →

opus100

HuggingFace

Dataset com traduções de inglês para espanhol

Uso: Treinamento de modelos de tradução inglês-espanhol

1M linhas 2 colunas 210 MB
Ver no HuggingFace →

netflix_titles

HuggingFace

Dataset com filmes e séries da Netflix

Uso: Análise de catálogo Netflix e sistemas de recomendação

8.8K linhas 12 colunas 3.5 MB
Ver no HuggingFace →
Ver mais datasets -->