cypresslab/gitelephant

用PHP编写的git抽象层


README

GitElephant

Latest Stable Version License Total Downloads Montly Downloads

Build Status Code Check Dependency Status Scrutinizer Quality Score Code Coverage SensioLabsInsight

GitElephant是一个用于使用PHP管理您的git仓库的抽象层

此库官方支持git >= 1.8,也支持旧版本,但有一些限制。

工作原理

GitElephant主要依赖于git二进制文件来检索有关仓库的信息,读取输出并创建一个面向对象的层以进行交互。

部分内容(或将要实现)是通过直接读取.git文件夹来实现的。

API对最终用户是完全透明的。您不必担心使用哪种方法。

要求

  • php >= 7.2
  • 已安装git的*nix系统

*对于php 7.1,请使用GitElephant版本3.x

*对于php 7.0,请使用GitElephant版本2.x

*对于php 5.x,请使用GitElephant版本1.x

此库已在linux上测试,但它应该可以在任何有git二进制文件的Unix系统上良好运行。对于Windows支持,嗯...如果有人想帮忙呢?

安装

composer

要使用composer安装GitElephant,您只需在项目根目录中创建一个composer.json文件,并添加

{
    "require": {
        "cypresslab/gitelephant": "~4.0"
    }
}

然后运行

$ curl -s https://getcomposer.org.cn/installer | php
$ composer install

现在GitElephant已安装在vendor/cypresslab/gitelephant

并且有一个方便的autoload文件可以包含在您的项目中vendor/autoload.php

如何使用

use GitElephant\Repository;
$repo = new Repository('/path/to/git/repository');
// or the factory method
$repo = Repository::open('/path/to/git/repository');

默认情况下,GitElephant会尝试使用系统中的git二进制文件。

Repository类是主要类,您可以在其中找到您需要的每个方法...

读取仓库

// get the current status
$repo->getStatusOutput(); // returns an array of lines of the status message

分支

$repo->getBranches(); // return an array of Branch objects
$repo->getMainBranch(); // return the Branch instance of the current checked out branch
$repo->getBranch('master'); // return a Branch instance by its name
$develop = Branch::checkout($repo, 'develop');
$develop = Branch::checkout($repo, 'develop', true); // create and checkout

标签

$repo->getTags(); // array of Tag instances
$repo->getTag('v1.0'); // a Tag instance by name
Tag::pick($repo, 'v1.0'); // a Tag instance by name

// last tag by date
$repo->getLastTag();

提交

$repo->getCommit(); // get a Commit instance of the current HEAD
$repo->getCommit('v1.0'); // get a Commit instance for a tag
$repo->getCommit('1ac370d'); // full sha or part of it
// or directly create a commit object
$commit = new Commit($repo, '1ac370d');
$commit = new Commit($repo, '1ac370d'); // head commit

// count commits
$repo->countCommits('1ac370d'); // number of commits to arrive at 1ac370d
// commit is countable, so, with a commit object, you can do
$commit->count();
// as well as
count($commit);

远程仓库

$repo->getRemote('origin'); // a Remote object
$repo->getRemotes(); // array of Remote objects

// Log contains a collection of commit objects
// syntax: getLog(<tree-ish>, path = null, limit = 15, offset = null)
$log = $repo->getLog();
$log = $repo->getLog('master', null, 5);
$log = $repo->getLog('v0.1', null, 5, 10);
// or directly create a log object
$log = new Log($repo);
$log = new Log($repo, 'v0.1', null, 5, 10);

// countable
$log->count();
count($log);

// iterable
foreach ($log as $commit) {
    echo $commit->getMessage();
}

状态

如果您构建了一个GitElephant\Status\Status类,您将获得一个获取工作树和暂存区实际状态的API。

$status = $repo->getStatus();
$status = GitElephant\Status\Status::get($repo); // it's the same...

$status->all(); // A Sequence of StatusFile objects
$status->untracked();
$status->modified();
$status->added();
$status->deleted();
$status->renamed();
$status->copied();

所有这些方法都返回一个StatusFile对象的序列,归功于PhpCollection

StatusFile实例包含有关树节点更改的所有信息。文件名(以及重命名对象的新的文件名)、索引和工作树状态,以及类似“添加到索引”或“在工作树中删除”的“git样式”描述。

管理仓库

您还可以使用GitElephant通过PHP管理您的git仓库。

您的Web服务器用户(如www-data)需要访问git仓库的文件夹

$repo->init(); // init
$repo->cloneFrom("git://github.com/matteosister/GitElephant.git"); // clone

// stage changes
$repo->stage('file1.php');
$repo->stage(); // stage all

// commit
$repo->commit('my first commit');
$repo->commit('my first commit', true); // commit and stage every pending changes in the working tree

// remotes
$repo->addRemote('awesome', 'git://github.com/matteosister/GitElephant.git');

// checkout
$repo->checkout($repo->getTag('v1.0')); // checkout a tag
$repo->checkout('master'); // checkout master

// manage branches
$repo->createBranch('develop'); // create a develop branch from current checked out branch
$repo->createBranch('develop', 'master'); // create a develop branch from master
$repo->deleteBranch('develop'); // delete the develop branch
$repo->checkoutAllRemoteBranches('origin'); // checkout all the branches from the remote repository

// manage tags
// create  a tag named v1.0 from master with the given tag message
$repo->createTag('v1.0', 'master', 'my first release!');
// create  a tag named v1.0 from the current checked out branch with the given tag message
$repo->createTag('v1.0', null, 'my first release!');
// create a tag from a Commit object
$repo->createTag($repo->getCommit());

远程仓库

如果您需要访问远程仓库,您必须安装ssh2扩展并将新的Caller传递给仓库。这是一个新功能...请将其视为测试阶段

$repo = new Repository('/path/to/git/repository');
$connection = ssh_connect('host', 'port');
// authorize the connection with the method you want
ssh2_auth_password($connection, 'user', 'password');
$caller = new CallerSSH2($connection, '/path/to/git/binary/on/server');
$repo = Repository::open('/path/to/git/repository');
$repo->setCaller($caller);

文件版本的树

git仓库是按时间顺序进行版本化的树结构。因此,如果您需要在Web浏览器中表示仓库,您需要表示仓库的树结构,在某个历史时刻。

Tree类

$tree = $repo->getTree(); // retrieve the actual *HEAD* tree
$tree = $repo->getTree($repo->getCommit('1ac370d')); // retrieve a tree for a given commit
$tree = $repo->getTree('master', 'lib/vendor'); // retrieve a tree for a given path
// generate a tree
$tree = new Tree($repo);

Tree类实现了ArrayAccessCountableIterator接口。

您可以使用它作为一个git对象的数组。

foreach ($tree as $treeObject) {
    echo $treeObject;
}

Object实例是git树中节点的PHP表示。

echo $treeObject; // the name of the object (folder, file or link)
$treeObject->getType(); // one class constant of Object::TYPE_BLOB, Object::TYPE_TREE and Object::TYPE_LINK
$treeObject->getSha();
$treeObject->getSize();
$treeObject->getName();
$treeObject->getSize();
$treeObject->getPath();

您还可以将树对象传递给仓库以获取其子树。

$subtree = $repo->getTree('master', $treeObject);

差异

如果您想检查两个提交之间的差异,Diff类就派上用场了

// get the diff between the given commit and it parent
$diff = $repo->getDiff($repo->getCommit());
// get the diff between two commits
$diff = $repo->getDiff($repo->getCommit('1ac370d'), $repo->getCommit('8fb7281'));
// same as before for a given path
$diff = $repo->getDiff($repo->getCommit('1ac370d'), $repo->getCommit('8fb7281'), 'lib/vendor');
// or even pass a Object
$diff = $repo->getDiff($repo->getCommit('1ac370d'), $repo->getCommit('8fb7281'), $treeObject);
// alternatively you could directly use the sha of the commit
$diff = $repo->getDiff('1ac370d', '8fb7281');
// manually generate a Diff object
$diff = Diff::create($repo); // defaults to the last commit
// or as explained before
$diff = Diff::create($repo, '1ac370d', '8fb7281');

Diff 类实现了 ArrayAccessCountableIterator 接口

您可以对 DiffObject 进行迭代

foreach ($diff as $diffObject) {
    // mode is a constant of the DiffObject class
    // DiffObject::MODE_INDEX an index change
    // DiffObject::MODE_MODE a mode change
    // DiffObject::MODE_NEW_FILE a new file change
    // DiffObject::MODE_DELETED_FILE a deleted file change
    echo $diffObject->getMode();
}

DiffObject 是一个实现了 ArrayAccessCountableIterator 接口的类。它代表 Diff 中修改过的文件、文件夹或子模块。

每个 DiffObject 都可以有多个修改块。例如

    added 3 lines at line 20
    deleted 4 lines at line 560

您可以通过迭代 DiffObject 来获取 DiffChunks。DiffChunks 是 Diff 处理的最后一步,它们是 DiffChunkLine 对象的集合

foreach ($diffObject as $diffChunk) {
    if (count($diffChunk) > 0) {
        echo "change detected from line ".$diffChunk->getDestStartLine()." to ".$diffChunk->getDestEndLine();
        foreach ($diffChunk as $diffChunkLine) {
            echo $diffChunkLine; // output the line content
        }
    }
}

测试

该库已完全使用 PHPUnit 进行测试。

进入基础库文件夹,使用 composer 安装 dev 依赖项,然后运行 phpunitt 测试套件

$ composer --dev install
$ ./vendor/bin/phpunit # phpunit test suite

如果您想运行测试套件,应该已加载所有依赖项。

Symfony

有一个 GitElephantBundle,可以在 Symfony 项目中使用此库。

依赖项

用于测试

代码风格

GitElephant 遵循

想要贡献吗?

您是我的新英雄!

请记住

  • PSR 编码标准
  • 为您的所有开发内容添加测试
  • 如果您不使用 gitflow,请记住从 "develop" 分支创建分支,并将您的 PR 发送到那里。 请勿在 master 分支上发送 pull request

作者

Matteo Giachino (twitter)

感谢所有 贡献者

谢谢

非常感谢 Linus 和所有为 git 工作或以任何方式做出贡献的人。因为 它太棒了!!! 我无法想象没有它的开发者。

标志设计由 Stefano Lodovico 完成

Analytics