return null;
}
+ public static function get_commit_changes($git_path, $commit_id, $parents) {
+ $args = array("diff-tree", "-r", "--no-commit-id");
+ switch(GitConfig::DETECT_RENAME_LEVEL) {
+ case 0:
+ $args[] = "-M";
+ break;
+ case 1:
+ $args[] = "-C";
+ break;
+ case 2:
+ $args[] = "-C";
+ $args[] = "--find-copies-harder";
+ break;
+ }
+ if(GitConfig::DETECT_REWRITES)
+ $args[] = "-B";
+ if(is_array($parents) && count($parents) > 1)
+ $args[] = "-c";
+ else if(is_array($parents) && count($parents) == 1)
+ $args[] = $parents[0];
+ else
+ $args[] = "--root";
+ $args[] = $commit_id;
+ $args[] = "--";
+ $result = self::git_execute($args, $git_path);
+ $tree = array();
+ foreach(explode("\n", $result) as $line) {
+ if($line == "")
+ continue;
+ $entry = array();
+ if(preg_match('/^:([0-7]{6}) ([0-7]{6}) ([0-9a-fA-F]{40}) ([0-9a-fA-F]{40}) (.)([0-9]{0,3})\t(.*)$/i', $line, $matches)) {
+ $entry['parents'] = 1;
+ $entry['from_mode'] = $matches[1];
+ $entry['to_mode'] = $matches[2];
+ $entry['from_id'] = $matches[3];
+ $entry['to_id'] = $matches[4];
+ $entry['status'] = $matches[5];
+ $entry['similarity'] = $matches[6];
+ $entry['file'] = $matches[7];
+ if($entry['status'] == 'R' || $entry['status'] == 'C') { //renamed or copied
+ $files = explode("\t", $entry['file']);
+ $entry['from_file'] = $files[0];
+ $entry['to_file'] = $files[1];
+ }
+ } else if(preg_match('/^(::+)((?:[0-7]{6} )+)((?:[0-9a-fA-F]{40} )+)([a-zA-Z]+)\t(.*)$/i', $line, $matches)) {
+ $entry['parents'] = strlen($matches[1]);
+ $from_modes = explode(" ", $matches[2]);
+ $entry['from_mode'] = array_slice($from_modes, 1);
+ $entry['to_mode'] = $from_modes[0];
+ $from_ids = explode(" ", $matches[3]);
+ $entry['from_id'] = array_slice($from_ids, 1);
+ $entry['to_id'] = $from_ids[0];
+ $entry['status'] = str_split($matches[4]);
+ $entry['file'] = $matches[5];
+ }
+ $tree[] = $entry;
+ }
+ return $tree;
+ }
+
}
require_once('pages/shortlog.class.php');
+class difftree {
+
+ public function generate_difftree($project, $commit, $patch_link) {
+ $difftree = new ContentProvider('commit', 'difftree');
+ $tree = GitCommand::get_commit_changes($project['path'], $commit['id'], $commit['parent']);
+ $entry_count = 0;
+ if(count($commit['parent']) > 1)
+ $difftree->set('class', ' combined');
+ else
+ $difftree->set('class', '');
+ foreach($tree as $entry) {
+ $entry_count++;
+ $difftree->append('tree', $this->tree_entry($entry_count, (($entry_count % 2) ? 'dark' : 'light'), $commit, $entry, $patch_link));
+ }
+ if(count($tree) == 0)
+ $difftree->set('tree', '');
+ return $difftree;
+ }
+
+ private function tree_entry($diffid, $class, $commit, $entry, $patch_link) {
+ $tree = new ContentProvider('commit', 'tree');
+ $tree->set('class', $class);
+ $tree->set('hash', $commit['id']);
+ $tree->set('file', $entry['file']);
+
+ if(count($commit['parent']) > 1) {
+ if(preg_match('/^[0]{40}$/', $entry['to_id'])) //file doesn't exist in the result (child) commit
+ $tree->set('file', $entry['file']);
+ else
+ $tree->set('file', new ContentProvider('commit', 'tree_file_link', array('file' => $entry['file'])));
+
+ $tree->set('specials', '');
+
+ if($patch_link)
+ $tree->append('merge', new ContentProvider('commit', 'tree_merge_patch_link', array("patch_marker" => "patch".$diffid)));
+
+ $has_history = false;
+ $not_deleted = false;
+
+ for($i = 0; $i < count($commit['parent']); $i++) {
+ $status = $entry['status'][$i];
+ $merge = null;
+
+ $has_history = ($has_history || ($status != 'A'));
+ $not_deleted = ($not_deleted || ($status != 'D'));
+
+ switch($status) {
+ case 'A': //Added
+ $merge = new ContentProvider('commit', 'tree_merge_new');
+ break;
+ case 'D': //Deleted
+ $merge = new ContentProvider('commit', 'tree_merge');
+ $merge->set('class', '');
+ $blob_link = new ContentProvider('commit', 'tree_merge_blob', array('hash' => $commit['parent'][$i], 'file' => $entry['file']));
+ $merge->set('links', array($blob_link, ' | '));
+ break;
+ default:
+ $merge = new ContentProvider('commit', 'tree_merge');
+ if($entry['from_id'][$i] == $entry['to_id']) {
+ $merge->set('class', ' nochange');
+ $merge->set('links', ' | ');
+ } else {
+ $merge->set('class', '');
+ $merge->set('links', new ContentProvider('commit', 'tree_merge_diff', array('hash' => $commit['id'], 'parent' => $commit['parent'][$i], 'file' => $entry['file'], 'id' => ($i + 1))));
+ }
+ }
+ $tree->append('merge', $merge);
+ }
+
+ $tree->set('links', '');
+ if($not_deleted) {
+ $tree->append('links', new ContentProvider('commit', 'tree_merge_blob', array('hash' => $commit['id'], 'file' => $entry['file'])));
+ if($has_history)
+ $tree->append('links', ' | ');
+ }
+ if($has_history)
+ $tree->append('links', new ContentProvider('commit', 'tree_merge_history', array('hash' => $commit['id'], 'file' => $entry['file'])));
+
+ } else {
+ $tree->set('file', new ContentProvider('commit', 'tree_file_link', array('file' => $entry['file'])));
+ $tree->set('merge', '');
+
+ $from_type = Tools::get_filetype($entry['from_mode']);
+ $to_type = Tools::get_filetype($entry['to_mode']);
+
+ $from_mode = (Tools::is_regular_file($entry['from_mode']) ? Tools::get_file_permissions($entry['from_mode']) : null);
+ $to_mode = (Tools::is_regular_file($entry['to_mode']) ? Tools::get_file_permissions($entry['to_mode']) : null);
+
+ $link_placeholders = array(
+ "hash" => $commit['id'],
+ "file" => $entry['file'],
+ "parent" => (count($commit['parent']) ? $commit['parent'][0] : ""),
+ );
+ if($patch_link)
+ $tree->append('links', new ContentProvider('commit', 'tree_patch_link', array("patch_marker" => "patch".$diffid)));
+
+ switch($entry['status']) {
+ case 'A': //Added
+ $tree->set('specials', new ContentProvider('commit', (Tools::is_regular_file($entry['to_mode']) ? 'tree_new_file' : 'tree_new'), array('type' => $to_type, 'mode' => $to_mode)));
+ $tree->append('links', new ContentProvider('commit', 'tree_new_links', $link_placeholders));
+ break;
+ case 'D': //Deleted
+ $tree->set('specials', new ContentProvider('commit', 'tree_deleted', array('type' => $from_type)));
+ $tree->append('links', new ContentProvider('commit', 'tree_deleted_links', $link_placeholders));
+ break;
+ case 'M': //Modified
+ case 'T': //Type changed
+ if($entry['from_mode'] != $entry['to_mode']) {
+ $modified = new ContentProvider('commit', 'tree_changed');
+ $tree->set('specials', $modified);
+ if($from_type != $to_type)
+ $modified->append('changes', new ContentProvider('commit', 'tree_changed_type', array('from' => $from_type, 'to' => $to_type)));
+ if($from_mode != $to_mode && $to_mode) {
+ if($from_mode)
+ $modified->append('changes', new ContentProvider('commit', 'tree_changed_mode', array('from' => $from_mode, 'to' => $to_mode)));
+ else
+ $modified->append('changes', new ContentProvider('commit', 'tree_changed_mode_to', array('to' => $to_mode)));
+ }
+ } else
+ $tree->set('specials', '');
+ if($entry['from_id'] != $entry['to_id'])
+ $tree->append('links', new ContentProvider('commit', 'tree_changed_links_diff', $link_placeholders));
+ $tree->append('links', new ContentProvider('commit', 'tree_changed_links', $link_placeholders));
+ break;
+ case 'R': //Renamed
+ case 'C': //Copied
+ $actions = array('R' => 'tree_moved', 'C' => 'tree_copied');
+ $move = new ContentProvider('commit', $actions[$entry['status']]);
+ $tree->set('specials', $move);
+ $tree->set('file', $entry['to_file']);
+ $move->set('file', $entry['from_file']);
+ $move->set('hash', $commit['parent'][0]);
+ $move->set('similarity', $entry['similarity']);
+ if($from_mode != $to_mode)
+ $move->set('mode', new ContentProvider('commit', 'tree_moved_mode', array('mode' => $to_mode)));
+ else
+ $move->set('mode', '');
+ if($entry['from_id'] != $entry['to_id'])
+ $tree->append('links', new ContentProvider('commit', 'tree_moved_links_diff', $link_placeholders));
+ $tree->append('links', new ContentProvider('commit', 'tree_moved_links', $link_placeholders));
+ break;
+ default:
+
+ }
+
+ }
+ return $tree;
+ }
+
+}
+
class page_commit {
private $page, $phpgitweb;
private $commitid;
foreach($commit['parent'] as $parent) {
$this->page->append('parents', new ContentProvider('commit', 'parent', array('hash' => $parent, 'head' => $commit['id'])));
}
+ if(count($commit['parent']) == 0)
+ $this->page->set('parents', '');
$refs = new ContentProvider('commit', 'commit_refs');
$found = false;
}
$this->page->set('refs', ($found ? $refs : ""));
+ $difftree = new difftree();
+ $this->page->set('difftree', $difftree->generate_difftree($project, $commit, false));
+
return $this->page;
}
+
+
}
?>
\ No newline at end of file
<div class="list_head">
</div>
-<table class="diff_tree">
-%tree%
-</table>
+%difftree%
# [parent]
# [commit_ref_tag]
<span class="tag" title="tags/%name%">%name%</span>
+# [difftree]
+<table class="diff_tree%class%">
+%tree%
+</table>
+
# [tree]
<tr class="%class%">
- <td><a class="list" href="?p=%project%&a=blob&h=%hash%&f=%file%">src/mod-helpserv.c</a></td>
- <td></td>
- <td class="link">
- <a href="?p=%project%&a=blobdiff&h=%hash%&f=src/mod-helpserv.c&hp=%parent%">diff</a> |
- <a href="?p=%project%&a=blob&h=%hash%&f=%file%">blob</a> |
- <a href="?p=%project%&a=history&h=%hash%&f=%file%">history</a></td>
+ <td>%file%</td>
+ <td>%specials%</td>
+ %merge%
+ <td class="link">%links%</td>
</tr>
+
+# [tree_merge]
+ <td class="link%class%">%links%</td>
+# [tree_merge_new]
+ <td class="link" align="right"> | </td>
+# [tree_merge_blob]
+<a href="?p=%project%&a=blob&h=%hash%&f=%file%">blob</a>
+# [tree_merge_history]
+<a href="?p=%project%&a=history&h=%hash%&f=%file%">history</a>
+# [tree_merge_diff]
+<a href="?p=%project%&a=blobdiff&h=%hash%&f=%file%&hp=%parent%">diff%id%</a> |
+# [tree_merge_patch_link]
+ <td class="link"><a href="#%patch_marker%">patch</a> | </td>
+
+
+# [tree_file_link]
+<a class="list" href="?p=%project%&a=blob&h=%hash%&f=%file%">%file%</a>
+
+# [tree_patch_link]
+<a href="#%patch_marker%">patch</a> |
+
+# [tree_new]
+<span class="file_status new">[new %type%]</span>
+
+# [tree_new_file]
+<span class="file_status new">[new %type% with mode: %mode%]</span>
+
+# [tree_new_links]
+<a href="?p=%project%&a=blob&h=%hash%&f=%file%">blob</a>
+
+# [tree_deleted]
+<span class="file_status deleted">[deleted %type%]</span>
+
+# [tree_deleted_links]
+<a href="?p=%project%&a=blob&h=%hash%&f=%file%">blob</a> | <a href="?p=%project%&a=history&h=%hash%&f=%file%">history</a>
+
+# [tree_changed]
+<span class="file_status mode_chnge">[changed%changes%]</span>
+# [tree_changed_type]
+ from %from% to %to%
+# [tree_changed_mode]
+ mode: %from%->%to%
+# [tree_changed_mode_to]
+ mode: %to%
+
+# [tree_changed_links_diff]
+<a href="?p=%project%&a=blobdiff&h=%hash%&f=%file%&hp=%parent%">diff</a> |
+# [tree_changed_links]
+<a href="?p=%project%&a=blob&h=%hash%&f=%file%">blob</a> | <a href="?p=%project%&a=history&h=%hash%&f=%file%">history</a>
+
+# [tree_moved]
+<span class="file_status moved">[moved from <a class="list" href="?p=%project%&a=blob&f=%file%&h=%hash%">%file%</a> with %similarity% similarity%mode%]</span>
+# [tree_copied]
+<span class="file_status copied">[copied from <a class="list" href="?p=%project%&a=blob&f=%file%&h=%hash%">%file%</a> with %similarity% similarity%mode%]</span>
+# [tree_moved_mode]
+, mode: %mode%
+
+# [tree_moved_links_diff]
+<a href="?p=%project%&a=blobdiff&h=%hash%&f=src/mod-helpserv.c&hp=%parent%">diff</a> |
+# [tree_moved_links]
+<a href="?p=%project%&a=blob&h=%hash%&f=%file%">blob</a> | <a href="?p=%project%&a=history&h=%hash%&f=%file%">history</a>