diff options
Diffstat (limited to 'library/kzykhys/git')
64 files changed, 7210 insertions, 0 deletions
diff --git a/library/kzykhys/git/.travis.yml b/library/kzykhys/git/.travis.yml new file mode 100644 index 000000000..ff4164104 --- /dev/null +++ b/library/kzykhys/git/.travis.yml @@ -0,0 +1,20 @@ +language: php + +php: + - 5.5 + - 5.4 + - 5.3 + +before_script: + - composer require --no-update satooshi/php-coveralls:dev-master@dev sensiolabs/security-checker:dev-master + - composer update --dev --no-interaction + - git config --global user.name "John Doe" + - git config --global user.email "example@example.com" + +script: + - mkdir -p build/logs + - phpunit -c phpunit.xml.dist --coverage-clover build/logs/clover.xml + - php vendor/bin/security-checker security:check composer.lock + +after_script: + - php vendor/bin/coveralls
\ No newline at end of file diff --git a/library/kzykhys/git/README.md b/library/kzykhys/git/README.md new file mode 100644 index 000000000..b2f6635af --- /dev/null +++ b/library/kzykhys/git/README.md @@ -0,0 +1,1347 @@ +PHPGit - A Git wrapper for PHP5.3+ +================================== + +[![Latest Unstable Version](https://poser.pugx.org/kzykhys/git/v/unstable.png)](https://packagist.org/packages/kzykhys/git) +[![Build Status](https://travis-ci.org/kzykhys/PHPGit.png?branch=master)](https://travis-ci.org/kzykhys/PHPGit) +[![Coverage Status](https://coveralls.io/repos/kzykhys/PHPGit/badge.png)](https://coveralls.io/r/kzykhys/PHPGit) +[![SensioLabsInsight](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f/mini.png)](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f) + +Requirements +------------ + +* PHP5.3 +* Git + +Installation +------------ + +Update your composer.json and run `composer update` + +``` json +{ + "require": { + "kzykhys/git": "dev-master" + } +} +``` + +Basic Usage +----------- + +``` php +<?php + +require __DIR__ . '/vendor/autoload.php'; + +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); +$git->setRepository('/path/to/repo'); +$git->remote->add('production', 'git://example.com/your/repo.git'); +$git->add('README.md'); +$git->commit('Adds README.md'); +$git->checkout('release'); +$git->merge('master'); +$git->push(); +$git->push('production', 'release'); +$git->tag->create('v1.0.1', 'release'); + +foreach ($git->tree('release') as $object) { + if ($object['type'] == 'blob') { + echo $git->show($object['file']); + } +} +``` + +API +--- + +### Git commands + +* [git add](#git-add) + * $git->[add](#git-addstringarraytraversable-file-array-options--)(_string|array|\Traversable_ $file, _array_ $options = []) +* [git archive](#git-archive) + * $git->[archive](#git-archivestring-file-string-tree--null-stringarraytraversable-path--null-array-options--)(_string_ $file, _string_ $tree = null, _string|array|\Traversable_ $path = null, _array_ $options = []) +* [git branch](#git-branch) + * $git->[branch](#git-brancharray-options--)(_array_ $options = []) + * $git->branch->[create](#git-branch-createstring-branch-string-startpoint--null-array-options--)(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) + * $git->branch->[move](#git-branch-movestring-branch-string-newbranch-array-options--)(_string_ $branch, _string_ $newBranch, _array_ $options = []) + * $git->branch->[delete](#git-branch-deletestring-branch-array-options--)(_string_ $branch, _array_ $options = []) +* [git cat-file](#git-cat-file) + * $git->cat->[blob](#git-cat-blobstring-object)(_string_ $object) + * $git->cat->[type](#git-cat-typestring-object)(_string_ $object) + * $git->cat->[size](#git-cat-sizestring-object)(_string_ $object) +* [git checkout](#git-checkout) + * $git->[checkout](#git-checkoutstring-branch-array-options--)(_string_ $branch, _array_ $options = []) + * $git->checkout->[create](#git-checkout-createstring-branch-string-startpoint--null-array-options--)(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) + * $git->checkout->[orphan](#git-checkout-orphanstring-branch-string-startpoint--null-array-options--)(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) +* [git clone](#git-clone) + * $git->[clone](#git-clonestring-repository-string-path--null-array-options--)(_string_ $repository, _string_ $path = null, _array_ $options = []) +* [git commit](#git-commit) + * $git->[commit](#git-commitstring-message-array-options--)(_string_ $message, _array_ $options = []) +* [git config](#git-config) + * $git->[config](#git-configarray-options--)(_array_ $options = []) + * $git->config->[set](#git-config-setstring-name-string-value-array-options--)(_string_ $name, _string_ $value, _array_ $options = []) + * $git->config->[add](#git-config-addstring-name-string-value-array-options--)(_string_ $name, _string_ $value, _array_ $options = []) +* [git describe](#git-describe) + * $git->[describe](#git-describestring-committish--null-array-options--)(_string_ $committish = null, _array_ $options = []) + * $git->describe->[tags](#git-describe-tagsstring-committish--null-array-options--)(_string_ $committish = null, _array_ $options = []) +* [git fetch](#git-fetch) + * $git->[fetch](#git-fetchstring-repository-string-refspec--null-array-options--)(_string_ $repository, _string_ $refspec = null, _array_ $options = []) + * $git->fetch->[all](#git-fetch-allarray-options--)(_array_ $options = []) +* [git init](#git-init) + * $git->[init](#git-initstring-path-array-options--)(_string_ $path, _array_ $options = []) +* [git log](#git-log) + * $git->[log](#git-logstring-revrange---string-path--null-array-options--)(_string_ $revRange = '', _string_ $path = null, _array_ $options = []) +* [git merge](#git-merge) + * $git->[merge](#git-mergestringarraytraversable-commit-string-message--null-array-options--)(_string|array|\Traversable_ $commit, _string_ $message = null, _array_ $options = []) + * $git->merge->[abort](#git-merge-abort)() +* [git mv](#git-mv) + * $git->[mv](#git-mvstringarrayiterator-source-string-destination-array-options--)(_string|array|\Iterator_ $source, _string_ $destination, _array_ $options = []) +* [git pull](#git-pull) + * $git->[pull](#git-pullstring-repository--null-string-refspec--null-array-options--)(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) +* [git push](#git-push) + * $git->[push](#git-pushstring-repository--null-string-refspec--null-array-options--)(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) +* [git rebase](#git-rebase) + * $git->[rebase](#git-rebasestring-upstream--null-string-branch--null-array-options--)(_string_ $upstream = null, _string_ $branch = null, _array_ $options = []) + * $git->rebase->[continues](#git-rebase-continues)() + * $git->rebase->[abort](#git-rebase-abort)() + * $git->rebase->[skip](#git-rebase-skip)() +* [git remote](#git-remote) + * $git->[remote](#git-remote)() + * $git->remote->[add](#git-remote-addstring-name-string-url-array-options--)(_string_ $name, _string_ $url, _array_ $options = []) + * $git->remote->[rename](#git-remote-renamestring-name-string-newname)(_string_ $name, _string_ $newName) + * $git->remote->[rm](#git-remote-rmstring-name)(_string_ $name) + * $git->remote->[show](#git-remote-showstring-name)(_string_ $name) + * $git->remote->[prune](#git-remote-prunestring-name--null)(_string_ $name = null) + * $git->remote->[head](#git-remote-headstring-name-string-branch--null)(_string_ $name, _string_ $branch = null) + * $git->remote->head->[set](#git-remote-head-setstring-name-string-branch)(_string_ $name, _string_ $branch) + * $git->remote->head->[delete](#git-remote-head-deletestring-name)(_string_ $name) + * $git->remote->head->[remote](#git-remote-head-remotestring-name)(_string_ $name) + * $git->remote->[branches](#git-remote-branchesstring-name-array-branches)(_string_ $name, _array_ $branches) + * $git->remote->branches->[set](#git-remote-branches-setstring-name-array-branches)(_string_ $name, _array_ $branches) + * $git->remote->branches->[add](#git-remote-branches-addstring-name-array-branches)(_string_ $name, _array_ $branches) + * $git->remote->[url](#git-remote-urlstring-name-string-newurl-string-oldurl--null-array-options--)(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) + * $git->remote->url->[set](#git-remote-url-setstring-name-string-newurl-string-oldurl--null-array-options--)(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) + * $git->remote->url->[add](#git-remote-url-addstring-name-string-newurl-array-options--)(_string_ $name, _string_ $newUrl, _array_ $options = []) + * $git->remote->url->[delete](#git-remote-url-deletestring-name-string-url-array-options--)(_string_ $name, _string_ $url, _array_ $options = []) +* [git reset](#git-reset) + * $git->[reset](#git-resetstringarraytraversable-paths-string-commit--null)(_string|array|\Traversable_ $paths, _string_ $commit = null) + * $git->reset->[soft](#git-reset-softstring-commit--null)(_string_ $commit = null) + * $git->reset->[mixed](#git-reset-mixedstring-commit--null)(_string_ $commit = null) + * $git->reset->[hard](#git-reset-hardstring-commit--null)(_string_ $commit = null) + * $git->reset->[merge](#git-reset-mergestring-commit--null)(_string_ $commit = null) + * $git->reset->[keep](#git-reset-keepstring-commit--null)(_string_ $commit = null) + * $git->reset->[mode](#git-reset-modestring-mode-string-commit--null)(_string_ $mode, _string_ $commit = null) +* [git rm](#git-rm) + * $git->[rm](#git-rmstringarraytraversable-file-array-options--)(_string|array|\Traversable_ $file, _array_ $options = []) + * $git->rm->[cached](#git-rm-cachedstringarraytraversable-file-array-options--)(_string|array|\Traversable_ $file, _array_ $options = []) +* [git shortlog](#git-shortlog) + * $git->[shortlog](#git-shortlogstringarraytraversable-commits--head)(_string|array|\Traversable_ $commits = HEAD) + * $git->shortlog->[summary](#git-shortlog-summarystring-commits--head)(_string_ $commits = HEAD) +* [git show](#git-show) + * $git->[show](#git-showstring-object-array-options--)(_string_ $object, _array_ $options = []) +* [git stash](#git-stash) + * $git->[stash](#git-stash)() + * $git->stash->[save](#git-stash-savestring-message--null-array-options--)(_string_ $message = null, _array_ $options = []) + * $git->stash->[lists](#git-stash-listsarray-options--)(_array_ $options = []) + * $git->stash->[show](#git-stash-showstring-stash--null)(_string_ $stash = null) + * $git->stash->[drop](#git-stash-dropstring-stash--null)(_string_ $stash = null) + * $git->stash->[pop](#git-stash-popstring-stash--null-array-options--)(_string_ $stash = null, _array_ $options = []) + * $git->stash->[apply](#git-stash-applystring-stash--null-array-options--)(_string_ $stash = null, _array_ $options = []) + * $git->stash->[branch](#git-stash-branchstring-name-string-stash--null)(_string_ $name, _string_ $stash = null) + * $git->stash->[clear](#git-stash-clear)() + * $git->stash->[create](#git-stash-create)() +* [git status](#git-status) + * $git->[status](#git-statusarray-options--)(_array_ $options = []) +* [git tag](#git-tag) + * $git->[tag](#git-tag)() + * $git->tag->[create](#git-tag-createstring-tag-string-commit--null-array-options--)(_string_ $tag, _string_ $commit = null, _array_ $options = []) + * $git->tag->[delete](#git-tag-deletestringarraytraversable-tag)(_string|array|\Traversable_ $tag) + * $git->tag->[verify](#git-tag-verifystringarraytraversable-tag)(_string|array|\Traversable_ $tag) +* [git ls-tree](#git-ls-tree) + * $git->[tree](#git-treestring-branch--master-string-path--)(_string_ $branch = master, _string_ $path = '') + +* * * * * + +### git add + +#### $git->add(_string|array|\Traversable_ $file, _array_ $options = []) + +Add file contents to the index + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->add('file.txt'); +$git->add('file.txt', ['force' => false, 'ignore-errors' => false); +``` + +##### Options + +- **force** (_boolean_) Allow adding otherwise ignored files +- **ignore-errors** (_boolean_) Do not abort the operation + +* * * * * + +### git archive + +#### $git->archive(_string_ $file, _string_ $tree = null, _string|array|\Traversable_ $path = null, _array_ $options = []) + +Create an archive of files from a named tree + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->archive('repo.zip', 'master', null, ['format' => 'zip']); +``` + +##### Options + +- **format** (_boolean_) Format of the resulting archive: tar or zip +- **prefix** (_boolean_) Prepend prefix/ to each filename in the archive + +* * * * * + +### git branch + +#### $git->branch(_array_ $options = []) + +Returns an array of both remote-tracking branches and local branches + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$branches = $git->branch(); +``` + +##### Output Example + +``` +[ + 'master' => ['current' => true, 'name' => 'master', 'hash' => 'bf231bb', 'title' => 'Initial Commit'], + 'origin/master' => ['current' => false, 'name' => 'origin/master', 'alias' => 'remotes/origin/master'] +] +``` + +##### Options + +- **all** (_boolean_) List both remote-tracking branches and local branches +- **remotes** (_boolean_) List the remote-tracking branches + +#### $git->branch->create(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) + +Creates a new branch head named **$branch** which points to the current HEAD, or **$startPoint** if given + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->branch->create('bugfix'); // from current HEAD +$git->branch->create('patch-1', 'a092bf7s'); // from commit +$git->branch->create('1.0.x-fix', 'v1.0.2'); // from tag +``` + +##### Options + +- **force** (_boolean_) Reset **$branch** to **$startPoint** if **$branch** exists already + +#### $git->branch->move(_string_ $branch, _string_ $newBranch, _array_ $options = []) + +Move/rename a branch and the corresponding reflog + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->branch->move('bugfix', '2.0'); +``` + +##### Options + +- **force** (_boolean_) Move/rename a branch even if the new branch name already exists + +#### $git->branch->delete(_string_ $branch, _array_ $options = []) + +Delete a branch + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->branch->delete('2.0'); +``` + +The branch must be fully merged in its upstream branch, or in HEAD if no upstream was set with --track or --set-upstream. + +##### Options + +- **force** (_boolean_) Delete a branch irrespective of its merged status + +* * * * * + +### git cat-file + +#### $git->cat->blob(_string_ $object) + +Returns the contents of blob object + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$contents = $git->cat->blob('e69de29bb2d1d6434b8b29ae775ad8'); +``` + +#### $git->cat->type(_string_ $object) + +Returns the object type identified by **$object** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$type = $git->cat->type('e69de29bb2d1d6434b8b29ae775ad8'); +``` + +#### $git->cat->size(_string_ $object) + +Returns the object size identified by **$object** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$type = $git->cat->size('e69de29bb2d1d6434b8b29ae775ad8'); +``` + +* * * * * + +### git checkout + +#### $git->checkout(_string_ $branch, _array_ $options = []) + +Switches branches by updating the index, working tree, and HEAD to reflect the specified branch or commit + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->checkout('develop'); +``` + +##### Options + +- **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD +- **merge** (_boolean_) Merges local modification + +#### $git->checkout->create(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) + +Create a new branch and checkout + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->checkout->create('patch-1'); +$git->checkout->create('patch-2', 'develop'); +``` + +##### Options + +- **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD + +#### $git->checkout->orphan(_string_ $branch, _string_ $startPoint = null, _array_ $options = []) + +Create a new orphan branch, named <new_branch>, started from <start_point> and switch to it + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->checkout->orphan('gh-pages'); +``` + +##### Options + +- **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD + +* * * * * + +### git clone + +#### $git->clone(_string_ $repository, _string_ $path = null, _array_ $options = []) + +Clone a repository into a new directory + +``` php +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); +``` + +##### Options + +- **shared** (_boolean_) Starts out without any object of its own +- **bare** (_boolean_) Make a bare GIT repository + +* * * * * + +### git commit + +#### $git->commit(_string_ $message, _array_ $options = []) + +Record changes to the repository + +``` php +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); +$git->setRepository('/path/to/repo'); +$git->add('README.md'); +$git->commit('Fixes README.md'); +``` + +##### Options + +- **all** (_boolean_) Stage files that have been modified and deleted +- **reuse-message** (_string_) Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit +- **squash** (_string_) Construct a commit message for use with rebase --autosquash +- **author** (_string_) Override the commit author +- **date** (_string_) Override the author date used in the commit +- **cleanup** (_string_) Can be one of verbatim, whitespace, strip, and default +- **amend** (_boolean_) Used to amend the tip of the current branch + +* * * * * + +### git config + +#### $git->config(_array_ $options = []) + +Returns all variables set in config file + + +##### Options + +- **global** (_boolean_) Read or write configuration options for the current user +- **system** (_boolean_) Read or write configuration options for all users on the current machine + +#### $git->config->set(_string_ $name, _string_ $value, _array_ $options = []) + +Set an option + +##### Options + +- **global** (_boolean_) Read or write configuration options for the current user +- **system** (_boolean_) Read or write configuration options for all users on the current machine + +#### $git->config->add(_string_ $name, _string_ $value, _array_ $options = []) + +Adds a new line to the option without altering any existing values + +##### Options + +- **global** (_boolean_) Read or write configuration options for the current user +- **system** (_boolean_) Read or write configuration options for all users on the current machine + +* * * * * + +### git describe + +#### $git->describe(_string_ $committish = null, _array_ $options = []) + +Returns the most recent tag that is reachable from a commit + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->tag->create('v1.0.0'); +$git->commit('Fixes #14'); +echo $git->describe('HEAD', ['tags' => true]); +``` + +##### Output Example + +``` +v1.0.0-1-g7049efc +``` + +##### Options + +- **all** (_boolean_) Enables matching any known branch, remote-tracking branch, or lightweight tag +- **tags** (_boolean_) Enables matching a lightweight (non-annotated) tag +- **always** (_boolean_) Show uniquely abbreviated commit object as fallback + +#### $git->describe->tags(_string_ $committish = null, _array_ $options = []) + +Equivalent to $git->describe($committish, ['tags' => true]); + +* * * * * + +### git fetch + +#### $git->fetch(_string_ $repository, _string_ $refspec = null, _array_ $options = []) + +Fetches named heads or tags from one or more other repositories, along with the objects necessary to complete them + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'git://your/repo.git'); +$git->fetch('origin'); +``` + +##### Options + +- **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD +- **keep** (_boolean_) Keep downloaded pack +- **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote + +#### $git->fetch->all(_array_ $options = []) + +Fetch all remotes + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'git://your/repo.git'); +$git->remote->add('release', 'git://your/another_repo.git'); +$git->fetch->all(); +``` + +##### Options + +- **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD +- **keep** (_boolean_) Keep downloaded pack +- **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote + +* * * * * + +### git init + +#### $git->init(_string_ $path, _array_ $options = []) + +Create an empty git repository or reinitialize an existing one + +``` php +$git = new PHPGit\Git(); +$git->init('/path/to/repo1'); +$git->init('/path/to/repo2', array('shared' => true, 'bare' => true)); +``` + +##### Options + +- **shared** (_boolean_) Specify that the git repository is to be shared amongst several users +- **bare** (_boolean_) Create a bare repository + +* * * * * + +### git log + +#### $git->log(_string_ $revRange = '', _string_ $path = null, _array_ $options = []) + +Returns the commit logs + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$logs = $git->log(array('limit' => 10)); +``` + +##### Output Example + +``` php +[ + 0 => [ + 'hash' => '1a821f3f8483747fd045eb1f5a31c3cc3063b02b', + 'name' => 'John Doe', + 'email' => 'john@example.com', + 'date' => 'Fri Jan 17 16:32:49 2014 +0900', + 'title' => 'Initial Commit' + ], + 1 => [ + //... + ] +] +``` + +##### Options + +- **limit** (_integer_) Limits the number of commits to show +- **skip** (_integer_) Skip number commits before starting to show the commit output + +* * * * * + +### git merge + +#### $git->merge(_string|array|\Traversable_ $commit, _string_ $message = null, _array_ $options = []) + +Incorporates changes from the named commits into the current branch + +```php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->merge('1.0'); +$git->merge('1.1', 'Merge message', ['strategy' => 'ours']); +``` + +##### Options + +- **no-ff** (_boolean_) Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer +- **rerere-autoupdate** (_boolean_) Allow the rerere mechanism to update the index with the result of auto-conflict resolution if possible +- **squash** (_boolean_) Allows you to create a single commit on top of the current branch whose effect is the same as merging another branch +- **strategy** (_string_) Use the given merge strategy +- **strategy-option** (_string_) Pass merge strategy specific option through to the merge strategy + +#### $git->merge->abort() + +Abort the merge process and try to reconstruct the pre-merge state + +```php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +try { + $git->merge('dev'); +} catch (PHPGit\Exception\GitException $e) { + $git->merge->abort(); +} +``` + +* * * * * + +### git mv + +#### $git->mv(_string|array|\Iterator_ $source, _string_ $destination, _array_ $options = []) + +Move or rename a file, a directory, or a symlink + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->mv('UPGRADE-1.0.md', 'UPGRADE-1.1.md'); +``` + +##### Options + +- **force** (_boolean_) Force renaming or moving of a file even if the target exists + +* * * * * + +### git pull + +#### $git->pull(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) + +Fetch from and merge with another repository or a local branch + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->pull('origin', 'master'); +``` + +* * * * * + +### git push + +#### $git->push(_string_ $repository = null, _string_ $refspec = null, _array_ $options = []) + +Update remote refs along with associated objects + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->push('origin', 'master'); +``` + +* * * * * + +### git rebase + +#### $git->rebase(_string_ $upstream = null, _string_ $branch = null, _array_ $options = []) + +Forward-port local commits to the updated upstream head + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->fetch('origin'); +$git->rebase('origin/master'); +``` + +##### Options + +- **onto** (_string_) Starting point at which to create the new commits +- **no-verify** (_boolean_) Bypasses the pre-rebase hook +- **force-rebase** (_boolean_) Force the rebase even if the current branch is a descendant of the commit you are rebasing onto + +#### $git->rebase->continues() + +Restart the rebasing process after having resolved a merge conflict + +#### $git->rebase->abort() + +Abort the rebase operation and reset HEAD to the original branch + +#### $git->rebase->skip() + +Restart the rebasing process by skipping the current patch + +* * * * * + +### git remote + +#### $git->remote() + +Returns an array of existing remotes + +``` php +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); +$git->setRepository('/path/to/repo'); +$remotes = $git->remote(); +``` + +##### Output Example + +``` php +[ + 'origin' => [ + 'fetch' => 'https://github.com/kzykhys/Text.git', + 'push' => 'https://github.com/kzykhys/Text.git' + ] +] +``` + +#### $git->remote->add(_string_ $name, _string_ $url, _array_ $options = []) + +Adds a remote named **$name** for the repository at **$url** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->fetch('origin'); +``` + +##### Options + +- **tags** (_boolean_) With this option, `git fetch <name>` imports every tag from the remote repository +- **no-tags** (_boolean_) With this option, `git fetch <name>` does not import tags from the remote repository + +#### $git->remote->rename(_string_ $name, _string_ $newName) + +Rename the remote named **$name** to **$newName** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->rename('origin', 'upstream'); +``` + +#### $git->remote->rm(_string_ $name) + +Remove the remote named **$name** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->rm('origin'); +``` + +#### $git->remote->show(_string_ $name) + +Gives some information about the remote **$name** + +``` php +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); +$git->setRepository('/path/to/repo'); +echo $git->remote->show('origin'); +``` + +##### Output Example + +``` +\* remote origin + Fetch URL: https://github.com/kzykhys/Text.git + Push URL: https://github.com/kzykhys/Text.git + HEAD branch: master + Remote branch: + master tracked + Local branch configured for 'git pull': + master merges with remote master + Local ref configured for 'git push': + master pushes to master (up to date) +``` + +#### $git->remote->prune(_string_ $name = null) + +Deletes all stale remote-tracking branches under **$name** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->prune('origin'); +``` + +#### $git->remote->head(_string_ $name, _string_ $branch = null) + +Alias of set() + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->head('origin'); +``` + +#### $git->remote->head->set(_string_ $name, _string_ $branch) + +Sets the default branch for the named remote + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->head->set('origin'); +``` + +#### $git->remote->head->delete(_string_ $name) + +Deletes the default branch for the named remote + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->head->delete('origin'); +``` + +#### $git->remote->head->remote(_string_ $name) + +Determine the default branch by querying remote + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->head->remote('origin'); +``` + +#### $git->remote->branches(_string_ $name, _array_ $branches) + +Alias of set() + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->branches('origin', array('master', 'develop')); +``` + +#### $git->remote->branches->set(_string_ $name, _array_ $branches) + +Changes the list of branches tracked by the named remote + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->branches->set('origin', array('master', 'develop')); +``` + +#### $git->remote->branches->add(_string_ $name, _array_ $branches) + +Adds to the list of branches tracked by the named remote + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->branches->add('origin', array('master', 'develop')); +``` + +#### $git->remote->url(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) + +Alias of set() + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->url('origin', 'https://github.com/text/Text.git'); +``` + +##### Options + +- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + +#### $git->remote->url->set(_string_ $name, _string_ $newUrl, _string_ $oldUrl = null, _array_ $options = []) + +Sets the URL remote to $newUrl + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->url->set('origin', 'https://github.com/text/Text.git'); +``` + +##### Options + +- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + +#### $git->remote->url->add(_string_ $name, _string_ $newUrl, _array_ $options = []) + +Adds new URL to remote + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->url->add('origin', 'https://github.com/text/Text.git'); +``` + +##### Options + +- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + +#### $git->remote->url->delete(_string_ $name, _string_ $url, _array_ $options = []) + +Deletes all URLs matching regex $url + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); +$git->remote->url->delete('origin', 'https://github.com'); +``` + +##### Options + +- **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + +* * * * * + +### git reset + +#### $git->reset(_string|array|\Traversable_ $paths, _string_ $commit = null) + +Resets the index entries for all **$paths** to their state at **$commit** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset(); +``` + +#### $git->reset->soft(_string_ $commit = null) + +Resets the current branch head to **$commit** + +Does not touch the index file nor the working tree at all (but resets the head to **$commit**, +just like all modes do). +This leaves all your changed files "Changes to be committed", as git status would put it. + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset->soft(); +``` + +#### $git->reset->mixed(_string_ $commit = null) + +Resets the current branch head to **$commit** + +Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) +and reports what has not been updated. This is the default action. + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset->mixed(); +``` + +#### $git->reset->hard(_string_ $commit = null) + +Resets the current branch head to **$commit** + +Resets the index and working tree. Any changes to tracked files in the working tree since **$commit** are discarded + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset->hard(); +``` + +#### $git->reset->merge(_string_ $commit = null) + +Resets the current branch head to **$commit** + +Resets the index and updates the files in the working tree that are different between **$commit** and HEAD, +but keeps those which are different between the index and working tree +(i.e. which have changes which have not been added). If a file that is different between **$commit** and +the index has unstaged changes, reset is aborted + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset->merge(); +``` + +#### $git->reset->keep(_string_ $commit = null) + +Resets the current branch head to **$commit** + +Resets index entries and updates files in the working tree that are different between **$commit** and HEAD. +If a file that is different between **$commit** and HEAD has local changes, reset is aborted. + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset->keep(); +``` + +#### $git->reset->mode(_string_ $mode, _string_ $commit = null) + +Resets the current branch head to **$commit** + +Possibly updates the index (resetting it to the tree of **$commit**) and the working tree depending on **$mode** + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->reset->mode('hard'); +``` + +* * * * * + +### git rm + +#### $git->rm(_string|array|\Traversable_ $file, _array_ $options = []) + +Remove files from the working tree and from the index + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->rm('CHANGELOG-1.0-1.1.txt', ['force' => true]); +``` + +##### Options + +- **force** (_boolean_) Override the up-to-date check +- **cached** (_boolean_) Unstage and remove paths only from the index +- **recursive** (_boolean_) Allow recursive removal when a leading directory name is given + +#### $git->rm->cached(_string|array|\Traversable_ $file, _array_ $options = []) + +Equivalent to $git->rm($file, ['cached' => true]); + +##### Options + +- **force** (_boolean_) Override the up-to-date check +- **recursive** (_boolean_) Allow recursive removal when a leading directory name is given + +* * * * * + +### git shortlog + +#### $git->shortlog(_string|array|\Traversable_ $commits = HEAD) + +Summarize 'git log' output + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$shortlog = $git->shortlog(); +``` + +##### Output Example + +``` php +[ + 'John Doe <john@example.com>' => [ + 0 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-10 12:56:15 +0300'), 'subject' => 'Update README'], + 1 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-15 12:56:15 +0300'), 'subject' => 'Update README'], + ], + //... +] +``` + +#### $git->shortlog->summary(_string_ $commits = HEAD) + +Suppress commit description and provide a commit count summary only + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$shortlog = $git->shortlog->summary(); +``` + +##### Output Example + +``` php +[ + 'John Doe <john@example.com>' => 153, + //... +] +``` + +* * * * * + +### git show + +#### $git->show(_string_ $object, _array_ $options = []) + +Shows one or more objects (blobs, trees, tags and commits) + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +echo $git->show('3ddee587e209661c8265d5bfd0df999836f6dfa2'); +``` + +##### Options + +- **format** (_string_) Pretty-print the contents of the commit logs in a given format, where <format> can be one of oneline, short, medium, full, fuller, email, raw and format:<string> +- **abbrev-commit** (_boolean_) Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix + +* * * * * + +### git stash + +#### $git->stash() + +Save your local modifications to a new stash, and run git reset --hard to revert them + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash(); +``` + +#### $git->stash->save(_string_ $message = null, _array_ $options = []) + +Save your local modifications to a new stash, and run git reset --hard to revert them. + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash->save('My stash'); +``` + +#### $git->stash->lists(_array_ $options = []) + +Returns the stashes that you currently have + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$stashes = $git->stash->lists(); +``` + +##### Output Example + +``` php +[ + 0 => ['branch' => 'master', 'message' => '0e2f473 Fixes README.md'], + 1 => ['branch' => 'master', 'message' => 'ce1ddde Initial commit'], +] +``` + +#### $git->stash->show(_string_ $stash = null) + +Show the changes recorded in the stash as a diff between the stashed state and its original parent + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +echo $git->stash->show('stash@{0}'); +``` + +##### Output Example + +``` + REAMDE.md | 2 +- + 1 files changed, 1 insertions(+), 1 deletions(-) +``` + +#### $git->stash->drop(_string_ $stash = null) + +Remove a single stashed state from the stash list + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash->drop('stash@{0}'); +``` + +#### $git->stash->pop(_string_ $stash = null, _array_ $options = []) + +Remove a single stashed state from the stash list and apply it on top of the current working tree state + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash->pop('stash@{0}'); +``` + +#### $git->stash->apply(_string_ $stash = null, _array_ $options = []) + +Like pop, but do not remove the state from the stash list + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash->apply('stash@{0}'); +``` + +#### $git->stash->branch(_string_ $name, _string_ $stash = null) + +Creates and checks out a new branch named <branchname> starting from the commit at which the <stash> was originally created, applies the changes recorded in <stash> to the new working tree and index + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash->branch('hotfix', 'stash@{0}'); +``` + +#### $git->stash->clear() + +Remove all the stashed states + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->stash->clear(); +``` + +#### $git->stash->create() + +Create a stash (which is a regular commit object) and return its object name, without storing it anywhere in the ref namespace + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$commit = $git->stash->create(); +``` + +##### Output Example + +``` +877316ea6f95c43b7ccc2c2a362eeedfa78b597d +``` + +* * * * * + +### git status + +#### $git->status(_array_ $options = []) + +Returns the working tree status + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$status = $git->status(); +``` + +##### Constants + +- StatusCommand::UNMODIFIED [=' '] unmodified +- StatusCommand::MODIFIED [='M'] modified +- StatusCommand::ADDED [='A'] added +- StatusCommand::DELETED [='D'] deleted +- StatusCommand::RENAMED [='R'] renamed +- StatusCommand::COPIED [='C'] copied +- StatusCommand::UPDATED_BUT_UNMERGED [='U'] updated but unmerged +- StatusCommand::UNTRACKED [='?'] untracked +- StatusCommand::IGNORED [='!'] ignored + +##### Output Example + +``` php +[ + 'branch' => 'master', + 'changes' => [ + ['file' => 'item1.txt', 'index' => 'A', 'work_tree' => 'M'], + ['file' => 'item2.txt', 'index' => 'A', 'work_tree' => ' '], + ['file' => 'item3.txt', 'index' => '?', 'work_tree' => '?'], + ] +] +``` + +##### Options + +- **ignored** (_boolean_) Show ignored files as well + +* * * * * + +### git tag + +#### $git->tag() + +Returns an array of tags + +``` php +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); +$git->setRepository('/path/to/repo'); +$tags = $git->tag(); +``` + +##### Output Example + +``` +['v1.0.0', 'v1.0.1', 'v1.0.2'] +``` + +#### $git->tag->create(_string_ $tag, _string_ $commit = null, _array_ $options = []) + +Creates a tag object + +``` php +$git = new PHPGit\Git(); +$git->setRepository('/path/to/repo'); +$git->tag->create('v1.0.0'); +``` + +##### Options + +- **annotate** (_boolean_) Make an unsigned, annotated tag object +- **sign** (_boolean_) Make a GPG-signed tag, using the default e-mail address’s key +- **force** (_boolean_) Replace an existing tag with the given name (instead of failing) + +#### $git->tag->delete(_string|array|\Traversable_ $tag) + +Delete existing tags with the given names + +#### $git->tag->verify(_string|array|\Traversable_ $tag) + +Verify the gpg signature of the given tag names + +* * * * * + +### git ls-tree + +#### $git->tree(_string_ $branch = master, _string_ $path = '') + +Returns the contents of a tree object + +``` php +$git = new PHPGit\Git(); +$git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); +$git->setRepository('/path/to/repo'); +$tree = $git->tree('master'); +``` + +##### Output Example + +``` php +[ + ['mode' => '100644', 'type' => 'blob', 'hash' => '1f100ce9855b66111d34b9807e47a73a9e7359f3', 'file' => '.gitignore', 'sort' => '2:.gitignore'], + ['mode' => '100644', 'type' => 'blob', 'hash' => 'e0bfe494537037451b09c32636c8c2c9795c05c0', 'file' => '.travis.yml', 'sort' => '2:.travis.yml'], + ['mode' => '040000', 'type' => 'tree', 'hash' => '8d5438e79f77cd72de80c49a413f4edde1f3e291', 'file' => 'bin', 'sort' => '1:.bin'], +] +``` + +License +------- + +The MIT License + +Author +------ + +Kazuyuki Hayashi (@kzykhys) diff --git a/library/kzykhys/git/phpunit.xml.dist b/library/kzykhys/git/phpunit.xml.dist new file mode 100644 index 000000000..ad8dd7b00 --- /dev/null +++ b/library/kzykhys/git/phpunit.xml.dist @@ -0,0 +1,28 @@ +<?xml version="1.0" encoding="UTF-8"?> + +<!-- http://www.phpunit.de/manual/current/en/appendixes.configuration.html --> +<phpunit + backupGlobals = "false" + backupStaticAttributes = "false" + colors = "true" + convertErrorsToExceptions = "true" + convertNoticesToExceptions = "true" + convertWarningsToExceptions = "true" + processIsolation = "false" + stopOnFailure = "false" + syntaxCheck = "false" + bootstrap = "vendor/autoload.php" > + + <testsuites> + <testsuite name="Project Test Suite"> + <directory>test</directory> + </testsuite> + </testsuites> + + <filter> + <whitelist> + <directory>src</directory> + </whitelist> + </filter> + +</phpunit>
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command.php b/library/kzykhys/git/src/PHPGit/Command.php new file mode 100644 index 000000000..9238a5454 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command.php @@ -0,0 +1,123 @@ +<?php + +namespace PHPGit; + +use Symfony\Component\OptionsResolver\OptionsResolver; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; +use Symfony\Component\Process\ProcessBuilder; + +/** + * Base class for git commands + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +abstract class Command +{ + + /** + * @var Git + */ + protected $git; + + /** + * @param Git $git + */ + public function __construct(Git $git) + { + $this->git = $git; + } + + /** + * Returns the combination of the default and the passed options + * + * @param array $options An array of options + * + * @return array + */ + public function resolve(array $options = array()) + { + $resolver = new OptionsResolver(); + $this->setDefaultOptions($resolver); + + return $resolver->resolve($options); + } + + /** + * Sets the default options + * + * @param OptionsResolverInterface $resolver The resolver for the options + * + * @codeCoverageIgnore + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + } + + /** + * Split string by new line or null(\0) + * + * @param string $input The string to split + * @param bool $useNull True to split by new line, otherwise null + * + * @return array + */ + protected function split($input, $useNull = false) + { + if ($useNull) { + $pattern = '/\0/'; + } else { + $pattern = '/\r?\n/'; + } + + return preg_split($pattern, rtrim($input), -1, PREG_SPLIT_NO_EMPTY); + } + + /** + * Adds boolean options to command arguments + * + * @param ProcessBuilder $builder A ProcessBuilder object + * @param array $options An array of options + * @param array $optionNames The names of options to add + */ + protected function addFlags(ProcessBuilder $builder, array $options = array(), array $optionNames = null) + { + if ($optionNames) { + foreach ($optionNames as $name) { + if (isset($options[$name]) && is_bool($options[$name]) && $options[$name]) { + $builder->add('--' . $name); + } + } + } else { + foreach ($options as $name => $option) { + if ($option) { + $builder->add('--' . $name); + } + } + } + } + + /** + * Adds options with values to command arguments + * + * @param ProcessBuilder $builder A ProcessBuilder object + * @param array $options An array of options + * @param array $optionNames The names of options to add + */ + protected function addValues(ProcessBuilder $builder, array $options = array(), array $optionNames = null) + { + if ($optionNames) { + foreach ($optionNames as $name) { + if (isset($options[$name]) && $options[$name]) { + $builder->add('--' . $name . '=' . $options[$name]); + } + } + } else { + foreach ($options as $name => $option) { + if ($option) { + $builder->add('--' . $name . '=' . $option); + } + } + } + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/AddCommand.php b/library/kzykhys/git/src/PHPGit/Command/AddCommand.php new file mode 100644 index 000000000..c035b2412 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/AddCommand.php @@ -0,0 +1,75 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Add file contents to the index - `git add` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class AddCommand extends Command +{ + + /** + * Add file contents to the index + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->add('file.txt'); + * $git->add('file.txt', ['force' => false, 'ignore-errors' => false); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Allow adding otherwise ignored files + * - **ignore-errors** (_boolean_) Do not abort the operation + * + * @param string|array|\Traversable $file Files to add content from + * @param array $options [optional] An array of options {@see AddCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($file, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('add'); + + $this->addFlags($builder, $options); + + if (!is_array($file) && !($file instanceof \Traversable)) { + $file = array($file); + } + + foreach ($file as $value) { + $builder->add($value); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **force** (_boolean_) Allow adding otherwise ignored files + * - **ignore-errors** (_boolean_) Do not abort the operation + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + //'dry-run' => false, + 'force' => false, + 'ignore-errors' => false, + //'ignore-missing' => false, + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php b/library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php new file mode 100644 index 000000000..a6c9bd0d9 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/ArchiveCommand.php @@ -0,0 +1,96 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Create an archive of files from a named tree - `git archive` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class ArchiveCommand extends Command +{ + + /** + * Create an archive of files from a named tree + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->archive('repo.zip', 'master', null, ['format' => 'zip']); + * ``` + * + * ##### Options + * + * - **format** (_boolean_) Format of the resulting archive: tar or zip + * - **prefix** (_boolean_) Prepend prefix/ to each filename in the archive + * + * @param string $file The filename + * @param string $tree [optional] The tree or commit to produce an archive for + * @param string|array|\Traversable $path [optional] If one or more paths are specified, only these are included + * @param array $options [optional] An array of options {@see ArchiveCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($file, $tree = null, $path = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('archive'); + + if ($options['format']) { + $builder->add('--format=' . $options['format']); + } + + if ($options['prefix']) { + $builder->add('--prefix=' . $options['prefix']); + } + + $builder->add('-o')->add($file); + + if ($tree) { + $builder->add($tree); + } + + if (!is_array($path) && !($path instanceof \Traversable)) { + $path = array($path); + } + + foreach ($path as $value) { + $builder->add($value); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **format** (_boolean_) Format of the resulting archive: tar or zip + * - **prefix** (_boolean_) Prepend prefix/ to each filename in the archive + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'format' => null, + 'prefix' => null + )); + + $resolver->setAllowedTypes(array( + 'format' => array('null', 'string'), + 'prefix' => array('null', 'string') + )); + + $resolver->setAllowedValues(array( + 'format' => array('tar', 'zip') + )); + } + + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/BranchCommand.php b/library/kzykhys/git/src/PHPGit/Command/BranchCommand.php new file mode 100644 index 000000000..4b42f5048 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/BranchCommand.php @@ -0,0 +1,229 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * List, create, or delete branches - `git branch` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class BranchCommand extends Command +{ + + /** + * Returns an array of both remote-tracking branches and local branches + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $branches = $git->branch(); + * ``` + * + * ##### Output Example + * + * ``` + * [ + * 'master' => ['current' => true, 'name' => 'master', 'hash' => 'bf231bb', 'title' => 'Initial Commit'], + * 'origin/master' => ['current' => false, 'name' => 'origin/master', 'alias' => 'remotes/origin/master'] + * ] + * ``` + * + * ##### Options + * + * - **all** (_boolean_) List both remote-tracking branches and local branches + * - **remotes** (_boolean_) List the remote-tracking branches + * + * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} + * + * @throws GitException + * @return array + */ + public function __invoke(array $options = array()) + { + $options = $this->resolve($options); + $branches = array(); + $builder = $this->getProcessBuilder() + ->add('-v')->add('--abbrev=7'); + + if ($options['remotes']) { + $builder->add('--remotes'); + } + + if ($options['all']) { + $builder->add('--all'); + } + + $process = $builder->getProcess(); + $this->git->run($process); + + $lines = preg_split('/\r?\n/', rtrim($process->getOutput()), -1, PREG_SPLIT_NO_EMPTY); + + foreach ($lines as $line) { + $branch = array(); + preg_match('/(?<current>\*| ) (?<name>[^\s]+) +((?:->) (?<alias>[^\s]+)|(?<hash>[0-9a-z]{7}) (?<title>.*))/', $line, $matches); + + $branch['current'] = ($matches['current'] == '*'); + $branch['name'] = $matches['name']; + + if (isset($matches['hash'])) { + $branch['hash'] = $matches['hash']; + $branch['title'] = $matches['title']; + } else { + $branch['alias'] = $matches['alias']; + } + + $branches[$matches['name']] = $branch; + } + + return $branches; + } + + /** + * Creates a new branch head named **$branch** which points to the current HEAD, or **$startPoint** if given + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->branch->create('bugfix'); // from current HEAD + * $git->branch->create('patch-1', 'a092bf7s'); // from commit + * $git->branch->create('1.0.x-fix', 'v1.0.2'); // from tag + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Reset **$branch** to **$startPoint** if **$branch** exists already + * + * @param string $branch The name of the branch to create + * @param string $startPoint [optional] The new branch head will point to this commit. + * It may be given as a branch name, a commit-id, or a tag. + * If this option is omitted, the current HEAD will be used instead. + * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function create($branch, $startPoint = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->getProcessBuilder(); + + if ($options['force']) { + $builder->add('-f'); + } + + $builder->add($branch); + + if ($startPoint) { + $builder->add($startPoint); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Move/rename a branch and the corresponding reflog + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->branch->move('bugfix', '2.0'); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Move/rename a branch even if the new branch name already exists + * + * @param string $branch The name of an existing branch to rename + * @param string $newBranch The new name for an existing branch + * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function move($branch, $newBranch, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->getProcessBuilder(); + + if ($options['force']) { + $builder->add('-M'); + } else { + $builder->add('-m'); + } + + $builder->add($branch)->add($newBranch); + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Delete a branch + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->branch->delete('2.0'); + * ``` + * + * The branch must be fully merged in its upstream branch, or in HEAD if no upstream was set with --track or --set-upstream. + * + * ##### Options + * + * - **force** (_boolean_) Delete a branch irrespective of its merged status + * + * @param string $branch The name of the branch to delete + * @param array $options [optional] An array of options {@see BranchCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function delete($branch, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->getProcessBuilder(); + + if ($options['force']) { + $builder->add('-D'); + } else { + $builder->add('-d'); + } + + $builder->add($branch); + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **force** (_boolean_) Reset <branchname> to <startpoint> if <branchname> exists already + * - **all** (_boolean_) List both remote-tracking branches and local branches + * - **remotes** (_boolean_) List or delete (if used with delete()) the remote-tracking branches + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'force' => false, + 'all' => false, + 'remotes' => false, + )); + } + + /** + * @return \Symfony\Component\Process\ProcessBuilder + */ + protected function getProcessBuilder() + { + return $this->git->getProcessBuilder() + ->add('branch'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CatCommand.php b/library/kzykhys/git/src/PHPGit/Command/CatCommand.php new file mode 100644 index 000000000..0c4fc1f41 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/CatCommand.php @@ -0,0 +1,91 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; + +/** + * Provide content or type and size information for repository objects - `git cat-file` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class CatCommand extends Command +{ + + /** + * Returns the contents of blob object + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $contents = $git->cat->blob('e69de29bb2d1d6434b8b29ae775ad8'); + * ``` + * + * @param string $object The name of the blob object to show + * + * @throws GitException + * @return string + */ + public function blob($object) + { + $process = $this->git->getProcessBuilder() + ->add('cat-file') + ->add('blob') + ->add($object) + ->getProcess(); + + return $this->git->run($process); + } + + /** + * Returns the object type identified by **$object** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $type = $git->cat->type('e69de29bb2d1d6434b8b29ae775ad8'); + * ``` + * + * @param string $object The name of the object to show + * + * @throws GitException + * @return string + */ + public function type($object) + { + $process = $this->git->getProcessBuilder() + ->add('cat-file') + ->add('-t') + ->add($object) + ->getProcess(); + + return trim($this->git->run($process)); + } + + /** + * Returns the object size identified by **$object** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $type = $git->cat->size('e69de29bb2d1d6434b8b29ae775ad8'); + * ``` + * + * @param string $object The name of the object to show + * + * @throws GitException + * @return string + */ + public function size($object) + { + $process = $this->git->getProcessBuilder() + ->add('cat-file') + ->add('-s') + ->add($object) + ->getProcess(); + + return trim($this->git->run($process)); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php b/library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php new file mode 100644 index 000000000..caddf07bd --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/CheckoutCommand.php @@ -0,0 +1,145 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Checkout a branch or paths to the working tree - `git checkout` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class CheckoutCommand extends Command +{ + + /** + * Switches branches by updating the index, working tree, and HEAD to reflect the specified branch or commit + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->checkout('develop'); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD + * - **merge** (_boolean_) Merges local modification + * + * @param string $branch Branch to checkout + * @param array $options [optional] An array of options {@see CheckoutCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($branch, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('checkout'); + + $this->addFlags($builder, $options, array('force', 'merge')); + + $builder->add($branch); + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Create a new branch and checkout + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->checkout->create('patch-1'); + * $git->checkout->create('patch-2', 'develop'); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD + * + * @param string $branch Branch to checkout + * @param string $startPoint The name of a commit at which to start the new branch + * @param array $options [optional] An array of options {@see CheckoutCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function create($branch, $startPoint = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('checkout') + ->add('-b'); + + $this->addFlags($builder, $options, array('force', 'merge')); + + $builder->add($branch); + + if ($startPoint) { + $builder->add($startPoint); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Create a new orphan branch, named <new_branch>, started from <start_point> and switch to it + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->checkout->orphan('gh-pages'); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD + * + * @param string $branch Branch to checkout + * @param string $startPoint [optional] The name of a commit at which to start the new branch + * @param array $options [optional] An array of options {@see CheckoutCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function orphan($branch, $startPoint = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('checkout'); + + $this->addFlags($builder, $options, array('force', 'merge')); + + $builder->add('--orphan')->add($branch); + + if ($startPoint) { + $builder->add($startPoint); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **force** (_boolean_) Proceed even if the index or the working tree differs from HEAD + * - **merge** (_boolean_) Merges local modification + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'force' => false, + 'merge' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CloneCommand.php b/library/kzykhys/git/src/PHPGit/Command/CloneCommand.php new file mode 100644 index 000000000..cc6b4ab37 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/CloneCommand.php @@ -0,0 +1,71 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Clone a repository into a new directory - `git clone` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class CloneCommand extends Command +{ + + /** + * Clone a repository into a new directory + * + * ``` php + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); + * ``` + * + * ##### Options + * + * - **shared** (_boolean_) Starts out without any object of its own + * - **bare** (_boolean_) Make a bare GIT repository + * + * @param string $repository The repository to clone from + * @param string $path [optional] The name of a new directory to clone into + * @param array $options [optional] An array of options {@see CloneCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($repository, $path = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('clone') + ->add('--quiet'); + + $this->addFlags($builder, $options); + + $builder->add($repository); + + if ($path) { + $builder->add($path); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **shared** (_boolean_) Starts out without any object of its own + * - **bare** (_boolean_) Make a bare GIT repository + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'shared' => false, + 'bare' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/CommitCommand.php b/library/kzykhys/git/src/PHPGit/Command/CommitCommand.php new file mode 100644 index 000000000..a4f2bdd95 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/CommitCommand.php @@ -0,0 +1,87 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Record changes to the repository - `git commit` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class CommitCommand extends Command +{ + + /** + * Record changes to the repository + * + * ``` php + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); + * $git->setRepository('/path/to/repo'); + * $git->add('README.md'); + * $git->commit('Fixes README.md'); + * ``` + * + * ##### Options + * + * - **all** (_boolean_) Stage files that have been modified and deleted + * - **reuse-message** (_string_) Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit + * - **squash** (_string_) Construct a commit message for use with rebase --autosquash + * - **author** (_string_) Override the commit author + * - **date** (_string_) Override the author date used in the commit + * - **cleanup** (_string_) Can be one of verbatim, whitespace, strip, and default + * - **amend** (_boolean_) Used to amend the tip of the current branch + * + * @param string $message Use the given <$msg> as the commit message + * @param array $options [optional] An array of options {@see CloneCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($message, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('commit') + ->add('-m')->add($message); + + $this->addFlags($builder, $options, array('all', 'amend')); + $this->addValues($builder, $options, array('reuse-message', 'squash', 'author', 'date', 'cleanup')); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **all** (_boolean_) Stage files that have been modified and deleted + * - **reuse-message** (_string_) Take an existing commit object, and reuse the log message and the authorship information (including the timestamp) when creating the commit + * - **squash** (_string_) Construct a commit message for use with rebase --autosquash + * - **author** (_string_) Override the commit author + * - **date** (_string_) Override the author date used in the commit + * - **cleanup** (_string_) Can be one of verbatim, whitespace, strip, and default + * - **amend** (_boolean_) Used to amend the tip of the current branch + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'all' => false, + 'reuse-message' => null, + 'squash' => null, + 'author' => null, + 'date' => null, + 'cleanup' => null, + 'amend' => false + )); + + $resolver->setAllowedValues(array( + 'cleanup' => array(null, 'default', 'verbatim', 'whitespace', 'strip') + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php b/library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php new file mode 100644 index 000000000..cb8bb625f --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/ConfigCommand.php @@ -0,0 +1,132 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Get and set repository or global options - `git config` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class ConfigCommand extends Command +{ + + /** + * Returns all variables set in config file + * + * + * ##### Options + * + * - **global** (_boolean_) Read or write configuration options for the current user + * - **system** (_boolean_) Read or write configuration options for all users on the current machine + * + * @param array $options [optional] An array of options {@see ConfigCommand::setDefaultOptions} + * + * @throws GitException + * @return array + */ + public function __invoke(array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('config') + ->add('--list') + ->add('--null'); + + $this->addFlags($builder, $options, array('global', 'system')); + + $config = array(); + $output = $this->git->run($builder->getProcess()); + $lines = $this->split($output, true); + + foreach ($lines as $line) { + list($name, $value) = explode("\n", $line, 2); + + if (isset($config[$name])) { + $config[$name] .= "\n" . $value; + } else { + $config[$name] = $value; + } + } + + return $config; + } + + /** + * Set an option + * + * ##### Options + * + * - **global** (_boolean_) Read or write configuration options for the current user + * - **system** (_boolean_) Read or write configuration options for all users on the current machine + * + * @param string $name The name of the option + * @param string $value The value to set + * @param array $options [optional] An array of options {@see ConfigCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function set($name, $value, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('config'); + + $this->addFlags($builder, $options, array('global', 'system')); + + $builder->add($name)->add($value); + $process = $builder->getProcess(); + $this->git->run($process); + + return true; + } + + /** + * Adds a new line to the option without altering any existing values + * + * ##### Options + * + * - **global** (_boolean_) Read or write configuration options for the current user + * - **system** (_boolean_) Read or write configuration options for all users on the current machine + * + * @param string $name The name of the option + * @param string $value The value to add + * @param array $options [optional] An array of options {@see ConfigCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function add($name, $value, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('config'); + + $this->addFlags($builder, $options, array('global', 'system')); + + $builder->add('--add')->add($name)->add($value); + $process = $builder->getProcess(); + $this->git->run($process); + + return true; + } + + /** + * {@inheritdoc} + * + * - **global** (_boolean_) Read or write configuration options for the current user + * - **system** (_boolean_) Read or write configuration options for all users on the current machine + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'global' => false, + 'system' => false, + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php b/library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php new file mode 100644 index 000000000..affdd009b --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/DescribeCommand.php @@ -0,0 +1,90 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Show the most recent tag that is reachable from a commit - `git describe` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class DescribeCommand extends Command +{ + + /** + * Returns the most recent tag that is reachable from a commit + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->tag->create('v1.0.0'); + * $git->commit('Fixes #14'); + * echo $git->describe('HEAD', ['tags' => true]); + * ``` + * + * ##### Output Example + * + * ``` + * v1.0.0-1-g7049efc + * ``` + * + * ##### Options + * + * - **all** (_boolean_) Enables matching any known branch, remote-tracking branch, or lightweight tag + * - **tags** (_boolean_) Enables matching a lightweight (non-annotated) tag + * - **always** (_boolean_) Show uniquely abbreviated commit object as fallback + * + * @param string $committish [optional] Committish object names to describe. + * @param array $options [optional] An array of options {@see DescribeCommand::setDefaultOptions} + * + * @return string + */ + public function __invoke($committish = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('describe'); + + $this->addFlags($builder, $options, array()); + + if ($committish) { + $builder->add($committish); + } + + return trim($this->git->run($builder->getProcess())); + } + + /** + * Equivalent to $git->describe($committish, ['tags' => true]); + * + * @param string $committish [optional] Committish object names to describe. + * @param array $options [optional] An array of options {@see DescribeCommand::setDefaultOptions} + * + * @return string + */ + public function tags($committish = null, array $options = array()) + { + $options['tags'] = true; + + return $this->__invoke($committish, $options); + } + + /** + * {@inheritdoc} + * + * - **all** (_boolean_) Enables matching any known branch, remote-tracking branch, or lightweight tag + * - **tags** (_boolean_) Enables matching a lightweight (non-annotated) tag + * - **always** (_boolean_) Show uniquely abbreviated commit object as fallback + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'all' => false, + 'tags' => false, + 'always' => false, + )); + } + +} diff --git a/library/kzykhys/git/src/PHPGit/Command/FetchCommand.php b/library/kzykhys/git/src/PHPGit/Command/FetchCommand.php new file mode 100644 index 000000000..1302038e8 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/FetchCommand.php @@ -0,0 +1,112 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Download objects and refs from another repository - `git fetch` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class FetchCommand extends Command +{ + + /** + * Fetches named heads or tags from one or more other repositories, along with the objects necessary to complete them + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'git://your/repo.git'); + * $git->fetch('origin'); + * ``` + * + * ##### Options + * + * - **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD + * - **keep** (_boolean_) Keep downloaded pack + * - **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote + * + * @param string $repository The "remote" repository that is the source of a fetch or pull operation + * @param string $refspec The format of a <refspec> parameter is an optional plus +, followed by the source ref <src>, + * followed by a colon :, followed by the destination ref <dst> + * @param array $options [optional] An array of options {@see FetchCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($repository, $refspec = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('fetch'); + + $this->addFlags($builder, $options); + $builder->add($repository); + + if ($refspec) { + $builder->add($refspec); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Fetch all remotes + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'git://your/repo.git'); + * $git->remote->add('release', 'git://your/another_repo.git'); + * $git->fetch->all(); + * ``` + * + * ##### Options + * + * - **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD + * - **keep** (_boolean_) Keep downloaded pack + * - **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote + * + * @param array $options [optional] An array of options {@see FetchCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function all(array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('fetch') + ->add('--all'); + + $this->addFlags($builder, $options); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **append** (_boolean_) Append ref names and object names of fetched refs to the existing contents of .git/FETCH_HEAD + * - **keep** (_boolean_) Keep downloaded pack + * - **prune** (_boolean_) After fetching, remove any remote-tracking branches which no longer exist on the remote + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'append' => false, + //'force' => false, + 'keep' => false, + 'prune' => false, + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/InitCommand.php b/library/kzykhys/git/src/PHPGit/Command/InitCommand.php new file mode 100644 index 000000000..1ff56fa5b --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/InitCommand.php @@ -0,0 +1,65 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Create an empty git repository or reinitialize an existing one - `git init` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class InitCommand extends Command +{ + + /** + * Create an empty git repository or reinitialize an existing one + * + * ``` php + * $git = new PHPGit\Git(); + * $git->init('/path/to/repo1'); + * $git->init('/path/to/repo2', array('shared' => true, 'bare' => true)); + * ``` + * + * ##### Options + * + * - **shared** (_boolean_) Specify that the git repository is to be shared amongst several users + * - **bare** (_boolean_) Create a bare repository + * + * @param string $path The directory to create an empty repository + * @param array $options [optional] An array of options {@see InitCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($path, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('init'); + + $this->addFlags($builder, $options, array('shared', 'bare')); + + $process = $builder->add($path)->getProcess(); + $this->git->run($process); + + return true; + } + + /** + * {@inheritdoc} + * + * - **shared** (_boolean_) Specify that the git repository is to be shared amongst several users + * - **bare** (_boolean_) Create a bare repository + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'shared' => false, + 'bare' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/LogCommand.php b/library/kzykhys/git/src/PHPGit/Command/LogCommand.php new file mode 100644 index 000000000..c116550f7 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/LogCommand.php @@ -0,0 +1,105 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Show commit logs - `git log` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class LogCommand extends Command +{ + + /** + * Returns the commit logs + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $logs = $git->log(array('limit' => 10)); + * ``` + * + * ##### Output Example + * + * ``` php + * [ + * 0 => [ + * 'hash' => '1a821f3f8483747fd045eb1f5a31c3cc3063b02b', + * 'name' => 'John Doe', + * 'email' => 'john@example.com', + * 'date' => 'Fri Jan 17 16:32:49 2014 +0900', + * 'title' => 'Initial Commit' + * ], + * 1 => [ + * //... + * ] + * ] + * ``` + * + * ##### Options + * + * - **limit** (_integer_) Limits the number of commits to show + * - **skip** (_integer_) Skip number commits before starting to show the commit output + * + * @param string $revRange [optional] Show only commits in the specified revision range + * @param string $path [optional] Show only commits that are enough to explain how the files that match the specified paths came to be + * @param array $options [optional] An array of options {@see LogCommand::setDefaultOptions} + * + * @throws GitException + * @return array + */ + public function __invoke($revRange = '', $path = null, array $options = array()) + { + $commits = array(); + $options = $this->resolve($options); + + $builder = $this->git->getProcessBuilder() + ->add('log') + ->add('-n')->add($options['limit']) + ->add('--skip=' . $options['skip']) + ->add('--format=%H||%aN||%aE||%aD||%s'); + + if ($revRange) { + $builder->add($revRange); + } + + if ($path) { + $builder->add('--')->add($path); + } + + $output = $this->git->run($builder->getProcess()); + $lines = $this->split($output); + + foreach ($lines as $line) { + list($hash, $name, $email, $date, $title) = preg_split('/\|\|/', $line, -1, PREG_SPLIT_NO_EMPTY); + $commits[] = array( + 'hash' => $hash, + 'name' => $name, + 'email' => $email, + 'date' => $date, + 'title' => $title + ); + } + + return $commits; + } + + /** + * {@inheritdoc} + * + * - **limit** (_integer_) Limits the number of commits to show + * - **skip** (_integer_) Skip number commits before starting to show the commit output + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'limit' => 10, + 'skip' => 0 + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/MergeCommand.php b/library/kzykhys/git/src/PHPGit/Command/MergeCommand.php new file mode 100644 index 000000000..e1987151f --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/MergeCommand.php @@ -0,0 +1,110 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Join two or more development histories together - `git merge` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class MergeCommand extends Command +{ + + /** + * Incorporates changes from the named commits into the current branch + * + * ```php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->merge('1.0'); + * $git->merge('1.1', 'Merge message', ['strategy' => 'ours']); + * ``` + * + * ##### Options + * + * - **no-ff** (_boolean_) Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer + * - **rerere-autoupdate** (_boolean_) Allow the rerere mechanism to update the index with the result of auto-conflict resolution if possible + * - **squash** (_boolean_) Allows you to create a single commit on top of the current branch whose effect is the same as merging another branch + * - **strategy** (_string_) Use the given merge strategy + * - **strategy-option** (_string_) Pass merge strategy specific option through to the merge strategy + * + * @param string|array|\Traversable $commit Commits to merge into our branch + * @param string $message [optional] Commit message to be used for the merge commit + * @param array $options [optional] An array of options {@see MergeCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function __invoke($commit, $message = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('merge'); + + $this->addFlags($builder, $options, array('no-ff', 'rerere-autoupdate', 'squash')); + + if (!is_array($commit) && !($commit instanceof \Traversable)) { + $commit = array($commit); + } + foreach ($commit as $value) { + $builder->add($value); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Abort the merge process and try to reconstruct the pre-merge state + * + * ```php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * try { + * $git->merge('dev'); + * } catch (PHPGit\Exception\GitException $e) { + * $git->merge->abort(); + * } + * ``` + * + * @throws GitException + * @return bool + */ + public function abort() + { + $builder = $this->git->getProcessBuilder() + ->add('merge') + ->add('--abort'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **no-ff** (_boolean_) Do not generate a merge commit if the merge resolved as a fast-forward, only update the branch pointer + * - **rerere-autoupdate** (_boolean_) Allow the rerere mechanism to update the index with the result of auto-conflict resolution if possible + * - **squash** (_boolean_) Allows you to create a single commit on top of the current branch whose effect is the same as merging another branch + * - **strategy** (_string_) Use the given merge strategy + * - **strategy-option** (_string_) Pass merge strategy specific option through to the merge strategy + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'no-ff' => false, + 'rerere-autoupdate' => false, + 'squash' => false, + + 'strategy' => null, + 'strategy-option' => null + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/MvCommand.php b/library/kzykhys/git/src/PHPGit/Command/MvCommand.php new file mode 100644 index 000000000..fe7ce6af6 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/MvCommand.php @@ -0,0 +1,70 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Move or rename a file, a directory, or a symlink - `git mv` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class MvCommand extends Command +{ + + /** + * Move or rename a file, a directory, or a symlink + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->mv('UPGRADE-1.0.md', 'UPGRADE-1.1.md'); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Force renaming or moving of a file even if the target exists + * + * @param string|array|\Iterator $source The files to move + * @param string $destination The destination + * @param array $options [optional] An array of options {@see MvCommand::setDefaultOptions} + * + * @return bool + */ + public function __invoke($source, $destination, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('mv'); + + $this->addFlags($builder, $options, array('force')); + + if (!is_array($source) && !($source instanceof \Traversable)) { + $source = array($source); + } + + foreach ($source as $value) { + $builder->add($value); + } + + $builder->add($destination); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **force** (_boolean_) Force renaming or moving of a file even if the target exists + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'force' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/PullCommand.php b/library/kzykhys/git/src/PHPGit/Command/PullCommand.php new file mode 100644 index 000000000..a7cea0025 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/PullCommand.php @@ -0,0 +1,59 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Fetch from and merge with another repository or a local branch - `git pull` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class PullCommand extends Command +{ + + /** + * Fetch from and merge with another repository or a local branch + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->pull('origin', 'master'); + * ``` + * + * @param string $repository The "remote" repository that is the source of a fetch or pull operation + * @param string $refspec The format of a <refspec> parameter is an optional plus +, + * followed by the source ref <src>, followed by a colon :, followed by the destination ref <dst> + * @param array $options [optional] An array of options {@see PullCommand::setDefaultOptions} + * + * @return bool + */ + public function __invoke($repository = null, $refspec = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('pull'); + + if ($repository) { + $builder->add($repository); + + if ($refspec) { + $builder->add($refspec); + } + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/PushCommand.php b/library/kzykhys/git/src/PHPGit/Command/PushCommand.php new file mode 100644 index 000000000..d0665d735 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/PushCommand.php @@ -0,0 +1,65 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Update remote refs along with associated objects - `git push` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class PushCommand extends Command +{ + + /** + * Update remote refs along with associated objects + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->push('origin', 'master'); + * ``` + * + * @param string $repository The "remote" repository that is destination of a push operation + * @param string $refspec Specify what destination ref to update with what source object + * @param array $options [optional] An array of options {@see PushCommand::setDefaultOptions} + * + * @return bool + */ + public function __invoke($repository = null, $refspec = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('push'); + + $this->addFlags($builder, $options); + + if ($repository) { + $builder->add($repository); + + if ($refspec) { + $builder->add($refspec); + } + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'all' => false, + 'mirror' => false, + 'tags' => false, + 'force' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php b/library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php new file mode 100644 index 000000000..7516b360c --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/RebaseCommand.php @@ -0,0 +1,129 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Forward-port local commits to the updated upstream head - `git rebase` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class RebaseCommand extends Command +{ + + /** + * Forward-port local commits to the updated upstream head + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->fetch('origin'); + * $git->rebase('origin/master'); + * ``` + * + * ##### Options + * + * - **onto** (_string_) Starting point at which to create the new commits + * - **no-verify** (_boolean_) Bypasses the pre-rebase hook + * - **force-rebase** (_boolean_) Force the rebase even if the current branch is a descendant of the commit you are rebasing onto + * + * @param string $upstream [optional] Upstream branch to compare against + * @param string $branch [optional] Working branch; defaults to HEAD + * @param array $options [optional] An array of options {@see RebaseCommand::setDefaultOptions} + * + * @return bool + */ + public function __invoke($upstream = null, $branch = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('rebase'); + + if ($options['onto']) { + $builder->add('--onto')->add($options['onto']); + } + + if ($upstream) { + $builder->add($upstream); + } + + if ($branch) { + $builder->add($branch); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Restart the rebasing process after having resolved a merge conflict + * + * @return bool + */ + public function continues() + { + $builder = $this->git->getProcessBuilder() + ->add('rebase') + ->add('--continue'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Abort the rebase operation and reset HEAD to the original branch + * + * @return bool + */ + public function abort() + { + $builder = $this->git->getProcessBuilder() + ->add('rebase') + ->add('--abort'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Restart the rebasing process by skipping the current patch + * + * @return bool + */ + public function skip() + { + $builder = $this->git->getProcessBuilder() + ->add('rebase') + ->add('--skip'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **onto** (_string_) Starting point at which to create the new commits + * - **no-verify** (_boolean_) Bypasses the pre-rebase hook + * - **force-rebase** (_boolean_) Force the rebase even if the current branch is a descendant of the commit you are rebasing onto + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'onto' => null, + 'no-verify' => false, + 'force-rebase' => false + )); + + $resolver->setAllowedTypes(array( + 'onto' => array('null', 'string') + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php b/library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php new file mode 100644 index 000000000..4e17a4d48 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/Remote/SetBranchesCommand.php @@ -0,0 +1,98 @@ +<?php + +namespace PHPGit\Command\Remote; + +use PHPGit\Command; + +/** + * Changes the list of branches tracked by the named remote + * + * @author Kazuyuki Hayashi + */ +class SetBranchesCommand extends Command +{ + + /** + * Alias of set() + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->branches('origin', array('master', 'develop')); + * ``` + * + * @param string $name The remote name + * @param array $branches The names of the tracked branch + * + * @return bool + */ + public function __invoke($name, array $branches) + { + return $this->set($name, $branches); + } + + /** + * Changes the list of branches tracked by the named remote + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->branches->set('origin', array('master', 'develop')); + * ``` + * + * @param string $name The remote name + * @param array $branches The names of the tracked branch + * + * @return bool + */ + public function set($name, array $branches) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-branches') + ->add($name); + + foreach ($branches as $branch) { + $builder->add($branch); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Adds to the list of branches tracked by the named remote + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->branches->add('origin', array('master', 'develop')); + * ``` + * + * @param string $name The remote name + * @param array $branches The names of the tracked branch + * + * @return bool + */ + public function add($name, array $branches) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-branches') + ->add($name) + ->add('--add'); + + foreach ($branches as $branch) { + $builder->add($branch); + } + + $this->git->run($builder->getProcess()); + + return true; + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php b/library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php new file mode 100644 index 000000000..9241ef5b7 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/Remote/SetHeadCommand.php @@ -0,0 +1,120 @@ +<?php + +namespace PHPGit\Command\Remote; + +use PHPGit\Command; + +/** + * Sets or deletes the default branch (i.e. the target of the symbolic-ref refs/remotes/<name>/HEAD) for the named remote + * + * @author Kazuyuki Hayashi + */ +class SetHeadCommand extends Command +{ + + /** + * Alias of set() + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->head('origin'); + * ``` + * + * @param string $name The remote name + * @param string $branch [optional] The symbolic-ref to set + * + * @return bool + */ + public function __invoke($name, $branch = null) + { + return $this->set($name, $branch); + } + + /** + * Sets the default branch for the named remote + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->head->set('origin'); + * ``` + * + * @param string $name The remote name + * @param string $branch [optional] The symbolic-ref to set + * + * @return bool + */ + public function set($name, $branch) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-head') + ->add($name); + + if ($branch) { + $builder->add($branch); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Deletes the default branch for the named remote + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->head->delete('origin'); + * ``` + * + * @param string $name The remote name + * + * @return bool + */ + public function delete($name) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-head') + ->add($name) + ->add('-d'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Determine the default branch by querying remote + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->head->remote('origin'); + * ``` + * + * @param string $name The remote name + * + * @return bool + */ + public function remote($name) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-head') + ->add($name) + ->add('-a'); + + $this->git->run($builder->getProcess()); + + return true; + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php b/library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php new file mode 100644 index 000000000..7b7d84ff5 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/Remote/SetUrlCommand.php @@ -0,0 +1,175 @@ +<?php + +namespace PHPGit\Command\Remote; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Changes URL remote points to + * + * @author Kazuyuki Hayashi + */ +class SetUrlCommand extends Command +{ + + /** + * Alias of set() + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->url('origin', 'https://github.com/text/Text.git'); + * ``` + * + * ##### Options + * + * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + * + * @param string $name The name of remote + * @param string $newUrl The new URL + * @param string $oldUrl [optional] The old URL + * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} + * + * @return bool + */ + public function __invoke($name, $newUrl, $oldUrl = null, array $options = array()) + { + return $this->set($name, $newUrl, $oldUrl, $options); + } + + /** + * Sets the URL remote to $newUrl + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->url->set('origin', 'https://github.com/text/Text.git'); + * ``` + * + * ##### Options + * + * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + * + * @param string $name The name of remote + * @param string $newUrl The new URL + * @param string $oldUrl [optional] The old URL + * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} + * + * @return bool + */ + public function set($name, $newUrl, $oldUrl = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-url'); + + $this->addFlags($builder, $options); + + $builder + ->add($name) + ->add($newUrl); + + if ($oldUrl) { + $builder->add($oldUrl); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Adds new URL to remote + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->url->add('origin', 'https://github.com/text/Text.git'); + * ``` + * + * ##### Options + * + * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + * + * @param string $name The name of remote + * @param string $newUrl The new URL + * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} + * + * @return bool + */ + public function add($name, $newUrl, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-url') + ->add('--add'); + + $this->addFlags($builder, $options); + + $builder + ->add($name) + ->add($newUrl); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Deletes all URLs matching regex $url + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->url->delete('origin', 'https://github.com'); + * ``` + * + * ##### Options + * + * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + * + * @param string $name The remote name + * @param string $url The URL to delete + * @param array $options [optional] An array of options {@see SetUrlCommand::setDefaultOptions} + * + * @return bool + */ + public function delete($name, $url, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('set-url') + ->add('--delete'); + + $this->addFlags($builder, $options); + + $builder + ->add($name) + ->add($url); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **push** (_boolean_) Push URLs are manipulated instead of fetch URLs + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'push' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php b/library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php new file mode 100644 index 000000000..08220a551 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/RemoteCommand.php @@ -0,0 +1,278 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Git; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Manage set of tracked repositories - `git remote` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + * + * @method head($name, $branch) Sets the default branch for the named remote + * @method branches($name, $branches) Changes the list of branches tracked by the named remote + * @method url($name, $newUrl, $oldUrl = null, $options = array()) Sets the URL remote to $newUrl + */ +class RemoteCommand extends Command +{ + + /** @var Remote\SetHeadCommand */ + public $head; + + /** @var Remote\SetBranchesCommand */ + public $branches; + + /** @var Remote\SetUrlCommand */ + public $url; + + /** + * @param Git $git + */ + public function __construct(Git $git) + { + parent::__construct($git); + + $this->head = new Remote\SetHeadCommand($git); + $this->branches = new Remote\SetBranchesCommand($git); + $this->url = new Remote\SetUrlCommand($git); + } + + /** + * Calls sub-commands + * + * @param string $name The name of a property + * @param array $arguments An array of arguments + * + * @throws \BadMethodCallException + * @return mixed + */ + public function __call($name, $arguments) + { + if (isset($this->{$name}) && is_callable($this->{$name})) { + return call_user_func_array($this->{$name}, $arguments); + } + + throw new \BadMethodCallException(sprintf('Call to undefined method %s::%s()', __CLASS__, $name)); + } + + /** + * Returns an array of existing remotes + * + * ``` php + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); + * $git->setRepository('/path/to/repo'); + * $remotes = $git->remote(); + * ``` + * + * ##### Output Example + * + * ``` php + * [ + * 'origin' => [ + * 'fetch' => 'https://github.com/kzykhys/Text.git', + * 'push' => 'https://github.com/kzykhys/Text.git' + * ] + * ] + * ``` + * + * @return array + */ + public function __invoke() + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('-v'); + + $remotes = array(); + $output = $this->git->run($builder->getProcess()); + $lines = $this->split($output); + + foreach ($lines as $line) { + if (preg_match('/^(.*)\t(.*)\s\((.*)\)$/', $line, $matches)) { + if (!isset($remotes[$matches[1]])) { + $remotes[$matches[1]] = array(); + } + + $remotes[$matches[1]][$matches[3]] = $matches[2]; + } + } + + return $remotes; + } + + /** + * Adds a remote named **$name** for the repository at **$url** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->fetch('origin'); + * ``` + * + * ##### Options + * + * - **tags** (_boolean_) With this option, `git fetch <name>` imports every tag from the remote repository + * - **no-tags** (_boolean_) With this option, `git fetch <name>` does not import tags from the remote repository + * + * @param string $name The name of the remote + * @param string $url The url of the remote + * @param array $options [optional] An array of options {@see RemoteCommand::setDefaultOptions} + * + * @return bool + */ + public function add($name, $url, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('add'); + + $this->addFlags($builder, $options, array('tags', 'no-tags')); + + $builder->add($name)->add($url); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Rename the remote named **$name** to **$newName** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->rename('origin', 'upstream'); + * ``` + * + * @param string $name The remote name to rename + * @param string $newName The new remote name + * + * @return bool + */ + public function rename($name, $newName) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('rename') + ->add($name) + ->add($newName); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Remove the remote named **$name** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + * $git->remote->rm('origin'); + * ``` + * + * @param string $name The remote name to remove + * + * @return bool + */ + public function rm($name) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('rm') + ->add($name); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Gives some information about the remote **$name** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/Text.git', '/path/to/repo'); + * $git->setRepository('/path/to/repo'); + * echo $git->remote->show('origin'); + * ``` + * + * ##### Output Example + * + * ``` + * \* remote origin + * Fetch URL: https://github.com/kzykhys/Text.git + * Push URL: https://github.com/kzykhys/Text.git + * HEAD branch: master + * Remote branch: + * master tracked + * Local branch configured for 'git pull': + * master merges with remote master + * Local ref configured for 'git push': + * master pushes to master (up to date) + * ``` + * + * @param string $name The remote name to show + * + * @return string + */ + public function show($name) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('show') + ->add($name); + + return $this->git->run($builder->getProcess()); + } + + /** + * Deletes all stale remote-tracking branches under **$name** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->remote->prune('origin'); + * ``` + * + * @param string $name The remote name + * + * @return bool + */ + public function prune($name = null) + { + $builder = $this->git->getProcessBuilder() + ->add('remote') + ->add('prune'); + + if ($name) { + $builder->add($name); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **tags** (_boolean_) With this option, `git fetch <name>` imports every tag from the remote repository + * - **no-tags** (_boolean_) With this option, `git fetch <name>` does not import tags from the remote repository + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'tags' => false, + 'no-tags' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ResetCommand.php b/library/kzykhys/git/src/PHPGit/Command/ResetCommand.php new file mode 100644 index 000000000..f70f53e2e --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/ResetCommand.php @@ -0,0 +1,199 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; + +/** + * Reset current HEAD to the specified state - `git reset` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class ResetCommand extends Command +{ + + /** + * Resets the index entries for all **$paths** to their state at **$commit** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset(); + * ``` + * + * @param string|array|\Traversable $paths The paths to reset + * @param string $commit The commit + * + * @return bool + */ + public function __invoke($paths, $commit = null) + { + $builder = $this->git->getProcessBuilder() + ->add('reset'); + + if ($commit) { + $builder->add($commit)->add('--'); + } + + if (!is_array($paths) && !($paths instanceof \Traversable)) { + $paths = array($paths); + } + + foreach ($paths as $path) { + $builder->add($path); + } + + try { + $this->git->run($builder->getProcess()); + } catch (GitException $e) { + // Confirm exit code + } + + return true; + } + + /** + * Resets the current branch head to **$commit** + * + * Does not touch the index file nor the working tree at all (but resets the head to **$commit**, + * just like all modes do). + * This leaves all your changed files "Changes to be committed", as git status would put it. + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset->soft(); + * ``` + * + * @param string $commit The commit + * + * @return bool + */ + public function soft($commit = null) + { + return $this->mode('soft', $commit); + } + + /** + * Resets the current branch head to **$commit** + * + * Resets the index but not the working tree (i.e., the changed files are preserved but not marked for commit) + * and reports what has not been updated. This is the default action. + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset->mixed(); + * ``` + * + * @param string $commit The commit + * + * @return bool + */ + public function mixed($commit = null) + { + return $this->mode('mixed', $commit); + } + + /** + * Resets the current branch head to **$commit** + * + * Resets the index and working tree. Any changes to tracked files in the working tree since **$commit** are discarded + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset->hard(); + * ``` + * + * @param string $commit The commit + * + * @return bool + */ + public function hard($commit = null) + { + return $this->mode('hard', $commit); + } + + /** + * Resets the current branch head to **$commit** + * + * Resets the index and updates the files in the working tree that are different between **$commit** and HEAD, + * but keeps those which are different between the index and working tree + * (i.e. which have changes which have not been added). If a file that is different between **$commit** and + * the index has unstaged changes, reset is aborted + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset->merge(); + * ``` + * + * @param string $commit The commit + * + * @return bool + */ + public function merge($commit = null) + { + return $this->mode('merge', $commit); + } + + /** + * Resets the current branch head to **$commit** + * + * Resets index entries and updates files in the working tree that are different between **$commit** and HEAD. + * If a file that is different between **$commit** and HEAD has local changes, reset is aborted. + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset->keep(); + * ``` + * + * @param string $commit The commit + * + * @return bool + */ + public function keep($commit = null) + { + return $this->mode('keep', $commit); + } + + /** + * Resets the current branch head to **$commit** + * + * Possibly updates the index (resetting it to the tree of **$commit**) and the working tree depending on **$mode** + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->reset->mode('hard'); + * ``` + * + * @param string $mode --<mode> + * @param string $commit The commit + * + * @throws \InvalidArgumentException + * @return bool + */ + public function mode($mode, $commit = null) + { + if (!in_array($mode, array('soft', 'mixed', 'hard', 'merge', 'keep'))) { + throw new \InvalidArgumentException('$mode must be one of the following: soft, mixed, hard, merge, keep'); + } + + $builder = $this->git->getProcessBuilder() + ->add('reset') + ->add('--' . $mode); + + if ($commit) { + $builder->add($commit); + } + + $this->git->run($builder->getProcess()); + + return true; + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/RmCommand.php b/library/kzykhys/git/src/PHPGit/Command/RmCommand.php new file mode 100644 index 000000000..d6da31230 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/RmCommand.php @@ -0,0 +1,97 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Remove files from the working tree and from the index - `git rm` + * + * @author Kazuyuki Hayashi + */ +class RmCommand extends Command +{ + + /** + * Remove files from the working tree and from the index + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->rm('CHANGELOG-1.0-1.1.txt', ['force' => true]); + * ``` + * + * ##### Options + * + * - **force** (_boolean_) Override the up-to-date check + * - **cached** (_boolean_) Unstage and remove paths only from the index + * - **recursive** (_boolean_) Allow recursive removal when a leading directory name is given + * + * @param string|array|\Traversable $file Files to remove. Fileglobs (e.g. *.c) can be given to remove all matching files. + * @param array $options [optional] An array of options {@see RmCommand::setDefaultOptions} + * + * @return bool + */ + public function __invoke($file, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('rm'); + + $this->addFlags($builder, $options, array('force', 'cached')); + + if ($options['recursive']) { + $builder->add('-r'); + } + + if (!is_array($file) && !($file instanceof \Traversable)) { + $file = array($file); + } + + foreach ($file as $value) { + $builder->add($value); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Equivalent to $git->rm($file, ['cached' => true]); + * + * ##### Options + * + * - **force** (_boolean_) Override the up-to-date check + * - **recursive** (_boolean_) Allow recursive removal when a leading directory name is given + * + * @param string|array|\Traversable $file Files to remove. Fileglobs (e.g. *.c) can be given to remove all matching files. + * @param array $options [optional] An array of options {@see RmCommand::setDefaultOptions} + * + * @return bool + */ + public function cached($file, array $options = array()) + { + $options['cached'] = true; + + return $this->__invoke($file, $options); + } + + /** + * {@inheritdoc} + * + * - **force** (_boolean_) Override the up-to-date check + * - **cached** (_boolean_) Unstage and remove paths only from the index + * - **recursive** (_boolean_) Allow recursive removal when a leading directory name is given + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'force' => false, + 'cached' => false, + 'recursive' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php b/library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php new file mode 100644 index 000000000..23c66e464 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/ShortlogCommand.php @@ -0,0 +1,134 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; + +/** + * Summarize 'git log' output - `git shortlog` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class ShortlogCommand extends Command +{ + + /** + * Summarize 'git log' output + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $shortlog = $git->shortlog(); + * ``` + * + * ##### Output Example + * + * ``` php + * [ + * 'John Doe <john@example.com>' => [ + * 0 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-10 12:56:15 +0300'), 'subject' => 'Update README'], + * 1 => ['commit' => '589de67', 'date' => new \DateTime('2014-02-15 12:56:15 +0300'), 'subject' => 'Update README'], + * ], + * //... + * ] + * ``` + * @param string|array|\Traversable $commits [optional] Defaults to HEAD + * + * @return array + */ + public function __invoke($commits = 'HEAD') + { + $builder = $this->git->getProcessBuilder() + ->add('shortlog') + ->add('--numbered') + ->add('--format=') + ->add('-w256,2,2') + ->add('-e'); + + if (!is_array($commits) && !($commits instanceof \Traversable)) { + $commits = array($commits); + } + + foreach ($commits as $commit) { + $builder->add($commit); + } + + $process = $builder->getProcess(); + $process->setCommandLine(str_replace('--format=', '--format=%h|%ci|%s', $process->getCommandLine())); + + $output = $this->git->run($process); + $lines = $this->split($output); + $result = array(); + $author = null; + + foreach ($lines as $line) { + if (substr($line, 0, 1) != ' ') { + if (preg_match('/([^<>]*? <[^<>]+>)/', $line, $matches)) { + $author = $matches[1]; + $result[$author] = array(); + } + continue; + } + + list ($commit, $date, $subject) = explode('|', trim($line), 3); + $result[$author][] = array( + 'commit' => $commit, + 'date' => new \DateTime($date), + 'subject' => $subject + ); + } + + return $result; + } + + /** + * Suppress commit description and provide a commit count summary only + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $shortlog = $git->shortlog->summary(); + * ``` + * + * ##### Output Example + * + * ``` php + * [ + * 'John Doe <john@example.com>' => 153, + * //... + * ] + * ``` + * + * @param string $commits [optional] Defaults to HEAD + * + * @return array + */ + public function summary($commits = 'HEAD') + { + $builder = $this->git->getProcessBuilder() + ->add('shortlog') + ->add('--numbered') + ->add('--summary') + ->add('-e'); + + if (!is_array($commits) && !($commits instanceof \Traversable)) { + $commits = array($commits); + } + + foreach ($commits as $commit) { + $builder->add($commit); + } + + $output = $this->git->run($builder->getProcess()); + $lines = $this->split($output); + $result = array(); + + foreach ($lines as $line) { + list ($commits, $author) = explode("\t", trim($line), 2); + $result[$author] = (int) $commits; + } + + return $result; + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/ShowCommand.php b/library/kzykhys/git/src/PHPGit/Command/ShowCommand.php new file mode 100644 index 000000000..866388357 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/ShowCommand.php @@ -0,0 +1,70 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Show various types of objects - `git show` + * + * @author Kazuyuki Hayashi + */ +class ShowCommand extends Command +{ + + /** + * Shows one or more objects (blobs, trees, tags and commits) + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * echo $git->show('3ddee587e209661c8265d5bfd0df999836f6dfa2'); + * ``` + * + * ##### Options + * + * - **format** (_string_) Pretty-print the contents of the commit logs in a given format, where <format> can be one of oneline, short, medium, full, fuller, email, raw and format:<string> + * - **abbrev-commit** (_boolean_) Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix + * + * @param string $object The names of objects to show + * @param array $options [optional] An array of options {@see ShowCommand::setDefaultOptions} + * + * @return string + */ + public function __invoke($object, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('show'); + + $this->addFlags($builder, $options, array('abbrev-commit')); + + if ($options['format']) { + $builder->add('--format=' . $options['format']); + } + + $builder->add($object); + + return $this->git->run($builder->getProcess()); + } + + /** + * {@inheritdoc} + * + * - **format** (_string_) Pretty-print the contents of the commit logs in a given format, where <format> can be one of oneline, short, medium, full, fuller, email, raw and format:<string> + * - **abbrev-commit** (_boolean_) Instead of showing the full 40-byte hexadecimal commit object name, show only a partial prefix + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'format' => null, + 'abbrev-commit' => false + )); + + $resolver->setAllowedTypes(array( + 'format' => array('null', 'string'), + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/StashCommand.php b/library/kzykhys/git/src/PHPGit/Command/StashCommand.php new file mode 100644 index 000000000..52dceaa6b --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/StashCommand.php @@ -0,0 +1,309 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; + +/** + * Stash the changes in a dirty working directory away - `git stash` + * + * @author Kazuyuki Hayashi + */ +class StashCommand extends Command +{ + + /** + * Save your local modifications to a new stash, and run git reset --hard to revert them + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash(); + * ``` + * + * @return bool + */ + public function __invoke() + { + $builder = $this->git->getProcessBuilder() + ->add('stash'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Save your local modifications to a new stash, and run git reset --hard to revert them. + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash->save('My stash'); + * ``` + * + * @param string $message [optional] The description along with the stashed state + * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} + * + * @return bool + */ + public function save($message = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('save'); + + $builder->add($message); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Returns the stashes that you currently have + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $stashes = $git->stash->lists(); + * ``` + * + * ##### Output Example + * + * ``` php + * [ + * 0 => ['branch' => 'master', 'message' => '0e2f473 Fixes README.md'], + * 1 => ['branch' => 'master', 'message' => 'ce1ddde Initial commit'], + * ] + * ``` + * + * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} + * + * @return array + */ + public function lists(array $options = array()) + { + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('list'); + + $output = $this->git->run($builder->getProcess()); + $lines = $this->split($output); + $list = array(); + + foreach ($lines as $line) { + if (preg_match('/stash@{(\d+)}:.* [Oo]n (.*): (.*)/', $line, $matches)) { + $list[$matches[1]] = array( + 'branch' => $matches[2], + 'message' => $matches[3] + ); + } + } + + return $list; + } + + /** + * Show the changes recorded in the stash as a diff between the stashed state and its original parent + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * echo $git->stash->show('stash@{0}'); + * ``` + * + * ##### Output Example + * + * ``` + * REAMDE.md | 2 +- + * 1 files changed, 1 insertions(+), 1 deletions(-) + * ``` + * + * @param string $stash The stash to show + * + * @return string + */ + public function show($stash = null) + { + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('show'); + + if ($stash) { + $builder->add($stash); + } + + return $this->git->run($builder->getProcess()); + } + + /** + * Remove a single stashed state from the stash list + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash->drop('stash@{0}'); + * ``` + * + * @param string $stash The stash to drop + * + * @return mixed + */ + public function drop($stash = null) + { + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('drop'); + + if ($stash) { + $builder->add($stash); + } + + return $this->git->run($builder->getProcess()); + } + + /** + * Remove a single stashed state from the stash list and apply it on top of the current working tree state + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash->pop('stash@{0}'); + * ``` + * + * @param string $stash The stash to pop + * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} + * + * @return bool + */ + public function pop($stash = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('pop'); + + $this->addFlags($builder, $options, array('index')); + + if ($stash) { + $builder->add($stash); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Like pop, but do not remove the state from the stash list + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash->apply('stash@{0}'); + * ``` + * + * @param string $stash The stash to apply + * @param array $options [optional] An array of options {@see StashCommand::setDefaultOptions} + * + * @return bool + */ + public function apply($stash = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('apply'); + + $this->addFlags($builder, $options, array('index')); + + if ($stash) { + $builder->add($stash); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Creates and checks out a new branch named <branchname> starting from the commit at which the <stash> was originally created, applies the changes recorded in <stash> to the new working tree and index + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash->branch('hotfix', 'stash@{0}'); + * ``` + * + * @param string $name The name of the branch + * @param string $stash The stash + * + * @return bool + */ + public function branch($name, $stash = null) + { + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('branch') + ->add($name); + + if ($stash) { + $builder->add($stash); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Remove all the stashed states + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->stash->clear(); + * ``` + * + * @return bool + */ + public function clear() + { + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('clear'); + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Create a stash (which is a regular commit object) and return its object name, without storing it anywhere in the ref namespace + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $commit = $git->stash->create(); + * ``` + * + * ##### Output Example + * + * ``` + * 877316ea6f95c43b7ccc2c2a362eeedfa78b597d + * ``` + * + * @return string + */ + public function create() + { + $builder = $this->git->getProcessBuilder() + ->add('stash') + ->add('create'); + + return $this->git->run($builder->getProcess()); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php b/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php new file mode 100644 index 000000000..c2bc983fe --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/StatusCommand.php @@ -0,0 +1,147 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Show the working tree status - `git status` + * + * = unmodified + * M = modified + * A = added + * D = deleted + * R = renamed + * C = copied + * U = updated but unmerged + * + * X Y Meaning + * ------------------------------------------------- + * [MD] not updated + * M [ MD] updated in index + * A [ MD] added to index + * D [ M] deleted from index + * R [ MD] renamed in index + * C [ MD] copied in index + * [MARC] index and work tree matches + * [ MARC] M work tree changed since index + * [ MARC] D deleted in work tree + * ------------------------------------------------- + * D D unmerged, both deleted + * A U unmerged, added by us + * U D unmerged, deleted by them + * U A unmerged, added by them + * D U unmerged, deleted by us + * A A unmerged, both added + * U U unmerged, both modified + * ------------------------------------------------- + * ? ? untracked + * ! ! ignored + * ------------------------------------------------- + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class StatusCommand extends Command +{ + + const UNMODIFIED = ' '; + const MODIFIED = 'M'; + const ADDED = 'A'; + const DELETED = 'D'; + const RENAMED = 'R'; + const COPIED = 'C'; + const UPDATED_BUT_UNMERGED = 'U'; + const UNTRACKED = '?'; + const IGNORED = '!'; + + /** + * Returns the working tree status + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $status = $git->status(); + * ``` + * + * ##### Constants + * + * - StatusCommand::UNMODIFIED [=' '] unmodified + * - StatusCommand::MODIFIED [='M'] modified + * - StatusCommand::ADDED [='A'] added + * - StatusCommand::DELETED [='D'] deleted + * - StatusCommand::RENAMED [='R'] renamed + * - StatusCommand::COPIED [='C'] copied + * - StatusCommand::UPDATED_BUT_UNMERGED [='U'] updated but unmerged + * - StatusCommand::UNTRACKED [='?'] untracked + * - StatusCommand::IGNORED [='!'] ignored + * + * ##### Output Example + * + * ``` php + * [ + * 'branch' => 'master', + * 'changes' => [ + * ['file' => 'item1.txt', 'index' => 'A', 'work_tree' => 'M'], + * ['file' => 'item2.txt', 'index' => 'A', 'work_tree' => ' '], + * ['file' => 'item3.txt', 'index' => '?', 'work_tree' => '?'], + * ] + * ] + * ``` + * + * ##### Options + * + * - **ignored** (_boolean_) Show ignored files as well + * + * @param array $options [optional] An array of options {@see StatusCommand::setDefaultOptions} + * + * @return mixed + */ + public function __invoke(array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('status') + ->add('--porcelain')->add('-s')->add('-b')->add('--null'); + + $this->addFlags($builder, $options); + + $process = $builder->getProcess(); + $result = array('branch' => null, 'changes' => array()); + $output = $this->git->run($process); + + list($branch, $changes) = preg_split('/(\0|\n)/', $output, 2); + $lines = $this->split($changes, true); + + if (substr($branch, -11) == '(no branch)') { + $result['branch'] = null; + } elseif (preg_match('/([^ ]*)\.\.\..*?\[.*?\]$/', $branch, $matches)) { + $result['branch'] = $matches[1]; + } elseif (preg_match('/ ([^ ]*)$/', $branch, $matches)) { + $result['branch'] = $matches[1]; + } + + foreach ($lines as $line) { + $result['changes'][] = array( + 'file' => substr($line, 3), + 'index' => substr($line, 0, 1), + 'work_tree' => substr($line, 1, 1) + ); + } + + return $result; + } + + /** + * {@inheritdoc} + * + * - **ignored** (_boolean_) Show ignored files as well + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'ignored' => false + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/TagCommand.php b/library/kzykhys/git/src/PHPGit/Command/TagCommand.php new file mode 100644 index 000000000..197d3e887 --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/TagCommand.php @@ -0,0 +1,156 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\OptionsResolver\OptionsResolverInterface; + +/** + * Create, list, delete or verify a tag object signed with GPG - `git tag` + * + * @author Kazuyuki Hayashi + */ +class TagCommand extends Command +{ + + /** + * Returns an array of tags + * + * ``` php + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); + * $git->setRepository('/path/to/repo'); + * $tags = $git->tag(); + * ``` + * + * ##### Output Example + * + * ``` + * ['v1.0.0', 'v1.0.1', 'v1.0.2'] + * ``` + * + * @throws GitException + * @return array + */ + public function __invoke() + { + $builder = $this->git->getProcessBuilder() + ->add('tag'); + + $output = $this->git->run($builder->getProcess()); + + return $this->split($output); + } + + /** + * Creates a tag object + * + * ``` php + * $git = new PHPGit\Git(); + * $git->setRepository('/path/to/repo'); + * $git->tag->create('v1.0.0'); + * ``` + * + * ##### Options + * + * - **annotate** (_boolean_) Make an unsigned, annotated tag object + * - **sign** (_boolean_) Make a GPG-signed tag, using the default e-mail address’s key + * - **force** (_boolean_) Replace an existing tag with the given name (instead of failing) + * + * @param string $tag The name of the tag to create + * @param string $commit The SHA1 object name of the commit object + * @param array $options [optional] An array of options {@see TagCommand::setDefaultOptions} + * + * @throws GitException + * @return bool + */ + public function create($tag, $commit = null, array $options = array()) + { + $options = $this->resolve($options); + $builder = $this->git->getProcessBuilder() + ->add('tag') + ->add($tag); + + $this->addFlags($builder, $options, array('annotate', 'sign', 'force')); + + if ($commit) { + $builder->add($commit); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Delete existing tags with the given names + * + * @param string|array|\Traversable $tag The name of the tag to create + * + * @throws GitException + * @return bool + */ + public function delete($tag) + { + $builder = $this->git->getProcessBuilder() + ->add('tag') + ->add('-d'); + + if (!is_array($tag) && !($tag instanceof \Traversable)) { + $tag = array($tag); + } + + foreach ($tag as $value) { + $builder->add($value); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * Verify the gpg signature of the given tag names + * + * @param string|array|\Traversable $tag The name of the tag to create + * + * @throws GitException + * @return bool + */ + public function verify($tag) + { + $builder = $this->git->getProcessBuilder() + ->add('tag') + ->add('-v'); + + if (!is_array($tag) && !($tag instanceof \Traversable)) { + $tag = array($tag); + } + + foreach ($tag as $value) { + $builder->add($value); + } + + $this->git->run($builder->getProcess()); + + return true; + } + + /** + * {@inheritdoc} + * + * - **annotate** (_boolean_) Make an unsigned, annotated tag object + * - **sign** (_boolean_) Make a GPG-signed tag, using the default e-mail address’s key + * - **force** (_boolean_) Replace an existing tag with the given name (instead of failing) + */ + public function setDefaultOptions(OptionsResolverInterface $resolver) + { + $resolver->setDefaults(array( + 'annotate' => false, + 'sign' => false, + 'force' => false, + )); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Command/TreeCommand.php b/library/kzykhys/git/src/PHPGit/Command/TreeCommand.php new file mode 100644 index 000000000..ea1040a6a --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Command/TreeCommand.php @@ -0,0 +1,70 @@ +<?php + +namespace PHPGit\Command; + +use PHPGit\Command; + +/** + * List the contents of a tree object - `git ls-tree` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class TreeCommand extends Command +{ + + /** + * Returns the contents of a tree object + * + * ``` php + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); + * $git->setRepository('/path/to/repo'); + * $tree = $git->tree('master'); + * ``` + * + * ##### Output Example + * + * ``` php + * [ + * ['mode' => '100644', 'type' => 'blob', 'hash' => '1f100ce9855b66111d34b9807e47a73a9e7359f3', 'file' => '.gitignore', 'sort' => '2:.gitignore'], + * ['mode' => '100644', 'type' => 'blob', 'hash' => 'e0bfe494537037451b09c32636c8c2c9795c05c0', 'file' => '.travis.yml', 'sort' => '2:.travis.yml'], + * ['mode' => '040000', 'type' => 'tree', 'hash' => '8d5438e79f77cd72de80c49a413f4edde1f3e291', 'file' => 'bin', 'sort' => '1:.bin'], + * ] + * ``` + * + * @param string $branch The commit + * @param string $path The path + * + * @return array + */ + public function __invoke($branch = 'master', $path = '') + { + $objects = array(); + $builder = $this->git->getProcessBuilder(); + $process = $builder->add('ls-tree')->add($branch . ':' . $path)->getProcess(); + $output = $this->git->run($process); + $lines = $this->split($output); + + $types = array( + 'submodule' => 0, + 'tree' => 1, + 'blob' => 2 + ); + + foreach ($lines as $line) { + list($meta, $file) = explode("\t", $line); + list($mode, $type, $hash) = explode(" ", $meta); + + $objects[] = array( + 'sort' => sprintf('%d:%s', $types[$type], $file), + 'mode' => $mode, + 'type' => $type, + 'hash' => $hash, + 'file' => $file + ); + } + + return $objects; + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Exception/GitException.php b/library/kzykhys/git/src/PHPGit/Exception/GitException.php new file mode 100644 index 000000000..f5901010c --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Exception/GitException.php @@ -0,0 +1,39 @@ +<?php + +namespace PHPGit\Exception; + +/** + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class GitException extends \Exception +{ + + /** + * @var string + */ + protected $commandLine; + + /** + * Construct the exception. Note: The message is NOT binary safe. + * + * @param string $message [optional] The Exception message to throw. + * @param int $code [optional] The Exception code. + * @param string $commandLine [optional] Command-line + * @param \Exception $previous [optional] The previous exception used for the exception chaining. Since 5.3.0 + */ + public function __construct($message = "", $code = 0, $commandLine = null, \Exception $previous = null) + { + parent::__construct($message, $code, $previous); + + $this->commandLine = $commandLine; + } + + /** + * @return null|string + */ + public function getCommandLine() + { + return $this->commandLine; + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/src/PHPGit/Git.php b/library/kzykhys/git/src/PHPGit/Git.php new file mode 100644 index 000000000..f952d6f1f --- /dev/null +++ b/library/kzykhys/git/src/PHPGit/Git.php @@ -0,0 +1,308 @@ +<?php + +namespace PHPGit; + +use PHPGit\Command; +use PHPGit\Exception\GitException; +use Symfony\Component\Process\Process; +use Symfony\Component\Process\ProcessBuilder; + +/** + * PHPGit - A Git wrapper for PHP5.3+ + * ================================== + * + * [![Latest Unstable Version](https://poser.pugx.org/kzykhys/git/v/unstable.png)](https://packagist.org/packages/kzykhys/git) + * [![Build Status](https://travis-ci.org/kzykhys/PHPGit.png?branch=master)](https://travis-ci.org/kzykhys/PHPGit) + * [![Coverage Status](https://coveralls.io/repos/kzykhys/PHPGit/badge.png)](https://coveralls.io/r/kzykhys/PHPGit) + * [![SensioLabsInsight](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f/mini.png)](https://insight.sensiolabs.com/projects/04f10b57-a113-47ad-8dda-9a6dacbb079f) + * + * Requirements + * ------------ + * + * * PHP5.3 + * * Git + * + * Installation + * ------------ + * + * Update your composer.json and run `composer update` + * + * ``` json + * { + * "require": { + * "kzykhys/git": "dev-master" + * } + * } + * ``` + * + * Basic Usage + * ----------- + * + * ``` php + * <?php + * + * require __DIR__ . '/vendor/autoload.php'; + * + * $git = new PHPGit\Git(); + * $git->clone('https://github.com/kzykhys/PHPGit.git', '/path/to/repo'); + * $git->setRepository('/path/to/repo'); + * $git->remote->add('production', 'git://example.com/your/repo.git'); + * $git->add('README.md'); + * $git->commit('Adds README.md'); + * $git->checkout('release'); + * $git->merge('master'); + * $git->push(); + * $git->push('production', 'release'); + * $git->tag->create('v1.0.1', 'release'); + * + * foreach ($git->tree('release') as $object) { + * if ($object['type'] == 'blob') { + * echo $git->show($object['file']); + * } + * } + * ``` + * + * @author Kazuyuki Hayashi <hayashi@valnur.net> + * @license MIT + * + * @method add($file, $options = array()) Add file contents to the index + * @method archive($file, $tree = null, $path = null, $options = array()) Create an archive of files from a named tree + * @method branch($options = array()) List both remote-tracking branches and local branches + * @method checkout($branch, $options = array()) Checkout a branch or paths to the working tree + * @method clone($repository, $path = null, $options = array()) Clone a repository into a new directory + * @method commit($message = '', $options = array()) Record changes to the repository + * @method config($options = array()) List all variables set in config file + * @method describe($committish = null, $options = array()) Returns the most recent tag that is reachable from a commit + * @method fetch($repository, $refspec = null, $options = array()) Fetches named heads or tags from one or more other repositories + * @method init($path, $options = array()) Create an empty git repository or reinitialize an existing one + * @method log($path = null, $options = array()) Returns the commit logs + * @method merge($commit, $message = null, $options = array()) Incorporates changes from the named commits into the current branch + * @method mv($source, $destination, $options = array()) Move or rename a file, a directory, or a symlink + * @method pull($repository = null, $refspec = null, $options = array()) Fetch from and merge with another repository or a local branch + * @method push($repository = null, $refspec = null, $options = array()) Update remote refs along with associated objects + * @method rebase($upstream = null, $branch = null, $options = array()) Forward-port local commits to the updated upstream head + * @method remote() Returns an array of existing remotes + * @method reset($commit = null, $paths = array()) Resets the index entries for all <paths> to their state at <commit> + * @method rm($file, $options = array()) Remove files from the working tree and from the index + * @method shortlog($commits = array()) Summarize 'git log' output + * @method show($object, $options = array()) Shows one or more objects (blobs, trees, tags and commits) + * @method stash() Save your local modifications to a new stash, and run git reset --hard to revert them + * @method status($options = array()) Show the working tree status + * @method tag() Returns an array of tags + * @method tree($branch = 'master', $path = '') List the contents of a tree object + */ +class Git +{ + + /** @var Command\AddCommand */ + public $add; + + /** @var Command\ArchiveCommand */ + public $archive; + + /** @var Command\BranchCommand */ + public $branch; + + /** @var Command\CatCommand */ + public $cat; + + /** @var Command\CheckoutCommand */ + public $checkout; + + /** @var Command\CloneCommand */ + public $clone; + + /** @var Command\CommitCommand */ + public $commit; + + /** @var Command\ConfigCommand */ + public $config; + + /** @var Command\DescribeCommand */ + public $describe; + + // Not implemented yet + public $diff; + + /** @var Command\FetchCommand */ + public $fetch; + + /** @var Command\InitCommand */ + public $init; + + /** @var Command\LogCommand */ + public $log; + + /** @var Command\MergeCommand */ + public $merge; + + /** @var Command\MvCommand */ + public $mv; + + /** @var Command\PullCommand */ + public $pull; + + /** @var Command\PushCommand */ + public $push; + + /** @var Command\RebaseCommand */ + public $rebase; + + /** @var Command\RemoteCommand */ + public $remote; + + /** @var Command\ResetCommand */ + public $reset; + + /** @var Command\RmCommand */ + public $rm; + + /** @var Command\ShortlogCommand */ + public $shortlog; + + /** @var Command\ShowCommand */ + public $show; + + /** @var Command\StashCommand */ + public $stash; + + /** @var Command\StatusCommand */ + public $status; + + /** @var Command\TagCommand */ + public $tag; + + /** @var Command\TreeCommand */ + public $tree; + + /** @var string */ + private $bin = 'git'; + + /** @var string */ + private $directory = '.'; + + /** + * Initializes sub-commands + */ + public function __construct() + { + $this->add = new Command\AddCommand($this); + $this->archive = new Command\ArchiveCommand($this); + $this->branch = new Command\BranchCommand($this); + $this->cat = new Command\CatCommand($this); + $this->checkout = new Command\CheckoutCommand($this); + $this->clone = new Command\CloneCommand($this); + $this->commit = new Command\CommitCommand($this); + $this->config = new Command\ConfigCommand($this); + $this->describe = new Command\DescribeCommand($this); + $this->fetch = new Command\FetchCommand($this); + $this->init = new Command\InitCommand($this); + $this->log = new Command\LogCommand($this); + $this->merge = new Command\MergeCommand($this); + $this->mv = new Command\MvCommand($this); + $this->pull = new Command\PullCommand($this); + $this->push = new Command\PushCommand($this); + $this->rebase = new Command\RebaseCommand($this); + $this->remote = new Command\RemoteCommand($this); + $this->reset = new Command\ResetCommand($this); + $this->rm = new Command\RmCommand($this); + $this->shortlog = new Command\ShortlogCommand($this); + $this->show = new Command\ShowCommand($this); + $this->stash = new Command\StashCommand($this); + $this->status = new Command\StatusCommand($this); + $this->tag = new Command\TagCommand($this); + $this->tree = new Command\TreeCommand($this); + } + + /** + * Calls sub-commands + * + * @param string $name The name of a property + * @param array $arguments An array of arguments + * + * @throws \BadMethodCallException + * @return mixed + */ + public function __call($name, $arguments) + { + if (isset($this->{$name}) && is_callable($this->{$name})) { + return call_user_func_array($this->{$name}, $arguments); + } + + throw new \BadMethodCallException(sprintf('Call to undefined method PHPGit\Git::%s()', $name)); + } + + /** + * Sets the Git binary path + * + * @param string $bin + * + * @return Git + */ + public function setBin($bin) + { + $this->bin = $bin; + + return $this; + } + + /** + * Sets the Git repository path + * + * @var string $directory + * + * @return Git + */ + public function setRepository($directory) + { + $this->directory = $directory; + + return $this; + } + + /** + * Returns version number + * + * @return mixed + */ + public function getVersion() + { + $process = $this->getProcessBuilder() + ->add('--version') + ->getProcess(); + + return $this->run($process); + } + + /** + * Returns an instance of ProcessBuilder + * + * @return ProcessBuilder + */ + public function getProcessBuilder() + { + return ProcessBuilder::create() + ->setPrefix($this->bin) + ->setWorkingDirectory($this->directory); + } + + /** + * Executes a process + * + * @param Process $process The process to run + * + * @throws Exception\GitException + * @return mixed + */ + public function run(Process $process) + { + $process->run(); + + if (!$process->isSuccessful()) { + throw new GitException($process->getErrorOutput(), $process->getExitCode(), $process->getCommandLine()); + } + + return $process->getOutput(); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/BaseTestCase.php b/library/kzykhys/git/test/PHPGit/BaseTestCase.php new file mode 100644 index 000000000..df69b216e --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/BaseTestCase.php @@ -0,0 +1,33 @@ +<?php + +use Symfony\Component\Filesystem\Filesystem; + +/** + * @author Kazuyuki Hayashi <hayashi@siance.co.jp> + */ +abstract class BaseTestCase extends PHPUnit_Framework_TestCase +{ + + /** + * @var string + */ + protected $directory; + + /** + * {@inheritdoc} + */ + public function setUp() + { + $this->directory = __DIR__.'/../../build/' . strtolower(get_class($this)); + } + + /** + * {@inheritdoc} + */ + public function tearDown() + { + $filesystem = new Filesystem(); + $filesystem->remove($this->directory); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php new file mode 100644 index 000000000..1fad08417 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/AddCommandTest.php @@ -0,0 +1,42 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +/** + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class AddCommandTest extends BaseTestCase +{ + + public function testAdd() + { + $filesystem = new Filesystem(); + $filesystem->mkdir($this->directory); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $filesystem->dumpFile($this->directory . '/test.md', '**foo**'); + + $this->assertTrue($git->add('test.txt')); + $this->assertTrue($git->add(array('test.md'), array('force' => true))); + } + + /** + * @expectedException \PHPGit\Exception\GitException + * @expectedExceptionCode 128 + */ + public function testException() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->add('foo'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php new file mode 100644 index 000000000..982c8f7c7 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/ArchiveCommandTest.php @@ -0,0 +1,32 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +/** + * @author Kazuyuki Hayashi <hayashi@valnur.net> + */ +class ArchiveCommandTest extends BaseTestCase +{ + + public function testArchive() + { + $filesystem = new Filesystem(); + $filesystem->mkdir($this->directory); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'hello'); + $git->add('test.txt'); + $git->commit('Initial commit'); + + $git->archive($this->directory . '/test.zip', 'master', null, array('format' => 'zip', 'prefix' => 'test/')); + + $this->assertFileExists($this->directory . '/test.zip'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php new file mode 100644 index 000000000..4deeea367 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/BranchCommandTest.php @@ -0,0 +1,106 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class BranchCommandTest extends BaseTestCase +{ + + public function setUp() + { + parent::setUp(); + + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', ''); + $git->add('test.txt'); + $git->commit('Initial commit'); + } + + public function testBranch() + { + $git = new Git(); + $git->setRepository($this->directory); + + $branches = $git->branch(); + + $this->assertCount(1, $branches); + $this->assertEquals('master', $branches['master']['name']); + $this->assertTrue($branches['master']['current']); + $this->assertEquals('Initial commit', $branches['master']['title']); + } + + public function testAllBranch() + { + $git = new Git(); + $git->clone('file://' . realpath($this->directory), $this->directory.'2'); + $git->setRepository($this->directory.'2'); + + $branches = $git->branch(array('remotes' => true)); + $this->assertArrayHasKey('origin/master', $branches); + + $branches = $git->branch(array('all' => true)); + $this->assertArrayHasKey('master', $branches); + $this->assertArrayHasKey('remotes/origin/master', $branches); + + $filesystem = new Filesystem(); + $filesystem->remove($this->directory.'2'); + } + + public function testBranchCreate() + { + $git = new Git(); + $git->setRepository($this->directory); + + $git->branch->create('1.0'); + $branches = $git->branch(); + $this->assertCount(2, $branches); + + $git->branch->create('1.0-fix', '1.0', array('force' => true)); + $branches = $git->branch(); + $this->assertCount(3, $branches); + $this->assertArrayHasKey('1.0', $branches); + $this->assertArrayHasKey('1.0-fix', $branches); + } + + public function testBranchMove() + { + $git = new Git(); + $git->setRepository($this->directory); + $git->branch->create('1.0'); + $git->branch->move('1.0', '1.0.x'); + $branches = $git->branch(); + $this->assertCount(2, $branches); + $this->assertArrayHasKey('1.0.x', $branches); + + $git->branch->move('1.0.x', '2.x', array('force' => true)); + $branches = $git->branch(); + $this->assertCount(2, $branches); + $this->assertArrayHasKey('2.x', $branches); + } + + public function testBranchDelete() + { + $git = new Git(); + $git->setRepository($this->directory); + $git->branch->create('1.0'); + $git->branch->create('2.0'); + $branches = $git->branch(); + $this->assertCount(3, $branches); + + $git->branch->delete('1.0'); + $branches = $git->branch(); + $this->assertCount(2, $branches); + + $git->branch->delete('2.0', array('force' => true)); + $branches = $git->branch(); + $this->assertCount(1, $branches); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php new file mode 100644 index 000000000..945924ccb --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/CatCommandTest.php @@ -0,0 +1,65 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class CatCommandTest extends BaseTestCase +{ + + public function testCatBlob() + { + $filesystem = new Filesystem(); + $filesystem->mkdir($this->directory); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('Initial commit'); + + $tree = $git->tree(); + + $this->assertEquals('foo', $git->cat->blob($tree[0]['hash'])); + } + + public function testCatType() + { + $filesystem = new Filesystem(); + $filesystem->mkdir($this->directory); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('Initial commit'); + + $tree = $git->tree(); + + $this->assertEquals('blob', $git->cat->type($tree[0]['hash'])); + } + + public function testCatSize() + { + $filesystem = new Filesystem(); + $filesystem->mkdir($this->directory); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('Initial commit'); + + $tree = $git->tree(); + + $this->assertEquals(3, $git->cat->size($tree[0]['hash'])); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php new file mode 100644 index 000000000..c306ea407 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/CheckoutCommandTest.php @@ -0,0 +1,65 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class CheckoutCommandTest extends BaseTestCase +{ + + public function setUp() + { + parent::setUp(); + + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', ''); + $git->add('test.txt'); + $git->commit('Initial commit'); + } + + public function testCheckout() + { + $git = new Git(); + $git->setRepository($this->directory); + $git->branch->create('next'); + $git->checkout('next'); + + $branches = $git->branch(); + $this->assertArrayHasKey('next', $branches); + $this->assertTrue($branches['next']['current']); + } + + public function testCheckoutCreate() + { + $git = new Git(); + $git->setRepository($this->directory); + $git->checkout->create('next'); + + $branches = $git->branch(); + $this->assertArrayHasKey('next', $branches); + $this->assertTrue($branches['next']['current']); + + $git->checkout->create('develop', 'next'); + + $branches = $git->branch(); + $this->assertArrayHasKey('develop', $branches); + $this->assertTrue($branches['develop']['current']); + } + + public function testCheckoutOrphan() + { + $git = new Git(); + $git->setRepository($this->directory); + $git->checkout->orphan('gh-pages', 'master', array('force' => true)); + + $status = $git->status(); + $this->assertEquals('gh-pages', $status['branch']); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php new file mode 100644 index 000000000..d6a4d26ff --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/CloneCommandTest.php @@ -0,0 +1,28 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class CloneCommandTest extends BaseTestCase +{ + + public function testClone() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $this->assertFileExists($this->directory . '/.git'); + + $filesystem = new Filesystem(); + $filesystem->remove($this->directory); + + $git->setRepository('.'); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory, array('shared' => true)); + + $this->assertFileExists($this->directory . '/.git'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php new file mode 100644 index 000000000..01b50ad8d --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/CommitCommandTest.php @@ -0,0 +1,26 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class CommitCommandTest extends BaseTestCase +{ + + public function testCommit() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem = new Filesystem(); + $filesystem->dumpFile($this->directory . '/test.txt', ''); + $git->add('test.txt'); + $git->commit('Initial commit'); + $logs = $git->log('test.txt'); + + $this->assertCount(1, $logs); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php new file mode 100644 index 000000000..fba2fbf76 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/ConfigCommandTest.php @@ -0,0 +1,55 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class ConfigCommandTest extends BaseTestCase +{ + + public function testConfigSetAndList() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $before = $git->config(); + + $git->config->set('user.name', 'John Doe'); + + $config = $git->config(); + $this->assertArrayHasKey('user.name', $config); + + $expected = 'John Doe'; + + if (isset($before['user.name'])) { + $expected = $before['user.name'] . "\n" . $expected; + } + + $this->assertEquals($expected, $config['user.name']); + } + + public function testConfigAdd() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $before = $git->config(); + + $git->config->set('user.name', 'John Doe'); + $git->config->add('user.name', 'Foo'); + + $config = $git->config(); + $this->assertArrayHasKey('user.name', $config); + + $expected = "John Doe\nFoo"; + + if (isset($before['user.name'])) { + $expected = $before['user.name'] . "\n" . $expected; + } + + $this->assertEquals($expected, $config['user.name']); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php new file mode 100644 index 000000000..04d3bd3b0 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/DescribeCommandTest.php @@ -0,0 +1,36 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class DescribeCommandTest extends BaseTestCase +{ + + public function testDescribeTags() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('README.md'); + $git->commit('Initial commit'); + $git->tag->create('v1.0.0'); + $version = $git->describe->tags('HEAD'); + + $this->assertEquals('v1.0.0', $version); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello2'); + $git->add('README.md'); + $git->commit('Fixes README'); + $version = $git->describe->tags('HEAD'); + + $this->assertStringStartsWith('v1.0.0', $version); + $this->assertStringEndsNotWith('v1.0.0', $version); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php new file mode 100644 index 000000000..f52943099 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/FetchCommandTest.php @@ -0,0 +1,36 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class FetchCommandTest extends BaseTestCase +{ + + public function testFetch() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->fetch('origin', '+refs/heads/*:refs/remotes/origin/*'); + + $tags = $git->tag(); + $this->assertContains('v1.0.0', $tags); + } + + public function testFetchAll() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->fetch->all(); + + $tags = $git->tag(); + $this->assertContains('v1.0.0', $tags); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php new file mode 100644 index 000000000..208461523 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/MergeCommandTest.php @@ -0,0 +1,101 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class MergeCommandTest extends BaseTestCase +{ + + public function testMerge() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('master'); + + $git->checkout->create('develop'); + $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); + $git->add('test.txt'); + $git->commit('develop'); + + $git->checkout('master'); + + $this->assertEquals('foo', file_get_contents($this->directory . '/test.txt')); + + $git->merge('develop'); + + $this->assertEquals('bar', file_get_contents($this->directory . '/test.txt')); + } + + /** + * @expectedException \PHPGit\Exception\GitException + */ + public function testMergeFail() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + // branch:master + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('master'); + + // branch:develop + $git->checkout->create('develop'); + $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); + $git->add('test.txt'); + $git->commit('develop'); + + // branch:master + $git->checkout('master'); + $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); + $git->merge('develop'); + } + + public function testMergeAbort() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + // branch:master + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('master'); + + // branch:develop + $git->checkout->create('develop'); + $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); + $git->add('test.txt'); + $git->commit('develop'); + + // branch:master + $git->checkout('master'); + $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); + $git->add('test.txt'); + $git->commit('master'); + + try { + $git->merge('develop'); + $this->fail('$git->merge("develop") should fail'); + } catch (Exception $e) { + } + + $git->merge->abort(); + + $this->assertEquals('baz', file_get_contents($this->directory . '/test.txt')); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php new file mode 100644 index 000000000..dd5f46c55 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/MvCommandTest.php @@ -0,0 +1,26 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class MvCommandTest extends BaseTestCase +{ + + public function testMv() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('Initial commit'); + $git->mv('test.txt', 'test2.txt'); + + $this->assertFileExists($this->directory . '/test2.txt'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php new file mode 100644 index 000000000..89dec75a9 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/PullCommandTest.php @@ -0,0 +1,22 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class PullCommandTest extends BaseTestCase +{ + + public function testPull() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->pull('origin', 'master'); + + $this->assertFileExists($this->directory . '/README.md'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php new file mode 100644 index 000000000..11424cebc --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/PushCommandTest.php @@ -0,0 +1,34 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class PushCommandTest extends BaseTestCase +{ + + public function testPush() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory, array('shared' => true, 'bare' => true)); + + $git->clone('file://' . realpath($this->directory), $this->directory.'2'); + $git->setRepository($this->directory.'2'); + + $filesystem->dumpFile($this->directory.'2/test.txt', 'foobar'); + $git->add('test.txt'); + $git->commit('test'); + $git->push('origin', 'master'); + + $git->clone('file://' . realpath($this->directory), $this->directory.'3'); + + $this->assertFileExists($this->directory.'3/test.txt'); + + $filesystem->remove($this->directory.'2'); + $filesystem->remove($this->directory.'3'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php new file mode 100644 index 000000000..af7e87a19 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/RebaseCommandTest.php @@ -0,0 +1,154 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class RebaseCommandTest extends BaseTestCase +{ + + public function testRebase() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', '123'); + $git->add('test.txt'); + $git->commit('initial commit'); + + $git->checkout->create('next'); + $filesystem->dumpFile($this->directory . '/test2.txt', '123'); + $git->add('test2.txt'); + $git->commit('test'); + + $git->checkout('master'); + $git->rebase('next', 'master'); + + $this->assertFileExists($this->directory. '/test2.txt'); + } + + public function testRebaseOnto() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/test.txt', '123'); + $git->add('test.txt'); + $git->commit('initial commit'); + + $git->checkout->create('next'); + $filesystem->dumpFile($this->directory . '/test2.txt', '123'); + $git->add('test2.txt'); + $git->commit('test'); + + $git->checkout->create('topic', 'next'); + $filesystem->dumpFile($this->directory . '/test3.txt', '123'); + $git->add('test3.txt'); + $git->commit('test'); + + $git->rebase('next', null, array('onto' => 'master')); + $this->assertFileNotExists($this->directory . '/test2.txt'); + } + + public function testRebaseContinue() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('initial commit'); + + $git->checkout->create('next'); + $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); + $git->add('test.txt'); + $git->commit('next commit'); + + $git->checkout('master'); + $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); + $git->add('test.txt'); + $git->commit('master commit'); + + try { + $git->rebase('next'); + $this->fail('GitException should be thrown'); + } catch (\PHPGit\Exception\GitException $e) { + } + + $filesystem->dumpFile($this->directory . '/test.txt', 'foobar'); + $git->add('test.txt'); + $git->rebase->continues(); + } + + public function testRebaseAbort() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('initial commit'); + + $git->checkout->create('next'); + $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); + $git->add('test.txt'); + $git->commit('next commit'); + + $git->checkout('master'); + $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); + $git->add('test.txt'); + $git->commit('master commit'); + + try { + $git->rebase('next'); + $this->fail('GitException should be thrown'); + } catch (\PHPGit\Exception\GitException $e) { + } + + $git->rebase->abort(); + } + + public function testRebaseSkip() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', 'foo'); + $git->add('test.txt'); + $git->commit('initial commit'); + + $git->checkout->create('next'); + $filesystem->dumpFile($this->directory . '/test.txt', 'bar'); + $git->add('test.txt'); + $git->commit('next commit'); + + $git->checkout('master'); + $filesystem->dumpFile($this->directory . '/test.txt', 'baz'); + $git->add('test.txt'); + $git->commit('master commit'); + + try { + $git->rebase('next'); + $this->fail('GitException should be thrown'); + } catch (\PHPGit\Exception\GitException $e) { + } + + $git->rebase->skip(); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php new file mode 100644 index 000000000..4f428f832 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/Remote/SetBranchesCommandTest.php @@ -0,0 +1,28 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../../BaseTestCase.php'; + +class SetBranchesCommandTest extends BaseTestCase +{ + + public function testSetBranches() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $git->remote->branches('origin', array('master')); + } + + public function testSetBranchesAdd() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $git->remote->branches->add('origin', array('gh-pages')); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php new file mode 100644 index 000000000..679c2976f --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/Remote/SetHeadCommandTest.php @@ -0,0 +1,56 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../../BaseTestCase.php'; + +class SetHeadCommandTest extends BaseTestCase +{ + + public function testSetHead() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $before = $git->branch(array('all' => true)); + + $git->remote->head('origin', 'master'); + + $after = $git->branch(array('all' => true)); + + $this->assertEquals($before, $after); + } + + public function testSetHeadDelete() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $before = $git->branch(array('all' => true)); + + $git->remote->head->delete('origin'); + + $after = $git->branch(array('all' => true)); + + $this->assertNotEquals($before, $after); + } + + public function testSetHeadRemote() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $before = $git->branch(array('all' => true)); + + $git->remote->head->delete('origin'); + $git->remote->head->remote('origin'); + + $after = $git->branch(array('all' => true)); + + $this->assertEquals($before, $after); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php new file mode 100644 index 000000000..b70b67d40 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/Remote/SetUrlCommandTest.php @@ -0,0 +1,46 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../../BaseTestCase.php'; + +class SetUrlCommandTest extends BaseTestCase +{ + + public function testSetUrl() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'http://example.com/test.git'); + $git->remote->url('origin', 'https://github.com/kzykhys/Text.git', 'http://example.com/test.git'); + + $remotes = $git->remote(); + + $this->assertEquals('https://github.com/kzykhys/Text.git', $remotes['origin']['fetch']); + } + + public function testSetUrlAdd() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'http://example.com/test.git'); + $git->remote->url->add('origin', 'https://github.com/kzykhys/Text.git'); + } + + public function testSetUrlDelete() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'http://example.com/test.git'); + $git->remote->url->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->remote->url->delete('origin', 'https://github.com'); + + $remotes = $git->remote(); + + $this->assertEquals('http://example.com/test.git', $remotes['origin']['fetch']); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php new file mode 100644 index 000000000..78aa81309 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/RemoteCommandTest.php @@ -0,0 +1,100 @@ +<?php + +use PHPGit\Git; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class RemoteCommandTest extends BaseTestCase +{ + + public function testRemote() + { + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $remotes = $git->remote(); + + $this->assertEquals(array( + 'origin' => array( + 'fetch' => 'https://github.com/kzykhys/Text.git', + 'push' => 'https://github.com/kzykhys/Text.git' + ) + ), $remotes); + } + + public function testRemoteAdd() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + + $remotes = $git->remote(); + + $this->assertEquals(array( + 'origin' => array( + 'fetch' => 'https://github.com/kzykhys/Text.git', + 'push' => 'https://github.com/kzykhys/Text.git' + ) + ), $remotes); + } + + public function testRemoteRename() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->remote->rename('origin', 'upstream'); + + $remotes = $git->remote(); + $this->assertEquals(array( + 'upstream' => array( + 'fetch' => 'https://github.com/kzykhys/Text.git', + 'push' => 'https://github.com/kzykhys/Text.git' + ) + ), $remotes); + } + + public function testRemoteRm() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->remote->rm('origin'); + + $remotes = $git->remote(); + $this->assertEquals(array(), $remotes); + } + + public function testRemoteShow() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + + $this->assertNotEmpty($git->remote->show('origin')); + } + + public function testRemotePrune() + { + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->remote->add('origin', 'https://github.com/kzykhys/Text.git'); + $git->remote->prune('origin'); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testBadMethodCall() + { + $git = new Git(); + $git->remote->foo(); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php new file mode 100644 index 000000000..777e48512 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/ResetCommandTest.php @@ -0,0 +1,128 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + + +class ResetCommandTest extends BaseTestCase +{ + + public function testReset() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('README.md'); + + $git->reset('README.md', 'HEAD'); + } + + public function testResetSoft() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + + $git->reset->soft(); + } + + public function testResetMixed() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + + $git->reset->mixed(); + } + + public function testResetHard() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + + $git->reset->hard('HEAD'); + } + + public function testResetMerge() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + + $git->reset->merge(); + } + + public function testResetKeep() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + + $git->reset->keep(); + } + + /** + * @expectedException InvalidArgumentException + */ + public function testResetInvalidMode() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + + $git->reset->mode('foo'); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php new file mode 100644 index 000000000..34996cc12 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/RmCommandTest.php @@ -0,0 +1,51 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class RmCommandTest extends BaseTestCase +{ + + public function testRm() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $filesystem->dumpFile($this->directory . '/bin/test.php', 'foo'); + $git->add(array('README.md', 'bin/test.php')); + $git->commit('Initial commit'); + + $git->rm('README.md'); + $git->rm('bin', array('recursive' => true)); + + $this->assertFileNotExists($this->directory . '/README.md'); + } + + public function testRmCached() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/README.md', 'foo'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $git->rm->cached('README.md'); + $git->commit('Delete README.md'); + + $this->assertFileExists($this->directory . '/README.md'); + + $tree = $git->tree(); + $this->assertEquals(array(), $tree); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php new file mode 100755 index 000000000..48967cab1 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/ShortlogCommandTest.php @@ -0,0 +1,71 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class ShortlogCommandTest extends BaseTestCase +{ + + public function testShortlog() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->config->set('user.name', 'Name One'); + $git->config->set('user.email', 'one@example.com'); + $filesystem->dumpFile($this->directory . '/test.txt', ''); + $git->add('test.txt'); + $git->commit('1'); + $filesystem->dumpFile($this->directory . '/test2.txt', ''); + $git->add('test2.txt'); + $git->commit('2'); + + $git->config->set('user.name', 'Name Two'); + $git->config->set('user.email', 'two@example.com'); + $filesystem->dumpFile($this->directory . '/test3.txt', ''); + $git->add('test3.txt'); + $git->commit('3'); + + $shortlog = $git->shortlog(); + + $this->assertCount(2, $shortlog); + $this->assertCount(2, $shortlog['Name One <one@example.com>']); + $this->assertCount(1, $shortlog['Name Two <two@example.com>']); + $this->assertEquals('1', $shortlog['Name One <one@example.com>'][0]['subject']); + } + + public function testShortlogSummary() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $git->config->set('user.name', 'Name One'); + $git->config->set('user.email', 'one@example.com'); + $filesystem->dumpFile($this->directory . '/test.txt', ''); + $git->add('test.txt'); + $git->commit('1'); + $filesystem->dumpFile($this->directory . '/test2.txt', ''); + $git->add('test2.txt'); + $git->commit('2'); + + $git->config->set('user.name', 'Name Two'); + $git->config->set('user.email', 'two@example.com'); + $filesystem->dumpFile($this->directory . '/test3.txt', ''); + $git->add('test3.txt'); + $git->commit('3'); + + $summary = $git->shortlog->summary(); + + $this->assertEquals(array( + 'Name One <one@example.com>' => 2, + 'Name Two <two@example.com>' => 1 + ), $summary); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php new file mode 100644 index 000000000..25b22fe4f --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/ShowCommandTest.php @@ -0,0 +1,26 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class ShowCommandTest extends BaseTestCase +{ + + public function testShow() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/README.md', 'foobar'); + $git->add('README.md'); + $git->commit('Initial commit'); + + $git->show('master', array('format' => 'oneline')); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php new file mode 100644 index 000000000..bb87e48ea --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/StashCommandTest.php @@ -0,0 +1,204 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class StashCommandTest extends BaseTestCase +{ + + public function testStash() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + + $this->assertEquals('hello', file_get_contents($this->directory.'/README.md')); + } + + public function testStashSave() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash->save('stash test'); + + $this->assertEquals('hello', file_get_contents($this->directory.'/README.md')); + } + + public function testStashList() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + + $stashes = $git->stash->lists(); + + $this->assertCount(1, $stashes); + $this->assertEquals('master', $stashes[0]['branch']); + $this->assertStringEndsWith('Initial commit', $stashes[0]['message']); + } + + public function testStashShow() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + $git->stash->show('stash@{0}'); + } + + public function testStashDrop() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + $git->stash->drop(); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + $git->stash->drop('stash@{0}'); + + $this->assertCount(0, $git->stash->lists()); + } + + public function testStashPop() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash->save('stash#1'); + + $filesystem->dumpFile($this->directory . '/README.md', 'bar'); + $git->stash->save('stash#2'); + $git->stash->pop('stash@{1}'); + + $this->assertEquals('hi!', file_get_contents($this->directory.'/README.md')); + $this->assertCount(1, $git->stash->lists()); + } + + public function testStashApply() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash->save('stash#1'); + + $filesystem->dumpFile($this->directory . '/README.md', 'bar'); + $git->stash->save('stash#2'); + $git->stash->apply('stash@{1}'); + + $this->assertEquals('hi!', file_get_contents($this->directory.'/README.md')); + $this->assertCount(2, $git->stash->lists()); + } + + public function testStashBranch() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + + $git->stash->branch('dev', 'stash@{0}'); + $status = $git->status(); + + $this->assertEquals('dev', $status['branch']); + $this->assertEquals('hi!', file_get_contents($this->directory.'/README.md')); + } + + public function testStashClear() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $git->stash(); + $git->stash->clear(); + + $this->assertCount(0, $git->stash->lists()); + } + + public function testStashCreate() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + + $filesystem->dumpFile($this->directory . '/README.md', 'hi!'); + $object = $git->stash->create(); + + $this->assertNotEmpty($object); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php new file mode 100644 index 000000000..ad04a74c0 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/StatusCommandTest.php @@ -0,0 +1,76 @@ +<?php + +use PHPGit\Command\StatusCommand; +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class StatusCommandTest extends BaseTestCase +{ + + public function testStatus() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/item1.txt', '1'); + $filesystem->dumpFile($this->directory . '/item2.txt', '2'); + $filesystem->dumpFile($this->directory . '/item3.txt', '3'); + + $git->add('item1.txt'); + $git->add('item2.txt'); + + $filesystem->dumpFile($this->directory . '/item1.txt', '1-1'); + + $status = $git->status(); + + $this->assertEquals(array( + 'branch' => 'master', + 'changes' => array( + array('file' => 'item1.txt', 'index' => StatusCommand::ADDED, 'work_tree' => StatusCommand::MODIFIED), + array('file' => 'item2.txt', 'index' => StatusCommand::ADDED, 'work_tree' => StatusCommand::UNMODIFIED), + array('file' => 'item3.txt', 'index' => StatusCommand::UNTRACKED, 'work_tree' => StatusCommand::UNTRACKED), + ) + ), $status); + } + + public function testDetachedHeadStatus() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/item1.txt', '1'); + $git->add('item1.txt'); + $git->commit('initial commit'); + $logs = $git->log(); + $hash = $logs[0]['hash']; + + $git->checkout($hash); + $status = $git->status(); + $this->assertEquals(null, $status['branch']); + } + + public function testTrackingBranchStatus() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->clone('https://github.com/kzykhys/Text.git', $this->directory); + $git->setRepository($this->directory); + + $filesystem->dumpFile($this->directory . '/test.txt', '1'); + $git->add('test.txt'); + $git->commit('test'); + + $status = $git->status(); + $this->assertEquals('master', $status['branch']); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php b/library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php new file mode 100644 index 000000000..5715ba92e --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Command/TagCommandTest.php @@ -0,0 +1,58 @@ +<?php + +use PHPGit\Git; +use Symfony\Component\Filesystem\Filesystem; + +require_once __DIR__ . '/../BaseTestCase.php'; + +class TagCommandTest extends BaseTestCase +{ + + public function testTagDelete() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + $git->tag->create('v1.0.0'); + $git->tag->delete('v1.0.0'); + $this->assertCount(0, $git->tag()); + } + + /** + * @expectedException \PHPGit\Exception\GitException + */ + public function testTagVerify() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + $git->tag->create('v1.0.0'); + $git->tag->verify('v1.0.0'); + } + + public function testCreateTagFromCommit() + { + $filesystem = new Filesystem(); + + $git = new Git(); + $git->init($this->directory); + $git->setRepository($this->directory); + $filesystem->dumpFile($this->directory . '/README.md', 'hello'); + $git->add('.'); + $git->commit('Initial commit'); + $log = $git->log(null, null, array('limit' => 1)); + $git->tag->create('v1.0.0', $log[0]['hash']); + $this->assertCount(1, $git->tag()); + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php b/library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php new file mode 100644 index 000000000..154d6b906 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/Exception/GitExceptionTest.php @@ -0,0 +1,23 @@ +<?php + +use PHPGit\Exception\GitException; +use PHPGit\Git; + +class GitExceptionTest extends PHPUnit_Framework_TestCase +{ + + public function testException() + { + $git = new Git(); + $git->setRepository(sys_get_temp_dir()); + try { + $git->status(); + $this->fail('Previous operation should fail'); + } catch (GitException $e) { + $command = $e->getCommandLine(); + $command = str_replace(array('"', "'"), '', $command); + $this->assertStringEndsWith('status --porcelain -s -b --null', $command); + } + } + +}
\ No newline at end of file diff --git a/library/kzykhys/git/test/PHPGit/GitTest.php b/library/kzykhys/git/test/PHPGit/GitTest.php new file mode 100644 index 000000000..c9aceeb13 --- /dev/null +++ b/library/kzykhys/git/test/PHPGit/GitTest.php @@ -0,0 +1,33 @@ +<?php + +use PHPGit\Git; + +class GitTest extends PHPUnit_Framework_TestCase +{ + + public function testGetVersion() + { + $git = new Git(); + $this->assertNotEmpty($git->getVersion()); + } + + /** + * @expectedException \PHPGit\Exception\GitException + */ + public function testInvalidGitBinary() + { + $git = new Git(); + $git->setBin('/foo/bar'); + $git->getVersion(); + } + + /** + * @expectedException \BadMethodCallException + */ + public function testBadMethodCall() + { + $git = new Git(); + $git->foo(); + } + +}
\ No newline at end of file |