teqneers/php-stream-wrapper-for-git

PHP 的 Git 流包装器

v3.0.0 2023-04-24 08:40 UTC

This package is auto-updated.

Last update: 2024-09-24 12:00:10 UTC


README

PHP Testing

PHP 的 Git 流包装器 是一个 PHP 库,允许 PHP 代码在应用程序内部与一个或多个 Git 仓库进行交互。该库包含一个 Git 仓库抽象,可用于以编程方式访问 Git 仓库,以及一个可以钩入 PHP 流基础设施的流包装器,允许开发者直接在 Git 仓库中的文件上使用文件和目录访问函数。此外,该库还提供访问 Git 仓库状态信息的方法,例如日志、当前仓库状态或提交信息。

PHP 的 Git 流包装器 的核心是对 Git 命令行二进制的包装,因此需要在运行 PHP 代码的机器上安装 Git。 PHP 的 Git 流包装器 不包含 Git 协议抽象,它依赖于 Git 命令行二进制的所有功能。

代码目前运行稳定(请参阅以下 Windows 的评论),应该是 API 稳定的。然而,它不是功能完整的 - 因此,请随时提出您所需的功能。

示例

使用仓库抽象

use TQ\Git\Repository\Repository;
// open an already initialized repository
$git = Repository::open('/path/to/your/repository', '/usr/bin/git');

// open repository and create path and init repository if necessary
$git = Repository::open('/path/to/your/repository', '/usr/bin/git', 0755);

// get current branch
$branch = $git->getCurrentBranch();

// get status of working directory
$status = $git->getStatus();
// are there uncommitted changes in the staging area or in the working directory
$isDirty = $git->isDirty();

// retrieve the commit log limited to $limit entries skipping the first $skip
$log = $git->getLog($limit, $skip);

// retrieve the second to last commit
$commit = $git->showCommit('HEAD^');

// list the directory contents two commits before
$list  = $git->listDirectory('.', 'HEAD^^');

// show contents of file $file at commit abcd123...
$contents = $git->showFile($file, 'abcd123');

// write a file and commit the changes
$commit = $git->writeFile('test.txt', 'Test', 'Added test.txt');

// remove multiple files
$commit = $git->removeFile('file_*', 'Removed all files not needed any more');

// rename a file
$commit = $c->renameFile('test.txt', 'test.txt-old', 'Made a backup copy');

// do some file operations and commit all changes at once
$result = $git->transactional(function(TQ\Vcs\Repository\Transaction $t) {
    file_put_contents($t->getRepositoryPath().'/text1.txt', 'Test 1');
    file_put_contents($t->getRepositoryPath().'/text2.txt', 'Test 2');

    unlink($t->resolvePath('old.txt'));
    rename($t->resolvePath('to_keep.txt'), $t->resolvePath('test3.txt'));

    $t->setCommitMsg('Don\'t know what to write here');

    // if we throw an exception from within the callback the changes are discarded
    // throw new Exception('No we don\'t want to make these changes');
    // note: the exception will be re-thrown by the repository so you have to catch
    // the exception yourself outside the transactional scope.
});

使用流包装器

use TQ\Git\StreamWrapper\StreamWrapper;

// register the wrapper
StreamWrapper::register('git', '/usr/bin/git');

// read the contents of a file
$content = file_get_contents('git:///path/to/your/repository/file_0.txt');

// show contents of a file at commit abcd123...
$content = file_get_contents('git:///path/to/your/repository/file_0.txt#abcd123');

// show contents of a file two commits before
$content = file_get_contents('git:///path/to/your/repository/file_0.txt#HEAD^^');

// show the directory information two commits before
$directory = file_get_contents('git:///path/to/your/repository/#HEAD^^');

// list directory contents two commits before
$dir = opendir('git:///path/to/your/repository/subdir#HEAD^^');
while ($f = readdir($dir)) {
    echo $f.PHP_EOL;
}
closedir($dir);

// recursively traverse the repository two commits before
$dir = new RecursiveDirectoryIterator('git:///path/to/your/repository#HEAD^^');
$it  = new RecursiveIteratorIterator($dir, RecursiveIteratorIterator::SELF_FIRST);
foreach ($it as $fileInfo) {
    echo str_repeat(' ', $it->getDepth() * 3).$fileInfo->getFilename().PHP_EOL;
}

// retrieve the second to last commit
$commit = file_get_contents('git:///path/to/your/repository?commit&ref=HEAD^^');

// retrieve the commit log limited to 5entries skipping the first 2
$log = file_get_contents('git:///path/to/your/repository?log&limit=5&skip=2');

// remove a file - change is committed to the repository
unlink('git:///path/to/your/repository/file_to_delete.txt');

// rename a file - change is committed to the repository
rename('git:///path/to/your/repository/old.txt', 'git:///path/to/your/repository/new.txt');

// remove a directory - change is committed to the repository
rmdir('git:///path/to/your/repository/directory_to_delete');

// create a directory - change is committed to the repository
// this creates a .gitkeep file in new_directory because Git does not track directories
mkdir('git:///path/to/your/repository/new_directory');

// write to a file - change is committed to the repository when file is closed
$file = fopen('git:///path/to/your/repository/test.txt', 'w');
fwrite($file, 'Test');
fclose($file);

// support for stream context
$context = stream_context_create(array(
    'git'   => array(
        'commitMsg' => 'Hello World',
        'author'    => 'Luke Skywalker <skywalker@deathstar.com>'
    )
));
$file = fopen('git:///path/to/your/repository/test.txt', 'w', false, $context);
fwrite($file, 'Test');
fclose($file); // file gets committed with the preset commit message and author

// append to a file using file_put_contents using a custom author and commit message
$context = stream_context_create(array(
    'git'   => array(
        'commitMsg' => 'Hello World',
        'author'    => 'Luke Skywalker <skywalker@deathstar.com>'
    )
));
file_put_contents('git:///path/to/your/repository/test.txt', 'Test', FILE_APPEND, $context);

// it is now possible to register repository-specific paths on the stream wrapper
StreamWrapper::getRepositoryRegistry()->addRepositories(
    array(
        'repo1' => Repository::open('/path/to/repository/1', '/usr/bin/git', false),
        'repo2' => Repository::open('/path/to/repository/2', '/usr/bin/git', false),
    )
);
$content1 = file_get_contents('git://repo1/file_0.txt');
$content2 = file_get_contents('git://repo2/file_0.txt');

// unregister the wrapper if needed
StreamWrapper::unregister();

要求

  • PHP >= 8.0.0
  • Composer 可用于包含依赖项
  • 在运行 PHP 代码的机器上安装 Git
  • 如果想要使用 SVN 组件,请在运行 PHP 代码的机器上安装 SVN

运行测试

  1. 克隆仓库
  2. 运行 composer install 安装依赖项并创建自动加载器
  3. phpunit.xml.dist 复制到 phpunit.xml
  4. phpunit.xml 中将 GIT_BINARYSVN_BINARYSVN_ADMIN_BINARY 常量调整为您的 Git 二进制文件路径
  5. 从克隆的项目文件夹中运行 phpunit

请注意,该库已在 Mac OS X 12.6 上与捆绑的 PHP 8.0.27、8.1.14 和 8.2.1(git 版本 2.39.1)以及多个 Ubuntu Linux 安装上进行了测试。由于目前未知的原因,Windows 上的测试运行有些不稳定。所有测试都应该显示 绿色,但在清理过程中,可能会出现某些随机访问限制,阻止清理代码删除测试目录。

单元测试套件正在通过 GitHub Actions 在 PHP 8.0、8.1、8.2 和 8.3 上进行持续测试,其当前状态为:Build Status

贡献

请随时使用 Git 问题跟踪来报告任何问题或错误。如果您想积极地为库的开发做出贡献,鼓励您克隆仓库并发送 pull requests。

许可

版权 (C) 2023 由 TEQneers GmbH & Co. KG 所有权

特此授予任何人免费获得此软件及其相关文档文件(以下简称“软件”)的副本的权利,允许在不作任何限制的情况下处理该软件,包括但不限于使用、复制、修改、合并、发布、分发、再许可和/或销售软件的副本,并允许向获得软件的人提供软件,前提是遵守以下条件

上述版权声明和本许可声明应包含在软件的所有副本或主要部分中。

软件按“原样”提供,不提供任何形式的保证,无论是明示的、暗示的还是与特定目的适用性或非侵权有关的保证。在任何情况下,作者或版权所有者不对任何索赔、损害或其他责任负责,无论这些责任源于合同行为、侵权或其他,无论这些责任是否与软件或其使用或其它操作有关。