Guía9 min

git check-mailmap para coding agents: canónico, no reescritura

Resumen

git check-mailmap resuelve un contacto contra .mailmap y imprime el nombre y email canónicos. Un agente consulta. Cero editar .mailmap. Cero --mailmap-file global. Cero dump de historia. Distinto de shortlog, blame y config. Git 2.50.1.

GitHub
Un coding agent consulta contactos contra .mailmap; el archivo y HEAD no se tocan

Qué resuelve

Esta pieza se queda en la decisión práctica: qué instalar, qué riesgo agrega y cómo aplicarlo sin romper operación.

git check-mailmap resuelve un contacto. El man (git-check-mailmap(1); git-scm.com/docs/git-check-mailmap HTTP 200, last-modified 2026-08-31; pie del man local Git 2.50.1.428.g0e8243, 2025-07-22; binario Git 2.50.1 / Apple Git-155): Show canonical names and email addresses of contacts. SYNOPSIS: git check-mailmap [<options>] <contact>.... DESCRIPTION: para cada Name <user@host>, <user@host> o user@host de argv o de stdin (--stdin), busca el nombre y email canónicos (ver Mapping Authors). Si hay match, imprime el canónico; si no, imprime el input.

Contrato para un coding agent: consulta, no reescribe. No toca el working tree. No mueve HEAD. No edita .mailmap. El mapa vive en $GIT_WORK_TREE/.mailmap o en mailmap.file / mailmap.blob (config). El humano es dueño de esas líneas.

No es shortlog: shortlog agrupa commits y aplica el mailmap al recuento. check-mailmap no camina historia. No es blame: blame anota líneas. No es log --use-mailmap: log reescribe identidades al mostrar commits. Aquí no hay walk.

Qué imprime (y qué no)

OUTPUT del man: una línea por contacto, con newline. Si el nombre se dio o el mailmap lo conoce, imprime Name <user@host>; si no, solo <user@host>.

Verificado 2026-09-06 (Git 2.50.1 / Apple Git-155), sin .mailmap:

InputStdoutExit
(sin args)fatal: no contacts specified128
--unknownunknown option, usage129
Jane Doe <[email protected]>Jane Doe <[email protected]>0
[email protected]<[email protected]>0
<[email protected]><[email protected]>0
--stdin con stdin vacío(vacío)0

El email suelto no se imprime “tal cual”: el man lo envuelve en <> cuando no hay nombre. Un agente que parsea stdout no puede asumir que el string de argv vuelve byte a byte.

Con un .mailmap del EXAMPLES de gitmailmap(5) (Jane Doe <[email protected]> <jane@laptop.(none)> y Joe R. Developer <[email protected]>):

InputStdout
Jane Doe <jane@laptop.(none)>Jane Doe <[email protected]>
JANE DOE <JANE@LAPTOP.(NONE)>Jane Doe <[email protected]> (match case-insensitive)
<jane@laptop.(none)>Jane Doe <[email protected]> (el mapa conoce el nombre)
jane@laptop.(none)Jane Doe <[email protected]>
Joe Developer <[email protected]>Joe R. Developer <[email protected]>
Other <[email protected]>Other <[email protected]> (sin match, tal cual)

Varios contactos en argv: una línea por contacto, en orden. --stdin después de agotar argv: check-mailmap --stdin 'Jane Doe <jane@laptop.(none)>' + stdin Joe <[email protected]> imprime Jane canónica y luego Joe <[email protected]>.

Alias de laptop y desktop colapsan a un email canónico; el agente no edita el mapa

Flags: file y blob, no config global

FlagManAgente
--stdinContactos, uno por línea, después de argvSí, lista corta. Cero volcar git log entero
--mailmap-file=<file>Extra al mapa default/config; este archivo ganaSolo si el humano lo pide. Cero inventar un path
--mailmap-blob=<blob>Igual, pero blob del repo. Si hay file y blob, file ganaHEAD:.mailmap es lectura. Cero blob inventado

--mailmap-file pisa el .mailmap del worktree. Verificado: un extra Override Name <[email protected]> <jane@laptop.(none)> hace que el mismo contacto salga Override Name <[email protected]>. Un agente no usa esto para “corregir” identidades: es un overlay, no un commit.

Path inexistente: check-mailmap --mailmap-file=/no/such/file '[email protected]' imprimió <[email protected]>, exit 0. No es un gate. Blob inexistente (--mailmap-blob=HEAD:nope) igual: imprime y sale 0. No trates un overlay roto como fallo de lookup.

git-config(1) (HTTP 200, last-modified 2026-08-31): mailmap.file carga el default primero y luego este archivo (puede vivir fuera del repo). mailmap.blob es el equivalente objeto; si ambos, file gana. Bare repo: blob default HEAD:.mailmap. No-bare: blob default vacío. Un agente no pone mailmap.file con --global ni --system. Techo: --local, y solo si el humano lo pide. Ver config.

gitmailmap(5) (HTTP 200, last-modified 2026-08-31): # comenta hasta fin de línea; blanks se ignoran. Cuatro formas: nombre canónico + email de commit; solo emails; nombre+email canónicos + email de commit; nombre+email canónicos + nombre+email de commit. Match case-insensitive. Git no sigue symlinks al leer .mailmap del working tree.

Dónde sí y dónde no

Sí (consulta):

  • Antes de agrupar autores en un reporte: resuelve 2–10 contactos que ya viste. Luego shortlog -sn con rango A..B si el recuento es el entregable.
  • Confirmar que jane@laptop.(none) ya está mapeado, sin abrir el archivo. Si sale el alias crudo, reporta. No “arregles” el mapa.
  • --stdin con una lista que construiste (emails del diff, no todo el reflog).

No:

  • Editar .mailmap. Identidades rotas se reportan; el humano decide las líneas. Shortlog lo dice igual: el recuento no autoriza reescritura.
  • git config --global mailmap.file. Ni --system. Ni un overlay silencioso con --mailmap-file apuntando a /tmp.
  • Atribuir autoría legal. Canónico ≠ dueño del código ≠ a quién pinguear. Blame anota; no culpa.
  • Dump: git log --format='%an <%ae>' \| git check-mailmap --stdin sobre historia completa vuela el contexto. Rango corto o contactos concretos.
  • Tratar exit 0 + identidad igual al input como “el mapa está bien”. Puede ser un contacto sin entrada. El no-match es silencio, no un OK de calidad.

Flujo seguro

  1. Toma un contacto (o un puñado). Formato Name <email> si lo tienes; si no, el email basta.
  2. git check-mailmap 'Name <email>'. Exit 0 es lookup. Exit 128 = no pasaste contactos. 129 = flag inventado.
  3. Compara stdout con el input. Si cambió, usa el canónico en el reporte. Si no, déjalo y anota “sin entrada de mailmap”.
  4. Cero write_file sobre .mailmap. Cero git add .mailmap.
  5. Recuentos: shortlog -sn. Historia: log con A..B. Líneas: blame -L. Este comando no sustituye ninguno.

File y blob son overlays de lectura; el agente no escribe .mailmap ni config global

Checklist:

  • Al menos un contacto. Sin args = 128.
  • Stdout canónico o input. Cero asumir igualdad byte a byte.
  • Cero editar .mailmap / mailmap.file / mailmap.blob.
  • Cero --global. Overlay --mailmap-file solo si el humano lo pide.
  • Cero dump de historia. Lista corta.
  • Path/blob inexistente no falla el comando: no lo uses como validación.

FAQ

¿Puedo “arreglar” Jane que aparece dos veces? No. Dos barras en shortlog = mailmap incompleto o emails que no matchean. Reporta. El humano escribe las líneas del EXAMPLES de gitmailmap(5).

¿--stdin sin contactos en argv está bien? Sí. Stdin vacío → stdout vacío, exit 0. No lo conviertas en un error ni en un commit.

¿Es lo mismo que git log --use-mailmap? No. log aplica el mapa al mostrar una revisión. check-mailmap no lee commits: solo contactos. Si necesitas un SHA, usa log o show.

¿Por qué el man manda a gitmailmap? Porque la sintaxis del archivo no vive aquí. Cuatro formas, comments #, case-insensitive, sin seguir symlinks. check-mailmap es el lector.

¿Puedo usar --mailmap-blob=HEAD:.mailmap en un clone sucio? Sí: lee el blob, no el working tree. Útil si alguien ensució .mailmap sin commitear. No es permiso para checkout del archivo.

Si estás armando el agente desde cero, el curso de instalar un agente cubre el loop y las tools. El hub de comparativas agrupa el resto de verbos Git. Esta guía es la regla del lookup: consulta el canónico, no reescribas el mapa.