def object_merge(
    old: Any,
    new: Any,
    unique: bool = False,
    full_path: list[str] = None,
    list_merge: Literal["merge", "shallow", "deep"] = "merge",
) -> Any:
    """
    Recursively merge two data structures, new is mutated in-place.

    :param old: The existing data.
    :param new: The new data to get old values merged in to.
    :param unique: When set to True existing list items are not set.
    :param full_path: Indicates the elements of a tree.
    :param list_merge: Methods to use to merge lists
        - merge: default merge behavior, i.e. (unique) concatenation
        - shallow: replace the top-most level list of the nested structure
        - deep: iteratively traverse the nested structure and replace
            the element in the list at the level specified by the full_path
    """
    if full_path is None:
        full_path = []
    if old == new or old is None or new is None:
        # Nothing to merge
        return new

    if isinstance(old, list) and isinstance(new, list):
        # 726: allow local_merge to override global merge on lists
        if "dynaconf_merge_unique" in new:
            new.remove("dynaconf_merge_unique")
            unique = True

        if list_merge == "merge" or unique:
            for item in old[::-1]:
                if unique and item in new:
                    continue
                new.insert(0, item)
        # replace mode
        # elif list_merge == "replace": pass
        elif len(full_path) > 0:  # element-wise merge
            new.extend([[]] * max(len(old) - len(new), 0))
            for ii, item in enumerate(old):
                # replace at corresponding positions
                if list_merge == "shallow":
                    new[ii] = new[ii] or item
                else:  # deep replace
                    if not new[ii]:  # copy over the older values
                        new[ii] = item
                    elif item:  # old[ii] is not None
                        object_merge(
                            old[ii],
                            new[ii],
                            full_path=full_path[1:],
                            list_merge="deep",
                        )

    if isinstance(old, dict) and isinstance(new, dict):
        existing_value = recursive_get(old, full_path)  # doesn't handle None
        # Need to make every `None` on `_store` to be an wrapped `LazyNone`

        # data coming from source, in `new` can be mix case: KEY4|key4|Key4
        # data existing on `old` object has the correct case: key4|KEY4|Key4
        # So we need to ensure that new keys matches the existing keys
        for new_key in list(new.keys()):
            correct_case_key = find_the_correct_casing(new_key, old)
            if correct_case_key:
                new[correct_case_key] = new.pop(new_key)

        def safe_items(data):
            """
            Get items from DynaBox without triggering recursive evaluation
            """
            if data.__class__.__name__ == "DynaBox":
                return data._safe_items()
            else:
                return data.items()

        # local mark may set dynaconf_merge=False
        should_merge = new.pop("dynaconf_merge", True)
        if should_merge:
            for old_key, value in safe_items(old):
                # This is for when the dict exists internally
                # but the new value on the end of full path is the same
                if (
                    existing_value is not None
                    and old_key.lower() == full_path[-1].lower()
                    and existing_value is value
                ):
                    # Here Be The Dragons
                    # This comparison needs to be smarter
                    continue

                if old_key not in new:
                    new[old_key] = value
                else:
                    new[old_key] = object_merge(
                        value,
                        new[old_key],
                        full_path=full_path[1:] if full_path else None,
                        list_merge=list_merge,
                    )
        handle_metavalues(old, new, list_merge=list_merge)

    return new

    Recursively merge two data structures, new is mutated in-place.

    :param old: The existing data.
    :param new: The new data to get old values merged in to.
    :param unique: When set to True existing list items are not set.
    :param full_path: Indicates the elements of a tree.
    :param list_merge: Methods to use to merge lists
        - merge: default merge behavior, i.e. (unique) concatenation
        - shallow: replace the top-most level list of the nested structure
        - deep: iteratively traverse the nested structure and replace
            the element in the list at the level specified by the full_path
    
dynaconf/utils/__init__.py