131

Flujo de trabajo profesional y Comandos oscuros de Git que te salvan el día

212916Puntos

hace 5 años

Si quieres desarrollar profesionalmente debes entender muy bien cómo funciona Git. No basta con utilizar los comandos básicos (git add, commit, push y pull request). Vamos a entender, de verdad, cómo funciona el flujo de trabajo de un repositorio, qué hacer cuando nos conectamos a un servidor remoto y encontramos conflictos para trabajar en equipo.

Seamos honestos, trabajar con Git es un poco aterrador, ¿verdad? Igual que hacer Pull Requests en GitHub o Merge Requests en GitLab. Pero también sabemos que basta con conocerlos y dominarlos para que convertirlos en nuestros mejores aliados.

Todo esto, de principio a fin, lo puedes aprender en el Curso de Git y Github de Platzi. También esta el Curso de DevOps con Gitlab para aprender a trabajar con pruebas, integraciones y entornos de trabajo automatizados. Te recomiendo ambos cursos.

Voy a mostrarte algunos comandos oscuros de Git que nos pueden salvar la vida. Literalmente. También vamos a repasar un poco el flujo de trabajo de nuestro proyecto y las etapas por las que deben pasar nuestros archivos.

¡Empecemos!

Ciclo de vida y Comandos para cambiar el Estado de nuestros archivos en Git

Así como el agua puede ser líquida, sólida o gaseosa, nuestros archivos pueden vivir y moverse entre diferentes estados cuando nuestro proyecto está conectado con Git.

Recuerda que podemos ver en qué estado se encuentran nuestros archivos usando el comando git status. Cada archivo puede estar en un estado diferente.

Comencemos por los estados normales, esos que son independientes de nuestro trabajo con otras ramas o servidores remotos:

GIT One Branch.png

Untracked: Son archivos que NO viven dentro de Git, solo en nuestro disco duro. Si nunca antes fueron incluidos en el repositorio de Git (por comandos como git add), el sistema de control de versiones no tiene forma de guardar los registros de cambios de este archivo. Pero si estos archivos alguna vez fueron incluidos dentro de Git y fueron removidos por comandos como git rm, entonces Git debe tener registros antiguos sobre estos archivos.

Todos los archivos comienzan en estado Untracked...

Mover un archivo de cualquier estado a Untracked
(pero conservando el archivo en el disco duro)
git rm --cached archivito

Remover un archivo de cualquier estado y del disco duro podremos recuperarlo si el archivo tiene historial dentro de Git,
# o sea, si alguna vez ha estado en un commit
git rm --force archivito

Staged: El Staging es un estado de preparación antes de hacer commit. Aquí guardamos las actualizaciones y nuevas incorporaciones de archivos al proyecto con el comando git add. Son archivos en el área de Staging. Viven dentro de Git, tienen historial de cambios y sus últimas actualizaciones están listas para guardarse definitivamente en un nuevo commit cuando hagamos git commit.

# Mover un archivo al área de Staging
git add archivito

# Mover TODOS los archivos al área de Staging# (excepto por los nombres del archivo .gitignore)
git add -A
git add .

Unstaged: También podemos entender este estado como “Tracked pero Unstaged”. Los archivos en este estado sí tienen historial de cambios en Git… Pero sus últimos cambios todavía no han pasado al área de Staging ni mucho menos han sido guardados en un nuevo commit. Todos los archivos entran a este estado luego de ser editados.

Recuerda que un mismo archivo puede tener ambos estados, Untracked y Unstaged, y eso lo resolvemos volviendo a ejecutar el comando git add para traer al Staging los cambios restantes. También podemos devolver un archivo del estado Staged a Unstaged con el comando git reset HEAD.

# Todos los archivos entran a este estado luego de# ser editados y antes de ser enviados a Staging…# Mover un archivo de Staged a Unstaged:
git reset HEAD archivo

# Mover TODOS los archivos de estado Staged# a Unstaged:
git reset HEAD

Tracked: Son los archivos que viven dentro de Git y no tienen cambios pendientes. Sus últimas actualizaciones han sido guardadas en el repositorio y, a menos que se borren los últimos commits, su historial de cambios está disponible.

Los archivos solo pueden pasar a este estado si antes estuvieron en el área de Staging. Todos los archivos en estado Staged pasan al estado tracked con el comando git commit. También podemos pasar los archivos al área Staged e inmediatamente al estado Tracked con el comando git commit -a.

# Solo podemos hacer commit de archivos Staged…# Commit de archivos en el área de Staging:
git commit -m “Mensaje del commit”

# Pasar archivos al área de Staging y hacer commit# en un solo comando:
git commit -am “Mensaje del commit”

Recuerda que puedes ver los cambios entre los archivos Tracked y Staged con el comando git diff y que puedes volver a un commit anterior con el comando git checkout id-del-commit.

Estados y Comandos para trabajar entre ramas y repositorios remotos

GIT Multiple Branches.png

Al trabajar con ramas diferentes puede que nos encontremos con estos nuevos estados:

Unmerged: Es un estado especial, algo parecido a un estado intermedio entre Untracked y Unstaged. Solo debemos resolver los conflictos (editando nuestros archivos), hacer git add para mandar los cambios a Staging y git commit para guardar los cambios del merge en el repositorio.

Stashed: Es un estado que nos ayuda a guardar los cambios en Staging para poder cambiar sin perder el trabajo que todavía no guardamos en un commit. Nos permite cambiar de ramas, hacer cambios, trabajar en otras cosas y, más adelante, retomar el trabajo con los archivos que teníamos en Staging pero que podemos recuperar ya que los guardamos en el Stash.

¿Qué es git stash? y Fusión de ramas con Git Merge

# Guardar los cambios del Staging en Stash:
git stash

# Retomar los últimos cambios guardados en Stash, recuerda# que pueden generar conflictos que se resuelven igual que# los conflictos de git merge
git stash pop

# Ver la lista de cambios guardados en Stash:
git stash list

# Retomar los cambios de una posición específica del Stash:
git stash apply stash@{x}

# Borrar una posición específica del Stash:
git stash drop stash@{x}

# Aplicar los cambios del Stash a una rama:
git stash branch nombre_de_la_rama

Por último, recuerda que tenemos muchos otros estados cuando trabajamos con repositorios remotos (si, repositorios, en plural). Podemos tener más de un repositorio remoto, por ejemplo, cuando hacemos fork de un proyecto open source, enviamos commits (hacemos git push) al repositorio fork y desde GitHub enviamos pull request al proyecto “original”.

¿Con cuantos repositorios diferentes podemos trabajar?

  • El repositorio remoto original
  • Repositorio local clonado del repositorio remoto original
  • Repositorio remoto fork del original
  • Repositorio local clonado del repositorio remoto fork (SPOILER: podemos conectar el clon de nuestro proyecto a más de un repositorio remoto)

¿Cuantos estados diferentes nos podemos encontrar cuando trabajamos con todos los repositorios juntos? ¿Como se solucionan los conflictos?

Todo está bien si:

  • El repositorio local tiene nuevos cambios o está perfectamente sincronizado con el repositorio remoto original.

Solo debes hacer git push para mandar los últimos cambios al repositorio remoto.

  • El repositorio local tiene nuevos cambios o está perfectamente sincronizado con el repositorio remoto fork que, a su vez, está perfectamente sincronizado con el repositorio remoto original.

Solo debes hacer git push para mandar los últimos cambios al repositorio remoto fork y, cuando todo esté listo, mandas un pull request al repositorio remoto original.

  • El repositorio local no tiene los ultimos cambios del repositorio remoto original.

Solo debes hacer git pull (git fetch y git merge) para traer los últimos cambios del repositorio remoto. De hecho, siempre es muy buena práctica hacer pull antes de intentar hacer push o empezar a trabajar.

  • El repositorio local está perfectamente sincronizado con el repositorio remoto fork… Pero el fork no tiene los ultimos cambios del repositorio remoto original.

Tienes dos opciones:

  1. Hacer un Pull Request desde el repositorio remoto original al repositorio fork y hacer pull desde el repositorio local para traer los nuevos cambios.
  2. Conectar ambos repositorios remotos al repositorio local. La convención es llamar origin al repositorio fork y upstream al repositorio original. Esto significa que puedes hacer pull del repositorio remoto original y push al repositorio remoto.

También recuerda que pueden haber ramas diferentes en cada repositorio y debemos seguir el mismo proceso para cada una.

Casos de uso

Vamos a ver algunos ejemplos y conflictos de la vida real que pueden sucedernos pero, en vez de alarmarnos, debemos aprender de ellos para convertirnos en mejores profesionales.

Caso #1 (noob): Te equivocaste en el mensaje de tu último commit

¿Que haces? Puedes guardar los cambios de los archivos en alguna parte, revertir el commit y volver a empezar. Por supuesto que puedes, pero hay una forma aún más fácil.

Solo debes volver a hacer commit pero esta vez usando el flag --amend para indicarle a GIT que quieres aplicar los cambios sobre el commit anterior.

Por ejemplo:

git commit -m “Arreglado el bug #12”# Wait, ¡era el #13!
git commit --amend -m “Arreglado el bug #13”

Caso #2 (noob): Hiciste commit pero olvidaste algo.

¿Que haces? Puedes hacer los cambios en un nuevo commit, por supuesto, pero esa no es la idea. Este commit estaba destinado a hacer eso que dijiste que debía hacer. Por lo tanto, debes solucionarlo, no solo hacer otro commit.

En realidad, es muy fácil. Solo Haz los cambios que faltaban, luego los añades al staging area (sí, con git add) y usas git commit pero con los flags --amend y --no-edit para aplicar los nuevos cambios al último commit y dejando que el mensaje del commit sea el mismo de antes.

git commit -m “Ahora el carro es rojo”
# Wait, ¡todavía es azul! SHAME...# Hago los cambios para que el carro sea rojo

git add archivo-del-carrito
git commit --amend --no-edit # Yei!!

Recuerda que, aunque el flag --amend nos permite trabajar y hacer correcciones “sobre el mismo commit”, en realidad, estamos creando un nuevo commit y ubicándolo en la línea de tiempo en lugar de los commits donde nos equivocamos.

Esto significa que si trabajamos con alguien más y esas personas trabajan sobre el mismo commit que acabas de corregir con --amend, van a tener problemas y conflictos. Cada uno tendrá historiales diferentes.

Usa --amend con responsabilidad. De preferencia, usa `–amend en los cambios que solo te afectan a ti (en local). Si el error ya llego al resto del equipo es mejor resolver las fallas con ramas y merges.

Caso #3 (noob): Tu trabajo no está listo para hacer commit pero tienes que cambiar de rama para resolver otra cosa

¿Que haces? Lo admito: Hacer commit del trabajo que no está listo (con un mensaje explicando que no está listo) y cambiando de rama con mucho dolor en mi corazón por dañar la lista de mensaje bonitos de mi proyecto. Podemos hacer eso, por supuesto que podemos. Pero existe el comando git stash que puede guardar nuestros cambios prematuros para retomarlos en otro momento.
Ya te explique como funciona git stash. Vamos con un ejemplo:

# El carrito azul está quedando bonito. ¡AY! ¡Tengo un# error gravísimo y debo solucionarlo inmediatamente!# Pero… ¿qué hago con los cambios que no están listos
para hacer commit?

# Batman: ¡No se diga más!
git stash
git checkout -b fix-issue-130

# Juan todo tonto que no sabe para qué sirve git stash:# AAAHHHH NOOO MIS CAMBIOOS NOOOO!!!# Juan arregla el bugsito pero está todo triste porque# no ha tomado el curso de Git en Platzi y piensa que# sus cambios se perdieron para siempre…# Batman:
git stash pop

# Juan viendo que sus avances no se perdieron:# :O____# Batman: I’m Batman.

Caso #4 (pro): Recuperar cambios de ramas que borraste

¿Que haces? Podemos entrar en pánico, por supuesto que puedes. Pero existe un comando que guarda todos nuestros movimientos, los commits que hemos creado, las ramas por donde nos hemos movido, todo lo podemos encontrar con git reflog.

Recuerda que este comando es muy diferente de git log que solo nos muestra los commits de la rama donde nos encontramos. Reflog nos muestra todo el historial, incluso, si las ramas donde trabajamos han sido borradas.

# Juan: El carro es rojo pero yo lo quiero azul... Voy a# crear una nueva rama para probar cómo se vé…
git checkout -b prueba-carro-azul

# El Jefe llega 5 min después: Juan, antes de hacer# cualquier otra cosa quiero que arregles el bug #131...# Juan: ¡Sí señor! Hmm… Esto es demorado. Creo que # voy a borrar la rama `prueba-carro-azul` para solo# enfocarme en el bugsito del jefe…# El tonto Juan borra la rama `prueba-carro-azul` y# arregla el bug que le dijo el jefe… Por supuesto, Juan# no recordaba que existía `git stash`... Juan es muy# novato y debería tomar el curso de Git en Platzi...# Juan después de arreglar el bugsito del jefe:# Hmm… Creo que quiero probar con el carrito azul# pero ya borre la rama con los cambios… ¿Y ahora?# Batman: ¡No se diga más!
git reflog
# … batman busca y copia el id del último commit de la# rama `prueba-carrito-azul` y lo pega al final de:
git checkout -b carrito-azul-segundo-intento id-del-commit

# Juan: :O____# Batman: I’m Batman.

Caso #5 (ALERTA DE CONTENIDO ULTRA VIOLENTO): git push --force (AHHH)

DO NOT USE GIT PUSH --FORCE!

El más oscuro de todos los comandos creados por todos los programas creados hasta el dia de hoy. Cada vez que lo usas muere un conejito. De hecho, como si no fuera suficiente, ese conejito va hasta tu casa y te atormentará el resto de días de tu vida recordándote que fuiste una mala persona y por tu culpa murió un conejito.

Nunca lo uses. Nunca lo menciones. Tu no sabes que existe ni mucho menos que yo te lo conte.

Este comando lo menciono por lo contrario; para que nunca lo uses. Por favor, aprende a convivir (en vez de luchar) con los conflictos. Están hechos por y para ti. Solo debemos aprender los comandos y los flujos de trabajo para solucionarlos.

En vez de esto, puedes (entre algunas otras formas de resolver este problema) usar diferentes ramas, generar conflictos, resolver los conflictos y, finalmente, hacer push a nuestro repositorio sin necesidad del flag --force.

Branch en Git: Qué es y cómo hacer ramas.

Conclusiones

Todos estos comandos, desde el comienzo con git init hasta la mejor forma de resolver conflictos entre archivos, los puedes aprender en el Curso de Git y GitHub de Platzi. GitHub y GitLab (y Bitbucket o la plataforma que te guste) son muy poderosos pero solo sacaremos su máximo potencial si entendemos, de verdad, cómo funciona GIT. Además, GitLab tiene herramientas de DevOps muy poderosas que vale la pena aprender una vez tenemos las bases sólidas de Git.

#NuncaParesDeAprender y #NuncaParesDeAprenderGIT 🤓 💚

Juan
Juan
juandc

212916Puntos

hace 5 años

Todas sus entradas
Escribe tu comentario
+ 2
Ordenar por:
11
14176Puntos

Un deporte extremo:
git rm -r --force * —> ves el diablo
git reset hard --hard [hash] —> ves una luz

2
14176Puntos
5 años

*git reset --hard [hash] — ups

2
212916Puntos
5 años

😂

2
13649Puntos
5 años

Hahaha lo hice cuando aprendí git
😄

3
8219Puntos

Nadie:
De verdad, NADIE:

Batman: I’m Batman.
2
4368Puntos

Muy bien explicado!!

2
7495Puntos

Excelente aporte. Gracias
De mis comandos favoritos el git stash, salva mucho trabajo.
Saludos

2
41676Puntos

No se por qué, pero por alguna razón cada vez que se usaba un ejemplo de algún comando lo leía con la voz de Freddy jajaja
Muy bien explicado y guardado para consultas futuras.

1
212916Puntos
5 años

😎😬

2
14898Puntos

Graaaaaaaaaaacias! Hoy tuve un lunes negro con Git :p

1
212916Puntos
5 años

💪💪

2
30236Puntos

Muy pro, vendría bien un nuevo post con otros commandos o cosas que hayas aprendido.

2
10877Puntos

Genial, sobretodo la parte de los conejitos jajaja

2
5691Puntos

Dios, es la explicación definitiva de los estados de Git y los distintos comandos para cambiar entre ellos. Me ha ayudado a entender cosas que no terminaba de pillar. ¡Gracias!

1

Wow, queda super bien despues de tomado el curso.Super buen resumen!

1
24892Puntos

Yo actualmente estoy tomando el curso de Git y GitHub de Freddy, y sin duda es todo un dolor de cabeza, pero sé que va a ser para bien. Y tengo muchos compañeros desarrolladores que me dicen que Git sin duda despues de que lo haya aprendido y lo haya dominado me va a cambiar la vida por completo (aunque creo que ya lo hizo 😅👌)

1
19273Puntos

No se porque rei diabólicamente e hice un git push --force, efectivamente fue rechazado mi push pero tenia que intentarlo.