Git

Git Git

Gitlink image 0

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 ella 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 necesaro. 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 una área más y 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 simil, 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 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 álbun de fotos la evolución del código. Por último puedes subir esa foto a una 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

	
!git --version
Copy
	
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

	
!sudo apt update && sudo apt install git
Copy
	
[sudo] password for maximo.fernandez@AEROESPACIAL.SENER:

Volvemos a comprobar la versión

	
!git --version
Copy
	
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 quien 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 quita 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 --lits

	
!git config --list
Copy
	
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 solo la configuración global, local (si existe) y de sistema (si existe)

	
!git config --global --list
Copy
	
user.name=maximofn
user.email=maximofn@gmail.com
user.user=maximofn
http.sslverify=true
	
!git config --local --list
Copy
	
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
	
!git config --system --list
Copy
	
fatal: unable to read config file '/etc/gitconfig': No such file or directory

En mi caso no existe configuración de sistema

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

	
!git config user.name
Copy
	
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 <nombre repositorio>. 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

	
!git init notebook_git
Copy
	
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

	
!ls | grep notebook_git
Copy
	
notebook_git

Nos movemos a ella

	
!cd notebook_git
Copy

Ahora dentro de la carpeta tenemos dos maneras de saber que se ha creado el repositorio, una haciendo ls -a que mostará 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

	
!cd notebook_git
!cd notebook_git && ls -a
Copy
	
. .. .git
	
!cd notebook_git && git status
Copy
	
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

	
!cd ~/ && git status
Copy
	
fatal: no es un repositorio git (ni ninguno de los directorios superiores): .git

Crear nuevos archivoslink image 10

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

	
!cd notebook_git && echo "print('Hello World')" > hello.py
Copy

Si ahora volvemos a hacer git status vemos qué nos aparece

	
!cd notebook_git && echo "print('Hello World')" > hello.py
!cd notebook_git && git status
Copy
	
En la rama master
No hay commits todavía
Archivos sin seguimiento:
(usa "git add <archivo>..." 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 aun no está siguiendo, es decir, que aun no están en el área de staged tendríamos tres maneras de hacerlo

  • Borrándolo simplemente: Como git aun 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

	
!cd notebook_git && git clean
Copy
	
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 y -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

	
!cd notebook_git && git clean -n
Copy
	
Será borrado hello.py

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

	
!cd notebook_git && git clean -f
Copy
	
Borrando hello.py

Como vemos ha borrado hello.py

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

Volvemos a crear un archivo

	
!cd notebook_git && echo "print('Hola mundo')" > hola.py
Copy

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

	
!cd notebook_git && echo "print('Hola mundo')" > hola.py
!cd notebook_git && git status
Copy
	
En la rama master
No hay commits todavía
Archivos sin seguimiento:
(usa "git add <archivo>..." 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 <archivo1> <archivo2> <archivo3>
  • 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 <folder>/
  • 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

	
!cd notebook_git && git add hola.py
Copy

Hacemos un git status para ver qué ha pasado

	
!cd notebook_git && git add hola.py
!cd notebook_git && git status
Copy
	
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached <archivo>..." 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 staged un nuevo archivo

	
!cd notebook_git && echo "print('Este no')" > adios.py && git add adios.py
Copy

Hacemos git status para comprobar que está en el área de staged

	
!cd notebook_git && echo "print('Este no')" > adios.py && git add adios.py
!cd notebook_git && git status
Copy
	
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached <archivo>..." 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 staged

	
!cd notebook_git && git reset adios.py
Copy

Hacemos un git status para comprobar que ha salido

	
!cd notebook_git && git reset adios.py
!cd notebook_git && git status
Copy
	
En la rama master
No hay commits todavía
Cambios a ser confirmados:
(usa "git rm --cached <archivo>..." para sacar del área de stage)
nuevos archivos: hola.py
Archivos sin seguimiento:
(usa "git add <archivo>..." 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 staged

Hacemos git clean -f para borrarlo

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

Commit (git commit)link image 15

Si volvemos al simil en el que digimos 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 album 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 "Titulo del commit" -m "Primera linea explicando más" -m "Segunda linea explicando más"

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

Vamos a probar a hacer el commit

	
!cd notebook_git && git commit -m "Primer commit, hola.py"
Copy
	
[master (commit-raíz) 1c95e4f] Primer commit, hola.py
1 file changed, 1 insertion(+)
create mode 100644 hola.py

Hacemos un git status

	
!cd notebook_git && git status
Copy
	
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 saltandonos add (git commit -a -m o git commit -am)link image 16

En el caso en el que todos los archivos que hayamos modificados 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

	
!cd notebook_git && echo "print('He añadido una nueva linea')" >> hola.py
Copy

Vamos a hacer un git status para asegurarnos

	
!cd notebook_git && echo "print('He añadido una nueva linea')" >> hola.py
!cd notebook_git && git status
Copy
	
En la rama master
Cambios no rastreados para el commit:
(usa "git add <archivo>..." para actualizar lo que será confirmado)
(usa "git restore <archivo>..." 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çi que vamos a hacerlo

	
!cd notebook_git && git commit -am "Segundo commit, hola.py"
Copy
	
[master 6e99e73] Segundo commit, hola.py
1 file changed, 1 insertion(+)

Volvemos a hacer un git status

	
!cd notebook_git && git status
Copy
	
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 comit del cambio

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

Como mientras desarrollamos estamos modificando archivos, puede que en algun archivo al que ya le habíamos hecho commit lo modifiquemos. En nuestro caso vamos a añadir una línea a hola.py

	
!cd notebook_git && echo "print('He añadido una tercera linea')" >> hola.py
Copy
	
!cd notebook_git && echo "print('He añadido una tercera linea')" >> hola.py
!cd notebook_git && cat hola.py
Copy
	
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

	
!cd notebook_git && git status
Copy
	
En la rama master
Cambios no rastreados para el commit:
(usa "git add <archivo>..." para actualizar lo que será confirmado)
(usa "git restore <archivo>..." 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

	
!cd notebook_git && git diff hola.py
Copy
	
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>

	
!cd notebook_git && git restore hola.py
Copy

Veamos qué ha pasado con un git status

	
!cd notebook_git && git restore hola.py
!cd notebook_git && git status
Copy
	
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 album de fotos

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

Podemos ver el historial de cambios, hay que leerlo de abajo 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="<autor>": Filtra el historial de commits para mostrar solo aquellos realizados por un autor específico.
  • git log --since="<fecha>": 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="<fecha>": Muestra los commits realizados hasta una fecha específica.
  • git log <rama>: Muestra los commits de una rama específica.
  • git log <commit1>..<commit2>: Muestra los commits que están en el rango entre dos commits específicos.
  • git log --grep="<palabra>": 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 <número>: Muestra los últimos número 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 vver el histórico es usar git log --graph --oneline --decorate

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 6e99e73 (HEAD -> 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 album de fotos de nuestro código. HEAD es la posición en el album 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

	
!cd notebook_git && git rev-parse HEAD
Copy
	
6e99e73cf0c5474078cc9f328ee6a54fb9ffb169

Como se puede ver, el hash obtenido coincide con el último obtenido al hacer git log

	
!cd notebook_git && git log
Copy
	
commit 6e99e73cf0c5474078cc9f328ee6a54fb9ffb169 (HEAD -> master)
Author: maximofn <maximofn@gmail.com>
Date: Sun Apr 16 02:29:04 2023 +0200
Segundo commit, hola.py
commit 1c95e4fd8388ceedee368e0121c4b0ef4900c2ac
Author: maximofn <maximofn@gmail.com>
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

	
!cd notebook_git && echo "print('Esta es la tercera linea')" >> hola.py
Copy

Hacemos un git status

	
!cd notebook_git && echo "print('Esta es la tercera linea')" >> hola.py
!cd notebook_git && git status
Copy
	
En la rama master
Cambios no rastreados para el commit:
(usa "git add <archivo>..." para actualizar lo que será confirmado)
(usa "git restore <archivo>..." 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

	
!cd notebook_git && git commit -am "Tercer commot, hola.py"
Copy
	
[master 60e2ffd] Tercer commot, hola.py
1 file changed, 1 insertion(+)

Vamos a ver el historial de commits

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 60e2ffd (HEAD -> 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

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

Volvemos a ver el hostorial

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* c4930d7 (HEAD -> 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

	
!cd notebook_git && echo "print('Este es el archivo 1')" > archivo1.py
Copy
	
!cd notebook_git && echo "print('Este es el archivo 1')" > archivo1.py
!cd notebook_git && echo "print('Este es el archivo 2')" > archivo2.py
Copy

Ahora hacemos commit solo de uno

	
!cd notebook_git && echo "print('Este es el archivo 1')" > archivo1.py
!cd notebook_git && echo "print('Este es el archivo 2')" > archivo2.py
!cd notebook_git && git add archivo1.py && git commit -m "Commit con el archivo 1"
Copy
	
[master 285b243] Commit con el archivo 1
1 file changed, 1 insertion(+)
create mode 100644 archivo1.py
	
!cd notebook_git && git status
Copy
	
En la rama master
Archivos sin seguimiento:
(usa "git add <archivo>..." 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)
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 285b243 (HEAD -> 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

	
!cd notebook_git && git add archivo2.py
Copy
	
!cd notebook_git && git add archivo2.py
!cd notebook_git && git commit --amend -m "Commit con los archivos 1 y 2"
Copy
	
[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
	
!cd notebook_git && git status
Copy
	
En la rama master
nada para hacer commit, el árbol de trabajo está limpio
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 04ebd1f (HEAD -> 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á 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

	
!cd notebook_git && echo "print('Este es el archivo 3')" > archivo3.py
Copy

Hacemos un git status

	
!cd notebook_git && echo "print('Este es el archivo 3')" > archivo3.py
!cd notebook_git && git status
Copy
	
En la rama master
Archivos sin seguimiento:
(usa "git add <archivo>..." 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

	
!cd notebook_git && git add archivo3.py && git commit -m "Commit con el archivos 3"
Copy
	
[master 6dc7be6] Commit con el archivos 3
1 file changed, 1 insertion(+)
create mode 100644 archivo3.py
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 6dc7be6 (HEAD -> 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

	
!cd notebook_git && git reset --soft HEAD~1
Copy

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

	
!cd notebook_git && git reset --soft HEAD~1
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 04ebd1f (HEAD -> 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

	
!cd notebook_git && git status
Copy
	
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." 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 staged

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

Por lo que hacemos un commit

	
!cd notebook_git && git commit -m "Commit con el archivo 3"
Copy
	
[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

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 0147d65 (HEAD -> 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

	
!cd notebook_git && git reset --hard HEAD~1
Copy
	
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

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 04ebd1f (HEAD -> 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

	
!cd notebook_git && git status
Copy
	
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

	
!cd notebook_git && ls | grep archivo3
Copy

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

	
!cd notebook_git && ls | grep archivo3
!cd notebook_git && touch api_keys.py
Copy

Si hacemos git status vemos que git lo contempla

	
!cd notebook_git && ls | grep archivo3
!cd notebook_git && touch api_keys.py
!cd notebook_git && git status
Copy
	
En la rama master
Archivos sin seguimiento:
(usa "git add <archivo>..." 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 no hacemos nada puee 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

	
!cd notebook_git && echo "api_keys.py" >> .gitignore
Copy

Veamos qué pasa si ahora hacemos git status

	
!cd notebook_git && echo "api_keys.py" >> .gitignore
!cd notebook_git && git status
Copy
	
En la rama master
Archivos sin seguimiento:
(usa "git add <archivo>..." 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í que contempla .gitignore, por lo que hacemos un commit para añadir .gitignore

	
!cd notebook_git && git add .gitignore && git commit -m "Añadido .gitignore"
Copy
	
[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 variable 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 arhivos de configuración, estaría bien poderle decir a git que siempre ignore esos archivos, para ello creamos un .gitignore global

	
!touch ~/.gitignore_global
Copy

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

	
!touch ~/.gitignore_global
!echo "__pycache__/" >> ~/.gitignore_global
Copy

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

	
!touch ~/.gitignore_global
!echo "__pycache__/" >> ~/.gitignore_global
!git config --global core.excludesfile ~/.gitignore_global
Copy

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

GitHub tiene un repositorio con .gitignores oara 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 commir

	
!touch ~/.gitignore_global
!echo "__pycache__/" >> ~/.gitignore_global
!git config --global core.excludesfile ~/.gitignore_global
!cd notebook_git && echo "print('Este es el archivo 4')" > archivo4.py
Copy
	
!touch ~/.gitignore_global
!echo "__pycache__/" >> ~/.gitignore_global
!git config --global core.excludesfile ~/.gitignore_global
!cd notebook_git && echo "print('Este es el archivo 4')" > archivo4.py
!cd notebook_git && echo "print('Este es el archivo 5')" > archivo5.py
Copy

Hacemos un commit con los dos archivos

	
!touch ~/.gitignore_global
!echo "__pycache__/" >> ~/.gitignore_global
!git config --global core.excludesfile ~/.gitignore_global
!cd notebook_git && echo "print('Este es el archivo 4')" > archivo4.py
!cd notebook_git && echo "print('Este es el archivo 5')" > archivo5.py
!cd notebook_git && git add archivo4.py archivo5.py && git commit -m "Commit con los archivos 4 y 5"
Copy
	
[master e3153a5] Commit con los archivos 4 y 5
2 files changed, 2 insertions(+)
create mode 100644 archivo4.py
create mode 100644 archivo5.py
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* e3153a5 (HEAD -> 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

	
!cd notebook_git && git rm archivo5.py
Copy
	
rm 'archivo5.py'

Hagamos un git status a ver qué ocurre

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

Como vemos se ha borrado archivo5.py. Ahora creamos un nuevo commit

	
!cd notebook_git && git commit -m "Eliminado archivo5.py"
Copy
	
[master ea615a9] Eliminado archivo5.py
1 file changed, 1 deletion(-)
delete mode 100644 archivo5.py
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* ea615a9 (HEAD -> 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

	
!cd notebook_git && echo "print('Este es el archivo 6')" > archivo6.py && echo "print('Este es el archivo 7')" > archivo7.py
Copy
	
!cd notebook_git && echo "print('Este es el archivo 6')" > archivo6.py && echo "print('Este es el archivo 7')" > archivo7.py
!cd notebook_git && git status
Copy
	
En la rama master
Archivos sin seguimiento:
(usa "git add <archivo>..." 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)
	
!cd notebook_git && git add archivo6.py archivo7.py && git commit -m "Commit con los archivos 6 y 7"
Copy
	
[master d6dc485] Commit con los archivos 6 y 7
2 files changed, 2 insertions(+)
create mode 100644 archivo6.py
create mode 100644 archivo7.py
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* d6dc485 (HEAD -> 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

	
!cd notebook_git && git reset --soft HEAD~1
Copy

Hacemos un git status para ver qué ha ocurrido

	
!cd notebook_git && git reset --soft HEAD~1
!cd notebook_git && git status
Copy
	
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
nuevos archivos: archivo6.py
nuevos archivos: archivo7.py

Vemos que he ha deshecho el commit, pero que los dos archivos se encuentran en el área de staged, por lo que para sacar del commir uno de los archivos, primero hay que sacarlo del área de staged, para ello hacemos git reset archivo6.py

	
!cd notebook_git && git reset archivo6.py
Copy

Volvemos ha hacer un git status

	
!cd notebook_git && git reset archivo6.py
!cd notebook_git && git status
Copy
	
En la rama master
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
nuevos archivos: archivo7.py
Archivos sin seguimiento:
(usa "git add <archivo>..." 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

	
!cd notebook_git && git clean -n
Copy
	
Será borrado archivo6.py
	
!cd notebook_git && git clean -f
Copy
	
Borrando archivo6.py

Volvemos a hacer un git status

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

Como vemos archiv6.py ya no está, por lo que podemos hacer un nuevo commit

	
!cd notebook_git && git commit -m "Commit con el archivo 7"
Copy
	
[master 4bb9d75] Commit con el archivo 7
1 file changed, 1 insertion(+)
create mode 100644 archivo7.py
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 4bb9d75 (HEAD -> 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 sobreescrito 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

	
!cd notebook_git && ls
Copy
	
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

	
!cd notebook_git && git log --graph --oneline --decorate hola.py
Copy
	
* 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

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 4bb9d75 (HEAD -> 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

	
!cd notebook_git && git show c4930d7 hola.py
Copy
	
commit c4930d7267c3f8df389ab0cb1bda0b5fceabb5c2
Author: maximofn <maximofn@gmail.com>
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 linea')

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)

	
!cd notebook_git && git diff 1c95e4f hola.py
Copy
	
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

	
!cd notebook_git && git diff 1c95e4f 6e99e73 hola.py
Copy
	
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 el primero, pero si lo que queremos es los cambios del primer commit con respecto el segundo, solo hay que poner los hash al revés de como los hemos puesto, es decir git diff 6e99e73 1c95e4f hola.py

	
!cd notebook_git && git diff 6e99e73 1c95e4f hola.py
Copy
	
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 mediate git reset --hard <hash> (esto no mantendrá los cambios) o git reset --soft <hash> (esto sí mantendrá los cambios)

Primero veamos el historial

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 4bb9d75 (HEAD -> 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

	
!cd notebook_git && ls
Copy
	
api_keys.py archivo1.py archivo2.py archivo4.py archivo7.py hola.py

Vamos al tercer commit

	
!cd notebook_git && git reset --hard c4930d7
Copy
	
HEAD está ahora en c4930d7 Tercer commit, hola.py

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

	
!cd notebook_git && ls
Copy
	
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

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* c4930d7 (HEAD -> 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

	
!cd notebook_git && git reflog
Copy
	
c4930d7 (HEAD -> 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 -> 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 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

	
!cd notebook_git && git reset --hard 4bb9d75
Copy
	
HEAD está ahora en 4bb9d75 Commit con el archivo 7

Si ahora volvemos a hacer un log

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 4bb9d75 (HEAD -> 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

Busqueda en ficheros (git grep <palabra>)link image 40

Si queremos buscar en ficheros podemos hacerlo con la el comando git grep. Como en 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

	
!git clone https://github.com/facebookresearch/segment-anything.git
Copy
	
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 cuantas veces se ha escrito la palabra softmax

	
!cd segment-anything && git grep softmax
Copy
	
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é lineas de los archivos se ha escrito usamos el flag -n

	
!cd segment-anything && git grep -n softmax
Copy
	
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 cuantas veces aparece la palabra podemos usar el flag -c

	
!cd segment-anything && git grep -c softmax
Copy
	
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á en las líneas 236 y 233 respectivamente

Busqueda en commits (git log -S <palabra>)link image 41

Si lo que queremos es buscar en el historial de commit 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

	
!cd segment-anything && git log -S "collab"
Copy
	
commit 2780a301de4483e5c46edb230ea781556159c658
Author: Eric Mintun <eric.mintun@gmail.com>
Date: Mon Apr 10 10:50:17 2023 -0700
Fix typo in notebook 'using_collab'->'using_colab' in other two notebooks.
commit 2c11ea23525970ac288f23dc74b203bcbfb4cc6a
Author: jp-x-g <jpxg-dev@protonmail.com>
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 <eric.mintun@gmail.com>
Date: Wed Apr 5 06:13:09 2023 -0700
Fix broken links in notebook Colab setup.
commit 571794162e0887c15d12b809505b902c7bf8b4db
Author: Eric Mintun <eric.mintun@gmail.com>
Date: Tue Apr 4 22:25:49 2023 -0700
Initial commit

Borramos la carpeta de SAM

	
!rm -r segment-anything
Copy

Ramaslink image 42

branches

El uso de ramas es muy útil, ya que podemos empezar a desarrollar una nueva característica sin tener que modificar el código original

Crear una rama (git branch <branch name>)link image 43

Nota: Antes de nada hay que decir que para crear una rama en un repositorio debe haber al menos un commit, si se intenta crear una rama antes de hacer el primer commit recibiremos un error

Para crear una rama utilizamos el comando git branch <nombre de la rama>

	
!rm -r segment-anything
!cd notebook_git && git branch new_branch
Copy

Listar ramas (git branch)link image 44

Hemos creado nuestra primera rama, podemos comprobar todas las ramas que tenemos creadas escribiéndo solo git branch

	
!rm -r segment-anything
!cd notebook_git && git branch new_branch
!cd notebook_git && git branch
Copy
	
* master
new_branch

Además de listar nos dice con un asterisco * en qué rama estamos, en este caso en la rama master

Renombrar ramas, adios a la rama master (git branch -m <old name> <new name>)link image 45

Históricamente en git se ha llamado master a la rama principal, pero esto tiene unas connotaciones historicas malas por el concepto de master-slave (maestro-esclavo), debido al sufrimiento que recibieron muchas personas, por lo que ahora se suele catalogar la rama principal como main, así que para cambiarle el nombre usamos git branch -m master main

	
!cd notebook_git && git branch -m master main
Copy

Listamos las ramas

	
!cd notebook_git && git branch -m master main
!cd notebook_git && git branch
Copy
	
* main
new_branch

Como vemos hemos podido cambiar el nombre de la rama principal de master a main

Cambiar de rama (git switch <branch>)link image 46

Si queremos cambiar de rama solo hay que escribir git switch <nombre de la rama>

	
!cd notebook_git && git switch new_branch
Copy
	
Cambiado a rama 'new_branch'

Vamos a ver en qué rama estamos con git branch

	
!cd notebook_git && git branch
Copy
	
main
* new_branch

Como vemos hemos cambiado de rama a new_branch

Si queremos crear y cambiar de rama en un solo comando podemos usar git switch -c <nombre de la rama>

	
!cd notebook_git && git switch -c new_branch2
Copy
	
Cambiado a nueva rama 'new_branch2'

Vamos a ver en qué rama estamos

	
!cd notebook_git && git branch
Copy
	
main
new_branch
* new_branch2

Hemos creado y cambiado de rama con un solo comando

Obtener la rama en la que estamos (git branch --show-current)link image 47

Como hemos visto hasta ahora con git branch podemos obtener una lista de todas las ramas y además ver en la que estamos actualmente, pero en el caso en el que tengamos una gran cantidad de ramas, cosa que se puede dar en un equipo de trabajo con mucha gente, está bien obtener la rama y no obtener una lista de todas, para eso usamos git branch --show-current

	
!cd notebook_git && git branch --show-current
Copy
	
new_branch2

Lista de ramas más recientes (git branch --sort=-committerdate)link image 48

En caso de tener muchas ramas a lo mejor nos interesa saber cuales son las más recientes para ver cuales han sido las últimas creadas y donde debería estar lo último en desarrollo, para eso usamos git branch --sort=-committerdate

	
!cd notebook_git && git branch --sort=-committerdate
Copy
	
* new_branch2
new_branch
main

Como vemos las ha ordenado en orden inverso a cuando las hemos creado

El comando deprecado git checkoutlink image 49

Hasta hace un tiempo el comando para crear ramas y cambiar entre ellas era git checkout, pero este comando no solo hace esto, sino que también restaura el directorio de trabajo. Pero esto va en contra de la filosofía de Linux, por lo que se crearon los comando git branch, git swicth y git restore para dividir esta funcionalidad

Fusionando ramas (git merge)link image 50

Como hemos dicho, el crear ramas es muy util para desarrollar nuevas características sin afectar al resto del equipo. Pero cuando estas están terminadas hay que llevarlas a la rama principal, para ello utilizamos el comando git merge <rama>

Importante: Tenemos que estar en la rama que va a adoptar los cambios, es decir, si queremos fusionar los cambios realizados en la rama new_branch2 en la rama main, primero tenemos que asegurarnos de estar en la rama main

Primero comprobamos en qué rama estamos

	
!cd notebook_git && git branch --show-current
Copy
	
new_branch2

Eliminamos archivo7.py

	
!cd notebook_git && git rm archivo7.py
Copy
	
rm 'archivo7.py'

Hacemos un commit con los cambios

	
!cd notebook_git && git commit -am "Eliminado archivo7.py"
Copy
	
[new_branch2 5168f78] Eliminado archivo7.py
1 file changed, 1 deletion(-)
delete mode 100644 archivo7.py

Si hacemos un ls vemos que archivo7.py ya no está

	
!cd notebook_git && ls | grep archivo7
Copy

Creamos un nuevo archivo y hacemos un commit

	
!cd notebook_git && ls | grep archivo7
!cd notebook_git && touch archivo8.py && git add archivo8.py && git commit -m "Commit con el archivo 8"
Copy
	
[new_branch2 564ccfb] Commit con el archivo 8
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 archivo8.py

Hemos hecho dos commits nuevos en esta rama, veamoslo con git log

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 564ccfb (HEAD -> new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch, main) 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

Cambiamos a la rama principal

	
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'

Si ahora hacemos otra vez ls veremos que archivo7.py sí está

	
!cd notebook_git && ls | grep archivo7
Copy
	
archivo7.py

Fusionamos las ramas, traemos los cambios de new_branch2 a main

	
!cd notebook_git && git merge new_branch2
Copy
	
Actualizando 4bb9d75..564ccfb
Fast-forward
archivo7.py | 1 -
archivo8.py | 0
2 files changed, 1 deletion(-)
delete mode 100644 archivo7.py
create mode 100644 archivo8.py

Hacemos un git status

	
!cd notebook_git && git status
Copy
	
En la rama main
nada para hacer commit, el árbol de trabajo está limpio

Vemos que al hacer el merge no es necesario hacer ningún commit, veamos con un git log qué ha pasado

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 564ccfb (HEAD -> main, new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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 el commit de la rama new_branch2 se ha incorporado a esta rama

Fast-forwardlink image 51

Este caso creamos una nueva rama, la principal no la tocamos y solo modificamos la nueva, realizando varios commits. Por lo que al unir la nueva en la principal se verán todos los commits que se habían hecho en la nueva. Para realizar este tipo de merge escribimos git merge --ff-only <rama>

### Este código es para crear el gráfico de las ramas, no es necesario para el curso
      
      import graphviz
      
      # Crear el gráfico con la dirección de las flechas de izquierda a derecha
      orin = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
      fast_foward = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
      
      # Agregar nodos (pelotas) A, B, C y D en la rama principal
      orin.node('A', shape='circle', label='A', color='blue')
      orin.node('B', shape='circle', label='B', color='blue')
      orin.node('C', shape='circle', label='C', color='blue')
      orin.node('D', shape='circle', label='D', color='blue')
      orin.node('E', shape='circle', label='', color='transparent')
      fast_foward.node('A', shape='circle', label='A', color='blue')
      fast_foward.node('B', shape='circle', label='B', color='blue')
      fast_foward.node('C', shape='circle', label='C', color='blue')
      fast_foward.node('D', shape='circle', label='D', color='blue')
      
      # Agregar nodos (pelotas) X e Y en la rama secundaria
      orin.node('X', shape='circle', label='X', color='green')
      orin.node('Y', shape='circle', label='Y', color='green')
      fast_foward.node('X', shape='circle', label='X', color='magenta')
      fast_foward.node('Y', shape='circle', label='Y', color='magenta')
      
      # Agregar flechas entre los nodos en la rama principal
      orin.edges(['AB', 'BC', 'CD'])
      orin.edge('D', 'E', color='transparent')  # Hacer la flecha de C a D transparente
      fast_foward.edges(['AB', 'BC', 'CD', 'DX', 'XY'])
      
      # Agregar flechas entre los nodos en la rama secundaria
      orin.edges(['DX', 'XY'])
      
      # Mostrar el diagrama de flujo en la celda de código de Jupyter Notebook
      display(orin)
      display(fast_foward)
      
No description has been provided for this image
No description has been provided for this image

Vamos primero a comprobar que estamos en la rama principal

	
### Este código es para crear el gráfico de las ramas, no es necesario para el curso
import graphviz
# Crear el gráfico con la dirección de las flechas de izquierda a derecha
orin = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
fast_foward = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
# Agregar nodos (pelotas) A, B, C y D en la rama principal
orin.node('A', shape='circle', label='A', color='blue')
orin.node('B', shape='circle', label='B', color='blue')
orin.node('C', shape='circle', label='C', color='blue')
orin.node('D', shape='circle', label='D', color='blue')
orin.node('E', shape='circle', label='', color='transparent')
fast_foward.node('A', shape='circle', label='A', color='blue')
fast_foward.node('B', shape='circle', label='B', color='blue')
fast_foward.node('C', shape='circle', label='C', color='blue')
fast_foward.node('D', shape='circle', label='D', color='blue')
# Agregar nodos (pelotas) X e Y en la rama secundaria
orin.node('X', shape='circle', label='X', color='green')
orin.node('Y', shape='circle', label='Y', color='green')
fast_foward.node('X', shape='circle', label='X', color='magenta')
fast_foward.node('Y', shape='circle', label='Y', color='magenta')
# Agregar flechas entre los nodos en la rama principal
orin.edges(['AB', 'BC', 'CD'])
orin.edge('D', 'E', color='transparent') # Hacer la flecha de C a D transparente
fast_foward.edges(['AB', 'BC', 'CD', 'DX', 'XY'])
# Agregar flechas entre los nodos en la rama secundaria
orin.edges(['DX', 'XY'])
# Mostrar el diagrama de flujo en la celda de código de Jupyter Notebook
display(orin)
display(fast_foward)
!cd notebook_git && git branch --show-current
Copy
	
main

Creamos una nueva rama

	
!cd notebook_git && git branch branch_fast_forward
Copy

Cambiamos a ella

	
!cd notebook_git && git branch branch_fast_forward
!cd notebook_git && git switch branch_fast_forward
Copy
	
Cambiado a rama 'branch_fast_forward'
	
!cd notebook_git && git branch --show-current
Copy
	
branch_fast_forward

Vamos a ver el log

	
!cd notebook_git && git log --graph --oneline --decorate --all
Copy
	
* 564ccfb (HEAD -> branch_fast_forward, new_branch2, main) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Vale, estamos en una rama creada a partir de la principal con todo su historial de logs, hacemos dos nuevos commits

	
!cd notebook_git && git rm archivo4.py && git commit -am "Eliminado archivo4.py"
Copy
	
rm 'archivo4.py'
[branch_fast_forward 4484e70] Eliminado archivo4.py
1 file changed, 1 deletion(-)
delete mode 100644 archivo4.py
	
!cd notebook_git && git rm hola.py && git commit -am "Eliminado hola.py"
Copy
	
rm 'hola.py'
[branch_fast_forward 94149fc] Eliminado hola.py
1 file changed, 3 deletions(-)
delete mode 100644 hola.py

Hacemos un nuevo log para ver que en esta nueva rama se han creado

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 94149fc (HEAD -> branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2, main) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Como vemos los dos últimos commits son los que hemos creado y podemos comprobar que esos commits no están en la rama principal (para eso especifico que lo haga sobre la rama main)

	
!cd notebook_git && git log main --graph --oneline --decorate
Copy
	
* 564ccfb (new_branch2, main) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Ahora nos vamos a la rama main para hacer el merge

	
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'

Por último hacemos el merge de tipo fast forward

	
!cd notebook_git && git merge --ff-only branch_fast_forward
Copy
	
Actualizando 564ccfb..94149fc
Fast-forward
archivo4.py | 1 -
hola.py | 3 ---
2 files changed, 4 deletions(-)
delete mode 100644 archivo4.py
delete mode 100644 hola.py

Se ha hecho el merge, veamos qué ha pasado con el log en la rama main

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 94149fc (HEAD -> main, branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Como se ve, se han mantenido los dos commits hechos en la rana `branch_fast_forward

No fast-forward o true mergelink image 52

Este caso creamos una nueva rama, la principal no la tocamos y modificamos la nueva, realizando varios commits. A continuación realizamos un commit en la principal. Por lo que al unir la nueva en la principal se verá un único commit en la nueva. Para hacer este tipo de merge escribimos git merge <rama> --no-ff

### Este código es para crear el gráfico de las ramas, no es necesario para el curso
      
      import graphviz
      
      # Crear el gráfico con la dirección de las flechas de izquierda a derecha
      orin = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
      not_fast_forward = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
      
      # Agregar nodos (pelotas) A, B, C y D en la rama principal
      orin.node('A', shape='circle', label='A', color='blue')
      orin.node('B', shape='circle', label='B', color='blue')
      orin.node('C', shape='circle', label='C', color='blue')
      orin.node('D', shape='circle', label='D', color='blue')
      orin.node('E', shape='circle', label='', color='transparent')
      not_fast_forward.node('A', shape='circle', label='A', color='blue')
      not_fast_forward.node('B', shape='circle', label='B', color='blue')
      not_fast_forward.node('C', shape='circle', label='C', color='blue')
      not_fast_forward.node('D', shape='circle', label='D', color='blue')
      not_fast_forward.node('E', shape='circle', label='E', color='blue')
      
      # Agregar nodos (pelotas) X e Y en la rama secundaria
      orin.node('X', shape='circle', label='X', color='green')
      orin.node('Y', shape='circle', label='Y', color='green')
      not_fast_forward.node('X', shape='circle', label='X', color='green')
      not_fast_forward.node('Y', shape='circle', label='Y', color='green')
      
      # Agregar nodo (pelota) M en la rama principal
      not_fast_forward.node('M', shape='circle', label='M', color='magenta')
      
      # Agregar flechas entre los nodos en la rama principal
      orin.edges(['AB', 'BC', 'CD'])
      orin.edge('D', 'E', color='transparent')  # Hacer la flecha de C a D transparente
      not_fast_forward.edges(['AB', 'BC', 'CD', 'DE'])
      
      # Agregar flechas entre los nodos en la rama secundaria
      orin.edges(['DX', 'XY'])
      not_fast_forward.edges(['DX', 'XY', 'YM'])
      
      # Agregar flechas de la rama principal al nodo M
      not_fast_forward.edge('E', 'M')
      
      # Mostrar el diagrama de flujo en la celda de código de Jupyter Notebook
      display(orin)
      display(not_fast_forward)
      
No description has been provided for this image
No description has been provided for this image

Vamos primero a comprobar que estamos en la rama principal

	
### Este código es para crear el gráfico de las ramas, no es necesario para el curso
import graphviz
# Crear el gráfico con la dirección de las flechas de izquierda a derecha
orin = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
not_fast_forward = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
# Agregar nodos (pelotas) A, B, C y D en la rama principal
orin.node('A', shape='circle', label='A', color='blue')
orin.node('B', shape='circle', label='B', color='blue')
orin.node('C', shape='circle', label='C', color='blue')
orin.node('D', shape='circle', label='D', color='blue')
orin.node('E', shape='circle', label='', color='transparent')
not_fast_forward.node('A', shape='circle', label='A', color='blue')
not_fast_forward.node('B', shape='circle', label='B', color='blue')
not_fast_forward.node('C', shape='circle', label='C', color='blue')
not_fast_forward.node('D', shape='circle', label='D', color='blue')
not_fast_forward.node('E', shape='circle', label='E', color='blue')
# Agregar nodos (pelotas) X e Y en la rama secundaria
orin.node('X', shape='circle', label='X', color='green')
orin.node('Y', shape='circle', label='Y', color='green')
not_fast_forward.node('X', shape='circle', label='X', color='green')
not_fast_forward.node('Y', shape='circle', label='Y', color='green')
# Agregar nodo (pelota) M en la rama principal
not_fast_forward.node('M', shape='circle', label='M', color='magenta')
# Agregar flechas entre los nodos en la rama principal
orin.edges(['AB', 'BC', 'CD'])
orin.edge('D', 'E', color='transparent') # Hacer la flecha de C a D transparente
not_fast_forward.edges(['AB', 'BC', 'CD', 'DE'])
# Agregar flechas entre los nodos en la rama secundaria
orin.edges(['DX', 'XY'])
not_fast_forward.edges(['DX', 'XY', 'YM'])
# Agregar flechas de la rama principal al nodo M
not_fast_forward.edge('E', 'M')
# Mostrar el diagrama de flujo en la celda de código de Jupyter Notebook
display(orin)
display(not_fast_forward)
!cd notebook_git && git branch --show-current
Copy
	
main

Creamos una nueva rama

	
!cd notebook_git && git branch branch_no_fast_forward
Copy

Cambiamos a ella

	
!cd notebook_git && git branch branch_no_fast_forward
!cd notebook_git && git switch branch_no_fast_forward
Copy
	
Cambiado a rama 'branch_no_fast_forward'
	
!cd notebook_git && git branch --show-current
Copy
	
branch_no_fast_forward

Vale, estamos en una rama creada a partir de la principal con todo su historial de logs, hacemos dos nuevos commits

	
!cd notebook_git && touch file1 && git add file1 && git commit -m "file1"
Copy
	
[branch_no_fast_forward e4e23c9] file1
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file1
	
!cd notebook_git && touch file2 && git add file2 && git commit -m "file2"
Copy
	
[branch_no_fast_forward 8df3429] file2
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file2

Hacemos un nuevo log para ver que en esta nueva rama se han creado

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 8df3429 (HEAD -> branch_no_fast_forward) file2
* e4e23c9 file1
* 94149fc (main, branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Como vemos los dos últimos commits son los que hemos creado y podemos comprobar que esos commits no están en la rama principal (para eso especifico que lo haga sobre la rama main)

	
!cd notebook_git && git log main --graph --oneline --decorate
Copy
	
* 94149fc (main, branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Ahora nos vamos a la rama main

	
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'

Creamos un nuevo commit

	
!cd notebook_git && touch file3 && git add file3 && git commit -m "file3"
Copy
	
[main 8bdf4d8] file3
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file3

Por último hacemos el merge de tipo no fast forward

	
!cd notebook_git && git merge branch_no_fast_forward --no-ff
Copy
	
ommit. comenzando con '#' serán ignoradas, y un mensaje vacío abortasaria esta># especialmente si esto fusiona un upstream actualizado en una rama de tópico. /home/wallabot/Documentos/web/portafolio/posts/notebook_git/.git/MERGE_MSG [ línea 1/7 (14%), col 1/48 (2%), car 0/301 (0%) ] [ Párrafo justificado ]...llabot/Documentos/web/portafolio/posts/notebook_git/.git/MERGE_MSG Modificado

Como vemos nos abre el editor para introducir un mensaje de commit y un mensaje por defecto. Aceptamos el mensaje y vemos qué ha pasado

	
!cd notebook_git && git status
Copy
	
En la rama main
nada para hacer commit, el árbol de trabajo está limpio
	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 274529c (HEAD -> main) Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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
	
!cd notebook_git && ls
Copy
	
api_keys.py archivo1.py archivo2.py archivo8.py file1 file2 file3

Como vemos se ha creado un nuevo commit con los cambios de la nueva rama en la rama principal

Squashlink image 53

En este tipo de fusión, todos los commits de una nueva rama se juntan en uno solo en la rama principal, para esto escribimos git merge <rama> --squash

### Este código es para crear el gráfico de las ramas, no es necesario para el curso
      
      import graphviz
      
      # Crear el gráfico con la dirección de las flechas de izquierda a derecha
      orin = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
      squash = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
      
      # Agregar nodos (pelotas) A, B, C y D en la rama principal
      orin.node('A', shape='circle', label='A', color='blue')
      orin.node('B', shape='circle', label='B', color='blue')
      orin.node('C', shape='circle', label='C', color='blue')
      orin.node('D', shape='circle', label='D', color='blue')
      orin.node('E', shape='circle', label='', color='transparent')
      squash.node('A', shape='circle', label='A', color='blue')
      squash.node('B', shape='circle', label='B', color='blue')
      squash.node('C', shape='circle', label='C', color='blue')
      squash.node('D', shape='circle', label='D', color='blue')
      
      # Agregar nodos (pelotas) X e Y en la rama secundaria
      orin.node('X', shape='circle', label='X', color='green')
      orin.node('Y', shape='circle', label='Y', color='green')
      
      # Agregar nodo (pelota) M en la rama principal
      squash.node('M', shape='circle', label='M', color='magenta')
      
      # Agregar flechas entre los nodos en la rama principal
      orin.edges(['AB', 'BC', 'CD'])
      orin.edge('D', 'E', color='transparent')  # Hacer la flecha de C a D transparente
      squash.edges(['AB', 'BC', 'CD', 'DM'])
      
      # Agregar flechas entre los nodos en la rama secundaria
      orin.edges(['DX', 'XY'])
      
      # Mostrar el diagrama de flujo en la celda de código de Jupyter Notebook
      display(orin)
      display(squash)
      
No description has been provided for this image
No description has been provided for this image

Vamos primero a comprobar que estamos en la rama principal

	
### Este código es para crear el gráfico de las ramas, no es necesario para el curso
import graphviz
# Crear el gráfico con la dirección de las flechas de izquierda a derecha
orin = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
squash = graphviz.Digraph('G', graph_attr={'rankdir': 'LR'})
# Agregar nodos (pelotas) A, B, C y D en la rama principal
orin.node('A', shape='circle', label='A', color='blue')
orin.node('B', shape='circle', label='B', color='blue')
orin.node('C', shape='circle', label='C', color='blue')
orin.node('D', shape='circle', label='D', color='blue')
orin.node('E', shape='circle', label='', color='transparent')
squash.node('A', shape='circle', label='A', color='blue')
squash.node('B', shape='circle', label='B', color='blue')
squash.node('C', shape='circle', label='C', color='blue')
squash.node('D', shape='circle', label='D', color='blue')
# Agregar nodos (pelotas) X e Y en la rama secundaria
orin.node('X', shape='circle', label='X', color='green')
orin.node('Y', shape='circle', label='Y', color='green')
# Agregar nodo (pelota) M en la rama principal
squash.node('M', shape='circle', label='M', color='magenta')
# Agregar flechas entre los nodos en la rama principal
orin.edges(['AB', 'BC', 'CD'])
orin.edge('D', 'E', color='transparent') # Hacer la flecha de C a D transparente
squash.edges(['AB', 'BC', 'CD', 'DM'])
# Agregar flechas entre los nodos en la rama secundaria
orin.edges(['DX', 'XY'])
# Mostrar el diagrama de flujo en la celda de código de Jupyter Notebook
display(orin)
display(squash)
!cd notebook_git && git branch --show-current
Copy
	
main

Creamos una nueva rama

	
!cd notebook_git && git branch branch_squash
Copy

Cambiamos a ella

	
!cd notebook_git && git branch branch_squash
!cd notebook_git && git switch branch_squash
Copy
	
Cambiado a rama 'branch_squash'
	
!cd notebook_git && git branch --show-current
Copy
	
branch_squash

Vamos a ver el log

	
!cd notebook_git && git log --graph --oneline --decorate --all
Copy
	
* 274529c (HEAD -> branch_squash, main) Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Vale, estamos en una rama creada a partir de la principal con todo su historial de logs, hacemos tres nuevos commits

	
!cd notebook_git && git rm file1 && git commit -am "Eliminado file1"
Copy
	
rm 'file1'
[branch_squash 767b632] Eliminado file1
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file1
	
!cd notebook_git && git rm file2 && git commit -am "Eliminado file2"
Copy
	
rm 'file2'
[branch_squash a47f771] Eliminado file2
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file2
	
!cd notebook_git && git rm file3 && git commit -am "Eliminado file3"
Copy
	
rm 'file3'
[branch_squash 85f8c9f] Eliminado file3
1 file changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file3

Hacemos un nuevo log para ver que en esta nueva rama se han creado

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 85f8c9f (HEAD -> branch_squash) Eliminado file3
* a47f771 Eliminado file2
* 767b632 Eliminado file1
* 274529c (main) Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Como vemos los tres últimos commits son los que hemos creado y podemos comprobar que esos commits no están en la rama principal (para eso especifico que lo haga sobre la rama main)

	
!cd notebook_git && git log main --graph --oneline --decorate
Copy
	
* 274529c (main) Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Ahora nos vamos a la rama main para hacer el merge

	
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'

Hacemos el merge de tipo squash

	
!cd notebook_git && git merge branch_squash --squash
Copy
	
Actualizando 274529c..85f8c9f
Fast-forward
Commit de aplastamiento -- no actualizando HEAD
file1 | 0
file2 | 0
file3 | 0
3 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file1
delete mode 100644 file2
delete mode 100644 file3

Se ha hecho el merge, veamos qué ha pasado con el log en la rama main

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 274529c (HEAD -> main) Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

No aparecen los cambios realizados en la rama, hagamos un git status

	
!cd notebook_git && git status
Copy
	
En la rama main
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
borrados: file1
borrados: file2
borrados: file3

Vemos que tenemos que hacer el commit con la fusión. Esto es porque git no sabe qué mensaje ponerle y nos deja a nosotros que lo hagamos, de modo que lo hacemos

	
!cd notebook_git && git commit -m "Merge squash de los commits de la rama branch_squash"
Copy
	
[main 52acb97] Merge squash de los commits de la rama branch_squash
3 files changed, 0 insertions(+), 0 deletions(-)
delete mode 100644 file1
delete mode 100644 file2
delete mode 100644 file3

Volvemos a hacer un git log

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 52acb97 (HEAD -> main) Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Conflictos a la hora de fusionarlink image 54

Cuando se fusionan ramas puede pasar que un mismo archivo haya sido modificado en varias ramas. Esto puede ser normal en proyectos donde varias personas están desarrollando, así que vamos a ver cómo solucionarlo

Creamos un conflictolink image 55

Comprobamos que estamos en la rama main

	
!cd notebook_git && git branch --show-current
Copy
	
main

Creamos una nueva rama a partir de esta

	
!cd notebook_git && git branch rama_con_conflicto
Copy

Añadimos una línea al archivo archivo1.py, recordamos que estamos en la rama main

	
!cd notebook_git && git branch rama_con_conflicto
!cd notebook_git && echo "print('rama main')" >> archivo1.py
Copy
	
!cd notebook_git && git branch rama_con_conflicto
!cd notebook_git && echo "print('rama main')" >> archivo1.py
!cd notebook_git && cat archivo1.py
Copy
	
print('Este es el archivo 1')
print('rama main')

archivo1.py está modificado, hacemos un commit

	
!cd notebook_git && git add archivo1.py && git commit -m "archivo1.py en rama main"
Copy
	
[main 53f909b] archivo1.py en rama main
1 file changed, 1 insertion(+)

Ahora nos vamos a la rama rama_con_conflicto y añadimos una nueva linea a archivo1.py

	
!cd notebook_git && git switch rama_con_conflicto
Copy
	
Cambiado a rama 'rama_con_conflicto'
	
!cd notebook_git && git branch --show-current
Copy
	
rama_con_conflicto
	
!cd notebook_git && echo "print('rama rama_con_conflicto')" >> archivo1.py
Copy
	
!cd notebook_git && echo "print('rama rama_con_conflicto')" >> archivo1.py
!cd notebook_git && cat archivo1.py
Copy
	
print('Este es el archivo 1')
print('rama rama_con_conflicto')

Como vemos archivo1.py no es igual en la rama main y en la rama rama_con_conflicto. Hacemos un commit con la modificación de archivo1.py en la rama rama_con_conflicto

	
!cd notebook_git && git add archivo1.py && git commit -m "archivo1.py en rama rama_con_conflicto"
Copy
	
[rama_con_conflicto 32851c3] archivo1.py en rama rama_con_conflicto
1 file changed, 1 insertion(+)

Volvemos a la rama main

	
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'
	
!cd notebook_git && git branch --show-current
Copy
	
main

Hacemos un merge de la rama rama_con_conflicto

	
!cd notebook_git && git merge rama_con_conflicto
Copy
	
Auto-fusionando archivo1.py
CONFLICTO (contenido): Conflicto de fusión en archivo1.py
Fusión automática falló; arregle los conflictos y luego realice un commit con el resultado.

Al hacer el merge ya nos avisa que hay un conflicto en archivo1.py y que no se ha podido hacer el merge. Hacemos un git status

	
!cd notebook_git && git status
Copy
	
En la rama main
Tienes rutas no fusionadas.
(arregla los conflictos y ejecuta "git commit"
(usa "git merge --abort" para abortar la fusion)
Rutas no fusionadas:
(usa "git add <archivo>..." para marcar una resolución)
modificados por ambos: archivo1.py
sin cambios agregados al commit (usa "git add" y/o "git commit -a")

Nos dice lo mismo, pero nos da más información, nos dice que podemos abortar la fusión con git merge --abort. Pero en vez de eso vamos a solucionarlo

Solucionar un conflictolink image 56

En nuestro caso sabemos dónde está el problema, pero en caso de no saberlo, mediante git diff podemos encontrar el problema

	
!cd notebook_git && git diff archivo1.py
Copy
	
diff --cc archivo1.py
index 8b4bf58,b5c003c..0000000
--- a/archivo1.py
+++ b/archivo1.py
@@@ -1,2 -1,2 +1,6 @@@
print('Este es el archivo 1')
++<<<<<<< HEAD
+print('rama main')
++=======
+ print('rama rama_con_conflicto')
++>>>>>>> rama_con_conflicto

git diff nos está diciendo que el problema está en la última líea. La versión del archivo de la rama HEAD (en la que estamos actualmente main) tiene print('rama main') en la última línea, mientras que la versión de la rama rama_con_conflicto tiene print('rama rama_con_conflicto') en la última línea. De modo que hay que abrir el fichero con cualquier editor y solucionar esto.

Tras editar el fichero con mi editor de código he quitado todas las líneas que sobran y se ha quedado así

	
!cd notebook_git && cat archivo1.py
Copy
	
print('Este es el archivo 1')
print('rama main')

Ahora hacemos un git status para ver qué tenemos que hacer

	
!cd notebook_git && git status
Copy
	
En la rama main
Tienes rutas no fusionadas.
(arregla los conflictos y ejecuta "git commit"
(usa "git merge --abort" para abortar la fusion)
Rutas no fusionadas:
(usa "git add <archivo>..." para marcar una resolución)
modificados por ambos: archivo1.py
sin cambios agregados al commit (usa "git add" y/o "git commit -a")

Nos dice que tenemos el archivo archivo1.py con modificaciones, por lo que lo añadimos al área de staged y luego hacemos un commit

	
!cd notebook_git && git add archivo1.py && git commit -m "archivo1.py con el merge resuelto"
Copy
	
[main 679bb49] archivo1.py con el merge resuelto

Volvemos a hacer un git status a ver si se ha resuelto

	
!cd notebook_git && git status
Copy
	
En la rama main
nada para hacer commit, el árbol de trabajo está limpio

Parece que se ha resuelto, hacemos un git log para comprobarlo

	
!cd notebook_git && git log --graph --oneline --decorate
Copy
	
* 679bb49 (HEAD -> main) archivo1.py con el merge resuelto
|
| * 32851c3 (rama_con_conflicto) archivo1.py en rama rama_con_conflicto
* | 53f909b archivo1.py en rama main
|/
* 52acb97 Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Eliminar ramaslink image 57

La idea de una rama es abrirla para desarrollar una nueva funcionalidad o característica de manera que no afecte al resto del equipo de desarrollo. Por lo tanto cuando esto está conseguido se fusiona con la rama principal. Así que después de la fusión ya no tiene sentido mantener la rama por lo que hay que eliminarla, pero se hará de una manera diferente si la rama se ha fusionado o no con la principal

Eliminar ramas que se han fusionado (git branch -d <rama>)link image 58

Para eliminar una rama sobre la que ya se ha hecho la fusión con la principal solo hay que hacer git branch -d <rama> o git branch --delete <rama>. Vamos a eliminar la última rama que hemos creado y fusionado

	
!cd notebook_git && git branch -d rama_con_conflicto
Copy
	
Eliminada la rama rama_con_conflicto (era 32851c3).

Si ahora listamos todas las ramas podemos ver que ya no tendremos rama_con_conflicto

	
!cd notebook_git && git branch
Copy
	
branch_fast_forward
branch_no_fast_forward
branch_squash
* main
new_branch
new_branch2

Eliminar ramas que no se han fusionado con la rama principal (git brnach -D <rama>)link image 59

Si intentamos hacer lo mismo que antes con una rama que nunca se ha fusionado con otra obtendremos un error

Vamos a crear una nueva rama, vamos a hacer un commit y no la vamos a fusionar

	
!cd notebook_git && git branch branch_sin_fusion
Copy
	
!cd notebook_git && git branch branch_sin_fusion
!cd notebook_git && git switch branch_sin_fusion
Copy
	
Cambiado a rama 'branch_sin_fusion'
	
!cd notebook_git && touch file4 && git add file4 && git commit -m "file4"
Copy
	
[branch_sin_fusion 9506b0a] file4
1 file changed, 0 insertions(+), 0 deletions(-)
create mode 100644 file4
	
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'

Con todo lo que hemos aprendidod hasta ahora, podemos ver que lo que hemos hecho ha sido crear una nueva rama, cambiar a ella, crear un nuevo archivo, hacer un commit y volver a la rama main. Ahora vamos a intentar eliminar esta nueva rama

	
!cd notebook_git && git branch -d branch_sin_fusion
Copy
	
error: La rama 'branch_sin_fusion' no ha sido fusionada completamente.
Si estás seguro de querer borrarla, ejecuta 'git branch -D branch_sin_fusion'.

Como vemos nos dice que branch_sin_fusion no ha sido fusionada por lo que no se ha eliminado y que si estamos seguros de eliminarla tenemos que hacer git branch -D branch_sin_fusion, de modo que lo hacemos para eliminarla

	
!cd notebook_git && git branch -D branch_sin_fusion
Copy
	
Eliminada la rama branch_sin_fusion (era 9506b0a).

Ahora sí se ha eliminado

Trabajando con repositorios remotoslink image 60

Cuando desarrollamos software no lo solemos hacer solos, solemos trabajar en equipo, por lo que no tiene sentido tener un repositorio local de git, si no tener un repositorio remoto con el que todos trabajemos y compartamos los avances

Nota: El objetivo de este post es explicar git. Para la conexión con repositorios remotos voy a explicarlo con GitHub porque es el servicio de hosting de repositorios git más usado, pero no voy a entrar en profundizar en GitHub

Clonar un repositorio remoto (git clone <repositorio>)link image 61

Si empezamos a trabajar en un repositorio que ya ha sido creado, lo primero que tenemos que hacer es clonarlo, para ello lo que tenemos que hacer es git clone <repositorio>, donde <repositorio> puede ser una URL o una dirección SSH. Como ahora mismo todo el tema de los grnades modelos de lenguaje y ChatGPT están muy de moda, vamos a clonar un repositorio opensource creada por la comunidad, Open-Assistant, para ello haremos git clone https://github.com/LAION-AI/Open-Assistant

	
!git clone https://github.com/LAION-AI/Open-Assistant.git
Copy
	
Clonando en 'Open-Assistant'...
remote: Enumerating objects: 29769, done.
remote: Counting objects: 100% (673/673), done.
remote: Compressing objects: 100% (310/310), done.
remote: Total 29769 (delta 398), reused 577 (delta 354), pack-reused 29096
Recibiendo objetos: 100% (29769/29769), 33.61 MiB | 29.29 MiB/s, listo.
Resolviendo deltas: 100% (19967/19967), listo.

Esto nos crea la carpeta Open-Assistant con todo el código del repositorio, podemos entrar dentro y ver todo el código

	
!cd Open-Assistant && ls
Copy
	
ansible deploy model safety
assets discord-bots notebooks scripts
backend docker oasst-data setup.cfg
CODEOWNERS docker-compose.yaml oasst-shared text-frontend
CONTRIBUTING.md docs pyproject.toml website
copilot inference README.md
data LICENSE redis.conf

Elimino la carpeta

	
!rm -r Open-Assistant
Copy

Enlazar un repositorio local en uno remotolink image 62

Si ocurre al revés, si primero empezamos a desarrollar en local y luego lo queremos sincronizar con un repositorio remoto tenemos que hacer lo siguiente

  • Primero crear un repositorio remoto vacío, en mi caso he creado el repositorio notebook_git en GitHub que más tarde borraré
  • Obtener la URL del repositorio, o dirección SSH
  • Sincronizarlos mediante `git remote add origin

El repositorio vacío que he creado en GitHub se ve así

notebook git repo

En mi caso voy a usar la dirección SSH que es git@github.com:maximofn/notebook_git.git

	
!rm -r Open-Assistant
!cd notebook_git && git remote add origin git@github.com:maximofn/notebook_git.git
Copy

Ya están enlazados, pero para asegurarnos podemos hacer git remote -v

	
!rm -r Open-Assistant
!cd notebook_git && git remote add origin git@github.com:maximofn/notebook_git.git
!cd notebook_git && git remote -v
Copy
	
origin git@github.com:maximofn/notebook_git.git (fetch)
origin git@github.com:maximofn/notebook_git.git (push)

Subir los cambios de un repositorio local a un repositorio remoto (git push)link image 63

Como hemos dicho están enlazados, pero si voy a mi repositorio en GitHub se sigue viendo así

notebook git repo

Están enlazados el repositorio local y el remoto, pero ahora hay que mandar todos los cambios del repositorio local al remoto, para ello habría que usar git push origin <rama local>:<rama remota>, es decir, como nuestra rama principal se llama main y la rama principal en GitHub se llama main habría que hacer git push origin main:main. Si te acuerdas git por defecto llamó a la rama principal master, pero GitHub llama por defecto a la rama principal main por lo que si cada persona llama en su repositorio local a sus ramas de una manera hay que especificar qué rama en local escribe a qué rama en remoto

Se puede configurar la conexión por defecto entre ramas en git, para ello hay que hacer git push --set-upstream origin main. Esto establece relación entre la rama local main y la rama remota main. Una vez hecha esta relación ya solo es necesario hacer git push para subir los cambios que se hacen en local al servidor remoto.

De modo que establecemos la conexión entre ramas

	
!cd notebook_git && git push --set-upstream origin main
Copy
	
Enumerando objetos: 51, listo.
Contando objetos: 100% (51/51), listo.
Compresión delta usando hasta 12 hilos
Comprimiendo objetos: 100% (38/38), listo.
Escribiendo objetos: 100% (51/51), 4.21 KiB | 2.11 MiB/s, listo.
Total 51 (delta 18), reusado 0 (delta 0)
remote: Resolving deltas: 100% (18/18), done.
To github.com:maximofn/notebook_git.git
* [new branch] main -> main
Rama 'main' configurada para hacer seguimiento a la rama remota 'main' de 'origin'.

Ahora ya podemos hace solo git push para subir los cambios locales al repositorio remoto

	
!cd notebook_git && git push
Copy
	
Everything up-to-date

Si ahora volvemos a nuestro repositorio de GitHub se ve así

notebook git repo push

Si hacemos un ls en nuestro repositorio local podremos ver que los archivos que tenemos en el repositorio remoto los tenemos en el repositorio local, es decir, hemos sincornizado el repositorio local y remoto

	
!cd notebook_git && ls -a
Copy
	
. .. api_keys.py archivo1.py archivo2.py archivo8.py .git .gitignore

Los únicos que no está en el repositorio remoto son api_keys.py, que es el que añadimos al archivo .gitignore, es decir, el que dijimos a git que no siguiera. Y .git que es donde está la configuración de nuestro repositorio local y que no se tiene que subir al repositorio remoto, porque cada persona tendrá su propia configuración de git y por tanto no se tiene que sincronizar

Descargar los cambios de un repositorio remoto a un repositorio local (git pull)link image 64

Ahora vamos a hacer al revés, vamos a bajar los nuevos cambios que se hayan hecho en el repositorio remoto. Si nos fijamos en cómo está el repositorio remoto podremos ver que hay un botón que pone Add a README, por lo que le damos para añadirlo

notebook git repo push

Al darle se nos abrirá un editor, dejamos lo que ha puesto GitHub y guardamos los cambios dándole al botón de Commit changes...

noteboot git repo readme

Nos saldrá una ventana en la que nos pedirá un mensaje de commit, dejamos el que viene por defecto y le damos a Comit changes

notebook git repo commit message

Al hacer eso el repositorio se nos quedará así

notebook git repo pull

Se ha creado un nuevo archivo llamado README.MD, pero si hacemos ls en el repositorio local no lo encontraremos

	
!cd notebook_git && ls | grep README
Copy

Por lo que nos tenemos que traer los cambios del repositorio remoto al local, para ello hay que hacer git pull origin <rama remota> para decirle a git sobre qué rama remota vamos a traer los datos, pero al igual que antes podemos establecer una relación entre la rama remota y la rama local de la siguiente manera git branch --set-upstream-to=origin/<rama local> <rama remota>, pero como nuestra rama local se llama main y la rama remota GitHub la llama main habría que cambiar lo anterior por git branch --set-upstream-to=origin/main main.

Una vez hecho esto para descargar los nuevos cambios del repositorio remoto al local solo habría que hacer git pull

Vamos a establecer la relación entre ramas con git branch --set-upstream-to=origin/main main

	
!cd notebook_git && ls | grep README
!cd notebook_git && git branch --set-upstream-to=origin/main main
Copy
	
Rama 'main' configurada para hacer seguimiento a la rama remota 'main' de 'origin'.

Ahora podemos traer los cambios del repositorio remoto al repositorio local con git pull

	
!cd notebook_git && git pull
Copy
	
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 1), reused 0 (delta 0), pack-reused 0
Desempaquetando objetos: 100% (3/3), 646 bytes | 646.00 KiB/s, listo.
Desde github.com:maximofn/notebook_git
679bb49..527e07a main -> origin/main
Actualizando 679bb49..527e07a
Fast-forward
README.md | 1 +
1 file changed, 1 insertion(+)
create mode 100644 README.md

Como vemos dice se ha añadido README.md, lo comprobamos haciendo ls

	
!cd notebook_git && ls | grep README
Copy
	
README.md

Tenemos el archivo en local

Sincronizar las ramas remotas y localeslink image 65

Como hemos visto hemos tenido que sincronizar las ramas remotas y locales para poder subir y bajar los datos, sin embargo, si primero creamos el repositorio en GitHub y después lo clonamos ya no es necesario dicha sincronización

Aliaslink image 66

Cada vez que hemos querido hacer un log hemos usado este comando git log --graph --oneline --decorate, sin embargo acordarse de este comando es bastante complicado, de hecho yo no me acuerdo de el, cada vez que lo he querido usar lo he tenido que buscar porque no lo recordaba, por lo que estaría muy bien tener una manera de abreviarlo.

Para esto git ofrece los alias, de manera que puedes crearte alias de los comandos que tu quieras, para ello tienes que hacer git config --global alias.<nombre del alias> "comando"

Por tanto vamos a llamar git tree al comando git log --graph --oneline --decorate, ya que nos permite ver el historial, con la bifurcación y fusión de ramas como si fuese el crecimiento de un árbol, por lo que hacemos git config --global alias.tree "log --graph --oneline --decorate"

Importante: No hay que poner la palabra git dentro del comando

	
!git config --global alias.tree "log --graph --oneline --decorate"
Copy

Si ahora nos vamos a nuestro repositorio y hacemos git tree veremos el historial como lo hacíamos antes

	
!git config --global alias.tree "log --graph --oneline --decorate"
!cd notebook_git && git tree
Copy
	
* 527e07a (HEAD -> main, origin/main) Create README.md
* 679bb49 archivo1.py con el merge resuelto
|
| * 32851c3 archivo1.py en rama rama_con_conflicto
* | 53f909b archivo1.py en rama main
|/
* 52acb97 Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Como vemos se ha creado nuestro alias

Alias de comandos existentes de gitlink image 67

Se pueden crear alias de comandos que ya existen en git, de hecho, es una práctica que usa mucha gente, sobre todo para abreviar, por lo que vamos a hacer uno. Vamos a hacer un alias del comando git status y lo vamos a renombrar como git st de la siguiente manera git config --global alias.st "status"

	
!git config --global alias.st "status"
Copy

Lo probamos ahora

	
!git config --global alias.st "status"
!cd notebook_git && git st
Copy
	
En la rama main
Tu rama está actualizada con 'origin/main'.
nada para hacer commit, el árbol de trabajo está limpio

Ya tenemos el comando git status simplificado a git st

Alias de comandos que no son de gitlink image 68

Podemos crearnos alias de comandos que no sean de git, por ejemplo, porque creamos que git necesita ese nuevo comando, se hace igual con la excepción de que el comando tiene que ir precedido de !, es decir, sería git config --global alias.<nombre del alias> "!comando"

Cuando hemos visto los conflictos, hemos visto que git nos decía donde estaban, pero para solucionarlos tenemos que editar el código nosotros mismo, por lo que podemos crear un alias de git de manera que podamos abrir un archivo con el editor de textos que queramos, en mi caso voy a crear un alias que me abrirá los archivos con vscode para ello tengo que hacer git config --global alias.code "!code"

	
!git config --global alias.code "!code"
Copy

Lo probamos

	
!git config --global alias.code "!code"
!cd notebook_git && git code README.md
Copy

Tras hacer esto, se me ha abierto README.md en vscode

Lista con todos los aliaslink image 69

En caso de no acordarnos de los alias que hemos creado podemos ver la configuración global de git, pero como esto puede ser un poco abrumador porque nos da mucha información, podemo filtrar para que nos muestre solo los alias que hemos creado, para ello usamos git config --get-regexp ^alias\.

	
!git config --global alias.code "!code"
!cd notebook_git && git code README.md
!git config --get-regexp ^alias.
Copy
	
alias.tree log --graph --oneline --decorate
alias.st status
alias.code !code

Obtenemos los alais que hemos creado

Pero aun mejor, podemos crear un alias para obtener los alias, para ello hacemos git config --global alias.alias "config --get-regexp ^alias\."

	
!git config --global alias.alias "config --get-regexp ^alias."
Copy

Si ahora hacemos git alias

	
!git config --global alias.alias "config --get-regexp ^alias."
!git alias
Copy
	
alias.tree log --graph --oneline --decorate
alias.st status
alias.code !code
alias.alias config --get-regexp ^alias.

Obtenemos la lista con todos nuestros alias

Almacén stash (git stash)link image 70

Supongamos que estamos trabajando en una rama, tenemos varios archivos modificados, no hemos hecho commit, y por la razón que sea tenemos que pasar a otra rama. Por ejemplo, estamos en una rama desarrollando una nueva funcionalidad, y la tenemos que dejar a medias porque hay un bug crítico en la rama main

Una solución sería hacer un commit para guardar los cambios y volver más adelante. Pero a lo mejor hemos dejado el código a medias y no queremos hacer un commit. Así que para ello se inventó el stash, que es como un almacen, donde dejas almacenado tu código para luego poder volver a recuperarlo.

Es una pila, eso quiere decir que lo último que entra es lo primero en salir

Veamos cómo hacerlo, en primer lugar creamos una nueva rama que vamos a llamar new_feature

	
!cd notebook_git && git branch new_feature
Copy

Cambiamos a ella

	
!cd notebook_git && git branch new_feature
!cd notebook_git && git switch new_feature
Copy
	
Cambiado a rama 'new_feature'

Vamos a modificar archivo2.py y archivo8.py

	
!cd notebook_git && echo "print('new_feature')" >> archivo2.py && echo "print('new_feature')" >> archivo8.py
Copy

Hacemos un git status para comprobar que se han modificado

	
!cd notebook_git && echo "print('new_feature')" >> archivo2.py && echo "print('new_feature')" >> archivo8.py
!cd notebook_git && git status
Copy
	
En la rama new_feature
Cambios no rastreados para el commit:
(usa "git add <archivo>..." para actualizar lo que será confirmado)
(usa "git restore <archivo>..." para descartar los cambios en el directorio de trabajo)
modificados: archivo2.py
modificados: archivo8.py
sin cambios agregados al commit (usa "git add" y/o "git commit -a")

Vamos a meter a archivo8.py al área de staged

	
!cd notebook_git && git add archivo8.py
Copy

Volvemos a hacer un git status

	
!cd notebook_git && git add archivo8.py
!cd notebook_git && git status
Copy
	
En la rama new_feature
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
modificados: archivo8.py
Cambios no rastreados para el commit:
(usa "git add <archivo>..." para actualizar lo que será confirmado)
(usa "git restore <archivo>..." para descartar los cambios en el directorio de trabajo)
modificados: archivo2.py

Como vemos tenemos dos archivos modificados, de los cuales uno de ellos además está en el área de staged. Si ahora tuviésemos que cambiar de rama, para no perder los cambios podríamos hacer un commit, o guardarlos en el almacen stash, así que vamos a hacer esto último mediante git stash

	
!cd notebook_git && git stash
Copy
	
Directorio de trabajo y estado de índice WIP on new_feature: 527e07a Create README.md guardados

Si ahora volvemos a hacer git status veamos qué pasa

	
!cd notebook_git && git status
Copy
	
En la rama new_feature
nada para hacer commit, el árbol de trabajo está limpio

Ya no aparecen los archivos con modificaciones, es como si hubiésemos hecho un commit

Importante: Los archivos creados nuevos, que nunca han sido seguidos por git no se irán al almacén, por lo que con los archivos nuevos es necesario, al menos, hacer primero un git add

Si yo ahora creo un archivo nuevo y lo intento llevar al almacén, me dará un error

	
!cd notebook_git && touch archivo9.py
Copy
	
!cd notebook_git && touch archivo9.py
!cd notebook_git && git status
Copy
	
En la rama new_feature
Archivos sin seguimiento:
(usa "git add <archivo>..." para incluirlo a lo que se será confirmado)
archivo9.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)
	
!cd notebook_git && git stash
Copy
	
No hay cambios locales para guardar
	
!cd notebook_git && git status
Copy
	
En la rama new_feature
Archivos sin seguimiento:
(usa "git add <archivo>..." para incluirlo a lo que se será confirmado)
archivo9.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Como vemos archivo9.py no lo ha guardado en el almacén, por lo que habría que haberlo añadido con git add.

	
!cd notebook_git && rm archivo9.py
Copy

Todo al almacén stash (git stash -u -a)link image 71

Como hemos visto solo se mandan al almacen los archivos a los que git les está haciendo seguimiento, pero si tenemos nuevos archivos creados, o arhivos ignorados, no se mandarán, así que para solucionar esto podemos usar los flags -u o --include-untracked para que mande los nuevos archivos a los que git aun no ha hecho seguimiento, y el flag -a o --all para incluir todo, incluso los archivos ignorados

Lista de almacenes (git stash list)link image 72

Como hemos comentado el almacén actúa como una pila, por lo que si hacemos uso de este almacén muchas veces, en realidad vamos a tener una lista de almacenes, y para ver los que tenemos almacenados podemos usar git stash list

	
!cd notebook_git && rm archivo9.py
!cd notebook_git && git stash list
Copy
	
stash@{0}: WIP on new_feature: 527e07a Create README.md

Como vemos solo tenemos uno, que nos indica la rama (on new_feature), el último commit (Create README.md) y un identificador (527e07a)

Almacén con descripción (git stash push -m <descripción>))link image 73

Como hemos visto, la lista nos devuelve la rama y el último commit, pero esta información solo nos vale para saber desde dónde hemos empezado a modificar antes de guardar en el historial. Además nos devuelve un identificador que no nos dice mucho, así que podemos añadir una primera descripción al stash con git stash push -m <descripción>

Primero hacemos un git status para ver que tenemos sin commitear

	
!cd notebook_git && git status
Copy
	
En la rama new_feature
Archivos sin seguimiento:
(usa "git add <archivo>..." para incluirlo a lo que se será confirmado)
archivo9.py
no hay nada agregado al commit pero hay archivos sin seguimiento presentes (usa "git add" para hacerles seguimiento)

Tenemos archivo9.py, pero recordemos que nunca ha sido seguido por git, por lo que para incluirlo en un stash tenemos que usar el flag -u o el flag -a, de modo que creamos un nuevo stash con una descripción con el comando git stash push -u -m <descripción>

	
!cd notebook_git && git stash push -u -m "archivo9.py"
Copy
	
Directorio de trabajo y estado de índice On new_feature: archivo9.py guardados

Sacamos la lista de stash

	
!cd notebook_git && git stash list
Copy
	
stash@{0}: On new_feature: archivo9.py
stash@{1}: WIP on new_feature: 527e07a Create README.md

Ya aparece el nuevo de manera mucho más clara

Recuperar el último stash (git stash pop)link image 74

Como hemos dicho, el stash es una pila con almacenes, por lo que a la hora de recuperarlos lo haremos igual que una pila, recuperando siempre el último

git stash push pop

Para recuperar el último stash tenemos que hacer git stash pop

Primero hacemos un git status para ver que no tenemos ningún cambio pendiente

	
!cd notebook_git && git status
Copy
	
En la rama new_feature
nada para hacer commit, el árbol de trabajo está limpio

Ahora recuperamos el último stash

	
!cd notebook_git && git stash pop
Copy
	
En la rama new_feature
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
nuevos archivos: archivo9.py
Descartado refs/stash@{0} (0246b0e922f654e7fc68cfeaf26e24fc511feb37)

Si volvemos a hacer git status veremos que volvemos a tener archivo9.py pendiente de hacer un commit

	
!cd notebook_git && git status
Copy
	
En la rama new_feature
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
nuevos archivos: archivo9.py

Y si comprobamos la lista de stash veremos que ya solo tenemos uno

	
!cd notebook_git && git stash list
Copy
	
stash@{0}: WIP on new_feature: 527e07a Create README.md

Eliminar un stash (git stash drop <posición>)link image 75

Si queremos eliminar un stash tenemos que hacer git stash drop <posición> donde <posición> es la posición que ocupa el stash en la lista

Obtenemos la lista de los stash

	
!cd notebook_git && git stash list
Copy
	
stash@{0}: WIP on new_feature: 527e07a Create README.md

En nuestro caso solo tenemos unos y en la posición 0 (stash@{0}), por lo que para eliminarlo tendríamos que hacer git stash drop 0, sin embargo no lo voy a hacer porque lo voy a eliminar ahora después con otro comando

Eliminar todos los stash (git stash clear)link image 76

Si queremos vaciar la lista entera de stash tenemos que hacer git stash clear

	
!cd notebook_git && git stash clear
Copy

Si ahora pedimos la lista de stash

	
!cd notebook_git && git stash clear
!cd notebook_git && git stash list
Copy

No obtenemos nada porque hemos eliminado todos

Vamos a dejar todo como estaba, hacemos un git status para recordar los cambios que teníamos pendientes

	
!cd notebook_git && git stash clear
!cd notebook_git && git stash list
!cd notebook_git && git status
Copy
	
En la rama new_feature
Cambios a ser confirmados:
(usa "git restore --staged <archivo>..." para sacar del área de stage)
nuevos archivos: archivo9.py

Vemos que estamos en la rama new_feature y que tenemos archivo9.py pendiente de hacer un commit, como lo hemos creado para el ejemplo lo eliminamos y volvemos a la rama principal

	
!cd notebook_git && git reset archivo9.py
Copy
	
!cd notebook_git && git reset archivo9.py
!cd notebook_git && rm archivo9.py
Copy
	
!cd notebook_git && git reset archivo9.py
!cd notebook_git && rm archivo9.py
!cd notebook_git && git switch main
Copy
	
Cambiado a rama 'main'
Tu rama está actualizada con 'origin/main'.

Tagslink image 77

Cuando estamos desarrollando código llegan momentos en los que generamos versiones, por ejemplo la v1.1, v1.2, etc. Para tener esto más controlado git nos proporciona los tags.

Crear un tag nuevo (git tag -a <nombre_de_etiqueta> -m "<mensaje>")link image 78

Para crear un tag tenemos que hacer git tag -a <nombre_de_etiqueta> -m "<mensaje>"

Por ejemplo, vamos a crear un tag en la versión actual del repositorio, para ello haré git tag -a v_tag -m "Tag con el repositorio en la parte final, en la que explicamos los tags"

	
!cd notebook_git && git tag -a v_tag -m "Tag con el repositorio en la parte final, en la que explicamos los tags"
Copy

Lista de tags (git tag)link image 79

Para ver los tags que hemos creado podemos hacer git tag

	
!cd notebook_git && git tag -a v_tag -m "Tag con el repositorio en la parte final, en la que explicamos los tags"
!cd notebook_git && git tag
Copy
	
v_tag

Crear un tag de un commit antiguo (git tag -a <nombre_de_etiqueta> -m "<mensaje>" <hash>)link image 80

Hagamos un git tree para ver el histórico

	
!cd notebook_git && git tree
Copy
	
* 527e07a (HEAD -> main, tag: v_tag, origin/main, new_feature) Create README.md
* 679bb49 archivo1.py con el merge resuelto
|
| * 32851c3 archivo1.py en rama rama_con_conflicto
* | 53f909b archivo1.py en rama main
|/
* 52acb97 Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (new_branch) 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

Aunque no lo pone en la descripción, cuando hicmos el commit 4bb9d75 fue cuando terminamos la parte de control de versiones de manera local, por lo que también estaría bien tener un tag de ese momento. Para ello lo que tenemos que hacer es crear un tag añadiendo el hash de ese momento

	
!cd notebook_git && git tag -a v_local -m "Tag con el repositorio en la parte de control de versiones de manera local" 4bb9d75
Copy

Si ahora hacemos un listado de los tags aparece el nuevo

	
!cd notebook_git && git tag -a v_local -m "Tag con el repositorio en la parte de control de versiones de manera local" 4bb9d75
!cd notebook_git && git tag
Copy
	
v_local
v_tag

Y si vemos el historial de commits

	
!cd notebook_git && git tree
Copy
	
* 527e07a (HEAD -> main, tag: v_tag, origin/main, new_feature) Create README.md
* 679bb49 archivo1.py con el merge resuelto
|
| * 32851c3 archivo1.py en rama rama_con_conflicto
* | 53f909b archivo1.py en rama main
|/
* 52acb97 Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (tag: v_local, new_branch) 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

En el punto del historial donde hemos creado el tag, ahora aparece el tag que hemos creado * 4bb9d75 (tag: v_local, new_branch) Commit con el archivo 7

Cambiar entre tags (git reset --hard <tag> o git reset --soft <tag>)link image 81

Al igual que nos podemos mover entre distintos commits del historial, también nos podemos mover entre tags. Esto tiene la ventaja de que podemos movernos a otro momento del historial sin tener que saberse el hash, con saber el nombre del tag que hemos puesto en ese momento podemos movernos simplemente haciendo git reset --hard <tag> o git reset --soft <tag>

Primero vamos a hacer un ls para ver los archivos que tenemos

	
!cd notebook_git && ls
Copy
	
api_keys.py archivo1.py archivo2.py archivo8.py README.md

Hacemos un git tree también para ver en qué momento del historial estamos

	
!cd notebook_git && git tree
Copy
	
* 527e07a (HEAD -> main, tag: v_tag, origin/main, new_feature) Create README.md
* 679bb49 archivo1.py con el merge resuelto
|
| * 32851c3 archivo1.py en rama rama_con_conflicto
* | 53f909b archivo1.py en rama main
|/
* 52acb97 Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (tag: v_local, new_branch) 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

Ahora cambiamos al punto en el que hemos creado el tag v_local mediante git reset --hard v_local

	
!cd notebook_git && git reset --hard v_local
Copy
	
HEAD está ahora en 4bb9d75 Commit con el archivo 7

Si ahora volvemos a hacer un ls vemos que no tenemos los mismo archivos

	
!cd notebook_git && ls
Copy
	
api_keys.py archivo1.py archivo2.py archivo4.py archivo7.py hola.py

Si ademas vemos el historial vemos que hemos cambiado de momento del historial

	
!cd notebook_git && git tree
Copy
	
* 4bb9d75 (HEAD -> main, tag: v_local, new_branch) 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

Para volver al último momento del historial, como hemos creado también un tag valdrá con hacer git reset --hard v_tag

	
!cd notebook_git && git reset --hard v_tag
Copy
	
HEAD está ahora en 527e07a Create README.md

Volvemos a ver el historial para comprobar que hemos vuelto al último momento del historial

	
!cd notebook_git && git tree
Copy
	
* 527e07a (HEAD -> main, tag: v_tag, origin/main, new_feature) Create README.md
* 679bb49 archivo1.py con el merge resuelto
|
| * 32851c3 archivo1.py en rama rama_con_conflicto
* | 53f909b archivo1.py en rama main
|/
* 52acb97 Merge squash de los commits de la rama branch_squash
* 274529c Merge branch 'branch_no_fast_forward' into main
|
| * 8df3429 (branch_no_fast_forward) file2
| * e4e23c9 file1
* | 8bdf4d8 file3
|/
* 94149fc (branch_fast_forward) Eliminado hola.py
* 4484e70 Eliminado archivo4.py
* 564ccfb (new_branch2) Commit con el archivo 8
* 5168f78 Eliminado archivo7.py
* 4bb9d75 (tag: v_local, new_branch) 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

Seguir leyendo

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

DoLa – Decoding by Contrasting Layers Improves Factuality in Large Language Models

¿Alguna vez has hablado con un LLM y te ha respondido algo que suena como si hubiera estado bebiendo café de máquina durante toda la noche? 😂 ¡Eso es lo que llamamos una alucinación en el mundo de los LLMs! Pero no te preocupes, porque no es que tu modelo de lenguaje esté loco (aunque a veces puede parecerlo 🤪). La verdad es que los LLMs pueden ser un poco... creativos cuando se trata de generar texto. Pero gracias a DoLa, un método que utiliza capas de contraste para mejorar la factibilidad de los LLMs, podemos evitar que nuestros modelos de lenguaje se conviertan en escritores de ciencia ficción 😂. En este post, te explicaré cómo funciona DoLa y te mostraré un ejemplo de código para que puedas entender mejor cómo hacer que tus LLMs sean más fiables y menos propensos a inventar historias. ¡Vamos a salvar a nuestros LLMs de la locura y hacer que sean más útiles! 🚀

Últimos posts -->

¿Has visto estos proyectos?

Subtify

Subtify Subtify

Generador de subtítulos para videos en el idioma que desees. Además a cada persona le pone su subtítulo de un color

Ver todos los proyectos -->

¿Quieres aplicar la IA en tu proyecto? Contactame!

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

Ver todos los contenedores -->

¿Quieres aplicar la IA en tu proyecto? Contactame!

¿Quieres entrenar tu modelo con estos datasets?

short-jokes-dataset

Dataset de chistes en inglés

opus100

Dataset con traducciones de inglés a español

netflix_titles

Dataset con películas y series de Netflix

Ver más datasets -->