git your blog

So I deleted my whole website by accident.

Yep, it wasn't very fun. Luckily, Linode's Backup Service saved the day. Though they backup the whole machine, it was easy to restore to the linode, change the configuration to use the required partition as a block device, reboot, and then manually mount the block device. At that point, restoration was a cp away.

The reason why this all happened is because I was working on the final piece to my ideal blogging workflow: putting everything under version control.

The problem came when I tried to initialize my current web folder. I mean, it worked, and I could clone the repo on my computer, but I couldn't push. Worse yet, I got something scary back:

remote: error: refusing to update checked out branch: refs/heads/master
remote: error: By default, updating the current branch in a non-bare repository
remote: error: is denied, because it will make the index and work tree inconsistent
remote: error: with what you pushed, and will require 'git reset --hard' to match
remote: error: the work tree to HEAD.
remote: error:
remote: error: You can set 'receive.denyCurrentBranch' configuration variable to
remote: error: 'ignore' or 'warn' in the remote repository to allow pushing into
remote: error: its current branch; however, this is not recommended unless you
remote: error: arranged to update its work tree to match what you pushed in some
remote: error: other way.
remote: error:
remote: error: To squelch this message and still keep the default behaviour, set
remote: error: 'receive.denyCurrentBranch' configuration variable to 'refuse'.

So in the process of struggling with this back and forth between local and remote, I killed my files. Don't you usually panic when you get some long error message that doesn't make a darn bit of sense?

Yeah, well, I guess I kind of got the idea, but it wasn't entirely clear. The key point is that we're trying to push to a non-bare folder— i.e. one that includes all the tracked files— and it's on a main branch.

Why is this bad? Well, what if you had uncommited changes on the remote repo and you pushed changes from the local repo? Data loss. So Git now won't let you do it unless you specifically allow it in your remote config in the receive.denyCurrentBranch variable.

So let's move to the solution: don't do this. You should either push to a different branch and then manually merge on remote, but merges aren't always guaranteed. Why not do something entirely different? Something more proper.

First, start with the remote:

# important: make a new folder!
git init --bare ~/path/to/some/new/folder

Then local:

git clone user@server:path/to/the/aforementioned/folder
cd folder
# make some changes
git add -A
git commit -am "initial commit or whatever you want to say"
git push

If you check out what's in that folder on remote you'll find it has no tracked files. Basically, a bare repo is basically just an index. It's a place to pull and push to. You're not goinng to go there and start changing files and getting git all confused.

Now here's the magic part: in the hooks subfolder of your folder, create a new executable file called post-receive containing the following:

#!/usr/bin/env sh
export GIT_WORK_TREE=/path/to/your/final/live/folder
git checkout -f master
# add any other commands that need to happen to rebuild your site, e.g.:
# blogofile build

Assuming you've already committed some changes, go ahead and run it and check your website.

Pretty cool, huh? Well, it gets even better. Next push you do will automatically update your website for you. So now for me, an update to the website is just a local push away. No need to even login to the server anymore.

There are other solutions to this problem but this one seems to be the most consistent and easy.

Read and Post Comments

blogophilia

Well, it's official. The blog is up. It took so long because I was trying to find the ideal way to blog. I've had several blogs over time and they always fade into obscurity. The major reason is that they weren't easy to write. So I went looking for something that was.

You know what's easy to write? Text files. Of course text isn't really good for proper formatting. You lose nice features like lists and tables. That's what markup languages are good for. HTML/CSS do this but they're just too weird for writing natural language.

Enter Markdown. Though other text-based markup languages exist that are more natural, Markdown seems to be the one most commonly found across the Internet. Github uses it. Coursera forums use it. The list goes on.

So that takes care of the writing. But what about publishing? We have to turn it into the blog, with all the nice features of a common blog, including RSS feeds. We have to have RSS feeds. Comments, too! And that's where Blogofile comes in. Written in Python, it's a static website compiler using Mako templates.

Once you get the templates tweaked just the way you want, it's quite simple. You make a post in Markdown like so:

---
categories: testing
title: Hello World
date: 2014/10/29 16:11:23
---
Hello World

And then run blogofile build.

To make it super easy, put it under version control. Then publishing or even making major changes to the layout is just a push away. Haven't got to that yet, but I'm writing, and that's what counts.

Read and Post Comments