Think you need GitHub or GitLab to host your Git repos? Think again. If you have a server with SSH access, you already have a fully-functional Git server just waiting to be unleashed. It’s like discovering your car has a secret turbo button you never knew about.
Let’s stop paying for things we can do ourselves and turn any server into a personal Git powerhouse.
The Obvious (But Overlooked) Connection
Getting started is dead simple. You don’t need to install anything special. Just point your local Git client at the server:
# It's this easy.
git clone ssh://username@hostname/path/to/repo
Boom. You’re now working with a repository on your server. You can make changes locally and push them back. But there’s one tiny, annoying speed bump.
Unlocking Pushing to the Checked-Out Branch
By default, Git is a bit of a neat freak. It throws a fit if you try to push to the branch that’s currently “checked out” on the server (i.e., the one you’re actively working with). It’s scared you’ll overwrite something important.
We can tell Git to chill out with a single, magic command. Run this on the remote server:
# Run this on the server, not your local machine.
git config receive.denyCurrentBranch updateInstead
This tells Git, “Hey, when a push comes in for the current branch, don’t panic. Just update the files in place. I know what I’m doing.”
This is already a game-changer for syncing code between your laptop and your desktop, or for editing server-side files without the soul-crushing lag of SSH or the hassle of manual FTP syncing.
Sharing Your Code with the World (HTTP Style)
Okay, so you’re syncing code. What if you want to make that repo public so others can clone it? You can just point your web server (like Nginx or Apache) at the .git directory.
# On your web server, you'd clone like this:
git clone https://hostname/path/to/repo/.git
But there’s a catch. For cloning over plain HTTP to work properly, Git needs some extra metadata files that it doesn’t create by default. You have to manually ask for them:
# This tells Git to create the info files needed for HTTP cloning.
# You have to run this on the server after every push. Annoying, right?
git update-server-info
Running that after every single push? That’s a job for a robot, not a human.
The Real Magic: Git Hooks
Git hooks are exactly what they sound like: little scripts that “hook” into Git’s lifecycle. They run automatically when certain things happen, like a commit or a push. We can use the post-update hook to run our update-server-info command for us.
Setting it up is a breeze:
# On the server, turn the sample hook into a real one.
cp .git/hooks/post-update.sample .git/hooks/post-update
# And make sure it's executable.
chmod a+x .git/hooks/post-update
That’s it! Now, every time you push to the server, that hook will automatically run git update-server-info in the background. Your HTTP repo will always be up-to-date, zero manual work required.
Level Up: Auto-Deploy Your Static Site
But hooks can do so much more than that. They’re just shell scripts, which means they can do anything you can do from the command line. This is how you set up a slick, automatic deployment pipeline for a Jekyll blog, a Hugo site, or any other static site generator.
Just replace the hook script with your own commands:
# Overwrite the default post-update hook with our custom deployment script.
cat > .git/hooks/post-update <<EOF
#!/bin/sh
set -euo pipefail
# Navigate to the directory where your site's source code lives.
cd /var/www/my-blog
# Run your static site generator.
/path/to/hugo
# Or maybe you use Gatsby or Jekyll...
# npm run build
# jekyll build
EOF
# Don't forget to make it executable!
chmod a+x .git/hooks/post-update
Now, my workflow for this blog is: write a post locally, git commit, and git push. That’s it. The server receives the push, the hook fires, the site is rebuilt, and the world sees the new content. No laggy typing in a web editor, no manual file transfers.
Why This Setup is So Damn Good
Beyond the slick automation, this setup gives you some incredible peace of mind:
- It’s a Free, Automatic Backup: My laptop has the code, and the server has the code. If one goes up in flames, I can restore it from the other in minutes.
- Version Control is Your Safety Net: Accidentally delete a crucial file? No problem.
git checkoutcan bring it back. Broke something and don’t know when?git logandgit bisectwill help you hunt down the culprit.
So go on, give your server the superpowers it deserves. You’ll be amazed at what it can already do.