Skip to content

yaml merge Hash Options

William W. Kimball, Jr., MBA, MSIS edited this page Oct 1, 2020 · 7 revisions
  1. Introduction
  2. Deep Merges
  3. Overwrite LHS Hashes
  4. Configuration File Options
    1. Configuration File Section: defaults
    2. Configuration File Section: rules

This document is part of the body of knowledge about yaml-merge, one of the reference command-line tools provided by the YAML Path project.

Introduction

The yaml-merge command-line tool enables users to control how it merges Hashes (AKA Maps or Dictionaries). By default, Hashes are deeply merged together with data from the RHS document overriding data in the LHS document wherever both Hashes share structure. Any additional structure in the RHS Hashes is added to the LHS Hashes. The available Hash merge options include:

  1. deep (the default) as described above, every data element in RHS Hashes is merged into LHS Hashes at the same locations.
  2. left causes RHS Hashes to be discarded when a Hash already exists at the same location with the LHS document.
  3. right causes RHS Hashes to entirely overwrite LHS Hashes at the same location.

Each of these options will be explored in the following sections. All sections will use these two documents for their discussions:

File: LHS.yaml

---
hash:
  structure:
    with:
      several: levels
    and:
      data: keys
  even: more
lhs_exclusive:
  key: value

File: RHS.yaml

---
hash:
  structure:
    with:
      several: leaves
      having: data
  more: structure
  even: less
rhs_exclusive:
  another_key: another value

Deep Merges

In most cases, this is the preferred merge mode for Hashes. For Hashes in the merge documents, these rules apply:

  1. A Hash in the RHS document but not in the LHS document is added to LHS.
  2. A Hash in the LHS document but not in the RHS document remains as-is.
  3. A Hash in both documents is recursively traversed in the RHS document. Any leaf nodes also in LHS are overwritten with RHS data. Any nodes not in LHS are appended to the LHS Hash. Non-Hash leaves in both Hashes are merged according to their own type-specific merge rules.

When the two example documents are merged with --hashes=deep or -H deep, the resulting document becomes:

---
hash:
  structure:
    with:
      several: leaves
      having: data
    and:
      data: keys
  even: less
  more: structure
lhs_exclusive:
  key: value
rhs_exclusive:
  another_key: another value

Block RHS Hashes

If ever you need to prohibit Hashes in RHS documents from merging -- at all -- with LHS Hashes but you want novel Hashes to be added from the RHS document into the LHS document, set --hashes=left or -H left. Using the sample documents, this results in the following merged document:

---
hash:
  structure:
    with:
      several: levels
    and:
      data: keys
  even: more
lhs_exclusive:
  key: value
rhs_exclusive:
  another_key: another value

Notice that the hash Hash -- which is in both documents at the same location -- is in no way altered during the merge. However, the novel RHS Hash, rhs_exclusive was appended to the LHS document.

Overwrite LHS Hashes

Should you need to completely replace LHS Hashes with their RHS counterparts -- with no merging between them -- set --hashes=right or -H right. Using the sample documents, you would generate this result:

---
hash:
  structure:
    with:
      several: leaves
      having: data
  more: structure
  even: less
lhs_exclusive:
  key: value
rhs_exclusive:
  another_key: another value

Notice that the hash Hash -- which is in both documents at the same location -- was entirely replaced by the same Hash from the RHS document. Even original nodes from the LHS Hash not present in the RHS Hash were dropped. However, because there is no root-level lhs_exclusive Hash in the RHS document, it survives the merge.

Configuration File Options

The yaml-merge tool can read per YAML Path merging options from an INI-Style configuration file via its --config (-c) argument. Whereas the --hashes (-H) argument supplies an overarching mode for merging Hashes, using a configuration file permits far more precise control whenever you need a different mode for specific parts of the merge documents.

Configuration File Section: defaults

The [defaults] section permits a key named, hashes, which behaves identically to the --hashes (-H) command-line argument to the yaml-merge tool. The [defaults]hashes setting is overridden by the same-named command-line argument, when supplied. In practice, this file may look like:

File merge-options.ini

[defaults]
hashes = deep

Note the spaces around the = sign are optional but only an = sign may be used to separate each key from its value.

Configuration File Section: rules

The [rules] section takes any YAML Paths as keys and any of the Hash merge modes that are available to the --hashes (-H) command-line argument. This enables extremely fine precision for applying the available modes.

To demonstrate, add this config.ini file along with the sample documents from above:

[rules]
hash.structure.with.several = left
/hash/even = left

All together, the command to execute would become yaml-merge --config=config.ini LHS.yaml RHS.yaml and the merge output becomes:

---
hash:
  structure:
    with:
      several: levels
      having: data
    and:
      data: keys
  even: more
  more: structure
lhs_exclusive:
  key: value
rhs_exclusive:
  another_key: another value

Notice:

  1. This overrode the default merge mode of deep for exactly two Hash nodes. Overall, a deep merge was still performed.
  2. The hash.structure.with.several node became levels from the LHS document rather than leaves from the RHS document.
  3. The /hash/even node similarly became more rather than less.

Any nodes can be targeted with the YAML Paths set in [rules]. Be sure to specify a correct merge mode for the type of every node that is selected. In other words, don't try to set an Array or Array-of-Hashes exclusive mode to a Hash node. Setting incompatible merge rules will result in an error and cancellation of the merge.

Clone this wiki locally