--- author: ~kst published: true title: hosting public git repos description: hosting public git repos on tilde.team category: - publishing - technical - guides --- Besides the [Gitea instance][1] of tildeverse, you could easily set up 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/` is mapped to `https://tilde.team/~name/` 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 ``` 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 asset 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 ``` 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 < ``` See the [blog post][14] of Drew DeVault for using git with mutt, and check out [aerc][15] if you want a 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/