---
author: ~kst
published: true
title: hosting public git repos
description: hosting public git repos on tilde.team
category:
    - main
---

Besides the [Gitea instance][1] of tildeverse, you could easily setup a
read-only clone URL fetchable using git clone similar to this one:

```
$ git clone https://tilde.team/~kst/grm.tilde.git
```

tl;dr
-----

If you are not interested in the details, you could use a minimal front end
called [git repo manager][2]. It should take care of all the details for you.

creating a repo
---------------

On tilde.team, the structure of `~name/public_html/<path>` is mapped to
`https://tilde.team/~name/<path>` so anything inside the `~name/public_html`
directory is publicly accessible. If you want to create a publicly accessible
git repository, all you need to do is to create a [bare repository][3] inside
`~name/public_html`:

```
$ cd ~/public_html
$ git init --bare my_repo.git
Initialized empty Git repository in /home/name/public_html/my_repo.git/
```

The `.git` suffix is a convention for bare repositories. If you have used GitHub,
GitLab, or Gitea before, you should have noticed that the clone URLs all have
the `.git` suffix.

After you have created the bare repository for your project, the URL

```
https://tilde.team/~name/my_repo.git
```

is not ready for clone yet. Because we are serving the repository using GET
requests, or what git internally called the ["dumb" HTTP protocol][4], git needs
some extra info files for cloning the repository. They can be generated by

```
$ cd ~/public_html/my_repo.git
$ git update-server-info
```

Now you should be able to clone the repository using

```
$ git clone https://tilde.team/~name/my_repo.git
Cloning into 'my_repo'...
warning: You appear to have cloned an empty repository.
```

The

```
$ git update-server-info
```

command needs to be run after every update to the repository. This could be
automated using the post-update [git hook][5]. Since the sample post-update hook
in

```
~/public_html/my_repo.git/hooks
```

already contains this command, we simply rename the sample hook

```
$ cd ~/public_html/my_repo.git
$ mv hooks/post-update.sample hooks/post-update
```

so that git will run this script after every update.

push via ssh
------------

Note that the HTTP clone URL is *read-only*, so you can't push anything using
this URL. Normally you would need to set up the ["smart" protocol][4] for
authentication, but since we are using SSH already, we could use a remote path
of the form `name@host:path`, similar to the arguments of scp, as the git
remote url, so you could use

```
$ git clone name@tilde.team:~/public_html/my_repo.git
```

to clone the repository on your local machine, or

```
$ git clone ~/public_html/my_repo.git
```

if you want to work on the server directly. If you have already made some
changes to the local repo, use

```
$ git remote set-url origin <url>
```

to update the remote URL. Now you should be able to push to your remote repo
using

```
$ git push
```

if you have a correct SSH keypair setup.

web front end
------------

Now that we have already figured out the push and clone access of our
repository. You could call it an end here, but one of the most important
features of git hosting services is a web interface so that people could browse
and discuss the source code without cloning it.

For this, we could use [stagit][6], which is a tool for generating static HTML
pages from a git repository. The generated web pages are even browsable using
terminal browsers such as elinks, w3m, and lynx. For example, try

```
$ lynx https://tilde.team/~kst/git/grm.tilde/file/TUTORIAL.html
```

Since tilde.team already have libgit2 installed, simply clone the repo and
build it:

```
$ git clone git://git.codemadness.org/stagit
$ cd stagit
$ make
$ cp stagit stagit-index ~/bin/
```

Here, we will assume that the index page of stagit, which lists all the repos
you have, is

```
https://tilde.team/~name/git/
```

and the index page of each repository is

```
https://tilde.team/~name/git/my_repo
```

To build the HTML pages for `my_repo`, we first make the corresponding directory

```
$ mkdir -p ~/public_html/git/my_repo
$ cd ~/public_html/git/my_repo
```

and add some metadata to your bare git repo

```
$ echo 'a cool project' > ~/public_html/my_repo.git/description
$ echo 'https://tilde.team/~name/my_repo.git' > ~/public_html/my_repo.git/url
$ echo 'name' > ~/public_html/my_repo.git/owner
```

then run

```
$ stagit ~/public_html/my_repo.git
```

to generate HTML files in the current directory. You could link `index.html` to
`log.html`

```
$ ln -sf log.html index.html
```

so that the URL

```
https://tilde.team/~name/git/my_repo
```

is pointed to the commit log page.

To generate the repository index, go back to

```
$ cd ~/public_html/git/
```

and run

```
$ stagit-index ~/public_html/my_repo.git > index.html
```

Note that the output will be empty if `my_repo` has no commits. In general, use

```
$ stagit-index repo_dir1 repo_dir2 ... > index.html
```

to generate index for multiple repositories. You should also copy over or
symlink some of the assets files in stagit's repository, such as `style.css`,
`logo.png`, etc. to

```
~/public_html/git/
```

and

```
~/public_html/git/my_repo/
```

you could also modify the source code of stagit to use a common location for
the assets.

Because the web pages generated by stagit is static, you need to run `stagit`
and `stagit-index` after each push operation to your repository in order to
update the HTML files. This process can be easily automated using a
`post-receive` hook.  An example of the `post-receive` hook can be found
[here][8]. To install it:

```
$ cd ~/public_html/my_repo.git/hooks
$ curl -o stagit-post-receive https://tilde.team/~kst/bin/stagit-post-receive
$ chmod +x stagit-post-receive
```

Now you should see something like this when you do a git push

```
$ git push
...
remote: [my_repo] stagit HTML pages... done!
...
```

a minimal front end for stagit
------------------------------

Since the process of creating repositories and recompiling stagit pages can be
very tedious, there is a simple front end called git repo manager (`grm`) to
deal with the chore, see the [readme][9] if you want to use `grm` to automate this
process.

If you want to host git repositories on your own server, you could use the [git
daemon][10] to better manage the visibility of your repositories. The remote
address exposed by the git daemon will have `git://` prefix. Check out the master
branch of [grm][11] if you want to use git daemon instead.

accepting patches
-----------------

Hosting git repositories this way means there will be no fancy features such as
issues and pull requests, but git have built-in support for [email workflows][12].

Contributors could format their commits to patches using

```
$ git format-patch
```

and use the

```
$ git send-email <patches>
```

command (see [here][13]) to send the patches to you, and you could apply the patches by
piping the email message or attached patches to the `git am` command

```
$ git am < <patch>
```

See the [blog post][14] of Drew DeVault for using git with mutt, and check out
[aerc][15] if you want an modern alternative for mutt built from such workflow.

[1]: https://tildegit.org/
[2]: https://tilde.team/~kst/git/grm.tilde/file/README.html
[3]: https://git-scm.com/book/en/v2/Git-on-the-Server-Getting-Git-on-a-Server
[4]: https://git-scm.com/book/en/v2/Git-Internals-Transfer-Protocols
[5]: https://git-scm.com/docs/githooks
[6]: https://git.codemadness.org/stagit/
[7]: https://git.codemadness.org/stagit/file/README.html
[8]: https://tilde.team/~kst/git/stagit-postrecv/file/stagit-post-receive.html
[9]: https://tilde.team/~kst/git/grm.tilde/file/README.html
[10]: https://git-scm.com/book/en/v2/Git-on-the-Server-Git-Daemon
[11]: https://sink.krj.st/grm/file/README.html
[12]: https://git-scm.com/docs/gitworkflows#_patch_workflow
[13]: https://git-send-email.io/
[14]: https://drewdevault.com/2019/05/13/Git-email-webcast.html
[15]: https://aerc-mail.org/
