Git is probably one of the most used collaboration tools around here.
But it's also, in its core, a very useful code versioning tool, nothing more.
We're used to Github, Gitlab, and such, but sometimes we want to have a private git setup without all the collaboration environment built around those tools.
Setting up a gitlab, or even a gitea, server is cumbersome, especially when dealing with proxies, user authentication, backups, etc.
But if you really need to have a few repositories on your local NAS, or to host a handful on a small VPS for your local project, you may instead want to go for a "bare" server git setup.
"Bare"
Basically put, git provides all the capabilities required to work in a
client-server fashion, without anything except
sshd
and git
.
Yup, that's it, those two tools are the only two tools you need to host some git repositories.
In this post, I'm gonna show how to create repositories, interact with them over SSH, then set up a basic proxy server to interact with them over HTTP, too.
Beforehand...
Git's way to resolve paths over SSH is dumb.
That's good! That means it will be dumb to set up some git server!
So, how does that actually work?
When you target a ssh path
(e.g., scp-style, user@server.tld:group/project.git
),
it will ssh to the server using the user user
(and your ssh key, if you have one, which you probably do),
then try to find the repository folder group/project.git
from
user
's home folder.
What that entails is that you only have to create a "bare" git repository inside your home folder, somewhere, and using the full path, you'll be able to access it.
In a more general way, since ssh is a direct access to a remote machine, you can technically interact with any folder on your server, if you have read / write rights to it, by starting from
/
(the root), or by providing a path relative to the user's home folder (e.g.../other/project.git
).For organisational purposes, I'm gonna stay with the home folder, here.
Create a repository
To create a "server-side" repository, you'll create what's known inside of Git as a "bare" repository, which is a structure which only contains what git needs to version code (no tracked branch, etc.).
Simply put, you'll create what can usually be found inside your
project's .git
.
To do that, the command is git init --bare
, to be run inside an
empty folder.
To create a new folder and init it along the way, append the folder path
at the end of the init command, e.g. git init --bare ~/project.git
.
That's it.
Here's a few examples, all run from the client to the server.
# create a git repository at $HOME/project.git
ssh server.tld git init --bare project.git
# create a project group at $HOME/group, then init a repository inside
ssh server.tld `mkdir group && git init --bare group/project.git`
Interact with them over SSH
You have two operations which you can use to interact with a remote git repository:
- fetch: retrieve changes to your local
.git
- push: push changes to the remote server
Both can be done using the concept of remotes
in git
(which I assume you're already familiar with. If it isn't the case, I invite you
to read the manual on remotes
).
As the documentation shows, an over-SSH repository can have the following formats.
# URL-style
ssh://[user@]host.xz[:port]/path/to/repo.git/
# SCP-style
[user@]host.xz:path/to/repo.git/
In our examples, our remotes would be:
- For
$HOME/project.git
,server.tld:project.git
(orserver.tld:project
) - For
$HOME/group/project.git
,server.tld:group/project.git
(orserver.tld:group/project
)
To clone one of them, the usual git command is as simple as
git clone server.tld:project.git
!
What about HTTP?
Yeah, what about HTTP?
What if I don't have SSH on my machine, or don't want to bother with it?
Well, you won't be able to create or manage your repositories over HTTP, but you'll be able to push / fetch from them, which is already a good start (and probably what you want if you want to, e.g., share a repository with someone).
Git provides a nifty CGI binary called git-http-backend
.
You can invoke it using git http-backend
if you wish to automate some tasks,
but the binary is usually installed at /usr/lib/git-core/git-http-backend
.
An example caddy configuration using its cgi extension would be as simple as the following.
git.server.tld:80 {
cgi / /usr/lib/git-core/git-http-backend {
env GIT_PROJECT_ROOT=/home/myuser/ GIT_HTTP_EXPORT_ALL=true
}
}
This will allow the fetch
operation for every client that can reach
git.server.tld
, but will only allow push
operations to the "authenticated"
clients.
I haven't yet been able to find a generic definition for when
git-http-backend
determines that a client is authenticated.I'm still reading on this topic and trying out things, mostly with Caddy.
Project templates
But gitea provided me with project templates.
I use them, they're really useful to quickly start a project!
Fear not, my child! Git also has you covered, as templates are a natively-supported git concept!
Again to the rescue,
the documentation
explains that there is an optional argument on git init
, and if it
points to a valid template directory, every file inside this directory
that does not start with a .
(dot, a.k.a. linux hidden file) will be
copied in the new git repository.
You also can set default template directories for all your projects!
When you initialize a repository using git init
, if you don't specify
a template directory, git will check, in the following order and until
it finds a directory at the requested path,
$GIT_TEMPLATE_DIR
: The environment variable, if setinit.templateDir
: The git configuration variable, if set/usr/share/git-core/templates
: The default template directory, if found
Now, this is still a very dumb template system, especially since it doesn't copy
dotfiles, so you cannot have your .gitignore
, .editorconfig
, and such,
automagically copied.
Still, if you don't have complex needs, it's a really decent feature that doesn't require you to install a template management tool.
You could also make a simple bash script to have some dotfiles, e.g.
something that would rename every file starting with dot
into a
starting .
.
If you still want some more complex templates, you may want to check out the neat tool called kickstart.
Backups?
Since git
is completely filesystem-level, it can easily be backuped,
especially using incremental
backup tools, such as restic
!
This section will showcase an example on how to backup some git repositories using restic.
I assume that you already know restic, as I'll only showcase backing-up, not repository creation.
Let's say I'm on server.tld
, and in its local network, there is a SFTP
server at sftp.tld
on which I have a backup repository initialized.
I have project.git
and group/project.git
as hosted git repositories I want
to backup.
restic -r sftp.tld:backups/ backup **/*.git
This will backup every git folder (so both project.git
and
group/project.git
) inside the backups/
repository found in sftp.tld
.
Additional notes
I found this guide to be pretty neat during my discovery on the topic, and I invite you to check it out if you have some questions.
I found this article showcasing a barebones CI system based on a barebones git repository, which is not only definitely worth checking out, but "good enough" and a decent base to start building on.