BarryServer : Git

All the code for all my projects
// BarryServer : Git / barryserver-git / commit / a6603d573a369feda0bc772d59bc48c3d1397442

// Related

barryserver-git

Barry Splitting into more pages + commit pages a6603d5 (2 years, 3 months ago)
diff --git a/README b/README
deleted file mode 100644
index 77d3be1..0000000
--- a/README
+++ /dev/null
@@ -1,80 +0,0 @@
-# Simple Web-based Git Browser
-This project is a simple, configurable, light weight, web-based git browser for any git repositories hosted on a webserver.
-
-This is the same script that is used to run this site.
-
-
-
-It has support for:
- - README files (with simple markdown)
- - Unicode icons
- - Simple navigation
- - Repositories, Branches, Folders, and Files
-
-
-
-It is easy to implement, and is very customisable as the script produces class based HTML pages, so CSS is easy to modify.
-
-NOTE: This software has not been tested fully, and is only tested to work on the conditions of my webserver, some other conditions may require tinkering.
-
-
-## Installation
-To install the script requires a little configuration of your web-server. I will use nginx as an example.
-
-Copy "git.php" into a folder in your webserver's directory (e.g. "/var/www/html/files/", or "/var/www/html/" if you don't have anything else there).
-
-
-
-If you are happy to access the script by URLs like "example.com/git.php/project/branch/test.txt", you can stop here. If you do not want this, you can access it through a URL like "example.com/git/project/branch/text.txt" if you placed the scripts in a folder ("/var/www/html/git/"), or by a URL like "example.com/project/branch/test.txt" if you placed the scripts in the webserver's root directory.
-
-To configure one of these options, you must modify your webserver's config. In nginx you would just add:
-```
-location / {
-	rewrite ^(.*)$ /git.php$1 last;
-}
-```
-if the script was in the root directory, or:
-```
-location /git {
-	rewrite ^/git(.*)$ /git.php$1 last;
-}
-```
-if the script was in a folder named "/git/" that was in the root directory of the webserver.
-
-
-The following must be present in both configurations:
-```
-location /path/to/git.php {
-	include snippets/fastcgi-php.conf;
-	fastcgi_pass unix:/run/php/php7.3-fpm.sock;
-}
-```
-(modify "/path/to/git.php" suitably)
-
-
-
-
-While this example is for nginx it can easily be adapted for any webserver. All that really matters is that any request gets routed through "git.php" as though it were a folder.
-
-## Setup
-To configure the script to your liking you may want to edit the script. At the start of "git.php" is all of the important variables, and must be edited to account for your setup. Just after the configuration variables, "git.php" contains the CSS style sheet, so you may want to edit this to re-theme the script.
-
-### Configuration Variables
-`$TITLE` is the title of the webpage, displayed as the name of the tab, and the header text at the top of each page.
-
-`$ROOT` is the name of the folder you placed the script in. Leave it blank for the root directory. This variable should always be preceded by a "/" unless blank.
-
-`$SCRIPT` is the name of the script. Set it to the "git.php" if you didn't configure your webserver in the installation section. Set it to whatever you configured your webserver to use otherwise. Leave it blank if the script is in the root of your webserer. Unless blank, this should be preceded by a "/".
-
-`$ORIGINAL` is the name of the folder that contains your repositories. It should always start with a "/" unless blank. Leave it blank if the repositories are in the same folder as the script.
-
-`$BRANCH` is the name of the default branch (if in doubt, leave as 'master').
-
-`$DESCRIPTION` is the description of the site, displayed on the first page.
-
-`$FOOTER` is the text that is displayed at the bottom of each page.
-
-
-### CSS
-Just after the start of the document is a block of CSS in a <style> tag. Any of this can be freely modified without affecting the performance of the script. You don't even have to leave the blocks that are there, you can completely reconfigure it or even delete it.
-
diff --git a/blob.php b/blob.php
new file mode 100644
index 0000000..65e11b1
--- /dev/null
+++ b/blob.php
@@ -0,0 +1,74 @@
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/config.php"; ?>
+<?php $SIDE_LINKS = array(); ?>
+<?php
+	ob_start();
+	if (!isset($_GET["repo"])) {header("Location: /");die();}
+	$repo = $_GET["repo"]??"";
+	if (isset($_GET["repo"])) {
+		$PAGE_TITLE = $repo;
+	}
+
+	if (!is_dir(GIT_DIR."/".$repo.".git")) { ?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1>Repository not found</h1>
+	<article>The repository you were looking for was not found on this server. Please check the URL and look for errors. If there are no errors, then the repository does not exist. Please use the index to reach any repositories you wish to access.</article>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
+<?php	die();}
+	$branch = $_GET["object"]??DEFAULT_BRANCH;
+	$path = $_GET["path"]??".";
+	chdir(GIT_DIR."/".$repo.".git");
+	if ($branch === "") {
+		header("Location: /".$repo."/tree/");
+		die();
+	} else {
+		if ($path == ".") {
+			header("Location: /".$repo."/tree/".$branch);
+			die();
+		}
+		$files = shell_exec("git ls-tree --full-name ".escapeshellarg($branch)." ".escapeshellarg($path));
+		if (substr($path,-1) !== "/" && $path !== "") {
+			if (explode(" ",explode("\n",$files)[0])[1] === "tree") {
+				header("Location: /".$repo."/tree/".$branch."/".$path."/");
+				die();
+			}
+		}
+		if (substr($path,-1) === "/" && $path !== "") {
+			if (count(explode("\n",$files)) > 1) {
+				header("Location: /".$repo."/tree/".$branch."/".$path);
+				die();
+			}
+		}
+		if (substr($path,-1) === "/" && $path !== "") {
+			if (explode(" ",explode("\n",shell_exec("git ls-tree --full-name ".escapeshellarg($branch)." ".escapeshellarg(substr($path,0,-1))))[0])[1] === "blob") {
+				header("Location: /".$repo."/blob/".$branch."/".substr($path,0,-1));
+				die();
+			}
+		}
+		$SIDE_LINKS["git clone"] = "git://".$_SERVER["SERVER_NAME"]."/".$repo.".git";
+		$SIDE_LINKS["Raw View"] = "/".$repo."/raw/".$branch."/".$path;
+		$SIDE_LINKS["Show History"] = "/".$repo."/commits/".$branch."/".$path;
+		$PAGE_TITLE = basename($path)." @ ".$PAGE_TITLE;
+		require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1><?= $repo ?></h1>
+<?php           $lastcommit = shell_exec("git log --summary --quiet --oneline --abbrev-commit --format=format:'<b>%an</b> %s <span><a href=\"/".escapeshellcmd($repo)."/commit/%H/".escapeshellcmd($path)."\">%h</a> (%ar)</span>' -n 1 ".escapeshellarg($branch)." -- ".escapeshellarg($path));
+		echo "<span class=\"last-commit\">".$lastcommit."</span>";
+		if (shell_exec("git ls-tree --full-name ".escapeshellarg($branch)." ".escapeshellarg($path))) {
+			$content = shell_exec("git cat-file -p ".explode("\t",explode(" ",explode("\n",$files)[0])[2])[0]);
+			if (isset($_GET["raw"])) {
+				ob_clean();
+				header("Content-type: text/plain");
+				echo $content;
+				die();
+			}
+			echo "<pre class=\"prettyprint\">\n".htmlspecialchars($content)."</pre>\n";
+		} else {
+			header("Location: .");
+			die();
+		}
+	}
+?>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
diff --git a/commit.php b/commit.php
new file mode 100644
index 0000000..f0fb241
--- /dev/null
+++ b/commit.php
@@ -0,0 +1,35 @@
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/config.php"; ?>
+<?php $SIDE_LINKS = array(); ?>
+<?php
+	if (!isset($_GET["repo"])) {header("Location: /");die();}
+	$repo = $_GET["repo"]??"";
+	if (isset($_GET["repo"])) {
+		$PAGE_TITLE = $repo;
+	}
+
+	if (!is_dir(GIT_DIR."/".$repo.".git")) { ?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1>Repository not found</h1>
+	<article>The repository you were looking for was not found on this server. Please check the URL and look for$
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
+<?php	die();}
+	$branch = $_GET["object"]??DEFAULT_BRANCH;
+	$path = $_GET["path"]??".";
+	chdir(GIT_DIR."/".$repo.".git");
+	if ($branch === "") {
+		$branch = DEFAULT_BRANCH;
+	}
+	$SIDE_LINKS["git clone"] = "git://".$_SERVER["SERVER_NAME"]."/".$repo.".git";
+	$SIDE_LINKS["Browse Files"] = "/".$repo."/tree/".$branch."/".$path;
+	$PAGE_TITLE = "Commit ".substr($branch,0,7)." @ ".$PAGE_TITLE;
+	require_once $_SERVER["DOCUMENT_ROOT"]."/head.php";
+	echo "<main><h1>".$repo."</h1>\n";
+	$lastcommit = shell_exec("git log --summary --quiet --oneline --abbrev-commit --format=format:'<b>%an</b> %s <span><a href=\"/".escapeshellcmd($repo)."/commit/%H/".escapeshellcmd($path)."\">%h</a> (%ar)</span>' -n 1 ".escapeshellarg($branch)." -- ".escapeshellarg($path));
+	echo "<span class=\"last-commit\">".$lastcommit."</span>";
+	$content = shell_exec("git --git-dir ".GIT_DIR."/".escapeshellcmd($repo).".git/ log --format= -p -n 1 ".escapeshellarg($branch)." -- ".escapeshellarg($path));
+	echo "<pre class=\"prettyprint\">\n".htmlspecialchars($content)."</pre>\n";
+?>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
diff --git a/commits.php b/commits.php
new file mode 100644
index 0000000..488458e
--- /dev/null
+++ b/commits.php
@@ -0,0 +1,49 @@
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/config.php"; ?>
+<?php $SIDE_LINKS = array(); ?>
+<?php
+	const MAX_PER_PAGE = 20;
+	if (!isset($_GET["repo"])) {header("Location: /");die();}
+	$repo = $_GET["repo"]??"";
+	if (isset($_GET["repo"])) {
+		$PAGE_TITLE = $repo;
+	}
+
+	if (!is_dir(GIT_DIR."/".$repo.".git")) { ?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1>Repository not found</h1>
+	<article>The repository you were looking for was not found on this server. Please check the URL and look for errors. If there are no errors, then the repository does not exist. Please use the index to reach any repositories you wish to access.</article>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
+<?php	die();}
+	$branch = $_GET["object"]??DEFAULT_BRANCH;
+	$path = $_GET["path"]??".";
+	chdir(GIT_DIR."/".$repo.".git");
+	if ($branch === "") {
+		$branch = DEFAULT_BRANCH;
+	}
+	$SIDE_LINKS["git clone"] = "git://".$_SERVER["SERVER_NAME"]."/".$repo.".git";
+	$PAGE_TITLE = "Commits - ".$PAGE_TITLE;
+	require_once $_SERVER["DOCUMENT_ROOT"]."/head.php";
+	echo "<main><h1>".$repo."</h1>\n";
+	$page = intval($_GET["page"]??0);
+	$commits = shell_exec("git rev-list --all --count");
+	if (($page*MAX_PER_PAGE)+1 >= $commits) {header("Location: .");die();}
+	echo shell_exec("git --git-dir ".GIT_DIR."/".escapeshellcmd($repo).".git/ log -n ".MAX_PER_PAGE." --skip ".($page*MAX_PER_PAGE)." --format='<a href=\"/".escapeshellcmd($repo)."/commit/%H/".escapeshellcmd($path)."\" class=\"commit\"><b>%s</b><br>%cn (%cr) &mdash; %h</a><br>' ".escapeshellarg($branch)." -- ".escapeshellarg($path));
+	if ($commits > MAX_PER_PAGE) { ?>
+<br>
+<div class="commit-nav">
+	<?= ($page*MAX_PER_PAGE)+1 ?> - <?= min(($page+1)*MAX_PER_PAGE,$commits) ?> of <?= $commits ?>
+	<br>
+	<form method="GET" action="">
+		<input type="hidden" name="page" value="<?= ($page > 0)?($page - 1):(0) ?>">
+		<input type="submit" value="Previous"<?= ($page <= 0)?" disabled":"" ?>>
+	</form>
+	<form method="GET" action="">
+		<input type="hidden" name="page" value="<?= (($page+1)*MAX_PER_PAGE < $commits)?($page + 1):($page) ?>">
+		<input type="submit" value="Next"<?= (($page+1)*MAX_PER_PAGE >= $commits)?" disabled":"" ?>>
+	</form>
+</div>
+<?php } ?>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
diff --git a/config.php b/config.php
new file mode 100644
index 0000000..093dbdc
--- /dev/null
+++ b/config.php
@@ -0,0 +1,8 @@
+<?php
+
+const SITE_TITLE = "BarryServer : Git";
+
+const GIT_DIR = "/srv/http/git";
+const DEFAULT_BRANCH = "master";
+
+?>
diff --git a/foot.php b/foot.php
new file mode 100644
index 0000000..7fb2bd6
--- /dev/null
+++ b/foot.php
@@ -0,0 +1,2 @@
+	</body>
+</html>
diff --git a/git.php b/git.php
deleted file mode 100644
index ae24323..0000000
--- a/git.php
+++ /dev/null
@@ -1,336 +0,0 @@
-<?php
-/*
- * Copyright (C) 2021 BarryServer
- *
- * This program is free software: you can redistribute it and/or modify
- * it under the terms of the GNU General Public License as published by
- * the Free Software Foundation, either version 3 of the License, or
- * (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program.  If not, see <https://www.gnu.org/licenses/>.
- */
-
-/* TITLE: Title of the site */
-$TITLE = "BarryServer : Git";
-
-/* ROOT: The location of this script in your document root
- * e.g. "example.com/abc/git.php" = "/abc",
- *      "example.com/git.php" = ""
- */
-$ROOT = "";
-
-/* SCRIPT: Name of the script after alias by server
- * e.g. "example.com/git" -> "example.com/git.php" = "/git"
- */
-$SCRIPT = "";
-
-/* ORIGINAL: The location of all the git repositories */
-$ORIGINAL = "/home/git";
-
-/* BRANCH: The default branch to use */
-$BRANCH = "master";
-
-/* DESCRIPTION: Description of the site */
-$DESCRIPTION = "A BarryServer Git Browser";
-
-/* FOOTER: Text displayed at the bottom of each page */
-$FOOTER = "BarryServer Git Browser";
-
-ob_start();
-?>
-<!DOCTYPE html>
-<html>
-	<head>
-		<title><?php echo $TITLE; ?></title>
-		<meta name="viewport" content="width=device-width, initial-scale=1">
-		<style>
-			/* Main Page */
-			body {
-				width: 90%;
-				max-width: 1180px;
-				min-width: 480px;
-				margin-left: auto;
-				margin-right: auto;
-				margin-top: 24px;
-				background-color: #0D0D0D;
-				color: white;
-				font-size: 1.1em;
-			}
-
-			/* Headings */
-			h1,h2,h3,h4,h5,h6 {
-				color: orange;
-				text-shadow: 2px 2px black;
-				display: block;
-				text-align: center;
-			}
-
-			/* Selected Links */
-			a:active, a:focus {
-				outline: none;
-				color: red;
-			}
-			/* Links */
-			a, a:visited {
-				color: blue;
-			}
-
-			/* Folders, Files, Repositories and Branches*/
-			.folder, .file, .repo, .branch {
-				background-color: #2D2D2D;
-				color: white;
-				padding: 8px;
-				border: 1px solid orange;
-				width: calc(100% - 18px);
-				width: -webkit-fill-available;
-				display: inline-block;
-				margin-bottom: 4px;
-				text-decoration: none;
-			}
-
-			/* Selected and Hovered Over Folders, Files, Repositories and Branches */
-			.folder:focus, .file:focus, .repo:focus, .branch:focus, .folder:hover, .file:hover, .repo:hover, .branch:hover {
-				background-color: #3D3D3D;
-			}
-			/* Selected Folders, Files, Repositories and Branches */
-			.folder:focus, .file:focus, .repo:focus, .branch:focus {
-				border: 1px solid blue;
-				color: white;
-			}
-			/* Visited Folders, Files, Repositories and Branches */
-			.folder:active, .file:active, .repo:active, .branch:active, .folder:visited, .file:visited, .repo:visited, .branch:visited {
-				color: white;
-			}
-
-			/* Icons */
-			.folder::before {
-				content: '🗁 ';
-			}
-			.file::before {
-				content: '🖹 ';
-			}
-			.repo::before {
-				content: '🕮 ';
-			}
-			.branch::before {
-				content: '⑃ ';
-			}
-
-			/* File Path */
-			.path {
-				font-weight: bold;
-				color: orange;
-				word-break: break-all;
-			}
-			.path a:focus, .path a:active {
-				color: red;
-			}
-
-			/* Description Text */
-			.description {
-				display: block;
-				text-align: center;
-			}
-
-			/* Footer Text */
-			.footer {
-				display: block;
-				text-align: center;
-			}
-
-			/* 404 */
-			.error {
-				display: block;
-				text-align: center;
-			}
-
-			/* Clone Text */
-			.clone {
-				font-style: italic;
-				color: lightgray;
-				display: inline-block;
-			}
-
-			/* Raw Link */
-			.raw-link {
-				font-weight: bold;
-				float: right;
-				display: inline-block;
-			}
-
-			/* File Content */
-			pre {
-				border: 2px solid yellow;
-				background-color: black;
-				padding: 4px;
-				-moz-tab-size: 2;
-				tab-size: 2;
-				white-space: pre-wrap;
-				word-wrap: break-word;
-			}
-
-			/* Readme Documents */
-			.readme {
-				text-align: left;
-			}
-			hr.readme {
-				border: 1px solid white;
-			}
-			li.readme {
-				margin-left: 40px;
-			}
-
-			/* Scrollbar */
-			::-webkit-scrollbar {width: 10px; height: 10px;}
-			::-webkit-scrollbar-track {background: #0D0D0D;}
-			::-webkit-scrollbar-thumb {background: orange;}
-			::-webkit-scrollbar-thumb:hover {background: #BB6100;}
-			::-webkit-scrollbar-corner {background: #0D0D0D;}
-
-			/* Mobile view */
-			@media only screen and (max-device-width: 960px) {
-				.clone {
-					margin-bottom: 16px
-				}
-				.raw-link {
-					float: none;
-				}
-			}
-		</style>
-	</head>
-	<body>
-		<h1><?php echo $TITLE; ?></h1>
-<?php
-	$path = $_SERVER["PATH_INFO"];
-	$path = str_replace("\"","\\\"",$path);
-	$path = str_replace("'","\'",$path);
-	$path = str_replace("$","\$",$path);
-	$path = str_replace(")","\)",$path);
-	$path = str_replace("(","\(",$path);
-	$path = str_replace("`","\`",$path);
-	$path = str_replace("|","\|",$path);
-	$path = str_replace("&","\&",$path);
-	if (!isset($path) || $path === "") {header("Location: ".$ROOT.$SCRIPT."/");}
-
-	echo "		<span class=\"path\"><a href=\"".$ROOT.$SCRIPT."/\">".$TITLE."</a>";
-	$full = $ROOT.$SCRIPT;
-	foreach (explode("/", substr($path,1)) as $part) {
-		$full .= "/".htmlspecialchars($part);
-		echo "/<a href=\"".$full."\">".htmlspecialchars($part)."</a>";
-	}
-	echo "</span><br><br>\n";
-
-	if ($path === "/") {
-		echo "		<span class=\"clone\">git clone git://".$_SERVER["SERVER_NAME"]."/&lt;repo&gt;.git</span><br><br>\n";
-		$repos = preg_grep("/(.git)$/", scandir($ORIGINAL));
-		foreach ($repos as $repo) {
-			$desc = file_get_contents($ORIGINAL."/".$repo."/description");
-			echo "<a href=\"".$ROOT.$SCRIPT."/".substr($repo,0,-4)."/".$BRANCH."\" class=\"repo\"><b>".substr($repo,0,-4)."</b> :: ".$desc."</a><br>";
-		}
-	} else {
-		$repo = explode("/", substr($path,1))[0];
-		if (!is_dir($ORIGINAL."/".$repo.".git")) {
-			echo "		<span class=\"error\">\n			<b>404! Repository not found!</b><br>\n";
-			echo "			[<a href=\"".$ROOT.$SCRIPT."/\">RETURN</a>]\n		</span>\n";
-		} else {
-			$branch = explode("/", substr($path,1))[1];
-			echo "		<span class=\"clone\">git clone ";
-			if ($branch !== $BRANCH && $branch !== "") {echo "-b ".$branch." ";}
-			echo "<a href=\"git://".$_SERVER["SERVER_NAME"]."/".$repo.".git\">git://".$_SERVER["SERVER_NAME"]."/".$repo.".git</a></span>\n";
-			$rest = implode("/",array_slice(explode("/", substr($path,1)),2));
-			chdir($ORIGINAL."/".$repo.".git");
-			if (!isset($branch)) {header("Location: ".$ROOT.$SCRIPT."/".$repo."/");}
-			if (substr($path,-1) !== "/" && $rest === "" && $branch !== "" && isset($branch)) {header("Location: ".$ROOT.$SCRIPT."/".$repo."/".$branch."/");}
-			if ($branch === "") {
-				echo "<br><br>\n";
-				$branches = shell_exec("git show-branch");
-				foreach (explode("\n",$branches) as $cbranch) {
-					echo preg_replace("/\[(.+)\] (.+)/","<a href=\"".$ROOT.$SCRIPT."/".$repo."/$1\" class=\"branch\">$1</a>",$cbranch)."<br>";
-				}
-			} else {
-				$files = shell_exec("git ls-tree --full-name ".$branch." ".$rest);
-				if (substr($rest,-1) !== "/" && $rest !== "") {
-					if (explode(" ",explode("\n",$files)[0])[1] === "tree") {header("Location: ".$ROOT.$SCRIPT."/".$repo."/".$branch."/".$rest."/");}
-				}
-				if (substr($rest,-1) === "/" && $rest !== "") {
-					if (explode(" ",explode("\n",shell_exec("git ls-tree --full-name ".$branch." ".substr($rest,0,-1)))[0])[1] === "blob") {header("Location: ".$ROOT.$SCRIPT."/".$repo."/".$branch."/".substr($rest,0,-1));}
-				}
-				if ($rest === "") {$ctype = "tree";} else {
-					if (substr($rest,-1) === "/") {
-						$ctype = "tree";
-					} else {
-						$ctyle = "blob";
-					}
-				}
-				if ($ctype === "tree") {
-					$folderstxt = "";
-					if ($rest !== "") {$folderstxt .= "		<a href=\"../\" class=\"folder\">../</a><br>\n";}
-					$filestxt = "";
-					foreach (explode("\n",$files) as $file) {
-						$name = explode(" ",$file);
-						if ($name[1] == "tree") {
-							$folderstxt .= "		<a href=\"".$ROOT.$SCRIPT."/".$repo."/".$branch."/".explode("\t",$name[2])[1]."/\" class=\"folder\">".end(explode("/",explode("\t",$name[2])[1]))."/</a><br>\n";
-						}
-						if ($name[1] == "blob") {
-							$filestxt .= "		<a href=\"".$ROOT.$SCRIPT."/".$repo."/".$branch."/".explode("\t",$name[2])[1]."\" class=\"file\">".end(explode("/",explode("\t",$name[2])[1]))."</a><br>\n";
-						}
-					}
-					echo "<br><br>\n";
-					echo $folderstxt;
-					echo $filestxt;
-					if ($readmefile = shell_exec("git ls-tree --full-name ".$branch." ".$rest."README")) {
-						$readme = shell_exec("git cat-file -p ".explode("\t",explode(" ",explode("\n",$readmefile)[0])[2])[0]);
-						$readme = preg_replace("/>/","&gt;",$readme);
-						$readme = preg_replace("/</","&lt;",$readme);
-						$readme = preg_replace("/(^|\n)# (.+)/","<h1 class=\"readme\">$2</h1>",$readme);
-						$readme = preg_replace("/(^|\n)## (.+)/","<h2 class=\"readme\">$2</h2>",$readme);
-						$readme = preg_replace("/(^|\n)### (.+)/","<h3 class=\"readme\">$2</h3>",$readme);
-						$readme = preg_replace("/(^|\n)#### (.+)/","<h4 class=\"readme\">$2</h4>",$readme);
-						$readme = preg_replace("/(^|\n)##### (.+)/","<h5 class=\"readme\">$2</h5>",$readme);
-						$readme = preg_replace("/(^|\n)###### (.+)/","<h6 class=\"readme\">$2</h6>",$readme);
-						$readme = preg_replace("/```([^`]+)```/","<pre style=\"color:magenta;font-style:italic\">$1</pre>",$readme);
-						$readme = preg_replace("/`([^`]+)`/","<span style=\"color:magenta;font-style:italic\">$1</span>",$readme);
-						$readme = preg_replace("/(^|\n)---($|\n)/","<br><hr class=\"readme\">",$readme);
-						$readme = preg_replace("/(^|\n) - (.*)/","<li class=\"readme\">$2</li>",$readme);
-						$readme = preg_replace("/\n\n/","<br>",$readme);
-						$readme = preg_replace("/\[img src=\"([^\"]+)\"\]/","<img src=\"$1\" class=\"readme\" style=\"max-width:100%\" />",$readme);
-						$readme = preg_replace("/\[link src=\"([^\"]+)\"\]/","<a href=\"$1\" class=\"readme\">$1</a>",$readme);
-						echo "		<br>\n		".$readme;
-					}
-				} else {
-					if (shell_exec("git ls-tree --full-name ".$branch." ".$rest)) {
-						$content = shell_exec("git cat-file -p ".explode("\t",explode(" ",explode("\n",$files)[0])[2])[0]);
-						if (isset($_GET["raw"])) {
-							ob_clean();
-							header("Content-type: text/plain");
-							echo $content;
-							die();
-						}
-						echo "<a class=\"raw-link\" href=\"?raw\">Raw View</a>";
-						echo "<pre>\n".htmlspecialchars($content)."</pre>\n";
-					} else {
-						echo "		<span class=\"error\">\n		<b>404! File not found!</b><br>\n";
-						echo "			[<a href=\"".$ROOT.$SCRIPT."/".$repo."/".$branch."\">RETURN</a>]\n		</span>\n";
-					}
-				}
-			}
-		}
-	}
-	if ($DESCRIPTION !== "" && $path === "/") {
-		echo "		<br><br>\n";
-		echo "		<span class=\"description\">".$DESCRIPTION."</span>\n";
-	}
-	if ($FOOTER !== "") {
-		echo "		<br><br>\n";
-		echo "		<small class=\"footer\">".$FOOTER."</small>\n";
-	}
-?>
-		<br>
-	</body>
-</html>
diff --git a/head.php b/head.php
new file mode 100644
index 0000000..787ecc4
--- /dev/null
+++ b/head.php
@@ -0,0 +1,33 @@
+<?php
+	$MOBILE = (strpos($_SERVER["HTTP_USER_AGENT"],"Mobile") !== FALSE);
+	if (isset($PAGE_TITLE)) {
+		$PAGE_TITLE .= " - ".SITE_TITLE;
+	} else {
+		$PAGE_TITLE = SITE_TITLE;
+	}
+?>
+<!DOCTYPE html>
+<html>
+	<head>
+		<title><?= $PAGE_TITLE ?></title>
+		<meta name="viewport" content="width=device-width, initial-scale=1">
+		<link rel="stylesheet" href="https://use.typekit.net/ihu3uze.css">
+		<link rel="stylesheet" href="//www.barryserver.net/assets/style.css">
+		<link rel="stylesheet" href="//files.barryserver.net/stylesheets/git.css">
+		<link rel="stylesheet" href="/style.css">
+		<script src="//files.barryserver.net/prettify/light.js"></script>
+	</head>
+	<body>
+<?php if (!$MOBILE) { ?>
+		<path>// <a href="/"><?= SITE_TITLE ?></a> <?php $c = ""; foreach (explode("/",explode("?",$_SERVER["REQUEST_URI"])[0]) as $page) {$c .= $page."/"; if ($c !== "/") {echo "/ <a href=\"".htmlspecialchars($c)."\">".htmlspecialchars($page)."</a> ";}} ?></path>
+<?php } ?>
+<?php if (isset($SIDE_LINKS) && count($SIDE_LINKS) > 0) { ?>
+		<sidenav>
+			<h1>Related</h1>
+			<ul>
+<?php foreach ($SIDE_LINKS as $txt => $url) { ?>
+				<li><a href="<?= $url ?>"><?= $txt ?></a></li>
+<?php } ?>
+			</ul>
+		</sidenav>
+<?php } ?>
diff --git a/index.php b/index.php
new file mode 100644
index 0000000..d0bb776
--- /dev/null
+++ b/index.php
@@ -0,0 +1,14 @@
+<?php session_start(); ?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/config.php"; ?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1>Repositories</h1>
+<?php
+	$repos = preg_grep("/(.git)$/", scandir(GIT_DIR));
+	foreach ($repos as $repo) {
+		$desc = file_get_contents(GIT_DIR."/".$repo."/description");
+		if (substr($desc,0,7) !== "PRIVATE" || isset($_SESSION["username"])) { ?>
+	<a href="/<?= substr($repo,0,-4) ?>" class="repo"><b><?= substr($repo,0,-4) ?></b> :: <?= $desc ?></a>
+<?php }} ?>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
diff --git a/pages.conf b/pages.conf
new file mode 100644
index 0000000..966bdd9
--- /dev/null
+++ b/pages.conf
@@ -0,0 +1,32 @@
+location /style.css {
+	try_files $uri $uri/ =404;
+}
+location ~ ^/(tree|index|blob|commit|commits)\.php {
+	include /etc/nginx/fastcgi.conf;
+	fastcgi_pass unix:/run/php-fpm/php-fpm.sock;
+}
+location / {
+	rewrite ^/([^/]+)(/?)$ /tree.php?repo=$1;
+
+	rewrite ^/([^/]+)/tree$ /tree.php?repo=$1;
+	rewrite ^/([^/]+)/tree/([^/]*)(/?)$ /tree.php?repo=$1&object=$2;
+	rewrite ^/([^/]+)/tree/([^/]*)/(.*)$ /tree.php?repo=$1&object=$2&path=$3;
+
+	rewrite ^/([^/]+)/blob$ /blob.php?repo=$1;
+	rewrite ^/([^/]+)/blob/([^/]*)(/?)$ /blob.php?repo=$1&object=$2;
+	rewrite ^/([^/]+)/blob/([^/]*)/(.*)$ /blob.php?repo=$1&object=$2&path=$3;
+
+	rewrite ^/([^/]+)/raw$ /blob.php?raw&repo=$1;
+	rewrite ^/([^/]+)/raw/([^/]*)(/?)$ /blob.php?raw&repo=$1&object=$2;
+	rewrite ^/([^/]+)/raw/([^/]*)/(.*)$ /blob.php?raw&repo=$1&object=$2&path=$3;
+
+	rewrite ^/([^/]+)/commit$ /commit.php?repo=$1;
+	rewrite ^/([^/]+)/commit/([^/]*)(/?)$ /commit.php?repo=$1&object=$2;
+	rewrite ^/([^/]+)/commit/([^/]*)/(.*)$ /commit.php?repo=$1&object=$2&path=$3;
+
+	rewrite ^/([^/]+)/commits$ /commits.php?repo=$1;
+	rewrite ^/([^/]+)/commits/([^/]*)(/?)$ /commits.php?repo=$1&object=$2;
+	rewrite ^/([^/]+)/commits/([^/]*)/(.*)$ /commits.php?repo=$1&object=$2&path=$3;
+
+	try_files $uri $uri/ =404;
+}
diff --git a/style.css b/style.css
new file mode 100644
index 0000000..b7f76e3
--- /dev/null
+++ b/style.css
@@ -0,0 +1,6 @@
+.aside {
+	top: calc(2em + 24px);
+}
+sidenav {
+	top: calc(2em + 64px);
+}
diff --git a/tree.php b/tree.php
new file mode 100644
index 0000000..79e154b
--- /dev/null
+++ b/tree.php
@@ -0,0 +1,97 @@
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/config.php"; ?>
+<?php $SIDE_LINKS = array(); ?>
+<?php
+	if (!isset($_GET["repo"])) {header("Location: /");die();}
+	$repo = $_GET["repo"]??"";
+	if (isset($_GET["repo"])) {
+		$PAGE_TITLE = $repo;
+	}
+
+	if (!is_dir(GIT_DIR."/".$repo.".git")) { ?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1>Repository not found</h1>
+	<article>The repository you were looking for was not found on this server. Please check the URL and look for errors. If there are no errors, then the repository does not exist. Please use the index to reach any repositories you wish to access.</article>
+</main>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>
+<?php	die();}
+
+	$branch = $_GET["object"]??DEFAULT_BRANCH;
+	$path = $_GET["path"]??".";
+	chdir(GIT_DIR."/".$repo.".git");
+	$commits = shell_exec("git rev-list --all --count");
+	if ($commits == 0) {
+		$SIDE_LINKS["git clone"] = "git://".$_SERVER["SERVER_NAME"]."/".$repo.".git";
+		require_once $_SERVER["DOCUMENT_ROOT"]."/head.php";
+		echo "<main><h1>".$repo."</h1>\n";
+		echo "No commits yet</main>";
+		require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php";
+		die();
+	}
+	if ($branch === "") {
+		$SIDE_LINKS["git clone"] = "git://".$_SERVER["SERVER_NAME"]."/".$repo.".git";
+		require_once $_SERVER["DOCUMENT_ROOT"]."/head.php";
+		echo "<main><h1>".$repo."</h1>\n";
+		$branches = shell_exec("git show-branch");
+		foreach (explode("\n",$branches) as $cbranch) {
+			echo preg_replace("/\[(.+)\] (.+)/","<a href=\"/".$repo."/tree/$1\" class=\"branch\">$1</a><br>",$cbranch);
+		}
+	} else {
+		$files = shell_exec("git ls-tree --full-name ".escapeshellarg($branch)." ".escapeshellarg($path));
+		if (substr($path,-1) !== "/" && $path !== "") {
+			if (explode(" ",explode("\n",$files)[0])[1] === "tree") {
+				header("Location: /".$repo."/tree/".$branch."/".$path."/");
+				die();
+			}
+		}
+		if (substr($path,-1) !== "/" && $path !== "") {
+			if (count(explode("\n",$files)) === 1) {
+				header("Location: /".$repo."/blob/".$branch."/".$path);
+				die();
+			}
+		}
+		if (substr($path,-1) === "/" && $path !== "") {
+			if (explode(" ",explode("\n",shell_exec("git ls-tree --full-name ".escapeshellarg($branch)." ".escapeshellarg(substr($path,0,-1))))[0])[1] === "blob") {
+				header("Location: /".$repo."/blob/".$branch."/".substr($path,0,-1));
+				die();
+			}
+		}
+		$SIDE_LINKS["git clone"] = "git://".$_SERVER["SERVER_NAME"]."/".$repo.".git";
+		if ($path == ".") {$SIDE_LINKS["Branches"] = "/".$repo."/tree/";}
+		$SIDE_LINKS["Show History"] = "/".$repo."/commits/".$branch."/".$path;
+		if ($path !== ".") {
+			$PAGE_TITLE = basename($path)."/ @ ".$PAGE_TITLE;
+		}
+		require_once $_SERVER["DOCUMENT_ROOT"]."/head.php"; ?>
+<main>
+	<h1><?= $repo ?></h1>
+<?php           $lastcommit = shell_exec("git log --summary --quiet --oneline --abbrev-commit --format=format:'<b>%an</b> %s <span><a href=\"/".escapeshellcmd($repo)."/commit/%H/".escapeshellcmd($path)."\">%h</a> (%ar)</span>' -n 1 ".escapeshellarg($branch)." -- ".escapeshellarg($path));
+		echo "<span class=\"last-commit\">".$lastcommit."</span>";
+		$folderstxt = "";
+		if ($path !== ".") {$folderstxt .= "		<a href=\"../\" class=\"folder\">../</a><br>\n";}
+		$filestxt = "";
+		foreach (explode("\n",$files) as $file) {
+			$name = explode(" ",$file);
+			if ($name[1] == "tree") {
+				$folderstxt .= "		<a href=\"/".$repo."/tree/".$branch."/".explode("\t",$name[2])[1]."/\" class=\"folder\">".end(explode("/",explode("\t",$name[2])[1]))."/</a><br>\n";
+			}
+			if ($name[1] == "blob") {
+				$filestxt .= "		<a href=\"/".$repo."/blob/".$branch."/".explode("\t",$name[2])[1]."\" class=\"file\">".end(explode("/",explode("\t",$name[2])[1]))."</a><br>\n";
+			}
+		}
+		echo $folderstxt;
+		echo $filestxt;
+		if ($readmefile = shell_exec("git ls-tree --full-name ".escapeshellarg($branch)." ".escapeshellarg($rest)."README.")) {
+			$readme = shell_exec("git cat-file -p ".explode("\t",explode(" ",explode("\n",$readmefile)[0])[2])[0]." | md2html");
+			echo "\n		</main><main>".$readme;
+		}
+	}
+?>
+</main>
+<?php
+if ($path === "." && $branch) {
+$desc = file_get_contents(GIT_DIR."/".$repo.".git/description");
+echo "<main class=\"aside\"><h1>About</h1>".$desc."</main>";
+}
+?>
+<?php require_once $_SERVER["DOCUMENT_ROOT"]."/foot.php"; ?>