{"id":50728855,"url":"https://github.com/andrew-grechkin/update-yaml","last_synced_at":"2026-06-10T06:48:05.470Z","repository":{"id":361228815,"uuid":"1253444749","full_name":"andrew-grechkin/update-yaml","owner":"andrew-grechkin","description":"A CLI filter for updating YAML documents from one or more YAML/JSON data files while preserving comments, key order and formatting of the original","archived":false,"fork":false,"pushed_at":"2026-06-04T16:25:51.000Z","size":43,"stargazers_count":1,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2026-06-10T06:48:03.012Z","etag":null,"topics":["cli","filter","yaml"],"latest_commit_sha":null,"homepage":"","language":"Go","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":"gpl-2.0","status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/andrew-grechkin.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":"CONTRIBUTING.md","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,"notice":null,"maintainers":null,"copyright":null,"agents":null,"dco":null,"cla":null}},"created_at":"2026-05-29T13:19:53.000Z","updated_at":"2026-06-04T16:26:06.000Z","dependencies_parsed_at":null,"dependency_job_id":null,"html_url":"https://github.com/andrew-grechkin/update-yaml","commit_stats":null,"previous_names":["andrew-grechkin/update-yaml"],"tags_count":1,"template":false,"template_full_name":null,"purl":"pkg:github/andrew-grechkin/update-yaml","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrew-grechkin%2Fupdate-yaml","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrew-grechkin%2Fupdate-yaml/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrew-grechkin%2Fupdate-yaml/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrew-grechkin%2Fupdate-yaml/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/andrew-grechkin","download_url":"https://codeload.github.com/andrew-grechkin/update-yaml/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/andrew-grechkin%2Fupdate-yaml/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":34140774,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-05-26T15:22:16.424Z","status":"online","status_checked_at":"2026-06-10T02:00:07.152Z","response_time":89,"last_error":null,"robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":true,"can_crawl_api":true,"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":["cli","filter","yaml"],"created_at":"2026-06-10T06:48:04.559Z","updated_at":"2026-06-10T06:48:05.461Z","avatar_url":"https://github.com/andrew-grechkin.png","language":"Go","funding_links":[],"categories":[],"sub_categories":[],"readme":"# update-yaml\n\n[![Go Reference](https://pkg.go.dev/badge/github.com/andrew-grechkin/update-yaml.svg)](https://pkg.go.dev/github.com/andrew-grechkin/update-yaml)\n[![Go Report Card](https://goreportcard.com/badge/github.com/andrew-grechkin/update-yaml)](https://goreportcard.com/report/github.com/andrew-grechkin/update-yaml)\n\nA CLI filter for updating YAML documents from one or more YAML/JSON data files while preserving comments, key order and\nformatting of the original.\n\nTailored for developers who maintain **hand-edited config files**, **Kubernetes manifests**, **Helm values**, **CI/CD\nconfigs**, or any YAML file where comments and structure matter and a full re-marshal would lose them.\n\nWhile round-tripping YAML through generic tools (`yq`, `jaq`, ad-hoc scripts) is easy, doing it without destroying\ncomments, blank lines and the author's intent is not. That's why it is important to separate 2 concerns for this task:\nupdate YAML file and calculate data for update. When these 2 concerns are separated any tool or any language can be used\nto prepare a new data set and what is left for `update-yaml` is just take the provided data and inject it into correct\nplace into existing YAML keeping it as close as possible to the original document.\n\n## SYNOPSIS\n\n```bash\n# source from STDIN, single data file\nupdate-yaml \u003c\u003c\u003c 'name: old # some name' \u003c(echo 'name: new')\n```\n\n```bash\n# source from STDIN, multiple data files merged in order (later wins)\nupdate-yaml \u003c source.yaml base.yaml override.yaml\n```\n\n## OPTIONS\n\n- -h, --help Display help message\n- -m, --man Display full readme (tip: update-yaml --man | colored-md)\n- -v, --version Display version information (tip: update-yaml --version | jq -r .Version)\n\n## ENVIRONMENT\n\n- `UPDATE_YAML_PREFER_ORDER_PRESERVED` - when set, new keys are appended at the end of their mapping in the order\n  declared by data files, instead of being spliced in alphabetically among the existing keys (the default).\n- `UPDATE_YAML_PREFER_SINGLE_QUOTE` - when set, values that need quoting are emitted with single quotes regardless of\n  what the source file uses. Plain strings stay plain - quotes are never added to values that don't need them, and\n  existing quoted values keep their original style on replace.\n\n## INSTALLATION\n\n```bash\ngo install github.com/andrew-grechkin/update-yaml@latest\n```\n\nBy default, `go install` creates binaries in `$GOBIN` or `$GOPATH/bin`.\nTo make sure you can use the installed binary you need to add this directory to your path.\n\n```bash\n# ensure the go install binaries are in your PATH, consider adding to your shell startup config\nexport PATH=\"${GOBIN:-${GOPATH:-$HOME/go}/bin}:$PATH\"\n```\n\n## FEATURES\n\n- Pure CLI filter: reads source YAML from STDIN, writes updated result to STDOUT\n- Preserves head, inline and trailing comments on untouched and replaced values\n- Preserves key order of the original document\n- Auto-detects and preserves indent width (block mappings) and sequence indent style (flush vs. extra-indented)\n- Auto-detects single vs. double quote preference from the source for new emissions; replaced values keep their original\n  quote style when meaningful, or drop quotes the new value doesn't need\n- Deep merges multiple data files (like Helm) with first-occurrence-wins ordering: later files override values, but new\n  keys are appended at the end while existing keys keep their slot\n- Explicit `null` in data removes the corresponding key from the output\n- Anchors (`\u0026name`) and aliases (`*name`) are preserved\n- Multi-document YAML supported on both sides (STDIN doc[i] is updated by merged data doc[i])\n\n## USAGE\n\n### Single data file\n\nUpdate with inline data:\n\n```bash\nupdate-yaml \u003c\u003c\u003c 'name: old # some name' \u003c(echo 'name: new')\n```\n\nOr with actual files:\n\n```bash\nupdate-yaml \u003c source.yaml data.yaml\n```\n\nOr [UUOC](\u003chttps://en.wikipedia.org/wiki/Cat_(Unix)#Useless_use_of_cat\u003e), if one would like:\n\n```bash\ncat source.yaml | update-yaml data.yaml\n```\n\n### Multiple data files with deep merge\n\n```bash\nupdate-yaml \u003c\u003c EO_INPUT \u003c(echo 'replicas: 5') \u003c(echo 'config: {debug: true, cache: enabled}')\nname: svc\n\n# one replica is enough\nreplicas: 1\n\nconfig:\n  timeout: 30 # timeout is required\n  debug: false\nEO_INPUT\n```\n\nOr with actual files:\n\n```bash\nupdate-yaml \u003c source.yaml base.yaml override.yaml override2.yaml\n```\n\nLater files override earlier ones (just like with `helm install -f base.yaml -f override.yaml`).\n\n### Comments and format are preserved\n\nGiven a source like:\n\n```yaml\n# Database connection settings\ndatabase:\n  host: localhost # default for dev\n  port: 5432\n```\n\nAnd data:\n\n```yaml\ndatabase:\n  host: db.internal\n```\n\nThe result keeps both the head comment and the inline comment and only the value changes:\n\n```yaml\n# Database connection settings\ndatabase:\n  host: db.internal # default for dev\n  port: 5432\n```\n\n### Removing keys with explicit nulls\n\nSetting a key to `null` in the merged data removes it from the output:\n\n```bash\nupdate-yaml \u003c\u003c EO_INPUT \u003c(echo 'debug: null')\n---\nname: svc # this is a name of a service\n# debugging disabled\ndebug: false\nEO_INPUT\n```\n\nThis works at any depth and survives merging - a later data file can null out a key set by an earlier one.\n\n### Appending new keys\n\nKeys present in data but absent from the source are spliced in among the existing keys at the position they belong\nalphabetically. When the source mapping is empty (just being created), keys are appended in the order data declares\nthem, since there is no existing order to fit into:\n\n```bash\nupdate-yaml \u003c\u003c\u003c $'name: svc\\ndescription: desc' \u003c(echo $'version: 1.0\\ndescription: my service')\n```\n\nSet `UPDATE_YAML_PREFER_ORDER_PRESERVED` to switch to \"append in data order\" for non-empty mappings as well.\n\n### Sequence indent style is preserved\n\nYAML allows two block-sequence styles: items flush with the parent key, or indented one level deeper. The first style\nthe source uses (per file) is auto-detected and applied to existing sequences when their value is replaced. New\nsequences (added as part of a freshly-appended key) use the indented form, which is the more readable default.\n\n```yaml\n# flush style - preserved on replace\nitems:\n- a\n- b\n\n# indented style - also preserved on replace\nitems:\n  - a\n  - b\n```\n\n### Quote style is auto-detected\n\nThe first explicitly-quoted string in the source decides the preference for newly-emitted values that need quoting\n(numbers-as-strings, looks-like-booleans, etc.). Plain strings stay plain - quotes are never added to values that don't\nneed them. When replacing a quoted value with another value that also needs quoting, the original quote style is\npreserved; if the new value can render plain, it does, dropping unnecessary quotes the source had.\n\nSet `UPDATE_YAML_PREFER_SINGLE_QUOTE` to skip detection and always prefer single quotes.\n\n### Empty input is valid\n\nEmpty STDIN is a valid YAML stream containing zero documents. When data is provided, the data becomes the result. A\nsingle `---` marker on STDIN counts as one empty document; data is injected into it and the leading marker is kept.\nA `{}` flow-style mapping likewise accepts data, and the flow style is preserved in the output.\n\n```bash\nupdate-yaml \u003c\u003c\u003c ''    \u003c(echo 'foo: bar')   # → foo: bar\nupdate-yaml \u003c\u003c\u003c '---' \u003c(echo 'foo: bar')   # → ---\\nfoo: bar\nupdate-yaml \u003c\u003c\u003c '{}'  \u003c(echo 'foo: bar')   # → {foo: bar}\n```\n\n### Multi-document YAML\n\nIf the source STDIN contains multiple YAML documents (`---` separated), each is updated independently by the merged\ndata document at the same index. When data files are provided they must cover **every** STDIN doc; fewer data docs than\nSTDIN docs is an error. Extra data docs (beyond STDIN's count) are ignored.\n\n```bash\nupdate-yaml \u003c\u003c EO_INPUT \u003c(echo $'{\"debug\": null}\\n---\\n{\"size\": \"micro\",\"service\": {\"enabled\": false}}')\n---\nname: svc\ndebug: false\n---\nservice:\n  name: svc\n  enabled: true\nEO_INPUT\n```\n\n#### Targeting non-first STDIN docs\n\nA data file may target a non-first STDIN doc by including explicit empty placeholder docs at the front, in canonical\nYAML 1.2 stream form. Use `{}` (empty mapping) or `null` as the placeholder body for any doc that should not contribute\nupdates. Trailing `...` end markers are supported but optional.\n\nThe most compact form uses an inline placeholder:\n\n```yaml\n--- {}\n---\nreal: updates for the second doc in the input\n```\n\nRepeat the `--- {}` line to skip more leading docs. Files emitted by tools that produce canonical streams (e.g. `jaq\n--to yaml` or `yq -y`) also work as-is:\n\n```yaml\n---\n{}\n...\n---\nreal: updates for the second doc in the input\n...\n```\n\n## EXIT CODES\n\n- **0**: Success\n- **1**: Parse errors, invalid input, doc count mismatch, or other runtime errors\n\n## GOTCHAS\n\n### Consecutive `---` markers collapse into one document\n\nThe underlying YAML library (`github.com/goccy/go-yaml`) parses `---\\n---\\n` as a single document with implicit-null\nbody, not as two empty documents. If you need N empty documents in a stream, write them with explicit null (or empty\nmapping) bodies:\n\n```yaml\n--- null\n--- null\n```\n\nWhen data is provided for an index which is an explicit `null` or implicit-null `---\\n` body is treated as an empty\nmapping so the data can land in it. Slots with no data leave the `null` body intact, so unmodified placeholder docs\nsurvive.\n\n### Folded block scalars (`\u003e`) become literal (`|`) on replace\n\nWhen a value uses YAML's folded-style block scalar (`\u003e`, with or without `+`/`-` chomping indicators), and that key is\nmodified by data, the output uses the literal style (`|`) instead.\n\nReason: the underlying YAML library (`github.com/goccy/go-yaml`) exposes a `UseLiteralStyleIfMultiline` marshalling\noption but no folded-style analogue, so multi-line strings always render as literal blocks. Untouched docs pass through\nverbatim and are not affected; only the replaced value loses its folded style.\n\nIf preserving `\u003e` matters for a specific key, leave it untouched and put any related changes on different keys.\n\n## AUTHOR\n\n- Andrew Grechkin\n\n## LICENSE\n\nThis project is licensed under the GNU General Public License Version 2 (GPLv2).\nSee the `LICENSE` file for details.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrew-grechkin%2Fupdate-yaml","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fandrew-grechkin%2Fupdate-yaml","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fandrew-grechkin%2Fupdate-yaml/lists"}