Guía PES

Git a fondo

Git en equipo: protecciones y buenas prácticas

Saber hacer commits no basta cuando sois cinco personas tocando el mismo código. Esta página explica, paso a paso, cómo proteger la rama principal, cómo revisaros, cómo evitar sustos y qué hacer cuando tenéis uno. No es materia de las diapositivas: es para consultarla cuando la necesitéis.

Git a fondo

Protege la rama main

La rama principal es lo que entregáis y lo que desplegáis. Un solo push equivocado puede romper la demo del miércoles. La protección de ramas hace que GitHub impida los errores, en lugar de confiar en que nadie se despiste.

Cómo activarla en GitHub

  1. Abrid el repositorio y id a Settings, luego a Rules y Rulesets (o a Branches, en la vista clásica de «branch protection rules»).
  2. Crea una regla nueva para la rama por defecto (main) y, si hacéis Gitflow, otra para develop.
  3. Ponedla en modo Active y marcad las opciones de la lista de abajo.
  4. Probadlo: intentad hacer git push directo a main. Tiene que ser rechazado.

Depende del plan. Los nombres exactos pueden cambiar un poco en la interfaz de GitHub, y en repositorios privados que las reglas se apliquen depende del plan de la organización (si los botones salen desactivados o la regla no se aplica, anotadlo en el acuerdo de equipo y vigiladlo a mano). Preguntad qué tiene habilitado la organización de vuestro grupo.

Qué marcar y por qué

Require a pull request before merging

Nadie sube código a main directamente: todo pasa por una PR. Pedid 1 aprobación como mínimo.

Dismiss stale approvals

Si se añaden commits tras aprobar, la aprobación caduca y hay que volver a revisar.

Require status checks to pass

La PR no se puede fusionar si la integración continua falla (mirad más abajo).

Require conversation resolution

No se fusiona con comentarios de revisión sin resolver.

Block force pushes

Nadie puede reescribir la historia de main con --force.

Restrict deletions

Nadie puede borrar la rama por error.

Do not allow bypassing

Ni siquiera quien administra el repositorio se salta las reglas. Así no hay excepciones «solo esta vez».

Pull requests que se pueden revisar

Una pull request (PR) es una propuesta de cambio con conversación. Si es pequeña y clara, la revisión es rápida y sirve; si es enorme, nadie la mira de verdad y se aprueba «a ojo».

Una buena PR

  • Una tarea, una PR. Si cambia más de 300-400 líneas o hace dos cosas, partidla.
  • Título con sentido, preferiblemente en formato Conventional Commits: feat(registro): valida el correo.
  • Enlaza la tarea de Taiga (o un Closes #34 si usáis issues de GitHub, que cierra el issue al fusionar).
  • Dos líneas de contexto: qué cambia, por qué y cómo lo habéis probado. Capturas si toca la interfaz.
  • Revisad vuestro propio diff antes de pedir revisión: encontraréis solos los prints olvidados y los archivos que no pintaban nada.
  • Pull request en borrador (draft) si queréis feedback de un trabajo a medias.

Cuando revisáis

  • Lo hace una persona distinta de quien lo ha escrito; rotar los revisores reparte el conocimiento.
  • Mirad primero que hace lo que dicen los criterios de aceptación de la historia, luego los casos límite, las pruebas y el nombre de las cosas.
  • Comentad el código, no a la persona: preguntad («¿por qué no usamos...?») antes de ordenar.
  • Separad lo imprescindible de lo opcional (nit) para que quien recibe el comentario sepa qué tiene que arreglar.

Plantilla de PR (opcional pero útil)

Si creáis el archivo .github/pull_request_template.md, GitHub lo pone como texto inicial en cada PR nueva:

## Qué cambia
(Una o dos frases: qué hace esta PR y por qué.)

## Ticket
Taiga: #34

## Cómo se ha probado
- [ ] Pruebas automáticas
- [ ] Probado a mano (explica cómo)

## Notas para quien revisa
(¿Qué quieres que se mire con más cuidado? Capturas si cambia la interfaz.)

Merge, squash o rebase: cómo se fusiona

GitHub ofrece tres maneras de fusionar una PR y cada una deja una historia distinta. Elegir una es una decisión de equipo, no de cada persona.

OpciónQué haceHistoria resultanteCuidado con
Create a merge commitAñade todos los commits de la rama y un commit de fusión.Fiel: se ven todos los commits y quién los ha hecho.Una historia con muchos «merge» si no se ordena.
Squash and mergeAplasta toda la PR en un solo commit en main.Limpia: un commit por tarea (el título de la PR pasa a ser el mensaje).Se pierde el detalle de los commits y se asignan a quien abre la PR.
Rebase and mergeReaplica los commits de la rama encima de main.Lineal, sin commits de fusión, conservando cada commit.Reescribe los hashes; no lo uséis en ramas compartidas.

Recomendación para PES: el curso mira que todo el mundo haga commits a menudo y de forma equilibrada. Con el squash, todo el trabajo de una PR queda a nombre de una sola persona, y si programáis en pareja se pierde quién ha hecho qué. Por eso conviene más Create a merge commit o Rebase and merge. Si en pareja solo una cuenta hace el commit, añadid a la otra persona con un pie Co-authored-by: Nombre <correo> para que GitHub se lo cuente.

Activad también Automatically delete head branches (Settings, General): al fusionar, GitHub borra la rama de la tarea y no se acumulan.

Integración continua: el portero de main

La integración continua (CI) ejecuta las pruebas, el linter y la compilación en cada PR en una máquina limpia. Si la CI es un required status check de la protección, una PR que rompe las pruebas no se puede fusionar.

  1. Crea el archivo .github/workflows/ci.yml (ejemplo de abajo, para Node: adaptadlo a Java, Python o Android).
  2. Haced una PR: en la pestaña Actions veréis cómo se ejecuta.
  3. En la regla de protección de main, en Require status checks, añadid el trabajo test.
  4. Mantenedla rápida (menos de 5 minutos) y, si falla en main, arreglad eso antes de hacer nada más.

La CI no sustituye a las pruebas: las ejecuta de forma automática e igual para todos. Más adelante podéis desplegar en virtech solo desde main y solo si la CI ha pasado.

name: CI
on:
  pull_request:
  push:
    branches: [main]
jobs:
  test:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: 22
          cache: npm
      - run: npm ci
      - run: npm test

Mantén tu rama al día

Cuanto más vive una rama, más cuesta fusionarla. Traed los cambios de main cada día y mantened las ramas cortas (de dos o tres días, no de dos semanas).

git switch main
git pull
git switch feature/34-registro
git rebase main             # o: git merge main
git push --force-with-lease   # solo tras un rebase y solo en tu rama
  • Merge es lo más seguro: no reescribe nada y sirve en ramas que otras personas también usan.
  • Rebase deja una historia lineal, pero reescribe los commits: no lo hagáis nunca en una rama que alguien más ya se ha bajado.
  • --force-with-lease falla si alguien ha subido algo que no tienes; mucho más seguro que --force.
  • Si dos personas han tocado la misma línea, Git marca el conflicto. Abrid el archivo, dejad lo que toca, borrad las marcas, haced git add y continuad (git rebase --continue o haced el commit de la fusión). Si os perdéis, git rebase --abort o git merge --abort vuelven al principio.

Así se ve un conflicto

<<<<<<< HEAD
tu cambio
=======
el cambio de la otra persona
>>>>>>> main

Secretos y archivos que no se deben subir

Un repositorio de GitHub es fácil de clonar, de copiar y de recordar para siempre. Lo que sube, se queda.

  • Archivo .gitignore desde el primer commit: node_modules/, build/, .env, *.log, carpetas del IDE, archivos .apk y claves de firma.
  • Nunca subáis contraseñas, tokens de API, claves privadas ni el .env. Añadid un .env.example con las variables vacías para que los compañeros sepan cuáles hacen falta.
  • Para la CI, guardad los valores en Settings, Secrets and variables, Actions, no en el código.
  • Si se os escapa uno, revocadlo y generad uno nuevo ahora mismo. Borrar el commit no basta: la historia, los forks y las cachés lo conservan.
  • No subáis binarios grandes (APK, vídeos). Para los ejecutables usad las Releases de GitHub.

Etiquetas y versiones

Una etiqueta (tag) es un nombre permanente para un commit. Etiquetad cada entrega y siempre podréis volver exactamente a lo que entregasteis.

git tag -a fag-3 -m "Entrega Fag-3"
git push origin fag-3
  • En GitHub, Releases permite adjuntar notas y el ejecutable a una etiqueta.
  • Para versiones que ven los usuarios, usad Versionado Semántico: MAJOR.MINOR.PATCH (1.4.2). Una corrección sube el PATCH, una funcionalidad el MINOR y un cambio que rompe la compatibilidad el MAJOR.
  • Los tipos de Conventional Commits (fix, feat, !) os dicen qué número toca: mirad Conventional Commits.

Cuando algo sale mal

Todo el mundo se equivoca con Git. La diferencia es saber deshacerlo sin empeorarlo. Regla de oro: si ya lo habéis subido a una rama compartida, no reescribáis la historia: haced un commit nuevo que lo corrija.

Qué ha pasadoQué hacer
He hecho commits en main por error (sin subirlos)git switch -c feature/34-x (los commits ya están en la rama nueva), luego git switch main y git reset --hard origin/main. Ojo: el reset --hard descarta cambios sin guardar.
Tengo un error en el mensaje del último commit (sin subir)git commit --amend
Me he dejado un archivo en el último commit (sin subir)git add archivo y git commit --amend --no-edit
He añadido un archivo al área de preparación por errorgit restore --staged archivo
Quiero descartar los cambios de un archivogit restore archivo (no se puede deshacer)
He subido un commit malo a una rama compartidagit revert <hash>: crea un commit que lo deshace. No hagáis reset ni --force.
El push se rechaza («non-fast-forward»)Alguien ha subido antes: git pull --rebase (o git pull) y volved a subir. No forcéis.
Creo que he perdido commitsgit reflog lista dónde ha estado HEAD; git switch -c rescate <hash> los recupera.

Acuerdo de equipo sobre Git

Escribid en la memoria qué habéis decidido y revisadlo en cada retrospectiva. Esta lista os sirve de guía; se guarda en vuestro navegador.

Acuerdo de equipo

0/10

Volver a Taiga y GitHub →