Git (1/3): control de versiones en local

Git (1/3): control de versiones en local

📚 **Esta entrada es parte de la serie _Guía de Git_**, dividida en tres capítulos que se leen en orden:

> * 👉 **Parte 1: Control de versiones en local**

* Parte 2: Ramas

* Parte 3: Repositorios remotos, stash y tags

Introducciónlink image 1

Git es un software de control de versiones creado por Linus Torvalds, quien lo creó para poder tener un buen control de versiones cuando desarrolló el kernel de Linux.

Las áreas de gitlink image 2

Git tiene tres áreas, aunque también se puede considerar una cuarta.

git states
  • La primera es nuestro espacio de trabajo, en él es donde tenemos todo nuestro código. Aquí, cuando modificamos o creamos un archivo, este pasa a estar como no trackeado, por lo que tenemos que pasarlo al área de staged * La segunda área es la de staged. Aquí los archivos que habíamos modificado o creado y que estaban no *trackeados* pasan a estar trackeados, es decir, Git les hace un seguimiento. Aquí mandaremos los archivos al siguiente área de head * La tercera área es la de head. En ella hemos grabado una versión de nuestro código. De esta manera, grabando versiones podemos volver a versiones pasadas si es necesario. La versión grabada de nuestro código puede ser mandada a un servidor de manera que sea accesible por varias personas
  • Las tres áreas anteriores corresponden al trabajo en local, pero hay un área más y es la de remote server. Aquí lo que hacemos es mandar la versión grabada de nuestro código a un servidor de manera que tengamos acceso al código desde cualquier lugar, o que tenga acceso más personas

Para hacer un símil, es como un escenario en el que vas a hacer una foto. Primero tienes tus archivos modificados, de manera que los que quieres inmortalizar los mandas al área de staged, es decir al escenario. En el momento en que has mandado todos los archivos que consideras, haces la foto, por lo que mandas todos los archivos al área de head. De esta manera, puedes ir haciendo muchas fotos, según va evolucionando el código, de manera que puedes tener en un álbum de fotos la evolución del código. Por último puedes subir esa foto a un servidor para que sea accesible por más gente, es decir, los mandas al área de remote server

Instalar gitlink image 3

En la mayoría de distribuciones Linux, git ya viene instalado, podemos comprobarlo haciendo git --version

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

Si no lo tienes o quieres actualizar la versión de git, solo tienes que ejecutar sudo apt update y a continuación sudo apt install git

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

Volvemos a comprobar la versión

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

En mi caso ya tenía la última versión

Configuración iniciallink image 4

Configuración del nombre y el correolink image 5

Antes de empezar a usar git es conveniente que hagas unas configuraciones mínimas como el nombre de usuario y el correo, esta información es la que saldrá a la hora de mostrar quién ha hecho cambios en el código. Para hacer esto hay que ejecutar

git config --global user.name "<nombre de usuario>"
git config --global user.email "<email>"

En mi caso metería

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

Como se puede ver el flag --global lo que hace es cambiar la configuración global de git, pero si en un repositorio en concreto tienes que poner otros datos, simplemente navegas hasta el repositorio y quitas el flag --global de los comandos anteriores

git config user.name "<nombre de usuario>"
git config user.email "<email>"

Configurar el editor por defectolink image 6

Cuando más adelante expliquemos qué son los commits veremos que en una de las opciones se nos puede abrir un navegador. Por defecto git intentará usar vim, pero dado que no es un editor muy sencillo de usar, podemos modificarlo. A continuación se muestra cómo hacerlo con algunos editores comunes

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

Comprobar configuración de gitlink image 7

Para revisar la configuración de 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 los flags --global, --local y --system para ver sólo la configuración global, local (si existe) y de sistema (si existe)

	
< > 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

En mi caso no existe configuración de sistema

Si se quiere saber solo el valor de un parámetro de la configuración valdría con introducir git config <parameter>

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

Control de versiones de manera locallink image 8

Inicializar un nuevo repositorio (git init)link image 9

Hay dos maneras de inicializar un nuevo repositorio haciendo

  • Una es haciendo git init . Esto creará una nueva carpeta con el nombre del repositorio
  • Otra es navegando a la carpeta donde queramos crear un repositorio y haciendo git init

Voy a crear un nuevo repositorio

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

Si ahora hacemos ls veremos que se ha creado una nueva carpeta llamada notebook_git

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

Nos movemos a ella

	
< > Input
Python
!cd notebook_git
Copied

Ahora dentro de la carpeta tenemos dos maneras de saber que se ha creado el repositorio, una haciendo ls -a que mostrará todos los archivos y veremos que hay una carpeta llamada .git. La otra manera es haciendo git status que nos dirá el estado del repositorio

	
< > 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 en un notebook, cada celda tiene su path en el path del notebook, por eso las dos veces he tenido que hacer cd notebook_git &&, para que cambie a la carpeta con el repositorio que acabamos de crear.

Si ahora pruebo git status en otro path donde no se haya inicializado un repositorio nos dará un error

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

Crear nuevos archivoslink image 10

En el momento en que hemos inicializado un repositorio podemos empezar a crear nuevos archivos, así que creamos uno y vemos qué ocurre

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

Si ahora volvemos a hacer git status vemos 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 puede ver, ahora nos está diciendo que el archivo hello.py no tiene seguimiento. Es decir, tenemos que añadir hello.py al área de staged, que recordemos era como el escenario donde íbamos a poner todo lo que más tarde le haremos una foto

Deshacer la creación de un archivo nuevolink image 11

En este caso, como son archivos que git aún no está siguiendo, es decir, que aún no están en el área de staged, tendríamos tres maneras de hacerlo

  • Borrándolo simplemente: Como git aún no sigue el archivo podríamos hacer rm hello.py y listo
  • Borrándolo mediante un comando de Git: Antes hemos borrado con rm, pero es posible que estés en un sistema que no tenga el comando rm. Por lo que, en ese caso, se puede usar el comando de Git git rm hello.py
  • Por último, podemos usar git clean. Este es útil, por ejemplo, cuando hay muchos archivos nuevos, y así, en un solo comando, eliminamos todos.

git cleanlink image 12

Si ejecutamos git clean a secas, nos dará un error

	
< > 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

Nos está diciendo que hace falta añadir uno de estos flags -n, -i o -f. Además vamos a ver el flag -d

  • -n (dry run): Nos dirá qué archivos se van a borrar, pero no los borrará
  • -i: Nos preguntará por cada archivo que se va a borrar
  • -f: Forzará el borrado de los archivos
  • -d: También borrará carpetas

Vamos a probarlo, primero hacemos git clean -n para saber qué archivos se borrarían

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

Ahora hacemos git clean -f para que lo borre, ya que estamos de acuerdo en que lo borre

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

Como vemos, ha borrado hello.py

Añadir un archivo al área de staging (git add)link image 13

Volvemos a crear un archivo

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

Volvemos a hacer un git status para comprobar que tenemos el archivo

	
< > 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 tenemos el archivo hola.py pero que git no le está haciendo un seguimiento. Además vemos que nos ayuda y nos dice usa "git add" para hacerles seguimiento

La sintaxis es la siguiente git add <archivo>, pero podemos hacerlo de varias maneras

  • Si queremos añadir más de un archivo, lo podemos hacer poniendo todos los archivos que queremos añadir al área de staged, separados por un espacio: git add * Si queremos añadir todos los archivos de un mismo formato, por ejemplo, si queremos añadir todos los archivos de Python, sería git add *.py * Si queremos añadir todos los archivos de una carpeta git add /
  • Si queremos añadir todos los archivos tenemos tres maneras: git add --all, git add -A o git add .

Vamos a añadir el nuevo archivo creado

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

Hacemos un git status para ver qué ha pasado

	
< > 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, nos dice que tenemos un nuevo archivo al que le hace seguimiento y que está pendiente de ser confirmado hola.py

Sacar un archivo del área de staged (git reset)link image 14

En caso de que añadamos un archivo al área de staged y lo queramos sacar, tenemos que usar git reset <archivo>, vamos a verlo

Creamos y añadimos al área de stage un nuevo archivo

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

Hacemos git status para comprobar que está en el á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án hola.py y adios.py, así que usamos git reset adios.py para sacarlo del área de staging

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

Hacemos un git status para comprobar que ha salido

	
< > 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 ya no tiene seguimiento por parte de git, lo ha sacado del área de stage

Hacemos git clean -f para borrarlo

	
< > 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 15

Si volvemos al símil en el que dijimos que el área de staged era el escenario donde mandábamos los archivos a los que queríamos hacerles la foto, ahora toca hacer la foto para inmortalizar el estado actual. Esto es hacer un commit

De esta manera se registra el estado actual del código, así, con cada commit, se irá teniendo un registro de la evolución del código. Al igual que con un álbum de fotos, con cada foto vamos teniendo un registro de la evolución de lo que ponemos en el escenario.

Como a la hora de hacer el commit se está registrando el cambio del código, git no nos deja hacer el commit si no hacemos un mínimo comentario. Por lo que hay dos maneras de hacer commit

  • git commit de esta manera se abrirá el editor que hayamos establecido en la configuración de git. Si no hemos configurado un editor por defecto, se abrirá vi. Si queremos cambiar la configuración del editor podemos hacer por ejemplo git config --global core.editor "code" o git config core.editor "code" para establecer VSCode como el editor por defecto de manera global o local. * git commit -m "Mensaje de commit". De esta manera añadimos el mensaje directamente

Al hacer el commit de la primera forma podemos tener una primera línea que será el título del commit y varias líneas más donde se explica en más detalle. Si queremos poder hacer esto con el flag -m bastará con añadir varios flags -m seguidos: git commit -m "Título del commit" -m "Primera línea explicando más" -m "Segunda línea explicando más"

Una vez hemos hecho el commit, esto guardará un registro del cambio de nuestro repositorio de manera local. Aún no hemos conectado con un servidor remoto

Vamos a probar a hacer el 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

Hacemos un 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 nos dice que no hay nada nuevo, tenemos todo nuestro repositorio totalmente controlado

Commit saltándonos add (git commit -a -m o git commit -am)link image 16

En el caso en el que todos los archivos que hayamos modificado los queramos llevar al área de staged y luego hacerles un commit, podemos hacer todo esto en un solo paso mediante git commit -a -m "mensaje", git commit --all -m "mensaje" o git commit -am "mensaje"

Nota: Esto solo es válido si se modifica un archivo. Si el archivo es nuevo y git no le hace seguimiento, esto no es válido

Veamos un ejemplo, vamos a modificar hola.py

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

Vamos a hacer un git status para asegurarnos

	
< > 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 en la propia ayuda de git ya nos sugiere usar git commit -a, así que vamos a hacerlo

	
< > 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(+)

Volvemos a hacer un 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

No hay nada para hacer commit, ya se ha hecho el commit del cambio

Modificar un archivo al que se le había hecho commitlink image 17

Como mientras desarrollamos estamos modificando archivos, puede que en algún archivo al que ya le habíamos hecho commit lo modifiquemos. En nuestro caso vamos a añadir una línea 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')

Si hacemos git status veremos que hola.py tiene modificaciones

	
< > 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 cambios en un archivo (git diff <archivo>)link image 18

Puede que llevemos un tiempo desarrollando desde el último commit y no sepamos qué modificaciones hemos hecho; para ello usamos git diff <archivo> que nos dirá los cambios que hemos hecho

	
< > 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')

Aunque no es muy intuitivo, podemos ver que hemos añadido la última línea en hola.py

Deshacer modificaciones en un archivo (git restore <archivo>)link image 19

Si los cambios que hemos hecho no nos gustan y los queremos quitar, lo que podemos hacer es git restore <archivo>

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

Veamos qué ha pasado con un 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 se han descartado los cambios en hola.py desde el último commit

Histórico de cambios (git log)link image 20

Con git podemos ver el historial de todos los cambios que hemos ido commiteando, para ello usamos git log. Es como si nos pusiéramos a revisar nuestro á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 el historial de cambios, hay que leerlo de abajo hacia arriba.

Primero vemos el commit con mensaje Primer commit, hola.py, podemos ver la fecha, el autor y el hash, que es su identificador único

A continuación vemos el segundo commit con mensaje Segundo commit, hola.py, con su fecha, autor y hash. Además, nos muestra dónde está el HEAD y en qué rama estamos

Si usamos flags podemos obtener la información de distintas maneras, pero en función de qué flags usemos puede que nos venga mejor. A continuación se muestran algunos flags útiles:

  • git log --oneline: Muestra los commits en una sola línea, con el hash abreviado y el mensaje del commit.
  • git log --graph: Muestra un gráfico de texto de la historia del repositorio, incluyendo ramas y fusiones.
  • git log --decorate: Muestra las referencias (ramas, etiquetas, HEAD, etc.) en el log junto con el commit al que apuntan.
  • git log --author="": Filtra el historial de commits para mostrar solo aquellos realizados por un autor específico.
  • git log --since="": Muestra los commits realizados desde una fecha específica. Puedes usar diferentes formatos de fecha, como "1 week ago" o "2023-01-01".
  • git log --until="": Muestra los commits realizados hasta una fecha específica.
  • git log : Muestra los commits de una rama específica.
  • git log ..: Muestra los commits que están en el rango entre dos commits específicos.
  • git log --grep="": Busca en los mensajes de commit por una palabra o frase específica.
  • git log -p: Muestra las diferencias (en forma de parche) introducidas en cada commit.
  • git log -n : Muestra los últimos números de commits. Por ejemplo, git log -n 5 mostrará los últimos 5 commits. * git log --stat: Muestra las estadísticas de cambios en archivos para cada commit, como el número de líneas añadidas y eliminadas.

Por ejemplo, una manera cómoda de ver el histórico es 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 en vez de darnos el hash entero nos da solo unos pocos números, esto es porque de momento el repositorio tiene tan poca historia que con esos pocos números es suficiente, si quisiésemos volver al punto anterior, en vez de introducir el hash entero (7c448f69e30ab1b5783f5cf9ee3ae5bc362ecd4d), con introducir solo 7c448f6 valdría

Más adelante hablaremos sobre las ramas, pero ahora vamos a ver qué es el HEAD

Mientras desarrollábamos hemos podido hacer cambios y commitearlos, es decir, hemos ido rellenando el álbum de fotos de nuestro código. HEAD es la posición en el álbum en la que estamos.

Normalmente es la última posición de todos los commits.

Si queremos saber en qué punto estamos, lo podemos hacer mediante git rev-parse HEAD

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

Como se puede ver, el hash obtenido coincide con el último obtenido al hacer 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 un commit (git commit --amend)link image 22

Puede que queramos modificar un commit, porque queramos cambiar el mensaje, o porque queramos añadir más archivos al commit, de modo que veremos los dos casos

Modificar el mensaje de commitlink image 23

Si solo se quiere modificar el mensaje, lo que tenemos que hacer es git commit --amend -m "Nuevo mensaje", veamos un ejemplo, vamos a modificar hola.py

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

Hacemos un 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")

Efectivamente vemos que hola.py tiene modificaciones, de modo que hacemos un commit con estas modificaciones

	
< > 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 a ver el historial 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 no!** hemos escrito commot en vez de commit, así que vamos a modificar el mensaje

	
< > 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(+)

Volvemos a ver el historial

	
< > 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 ahora está bien

Añadir archivos al último commitlink image 24

Supongamos que se nos ha olvidado añadir un archivo al último commit, simplemente hacemos un git add con ese archivo y hacemos git commit --amend -m "mensaje"

Vamos a crear dos archivos nuevos

	
< > 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

Ahora hacemos commit solo de uno

	
< > 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, nos hemos dejado el archivo 2, de modo que modificamos el commit y añadimos el archivo 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

Ahora el último commit tiene los dos nuevos archivos

Deshacer un commit (git reset HEAD~1)link image 25

Con este comando le decimos a git que retroceda una posición en el historial de commits. Hay dos opciones --soft que no borrarán los cambios que hayamos hecho y --hard que sí lo hará

Deshacer un commit manteniendo los cambios (git reset --soft HEAD~1)link image 26

Vamos a crear un nuevo archivo

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

Hacemos un 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)

Hacemos un commit añadiendo este archivo

	
< > 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 en el último commit se encuentra archivo3.py, vamos a eliminar el commit manteniendo archivo3.py

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

Hacemos ahora un git log para ver si se ha eliminado el último commit

	
< > 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

Efectivamente, vemos que se ha eliminado el último commit

Hacemos un git status para ver si se ha conservado archivo3.py

	
< > 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

Se ha mantenido

Deshacer un commit descartando los cambios (git reset --hard HEAD~1)link image 27

Tenemos archivo3.py que lo hemos creado y lo tenemos en el á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

Por lo tanto, hacemos un 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

Hacemos un git log para comprobar que hay un commit con este archivo

	
< > 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

Efectivamente, hay un commit añadiendo archivo3.py. Ahora eliminamos este commit descartando archivo3.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

Hacemos un git log para comprobar que se ha eliminado el último commit

	
< > 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

Se ha eliminado el commit con archivo3.py, ahora hacemos un git status para comprobar qué ha pasado con archivo3.py

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

No aparece archivo3.py como un archivo al que haya que hacer commit, vamos a ver si efectivamente se ha eliminado del todo

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

Efectivamente se ha eliminado archivo3.py del sistema de ficheros

Modificar un commit remoto (git push --force)link image 28

Aunque más adelante veremos cómo sincronizarnos con repositorios remotos, en el caso de que hayas hecho un commit, lo hayas subido a un repositorio remoto (git push) y hayas modificado el commit en local (porque has modificado el mensaje o has deshecho el commit), para revertir los cambios en el repositorio remoto tienes que hacer git push --force

**Cuidado**: Este comando modifica el historial del repositorio remoto, por lo que puede afectar al resto de gente que esté trabajando con ese repositorio, así que usa este comando con mucho cuidado y seguridad. Vale más la pena tener un historial de commits, en el que primero está el commit en el que has puesto mal la descripción y luego el nuevo commit con la nueva descripción bien puesta, que andar modificando el historial.

Modificar un commit remoto (git push --force-with-lease)link image 29

Si estás convencido de cambiar el historial, al menos usa git push --force-with-lease, que no modificará commits que haya habido posteriormente

Ignorar archivos (.gitignore)link image 30

Supongamos que tenemos un archivo con API keys, este archivo en realidad no queremos que se guarde en el repositorio, porque si luego compartimos este repositorio, cualquiera tendría acceso a estas claves, por lo que hay que decirle a git que no haga seguimiento de este archivo

Esto se hace con el archivo .gitignore, en él se añade la ruta de los archivos o directorios que no queremos que Git haga seguimiento

Vamos a verlo

Creamos el archivo con las claves

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

Si hacemos git status vemos que Git lo 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)

Si no hacemos nada puede que un día hagamos un git add . y lo metamos en el repositorio, así que por seguridad hay que decirle a git que no siga este archivo, para ello, lo que hacemos es crear el .gitignore añadiendo este archivo

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

Veamos qué pasa si ahora hacemos 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 git ha dejado de contemplar api_keys.py, pero sí contempla .gitignore, por lo que hacemos un commit para añadir .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

¿Qué archivos añadir al .gitignore?link image 31

  • Archivos que tengan credenciales o llaves de API (no deberías subirlas al repositorio, simplemente inyectarlas por variables de entorno) * Carpetas de configuración de tu editor (/.vscode)
  • Archivos de registro (log files)
  • Archivos de sistema como .DS_Store
  • Carpetas generadas con archivos estáticos o compilaciones como /dist o /build
  • Dependencias que pueden ser descargadas (/node_modules)
  • Coverage del testing (/coverage)

¿Cómo ignorar siempre los mismos archivos?link image 32

Si por ejemplo tu IDE siempre genera los mismos archivos de configuración, estaría bien poderle decir a git que siempre ignore esos archivos, para ello creamos un .gitignore global

	
< > Input
Python
!touch ~/.gitignore_global
Copied

En mi caso voy a añadir el directorio __pycache__/

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

Ahora hay que indicarle a Git que ese es nuestro .gitignore global

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

Listo, a partir de ahora el directorio __pycache__/ siempre será ignorado

GitHub tiene un repositorio con .gitignores para muchos lenguajes, yo me he guiado de este para Python

Eliminar un archivo de un commitlink image 33

Vamos a ver cómo eliminar un archivo de un commit que hemos hecho. Primero creamos dos archivos y les hacemos commit

	
< > 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

Hacemos un commit con los dos archivos

	
< > 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 de aquí hay dos opciones para eliminar un archivo de un commit:

  • Eliminar el archivo y crear un nuevo commit
  • Deshacer el commit y crearlo de nuevo sin el archivo

Eliminar el archivo y crear un nuevo commitlink image 34

Supongamos que queremos eliminar el archivo archivo5.py, pues lo eliminamos con git rm archivo5.py

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

Hagamos un git status a ver qué ocurre

	
< > 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, se ha borrado archivo5.py. Ahora creamos un nuevo 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

Deshacer el commit y crearlo de nuevo sin el archivolink image 35

Volvemos a crear dos archivos y hacer un 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

Primero deshacemos el último commit con git reset --soft HEAD~1

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

Hacemos un git status para ver qué ha ocurrido

	
< > 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 he deshecho el commit, pero que los dos archivos se encuentran en el área de staged, por lo que para sacar del commit uno de los archivos, primero hay que sacarlo del área de staged, para ello hacemos git reset archivo6.py

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

Volvemos a hacer un 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 archivo7.py está en el área de staged, mientras que archivo6.py ya no. Ahora podemos borrar archivo 6; para ello 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

Volvemos a hacer un 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 ya no está, por lo que podemos hacer un nuevo 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

Hemos eliminado el último commit y lo hemos sobrescrito con uno nuevo, eliminando el archivo que queríamos

Histórico de cambios de un archivo (git log <archivo>)link image 36

Aunque antes hemos visto cómo podíamos ver el historial del repositorio con git log puede que no nos interese el historial de todo el repositorio. Puede que tengamos un bug en un archivo de código que al principio no teníamos, por lo que es posible que queramos ver solo el historial de ese archivo, para eso usamos git log <archivo>

Primero vemos los archivos que tenemos

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

Supongamos que solo queremos ver los cambios en hola.py, por lo que hacemos 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 aparecen muchos menos resultados que si hubiésemos hecho 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 modificaciones de un archivo en un punto concreto del historial (git show <hash> <archivo> o git diff <archivo>)link image 37

Supongamos que ya sabemos en qué punto se realizó un cambio en el archivo que contiene un bug, por lo que ahora queremos saber qué cambios se realizaron para saber qué puede estar causando el bug, para ello podemos usar git show <hash> <archivo>

Veamos qué cambios se produjeron en hola.py en el hash c4930d7, es decir cuando se hizo el tercer 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')

La manera de ver los cambios en git no son muy intuitivas, pero podemos ver que se ha añadido la línea print('Esta es la tercera línea')

Otra manera de ver cambios es con git diff, tenemos dos opciones, podemos ver los cambios del fichero en el momento actual con un punto concreto del historial, para ello hacemos git diff <hash> <archivo.

Por ejemplo, si queremos ver los cambios de hola.py de cuando se hizo el primer commit (hash 1c95e4f) con la situación actual, hay que introducir (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')

Pero si lo que queremos es ver la diferencia entre un punto concreto del historial y otro punto concreto, hay que introducir los hash de los dos momentos, es decir git diff <hash1> <hash2> <archivo>

Si queremos ver los cambios de hola.py entre el segundo commit (hash 6e99e73) y el primer commit (hash 1c95e4f) tendríamos que introducir 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')

Lo anterior nos muestra los cambios del segundo commit con respecto al primero, pero si lo que queremos es los cambios del primer commit con respecto al segundo, solo hay que poner los hash al revés de como los hemos puesto, es decir 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')

Viaje al pasado (git reset --hard <hash> o git reset --soft <hash>)link image 38

Imaginemos que hemos encontrado que todo lo que hicimos después de generar el bug no sirve y tenemos que volver a trabajar desde ese punto, podemos volver a una posición del historial mediante git reset --hard <hash> (esto no mantendrá los cambios) o git reset --soft <hash> (esto sí mantendrá los cambios)

Primero veamos el historial

	
< > 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

Supongamos que queremos ir al momento en el que hicimos el tercer commit (hash c4930d7), además lo hacemos sin mantener los cambios, es decir, todas las modificaciones que hicimos después se borrarán, hacemos git reset --hard c4930d7

Primero hacemos ls para ver los archivos que tenemos ahora

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

Vamos al tercer commit

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

Si hacemos ls veremos que ya no tenemos ni archivo1.py, ni archivo2.py, ni archivo4.py, ni archivo7.py

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

Regreso al futuro (git reflog)link image 39

Supongamos que nos hemos arrepentido y queremos volver a donde estábamos, al último punto en el historial, una manera sería volver a hacer git reset --hard <hash>. Pero imaginemos que no sabemos el hash, porque no hicimos git log antes y si lo hacemos ahora solo nos da información del historial hasta el tercer 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

Aquí lo que podemos hacer es git reflog, que nos dará un historial incluyendo los 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ábamos en el commit con hash 4bb9d75, es decir el último commit que hicimos, y de ahí nos fuimos hasta el commit con hash c4930d7, que si te fijas, es el mismo hash que el commit con mensaje Tercer commit, hola.py. Por lo que ya sabemos el hash del último commit, el 4bb9d75, así que para volver a la posición del último commit hacemos 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

Si ahora volvemos a hacer un 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 efectivamente estamos en la posición del último commit, *hemos regresado al futuro*

Búsqueda en ficheros (git grep <palabra>)link image 40

Si queremos buscar en ficheros podemos hacerlo con el comando git grep. Como el repositorio que llevamos hecho es muy pequeño y tiene muy pocos archivos vamos a bajarnos uno nuevo mediante un comando que veremos después más en detalle

	
< > 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.

El repositorio que hemos bajado es el del código fuente de SAM, una red neuronal de Meta para segmentar cualquier objeto. Entramos en la carpeta del repositorio y buscamos, por ejemplo, cuántas veces se ha escrito la palabra softmax

	
< > 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 se ha escrito en los archivos segment_anything/modeling/image_encoder.py y segment_anything/modeling/transformer.py.

Si ahora además queremos saber en qué líneas de los archivos se ha escrito, usamos el 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)

Si lo que queremos es contar cuántas veces aparece la palabra, podemos usar el 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

Y vemos que aparece una vez en cada archivo

Y nos dice que están en las líneas 236 y 233, respectivamente

Búsqueda en commits (git log -S <palabra>)link image 41

Si lo que queremos es buscar en el historial de commits podemos usar el comando git log -S <palabra>. Por ejemplo, busquemos en el historial de commits del repositorio que nos hemos bajado antes la palabra 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

Borramos la carpeta de SAM

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

---

➡️ **Continúa en la Parte 2: ramas**, donde aprenderás a trabajar con varias líneas de desarrollo en paralelo.

Posts relacionados

Seguir leyendo

Últimos posts -->

¿Has visto estos proyectos?

Gymnasia

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

Aplicación móvil de entrenamiento personal con asistente de IA, biblioteca de ejercicios, seguimiento de rutinas, dieta y medidas corporales

Horeca chatbot

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

Chatbot conversacional para cocineros de hoteles y restaurantes. Un cocinero, jefe de cocina o camaeror de un hotel o restaurante puede hablar con el chatbot para obtener información de recetas y menús. Pero además implementa agentes, con los cuales puede editar o crear nuevas recetas o menús

Naviground

Naviground Naviground
Ver todos los proyectos -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres ver alguna charla?

Últimas charlas -->

¿Quieres mejorar con estos tips?

Últimos tips -->

Usa esto en local

Los espacios de Hugging Face nos permite ejecutar modelos con demos muy sencillas, pero ¿qué pasa si la demo se rompe? O si el usuario la elimina? Por ello he creado contenedores docker con algunos espacios interesantes, para poder usarlos de manera local, pase lo que pase. De hecho, es posible que si pinchas en alún botón de ver proyecto te lleve a un espacio que no funciona.

Flow edit

Flow edit Flow edit

Edita imágenes con este modelo de Flow. Basándose en SD3 o FLUX puedes editar cualquier imagen y generar nuevas

FLUX.1-RealismLora

FLUX.1-RealismLora FLUX.1-RealismLora
Ver todos los contenedores -->
>_ Disponible para proyectos

¿Tienes un proyecto con IA?

Hablemos.

maximofn@gmail.com

Especialista en Machine Learning e Inteligencia Artificial. Desarrollo soluciones con IA generativa, agentes inteligentes y modelos personalizados.

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

HuggingFace

Dataset de chistes en inglés

Uso: Fine-tuning de modelos de generación de texto humorístico

231K filas 2 columnas 45 MB
Ver en HuggingFace →

opus100

HuggingFace

Dataset con traducciones de inglés a español

Uso: Entrenamiento de modelos de traducción inglés-español

1M filas 2 columnas 210 MB
Ver en HuggingFace →

netflix_titles

HuggingFace

Dataset con películas y series de Netflix

Uso: Análisis de catálogo de Netflix y sistemas de recomendación

8.8K filas 12 columnas 3.5 MB
Ver en HuggingFace →
Ver más datasets -->