Skip to content

yaml merge

William W. Kimball, Jr., MBA, MSIS edited this page Sep 30, 2020 · 19 revisions
  1. Introduction
  2. Simple Example
    1. Whole File Merge
    2. Document Fragment Merge
    3. CLI-Supplied Data

Introduction

The yaml-merge command-line tool supports merging multiple YAML/Compatible files together. It also enables writing arbitrary simple or complex data to a YAML/Compatible document at any YAML Path, accepting such input from STDIN (the - pseudo-file), other compatible files, or both. The tool accepts 2 or more YAML_FILEs as input. Any one of them except the first (left-most) can be the - pseudo-file. Content is merged from the files, one at a time from right-to-left, into the first file's content. This is known as "RHS into LHS" merging (Right-Hand-Side content is merged into the Left-Hand-Side document). No files are changed by this process; merging is performed entirely in memory.

The yaml-merge tool defaults to writing its merged results to STDOUT. In order to direct the results to another file, you can set the --output (-o) argument, or redirect output using the operators specific to your operating system, like > and >>.

Not all merges are possible. There is no logical way to merge a Scalar or Array into a Hash without specifying a key to receive the new data (say, by using --mergeat/-m). Two documents with conflicting Anchors cannot be merged unless you select one of the --anchors (-a) options other than stop (the default). When an impossible merge condition is met, the tool will stop and emit an informative error message. Other conditions will be coallesced, like merging a Hash or Scalar into an Array will result in merely adding the new data as a new element of the Array.

With the --mergeat (-m) argument, you can direct all RHS content to one or more LHS destinations indicated via YAML Path. This enables users to merge together data fragments or even arbitrary data structure rather than premade, otherwise complete documents. Specifying a YAML Path which matches zero nodes however will result in an error message.

Simple Example

Document: LHS.yaml

---
deep:
  hash:
    structure:
      key: value

There are a few ways to change value to New Value. You could just use the yaml-set command rather than yaml-merge, like so: yaml-set --change=/deep/hash/structure/key --value='New Value' LHS.yaml

But what if you don't want LHS.yaml to be modified, or you want the changed document on STDOUT, say to feed into a subsequent piped command? This is where yaml-merge can help and there are multiple ways to solve these questions. These include:

  1. Whole file merge where the RHS document contains the minimum data structure necessary to indicate where with the LHS document its data is to be merged.
  2. File fragment merge where only the desired RHS data is written and a --mergeat (-m) indicates where within the LHS document this RHS data is to be merged.
  3. CLI-supplied merge data where only the desired RHS data is written in JSON or JSON-like form (JSON without all the quoting) and a --mergeat (-m) indicates where within the LHS document this RHS data is to be merged.

The following sections demonstrate all three approaches.

Whole File Merge

You could create a complete RHS document as an entirely new YAML file, like this:

Document: RHS-FULL.yaml

---
deep:
  hash:
    structure:
      key: New Value

To merge these two documents together, you'd simply execute: yaml-merge LHS.yaml RHS-FULL.yaml

While this would generate the desired outcome, far more complex LHS structures could be not only tedious, but also error-prone to build up a sufficient RHS document to affect the desired alteration.

Document Fragment Merge

You could supply a document fragment for the RHS, like so:

Document: RHS-FRAGMENT.yaml

---
key: New Value

To merge the fragment into the whole, execute: yaml-merge --mergeat=/deep/hash/structure LHS.yaml RHS-FRAGMENT.yaml

CLI-Supplied Data

You could spare all versions of the RHS file and instead use STDIN to emulate a yaml-set call via yaml-merge to get the same outcome: echo 'New Value' | yaml-merge --mergeat=/deep/hash/structure/key LHS.yaml -

Notice that only the actual Scalar data was provided in this case because for this example, we were only trying to change a single String value. You could provide the key-value pair of the destination and shorten the merge target path, like so: echo '{key: New Value}' | yaml-merge --mergeat=/deep/hash/structure LHS.yaml -

And naturally, any amount of the RHS can be provided as long as the supplied YAML Path places it precisely where you want it to be merged. For example:

echo '{structure: {key: New Value}}' | \
  yaml-merge --mergeat=/deep/hash LHS.yaml -`

And so on.

Clone this wiki locally