GITWEB(1)
๐ GITWEB(1) โ the Git Manual, but make it cute ๐
okay so bestie, welcome to the gitweb page โ it's part of the Git Manual, and honestly? it's giving "your repos finally got a glow-up and a public-facing website" โจ
โจ NAME โจ
gitweb โ the Git web interface, aka the web frontend to Git repositories ๐ฆ
Like, literally the pretty face your repos put on for the internet. No cap.
๐ SYNOPSIS ๐
So the whole "how do I even start this" situation โ here's the move:
To get started with gitweb, run git-instaweb(1) from a Git repository.
This will configure and start your web server, and run a web browser
pointing to gitweb.
That's it. That's the whole launch ritual ๐
Run git-instaweb(1) from inside a Git repository and it will: configure your web server, start your web server, and open a web browser pointing right at gitweb. Three-for-one. Iconic behaviour, honestly.
๐ธ DESCRIPTION ๐ธ
gitweb gives you a whole web interface to Git repositories. Main character energy for your commit history, fr fr.
Here's the feature rundown, bestie โ every single one, no skipping ๐
- Viewing multiple Git repositories with common root. Like a lil' lobby for all your repos that share a root. ๐
- Browsing every revision of the repository. Every. Single. One. Time travel, but make it git. ๐ฐ๏ธ
- Viewing the contents of files in the repository at any revision. Pick a revision, any revision, and peek at what that file looked like back then. ๐ซถ
- Viewing the revision log of branches, history of files and directories, seeing what was changed, when, and by whom. The full detective arc โ the what, the when, and the who-did-this ๐ญ
- Viewing the blame/annotation details of any file (if enabled). Yes, the blame view. Yes, it will expose your 3am commits. But only if enabled, so like, that's on you ๐
- Generating RSS and Atom feeds of commits, for any branch. The feeds are auto-discoverable in modern web browsers. Feed girlies stay winning โ and these? They're auto-discoverable in modern browsers, so the browser literally finds them for you. ๐ฅ
- Viewing everything that was changed in a revision, and stepping through revisions one at a time, viewing the history of the repository. Scroll through history one revision at a time like it's a feed you actually enjoy. โญ
- Finding commits whose commit messages match a given search term. Search the commit messages for a term โ yes, this is the "where did I write that thing" button. ๐
and if you wanna peek at the source code itself, it's here, browsed using gitweb itself (so meta, so slay):
https://repo.or.cz/w/git.git/tree/HEAD:/gitweb/
more of this page is coming, don't go anywhere bestie โ we're just getting started ๐
๐ธ CONFIGURATION ๐ธ
So like, gitweb has opinions and a whole personality, and you can tune basically all of it through the config file gitweb_config.perl or /etc/gitweb.conf. That's it, that's the whole vibe. Details live in gitweb.conf(5) if you wanna go deeper, bestie. ๐
โจ Repositories โจ
gitweb can show you info from one or more Git repositories. The catch? They all have to be on the local filesystem, and they all have to share a common repository root โ like, all tucked under a single parent repository. (But also peep the "Advanced web server setup" section, specifically the "Webserver configuration with multiple projects' root" subsection, if that's not your vibe.)
our $projectroot = '/path/to/parent/directory';
The default value for $projectroot is /pub/git. You can change it while building gitweb via the GITWEB_PROJECTROOT build configuration variable. Slay.
By default, all Git repositories under $projectroot are visible and available to gitweb. The list of projects is generated by default by scanning the $projectroot directory for Git repositories โ or, to be exact, for object databases, because gitweb is genuinely not interested in a working area and is best suited to showing "bare" repositories. Working trees? Not her main character era. ๐
The name of the repository in gitweb is the path to its $GIT_DIR (its object database) relative to $projectroot. So the repository $repo can be found at "$projectroot/$repo". Simple math, iconic behavior.
๐ Projects list file format ๐
Instead of letting gitweb find repositories by scanning the filesystem starting from $projectroot, you can hand it a pre-generated list of visible projects by setting $projects_list to point to a plain text file with a list of projects (plus some extra info). Very "here's my curated list, don't ask questions."
This file uses the following format:
- One record (for project / repository) per line; does not support line continuation (newline escaping). One line, one project, no exceptions.
- Leading and trailing whitespace are ignored. She's chill like that.
- Whitespace separated fields; any run of whitespace can be used as the field separator (the rules for Perl's
split(" ", $line)). - Fields use modified URI encoding, defined in RFC 3986, section 2.1 (Percent-Encoding), or rather "Query string encoding" (see https://en.wikipedia.org/wiki/Query_string#URL_encoding). The difference being that SP (
" ") can be encoded as"+"(and therefore"+"has to be also percent-encoded).
Reserved characters are: "%" (used for encoding), "+" (can be used to encode SPACE), and all whitespace characters as defined in Perl, including SP, TAB and LF (used to separate fields in a record). Respect the reserved characters or she will simply not parse you. ๐ญ
- Currently recognized fields are:
<repository path> : path to repository GIT_DIR, relative to $projectroot
<repository owner> : displayed as repository owner, preferably full name, or email, or both
You can generate the projects list index file using the project_index action (that's the TXT link on the projects list page) directly from gitweb; see also the "Generating projects list using gitweb" section below.
Example contents:
foo.git Joe+R+Hacker+<joe@example.com>
foo/bar.git O+W+Ner+<owner@example.org>
By default this file controls only which projects are visible on the projects list page (and note that entries that do not point to correctly recognized Git repositories won't be displayed by gitweb at all). Even if a project is not visible on the projects list page, you can still view it by hand-crafting a gitweb URL. Sneaky, but valid. ๐ By setting the $strict_export configuration variable (see gitweb.conf(5)) to a true value, you can allow viewing only of repositories also shown on the overview page โ meaning only projects explicitly listed in the projects list file will be accessible. Locked down, periodt.
๐ฆ Generating projects list using gitweb ๐ฆ
We assume that GITWEB_CONFIG has its default Makefile value, namely gitweb_config.perl. Put the following in the gitweb_make_index.perl file:
read_config_file("gitweb_config.perl");
$projects_list = $projectroot;
Then create the following script to get a list of projects in the format suitable for the GITWEB_LIST build configuration variable (or the $projects_list variable in gitweb config):
#!/bin/sh
export GITWEB_CONFIG="gitweb_make_index.perl"
export GATEWAY_INTERFACE="CGI/1.1"
export HTTP_ACCEPT="*/*"
export REQUEST_METHOD="GET"
export QUERY_STRING="a=project_index"
perl -- /var/www/cgi-bin/gitweb.cgi
Run this script and save its output to a file. That file could then be used as your projects list file, which means you can set $projects_list to its filename. Chef's kiss. ๐ค
๐ Controlling access to Git repositories ๐
By default, all Git repositories under $projectroot are visible and available to gitweb. But you can configure how gitweb controls access to repositories. Choose your fighter:
- As described in the "Projects list file format" section, you can control which projects are visible by selectively including repositories in the projects list file, and setting the
$projects_listgitweb configuration variable to point to it. With$strict_exportset, the projects list file can be used to control which repositories are available as well. Gatekeeping, but make it efficient. - You can configure gitweb to only list and allow viewing of the explicitly exported repositories via the
$export_okvariable in the gitweb config file; see thegitweb.conf(5)manpage. If it evaluates to true, gitweb shows repositories only if this file named by$export_okexists in its object database (i.e. if the directory has the magic file named$export_ok).
For example, git-daemon(1) by default (unless the --export-all option is used) allows pulling only for those repositories that have a git-daemon-export-ok file. Adding
our $export_ok = "git-daemon-export-ok";
makes gitweb show and allow access only to those repositories that can be fetched from via the git:// protocol. Matching outfits, cute.
- Finally, it is possible to specify an arbitrary perl subroutine that will be called for each repository to determine if it can be exported. The subroutine receives an absolute path to the project (repository) as its only parameter (i.e.
"$projectroot/$project").
For example, if you use mod_perl to run the script, and have dumb HTTP protocol authentication configured for your repositories, you can use the following hook to allow access only if the user is authorized to read the files:
$export_auth_hook = sub {
use Apache2::SubRequest ();
use Apache2::Const -compile => qw(HTTP_OK);
my $path = "$_[0]/HEAD";
my $r = Apache2::RequestUtil->request;
my $sub = $r->lookup_file($path);
return $sub->filename eq $path
&& $sub->status == Apache2::Const::HTTP_OK;
};
Custom logic, custom slay. โจ
๐ Per-repository gitweb configuration ๐
You can configure individual repositories shown in gitweb by creating a file in the GIT_DIR of the Git repository, or by setting some repo configuration variable (in GIT_DIR/config, see git-config(1)). Per-repo customization is the moment, honestly.
You can use the following files in the repository:
README.htmlโ A html file (HTML fragment) which is included on the gitweb project "summary" page inside a<div>block element. You can use it for a longer description of a project, to provide links (for example to the project's homepage), etc. Heads up though: this is recognized only if XSS prevention is off ($prevent_xssis false, seegitweb.conf(5)); a way to include a README safely when XSS prevention is on may be worked out in the future. So like, don't just paste mystery HTML in there with$prevent_xsson and expect it to show. ๐description(orgitweb.description) โ Short (shortened to$projects_list_description_widthin the projects list page, which is25characters by default; seegitweb.conf(5)) single line description of a project (of a repository). Plain text file; HTML will be escaped. By default set to
Unnamed repository; edit this file to name it for gitweb.
from the template during repository creation, usually installed in /usr/share/git-core/templates/. You can use the gitweb.description repo configuration variable, but the file takes precedence. File > config, always.
category(orgitweb.category) โ Single line category of a project, used to group projects if$projects_list_group_categoriesis enabled. By default (file and configuration variable absent), uncategorized projects are put in the$project_list_default_categorycategory. You can use thegitweb.categoryrepo configuration variable, but the file takes precedence.
The configuration variables $projects_list_group_categories and $project_list_default_category are described in gitweb.conf(5). Go read, bestie.
cloneurl(or multiple-valuedgitweb.url) โ File with repository URL (used for clone and fetch), one per line. Displayed in the project summary page. You can use the multiple-valuedgitweb.urlrepository configuration variable for that, but the file takes precedence.
This is the per-repository enhancement / version of the global prefix-based @git_base_url_list gitweb configuration variable (see gitweb.conf(5)). Glow-up behavior. ๐
gitweb.ownerโ You can use thegitweb.ownerrepository configuration variable to set the repository's owner. It is displayed in the project list and summary page.
If it's not set, the filesystem directory's owner is used (via the GECOS field, i.e. the real name field from getpwuid(3)) if $projects_list is unset (gitweb scans $projectroot for repositories); if $projects_list points to a file with a list of repositories, then the project owner defaults to the value from this file for the given repository. Either way, somebody's getting credit. ๐ซถ
- various
gitweb.*config variables (in config) โ Read the description of the%featurehash for the detailed list and descriptions. See also the "Configuring gitweb features" section ingitweb.conf(5). So many knobs, so little time. ๐๏ธ
๐ธ ACTIONS, AND URLS ๐ธ
Okay so here's the tea, bestie: gitweb has two ways of figuring out what you want. It can go the โจprettyโจ route with path_info (component) based URLs, or it can just shove literally everything through query parameters. Either way, the typical gitweb URL breaks down into five components ๐:
.../gitweb.cgi/<repo>/<action>/<revision>:/<path>?<arguments>
repo
The repository the action will be performed on. ๐
Every single action except the ones that list all available projects (in whatever form) requires this parameter. No repo, no service. ๐
action
The action that's gonna run. If repo isn't set, this defaults to projects_list; otherwise it defaults to summary.
revision
The revision being shown. Defaults to HEAD. โญ
path
The path inside the repository where the action happens โ but only for the actions that actually need it.
arguments
Any arguments that control how the action behaves. ๐๏ธ
Some actions literally require (or at least allow) you to specify two revisions, and sometimes even two pathnames. In its most general form, that path_info (component) based gitweb URL looks like this:
.../gitweb.cgi/<repo>/<action>/<revision-from>:/<path-from>..<revision-to>:/<path-to>?<arguments>
Every action is implemented as a subroutine, and it must be present in the %actions hash. Some actions are disabled by default and have to be switched on via the feature mechanism. For example, to enable the blame view, add this to the gitweb configuration file:
$feature{'blame'}{'default'} = [1];
โก Actions: โก
The standard actions are:
project_listโ Lists the available Git repositories. This is the default command if no repository is specified in the URL. ๐๏ธsummaryโ Displays a summary about the given repository. This is the default command if no action is specified in the URL and only the repository is specified. ๐heads,remotesโ Lists all local or all remote-tracking branches in the given repository.
The latter (remotes) is not available by default unless you configure it. ๐
tagsโ Lists all tags (lightweight and annotated) in the given repository. ๐ท๏ธblob,treeโ Shows the files and directories in a given repository path, at a given revision. This is the default command if no action is specified in the URL and a path is given.blob_plainโ Returns the raw data for the file in the given repository, at the given path and revision. Links to this action are markedraw. ๐blobdiffโ Shows the difference between two revisions of the same file.blame,blame_incrementalโ Shows the blame (also called annotation) information for a file. On a per-line basis it shows the revision in which that line was last changed and the user who committed the change. The incremental version โ which, if configured, is used automatically when JavaScript is enabled โ uses Ajax to incrementally add blame info to the contents of the given file. ๐
This action is disabled by default for performance reasons. (Yes, it's giving "expensive", handle with care ๐ )
commit,commitdiffโ Shows information about a specific commit in a repository. Thecommitview shows info about the commit in more detail; thecommitdiffaction shows the changeset for the given commit. ๐patchโ Returns the commit in plain-text mail format, suitable for applying withgit-am(1). ๐ฌtagโ Displays a specific annotated tag (tag object).log,shortlogโ Shows log information (the commit message, or just the commit subject) for a given branch, starting from the given revision.
The shortlog view is more compact โ one commit per line. โจ
historyโ Shows the history of the file or directory at a given repository path, starting from the given revision (defaults toHEAD, i.e. the default branch).
This view is similar to the shortlog view. ๐ฐ๏ธ
rss,atomโ Generates an RSS (or Atom) feed of changes to the repository. ๐ฅ
๐ฅ๏ธ WEBSERVER CONFIGURATION ๐ฅ๏ธ
This section explains how to configure some common webservers to run gitweb. In all cases, /path/to/gitweb in the examples is the directory where you installed gitweb, and it contains gitweb_config.perl. ๐ซถ
If you've configured a web server for gitweb that isn't listed here, please send in the instructions so they can be included in a future release. Community effort, bestie! ๐
Apache as CGI
Apache has to be configured to support CGI scripts in the directory where gitweb is installed. Let's assume that's the /var/www/cgi-bin directory.
ScriptAlias /cgi-bin/ "/var/www/cgi-bin/"
<Directory "/var/www/cgi-bin">
Options Indexes FollowSymlinks ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>
With that configuration, the full path to browse repositories would be:
http://server/cgi-bin/gitweb.cgi
Apache with mod_perl, via ModPerl::Registry
You can use mod_perl with gitweb. You must install Apache::Registry (for mod_perl 1.x) or ModPerl::Registry (for mod_perl 2.x) to enable this support. ๐ง
Assuming gitweb is installed to /var/www/perl, the following Apache configuration (for mod_perl 2.x) is suitable.
Alias /perl "/var/www/perl"
<Directory "/var/www/perl">
SetHandler perl-script
PerlResponseHandler ModPerl::Registry
PerlOptions +ParseHeaders
Options Indexes FollowSymlinks +ExecCGI
AllowOverride None
Order allow,deny
Allow from all
</Directory>
With that configuration, the full path to browse repositories would be:
http://server/perl/gitweb.cgi
Apache with FastCGI
Gitweb works with Apache and FastCGI. First you need to rename, copy or symlink gitweb.cgi to gitweb.fcgi. Let's assume gitweb is installed in the /usr/share/gitweb directory. The following Apache configuration is suitable (UNTESTED! ๐ญ)
FastCgiServer /usr/share/gitweb/gitweb.cgi
ScriptAlias /gitweb /usr/share/gitweb/gitweb.cgi
Alias /gitweb/static /usr/share/gitweb/static
<Directory /usr/share/gitweb/static>
SetHandler default-handler
</Directory>
With that configuration, the full path to browse repositories would be:
http://server/gitweb
๐ ADVANCED WEB SERVER SETUP ๐
okay bestie, advanced mode: all of those examples use request rewriting, and they need mod_rewrite (or an equivalent โ examples below are written for Apache). no cap.
๐ธ Single URL for gitweb and for fetching ๐ธ
If you want one URL for both gitweb and your http:// repositories, you can configure Apache like this:
<VirtualHost *:80>
ServerName git.example.org
DocumentRoot /pub/git
SetEnv GITWEB_CONFIG /etc/gitweb.conf
# turning on mod rewrite
RewriteEngine on
# make the front page an internal rewrite to the gitweb script
RewriteRule ^/$ /cgi-bin/gitweb.cgi
# make access for "dumb clients" work
RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ \
/cgi-bin/gitweb.cgi%{REQUEST_URI} [L,PT]
</VirtualHost>
The above configuration expects your public repositories to live under /pub/git and will serve them as http://git.domain.org/dir-under-pub-git, both as clonable Git URL and as browsable gitweb interface. If you then start your git-daemon(1) with --base-path=/pub/git --export-all then you can even use the git:// URL with exactly the same path. โจ
Setting the environment variable GITWEB_CONFIG will tell gitweb to use the named file (i.e. in this example /etc/gitweb.conf) as a configuration for gitweb. You donโt really need it in above example; it is required only if your configuration file is in different place than built-in (during compiling gitweb) gitweb_config.perl or /etc/gitweb.conf. See gitweb.conf(5) for details, especially information about precedence rules.
If you use the rewrite rules from the example you might also need something like the following in your gitweb configuration file (/etc/gitweb.conf following example):
@stylesheets = ("/some/absolute/path/gitweb.css");
$my_uri = "/";
$home_link = "/";
$per_request_config = 1;
Nowadays though gitweb should create HTML base tag when needed (to set base URI for relative links), so it should work automatically. ๐ฆ
๐ง Webserver configuration with multiple projects' root ๐ง
If you want to use gitweb with several project roots you can edit your Apache virtual host and gitweb configuration files in the following way.
The virtual host configuration (in Apache configuration file) should look like this:
<VirtualHost *:80>
ServerName git.example.org
DocumentRoot /pub/git
SetEnv GITWEB_CONFIG /etc/gitweb.conf
# turning on mod rewrite
RewriteEngine on
# make the front page an internal rewrite to the gitweb script
RewriteRule ^/$ /cgi-bin/gitweb.cgi [QSA,L,PT]
# look for a public_git directory in unix users' home
# http://git.example.org/~<user>/
RewriteRule ^/\~([^\/]+)(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
[QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
# http://git.example.org/+<user>/
#RewriteRule ^/\+([^\/]+)(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
[QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
# http://git.example.org/user/<user>/
#RewriteRule ^/user/([^\/]+)/(gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
[QSA,E=GITWEB_PROJECTROOT:/home/$1/public_git/,L,PT]
# defined list of project roots
RewriteRule ^/scm(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
[QSA,E=GITWEB_PROJECTROOT:/pub/scm/,L,PT]
RewriteRule ^/var(/|/gitweb.cgi)?$ /cgi-bin/gitweb.cgi \
[QSA,E=GITWEB_PROJECTROOT:/var/git/,L,PT]
# make access for "dumb clients" work
RewriteRule ^/(.*\.git/(?!/?(HEAD|info|objects|refs)).*)?$ \
/cgi-bin/gitweb.cgi%{REQUEST_URI} [L,PT]
</VirtualHost>
Here actual project root is passed to gitweb via GITWEB_PROJECT_ROOT environment variable from a web server, so you need to put the following line in gitweb configuration file (/etc/gitweb.conf in above example):
$projectroot = $ENV{'GITWEB_PROJECTROOT'} || "/pub/git";
Note that this requires to be set for each request, so either $per_request_config must be false, or the above must be put in code referenced by $per_request_config;
These configurations enable two things. First, each unix user (<user>) of the server will be able to browse through gitweb Git repositories found in ~/public_git/ with the following url:
http://git.example.org/~<user>/
If you do not want this feature on your server just remove the second rewrite rule.
If you already use mod_userdir in your virtual host or you donโt want to use the ~ as first character, just comment or remove the second rewrite rule, and uncomment one of the following according to what you want.
Second, repositories found in /pub/scm/ and /var/git/ will be accessible through http://git.example.org/scm/ and http://git.example.org/var/. You can add as many project roots as you want by adding rewrite rules like the third and the fourth. ๐
๐ฆ PATH_INFO usage ๐ฆ
If you enable PATH_INFO usage in gitweb by putting
$feature{'pathinfo'}{'default'} = [1];
in your gitweb configuration file, it is possible to set up your server so that it consumes and produces URLs in the form
http://git.example.com/project.git/shortlog/sometag
i.e. without gitweb.cgi part, by using a configuration such as the following. This configuration assumes that /var/www/gitweb is the DocumentRoot of your webserver, contains the gitweb.cgi script and complementary static files (stylesheet, favicon, JavaScript):
<VirtualHost *:80>
ServerAlias git.example.com
DocumentRoot /var/www/gitweb
<Directory /var/www/gitweb>
Options ExecCGI
AddHandler cgi-script cgi
DirectoryIndex gitweb.cgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
</Directory>
</VirtualHost>
The rewrite rule guarantees that existing static files will be properly served, whereas any other URL will be passed to gitweb as PATH_INFO parameter.
Notice that in this case you donโt need special settings for @stylesheets, $my_uri and $home_link, but you lose "dumb client" access to your project .git dirs (described in "Single URL for gitweb and for fetching" section). A possible workaround for the latter is the following: in your project root dir (e.g. /pub/git) have the projects named without a .git extension (e.g. /pub/git/project instead of /pub/git/project.git) and configure Apache as follows:
<VirtualHost *:80>
ServerAlias git.example.com
DocumentRoot /var/www/gitweb
AliasMatch ^(/.*?)(\.git)(/.*)?$ /pub/git$1$3
<Directory /var/www/gitweb>
Options ExecCGI
AddHandler cgi-script cgi
DirectoryIndex gitweb.cgi
RewriteEngine On
RewriteCond %{REQUEST_FILENAME} !-f
RewriteCond %{REQUEST_FILENAME} !-d
RewriteRule ^.* /gitweb.cgi/$0 [L,PT]
</Directory>
</VirtualHost>
The additional AliasMatch makes it so that
http://git.example.com/project.git
will give raw access to the projectโs Git dir (so that the project can be cloned), while
http://git.example.com/project
will provide human-friendly gitweb access.
This solution is not 100% bulletproof, in the sense that if some project has a named ref (branch, tag) starting with git/, then paths such as
http://git.example.com/project/command/abranch..git/abranch
will fail with a 404 error. ๐ญ
๐ BUGS ๐
Please report any bugs or feature requests to git@vger.kernel.org[1], putting "gitweb" in the subject of email.
๐ SEE ALSO ๐
gitweb.conf(5),git-instaweb(1)gitweb/README,gitweb/INSTALL
๐ GIT ๐
Part of the git(1) suite.
๐ NOTES ๐
git@vger.kernel.orgโmailto:git@vger.kernel.org
โฟ and thatโs the whole page, bestie โ source/version: Git 2.56.0, date: 2026-09-27 โฟ
๐ฆ where this page comes from
- arch rolling: git 2.56.0-1 ยท GPL-2.0-only
- ๐ girlified by deepseek-ai/DeepSeek-V4.1-Flash-1017 on : a language model's rewrite of the original, under its terms