2 puntos por GN⁺ 2025-06-05 | 1 comentarios | Compartir por WhatsApp
  • El formato Unified Diff tradicional tiene limitaciones para reflejar por completo las necesidades de los entornos de desarrollo
  • DiffX es totalmente compatible con el formato existente y ofrece una estructura pensada para el futuro junto con extensibilidad de metadatos
  • Permite almacenar de forma estructurada múltiples datos de commits, archivos binarios, codificación de caracteres y metadatos
  • Al incorporar reglas de parseo estandarizadas, facilita la integración con diversas herramientas (patch, revisión de código, etc.)
  • Puede usarse sin problemas con las herramientas y flujos de trabajo existentes; solo las nuevas funciones requieren soporte de esas herramientas

Los desarrolladores y los archivos Diff

  • Los desarrolladores de software suelen revisar los cambios de código mediante archivos diff en Git, Subversion, CVS y otros sistemas
  • Los archivos diff tienen una estructura que incluye inserciones de texto (+) y eliminaciones (-), además de nombres de archivo, rutas, marcas de tiempo y algunos metadatos
  • La mayoría de las herramientas y usuarios utilizan el formato Unified Diff, que visualiza las diferencias de forma relativamente simple

Limitaciones de Unified Diff

  • Unified Diff solo estandariza la identificación de archivos, el alcance de los cambios y las líneas insertadas o eliminadas; no estandariza aspectos como codificación, revisión y metadatos extendidos
  • Esto dificulta el soporte para distintos sistemas de control de código fuente, un parseo confiable y la extracción de información rica
  • Siguen apareciendo problemas como los siguientes
    • No puede representar varios commits a la vez
    • Falta un formato estándar específico para archivos binarios
    • Al no conocerse la codificación de caracteres, se producen pérdidas de información y confusión
    • La falta de estandarización para metadatos arbitrarios hace que cada herramienta use formatos distintos

Dirección de mejora

  • Aunque el Unified Diff existente carece de suficiente estructura y estandarización, ya está ampliamente difundido por su flexibilidad y uso en distintos entornos
  • Git Diff actúa de facto como un estándar, pero aún faltan una especificación oficial del formato y una extensibilidad verdaderamente general
  • Crece la necesidad de un nuevo formato que conserve las ventajas de Unified Diff existente y añada extensibilidad y una estructura estandarizada

¿Qué es DiffX?

  • DiffX es un formato Diff extensible que es totalmente compatible con las herramientas existentes, mantiene la legibilidad humana y al mismo tiempo permite contener metadatos y organización de forma estructurada
  • Ejemplos de sintaxis:
    • Guarda metadatos y contenido de archivos, commits y del diff completo mediante una estructura y un mecanismo de extensión
    • En la salida de ejemplo aparecen elementos como #diffx:, secciones, metadatos (JSON), rutas de archivos e información de commits

Principales características y ventajas de DiffX

  • Proporciona reglas de parseo estandarizadas, para que las herramientas puedan leer y escribir información de forma confiable
  • Oficializa el almacenamiento y la gestión de metadatos: puede usarse a nivel de diff completo, commit o archivo
  • Es compatible con todas las herramientas existentes, como parsers, patchers y revisión de código (las funciones nuevas requieren soporte, pero las existentes mantienen la compatibilidad)
  • Permite expresar de forma eficiente y estructurada múltiples contenidos en un solo archivo, como varios commits, diff binario e información de codificación de texto
  • Soporta la mutabilidad, permitiendo que una herramienta abra el diff, registre o modifique la información necesaria y luego lo vuelva a guardar

Objetivos y no objetivos de DiffX

  • No obliga a que todas las herramientas soporten el formato ni genera problemas de compatibilidad
  • No provoca dependencia de proveedor ni rompe los flujos de trabajo existentes
  • Busca resolver los problemas de los archivos Diff actuales y ofrecer una experiencia de uso consistente y confiable en herramientas de desarrollo, revisión y análisis

1 comentarios

 
GN⁺ 2025-06-05
Opiniones en Hacker News
  • No me gustan los formatos jerárquicamente complejos como ..meta y ...meta. Para que la expresión sea más clara, creo que sería más fácil de entender si se distinguiera solo en tres niveles —el diff completo, el archivo y el chunk— y se le diera a cada uno un nombre distinto. Incluso sin bloques meta, así se podría identificar el objetivo de un vistazo y también se reducirían errores o confusiones. También me parece poco razonable que los metadatos del diff completo y los metadatos a nivel de archivo estén compuestos por los mismos campos. Y no entiendo por qué se necesitan dos formatos, JSON y key=value; si hay pocos elementos que administrar, usar un solo formato sería mucho más conveniente para la implementación o la integración con herramientas existentes (bastaría con usar solo uno entre grep, sed o jq). Además, estaría bien permitir trailing commas en listas, y me da curiosidad cómo afecta este formato al hecho de que un diff originalmente pueda aplicarse por partes (por ejemplo, si quieres aplicar solo una parte del diff, parece engorroso tener que copiar el preámbulo y también copiar los bloques por separado). También me pregunto si revision es un atributo del archivo o un checksum del commit.

    • Probamos varios enfoques para la estructura y al final la organizamos en la forma #<section_level><section_type> por simplicidad desde el punto de vista del parseo. En cada bloque meta solo hace falta verificar verticalmente el nivel, y contando la cantidad de puntos se puede distinguir de forma natural a qué nivel de metadata pertenece. El formato de encabezado clave/valor estaba pensado para contener solo propiedades simples que el parser ya conoce de antemano, mientras que la metadata libre se diseñó para ir en un bloque meta separado. Además de JSON existente, también se puede indicar el formato en el encabezado para mantener extensibilidad si con el tiempo se necesita otro método de serialización. Es el resultado de intentar equilibrar simplicidad y flexibilidad. Personalmente me gustaría permitir trailing commas, pero es difícil exigir un parser JSON5 por temas de compatibilidad con JSON de nivel base. El diff sigue siendo divisible, y como la información se puso en áreas que Unified Diff ignora, herramientas como GNU patch la ignoran sin problema. Eso sí, si se divide en dos archivos DiffX, hay que volver a agregar los encabezados, así que puede volverse un poco más complejo. En algunos SCM, aunque dividas el diff, se puede perder cierta metadata (por ejemplo, información del commit padre) o puede haber pérdida de información según el objetivo de aplicación. revision varía según el SCM: puede ser un ID de commit, un ID por archivo, una combinación de ambos, información adicional, etc. La estructura se pensó para cubrir esas necesidades diversas de distintos SCM.
  • Desde mi punto de vista, de las cuatro observaciones de abajo, la única que realmente parece razonable como generalización de un archivo diff es la notación de parches binarios. Las demás son problemas de datos internos o de protocolo de sistemas de control de versiones (SCM) específicos, así que solo tienen sentido dentro de sus respectivos clientes, servidores o sistemas de respaldo. Todo lo demás me parece innecesario.

    • No se pueden listar varios commits en un solo diff

    • No hay un estándar para parches binarios

    • No se puede reconocer la codificación de texto (sorprendentemente sí es un problema)

    • No existe un formato estándar para metadata arbitraria

    • Llevamos 20 años desarrollando un producto de revisión de código que integra más de 12 SCM, y hemos sufrido innumerables problemas con formatos diff y peculiaridades de cada SCM que nadie imaginaría. En realidad no son temas de los que el usuario final deba preocuparse directamente, pero para quienes desarrollan herramientas son pain points que necesariamente hay que resolver. Algunos SCM no tienen su propio formato diff, o les falta mucha información (por ejemplo, no pueden indicar archivos eliminados), lo que a menudo hace que otras herramientas no puedan identificar correctamente los archivos, y por eso sentimos que hacía falta este tipo de mejora.

    • Hoy en día es menos común, pero yo también sigo usando de vez en cuando herramientas parecidas a patch(1). Cuando colaboran desarrolladores de varias plataformas, todavía surgen muchos problemas por temas como mayúsculas y minúsculas en nombres de archivos o codificación de caracteres.

  • Si se mete JSON como un formato auto-delimitado con información de longitud, entonces aunque JSON siga siendo válido con solo cambiar un espacio en blanco dentro de su contenido, DiffX corre el riesgo de romperse por completo. Se siente como una combinación estructuralmente torpe y desordenada (mezclar encabezados propios con payload JSON, no poder distinguir otros bloques meta sin contar puntos, requerir dos parsers, etc.). La idea de estandarizar un diff extensible para metadata me parece buena, pero esta implementación parece más bien un ensayo y error.

  • Creo que el formato patch ya resuelve todos estos problemas. Enlace a la explicación de git format-patch

    • Hoy me enteré por primera vez de que existe ese formato y lo tomo como referencia (solo soy un usuario común de internet, no el autor).

    • En git sí se puede resolver, pero en un producto como Review Board hay que integrarse con varios VCS como SVN, CVS o Perforce, así que parece que de ahí surgió este formato. Yo también usé Review Board y SVN, y cuando varios desarrolladores mezclaban git-svn y svn, a menudo había problemas al subir diffs para revisión. Si hubiera existido un formato diff estándar compatible con ambos lados, habría ayudado mucho más al uso de la herramienta.

  • En realidad no siento mucho que los problemas planteados existan de verdad (salvo en archivos binarios).

    • Aunque la codificación sea distinta, el algoritmo de patch es el mismo, así que no hace falta preocuparse (ni siquiera es necesario que los caracteres sean UTF-8 válidos).

    • Tampoco veo motivo para querer meter varios commits en un solo diff; dividirlo en varios diffs es más intuitivo.

    • Creo que la metadata solo es válida dentro del sistema interno.

    • También respecto a la codificación, los datos de patch al final tienen que tratarse como datos binarios basados en ASCII. Como se pueden modificar archivos con codificación mixta, no tiene mucho sentido fijar una codificación.

    • No me parece ningún problema en absoluto; creo que sería mejor escuchar la experiencia real de quienes usan mucho los diffs, y no sobreingenierizar un formato que ya funciona bien.

    • El problema con los datos binarios sí creo que existe claramente.

    • Normalmente estos problemas solo aparecen de verdad cuando haces tus propias herramientas o tienes que interactuar con un SCM específico.

      1. Los problemas de codificación existen tanto en nombres de archivo como en el contenido. Git sí presta atención a la codificación de nombres de archivo, pero la mayoría de los SCM no, así que a veces un diff generado automáticamente en un entorno no logra encontrar los nombres de archivo en otro entorno (lo he visto en Perforce, Subversion, etc.). En el contenido pasa igual: según la codificación local de cada SCM, el diff puede romperse. También me ha pasado que GNU patch fallara por mezcla de saltos de línea entre Windows y Linux o por problemas con BOM.
      2. Al manejar varios commits de una vez o pasarlos a una herramienta, pueden surgir muchos problemas como archivos faltantes o inconsistencias, y es tedioso hacer sanity checks diff por diff. Además, cada herramienta soporta formatos distintos, lo que resulta incómodo.
      3. Para encontrar archivos en el repositorio, cada sistema necesita distintos identificadores: por commit, por archivo, combinaciones, relaciones, etc. También son imprescindibles datos que no entran en Unified diff, como enlaces simbólicos, modo de archivo o información específica del SCM.
  • El documento completo se siente difícil de leer. Para mí, un “diff” significa la diferencia entre dos elementos (archivos, directorios, etc.), pero el diff del que habla TFA es en realidad lo que yo conozco como “patch”. Lo que aquí se está discutiendo no es el diff, sino la administración de metadata de patch. Si se estandarizara la metadata como un formato obligatorio, por ejemplo JSON, me parecería bien, pero al dejarlo como una estructura ambigua, auto-descriptiva y delimitada por longitud, da la impresión de que se están escondiendo los problemas. La estandarización en sí me parece buena, pero siento que hace falta una solución más clara y mejor organizada. También me parece interesante que, al final, el estilo de git diff me siga pareciendo más cercano a un estándar de facto.

    • Estoy completamente de acuerdo con la última frase: basta con usar varios diffs por separado.
  • Me pregunto qué problema intenta resolver realmente este formato. Se dice que el formato patch/diff no es lo suficientemente bueno, pero haría falta explicar con más detalle para quién es esta mejora, si se debe a que crecieron las quejas en la comunidad de GNU Patch o cuál es la razón concreta. Me sigue quedando la duda de por qué sería realmente necesario un formato de patch mejor.

    • Tengo un texto aparte, demasiado largo para ponerlo aquí, pero en resumen es una inquietud orientada a quienes crean SCM directamente o desarrollan herramientas que se integran con SCM. Si eres un usuario común, no necesitas preocuparte por esto. Además, los formatos diff varían totalmente entre SCM: algunos están muy bien hechos, otros tienen carencias graves y algunos ni siquiera tienen formato propio. Desde la perspectiva de un producto como Review Board, que debe cubrir muchos SCM, un estándar de integración como este sí es necesario en la práctica. De hecho, es un intento de mejora que refleja feedback obtenido en colaboración con proveedores de SCM.

    • Parece un formato usado sobre todo en Review Board; como este producto soporta varios VCS y el diff es clave en la revisión de código, da la impresión de que por eso lo adoptaron.

  • La forma más general y clara de representar un diff es simplemente incluir los dos archivos. Hoy en día el tamaño de los datos ya no es un problema, así que en vez de diff a b | patch c se podría hacer algo como apply a b c, y daría igual cuál fuera la representación interna. Los diffs son difíciles de leer para humanos, y una vista en color lado a lado es mucho mejor, así que desde el principio resulta más intuitivo recibir ambos archivos y procesarlos así. No creo que sea necesario transmitir un diff no estandarizado.

    • Un diff hecho a partir de dos archivos no es solo uno; pueden salir varias versiones distintas según el propósito. Tener un formato diff permite separar la lógica de generación y la de aplicación del diff, reduciendo el problema de n*m a uno de n+m.

    • En actualizaciones de programas y casos similares, tener que volver a descargar los 130 GB completos cada vez sería molesto, pero entre archivos casi idénticos también es fácil comprimir, así que sigue siendo muy útil enviar solo la diferencia entre dos versiones. Incluso parecen posibles métodos más eficientes, como enviar solo el hash del archivo original y transmitir el cuerpo del archivo comprimido.

    • Transmitir y administrar dos pares de archivos es difícil sin un contenedor dedicado, y si quieres intercambiar por correo u otros medios varios cambios a la vez (por ejemplo, modificar 10 archivos, borrar otros y agregar nuevos), terminas retrocediendo a algo parecido a la era pre-VCS, donde todo se vuelve una estructura más complicada tipo tar/zip.

    • Aunque enviar el archivo completo en vez de un diff pueda parecer más intuitivo, según el uso y el entorno el diff sigue teniendo mucha importancia. Hoy, por ejemplo, al generar resultados como ediciones de código con LLM, pedirlos en forma de diff ahorra muchos tokens y reduce la latencia de respuesta hasta 5-10 veces, con una mejora de eficiencia muy notable. Enviar ambos archivos completos desperdicia tokens y aumenta el costo. Para aplicar cambios rápidamente en un sandbox de código o en una máquina remota, el diff ofrece grandes ventajas de optimización. Si tienes el archivo A, el archivo A2 y el diff AxA2, también es fácil reconstruir A2 y optimizar el almacenamiento. Si al fusionar aparecen conflictos, se interviene manualmente solo en ese momento. En resumen: los diffs son excelentes.

  • Sigo molesto con que las herramientas de diff dependan demasiado de los saltos de línea. Cuando una línea es demasiado larga (por ejemplo, JSON, arreglos largos, etc.), revisar cambios se vuelve difícil.

    • Yo también estoy de acuerdo. Creo que todavía hay margen para explorar mejores formas de representar diffs en datos estructurados (por ejemplo, AST diff). Este formato (DiffX) se centra en ser una extensión del formato Unified Diff existente, y si en el futuro formatos más específicos como AST se vuelven de uso amplio, también fue diseñado para poder integrarlos y soportarlos fácilmente.

    • La forma de uso común es una solución intermedia entre legibilidad humana y facilidad de parseo por herramientas, así que queda en un punto ambiguo. Esta vez parece que intentaron resolver parte del problema ampliando la metadata, pero una solución realmente buena probablemente requeriría definir un formato nuevo que no sea texto plano y que aun así sea fácil de leer y parsear. Crear algoritmos diff mejores para líneas largas o datos estructurados es una tarea difícil, pero creo que se puede resolver perfectamente.

    • git también soporta un word diff más detallado que line diff, y el separador predeterminado es el espacio en blanco.

  • Me genera dudas que JSON sea el único formato de metadata soportado. Para un estándar de metadata diseñado con fines generales, JSON más bien me parece complejo.

    • Me gustaría escuchar una explicación concreta de por qué piensas que JSON es excesivamente complejo.