private function commitInternal(Changes $changes, string $path = ''): void
    {
        $root = $this->getRoot();
        $rootpath = $root->path();

        if ($path) {
            $path .= '/';
        }

        $own = $changes->own();
        foreach ($own as $filename => $vEntity) {
            $filepath = $path.$filename;
            $rPath = $rootpath.'/'.$filepath;

            /* @var EntityAbstract|VirtualInterface $vEntity */
            $vExists = $vEntity->file_exists();
            $rDeleted = false;

            $rEntity = $vEntity;
            do {
                $rEntity = $rEntity->getRealEntity();
                $rDeleted = $rDeleted || !$rEntity->file_exists();
            } while ($rEntity instanceof VirtualInterface);

            $rExists = $rEntity->file_exists();
            if ($rExists && !$vExists) {
                $rDeleted = true;
            }

            if (!$vExists && !$rExists) {
                continue;
            } elseif ($rDeleted) {
                if ($rExists) {
                    $this->fs->remove($rPath);
                }
                if ($vExists) {
                    $this->copyChanges($filepath);
                }
            } else {
                if ($vEntity->is_file()) {
                    unlink($rPath);
                    copy($vEntity->path(), $rPath);
                }
            }
        }

        $subtrees = $changes->sublists();
        foreach ($subtrees as $filename => $tree) {
            if (!isset($own[$filename])) {
                $this->commitInternal($tree, $path.$filename);
            }
        }
    }