Comandos útiles de git
Fusión — Merge
Tener múltiples ramas (branches) es extremadamente conveniente para mantener los cambios nuevos separados entre sí y para asegurarse de que no envíes accidentalmente cambios no aprobados o incompletos a producción. Una vez que se hayan aprobado los cambios, ¡queremos recibir estos cambios en nuestra rama de producción!
Una forma de obtener los cambios de una rama generalmente se realiza ungit merge
! Hay dos tipos de fusiones que Git puede realizar: un avance rápido o un avance sin avance rápido.
Es posible que esto no tenga mucho sentido en este momento, ¡así que veamos las diferencias!
Avance rápido ( --ff
) Fast-forward
Una fusión de avance rápido puede ocurrir cuando la rama actual no tiene confirmaciones adicionales en comparación con la rama que estamos fusionando.
Git es… perezoso y primero intentará realizar la opción más fácil: ¡el avance rápido! Este tipo de fusión no crea una nueva confirmación, sino que fusiona las confirmaciones en la rama que estamos fusionando directamente en la rama actual
¡Perfecto! Ahora tenemos todos los cambios que se hicieron en la rama disponibles en la rama master. Entonces, ¿de qué se trata el avance rápido ?
Sin avance rápido ( --no-ff
) No-fast-foward
Es genial si tu rama actual no tiene confirmaciones adicionales en comparación con la rama que desea fusionar, ¡pero desafortunadamente ese rara vez es el caso! y no podrás hacer Fast-forward o avance rápido.
Si realizamos cambios en la rama actual y la rama que deseamos fusionar no los tienes, git realizará una fusión sin avance rápido .
Con una fusión sin avance rápido, Git crea una nueva confirmación de fusión en la rama activa. ¡Las confirmaciones principales de la confirmación apuntan tanto a la rama activa como a la rama que queremos fusionar!
No es gran cosa, ¡una combinación perfecta! La ramamaster
ahora contiene todos los cambios que hemos hecho en la ramadev
.
Fusionar conflictos
Aunque Git es bueno para decidir cómo fusionar ramas y agregar cambios a los archivos, no siempre puede tomar esta decisión por sí mismo 🙂 Esto puede suceder cuando las dos ramas que intentamos fusionar tienen cambios en la misma línea en el mismo archivo, o si una rama eliminó un archivo que otra rama modificó, y así sucesivamente.
En ese caso, Git te pedirá que ayudes a decidir cuál de las dos opciones queremos conservar. Digamos que en ambas ramas, editamos la primera línea en el archivo README.md
.
Si queremos fusionarnos la ramadev
con la ramamaster
, esto terminará en un conflicto de fusión: y preguntara ¿le gustaría que se conservara la linea de la rama dev o la rama master?
Cuando intente fusionar las ramas, Git le mostrará dónde ocurre el conflicto. Podemos eliminar manualmente los cambios que no queremos conservar, guardar los cambios, agregar el archivo modificado nuevamente y confirmar los cambios.
Aunque los conflictos de fusión suelen ser bastante molestos, tiene mucho sentido: Git no debería simplemente asumir qué cambio queremos conservar.
rebase
Acabamos de ver cómo podíamos aplicar cambios de una rama a otra realizando un git merge
. Otra forma de agregar cambios de una rama a otra es realizando un git rebase
.
A git rebase
copia las confirmaciones de la rama actual y coloca estas confirmaciones copiadas encima de la rama especificada.
Perfecto, ya tenemos todos los cambios que se hicieron en la ramamaster
disponibles en la ramadev
!
Una gran diferencia en comparación con la “merge” es que Git no intentará averiguar qué archivos conservar y no conservar. ¡La rama que estamos reorganizando siempre tiene los últimos cambios que queremos conservar! No te encontrarás con ningún conflicto de fusión de esta manera, y mantiene un buen historial lineal de Git.
Este ejemplo muestra el cambio de base en la ramamaster
. Sin embargo, en proyectos más grandes, por lo general no desea hacer eso. ¡ A git rebase
cambia el historial del proyecto a medida que se crean nuevos hashes para las confirmaciones copiadas!
El cambio de base es excelente siempre que esté trabajando en una rama de características y la rama principal se haya actualizado. ¡Puede obtener todas las actualizaciones en su rama, lo que evitaría futuros conflictos de fusión!
Rebase interactivo
¡Antes de reorganizar los commits, podemos modificarlos! 😃 Podemos hacerlo con un rebase interactivo . Una reorganización interactiva también puede ser útil en la rama en la que está trabajando actualmente y desea modificar algunas confirmaciones.
Hay 6 acciones que podemos realizar en las confirmaciones que estamos reorganizando:
reword
: Cambiar el mensaje de confirmaciónedit
: Modificar este compromisosquash
: fusionar la confirmación con la confirmación anteriorfixup
: fusionar la confirmación con la confirmación anterior, sin conservar el mensaje de registro de la confirmaciónexec
: Ejecutar un comando en cada confirmación que queremos reorganizardrop
: Eliminar la confirmación
¡Increíble! De esta manera, podemos tener control total sobre nuestras confirmaciones. Si queremos eliminar un compromiso, podemos simplemente hacerlo con el comando drop.
O si queremos juntar varias confirmaciones para obtener un historial más limpio, ¡no hay problema!
Resetting — Restablecer
Puede suceder que cometamos cambios que no queríamos más adelante. ¡ Tal vez sea un compromisoWIP
, o tal vez un compromiso que introdujo errores! 🐛 En ese caso, podemos realizar un git reset
.
A git reset
se deshace de todos los archivos provisionales actuales y nos da control sobre dónde HEAD
debería apuntar.
Soft reset — Reinicio suave
¡ Un restablecimiento parcial se mueve HEAD
a la confirmación especificada (o el índice de la confirmación en comparación con HEAD
), sin deshacerse de los cambios que se introdujeron en las confirmaciones después!
Digamos que no queremos conservar la confirmación 9e78i
que agregó un archivo style.css
, y tampoco queremos conservar la confirmación 035cc
que agregó un archivoindex.js
.
El archivostyle.css
Sin embargo, ¡ queremos mantener el index.js
recién agregado! Un caso de uso perfecto para un restablecimiento parcial.
Al escribir git status
, verás que aún tenemos acceso a todos los cambios que se realizaron en las confirmaciones anteriores. ¡Esto es genial, ya que significa que podemos corregir el contenido de estos archivos y enviarlos nuevamente más adelante!
Hard reset — Restablecimiento completo
A veces, no queremos conservar los cambios introducidos por ciertas confirmaciones. A diferencia de un restablecimiento parcial, ya no deberíamos necesitar tener acceso a ellos. Git simplemente debería restablecer su estado a donde estaba en la confirmación especificada: ¡esto incluso incluye los cambios en su directorio de trabajo y archivos preparados!
Git ha descartado los cambios que se introdujeron en 9e78i
y 035cc
y ha restablecido su estado a donde estaba en el commitec5be
.
revert — revirtiendo
Otra forma de deshacer los cambios es realizando un git revert
. ¡Al revertir una determinada confirmación, creamos una nueva confirmación que contiene los cambios revertidos!
Digamos que ec5be
agregó un archivoindex.js
. ¡Más tarde, nos damos cuenta de que ya no queríamos que este cambio se introdujera por este compromiso! Vamos a revertir el commitec5be
.
¡Perfecto! La confirmación 9e78i
revirtió los cambios introducidos por el commitec5be
. Realizar un git revert
es muy útil para deshacer un determinado compromiso, sin modificar el historial de la rama.
Cherry-picking
Cuando una determinada rama contiene un commit que introdujo los cambios que necesitamos en nuestra rama activa, ¡podemos ejecutar cherry-pick
! .
cherry-pick al
enviar una confirmación, creamos una nueva confirmación en nuestra rama activa que contiene los cambios que introdujo el commitcherry-pick
.
Digamos que el commit76d12
en la ramadev
agregó un cambio al archivoindex.js
que queremos en nuestra ramamaster
. ¡No queremos todo , solo nos importa este único commit!
¡ Genial, la rama maestra ahora contiene los cambios que se introdujeron en el commit76d12
!
Fetching
Si tenemos una rama remota de Git, por ejemplo, una rama en Github, ¡puede suceder que la rama remota tenga commit que la rama actual no tiene! Tal vez se fusionó otra rama, tu compañero impulsó una solución rápida, y así sucesivamente.
¡Podemos obtener estos cambios localmente, realizando un git fetch
en la rama remota! No afecta a tu rama local de ninguna manera: fetch
simplemente descarga nuevos datos.
¡Ahora podemos ver todos los cambios que se han realizado desde la última vez que presionamos! Podemos decidir qué queremos hacer con los nuevos datos ahora que los tenemos localmente.
Pulling
Aunque un git fetch
es muy útil para obtener la información remota de una rama, también podemos realizar un git pull
.
git pull
es en realidad dos comandos en uno: a git fetch
y a git merge
. Cuando extraemos cambios desde el origen, primero obtenemos todos los datos como lo hicimos con un git fetch
, después de lo cual los cambios más recientes se fusionan automáticamente en la rama local.
Impresionante, ahora estamos perfectamente sincronizados con la rama remota y tenemos todos los cambios más recientes.
Reflog
Todo el mundo comete errores, ¡y eso está totalmente bien! A veces puede parecer que has estropeado tanto tu repositorio de git que solo quieres eliminarlo por completo.
git reflog
es un comando muy útil para mostrar un registro de todas las acciones que se han realizado. Esto incluye fusiones, reinicios, reversiones: básicamente cualquier alteración en su rama.