git pickaxe: encontrar el commit que introdujo una línea con git log -S y -G
Resumen
Guía práctica del pickaxe de git para coding agents: cómo usar git log -S<string> para encontrar dónde cambió el número de ocurrencias de un texto, y git log -G<regex> para buscar commits cuyo parche toca líneas que encajan con un patrón. Incluye el ejemplo canónico frotz de la documentación oficial, comparativa lado a lado, checklist de depuración y errores típicos al buscar el origen de una línea en un repo ajeno.

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.
El pickaxe de git son las opciones -S y -G de git log, y buscan en todo el historial los commits que tocaron una cadena o un patrón concreto. Para un coding agent que llega a un repo ajeno, el pickaxe responde la pregunta "¿en qué commit apareció o desapareció esto?" sin recorrer cientos de commits a mano, y es complementario a git log para conjuntos de commits y al hub de comparativas y decisiones si el archivo existe en el working tree.
La diferencia entre -S y -G no es cosmética: uno cuenta ocurrencias y el otro mira el texto del parche. Elegir mal te hace perder commits que sí te interesan, o te obliga a revisar diffs irrelevantes.
Qué detecta cada uno: ocurrencias vs texto del parche
git log -S"<string>" lista los commits donde el número de ocurrencias de esa cadena cambio (subió, bajó o llegó a cero), considerando las versiones del archivo antes y después del commit. git log -G"<regex>" lista los commits cuyo patch contiene líneas añadidas o eliminadas que encajan con la expresión regular.
git log -S"<string>" | git log -G"<regex>" | |
|---|---|---|
| Qué busca | cambios en el número de ocurrencias de la cadena | líneas añadidas o eliminadas que encajan con la regex |
| Argumento por defecto | cadena literal | expresión regular extendida POSIX |
| ¿Regex? | solo con --pickaxe-regex | siempre |
| Detecta que movieron la línea sin cambiar la cuenta | no | sí |
| Caso de uso documentado | encontrar el origen de una cadena | encontrar commits que tocaron un patrón |
El ejemplo canónico de la documentación oficial de git: un commit modifica una llamada y el número de apariciones no cambia.
- hit = frotz(nitfol, mf2.ptr, 1, 0);
+ return frotz(nitfol, two->ptr, 1, 0);
git log -G"frotz\(nitfol" muestra ese commit. git log -S"frotz\(nitfol" --pickaxe-regex no lo muestra, porque la cadena frotz(nitfol aparece una vez antes y una vez después: su cuenta es la misma. Esa es la distinción que debes memorizar: -S solo reacciona cuando la cantidad de veces que aparece el texto cambia.

Cuándo usar -S
Usa -S cuando quieras el commit que introdujo o eliminó una cadena concreta, no un patrón:
- localizar dónde nació un nombre de función, una ruta o un endpoint
- encontrar el commit que dejó de usar una función (
git log -S"funcionDeprecada" --oneline) - detectar cuándo un valor mágico (una API key de prueba, un id de entorno) entró al historial
git log -S"framework.startApp()" --oneline -- src/
Agrega --pickaxe-all cuando el commit modificó varios archivos y quieres ver el diff completo, no solo el archivo donde está la cadena. Para el caso de "buscamos el origen de un texto", -S es exactamente la herramienta que describe la documentación.
Cuándo usar -G
Usa -G cuando la línea pudo cambiar de forma sin cambiar de cuenta:
- renombrado de variable o extracción a constante
- cambio de argumento en una llamada (el caso
frotz) - cualquier búsqueda por patrón, por ejemplo todos los commits que tocaron llamadas a
fetchen archivos TypeScript
git log -G"\.push\(" -p -- '*.ts'
-G es regex por defecto, sin necesidad de --pickaxe-regex. Si además quieres el diff del commit candidato, combínalo con -p y confirma con git show <sha> antes de afirmar nada en el reporte.

Combinar con el resto del flujo git
El pickaxe escanea blobs, así que en repos grandes conviene acotar antes de ejecutar:
- ruta:
git log -S... -- src/services/limita el escaneo a esa subárbol - rango:
--since,--until, y-n 10para no inundar la salida - todas las ramas:
--allcuando el commit pudo venir de una rama ya fusionada - tipo de cambio:
--diff-filter=Apara commits que solo añadieron,-Dpara borrados - binarios: sin un filtro textconv, los binarios se ignoran; con
--texttambién se escanean
No confundas el pickaxe con git log --grep, que busca en los mensajes de commit, ni con git blame, que atribuye las líneas actuales a una versión concreta. El pickaxe trabaja sobre el contenido del diff a lo largo de la historia.
Checklist para depurar con pickaxe
- ¿Cadena literal o patrón?
-Svs-G(o-S+--pickaxe-regex) - ¿La cuenta pudo no cambiar? Entonces es
-G, no-S - ¿Acoté por ruta y por rango de fechas antes de correr?
- ¿Lo confirmé con
git show <sha>y vi el parche real? - ¿Necesito todo el changeset?
--pickaxe-all - ¿El resultado está vacío? Prueba
--allo quita el filtro de ruta - ¿Texto binario? Añade
--texto un filtro textconv
FAQ
¿Por qué git log -S"frotz\(nitfol" --pickaxe-regex no muestra el commit que modifica esa línea? Porque -S solo reacciona a cambios en el número de ocurrencias; si la cadena sigue apareciendo la misma cantidad de veces, el commit no califica. Para "el parche toca líneas que encajan con un patrón" usa -G, que no necesita --pickaxe-regex.
¿-S es siempre literal? Sí, salvo que pases --pickaxe-regex, que trata el argumento de -S como una expresión regular extendida POSIX.
¿Pickaxe y git log --grep son lo mismo? No. --grep filtra por el mensaje del commit; el pickaxe analiza el contenido del diff.
¿Detecta renombrados? -G sí, porque mira líneas del parche. -S detecta el cambio de cuenta, no la renombrada en sí: si el símbolo aparece igual cantidad de veces, no lo reporta.
¿El pickaxe tarda mucho? En repos grandes conviene acotar por ruta y rango; git log -S... -- src/ es notablemente más rápido que sin límite. Si el historial es enorme, revisa git commit-graph para acelerar el recorrido.
Resumen
-S responde "¿cuándo cambió la cuenta de esta cadena?" y -G responde "¿qué commits tocaron líneas que encajan con este patrón?". Acota por ruta y rango, confirma con git show, y usa --pickaxe-all para contexto completo. Con eso, encontrar el origen de una línea en un repo ajeno pasa de caracolear en git log a una consulta con respuesta en segundos. Si trabajas con repos compartidos, recuerda también el flujo seguro de worktrees para no contaminar tu rama mientras investigas.
Lecturas relacionadas
Sigue explorando Coding Agents y otras piezas para builders.

Hooks en Claude Code: automatiza y bloquea acciones del agente en el punto exacto

Kimi Code CLI: guía práctica del agente de IA en la terminal

Slash commands en Claude Code para agentes: crea tu /comando
