En el Nivel 0 aprendiste el flujo de una persona trabajando en solitario: add, commit, push.
Con eso ya ganas el ochenta por ciento del día a día. Pero en cuanto aparece un segundo
desarrollador, o tú mismo empiezas a gestionar varias funcionalidades a la vez, ese flujo
se queda corto.
Lo que cambia en el Nivel 9 no es Git en sí: es el contexto en el que lo usas. El mismo repositorio, pero ahora hay más de una línea de trabajo, hay revisión de código antes de integrar, y a veces dos personas tocan el mismo fichero a la vez. Git tiene herramientas para todo eso. Este capítulo las presenta en orden, del problema al comando.
El Team Builder sale del playground y entra a un repo local real. Para los ejercicios de este nivel necesitas tu Team Builder de React en tu máquina, en un repositorio de git, subido a GitHub. Si vienes construyéndolo desde el Nivel 7, ya lo tienes. Si necesitas un punto de partida limpio, el ejercicio del capítulo te explica cómo crearlo en minutos. A partir de aquí, los ejercicios son flujos reales, no playgrounds: un flujo de equipo necesita un repositorio de verdad.
Una rama por tarea#
Hasta ahora has trabajado siempre en main. Eso funciona cuando hay una persona y una
tarea a la vez, pero en cuanto hay dos funcionalidades en marcha al mismo tiempo el
historial se convierte en un ruido donde es imposible saber qué pertenece a qué.
La solución es una rama por tarea. Una rama es simplemente un puntero a un commit: un nombre que le das a una línea de trabajo para poder cambiar de contexto sin mezclar nada.
main: A ── B ── C
\
feature: D ── EEn este diagrama, A, B y C son commits de main. Cuando creaste la rama feature
a partir de C, empezaste a añadir tus commits (D, E) sin tocar main. Mientras tanto,
si alguien hace otro commit en main, las dos líneas siguen siendo independientes.
Los comandos para trabajar con ramas:
# crea la rama feature/filtro-por-rol y te mueve a ella en un solo paso
git switch -c feature/filtro-por-rol
# comprueba en qué rama estás y cuáles existen
git branch
# vuelve a main (o a cualquier otra rama existente)
git switch mainEl nombre de la rama importa para el equipo. La convención más extendida es un prefijo que
describe el tipo de trabajo: feature/ para funcionalidades nuevas, fix/ para arreglos,
chore/ para tareas de mantenimiento. El sufijo describe la tarea concreta: feature/filtro-por-rol,
fix/partidas-reinhardt.
En el Team Builder crearías una rama así para añadir el filtro por rol (tanque, daño, soporte)
sin tocar nada de lo que ya funciona en main. Si el filtro resulta ser más complicado de lo
esperado, main sigue intacto y en cualquier momento puedes volver a él.
Pull requests: pedir que revisen tu código#
Un pull request (o PR) no es un comando de Git: es una función de GitHub (y de GitLab, Bitbucket y otros forges similares). Es la forma de decirle al equipo: “he terminado esta parte, ¿alguien la revisa antes de que la integre?”.
El flujo es el siguiente. Trabajas en tu rama, haces tus commits, subes la rama al remoto, y
entonces abres un PR apuntando a main. GitHub te muestra la diferencia entre tu rama y main,
y cualquier miembro del equipo puede comentar línea por línea, pedir cambios o aprobar. Cuando
hay acuerdo, el PR se fusiona.
La revisión no es un trámite: es la red de seguridad. Un segundo par de ojos antes de integrar
en main atrapa errores que quien escribe el código no ve, alinea al equipo en cómo se resuelven
los problemas, y crea un registro escrito de por qué se decidió algo de una manera y no de otra.
Para abrir un PR desde la terminal, la GitHub CLI que ya viste en el Nivel 0 lo hace en un comando:
# sube la rama al remoto y la registra como rama de seguimiento
git push -u origin feature/filtro-por-rol
# abre el PR hacia main con título y descripción
gh pr create \
--base main \
--head feature/filtro-por-rol \
--title "feat: filtro de héroes por rol" \
--body "Añade un selector de rol que filtra el roster en tiempo real."También puedes abrirlo desde la web de GitHub, que es lo más habitual al principio. Tras hacer
el git push, GitHub muestra un aviso en la página del repositorio con un botón para crear el PR
directamente.
Fusionar: merge o rebase#
Cuando el PR recibe aprobación, toca integrar la rama en main. Hay dos formas de hacerlo y
producen historiales distintos.
Merge crea un commit de fusión que une las dos líneas. El historial refleja lo que ocurrió de verdad: dos líneas paralelas que se juntaron en un punto.
main: A ── B ── C ────────── F
\ /
feature: D ── E ──
(commit de merge F)Rebase toma tus commits y los reescribe encima del último commit de la rama destino. La
historia queda lineal: parece que siempre trabajaste a partir de lo último que había en main.
main: A ── B ── C ── D' ── E'
(tus commits, reescritos)Ninguno es universalmente mejor. Merge preserva el contexto histórico. Rebase produce un
historial más fácil de leer con git log. Muchos equipos usan rebase para limpiar su rama
antes de pedir revisión, y merge para la fusión final en main. Cuando main avanza de forma
limpia y sin commits de fusión por medio, se llama fast-forward: Git solo mueve el puntero de
main al último commit de tu rama, sin crear ningún commit nuevo.
Conflictos: cuando dos cambios chocan#
Un conflicto ocurre cuando dos ramas modifican el mismo fragmento del mismo fichero. Git puede fusionar cambios automáticamente si afectan a partes distintas, pero cuando chocan en el mismo sitio no puede decidir por ti: te marca el fichero y espera a que lo resuelvas.
Los marcadores tienen este aspecto:
<<<<<<< HEAD
{ nombre: 'Reinhardt', partidas: 312 },
=======
{ nombre: 'Reinhardt', partidas: 321 },
>>>>>>> mainLo que hay entre <<<<<<< HEAD y ======= es el estado de tu rama actual. Lo que hay entre
======= y >>>>>>> main es el estado de la rama que estás integrando. Tu trabajo es:
# tras editar el fichero y borrar los tres marcadores, márcalo como resuelto
git add src/data/heroes.ts
# cierra el merge con un commit que describe la resolución
git commit -m "merge main: resuelve conflicto en heroes.ts"La consecuencia de resolver mal es grave: si conservas un marcador sin borrarlo, el fichero queda con ese texto literal. El código puede compilar con errores raros, o directamente romper en producción sin que nadie se dé cuenta hasta que alguien abra ese fichero. Git no detecta que olvidaste borrar los marcadores: es responsabilidad tuya leer lo que quedó.
Rebase y la regla de oro#
git rebase main toma cada commit de tu rama y lo aplica uno a uno sobre el último commit
de main. Si hay conflicto en algún commit, Git se detiene, resuelves el conflicto, y
continúas:
# mueve tus commits encima del último commit de main
git rebase main
# si hay conflicto, Git se detiene: editas el fichero, borras los marcadores, y luego:
git add src/data/heroes.ts
# le dices a Git que continúe aplicando el resto de commits
git rebase --continuegit rebase -i main (la -i es de interactivo) abre un editor con la lista de tus commits y
te deja reordenarlos, combinarlos (squash) o editar sus mensajes antes de que lleguen a main.
Es la herramienta para limpiar el historial antes de pedir revisión: conviertes cinco “wip” en
dos commits con mensajes que cualquier compañero entiende.
La regla de oro del rebase: nunca hagas rebase de una rama que ya has compartido con otra persona. El rebase reescribe commits: los mismos cambios, pero con hashes nuevos. Si alguien más tiene tus commits con los hashes viejos y tú publicas los nuevos, sus historiales divergen de forma irreconciliable. Tendrán que resetear a mano o hacer cherry-pick de sus propios commits. En la práctica: rebase libre en tu rama local mientras la desarrollas; en cuanto otra persona trabaja en esa rama al mismo tiempo, solo merge.
Stash: aparcar trabajo a medias#
Estás en mitad de añadir estilos al filtro de roles cuando llega un mensaje: hay un dato incorrecto en la lista de héroes que está dando problemas en producción. Necesitas un directorio limpio para cambiar de contexto, pero no quieres hacer un commit a medias.
git stash aparca tus cambios sin commitear en una pila temporal y deja el working directory
limpio:
# aparca los cambios actuales del working directory y del staging
git stash
# (tu directorio está limpio; cambias de rama, arreglas el urgente, commiteas)
# recupera el trabajo que habías apartado y lo aplica encima del estado actual
git stash popLa pila puede tener varios elementos. git stash list muestra todo lo que hay aparcado.
git stash pop saca el último que metiste (el más reciente). Si olvidaste que había algo
ahí, no pasa nada: el stash no expira solo.
Tags: marcar versiones#
Un tag es un nombre fijo que apunta a un commit concreto. A diferencia de una rama (que avanza a medida que haces commits), un tag no se mueve nunca. Se usa para marcar releases, versiones desplegadas o puntos de referencia en el historial.
# crea un tag anotado con un mensaje descriptivo
git tag -a v1.0.0 -m "Primera versión con filtro por rol. Arreglos de datos en roster."
# git push por defecto NO sube los tags: hay que pedirlo explícitamente
git push --tagsHay dos tipos de tags. Los ligeros son solo un puntero a un commit, sin metadatos extra.
Los anotados (con -a) incluyen el nombre del autor, la fecha y el mensaje: son los que
se usan en producción porque llevan toda la información de quién marcó la versión y por qué.
En el día a día, siempre anotados.
Force push, con mucho cuidado#
Después de un rebase, si intentas hacer push normal de tu rama, Git lo rechaza:
# error: failed to push some refs
# hint: Updates were rejected because the tip of your current branch is behindEl motivo: el rebase reescribió los commits de tu rama local. El remoto aún tiene los commits con los hashes viejos. Las dos ramas han divergido y Git no puede resolver esa situación con un push estándar.
La solución es un force push, pero con la variante segura:
# sobreescribe la rama remota con tu historial rebaseado,
# pero ABORTA si alguien más subió commits desde tu última sincronización
git push --force-with-lease
# NUNCA uses esto si no sabes exactamente qué vas a pisar
git push --force--force-with-lease comprueba que el remoto está en el mismo estado que tenías cuando hiciste
el rebase. Si alguien subió algo entre medias, el push aborta con un error: no pierdes nada.
--force sobrescribe sin comprobar nada: si tu compañero subió tres commits mientras tú
rebaseabas, desaparecen sin aviso. Usa siempre --force-with-lease.
Deshacer sin reescribir la historia: revert#
Imagina que acabas de publicar un commit en main y, al cabo de unos minutos, te avisan de
que algo se ha roto en producción. El commit tiene un error. Necesitas deshacerlo, y rápido.
La tentación inmediata es git reset: mueve el puntero de la rama hacia atrás y, con
--hard, descarta los commits que quedan por encima. Parece limpio. Pero si la rama ya está
publicada (ya hiciste git push), borrar commits con reset y luego hacer git push --force
es exactamente lo que la regla de oro del rebase prohíbe: reescribes la historia que otros
ya tienen. Tus compañeros, el pipeline de CI, el deploy, cualquiera que haya recibido esos
commits tendrá su historial roto. Tendrán que resetear a mano.
La herramienta correcta en ese caso es git revert:
# revierte el último commit: crea un commit NUEVO que aplica los cambios inversos
git revert HEAD
# revierte un commit concreto identificado por su hash
# (Git abre el editor para que confirmes el mensaje del nuevo commit)
git revert a3f9c1b
# revierte sin abrir el editor: usa el mensaje por defecto
git revert --no-edit HEADgit revert no borra nada. Toma los cambios del commit que señalas y genera un commit nuevo
que los deshace: si el commit malo añadió una línea, el revert la elimina; si eliminó un
fichero, el revert lo restaura. El historial queda entero: el commit malo sigue ahí, y justo
después aparece el que lo corrige. No hay reescritura. No hay force-push. No hay problema
para el resto del equipo.
Puedes hacer git push normal con el revert, igual que con cualquier otro commit.
La regla práctica es sencilla:
- Algo ya publicado o en una rama compartida que necesitas deshacer →
git revert. - Commits locales que aún no has compartido con nadie → puedes usar
git reset, con cuidado.
Usar reset más force-push para “borrar” un commit que ya está en main reescribe el historial
de producción: lo deja inconsistente y el equipo pierde la trazabilidad de qué pasó. Es justo
lo que el capítulo de deploy te lleva a evitar al usar git revert como rollback: te da el
mismo resultado (el código vuelve al estado anterior) sin ninguna de esas consecuencias. Por
eso es la herramienta de rollback estándar en cualquier equipo.
Comprueba lo que sabes#
Pregunta 1 de 7
¿Qué diferencia hay en el historial resultante entre hacer un `git merge` y un `git rebase`?
Tu turno#
El ejercicio es un flujo de Git real: lo haces en tu repositorio local del Team Builder, no en un editor de esta página. Los ficheros de solución muestran la secuencia exacta de comandos de cada tier con su explicación. Haz el tuyo primero y luego léelos: la comparación entre lo que hiciste y la solución es donde está el aprendizaje.
Ejercicio · hazlo en local
Flujo de equipo profesional con Git
Sobre el repositorio de tu Team Builder de React (el que vienes construyendo desde el Nivel 7, o uno de prueba en local), recorre el ciclo de vida completo de una feature: rama, commits, PR, conflicto y resolución. Las soluciones muestran la secuencia exacta de comandos de cada tier con su explicación. Léelas después de hacer el tuyo: la comparación es donde está el aprendizaje.
Paso 1: Rama + PR + conflicto resuelto con merge
- Creas la rama `feature/filtro-por-rol` con `git switch -c`, haces al menos dos commits con mensajes descriptivos y la subes al remoto.
- Abres un Pull Request con `gh pr create` apuntando a `main`.
- Simulas que `main` avanza mientras el PR está abierto (cambias a main, haces un commit, vuelves a la feature).
- Integras los cambios de `main` en tu rama con `git merge main`, resuelves el conflicto borrando los marcadores, y cierras el merge con `git add` + `git commit`.
- Subes la rama actualizada con `git push`.
Paso 2: Mismo flujo con rebase en vez de merge
- Mismo flujo que el tier "ok" hasta el punto de integrar `main`.
- En lugar de merge, usas `git rebase main`: resuelves el conflicto, haces `git add` y `git rebase --continue` hasta que el rebase termine con éxito.
- Actualizas la rama del PR con `git push --force-with-lease` (el push normal falla porque el rebase reescribió los hashes).
- El historial del PR muestra tus commits directamente encima de `main`, sin ningún commit de merge.
Paso 3: Historia impecable con squash, stash, convenciones y tag
- Usas la convención `feat:`/`fix:`/`style:` en todos los mensajes de commit.
- Apartas trabajo a medias con `git stash` cuando llega algo urgente, arreglas el urgente, y recuperas el trabajo con `git stash pop`.
- Antes de pedir revisión, usas `git rebase -i main` para hacer squash de los commits WIP en commits lógicos con mensajes definitivos.
- Actualizas el PR con `git push --force-with-lease` tras el rebase interactivo.
- Tras fusionar el PR, vuelves a `main`, haces `git pull` y cierras el ciclo con un tag anotado: `git tag -a v0.9.0 -m "..."` + `git push --tags`.
Cómo hacerlo en local
Clona el repositorio del curso, entra en la carpeta del ejercicio y abre el
index.html en tu navegador. Toda tu solución va en
solucion.js.
git clone <repo>
cd exercises/nivel-9/git-avanzado
# abre index.html en el navegador y edita solucion.js Ver soluciones
# Tier ok: rama + PR + conflicto resuelto con merge.
# Demuestra el ciclo básico de trabajo en equipo: aislar el trabajo en una rama,
# abrirlo a revisión con un PR, y absorber cambios de main cuando hay colisión.
# --- 1. Crear la rama de la feature y cambiarte a ella ---
# crea la rama feature/filtro-por-rol y te mueve a ella en un solo paso
git switch -c feature/filtro-por-rol
# --- 2. Hacer cambios y commits en la rama ---
# (aquí editas los ficheros de tu proyecto — por ejemplo, añades el selector de rol
# en HeroCard.tsx o en el componente de filtros — y luego registras el trabajo)
# guarda el estado actual del área de preparación como primer commit de la feature
git add .
git commit -m "añade selector de rol en el filtro de héroes"
# (sigues trabajando: conectas el filtro al estado, pruebas que funciona)
# registra el segundo avance de la feature
git add .
git commit -m "filtra el roster según el rol seleccionado"
# --- 3. Subir la rama al repositorio remoto ---
# sube la rama y la registra como rama de seguimiento remoto (-u)
# a partir de aquí, git push sin argumentos actualiza esta misma rama
git push -u origin feature/filtro-por-rol
# --- 4. Abrir el Pull Request ---
# abre un PR desde feature/filtro-por-rol hacia main con título y descripción
# el flag --fill usa el mensaje del último commit como descripción si no pasas --body
gh pr create \
--base main \
--head feature/filtro-por-rol \
--title "feat: filtro de héroes por rol" \
--body "Añade un selector de rol (tanque/daño/soporte) que filtra el roster en tiempo real."
# --- 5. Simular que main avanza mientras el PR está abierto ---
# vuelve a main para simular el trabajo de otro miembro del equipo
git switch main
# (otro compañero ha tocado, por ejemplo, la lista de héroes en data/heroes.ts)
# registra ese cambio urgente en main
git add .
git commit -m "arregla dato de partidas de Reinhardt"
# vuelve a tu rama de feature para integrar lo que acaba de llegar a main
git switch feature/filtro-por-rol
# --- 6. Integrar main en tu rama con merge ---
# trae los commits nuevos de main a tu rama creando un commit de merge
# esto preserva exactamente lo que pasó en cada rama, pero añade un commit extra
git merge main
# en este punto Git marca los ficheros con conflicto con los marcadores <<<< ==== >>>>
# abre cada fichero afectado, decide qué fragmento conservar (o combina ambos),
# y elimina los marcadores antes de continuar
# tras resolver los marcadores, marca el fichero como resuelto
git add src/data/heroes.ts
# cierra el merge con un commit que describe la resolución
git commit -m "merge main: resuelve conflicto en heroes.ts"
# --- 7. Actualizar la rama remota ---
# sube los nuevos commits (los tuyos más el de merge) a la rama del PR
git push
# El PR ahora muestra tu feature más los cambios de main integrados y sin conflicto.
# El revisor puede aprobar y hacer merge directamente desde GitHub.
# --- Límite de este tier ---
# La historia del repositorio acaba con un commit de merge extra en cada integración.
# En proyectos largos eso acumula ruido: cada vez que main avanza y hay que integrar,
# aparece un nuevo "merge main en feature/..." que no aporta lógica de negocio.
# El tier "mejor" resuelve esto con rebase, que reescribe tu trabajo encima de main
# y deja una historia completamente lineal. Por qué este nivel
- El ciclo base de trabajo en equipo: aislar en una rama, abrir el PR, absorber los cambios de main cuando hay colisión. El merge preserva lo que ocurrió en cada rama, pero añade un commit de fusión cada vez que hay que integrar.
- Su límite: en proyectos activos, esos commits de merge se acumulan y ensucian el historial. `git log --oneline` mezcla tu trabajo con los "merge main en feature/..." que no aportan lógica de negocio. El tier "mejor" resuelve esto con rebase.
# Tier mejor: rama + PR + conflicto resuelto con rebase + force-with-lease.
# Demuestra cómo mantener una historia lineal: en lugar de añadir un commit de merge,
# reescribes tus commits encima del último estado de main, como si siempre hubieran
# partido desde ahí. El PR se actualiza con force-with-lease para no sobreescribir
# trabajo de otra persona por accidente.
# --- 1. Crear la rama de la feature y cambiarte a ella ---
# crea la rama feature/filtro-por-rol y te mueve a ella en un solo paso
git switch -c feature/filtro-por-rol
# --- 2. Hacer cambios y commits en la rama ---
# (editas los ficheros del proyecto — selector de rol, conexión al estado, etc.)
# registra el primer avance de la feature
git add .
git commit -m "añade selector de rol en el filtro de héroes"
# registra el segundo avance de la feature
git add .
git commit -m "filtra el roster según el rol seleccionado"
# --- 3. Subir la rama y abrir el PR ---
# sube la rama y la registra como rama de seguimiento remoto
git push -u origin feature/filtro-por-rol
# abre el PR hacia main con título y descripción
gh pr create \
--base main \
--head feature/filtro-por-rol \
--title "feat: filtro de héroes por rol" \
--body "Añade un selector de rol (tanque/daño/soporte) que filtra el roster en tiempo real."
# --- 4. Simular que main avanza mientras el PR está abierto ---
# vuelve a main para simular el avance de otro miembro del equipo
git switch main
# (otro compañero toca heroes.ts con un arreglo urgente)
# registra ese cambio en main
git add .
git commit -m "arregla dato de partidas de Reinhardt"
# vuelve a tu rama de feature para integrar lo nuevo de main
git switch feature/filtro-por-rol
# --- 5. Integrar main con rebase ---
# mueve tus commits encima del último commit de main
# Git aplica cada uno de tus commits uno a uno sobre main actualizado
# si hay conflicto en alguno de ellos, Git se detiene para que lo resuelvas
git rebase main
# en este punto Git indica el fichero en conflicto y te muestra los marcadores
# abre el fichero, elige qué fragmento queda (o combina ambos), elimina los marcadores
# tras resolver el conflicto en el fichero afectado, márcalo como resuelto
git add src/data/heroes.ts
# le dices a Git que continúe aplicando el resto de commits del rebase
git rebase --continue
# (si hay más commits con conflicto, Git volverá a detenerse: repite add + continue
# hasta que el rebase termine con "Successfully rebased")
# --- 6. Actualizar la rama remota con force-with-lease ---
# el rebase ha reescrito el historial de tu rama local: los commits tienen nuevos hashes
# un push normal falla porque el remoto y el local han divergido
# --force-with-lease sobreescribe la rama remota PERO aborta si alguien más ha subido
# commits desde la última vez que la descargaste, protegiéndote de borrar trabajo ajeno
git push --force-with-lease
# El PR ahora muestra una historia lineal: tus commits aparecen directamente encima
# de main, sin ningún commit de merge de por medio. El revisor ve el trabajo limpio.
# --- Por qué este tier supera al anterior ---
# El merge del tier "ok" funciona, pero añade un commit extra que no aporta lógica:
# solo dice "aquí integré main". Con rebase ese commit desaparece: tu historia dice
# exactamente lo que hiciste, en el orden en que lo hiciste, sin ruido.
# La contrapartida es que --force-with-lease requiere coordinación: nunca hagas
# force-push a una rama en la que otras personas están trabajando al mismo tiempo.
# El tier "excelente" añade la disciplina de los mensajes convencionales, el squash
# de commits WIP y el stash para apartar trabajo a medias sin perder nada. Por qué es mejor que el anterior
- La misma feature, pero el historial queda limpio: tus commits aparecen directamente encima del último commit de main, sin ruido de merge. El revisor ve el trabajo aislado, fácil de leer.
- La contrapartida: el rebase reescribe hashes, así que el push normal falla y necesitas `--force-with-lease`. Y nunca rebases una rama en la que otras personas estén trabajando al mismo tiempo: les reescribes la historia bajo los pies.
# Tier excelente: historia impecable con commits convencionales, squash interactivo,
# stash para cambios urgentes y tag de versión al cerrar el ciclo.
# Demuestra la disciplina de un equipo profesional: cada commit que llega a main
# tiene un propósito único, un mensaje que cualquier compañero puede leer en seis
# meses, y el historial del repo sirve como documentación del proyecto.
# --- 1. Crear la rama de la feature y cambiarte a ella ---
# crea la rama feature/filtro-por-rol y te mueve a ella
git switch -c feature/filtro-por-rol
# --- 2. Trabajar con commits atómicos y mensajes convencionales ---
# (editas HeroFilter.tsx: añades el <select> de rol al componente)
# registra solo el cambio del componente de UI, nada más
git add src/components/HeroFilter.tsx
git commit -m "feat(filtro): añade selector de rol al componente HeroFilter"
# (conectas el estado: el valor del select controla qué héroes se muestran)
# registra solo la lógica de filtrado
git add src/hooks/useRoster.ts
git commit -m "feat(roster): filtra héroes por rol en useRoster"
# (trabajas un rato más en los estilos del selector pero no has terminado)
# en este momento llega un mensaje: hay un dato incorrecto en la lista de héroes
# necesitas apartar tu trabajo a medias para no mezclarlo con el arreglo urgente
# guarda el trabajo en curso en una pila temporal sin hacer commit
git stash
# (ahora tu directorio está limpio, como si no hubieras tocado nada)
# arreglas el dato incorrecto de Reinhardt en heroes.ts
# registra el arreglo urgente con el prefijo fix: para que quede claro en el historial
git add src/data/heroes.ts
git commit -m "fix(datos): corrige partidas de Reinhardt (era 312, debe ser 321)"
# recupera el trabajo que habías apartado y lo aplica encima del estado actual
git stash pop
# (terminas los estilos del selector)
# registra el trabajo de estilos que habías apartado
git add src/components/HeroFilter.tsx
git commit -m "style(filtro): ajusta espaciado y color del selector de rol"
# --- 3. Subir la rama y abrir el PR ---
# sube la rama y la registra como rama de seguimiento remoto
git push -u origin feature/filtro-por-rol
# abre el PR con título y descripción en formato convencional
gh pr create \
--base main \
--head feature/filtro-por-rol \
--title "feat: filtro de héroes por rol" \
--body "Añade un selector de rol (tanque/daño/soporte) que filtra el roster en tiempo real. Incluye arreglo de datos de Reinhardt."
# --- 4. Simular que main avanza ---
# vuelve a main para simular el avance del equipo
git switch main
# (otro compañero ha tocado heroes.ts con otro arreglo)
# registra ese cambio en main
git add .
git commit -m "fix(datos): añade stat de victorias que faltaba en Ana"
# vuelve a la feature para integrar
git switch feature/filtro-por-rol
# --- 5. Limpiar la historia antes de pedir revisión ---
# antes de integrar main, aplana los commits WIP en commits lógicos
# -i significa interactivo: se abre el editor con la lista de tus commits
# cambia "pick" por "squash" (o "s") en los commits que quieres unir al anterior
# Git te pedirá que escribas el mensaje final del commit resultante
git rebase -i main
# (en el editor que se abre verás algo como:
# pick abc1234 feat(filtro): añade selector de rol al componente HeroFilter
# pick def5678 feat(roster): filtra héroes por rol en useRoster
# pick ghi9012 fix(datos): corrige partidas de Reinhardt (era 312, debe ser 321)
# pick jkl3456 style(filtro): ajusta espaciado y color del selector de rol
#
# si quieres dejar solo dos commits (uno de feat y uno de fix), marcas:
# pick abc1234 feat(filtro): añade selector de rol al componente HeroFilter
# squash def5678 feat(roster): filtra héroes por rol en useRoster
# squash jkl3456 style(filtro): ajusta espaciado y color del selector de rol
# pick ghi9012 fix(datos): corrige partidas de Reinhardt (era 312, debe ser 321)
#
# guarda y cierra el editor; Git abre otro para el mensaje del commit combinado)
# si durante el rebase interactivo aparece un conflicto, resuelve los marcadores,
# marca el fichero como resuelto y continúa el rebase
git add src/data/heroes.ts
git rebase --continue
# --- 6. Actualizar la rama remota ---
# el rebase interactivo ha reescrito el historial: necesitas force-with-lease
# para actualizar el remoto sin riesgo de borrar trabajo de otra persona
git push --force-with-lease
# --- 7. Etiquetar la versión al cerrar el ciclo ---
# (tras aprobar y hacer merge del PR en GitHub, vuelves a main y lo actualizas)
# sincroniza tu main local con el remoto
git switch main
git pull
# crea un tag anotado con la versión y una descripción del cambio principal
git tag -a v0.9.0 -m "Filtro de héroes por rol. Arreglos de datos en roster."
# sube el tag al repositorio remoto (git push solo no los sube por defecto)
git push --tags
# --- Por qué este tier supera al anterior ---
# El tier "mejor" deja una historia lineal, pero los commits todavía pueden mezclar
# propósitos: un commit de estilos mezclado con lógica, o varios "wip" antes de
# terminar. Aquí cada commit que llega a main tiene un solo propósito y un mensaje
# que cualquier compañero puede rastrear con git log o git blame sin tener que abrir
# el código. El stash evita commits de "guardado provisional" que ensuciarían la
# historia. El tag convierte el historial en un registro de versiones que puedes
# referenciar en changelogs, en issues o en el deploy. El resultado es un repo que
# trabaja como documentación viva del proyecto, no solo como copia de seguridad. Por qué es mejor que el anterior
- La disciplina de equipo completa: commits atómicos con mensajes convencionales, stash para no mezclar contextos, squash interactivo para que cada commit que llega a main tenga un propósito único, y un tag que convierte el historial en un registro de versiones legible.
- El resultado es un repo que trabaja como documentación viva: cualquier compañero puede leer `git log --oneline`, entender qué se hizo y cuándo, y referenciar versiones en changelogs o deploys. Eso no llega solo: es el producto de pequeñas decisiones correctas en cada paso del flujo.