Últimos primeros 3 comandos de git (capítulo III)

Últimos primeros 3 comandos de git (capítulo III)

Trabajando en equipo: remotes y push/pull

Éste es, tal vez, el final de la serie sobre Git. La verdad, podríamos escribir un libro sobre sus comandos (de hecho, los hay), pero la idea principal de estos artículos es que uno pueda arrancar de cero entendiendo qué problemas resuelve y cómo. Al menos de forma básica. Acá los links al capítulo I y al capítulo II .

Así que acá vamos, tercera entrega, tercer problema.

5ivr72.jpg

El problema

Tan pronto Héctor y Antony empezaron a desarrollar una aplicación, se dieron cuenta que compartir el progreso de cada uno con el otro no era, por decirlo de alguna forma, trivial.
Primero, dividieron las tareas como para no tener que depender de lo que hacía el otro. Después, cuando fue inevitable, empezaron a mandarse el código por email, y a dedicar tiempo a poner todo en común, juntando ambas partes en una computadora. Mientras se juntaban los códigos de ambos, nadie podía hacer nada más, porque había que esperar la nueva versión "común" para seguir desde ahí.
Conforme la aplicación crecía en complejidad, la puesta en común empezó a tomar cada vez más tiempo. Incluso a tal punto, que necesitaron asignar un responsable de la tarea. Los errores se volvieron frecuentes: a veces, el código de uno "pisaba" partes fundamentales del otro, y eso hacía que siempre hubiese funcionalidades rompiéndose. El resultado? una aplicación inestable, entregas de funcionalidad fuera de la fecha pactada, frustración y mal humor.

Git y el trabajo en equipo

Hasta ahora, tanto Jorge como Ivy estuvieron trabajando solos. Cada uno en su propia computadora. Git les venía ofreciendo un repositorio "local" donde versionar su código, y en donde podían cortar branches y volver a sincronizarlos si lo necesitaban.
Pero en realidad, una de las características más importantes (sino la más importante) de los versionadores de código es la de poder sincronizar el trabajo de varias personas.
Así que vayamos un nivel más arriba de los branches: sincronicemos varios repositorios.

Para ésto, hay que crear un repositorio remoto que todos van a usar como referencia u origen del proyecto. Dónde? Hay varias empresas que ofrecen repositorios gratuitos en la nube, las más conocidas son: GitHub , GitLab , BitBucket y seguro hay varias más. Para hacer uso de dichos repos, sólo hay que crear una cuenta e iniciar sesión.

Después, los pasos para crear el repo son más o menos iguales para todos:

  • definir un nombre y una descripción
  • elegir si va a ser público o privado
  • seleccionar la licencia del código
  • y finalmente, uno recibe un ID del repo para poder subir tu código.

remotes

Supongamos que estamos usando GitHub con nuestro flamante usuario super-hacker-123 y que creamos un proyecto llamado "Mi Proyecto Genial".
Una vez creado recibimos instrucciones para arrancar de cero, o sincronizar nuestro trabajo, de tener algo de código en nuestra máquina.

Empezando de cero:

echo "# mi-proyecto-genial" >> README.md
git init
git add README.md
git commit -m "first commit"
git branch -M main
git remote add origin git@github.com:super-hacker-123/mi-proyecto-genial.git
git push -u origin main

Si ya tenemos un repo local:

git remote add origin git@github.com:super-hacker-123/mi-proyecto-genial.git
git branch -M main
git push -u origin main

En ambos casos hay instrucciones que no conocemos. Repasemos:

  • Con git remote add estamos diciéndole a git que agregue una referencia a un repo remoto que vamos a llamar origin y que está ubicado en el ID super-hacker-123/mi-proyecto-genial.git.
  • Con git branch -M main estamos renombrando el branch actual donde estamos a main que de ahora en más vamos a usar como el principal. El parámetro M (mayúscula) significa que queremos forzar el cambio de nombre.
  • El último paso es git push, con el que subimos los cambios al repo remoto origin, en el branch remoto main. El parámetro u configura el repo y branch remoto por defecto para éste branch local. La próxima vez desde éste branch podemos hacer simplemente git push y git va a saber a dónde enviar nuestros cambios.

Creo que vale la pena resaltar que uno puede sincronizar cualquier branch con el repo remoto, no solamente main. Por ejemplo, si estoy trabajando en mi branch listado-de-productos, puedo sincronizar mis cambios para compartirlos con otras personas o simplemente como backup.

Sincronizando cambios con el equipo

Hasta acá lo que hicimos fue agregar el proyecto a un repo remoto. No es gran cosa pero es el primer paso para empezar a trabajar en equipo. Ahora Héctor y Antony tienen un punto de referencia en común para tener la versión final con los cambios de ambos.

Pero cómo compartimos los cambios?
Empecemos asumiendo el escenario en que Héctor tiene que bajarse cambios de Antony. Y digo "bajarse" porque asumo que el repo remoto está "en la nube". Así que "subimos" cambios al repo remoto para compartirlos con el equipo, y nos "bajamos" los cambios de los demás.
Si si, todavía no sabemos bien cómo subir los cambios, pero quiero hacer énfasis en una buena práctica que nos va a ayudar a trabajar en equipo.

Bajando cambios a mi repo local

Uno no trabaja directamente con el repo remoto, sino que siempre trabaja con el repo local, a veces offline, y sincroniza los cambios cuando le parece necesario.
Para bajar los cambios de Antony, Héctor ejecuta:

$ git pull origin main
remote: Enumerating objects: 4, done.
remote: Counting objects: 100% (4/4), done.
remote: Compressing objects: 100% (2/2), done.
remote: Total 3 (delta 0), reused 3 (delta 0), pack-reused 0
Unpacking objects: 100% (3/3), 315 bytes | 157.00 KiB/s, done.
From https://github.com/super-hacker-123/mi-proyecto-genial.git
 * branch            main       -> FETCH_HEAD
Updating 4c47631..6a7cda1
Fast-forward
 README.md | 2 ++
 1 file changed, 2 insertions(+)
 create mode 100644 README.md

$ git status
On branch main
nothing to commit, working tree clean

Con git pull origin main nos trajimos a nuestro repo local los cambios del branch main del repo remoto origin.
También se ve que los cambios son dos líneas agregadas en un archivo llamado README.md.

Nota mental: es una buena práctica tener un archivo README.md en la base del repo. GitHub y otros suelen tomar éste archivo para mostrar información en la página principal del repo. El formato del archivo es markdown.

Y hay algo más, que aparece inocentemente ahí pero que es muy importante: Fast-forward. Esto significa que al bajar los cambios y sincronizarlos con lo que hay en el repo local git no encontró ningún conflicto, y que aplicó todo automáticamente.
Esto no siempre es así, porque puede suceder que Antony justo modificó un archivo en el que Héctor venía trabajando. Y entonces tenemos que mergear.
Esto ya lo vimos en los capítulos anteriores, es lo mismo con la única diferencia que ahora el cambio viene del trabajo de alguien más.

Subiendo mis cambios al repo remoto

Una vez que trabajamos en algo y queremos subirlo al repo remoto, lo hacemos así:

$ git push origin main
Enumerating objects: 4, done.
Counting objects: 100% (4/4), done.
Delta compression using up to 16 threads
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 335 bytes | 335.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0), pack-reused 0
To https://github.com/super-hacker-123/mi-proyecto-genial.git
   4c47631..6a7cda1  main -> main

Con git push origin main estamos subiendo nuestros cambios al branch main del repo remoto llamado origin.
Acá git nos ayuda evitando que subamos cambios si el branch remoto tiene cambios nuevos. Cuando ésto sucede, tenemos que bajar los cambios, mergear si es necesario, para recién ahí poder subir lo nuestro.
Por ejemplo:

$ git push origin main
To https://github.com/super-hacker-123/mi-proyecto-genial.git
 ! [rejected]        main -> main (non-fast-forward)
error: failed to push some refs to 'https://github.com/super-hacker-123/mi-proyecto-genial.git'
hint: Updates were rejected because the tip of your current branch is behind
hint: its remote counterpart. Integrate the remote changes (e.g.
hint: 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

Buenas prácticas

Bajar el código y mergear frecuentemente. Así a la hora de subir no se encuentran con que git no se lo permite.

En la misma línea, subir cambios pequeños, frecuentemente. Así se evita tener que mergear gran cantidad de código cada vez que se actualiza. También ayuda a trabajar de forma más ordenada y por etapas.

Usar a main como branch principal y trabajar con branches distintos por cada funcionalidad que se agrega. Esto puede parecer engorroso al principio, pero ayuda mucho cuando se va poniendo el trabajo en común y se quiere salir a producción.

Conclusión

Volviendo al problema inicial, Ahora Héctor y Antony pueden integrar cambios usando el repo remoto como referencia. Con git integrado al repo de GitHub, pueden ordenar la forma en que los cambios se van agregando, al mismo tiempo que evitan pisarse el código.
Hay muchas cosas más por aprender de git. Dos temas que quedan en el tintero son: Pull Requests y Rollbacks. Ojalá pueda volver sobre éstos dos en algún momento. Esto es sólo el principio como para entender la herramienta.

Espero que les sirva y les haya gustado. Si tienen comentarios, dudas, críticas (de las constructivas eh!), son todas bienvenidas. Súmense al canal de Telegram donde charlamos de Software y nos comentan ahí.

Gracias por leer!