Lección 1 de 314 min
Git y GitLab
Commits, ramas, merge y rebase, remotos, flujos de trabajo y merge requests en GitLab.
Imagina a tres personas editando a la vez la misma web. Sin una herramienta que ponga orden, acabas con carpetas como tienda-final-v2-AHORA-SI.zip, cambios que se pisan y nadie que sepa qué versión hay en producción. Git resuelve eso: guarda la historia completa del proyecto y permite que cada persona trabaje en paralelo y después combine su trabajo con el de las demás.
En esta lección verás cómo piensa Git por dentro, cómo se combinan las ramas, cómo se sincroniza tu copia con un servidor y qué flujos de trabajo usan los equipos. Terminarás con GitLab, la plataforma donde vive el código de muchos equipos y donde arranca el pipeline que verás en la lección siguiente.
Cómo piensa Git
Git es un sistema de control de versiones distribuido: cada persona tiene en su máquina una copia completa del repositorio, con toda su historia. Puedes hacer commits, crear ramas y consultar el pasado sin conexión.
Commits, hashes y staging area
Git guarda fotos completas del proyecto, identificadas por un hash, no listas de cambios.
- Creado por:
- Linus Torvalds
- Desde:
- 2005
- Tipo:
- distribuido
Cada commit es una instantánea (snapshot) del proyecto en un momento dado, junto con su autor, la fecha, un mensaje y un enlace al commit anterior, su «padre». Conceptualmente, Git no guarda las diferencias entre versiones, sino la foto completa; si un archivo no ha cambiado, reutiliza el que ya tenía.
Cada commit se identifica con un hash: una huella de 40 caracteres hexadecimales calculada a partir de su contenido, como 3de9e4b…. Si cambia un solo byte, cambia el hash, así que nadie puede alterar la historia sin que se note. En el día a día basta con los primeros siete caracteres para referirse a un commit.
Entre tu carpeta de trabajo y la historia hay una zona intermedia, la staging area (o índice). Con git add eliges qué cambios entran en la próxima foto y con git commit la tomas. Así puedes hacer un commit con solo una parte de lo que has tocado.
Úsalo cuando
Siempre que trabajes con código, aunque sea en solitario: un commit pequeño y con un buen mensaje es un punto al que siempre puedes volver.
Ten en cuenta
Lo que entra en la historia compartida se queda ahí: nunca guardes contraseñas ni claves, aunque las borres en el commit siguiente. Usa .gitignore para excluir archivos como .env o node_modules.
git init # crea el repositorio en la carpeta actual
git status # qué ha cambiado y qué está preparado
git add src/carrito.ts # prepara solo este archivo
git commit -m "Añade el botón de vaciar el carrito"
git log --oneline # la historia, un commit por línea
# a1f3c9e Añade el botón de vaciar el carrito
# 3de9e4b Primer commitRamas y HEAD
Una rama no es una copia: es una etiqueta móvil que apunta a un commit.
- Rama principal:
- main, por convención
Una rama no duplica archivos: es un puntero ligero a un commit. Cuando haces un commit nuevo estando en una rama, el puntero avanza solo. Por eso crear una rama en Git es instantáneo, y los equipos crean una para cada cambio.
HEAD indica dónde estás: normalmente apunta a la rama actual. git branch lista y crea ramas, y git switch cambia de una a otra (en el Git moderno sustituye a la parte de git checkout que hacía eso). Si te sitúas en un commit concreto en lugar de en una rama, quedas en «HEAD separado» (detached HEAD): puedes mirar, pero los commits que hagas no pertenecen a ninguna rama.
Úsalo cuando
Para cualquier cambio que todavía no quieras mezclar con la rama principal: una funcionalidad, una corrección o un experimento.
Ten en cuenta
Si cambias de rama con cambios sin guardar, Git puede negarse o arrastrarlos contigo. Haz commit antes o apártalos un momento con git stash.
git branch # lista las ramas; * marca la actual
git switch -c cupones # crea la rama «cupones» y se cambia a ella
# ...editas y haces commits...
git switch main # vuelve a main: los archivos cambian al instante
git branch -d cupones # borra la rama cuando ya está integradaCombinar el trabajo
Tarde o temprano, el trabajo de una rama tiene que volver a la principal. Git ofrece dos formas de hacerlo, y la elección cambia cómo queda la historia.
git merge
Une dos ramas conservando la historia tal y como ocurrió.
git merge cupones, ejecutado desde main, trae a main el trabajo de cupones. Si main no ha avanzado desde que creaste la rama, Git hace un fast-forward: simplemente mueve el puntero de main hacia delante, sin crear nada nuevo.
Si las dos ramas han avanzado, Git crea un commit de merge con dos padres, que une ambas líneas. La historia refleja fielmente lo que pasó, aunque con muchas ramas puede parecer un mapa de metro. Con --no-ff fuerzas el commit de merge incluso cuando cabría un fast-forward, para dejar constancia de que hubo una rama.
Si las dos ramas tocaron las mismas líneas, aparece un conflicto: Git marca el archivo con <<<<<<<, ======= y >>>>>>> y te deja decidir. Lo resuelves editando el archivo, haces git add y terminas con git commit.
Úsalo cuando
Para integrar ramas compartidas o cuando quieres conservar la historia exacta. Es la opción segura: nunca reescribe commits existentes.
Ten en cuenta
Muchos commits de merge pequeños («Merge branch main into cupones») ensucian la historia. Por eso GitLab permite aplastar (squash) los commits de una rama en uno solo al fusionarla.
git switch main
git merge cupones
# Si main no había avanzado:
# Fast-forward → main apunta ahora al último commit de cupones
# Si las dos ramas avanzaron:
# Merge made by the 'ort' strategy → nuevo commit con dos padresgit rebase
Reaplica tus commits encima de otra rama para obtener una historia lineal.
git rebase main, ejecutado desde tu rama, toma tus commits y los vuelve a aplicar uno a uno sobre el último commit de main, como si hubieras empezado a trabajar hoy. El resultado es una historia lineal, sin commits de merge, más fácil de leer con git log.
El precio es que reescribe la historia: los commits reaplicados son nuevos y tienen otros hashes, aunque su contenido sea el mismo. Con git rebase -i (interactivo) puedes además reordenar, renombrar o fusionar commits antes de compartirlos.
Úsalo cuando
Para poner al día tu rama local con main antes de abrir un merge request, o para limpiar tus commits antes de que nadie los revise.
Ten en cuenta
La regla de oro: nunca hagas rebase de una rama que otras personas ya usan. Si reescribes commits que alguien tiene en su máquina, vuestras historias divergen y el arreglo es doloroso. Si rebasas tu propia rama ya subida, envíala con git push --force-with-lease, que se niega a sobrescribir trabajo ajeno.
# Antes: main: A - B - C
# cupones: A - B - X - Y
git switch cupones
git rebase main
# Después: cupones: A - B - C - X' - Y'
# X' e Y' tienen el mismo contenido que X e Y, pero otro hash
git push --force-with-lease # solo si la rama ya estaba en el servidorRemotos: clone, fetch, pull y push
Cómo tu repositorio local se sincroniza con el del servidor.
Un remoto es otra copia del repositorio, normalmente en un servidor como GitLab. git clone descarga el repositorio completo y guarda su dirección con el nombre origin, el remoto por defecto. Git recuerda dónde estaba cada rama del servidor con ramas de solo lectura como origin/main.
git fetch descarga los commits nuevos del servidor y actualiza origin/main, pero no toca tus ramas: puedes revisar qué ha cambiado antes de integrarlo. git pull hace un fetch y después integra los cambios en tu rama actual (con merge o, si lo configuras, con rebase). git push sube tus commits al servidor.
Úsalo cuando
A diario: git pull al empezar, para partir de lo último, y git push en cuanto tengas algo que otra persona deba ver o que el pipeline deba probar.
Ten en cuenta
Si alguien subió commits antes que tú, el servidor rechaza tu git push: integra primero sus cambios con git pull. No lo «arregles» con --force en una rama compartida, porque borrarías el trabajo de otra persona.
git clone https://gitlab.com/mi-equipo/tienda.git
cd tienda
git remote -v # origin https://gitlab.com/mi-equipo/tienda.git
git fetch # descarga lo nuevo sin tocar tus ramas
git log --oneline main..origin/main # ¿qué hay en el servidor que yo no tengo?
git pull # fetch + integración en tu rama actual
git push -u origin cupones # sube la rama y la enlaza con origin/cuponesTrabajar en equipo
Git no impone cómo organizar las ramas: eso lo decide el equipo con un flujo de trabajo. Los tres más comunes van del más estructurado al más ligero, y todos se apoyan en una plataforma como GitLab para revisar y proteger el código.
Ramas de funcionalidad (feature branches)
Una rama corta por cada cambio, que vuelve a main tras una revisión.
Es el flujo más extendido: main siempre funciona y se puede desplegar, y cada cambio se hace en su propia rama (feature/cupones, fix/iva). Se abre un merge request, el pipeline lo prueba, alguien lo revisa y se fusiona. Es lo que GitHub llama GitHub Flow y la base del GitLab Flow.
La clave está en que las ramas vivan poco: días, no semanas. Cuanto más tiempo pasa una rama separada, más se aleja de main y más dolorosos son los conflictos al juntarlas.
Úsalo cuando
En la mayoría de equipos que despliegan aplicaciones web con frecuencia y quieren revisar cada cambio antes de que llegue a main.
Ten en cuenta
Una rama que crece durante semanas se convierte en un proyecto paralelo. Divide el trabajo en merge requests pequeños y, si algo no está listo, ocúltalo tras un feature flag.
git switch -c feature/cupones main
# ...commits...
git push -u origin feature/cupones
# En GitLab: merge request → pipeline en verde → revisión → merge
git switch main
git pull # main ya incluye los cuponesGitFlow
Un modelo con ramas fijas para el desarrollo, las versiones y los parches urgentes.
- Propuesto por:
- Vincent Driessen
- Desde:
- 2010
GitFlow, propuesto por Vincent Driessen en 2010, usa dos ramas permanentes: main, que solo contiene versiones publicadas, y develop, donde se integra el trabajo. A su alrededor viven ramas temporales: las feature/* salen de develop, las release/* preparan una versión y las hotfix/* corrigen urgencias directamente sobre main.
Encaja con productos que publican versiones numeradas cada cierto tiempo y mantienen varias a la vez, como una aplicación de escritorio o una librería. Para una web que se despliega varias veces al día resulta pesado; su propio autor añadió años después una nota recomendando flujos más simples en ese caso.
Úsalo cuando
Cuando publicas versiones planificadas (por ejemplo, una al mes), necesitas un periodo de estabilización antes de cada una o mantienes varias versiones en uso.
Ten en cuenta
Cada cambio recorre varias ramas y cada hotfix hay que fusionarlo en dos sitios. Si haces entrega continua, la rama develop solo añade retraso y conflictos.
git switch -c feature/cupones develop # el trabajo nace en develop
git switch develop
git merge --no-ff feature/cupones
git switch -c release/2.4.0 develop # se estabiliza la versión
git switch main
git merge --no-ff release/2.4.0
git tag v2.4.0
git switch develop
git merge --no-ff release/2.4.0 # y vuelve también a developTrunk-based development
Todo el equipo integra en la rama principal al menos una vez al día.
En el desarrollo basado en el tronco (trunk), todo el mundo integra en main con mucha frecuencia: directamente o con ramas que duran horas, no días. No hay ramas largas donde acumular trabajo, así que los conflictos son pequeños y la integración es continua de verdad.
Para que el código a medio hacer no moleste, se esconde tras feature flags: interruptores que activan una funcionalidad solo cuando está lista. Exige una buena batería de pruebas automáticas y un pipeline rápido, porque main debe estar siempre en verde.
Úsalo cuando
En equipos con pruebas automáticas sólidas que quieren desplegar de forma continua. Es el flujo que mejor encaja con la integración continua de la lección siguiente.
Ten en cuenta
Sin pruebas fiables, integrar a diario en main significa romperlo a diario. Y los feature flags hay que retirarlos cuando ya no hacen falta, o se acumulan como deuda.
// La funcionalidad ya está en main, pero apagada hasta que esté lista
if (flags.estaActivo("pago-en-cuotas")) {
mostrarOpcionDeCuotas();
}GitLab
Una plataforma todo en uno: repositorios, issues, revisión, CI/CD y seguridad.
- Modalidades:
- GitLab.com o autogestionado
- Alternativa:
- GitHub
GitLab aloja repositorios Git y añade todo lo que rodea al código: issues para planificar tareas y errores, merge requests para revisar cambios, pipelines de CI/CD, un registro de imágenes de contenedor, wikis y análisis de seguridad. Se presenta como una plataforma DevSecOps: desarrollo, seguridad y operaciones en un mismo sitio.
Puedes usarlo como servicio en GitLab.com o instalarlo en tus propios servidores (autogestionado), algo habitual en empresas que no pueden sacar el código de su red. Tiene una edición gratuita y planes de pago con funciones extra.
Las ramas protegidas impiden subir directamente a main o reescribir su historia: los cambios solo entran mediante un merge request. Y si escribes Closes #42 en un commit o en la descripción de un merge request, la issue 42 se cierra sola cuando el cambio llega a la rama por defecto.
Úsalo cuando
Cuando quieres que código, tareas, revisión y pipeline estén en una sola herramienta, o necesitas alojarlo todo en tu propia infraestructura.
Ten en cuenta
Su gran alternativa es GitHub, con conceptos casi idénticos: allí los merge requests se llaman pull requests y los pipelines, GitHub Actions. Ten en cuenta también que algunas funciones dependen del plan contratado.
git commit -m "Corrige el redondeo del IVA
Closes #42"
git push
# Cuando este commit llegue a main, GitLab cerrará la issue #42
# y la enlazará con el commit que la resolvió.Merge requests y revisión de código
La puerta de entrada a main: diff, comentarios, pipeline y aprobación.
Un merge request (MR) es una petición para fusionar una rama en otra. GitLab muestra el diff, ejecuta el pipeline sobre esos cambios y permite comentar cualquier línea. El cambio no se fusiona hasta que los comentarios están resueltos y alguien lo aprueba.
La revisión de código no sirve solo para cazar errores: reparte el conocimiento del proyecto y mantiene un criterio común. Funciona mejor con MR pequeños, una descripción que explique el porqué y comentarios sobre el fondo; el formato déjaselo a herramientas como Prettier, que verás en el módulo de testing y calidad.
Al fusionar puedes crear un commit de merge, aplastar (squash) todos los commits de la rama en uno o exigir un fast-forward. Si el MR aún no está listo, márcalo como borrador (draft) para que nadie lo fusione por error.
Úsalo cuando
Para cualquier cambio que vaya a main en un equipo, aunque sea de una línea: el pipeline y una segunda mirada cuestan menos que un error en producción.
Ten en cuenta
Un MR con miles de líneas no lo revisa nadie de verdad: se aprueba por cansancio. Si crece demasiado, pártelo en varios.
# GitLab permite crear el MR al hacer push, con opciones del propio Git
git push -u origin feature/cupones \
-o merge_request.create \
-o merge_request.target=main \
-o merge_request.title="Añade cupones de descuento"Interactivo
Tres formas de organizar las ramas
Activa o desactiva opciones para compararlas cara a cara.
| Característica | Ramas de funcionalidad | GitFlow | Trunk-based |
|---|---|---|---|
| Ramas permanentes | Solo main | main y develop | Solo main |
| Vida de una rama de trabajo | Días | Días o semanas | Horas, o ninguna rama |
| Ritmo de publicación | Frecuente, tras cada merge | Versiones planificadas | Continuo, varias veces al día |
| Complejidad | Baja | Alta | Pocas ramas, mucha disciplina |
| Encaja con | La mayoría de aplicaciones web | Productos con versiones numeradas y varias en mantenimiento | Equipos con muchas pruebas y feature flags |
Ponlo en práctica
Saber qué es cada cosa es la mitad del trabajo. La otra mitad es reconocer cuándo usarla.
Interactivo
¿Qué usarías?
Lee cada situación y elige la opción que mejor la resuelve. Fallar aquí no cuenta: es para practicar.
Has hecho cuatro commits en tu rama local, que nadie más ha visto. Mientras tanto, main ha avanzado y quieres que tus commits queden encima, con una historia lineal, antes de abrir el merge request.
Para recordar
- Un commit es una instantánea del proyecto identificada por un hash; la staging area te deja elegir qué entra en cada una.
- Una rama es un puntero móvil a un commit y HEAD indica en cuál estás: crearlas no cuesta nada, así que usa una para cada cambio.
- Merge conserva la historia tal como ocurrió; rebase la deja lineal reescribiendo commits, así que úsalo solo en ramas que nadie más usa.
fetchdescarga sin tocar nada,pulldescarga e integra ypushsube;origines el nombre del remoto por defecto.- Ramas cortas, merge requests revisados, ramas protegidas y un pipeline en cada cambio son la base del trabajo en equipo en GitLab.
Comprueba lo aprendido
Cuestionario
Responde las 5 preguntas para completar la lección.
1.¿Qué es exactamente una rama en Git?
2.Haces
git merge featuredesdemainy Git responde «Fast-forward». ¿Qué ha pasado?3.¿Por qué no debes hacer rebase de una rama que ya usan otras personas?
4.¿Qué diferencia hay entre
git fetchygit pull?5.Has modificado tres archivos, pero solo quieres que uno entre en el próximo commit. ¿Qué te lo permite?