En este artículo, aprenderá diferentes formas de jugar con las confirmaciones en Git.
Como desarrollador, se habría enfrentado a situaciones de este tipo varias veces en las que hubiera querido volver a una de sus confirmaciones anteriores, pero no estaba seguro de cómo hacerlo. E incluso si conoces el ir comandos como reset, revert, rebase, no es consciente de las diferencias entre ellos. Así que comencemos y entendamos qué son git reset, revert y rebase.
Git Reset
Git reset es un comando complejo y se usa para deshacer los cambios.
Puedes pensar en git reset como una función de reversión. Con git reset, puedes saltar entre varias confirmaciones. Hay tres modos de ejecutar un comando git reset: –soft, –mixed y –hard. De forma predeterminada, el comando git reset usa el modo mixto. En un flujo de trabajo de reinicio de git, tres mecanismos de administración internos de git entran en escena: CABEZA, área de ensayo (índice) y el directorio de trabajo.
El directorio de trabajo es el lugar donde está trabajando actualmente, es el lugar donde están presentes sus archivos. Usando un comando de estado de git, puede ver qué archivos / carpetas están presentes en el directorio de trabajo.
El área de ensayo (índice) es donde git rastrea y guarda todos los cambios en los archivos. Los cambios guardados se reflejan en el directorio .git. Utiliza git add "nombre de archivo" para agregar el archivo al área de ensayo. Y como antes, cuando ejecute git status, verá qué archivos están presentes en el área de prueba.
La rama actual en Git se conoce como HEAD. Apunta a la última confirmación, que ocurrió en la rama de pago actual. Se trata como un puntero para cualquier referencia. Una vez que realiza el pago a otra sucursal, el HEAD también se mueve a la nueva sucursal.
Permítanme explicar cómo funciona git reset en los modos duro, suave y mixto. El modo difícil se usa para ir a la confirmación puntual, el directorio de trabajo se llena con los archivos de esa confirmación y el área de preparación se restablece. En el restablecimiento parcial, solo el puntero se cambia a la confirmación especificada. Los archivos de todas las confirmaciones permanecen en el directorio de trabajo y el área de preparación antes del reinicio. En el modo mixto (predeterminado), el puntero y el área de preparación se restablecen.
Restablecer duro de Git
El propósito de git hard reset es mover HEAD a la confirmación especificada. Eliminará todas las confirmaciones que ocurrieron después de la confirmación especificada. Este comando cambiará el historial de confirmaciones y apuntará a la confirmación especificada.
En este ejemplo, agregaré tres archivos nuevos, los confirmaré y luego realizaré un restablecimiento completo.
Como puede ver en el siguiente comando, en este momento, no hay nada que confirmar.
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
Ahora, crearé 3 archivos y agregaré algo de contenido.
$ vi file1.txt
$ vi file2.txt
$ vi file3.txt
Agregue estos archivos al repositorio existente.
$ git add file*
Cuando vuelva a ejecutar el comando de estado, reflejará los nuevos archivos que acabo de crear.
$ git status
On branch master
Your branch is ahead of 'origin/master' by 2 commits.
(use "git push" to publish your local commits)
Changes to be committed:
(use "git restore --staged <file>..." to unstage)
new file:
file1.txt
new file:
file2.txt
new file:
file3.txt
Antes de comprometerme, déjame mostrarte, actualmente tengo un registro de 3 confirmaciones en Git.
$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Ahora, me comprometeré con el repositorio.
$ git commit -m 'added 3 files'
[master d69950b] added 3 files
3 files changed, 3 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt
Si utilizo ls-files, verá que se han agregado los nuevos archivos.
$ git ls-files
demo
dummyfile
newfile
file1.txt
file2.txt
file3.txt
Cuando ejecuto el comando log en git, tengo 4 confirmaciones y HEAD apunta a la última confirmación.
$ git log --oneline
d69950b (HEAD -> master) added 3 files
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Si voy y elimino el file1.txt manualmente y hago un estado de git, mostrará el mensaje de que los cambios no están preparados para su confirmación.
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
Changes not staged for commit:
(use "git add/rm <file>..." to update what will be committed)
(use "git restore <file>..." to discard changes in working directory)
deleted:
file1.txt
no changes added to commit (use "git add" and/or "git commit -a")
Ahora, ejecutaré el comando de restablecimiento completo.
$ git reset --hard
HEAD is now at d69950b added 3 files
Si vuelvo a comprobar el estado, descubriré que no hay nada que confirmar y el archivo que eliminé ha vuelto al repositorio. La reversión ocurrió porque después de eliminar el archivo, no me comprometí, por lo que después de un restablecimiento completo, volvió al estado anterior.
$ git status
On branch master
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
nothing to commit, working tree clean
Si reviso el registro de git, así es como se verá.
$ git log
commit d69950b7ea406a97499e07f9b28082db9db0b387 (HEAD -> master)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 19:53:31 2020 +0530
added 3 files
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 01:04:13 2020 +0530
one more commit
commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:54:53 2020 +0530
new commit
commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:16:33 2020 +0530
test
El propósito del restablecimiento completo es apuntar a la confirmación especificada y actualizar el directorio de trabajo y el área de prueba. Déjame mostrarte un ejemplo más. Actualmente, la visualización de mis confirmaciones se ve a continuación:
Aquí, ejecutaré el comando con HEAD ^, lo que significa que quiero restablecer la confirmación anterior (una confirmación posterior).
$ git reset --hard HEAD^
HEAD is now at 0db602e one more commit
Puede ver que el puntero principal ahora ha cambiado a 0db602e desde d69950b.
$ git log --oneline
0db602e (HEAD -> master) one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Si comprueba el registro, la confirmación de d69950b desaparecerá y el encabezado ahora apunta a 0db602e SHA.
$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 01:04:13 2020 +0530
one more commit
commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:54:53 2020 +0530
new commit
commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:16:33 2020 +0530
Test
Si ejecuta ls-files, puede ver que file1.txt, file2.txt y files3.txt ya no están en el repositorio porque esa confirmación y su archivo se eliminaron después del restablecimiento completo.
$ git ls-files
demo
dummyfile
newfile
Reinicio suave de Git
Del mismo modo, ahora les mostraré un ejemplo de un reinicio por software. Considere, he agregado los 3 archivos nuevamente como se mencionó anteriormente y los comprometí. El registro de git aparecerá como se muestra a continuación. Puede ver que 'reinicio suave' es mi última confirmación, y HEAD también apunta a eso.
$ git log --oneline
aa40085 (HEAD -> master) soft reset
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Los detalles de la confirmación en el registro se pueden ver usando el siguiente comando.
$ git log
commit aa400858aab3927e79116941c715749780a59fc9 (HEAD -> master)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 21:01:36 2020 +0530
soft reset
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 01:04:13 2020 +0530
one more commit
commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:54:53 2020 +0530
new commit
commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:16:33 2020 +0530
test
Ahora, usando el reinicio por software, quiero cambiar a una de las confirmaciones más antiguas con SHA 0db602e085a4d59cfa9393abac41ff5fd7afcb14
Para hacer eso, ejecutaré el siguiente comando. Debe pasar más de 6 caracteres iniciales de SHA, no se requiere el SHA completo.
$ git reset --soft 0db602e085a4
Ahora, cuando ejecuto el registro de git, puedo ver que HEAD se ha restablecido a la confirmación que especifiqué.
$ git log
commit 0db602e085a4d59cfa9393abac41ff5fd7afcb14 (HEAD -> master)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 01:04:13 2020 +0530
one more commit
commit 59c86c96a82589bad5ecba7668ad38aa684ab323
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:54:53 2020 +0530
new commit
commit e2f44fca2f8afad8e4d73df6b72111f2f2fd71ad (origin/master, origin/HEAD)
Author: mrgeek <mrgeek@gmail.com>
Date:
Mon May 17 00:16:33 2020 +0530
test
Pero la diferencia aquí es que los archivos de la confirmación (aa400858aab3927e79116941c715749780a59fc9) donde había agregado 3 archivos todavía están en mi directorio de trabajo. No se han eliminado. Es por eso que debe usar un restablecimiento parcial en lugar de un restablecimiento completo. No hay riesgo de perder los archivos en el modo suave.
$ git ls-files
demo
dummyfile
file1.txt
file2.txt
file3.txt
newfile
Git Revert
En Git, el comando revert se usa para realizar una operación de reversión, es decir, para revertir algunos cambios. Es similar al comando de reinicio, pero la única diferencia aquí es que realiza una nueva confirmación para volver a una confirmación en particular. En resumen, es justo decir que el comando git revert es una confirmación.
El comando de reversión de Git no elimina ningún dato mientras se realiza la operación de reversión.
Digamos que estoy agregando 3 archivos y realizando una operación de confirmación de git para el ejemplo de reversión.
$ git commit -m 'add 3 files again'
[master 812335d] add 3 files again
3 files changed, 3 insertions(+)
create mode 100644 file1.txt
create mode 100644 file2.txt
create mode 100644 file3.txt
El registro mostrará la nueva confirmación.
$ git log --oneline
812335d (HEAD -> master) add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Ahora me gustaría volver a una de mis confirmaciones anteriores, digamos: "59c86c9 nueva confirmación". Ejecutaría el comando a continuación.
$ git revert 59c86c9
Esto abrirá un archivo, encontrará los detalles de la confirmación a la que está tratando de revertir, y puede darle un nombre a su nueva confirmación aquí, y luego guardar y cerrar el archivo.
Revert "new commit"
This reverts commit 59c86c96a82589bad5ecba7668ad38aa684ab323.
# Please enter the commit message for your changes. Lines starting
# with '#' will be ignored, and an empty message aborts the commit.
#
# On branch master
# Your branch is ahead of 'origin/master' by 4 commits.
# (use "git push" to publish your local commits)
#
# Changes to be committed:
# modified: dummyfile
Después de guardar y cerrar el archivo, esta es la salida que obtendrá.
$ git revert 59c86c9
[master af72b7a] Revert "new commit"
1 file changed, 1 insertion(+), 1 deletion(-)
Ahora, para realizar los cambios necesarios, a diferencia del reinicio, revert ha realizado una nueva confirmación más. Si vuelve a comprobar el registro, encontrará una nueva confirmación debido a la operación de reversión.
$ git log --oneline
af72b7a (HEAD -> master) Revert "new commit"
812335d add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Git log tendrá todo el historial de confirmaciones. Si desea eliminar las confirmaciones del historial, revertir no es una buena opción, pero si desea mantener los cambios de confirmación en el historial, revertir es el comando adecuado en lugar de restablecer.
Git Rebase
En Git, rebase es la forma de mover o combinar confirmaciones de una rama sobre otra rama. Como desarrollador, no crearía mis funciones en la rama maestra en un escenario del mundo real. Trabajaría en mi propia rama (una 'rama de características'), y cuando tenga algunas confirmaciones en mi rama de características con la característica agregada, me gustaría moverla a la rama maestra.
Rebase a veces puede ser un poco confuso de entender porque es muy similar a una fusión. El objetivo de fusionar y reajustar ambos es tomar las confirmaciones de mi rama de características y colocarlas en una rama maestra o en cualquier otra rama. Considere, tengo un gráfico que se ve así:
Suponga que está trabajando en equipo con otros desarrolladores. En ese caso, puede imaginar que esto podría volverse realmente complejo cuando hay un montón de otros desarrolladores trabajando en diferentes ramas de funciones y han estado fusionando múltiples cambios. Se vuelve confuso rastrear.
Entonces, aquí es donde rebase ayudará. Esta vez, en lugar de hacer una fusión de git, haré una rebase, donde quiero tomar mis dos confirmaciones de ramas de características y moverlas a la rama maestra. Una rebase tomará todas mis confirmaciones de la rama de características y las moverá a la parte superior de las confirmaciones de la rama maestra. Entonces, detrás de escena, git está duplicando las confirmaciones de la rama de características en la rama maestra.
Este enfoque le dará un gráfico de línea recta limpio con todas las confirmaciones en una fila.
Hace que sea fácil rastrear qué confirmaciones fueron a dónde. Puedes imaginar que si estás en un equipo con muchos desarrolladores, todas las confirmaciones siguen seguidas. Por lo tanto, es muy fácil de seguir incluso si tiene muchas personas trabajando en el mismo proyecto al mismo tiempo.
Déjame mostrarte esto de manera práctica.
Así es como se ve mi rama maestra actualmente. Tiene 4 confirmaciones.
$ git log --oneline
812335d (HEAD -> master) add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Ejecutaré el siguiente comando para crear y cambiar a una nueva rama llamada característica, y esta rama se creará a partir de la segunda confirmación, es decir, 2c59c86
(master)
$ git checkout -b feature 59c86c9
Switched to a new branch 'feature'
Si verifica el registro en la rama de funciones, solo tiene 2 confirmaciones provenientes del maestro (línea principal).
(feature)
$ git log --oneline
59c86c9 (HEAD -> feature) new commit
e2f44fc (origin/master, origin/HEAD) test
Crearé la característica 1 y la enviaré a la rama de características.
(feature)
$ vi feature1.txt
(feature)
$ git add .
The file will have its original line endings in your working directory
(feature)
$ git commit -m 'feature 1'
[feature c639e1b] feature 1
1 file changed, 1 insertion(+)
create mode 100644 feature1.txt
Crearé una característica más, es decir, la característica 2, en la rama de características y la confirmaré.
(feature)
$ vi feature2.txt
(feature)
$ git add .
The file will have its original line endings in your working directory
(feature)
$ git commit -m 'feature 2'
[feature 0f4db49] feature 2
1 file changed, 1 insertion(+)
create mode 100644 feature2.txt
Ahora, si revisa el registro de la rama de funciones, tiene dos nuevas confirmaciones, que ejecuté anteriormente.
(feature)
$ git log --oneline
0f4db49 (HEAD -> feature) feature 2
c639e1b feature 1
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Ahora quiero agregar estas dos nuevas características a la rama maestra. Para eso, usaré el comando rebase. Desde la rama de funciones, me basaré en la rama maestra. Lo que esto hará es volver a anclar mi rama de características contra los últimos cambios.
(feature)
$ git rebase master
Successfully rebased and updated refs/heads/feature.
Ahora voy a seguir adelante y verificar la rama maestra.
(feature)
$ git checkout master
Switched to branch 'master'
Your branch is ahead of 'origin/master' by 3 commits.
(use "git push" to publish your local commits)
Y finalmente, vuelva a basar la rama maestra con mi rama de características. Esto tomará esas dos nuevas confirmaciones en mi rama de características y las reproducirá en la parte superior de mi rama maestra.
(master)
$ git rebase feature
Successfully rebased and updated refs/heads/master.
Ahora, si reviso el registro en la rama maestra, puedo ver que las dos confirmaciones de mi rama de características se han agregado a mi rama maestra con éxito.
(master)
$ git log --oneline
766c996 (HEAD -> master, feature) feature 2
c036a11 feature 1
812335d add 3 files again
0db602e one more commit
59c86c9 new commit
e2f44fc (origin/master, origin/HEAD) test
Se trataba de reiniciar, revertir y reajustar los comandos en Git.
Conclusión
Se trataba de reiniciar, revertir y reajustar los comandos en ir. Espero que esta guía paso a paso haya sido útil. Ahora, sabe cómo jugar con sus confirmaciones según la necesidad utilizando los comandos mencionados en el artículo.