{"id":13581390,"url":"https://github.com/josephburnett/jd","last_synced_at":"2025-05-12T13:18:53.424Z","repository":{"id":38007283,"uuid":"72809829","full_name":"josephburnett/jd","owner":"josephburnett","description":"JSON diff and patch","archived":false,"fork":false,"pushed_at":"2025-05-08T02:12:05.000Z","size":7888,"stargazers_count":2030,"open_issues_count":11,"forks_count":55,"subscribers_count":11,"default_branch":"master","last_synced_at":"2025-05-12T13:18:35.234Z","etag":null,"topics":["diff","json","patch","yaml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"mit","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/josephburnett.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":"LICENSE","code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2016-11-04T03:12:05.000Z","updated_at":"2025-05-08T02:03:32.000Z","dependencies_parsed_at":"2024-01-26T04:30:05.762Z","dependency_job_id":"2da5b423-bdaf-4570-b168-d1f716fc4101","html_url":"https://github.com/josephburnett/jd","commit_stats":{"total_commits":369,"total_committers":12,"mean_commits":30.75,"dds":0.051490514905149,"last_synced_commit":"c59db45303149f1e720425c8e462d6855923cd02"},"previous_names":[],"tags_count":27,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josephburnett%2Fjd","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josephburnett%2Fjd/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josephburnett%2Fjd/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/josephburnett%2Fjd/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/josephburnett","download_url":"https://codeload.github.com/josephburnett/jd/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":253745196,"owners_count":21957319,"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":["diff","json","patch","yaml"],"created_at":"2024-08-01T15:02:01.095Z","updated_at":"2025-05-12T13:18:53.352Z","avatar_url":"https://github.com/josephburnett.png","language":"Go","funding_links":[],"categories":["Go","json","Other Text Formats"],"sub_categories":["Diff Enhancers"],"readme":"[![Go Report Card](https://goreportcard.com/badge/josephburnett/jd)](https://goreportcard.com/report/josephburnett/jd)\n\n# JSON diff and patch\n\n`jd` is a commandline utility and Go library for diffing and patching\nJSON and YAML values. It supports a native `jd` format (similar to\nunified format) as well as JSON Merge Patch ([RFC\n7386](https://datatracker.ietf.org/doc/html/rfc7386)) and a subset of\nJSON Patch ([RFC\n6902](https://datatracker.ietf.org/doc/html/rfc6902)). Try it out at\nhttp://play.jd-tool.io/.\n\n## Example\n\nDiff `jd a.json b.json`:\n\n```JSON\n{\"foo\":[\"bar\",\"baz\"]}\n```\n\n```JSON\n{\"foo\":[\"bar\",\"bam\",\"boom\"]}\n```\n\nOutput:\n\n```DIFF\n@ [\"foo\",1]\n  \"bar\"\n- \"baz\"\n+ \"bam\"\n+ \"boom\"\n]\n```\n\n## Features\n\n1. Human-friendly format, similar to Unified Diff.\n2. Produces a minimal diff between array elements using LCS algorithm.\n3. Adds context before and after when modifying an array to prevent bad patches.\n4. Create and apply structural patches in jd, patch (RFC 6902) and merge (RFC 7386) patch formats.\n5. Translates between patch formats.\n6. Includes Web Assembly-based UI (no network calls).\n\n## Installation\n\nGitHub Action:\n\n```yaml\n    - name: Diff A and B\n      id: diff\n      uses: josephburnett/jd@v2.1.2\n      with:\n        args: a.json b.json\n    - name: Print the diff\n      run: echo '${{ steps.diff.outputs.output }}'\n    - name: Check the exit code\n      run: if [ \"${{ steps.diff.outputs.exit_code }}\" != \"1\" ]; then exit 1; fi\n```\n\nTo get the `jd` commandline utility:\n* run `brew install jd`, or\n* run `go install github.com/josephburnett/jd/v2/jd@latest`, or\n* visit https://github.com/josephburnett/jd/releases/latest and download the pre-built binary for your architecture/os, or\n* run in a Docker image `jd(){ docker run --rm -i -v $PWD:$PWD -w $PWD josephburnett/jd \"$@\"; }`.\n\nTo use the `jd` web UI:\n* visit http://play.jd-tool.io/, or\n* run `jd -port 8080` and visit http://localhost:8080.\n\nNote: to include the UI when building from source, use the Makefile.\n\n## Command line usage\n\n```\nUsage: jd [OPTION]... FILE1 [FILE2]\nDiff and patch JSON files.\n\nPrints the diff of FILE1 and FILE2 to STDOUT.\nWhen FILE2 is omitted the second input is read from STDIN.\nWhen patching (-p) FILE1 is a diff.\n\nOptions:\n  -color       Print color diff.\n  -p           Apply patch FILE1 to FILE2 or STDIN.\n  -o=FILE3     Write to FILE3 instead of STDOUT.\n  -set         Treat arrays as sets.\n  -mset        Treat arrays as multisets (bags).\n  -setkeys     Keys to identify set objects\n  -yaml        Read and write YAML instead of JSON.\n  -port=N      Serve web UI on port N\n  -precision=N Maximum absolute difference for numbers to be equal.\n               Example: -precision=0.00001\n  -f=FORMAT    Read and write diff in FORMAT \"jd\" (default), \"patch\" (RFC 6902) or\n               \"merge\" (RFC 7386)\n  -t=FORMATS   Translate FILE1 between FORMATS. Supported formats are \"jd\",\n               \"patch\" (RFC 6902), \"merge\" (RFC 7386), \"json\" and \"yaml\".\n               FORMATS are provided as a pair separated by \"2\". E.g.\n               \"yaml2json\" or \"jd2patch\".\n\nExamples:\n  jd a.json b.json\n  cat b.json | jd a.json\n  jd -o patch a.json b.json; jd patch a.json\n  jd -set a.json b.json\n  jd -f patch a.json b.json\n  jd -f merge a.json b.json\n```\n\n#### Command Line Option Details\n\n`setkeys` This option determines what keys are used to decide if two\nobjects 'match'. Then the matched objects are compared, which will\nreturn a diff if there are differences in the objects themselves,\ntheir keys and/or values. You shouldn't expect this option to mask or\nignore non-specified keys, it is not intended as a way to 'ignore'\nsome differences between objects.\n\n## Library usage\n\nNote: import only release commits (`v2.Y.Z`) because `master` can be unstable.\n\nNote: the `v2` library replaces the v1 (`lib`) library. V2 adds diff\ncontext, minimal array diffs and hunk-level metadata. However the\nformat is not backward compatable. You should use `v2`.\n\n```GO\nimport (\n\t\"fmt\"\n\tjd \"github.com/josephburnett/jd/v2\"\n)\n\nfunc ExampleJsonNode_Diff() {\n\ta, _ := jd.ReadJsonString(`{\"foo\":[\"bar\"]}`)\n\tb, _ := jd.ReadJsonString(`{\"foo\":[\"baz\"]}`)\n\tfmt.Print(a.Diff(b).Render())\n\t// Output:\n\t// @ [\"foo\",0]\n\t// [\n\t// - \"bar\"\n\t// + \"baz\"\n\t// ]\n}\n\nfunc ExampleJsonNode_Patch() {\n\ta, _ := jd.ReadJsonString(`[\"foo\"]`)\n\tdiff, _ := jd.ReadDiffString(`\n@ [1]\n  \"foo\"\n+ \"bar\"\n]\n`\n\tb, _ := a.Patch(diff)\n\tfmt.Print(b.Json())\n\t// Output:\n\t// [\"foo\",\"bar\"]\n}\n```\n\n## Diff language\n\nNote: this is the v1 grammar. Needs to be updated with v2.\n\n![Railroad diagram of EBNF](/ebnf.png)\n\n- A diff is zero or more sections\n- Sections start with a `@` header and the path to a node\n- A path is a JSON list of zero or more elements accessing collections\n- A JSON number element (e.g. `0`) accesses an array\n- A JSON string element (e.g. `\"foo\"`) accesses an object\n- An empty JSON object element (`{}`) accesses an array as a set or multiset\n- After the path is one or more removals or additions, removals first\n- Removals start with `-` and then the JSON value to be removed\n- Additions start with `+` and then the JSON value to added\n\n### EBNF\n\n```EBNF\nDiff ::= ( '@' '[' ( 'JSON String' | 'JSON Number' | 'Empty JSON Object' )* ']' '\\n' ( ( '-' 'JSON Value' '\\n' )+ | '+' 'JSON Value' '\\n' ) ( '+' 'JSON Value' '\\n' )* )*\n```\n\n### Examples\n\n```DIFF\n@ [\"a\"]\n- 1\n+ 2\n```\n\n```DIFF\n@ [2]\n[\n+ {\"foo\":\"bar\"}\n]\n```\n\n```DIFF\n@ [\"Movies\",67,\"Title\"]\n- \"Dr. Strangelove\"\n+ \"Dr. Evil Love\"\n@ [\"Movies\",67,\"Actors\",\"Dr. Strangelove\"]\n- \"Peter Sellers\"\n+ \"Mike Myers\"\n@ [\"Movies\",102]\n  {\"Title\":\"Terminator\",\"Actors\":{\"Terminator\":\"Arnold\"}}\n+ {\"Title\":\"Austin Powers\",\"Actors\":{\"Austin Powers\":\"Mike Myers\"}}\n]\n```\n\n```DIFF\n@ [\"Movies\",67,\"Tags\",{}]\n- \"Romance\"\n+ \"Action\"\n+ \"Comedy\"\n```\n\n## Cookbook\n\n### Use git diff to produce a structural diff:\n```diff\ngit difftool -yx jd @ -- foo.json\n@ [\"foo\"]\n- \"bar\"\n+ \"baz\"\n```\n\n### See what changes in a Kubernetes Deployment:\n```bash\nkubectl get deployment example -oyaml \u003e a.yaml\nkubectl edit deployment example\n# change cpu resource from 100m to 200m\nkubectl get deployment example -oyaml | jd -yaml a.yaml\n```\noutput:\n```diff\n@ [\"metadata\",\"annotations\",\"deployment.kubernetes.io/revision\"]\n- \"2\"\n+ \"3\"\n@ [\"metadata\",\"generation\"]\n- 2\n+ 3\n@ [\"metadata\",\"resourceVersion\"]\n- \"4661\"\n+ \"5179\"\n@ [\"spec\",\"template\",\"spec\",\"containers\",0,\"resources\",\"requests\",\"cpu\"]\n- \"100m\"\n+ \"200m\"\n@ [\"status\",\"conditions\",1,\"lastUpdateTime\"]\n- \"2021-12-23T09:40:39Z\"\n+ \"2021-12-23T09:41:49Z\"\n@ [\"status\",\"conditions\",1,\"message\"]\n- \"ReplicaSet \\\"nginx-deployment-787d795676\\\" has successfully progressed.\"\n+ \"ReplicaSet \\\"nginx-deployment-795c7f5bb\\\" has successfully progressed.\"\n@ [\"status\",\"observedGeneration\"]\n- 2\n+ 3\n```\napply these change to another deployment:\n```bash\n# edit file \"patch\" to contain only the hunk updating cpu request\nkubectl patch deployment example2 --type json --patch \"$(jd -t jd2patch ~/patch)\"\n```\n\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosephburnett%2Fjd","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fjosephburnett%2Fjd","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fjosephburnett%2Fjd/lists"}