wandres.dev
CONTRIBUIR UPSTREAM · el proceso de parches

Preparar el parche: un cambio, un commit, un porqué

El primer acto de contribuir no es escribir código, sino empaquetarlo: aislar un único cambio lógico, redactar un mensaje de commit que justifique el PORQUÉ con el rigor que exige el kernel, firmarlo con git commit -s y convertirlo en un correo con git format-patch. La anatomía de un buen mensaje de commit es la mitad del trabajo.

⏱ 16 min

Tu código funciona, compila limpio, pasa checkpatch y sparse. Nada de eso importa todavía, porque un parche no es un diff: es un argumento. El diff dice qué cambia; el mensaje de commit dice por qué debe cambiar, y es lo primero —a menudo lo único— que un mantenedor sobrecargado lee antes de decidir si dedicarte su tiempo. Preparar un parche es el arte de destilar tu trabajo en una unidad atómica, autocontenida y justificada, lista para viajar por correo hasta la lista correcta. Empieza mucho antes del envío: empieza en la forma del commit.

🎯 Al terminar esta lección sabrás
  • Aislar un solo cambio lógico por commit y revisarlo con git add -p.
  • Dominar la anatomía del mensaje de commit del kernel: asunto, cuerpo y la regla 50/72.
  • Escribir en modo imperativo y justificar el porqué, no el cómo.
  • Firmar con git commit -s y generar el correo con git format-patch.

Un cambio lógico por commit

La regla fundacional del kernel: cada commit hace una cosa y la hace completa. Si tu trabajo arregla un bug y renombra una variable y añade una función, son tres parches, no uno. La atomicidad no es estética: es lo que permite revisar, revertir con git revert y bisecar (nivel 3.2) un cambio sin arrastrar equipaje ajeno. Un parche que mezcla asuntos es casi siempre rechazado antes de leerse.

# parte de una rama limpia sobre el árbol correcto del subsistema
git switch -c fix-uaf-en-midriver v6.12

# haz UN cambio lógico, compílalo y pásalo por las herramientas
$EDITOR drivers/misc/midriver.c

# registra exactamente lo que quieres, trozo a trozo
git add -p drivers/misc/midriver.c
git diff --cached           # lee tu propio parche antes que nadie

git add -p es la herramienta clave: te ofrece cada hunk por separado y te obliga a decidir, conscientemente, qué entra en este commit. Es la disciplina que separa un historial legible de un vertedero de cambios. Si un archivo mezcla dos ideas, add -p te deja partirlas en dos commits distintos.

La anatomía del mensaje de commit

Aquí se juega la contribución. El formato es rígido y universal en el kernel:

subsistema: resumen imperativo en una línea de unas 50 columnas

Explica el PROBLEMA que existía antes de tu cambio: qué síntoma
tenía, bajo qué condiciones se dispara, por qué el código actual
es incorrecto o insuficiente. El lector debe entender la avería
sin mirar el diff. Escribe en prosa, en modo imperativo, y ajusta
el cuerpo a unas 72 columnas para que se lea bien en un terminal
y en los clientes de correo.

Después describe el impacto —el crash, la fuga de memoria, la
regresión de rendimiento— y solo entonces, brevemente, la forma
de la solución. El diff ya cuenta el cómo; tú cuentas el porqué.

Signed-off-by: Nombre Apellido <tu@correo.org>

Tres leyes gobiernan el asunto. Primera, el prefijo de subsistema: mm/slab:, net: phy:, drivers/misc: midriver:. Mira git log --oneline del archivo que tocas y copia el prefijo que usan sus commits recientes; no lo inventes. Segunda, el modo imperativo: escribe “Arregla”, “Añade”, “Evita”, nunca “Arreglado” ni “Arreglando”. La prueba mental canónica es completar la frase “Si se aplica, este commit va a…” con tu asunto. Tercera, la longitud: el asunto ronda las 50 columnas y jamás termina en punto.

Así se ven asuntos reales del árbol, cada uno con su prefijo y su verbo imperativo en inglés, que es la lengua franca de la lista:

mm/slab: Fix memory leak in kmem_cache_create error path
net: phy: micrel: Add support for the KSZ9131 clock skew
gpio: pca953x: Use devm_ for the reset GPIO
Revert "sched/fair: simplify the task selection path"

El cuerpo también obedece convenciones finas: se escribe en tercera persona impersonal (“This patch…” se evita; se dice “Do X” o “The driver does Y”), se separan los párrafos con líneas en blanco, y las referencias a otros commits van con el formato de doce dígitos que verás en el nivel 56.4. Nada de esto es opcional: es el dialecto en el que el kernel lleva treinta años conversando.

⚠️
El porqué, no el cómo

El error más común del principiante es un mensaje que parafrasea el diff: “cambio kzalloc por devm_kzalloc”. Eso ya lo veo en el código. Lo que necesito saber es por qué: “el driver filtraba la estructura si probe fallaba tras la asignación; usar devm_kzalloc ata la liberación al ciclo de vida del dispositivo y cierra la fuga”. El primero describe el teclado; el segundo describe la ingeniería. Un mensaje que solo dice el cómo es motivo suficiente de rechazo.

git format-patch: del commit al correo

El kernel no vive en pull requests: vive en correos de texto plano (nivel 56.2). git format-patch convierte tus commits en ficheros con formato mbox, listos para enviarse:

git commit -s                        # -s añade tu Signed-off-by (nivel 56.4)

git format-patch -1                  # un commit -> 0001-....patch
git format-patch v6.12               # toda tu rama desde ese punto
git format-patch -1 -v2              # marca el asunto como [PATCH v2]
git format-patch --cover-letter -o out/ v6.12   # serie con carta 0000

Cada fichero resultante contiene las cabeceras de correo (From:, Subject: [PATCH] subsistema: ...), el mensaje de commit íntegro, la línea de tijeras ---, el diffstat y el diff unificado. Es, literalmente, el correo que enviarás. Ábrelo y léelo entero: lo que ves es lo que el mantenedor verá en su bandeja.

Moldear la historia antes de enviar

Casi nunca aciertas el commit perfecto a la primera, y no pasa nada: git te deja reescribir tu historia local —siempre antes de publicarla— hasta dejarla impecable. Esa es una libertad que el flujo por correo te concede y que un pull request ya fusionado te niega.

git commit -s --amend                 # rehacer el último commit y su mensaje
git rebase -i v6.12                    # reordenar, fundir (squash) o partir (edit)
git rebase -i --exec 'make -j$(nproc)' v6.12   # compila CADA commit de la serie
git format-patch --base=v6.12 -o out/ v6.12    # añade la línea base-commit:

El --exec es la joya oculta: compila cada commit de tu serie por separado y garantiza que el árbol bisecta limpio en todos ellos (nivel 3.2). Un commit intermedio que no compila rompe git bisect para siempre y es motivo de rechazo. Cuando necesites partir un commit demasiado grande, márcalo como edit en el rebase interactivo y usa git reset -p HEAD^ para devolver los cambios al área de trabajo y recomponerlos en trozos con git add -p. Y --base graba en el correo la línea base-commit:, que le dice al mantenedor exactamente sobre qué árbol aplicar, eliminando el clásico “¿contra qué rama era esto?”.

💡
Cada commit debe sostenerse solo

La prueba de fuego de una serie bien preparada: aplica el commit número tres y solo el tres, y el kernel debe compilar y funcionar. Nada de “esto lo arregla el siguiente parche”. Cada commit es una unidad autónoma, revisable y reversible por sí misma; esa es la propiedad que hace posible git bisect, git revert y la revisión parche a parche. Si un commit necesita a otro para no romper el build, o los fundes en uno, o reordenas la serie.

El commit es el artefacto que sobrevive al código

Detente en una asimetría profunda del kernel. Tu código será reescrito: dentro de cinco años alguien refactorizará tu función, cambiará su nombre, la fundirá con otra, quizá la borre. Pero tu mensaje de commit es inmortal. Queda grabado en el grafo de git para siempre, inmutable, y cuando dentro de una década un ingeniero haga git blame sobre una línea heredada de tu parche y se pregunte “¿por qué demonios está esto aquí?”, tu mensaje será la única voz capaz de responderle a través del tiempo. Por eso el kernel trata el mensaje de commit con una seriedad que asombra a quien viene de otros mundos: no es burocracia, es la construcción deliberada de la memoria de largo plazo de un sistema que ninguna persona abarca por completo. Escribir el porqué no es documentar el pasado; es hablarle al futuro. Cada commit del kernel es una carta a un ingeniero que aún no ha nacido, y la disciplina de redactarlo bien —el problema antes que la solución, el imperativo, las 72 columnas— es la etiqueta con la que treinta años de programadores de sistemas han acordado conversar entre generaciones. Tú no envías un diff. Envías un fragmento de razonamiento que durará más que tu código.

⚔️ Empaqueta tu primer parche
  1. Toma un módulo tuyo, introduce un cambio real y pequeño, y usa git add -p para registrar solo ese cambio, sin arrastrar nada más.
  2. Haz git commit -s y redacta el mensaje siguiendo la anatomía: prefijo de subsistema, asunto imperativo de ~50 columnas, cuerpo a 72 que explique el porqué.
  3. Verifica tu asunto completando en voz alta la frase “Si se aplica, este commit va a…”. Si no encaja, reescríbelo.
  4. Genera el fichero con git format-patch -1 y léelo entero: confirma que las cabeceras, el mensaje y el diff son exactamente lo que quieres que un desconocido lea.
  5. Pásalo por scripts/checkpatch.pl 0001-*.patch (nivel 9.2) y deja el parche limpio de avisos.