paint-brush
Reescribiendo la historia de Git con confianza: una guíapor@omerosenbaum
2,014 lecturas
2,014 lecturas

Reescribiendo la historia de Git con confianza: una guía

por Omer Rosenbaum18m2023/04/27
Read on Terminal Reader

Demasiado Largo; Para Leer

Git es un sistema para registrar instantáneas de un sistema de archivos en el tiempo. Un repositorio de Git tiene tres "estados" o "árboles": el índice, el área de preparación y el árbol de trabajo. Un directorio de trabajo (electrory) es cualquier directorio en nuestro sistema de archivos que tiene un repositorio de Git asociado.
featured image - Reescribiendo la historia de Git con confianza: una guía
Omer Rosenbaum HackerNoon profile picture

Como desarrollador, trabajas con Git todo el tiempo.


¿Alguna vez llegaste a un punto en el que dijiste: "Uh-oh, qué acabo de hacer?"

Cuando las cosas van mal con Git, muchos ingenieros se sienten impotentes (fuente: XKCD)


Esta publicación le dará las herramientas para reescribir la historia con confianza.

Notas antes de comenzar

  1. También di una charla en vivo cubriendo el contenido de esta publicación. Si prefiere un video (o desea verlo junto con la lectura), puede encontrarlo .


  2. ¡Estoy trabajando en un libro sobre Git! ¿Está interesado en leer las versiones iniciales y proporcionar comentarios? Envíame un correo electrónico: [email protected]

Registro de cambios en Git

Antes de comprender cómo deshacer cosas en Git, primero debe comprender cómo registramos los cambios en Git. Si ya conoce todos los términos, no dude en omitir esta parte.


Es muy útil pensar en Git como un sistema para registrar instantáneas de un sistema de archivos en el tiempo. Considerando un repositorio Git, tiene tres “estados” o “árboles”:

Los tres "árboles" de un repositorio de Git (fuente: https://youtu.be/ozA1V00GIT8)


Por lo general, cuando trabajamos en nuestro código fuente, lo hacemos desde un directorio de trabajo . Un directorio de trabajo (ectrory) (o árbol de trabajo ) es cualquier directorio en nuestro sistema de archivos que tiene un repositorio asociado.


Contiene las carpetas y archivos de nuestro proyecto y también un directorio llamado .git . Describí el contenido de la carpeta .git con más detalle en una publicación anterior .


Después de realizar algunos cambios, es posible que desee registrarlos en su repositorio . Un repositorio (en resumen: repo ) es una colección de confirmaciones , cada una de las cuales es un archivo de cómo se veía el árbol de trabajo del proyecto en una fecha pasada, ya sea en su máquina o en la de otra persona.


Un repositorio también incluye otras cosas además de nuestros archivos de código, como HEAD , ramas, etc.


En el medio, tenemos el índice o área de ensayo ; estos dos términos son intercambiables. Cuando checkout una rama, Git completa el índice con todo el contenido del archivo que se desprotegió por última vez en nuestro directorio de trabajo y cómo se veía cuando se desprotegió originalmente.


Cuando usamos git commit , el commit se crea basado en el estado del índice .


Entonces, el índice, o el área de preparación, es su campo de juego para la próxima confirmación. Puede trabajar y hacer lo que quiera con el índice , agregarle archivos, eliminar cosas de él y luego, solo cuando esté listo, continuar y comprometerse con el repositorio.


Es hora de ponerse manos a la obra 🙌🏻


Use git init para inicializar un nuevo repositorio. Escriba algo de texto en un archivo llamado 1.txt :

Iniciar un nuevo repositorio y crear el primer archivo en él (fuente: https://youtu.be/ozA1V00GIT8)


De los tres estados de árbol descritos anteriormente, ¿dónde está 1.txt ahora?


En el árbol de trabajo, ya que aún no se ha introducido en el índice.

El archivo `1.txt` ahora es solo parte del directorio de trabajo (fuente: https://youtu.be/ozA1V00GIT8)


Para organizarlo , para agregarlo al índice, use git add 1.txt .

El uso de `git add` prepara el archivo para que ahora también esté en el índice (fuente: https://youtu.be/ozA1V00GIT8)


Ahora, podemos usar git commit para confirmar nuestros cambios en el repositorio.

El uso de `git commit` crea un objeto de confirmación en el repositorio (fuente: https://youtu.be/ozA1V00GIT8)


Ha creado un nuevo objeto de confirmación, que incluye un puntero a un árbol que describe todo el árbol de trabajo. En este caso, será solo 1.txt dentro de la carpeta raíz. Además de un puntero al árbol, el objeto de confirmación incluye metadatos, como marcas de tiempo e información del autor.


Para obtener más información sobre los objetos en Git (como confirmaciones y árboles), echa un vistazo a mi publicación anterior .


(Sí, "echa un vistazo", juego de palabras 😇)


Git también nos dice el valor SHA-1 de este objeto de confirmación. En mi caso, fue c49f4ba (que son solo los primeros 7 caracteres del valor SHA-1, para ahorrar espacio).


Si ejecuta este comando en su máquina, obtendrá un valor SHA-1 diferente, ya que es un autor diferente; Además, crearía la confirmación en una marca de tiempo diferente.


Cuando inicializamos el repositorio, Git crea una nueva rama (llamada main por defecto). Y una rama en Git es solo una referencia con nombre a una confirmación . Entonces, de manera predeterminada, solo tiene la rama main . ¿Qué pasa si tienes varias sucursales? ¿Cómo sabe Git qué rama es la rama activa?


Git tiene otro puntero llamado HEAD , que apunta (generalmente) a una rama, que luego apunta a una confirmación. Por cierto, bajo el capó, HEAD es solo un archivo. Incluye el nombre de la sucursal con algunos prefijos.


¡Es hora de introducir más cambios en el repositorio!


Ahora, quiero crear otro. Entonces, creemos un nuevo archivo y agréguelo al índice, como antes:

El archivo `2.txt` está en el directorio de trabajo y el índice después de prepararlo con `git add` (fuente: https://youtu.be/ozA1V00GIT8)


Ahora es el momento de usar git commit . Es importante destacar git commit hace dos cosas:


Primero, crea un objeto de confirmación, por lo que hay un objeto dentro de la base de datos interna de objetos de Git con un valor SHA-1 correspondiente. Este nuevo objeto de confirmación también apunta a la confirmación principal. Esa es la confirmación a la que apuntaba HEAD cuando escribiste el comando git commit .

Se ha creado un nuevo objeto de confirmación, al principio: `main` todavía apunta a la confirmación anterior (fuente: https://youtu.be/ozA1V00GIT8)


En segundo lugar, git commit mueve el puntero de la rama activa; en nuestro caso, eso sería main , para apuntar al objeto de confirmación recién creado.

`git commit` también actualiza la rama activa para apuntar al objeto de confirmación recién creado (fuente: https://youtu.be/ozA1V00GIT8)


Deshacer los cambios

Para reescribir el historial, comencemos por deshacer el proceso de introducir una confirmación. Para eso, conoceremos el comando git reset , una herramienta súper poderosa.

git reset --soft

Entonces, el último paso que hiciste antes fue git commit , lo que en realidad significa dos cosas: Git creó un objeto de confirmación y movió main , la rama activa. Para deshacer este paso, usa el comando git reset --soft HEAD~1 .


La sintaxis HEAD~1 se refiere al primer padre de HEAD . Si tuviera más de una confirmación en el gráfico de confirmación, diga "Commit 3" apuntando a "Commit 2", que, a su vez, apunta a "Commit 1".


Y digamos que HEAD estaba apuntando a "Commit 3". Podría usar HEAD~1 para referirse a "Commit 2", y HEAD~2 se referiría a "Commit 1".


Entonces, volvamos al comando: git reset --soft HEAD~1


Este comando le pide a Git que cambie lo que apunta HEAD . (Nota: en los diagramas a continuación, uso *HEAD para "lo que sea que HEAD esté señalando"). En nuestro ejemplo, HEAD apunta a main . Entonces Git solo cambiará el puntero de main para que apunte a HEAD~1 . Es decir, main apuntará a "Commit 1".


Sin embargo, este comando no afectó el estado del índice o el árbol de trabajo. Entonces, si usa git status verá que 2.txt está preparado, al igual que antes de ejecutar git commit .

Restablecer `main` a "Commit 1" (fuente: https://youtu.be/ozA1V00GIT8)


¿Qué pasa con git log? Comenzará desde HEAD , irá a main y luego a "Commit 1". Tenga en cuenta que esto significa que "Commit 2" ya no es accesible desde nuestro historial.


¿Significa eso que se elimina el objeto de confirmación de "Commit 2"? 🤔


No, no se elimina. Todavía reside dentro de la base de datos interna de objetos de Git.


Si envía el historial actual ahora, usando git push , Git no enviará "Commit 2" al servidor remoto, pero el objeto de confirmación todavía existe en su copia local del repositorio.


Ahora, confirme nuevamente y use el mensaje de confirmación de "Commit 2.1" para diferenciar este nuevo objeto del "Commit 2" original:

Creación de una nueva confirmación (fuente: https://youtu.be/ozA1V00GIT8)


¿Por qué son diferentes "Commit 2" y "Commit 2.1"? Incluso si usamos el mismo mensaje de confirmación, y aunque apunten a el mismo objeto de árbol (de la carpeta raíz que consta de 1.txt y 2.txt ), todavía tienen marcas de tiempo diferentes, ya que se crearon en momentos diferentes.


En el dibujo de arriba, mantuve "Commit 2" para recordarte que todavía existe en la base de datos interna de objetos de Git. Tanto "Commit 2" como "Commit 2.1" ahora apuntan a "Commit 1", pero solo se puede acceder a "Commit 2.1" desde HEAD .

Restablecimiento de Git - Mixto

Es hora de ir incluso hacia atrás y deshacer más. Esta vez, use git reset --mixed HEAD~1 (nota: --mixed es el interruptor predeterminado para git reset ).


Este comando comienza igual que git reset --soft HEAD~1 . Lo que significa que toma el puntero de lo que HEAD esté apuntando ahora, que es la rama main , y lo establece en HEAD~1 , en nuestro ejemplo, "Commit 1".

El primer paso de `git reset --mixed` es el mismo que `git reset --soft` (fuente: https://youtu.be/ozA1V00GIT8)


Luego, Git va más allá y deshace efectivamente los cambios que hicimos en el índice. Es decir, cambiando el índice para que coincida con el HEAD actual, el HEAD nuevo después de configurarlo en el primer paso.


Si ejecutamos git reset --mixed HEAD~1 , significa que HEAD se establecería en HEAD~1 ("Commit 1"), y luego Git haría coincidir el índice con el estado de "Commit 1"; en este caso, significa que 2.txt ya no formará parte del índice.

El segundo paso de `git reset --mixed` es hacer coincidir el índice con el nuevo `HEAD` (fuente: https://youtu.be/ozA1V00GIT8)


Es hora de crear un nuevo compromiso con el estado del "Commit 2" original. Esta vez necesitamos volver a preparar 2.txt antes de crearlo:

Creando "Commit 2.2" (fuente: https://youtu.be/ozA1V00GIT8)


Restablecimiento de Git - Difícil

¡Adelante, deshazte aún más!


Continúe y ejecute git reset --hard HEAD~1


Nuevamente, Git comienza con la etapa --soft , configurando cualquier HEAD al que apunte ( main ), a HEAD~1 ("Commit 1").

El primer paso de `git reset --hard` es el mismo que `git reset --soft` (fuente: https://youtu.be/ozA1V00GIT8)


Hasta ahora, todo bien.


A continuación, pasar a la etapa --mixed , haciendo coincidir el índice con HEAD . Es decir, Git deshace la preparación de 2.txt .

El segundo paso de `git reset --hard` es el mismo que `git reset --mixed` (fuente: https://youtu.be/ozA1V00GIT8)


Es hora del paso --hard donde Git va más allá y hace coincidir el directorio de trabajo con la etapa del índice. En este caso, significa eliminar 2.txt también del directorio de trabajo.

El tercer paso de `git reset --hard` hace coincidir el estado del directorio de trabajo con el del índice (fuente: https://youtu.be/ozA1V00GIT8)


(**Nota: en este caso específico, el archivo no se rastrea, por lo que no se eliminará del sistema de archivos; sin embargo, no es realmente importante para comprender git reset ).


Entonces, para introducir un cambio en Git, tienes tres pasos. Cambia el directorio de trabajo, el índice o el área de preparación y luego confirma una nueva instantánea con esos cambios. Para deshacer estos cambios:


  • Si usamos git reset --soft , deshacemos el paso de confirmación.


  • Si usamos git reset --mixed , también deshacemos el paso de preparación.


  • Si usamos git reset --hard , deshacemos los cambios en el directorio de trabajo.

¡Escenarios de la vida real!

Escenario 1

Entonces, en un escenario de la vida real, escriba "Me encanta Git" en un archivo ( love.txt ), ya que todos amamos a Git 😍. Adelante, prepara y comete esto también:

Creando "Commit 2.3" (fuente: https://youtu.be/ozA1V00GIT8)


¡Uy!


En realidad, no quería que lo cometiera.


Lo que realmente quería que hicieras es escribir algunas palabras de amor más en este archivo antes de enviarlo.

¿Qué puedes hacer?


Bueno, una forma de superar esto sería usar git reset --mixed HEAD~1 , deshaciendo efectivamente las acciones de confirmación y puesta en escena que tomó:

Deshacer los pasos de preparación y confirmación (fuente: https://youtu.be/ozA1V00GIT8)


Entonces, los puntos main para "Commit 1" nuevamente, y love.txt ya no es parte del índice. Sin embargo, el archivo permanece en el directorio de trabajo. Ahora puede continuar y agregarle más contenido:

Agregar más letras de amor (fuente: https://youtu.be/ozA1V00GIT8)


Continúe, organice y confirme su archivo:

Crear la nueva confirmación con el estado deseado (fuente: https://youtu.be/ozA1V00GIT8)


Bien hecho 👏🏻


Obtuviste esta historia clara y agradable de "Commit 2.4" apuntando a "Commit 1".


Ahora tenemos una nueva herramienta en nuestra caja de herramientas, git reset 💪🏻

git reset ahora está en nuestra caja de herramientas (fuente: https://youtu.be/ozA1V00GIT8)


Esta herramienta es súper, súper útil y puedes lograr casi cualquier cosa con ella. No siempre es la herramienta más conveniente para usar, pero es capaz de resolver casi cualquier escenario de reescritura de la historia si la usa con cuidado.


Para los principiantes, recomiendo usar solo git reset durante casi cualquier momento que desee deshacer en Git. Una vez que se sienta cómodo con él, es hora de pasar a otras herramientas.

Escenario #2

Consideremos otro caso.


Cree un nuevo archivo llamado new.txt ; etapa y cometer:

Creando `nuevo.txt` y "Commit 3" (fuente: https://youtu.be/ozA1V00GIT8)


Ups. En realidad, eso es un error. Estabas en main y quería que crearas esta confirmación en una rama de características. Mi mal 😇


Hay dos herramientas más importantes que quiero que tome de esta publicación. El segundo es git reset . El primero y mucho más importante es comparar el estado actual con el estado en el que desea estar.


Para este escenario, el estado actual y el estado deseado se ven así:

Escenario n.° 2: estado actual versus estado deseado (fuente: https://youtu.be/ozA1V00GIT8)


Notarás tres cambios:


  1. puntos main a "Commit 3" (el azul) en el estado actual, pero a "Commit 2.4" en el estado deseado.


  2. La rama feature no existe en el estado actual, pero existe y apunta a "Commit 3" en el estado deseado.


  3. HEAD apunta a main en el estado actual y a feature en el estado deseado.


Si puede dibujar esto y sabe cómo usar git reset , definitivamente puede salir de esta situación.


De nuevo, lo más importante es respirar y sacar esto.


Observando el dibujo de arriba, ¿cómo pasamos del estado actual al deseado?


Por supuesto, hay algunas formas diferentes, pero presentaré una opción solo para cada escenario. Siéntase libre de jugar con otras opciones también.


Puede comenzar usando git reset --soft HEAD~1 . Esto establecería main para apuntar a la confirmación anterior, "Commit 2.4":

Cambiando `principal`; "Commit 3 está borroso porque todavía está allí, simplemente no accesible (fuente: https://youtu.be/ozA1V00GIT8)


Mirando de nuevo el diagrama actual-vs-deseado, puede ver que necesita una nueva rama, ¿verdad? Puede usar git switch -c feature para ello o git checkout -b feature (que hace lo mismo):

Creación de la rama `característica` (fuente: https://youtu.be/ozA1V00GIT8)


Este comando también actualiza HEAD para apuntar a la nueva rama.


Dado que usó git reset --soft , no cambió el índice, por lo que actualmente tiene exactamente el estado que desea confirmar, ¡qué conveniente! Simplemente puede comprometerse con la rama feature :

Comprometerse con la rama `feature` (fuente: https://youtu.be/ozA1V00GIT8)


Y llegaste al estado deseado 🎉

Escenario #3

¿Listo para aplicar su conocimiento a casos adicionales?


Agregue algunos cambios a love.txt y también cree un nuevo archivo llamado cool.txt . Ponlos en escena y comprométete:

Creando "Commit 4" (fuente: https://youtu.be/ozA1V00GIT8)


Vaya, en realidad quería que crearas dos confirmaciones separadas, una con cada cambio 🤦🏻

¿Quieres probar este tú mismo?


Puede deshacer los pasos de compromiso y preparación:

Deshaga la confirmación y la puesta en escena usando `git reset --mixed HEAD~1` (fuente: https://youtu.be/ozA1V00GIT8)


Siguiendo este comando, el índice ya no incluye esos dos cambios, pero ambos todavía están en su sistema de archivos. Así que ahora, si solo preparas love.txt , puedes enviarlo por separado y luego hacer lo mismo con cool.txt :

Comprometerse por separado (fuente: https://youtu.be/ozA1V00GIT8)


Bonito 😎

Escenario #4

Cree un nuevo archivo ( new_file.txt ) con algo de texto y agregue algo de texto a love.txt . Preparar ambos cambios y confirmarlos:

Una nueva confirmación (fuente: https://youtu.be/ozA1V00GIT8)


Uy 🙈🙈


Entonces, esta vez, quería que fuera en otra rama, pero no en una rama nueva , sino en una rama ya existente.


¿Entonces que puedes hacer?


Te daré una pista. La respuesta es muy corta y muy fácil. ¿Qué hacemos primero?


No, no reset . Dibujamos. Eso es lo primero que debe hacer, ya que haría que todo lo demás fuera mucho más fácil. Así que este es el estado actual:

La nueva confirmación en `main` aparece en azul (fuente: https://youtu.be/ozA1V00GIT8)


¿Y el estado deseado?

Queremos que la confirmación "azul" esté en otra rama "existente" (fuente: https://youtu.be/ozA1V00GIT8)


¿Cómo se pasa del estado actual al estado deseado, qué sería más fácil?


Entonces, una forma sería usar git reset como lo hizo antes, pero hay otra forma que me gustaría que probara.


Primero, mueva HEAD para señalar la rama existing :

Cambiar a la rama `existente` (fuente: https://youtu.be/ozA1V00GIT8)


Intuitivamente, lo que desea hacer es tomar los cambios introducidos en la confirmación azul y aplicar estos cambios ("copiar y pegar") en la parte superior de la rama existing . Y Git tiene una herramienta solo para eso.


Para pedirle a Git que tome los cambios introducidos entre esta confirmación y su confirmación principal y simplemente aplique estos cambios en la rama activa, puede usar git cherry-pick . Este comando toma los cambios introducidos en la revisión especificada y los aplica a la confirmación activa.


También crea un nuevo objeto de confirmación y actualiza la rama activa para apuntar a este nuevo objeto.

Usando `git cherry-pick` (fuente: https://youtu.be/ozA1V00GIT8)


En el ejemplo anterior, especifiqué el identificador SHA-1 de la confirmación creada, pero también podría usar git cherry-pick main , ya que la confirmación cuyos cambios estamos aplicando es la main a la que apunta.


Pero no queremos que estos cambios existan en la rama main . git cherry-pick solo aplicó los cambios a la rama existing . ¿Cómo puedes eliminarlos de main ?


Una forma sería switch a main y luego usar git reset --hard HEAD~1 :

Restablecimiento de `main` (fuente: https://youtu.be/ozA1V00GIT8)


¡Lo hiciste! 💪🏻


Tenga en cuenta que git cherry-pick en realidad calcula la diferencia entre la confirmación especificada y su padre, y luego los aplica a la confirmación activa. Esto significa que, a veces, Git no podrá aplicar esos cambios, ya que puede generar un conflicto, pero ese es un tema para otra publicación.


Además, tenga en cuenta que puede pedirle a Git que cherry-pick los cambios introducidos en cualquier confirmación, no solo las confirmaciones a las que hace referencia una rama.


Hemos adquirido una nueva herramienta, por lo que tenemos git reset y git cherry-pick en nuestro haber.

Escenario #5

Bien, otro día, otro repositorio, otro problema.


Crear un compromiso:

Otra confirmación (fuente: https://youtu.be/ozA1V00GIT8)


Y push al servidor remoto:

(fuente: https://youtu.be/ozA1V00GIT8)


Um, ups 😓...


Acabo de notar algo. Hay un error tipográfico allí. Escribí This is more tezt en lugar de This is more text . ¡Vaya! Entonces, ¿cuál es el gran problema ahora? push ed, lo que significa que alguien más podría haber pull esos cambios.


Si anulo esos cambios usando git reset , como lo hemos hecho hasta ahora, tendremos diferentes historias y todo podría desatarse. Puede reescribir su propia copia del repositorio tanto como desee hasta que lo push .


Una vez que push el cambio, debe estar muy seguro de que nadie más haya obtenido esos cambios si va a reescribir el historial.


Alternativamente, puede usar otra herramienta llamada git revert . Este comando toma la confirmación que le proporcionas y calcula la diferencia a partir de su confirmación principal, al igual que git cherry-pick , pero esta vez calcula los cambios inversos.


Entonces, si en la confirmación especificada agregaste una línea, lo contrario eliminaría la línea y viceversa.

Usando `git revert` para deshacer los cambios (fuente: https://youtu.be/ozA1V00GIT8)


git revert creó un nuevo objeto de confirmación, lo que significa que es una adición al historial. Al usar git revert , no reescribió el historial. Admitiste tu error pasado, y este compromiso es un reconocimiento de que cometiste un error y ahora lo arreglaste.


Algunos dirían que es la forma más madura. Algunos dirían que no es un historial tan limpio como el que obtendrías si usaras git reset para reescribir la confirmación anterior. Pero esta es una forma de evitar reescribir la historia.


Ahora puede corregir el error tipográfico y confirmar de nuevo:

Rehacer los cambios (fuente: https://youtu.be/ozA1V00GIT8)


Su caja de herramientas ahora está cargada con una nueva herramienta brillante, revert :

Nuestra caja de herramientas (fuente: https://youtu.be/ozA1V00GIT8)


Escenario #6

Trabaja un poco, escribe un código y agrégalo a love.txt . Realice este cambio y confírmelo:

Otra confirmación (fuente: https://youtu.be/ozA1V00GIT8)


Hice lo mismo en mi máquina, y usé la tecla de flecha Up en mi teclado para desplazarme hacia atrás a los comandos anteriores, y luego presioné Enter y... Wow.


¡Vaya!

¿Acabo de `git reset -- hard`? (fuente: https://youtu.be/ozA1V00GIT8)


¿Acabo de usar git reset --hard ? 😨


¿Qué sucedió realmente ? Git movió el puntero a HEAD~1 , por lo que no se puede acceder a la última confirmación, con todo mi precioso trabajo, desde el historial actual. Git también eliminó todos los cambios del área de preparación y luego hizo coincidir el directorio de trabajo con el estado del área de preparación.


Es decir, todo coincide con este estado en el que mi trabajo se ha... ido.


Tiempo de enloquecer. enloqueciendo

Pero, realmente, ¿hay alguna razón para enloquecer? No realmente… Somos gente relajada. qué hacemos? Bueno, intuitivamente, ¿se ha ido realmente el compromiso? ¿No por qué no? Todavía existe dentro de la base de datos interna de Git.


Si supiera dónde está, sabría el valor SHA-1 que identifica este compromiso, podríamos restaurarlo. Incluso podría deshacer la deshacer y reset de nuevo a este compromiso.


Entonces, lo único que realmente necesito aquí es el SHA-1 del compromiso "eliminado".


Entonces la pregunta es, ¿cómo lo encuentro? ¿Sería útil git log ?


Bueno en realidad no. git log iría a HEAD , que apunta a main , que apunta a la confirmación principal de la confirmación que estamos buscando. Luego, git log rastrearía a través de la cadena principal, que no incluye la confirmación con mi valioso trabajo.

`git log` no ayuda en este caso (fuente: https://youtu.be/ozA1V00GIT8)


Afortunadamente, las personas muy inteligentes que crearon Git también crearon un plan de respaldo para nosotros, y se llama reflog .


Mientras trabaja con Git, cada vez que cambia HEAD , lo que puede hacer usando git reset , pero también otros comandos como git switch o git checkout , Git agrega una entrada al reflog .


`git reflog` nos muestra dónde estaba `HEAD` (fuente: https://youtu.be/ozA1V00GIT8)


¡Encontramos nuestro compromiso! Es el que comienza con 0fb929e .


También podemos relacionarnos con él por su "apodo": HEAD@{1} . Por ejemplo, Git usa HEAD~1 para llegar al primer padre de HEAD , y HEAD~2 para referirse al segundo padre de HEAD y así sucesivamente, Git usa HEAD@{1} para referirse al primer padre reflog de HEAD , donde señaló HEAD en el paso anterior.


También podemos pedirle git rev-parse que nos muestre su valor:

(fuente: https://youtu.be/ozA1V00GIT8)


Otra forma de ver el reflog es usar git log -g , que le pide a git log que realmente considere el reflog :

La salida de `git log -g` (fuente: https://youtu.be/ozA1V00GIT8)


Vemos arriba que reflog , al igual que HEAD , apunta a main , que apunta a "Commit 2". Pero el padre de esa entrada en el reflog apunta a "Commit 3".


Entonces, para volver a "Commit 3", solo puede usar git reset --hard HEAD@{1} (o el valor SHA-1 de "Commit 3"):

(fuente: https://youtu.be/ozA1V00GIT8)


Y ahora, si git log :

Nuestra historia está de regreso!!! (fuente: https://youtu.be/ozA1V00GIT8)


¡Salvamos el día! 🎉👏🏻


¿Qué pasaría si volviera a usar este comando? ¿Y ejecutó git commit --reset HEAD@{1} ? Git configuraría HEAD a donde apuntaba HEAD antes del último reset , es decir, "Commit 2". Podemos seguir todo el día:

(fuente: https://youtu.be/ozA1V00GIT8)


Mirando nuestra caja de herramientas ahora, está cargada de herramientas que pueden ayudarlo a resolver muchos casos en los que las cosas salen mal en Git:

¡Nuestra caja de herramientas es bastante extensa! (fuente: https://youtu.be/ozA1V00GIT8)


Con estas herramientas, ahora comprenderá mejor cómo funciona Git. Hay más herramientas que te permitirían reescribir el historial específicamente, git rebase ), pero ya aprendiste mucho en esta publicación. En publicaciones futuras, también me sumergiré en git rebase .


La herramienta más importante, incluso más importante que las cinco herramientas enumeradas en esta caja de herramientas, es comparar la situación actual con la deseada. Confía en mí, hará que cada situación parezca menos desalentadora y la solución más clara.

Más información sobre Git

También di una charla en vivo cubriendo el contenido de esta publicación. Si prefiere un video (o desea verlo junto con la lectura), puede encontrarlo .


En general, mi canal de youtube cubre muchos aspectos de Git y sus componentes internos; eres bienvenido a Échale un vistazo (juego de palabras intencionado 😇)

Sobre el Autor

Omer Rosenbaum es el CTO y cofundador de Nadar , una herramienta de desarrollo que ayuda a los desarrolladores y sus equipos a administrar el conocimiento sobre su base de código con documentación interna actualizada. Omer es el fundador de Check Point Security Academy y fue líder de seguridad cibernética en ITC, una organización educativa que capacita a profesionales talentosos para desarrollar carreras en tecnología.


Omer tiene una Maestría en Lingüística de la Universidad de Tel Aviv y es el creador de la Breve canal de YouTube .


Publicado por primera vez aquí