{"id":13394737,"url":"https://github.com/trailofbits/graphtage","last_synced_at":"2025-04-12T20:38:44.330Z","repository":{"id":37394340,"uuid":"257655337","full_name":"trailofbits/graphtage","owner":"trailofbits","description":"A semantic diff utility and library for tree-like files such as JSON, JSON5, XML, HTML, YAML, and CSV.","archived":false,"fork":false,"pushed_at":"2024-05-07T23:29:01.000Z","size":8454,"stargazers_count":2402,"open_issues_count":27,"forks_count":48,"subscribers_count":51,"default_branch":"master","last_synced_at":"2025-04-12T15:50:08.173Z","etag":null,"topics":["command-line-tool","diff","graph-algorithms","hacktoberfest","hacktoberfest2021","library","python","utility"],"latest_commit_sha":null,"homepage":"","language":"Python","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"lgpl-3.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/trailofbits.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":"CODE_OF_CONDUCT.md","threat_model":null,"audit":null,"citation":"CITATION.cff","codeowners":"CODEOWNERS","security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2020-04-21T16:47:22.000Z","updated_at":"2025-04-10T14:47:51.000Z","dependencies_parsed_at":"2024-02-04T18:06:31.885Z","dependency_job_id":"a781c51f-d61d-4014-a716-2750862928ce","html_url":"https://github.com/trailofbits/graphtage","commit_stats":{"total_commits":532,"total_committers":11,"mean_commits":48.36363636363637,"dds":0.05639097744360899,"last_synced_commit":"23654acf488eb803a60ce27ac515ee0755feb1a7"},"previous_names":[],"tags_count":14,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailofbits%2Fgraphtage","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailofbits%2Fgraphtage/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailofbits%2Fgraphtage/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/trailofbits%2Fgraphtage/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/trailofbits","download_url":"https://codeload.github.com/trailofbits/graphtage/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":248593554,"owners_count":21130310,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":["command-line-tool","diff","graph-algorithms","hacktoberfest","hacktoberfest2021","library","python","utility"],"created_at":"2024-07-30T17:01:29.925Z","updated_at":"2025-04-12T20:38:44.308Z","avatar_url":"https://github.com/trailofbits.png","language":"Python","readme":"# Graphtage\n\n[![PyPI version](https://badge.fury.io/py/graphtage.svg)](https://badge.fury.io/py/graphtage)\n[![Tests](https://github.com/trailofbits/graphtage/workflows/Python%20package/badge.svg)](https://github.com/trailofbits/graphtage/actions)\n[![Slack Status](https://slack.empirehacking.nyc/badge.svg)](https://slack.empirehacking.nyc)\n\nGraphtage is a command-line utility and [underlying library](https://trailofbits.github.io/graphtage/latest/library.html)\nfor semantically comparing and merging tree-like structures, such as JSON, XML, HTML, YAML, plist, and CSS files. Its name is a\nportmanteau of “graph” and “graftage”—the latter being the horticultural practice of joining two trees together such\nthat they grow as one.\n\n```console\n$ echo Original: \u0026\u0026 cat original.json \u0026\u0026 echo Modified: \u0026\u0026 cat modified.json\n```\n```json\nOriginal:\n{\n    \"foo\": [1, 2, 3, 4],\n    \"bar\": \"testing\"\n}\nModified:\n{\n    \"foo\": [2, 3, 4, 5],\n    \"zab\": \"testing\",\n    \"woo\": [\"foobar\"]\n}\n```\n```console\n$ graphtage original.json modified.json\n```\n```json\n{\n    \"z̟b̶ab̟r̶\": \"testing\",\n    \"foo\": [\n        1̶,̶\n        2,\n        3,\n        4,̟\n        5̟\n    ],̟\n    \"̟w̟o̟o̟\"̟:̟ ̟[̟\n        \"̟f̟o̟o̟b̟a̟r̟\"̟\n    ]̟\n}\n```\n\n## Installation\n\n```console\n$ pip3 install graphtage\n```\n\n## Command Line Usage\n\n### Output Formatting\nGraphtage performs an analysis on an intermediate representation of the trees that is divorced from the filetypes of the\ninput files. This means, for example, that you can diff a JSON file against a YAML file. Also, the output format can be\ndifferent from the input format(s). By default, Graphtage will format the output diff in the same file format as the\nfirst input file. But one could, for example, diff two JSON files and format the output in YAML. There are several\ncommand-line arguments to specify these transformations, such as `--format`; please check the `--help` output for more\ninformation.\n\nBy default, Graphtage pretty-prints its output with as many line breaks and indents as possible.\n```json\n{\n    \"foo\": [\n        1,\n        2,\n        3\n    ],\n    \"bar\": \"baz\"\n}\n```\nUse the `--join-lists` or `-jl` option to suppress linebreaks after list items:\n```json\n{\n    \"foo\": [1, 2, 3],\n    \"bar\": \"baz\"\n}\n```\nLikewise, use the `--join-dict-items` or `-jd` option to suppress linebreaks after key/value pairs in a dict:\n```json\n{\"foo\": [\n    1,\n    2,\n    3\n], \"bar\":  \"baz\"}\n```\nUse `--condensed` or `-j` to apply both of these options:\n```json\n{\"foo\": [1, 2, 3], \"bar\": \"baz\"}\n```\n\nThe `--only-edits` or `-e` option will print out a list of edits rather than applying them to the input file in place.\n\nThe `--edit-digest` or `-d` option is like `--only-edits` but prints a more concise context for each edit that is more\nhuman-readable.\n\n### Matching Options\nBy default, Graphtage tries to match all possible pairs of elements in a dictionary.\n\nMatching two dictionaries with each other is hard. Although computationally tractable, this can sometimes be onerous for \ninput files with huge dictionaries. Graphtage has three different strategies for matching dictionaries:\n1. `--dict-strategy match` (the most computationally expensive) tries to match all pairs of keys and values between the\n   two dictionaries, resulting in a match of minimum edit distance;\n2. `--dict-strategy none` (the least computationally expensive) will not attempt to match any key/value pairs unless\n   they have the exact same key; and\n3. `--dict-strategy auto` (the default) will automatically match the values of any key-value pairs that have identical\n   keys and then use the `match` strategy for the remainder of key/value pairs.\n\nSee [Pull Request #51](https://github.com/trailofbits/graphtage/pull/51) for some examples of how these strategies\naffect output.\n\nThe `--no-list-edits` or `-l` option will not consider interstitial insertions and removals when comparing two lists.\nThe `--no-list-edits-when-same-length` or `-ll` option is a less drastic version of `-l` that will behave normally for\nlists that are of different lengths but behave like `-l` for lists that are of the same length.\n\n### ANSI Color\nBy default, Graphtage will only use ANSI color in its output if it is run from a TTY. If, for example, you would like\nto have Graphtage emit colorized output from a script or pipe, use the `--color` or `-c` argument. To disable color even\nwhen running on a TTY, use `--no-color`.\n\n### HTML Output\nGraphtage can optionally emit the diff in HTML with the `--html` option.\n```console\n$ graphtage --html original.json modified.json \u003e diff.html\n```\n\n### Status and Logging\nBy default, Graphtage prints status messages and a progress bar to STDERR. To suppress this, use the `--no-status`\noption. To additionally suppress all but critical log messages, use `--quiet`. Fine-grained control of log messages is\nvia the `--log-level` option.\n\n## Why does Graphtage exist?\n\nDiffing tree-like structures with unordered elements is tough. Say you want to compare two JSON files.\nThere are [limited tools available](https://github.com/zgrossbart/jdd), which are effectively equivalent to\ncanonicalizing the JSON (_e.g._, sorting dictionary elements by key) and performing a standard diff. This is not always\nsufficient. For example, if a key in a dictionary is changed but its value is not, a traditional diff\nwill conclude that the entire key/value pair was replaced by the new one, even though the only change was the key\nitself. See [our documentation](https://trailofbits.github.io/graphtage/latest/howitworks.html) for more information.\n\n## Using Graphtage as a Library\n\nGraphtage has a complete API for programmatically operating its diffing capabilities.\nWhen using Graphtage as a library, it is also capable of diffing in-memory Python objects.\nThis can be useful for debugging Python code, for example, to determine a differential between two objects.\nSee [our documentation](https://trailofbits.github.io/graphtage/latest/library.html) for more information.\n\n## Extending Graphtage\n\nGraphtage is designed to be extensible: New filetypes can easily be defined, as well as new node types, edit types,\nformatters, and printers. See [our documentation](https://trailofbits.github.io/graphtage/latest/extending.html) for\nmore information.\n\nComplete API documentation is available [here](https://trailofbits.github.io/graphtage/latest/package.html).\n\n## License and Acknowledgements\n\nThis research was developed by [Trail of Bits](https://www.trailofbits.com/) with partial funding from the Defense\nAdvanced Research Projects Agency (DARPA) under the SafeDocs program as a subcontractor to [Galois](https://galois.com).\nIt is licensed under the [GNU Lesser General Public License v3.0](LICENSE).\n[Contact us](mailto:opensource@trailofbits.com) if you're looking for an exception to the terms.\n© 2020–2023, Trail of Bits.\n","funding_links":[],"categories":["Python","Command-Line Tools","\u003ca name=\"data-management-json\"\u003e\u003c/a\u003eData management - JSON/YAML/etc.","Other","Other Text Formats"],"sub_categories":["Libraries","Diff Enhancers"],"project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrailofbits%2Fgraphtage","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Ftrailofbits%2Fgraphtage","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Ftrailofbits%2Fgraphtage/lists"}