Permalink
Switch branches/tags
Nothing to show
Find file
Fetching contributors…
Cannot retrieve contributors at this time
executable file 512 lines (466 sloc) 10.9 KB
<?php
/*
* Git.php
*
* A PHP git library
*
* @package Git.php
* @version 0.1.1-a
* @author James Brumond
* @copyright Copyright 2010 James Brumond
* @license http://github.com/kbjr/Git.php
* @link http://code.kbjrweb.com/project/gitphp
*/
if (__FILE__ == $_SERVER['SCRIPT_FILENAME']) die('Bad load order');
// ------------------------------------------------------------------------
/**
* Git Interface Class
*
* This class enables the creating, reading, and manipulation
* of git repositories.
*
* @class Git
*/
class Git_Git {
/**
* Create a new git repository
*
* Accepts a creation path, and, optionally, a source path
*
* @access public
* @param string repository path
* @param string directory to source
* @return GitRepo
*/
public static function &create($repo_path, $source = null) {
return GitRepo::create_new($repo_path, $source);
}
/**
* Open an existing git repository
*
* Accepts a repository path
*
* @access public
* @param string repository path
* @return GitRepo
*/
public static function open($repo_path) {
return new GitRepo($repo_path);
}
/**
* Checks if a variable is an instance of GitRepo
*
* Accepts a variable
*
* @access public
* @param mixed variable
* @return bool
*/
public static function is_repo($var) {
return (get_class($var) == 'GitRepo');
}
}
// ------------------------------------------------------------------------
/**
* Git Repository Interface Class
*
* This class enables the creating, reading, and manipulation
* of a git repository
*
* @class GitRepo
*/
class GitRepo {
protected $repo_path = null;
public $git_path = '/usr/bin/git';
/**
* Create a new git repository
*
* Accepts a creation path, and, optionally, a source path
*
* @access public
* @param string repository path
* @param string directory to source
* @return GitRepo
*/
public static function &create_new($repo_path, $source = null) {
if (is_dir($repo_path) && file_exists($repo_path."/.git") && is_dir($repo_path."/.git")) {
throw new Exception("\"$repo_path\" is already a git repository");
} else {
$repo = new self($repo_path, true, false);
if (is_string($source))
$repo->clone_from($source);
else $repo->run('init');
return $repo;
}
}
/**
* Constructor
*
* Accepts a repository path
*
* @access public
* @param string repository path
* @param bool create if not exists?
* @return void
*/
public function __construct($repo_path = null, $create_new = false, $_init = true) {
if (is_string($repo_path))
$this->set_repo_path($repo_path, $create_new, $_init);
}
/**
* Set the repository's path
*
* Accepts the repository path
*
* @access public
* @param string repository path
* @param bool create if not exists?
* @return void
*/
public function set_repo_path($repo_path, $create_new = false, $_init = true) {
if (is_string($repo_path)) {
if ($new_path = realpath($repo_path)) {
$repo_path = $new_path;
if (is_dir($repo_path)) {
if (file_exists($repo_path."/.git") && is_dir($repo_path."/.git")) {
$this->repo_path = $repo_path;
} else {
if ($create_new) {
$this->repo_path = $repo_path;
if ($_init) $this->run('init');
} else {
throw new Exception("\"$repo_path\" is not a git repository");
}
}
} else {
throw new Exception("\"$repo_path\" is not a directory");
}
} else {
if ($create_new) {
if ($parent = realpath(dirname($repo_path))) {
mkdir($repo_path);
$this->repo_path = $repo_path;
if ($_init) $this->run('init');
} else {
throw new Exception('cannot create repository in non-existent directory');
}
} else {
throw new Exception("\"$repo_path\" does not exist");
}
}
}
}
/**
* Tests if git is installed
*
* @access public
* @return bool
*/
public function test_git() {
$descriptorspec = array(
1 => array('pipe', 'w'),
2 => array('pipe', 'w'),
);
$pipes = array();
$resource = proc_open($this->git_path, $descriptorspec, $pipes);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) {
fclose($pipe);
}
$status = trim(proc_close($resource));
return ($status != 127);
}
/**
* Run a command in the git repository
*
* Accepts a shell command to run
*
* @access protected
* @param string command to run
* @return string
*/
protected function run_command($command) {
$descriptorspec = array(
1 => array('pipe', 'w'),
2 => array('pipe', 'w'),
);
$pipes = array();
$resource = proc_open($command, $descriptorspec, $pipes, $this->repo_path);
$stdout = stream_get_contents($pipes[1]);
$stderr = stream_get_contents($pipes[2]);
foreach ($pipes as $pipe) {
fclose($pipe);
}
$status = trim(proc_close($resource));
if ($status) throw new Exception($stderr);
return $stdout;
}
/**
* Run a git command in the git repository
*
* Accepts a git command to run
*
* @access public
* @param string command to run
* @return string
*/
public function run($command) {
return $this->run_command($this->git_path." ".$command);
}
/**
* Runs a `git add` call
*
* Accepts a list of files to add
*
* @access public
* @param mixed files to add
* @return string
*/
public function add($files = "*") {
if (is_array($files)) $files = '"'.implode('" "', $files).'"';
return $this->run("add $files -v");
}
/**
* Runs a `git reset HEAD` call
*
* Accepts a list of files to unstage
*
* @access public
* @param mixed files to unstage
* @return string
*/
public function unstage($files = "*") {
if (is_array($files)) $files = '"'.implode('" "', $files).'"';
return $this->run("reset HEAD $files");
}
/**
* Runs a `git commit` call
*
* Accepts a commit message string
*
* @access public
* @param string commit message
* @param string automatically stage files
* @return string
*/
public function commit($message = "", $all = true) {
return $this->run("commit".(($all) ? ' -a ' : '')." -v -m \"$message\"");
}
/**
* Runs a `git clone` call to clone the current repository
* into a different directory
*
* Accepts a target directory
*
* @access public
* @param string target directory
* @return string
*/
public function clone_to($target) {
return $this->run("clone --local ".$this->repo_path." $target");
}
/**
* Runs a `git clone` call to clone a different repository
* into the current repository
*
* Accepts a source directory
*
* @access public
* @param string source directory
* @return string
*/
public function clone_from($source) {
return $this->run("clone --local $source ".$this->repo_path);
}
/**
* Runs a `git clone` call to clone a remote repository
* into the current repository
*
* Accepts a source url
*
* @access public
* @param string source url
* @return string
*/
public function clone_remote($source) {
return $this->run("clone $source ".$this->repo_path);
}
/**
* Runs a `git clean` call
*
* Accepts a remove directories flag
*
* @access public
* @param bool delete directories?
* @return string
*/
public function clean($dirs = false) {
return $this->run("clean".(($dirs) ? " -d" : ""));
}
/**
* Runs a `git branch` call
*
* Accepts a name for the branch
*
* @access public
* @param string branch name
* @return string
*/
public function create_branch($branch) {
return $this->run("branch $branch");
}
/**
* Runs a `git branch -[d|D]` call
*
* Accepts a name for the branch
*
* @access public
* @param string branch name
* @return string
*/
public function delete_branch($branch, $force = false) {
return $this->run("branch ".(($force) ? '-D' : '-d')." $branch");
}
/**
* Runs a `git branch` call
*
* @access public
* @param bool keep asterisk mark on active branch
* @return array
*/
public function list_branches($keep_asterisk = false) {
$branchArray = explode("\n", $this->run("branch"));
foreach($branchArray as $i => &$branch) {
$branch = trim($branch);
if (! $keep_asterisk)
$branch = str_replace("* ", "", $branch);
if ($branch == "")
unset($branchArray[$i]);
}
return $branchArray;
}
/**
* Runs a `git tag` call
*
* @access public
* @return array
*/
public function list_tags() {
$tagArray = explode("\n", $this->run("tag"));
foreach($tagArray as $i => &$tag) {
$tag = trim($tag);
if ($tag == "")
unset($tagArray[$i]);
}
return $tagArray;
}
/**
* Returns name of active branch
*
* @access public
* @param bool keep asterisk mark on branch name
* @return string
*/
public function active_branch($keep_asterisk = false) {
$branchArray = $this->list_branches(true);
$active_branch = preg_grep("/^\*/", $branchArray);
reset($active_branch);
if ($keep_asterisk)
return current($active_branch);
else
return str_replace("* ", "", current($active_branch));
}
/**
* Runs a `git checkout` call
*
* Accepts a name for the branch
*
* @access public
* @param string branch name
* @return string
*/
public function checkout($branch) {
return $this->run("checkout $branch");
}
/**
* Runs a `git pull` call
*
* Accepts a name for the remote repo
*
* @access public
* @param string remote repo name
* @return string
*/
public function pull($repo = '') {
return $this->run("pull $repo -v");
}
/**
* Runs a `git push` call
*
* Accepts a name for the remote repo
*
* @access public
* @param string remote repo name
* @return string
*/
public function push($repo = '') {
return $this->run("push $repo -v");
}
/**
* Runs a `git ls-files` call
*
* @access public
* @return array
*/
public function list_files() {
return explode("\n", $this->run("ls-files"));
}
/**
* Runs a `git log -n 1 --pretty=format:%H` call
*
* @access public
* @return string
*/
public function log_recent_commit() {
return $this->run("log -n 1 --pretty=format:%H");
}
/**
* Runs a `git submodule` call
*
* @access public
* @return array
*/
public function submodule() {
return explode("\n", $this->run("submodule"));
}
/**
* Runs a `git config` call
*
* @access public
* @param string config
* @return string
*/
public function get_config($config = "") {
return $this->run("config --get ".$config);
}
/**
* Checks if a workspace is clean
*
* @access public
* @return boolean
*/
public function is_clean_workspace() {
return (preg_match("#nothing to commit*.#",$this->run("status -uno | tail -n 1")));
}
/**
* Runs a `git --version` call
*
* @access public
* @return string
*/
public function version() {
return $this->run("--version");
}
}
/* End Of File */