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);
            }
        }
    }
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);
            }
        }
    }
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 ) ; } } }
Commit changes into real FS.

Если удалено и не существовало с самого начала
- ничего не делаем
Иначе если когда-то не существовало
- удаляем всё RДерево
- Если сейчас существует, то
- переносим всё VДерево
Иначе если это файл, то
- удаляем RФайл
- копируем VФайл на место RФайла

По всем subtree
- сделать тоже самое, если не было собственных изменений
Commit changes into real FS .