diff --git a/Makefile b/Makefile
index ca6ebe681a99ac4f85d78d4ccd0974d4b4d7d413..21be0527f9b0b1061f7ed7a5eaef8ead2cf55bf0 100644
--- a/Makefile
+++ b/Makefile
@@ -40,11 +40,12 @@ uninstall:
 purge: uninstall
 	rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(PREFIX)/bin/
 	rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(PREFIX)/share/man/man1/
-	rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(DOCDIR_PREFIX)
+	rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(DOCDIR)
 	rmdir -p --ignore-fail-on-non-empty $(DESTDIR)$(ZSHDIR)
 
 test:
-	@if which git > /dev/null ; then :; else echo "'git' not found, exiting..."; exit 1; fi
+	@if which git   > /dev/null; then :    ; else echo "'git' not found, exiting..."; exit 1;  fi
+	@if which prove > /dev/null; then prove; else echo "'prove' not found; not running tests"; fi
 
 moo:
 	@ which cowsay >/dev/null 2>&1 && cowsay "I hope you're happy now..."
diff --git a/t/000-tear-env.t b/t/000-tear-env.t
new file mode 100644
index 0000000000000000000000000000000000000000..6cb384f15bc061378cc8f78e4ec5d6caa74c2aa1
--- /dev/null
+++ b/t/000-tear-env.t
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Shell::Command;
+use Test::Most;
+
+chdir 't' or die $!;
+
+if (!-d 'etc') {
+	plan skip_all => 'No need to tear down previous env.';
+}
+
+ok rm_rf 'etc';
+
+done_testing;
diff --git a/t/001-setup-env.t b/t/001-setup-env.t
new file mode 100644
index 0000000000000000000000000000000000000000..fb59f058e3f04826ced8230617f2e6e818f18ae3
--- /dev/null
+++ b/t/001-setup-env.t
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Test::Most;
+
+system ("mkdir -p t/etc");
+ok !$?;
+
+system ("mkdir -p t/etc/.vcsh_home");
+ok !$?;
+
+chdir 't/etc/' or die $!;
+
+system ("ln -s '../../vcsh'");
+ok !$?;
+
+done_testing;
diff --git a/t/100-init.t b/t/100-init.t
new file mode 100644
index 0000000000000000000000000000000000000000..f2b3a05155b66cfeb7c124d79cf97168b5cb7043
--- /dev/null
+++ b/t/100-init.t
@@ -0,0 +1,54 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Cwd 'abs_path';
+use Test::Most;
+
+chdir 't/etc/' or die $!;
+
+$ENV{'HOME'} = abs_path ('.vcsh_home');
+
+my $output = `./vcsh status`;
+
+ok $output eq "", 'No repos set up yet.';
+
+$output = `./vcsh init test1`;
+
+ok $output eq "Initialized empty shared Git repository in " . $ENV{'HOME'} . "/.config/vcsh/repo.d/test1.git/\n";
+
+$output = `./vcsh status`;
+
+ok $output eq "test1:\n\n", 'Our new repo is there';
+
+chdir $ENV{"HOME"} . '/.config/vcsh/repo.d/test1.git/' or die $!;
+
+ok -f 'HEAD';
+ok -d 'branches';
+ok -f 'config';
+ok -f 'description';
+ok -d 'hooks';
+ok -d 'info';
+ok -d 'objects';
+ok -d 'refs';
+
+ok -f 'hooks/applypatch-msg.sample';
+ok -f 'hooks/commit-msg.sample';
+ok -f 'hooks/post-update.sample';
+ok -f 'hooks/pre-applypatch.sample';
+ok -f 'hooks/pre-commit.sample';
+ok -f 'hooks/pre-push.sample';
+ok -f 'hooks/pre-rebase.sample';
+ok -f 'hooks/prepare-commit-msg.sample';
+ok -f 'hooks/update.sample';
+
+ok -f 'info/exclude';
+
+ok -d 'objects/info';
+ok -d 'objects/pack';
+
+ok -d 'refs/heads';
+ok -d 'refs/tags';
+
+done_testing;
diff --git a/t/300-add.t b/t/300-add.t
new file mode 100644
index 0000000000000000000000000000000000000000..24d9a8ae8742f9ae37204fcadccbe430bbbeb601
--- /dev/null
+++ b/t/300-add.t
@@ -0,0 +1,33 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Cwd 'abs_path';
+
+use Shell::Command;
+use Test::Most;
+
+chdir 't/etc/' or die $!;
+
+$ENV{'HOME'} = abs_path ('.vcsh_home');
+
+chdir '.vcsh_home' or die $!;
+
+eval {
+	touch 'a';
+};
+
+die $@ if $@;
+
+system (".././vcsh test1 add 'a'");
+
+my $output = `.././vcsh status`;
+
+ok $output eq "test1:
+A  a
+
+", 'Adding a file works';
+
+done_testing;
+
diff --git a/t/950-delete.t b/t/950-delete.t
new file mode 100644
index 0000000000000000000000000000000000000000..cd078714ad0c3c7396bc88c89966dd32f7ee0ed7
--- /dev/null
+++ b/t/950-delete.t
@@ -0,0 +1,19 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Cwd 'abs_path';
+use Test::Most;
+
+chdir 't/etc/' or die $!;
+
+$ENV{'HOME'} = abs_path ('.vcsh_home');
+
+system ("echo 'Yes, do as I say' | ./vcsh delete test1");
+
+my $output = `./vcsh status`;
+
+ok $output eq "", 'No repos set up anymore.';
+
+done_testing;
diff --git a/t/999-tear-env.t b/t/999-tear-env.t
new file mode 100644
index 0000000000000000000000000000000000000000..afe261a8a5ba3f10ec45a2f6b15d711743132ec9
--- /dev/null
+++ b/t/999-tear-env.t
@@ -0,0 +1,17 @@
+#!/usr/bin/perl
+
+use strict;
+use warnings;
+
+use Shell::Command;
+use Test::Most;
+
+chdir 't' or die $!;
+
+if (!-d 'etc') {
+	plan skip_all => 'No need to tear previous env.';
+}
+
+ok rm_rf 'etc';
+
+done_testing;
diff --git a/tools/hooks/pre-commit b/tools/hooks/pre-commit
new file mode 100755
index 0000000000000000000000000000000000000000..ddb0550d640a1b4bd901877b090df5278df7e729
--- /dev/null
+++ b/tools/hooks/pre-commit
@@ -0,0 +1,7 @@
+#!/bin/sh
+
+# Unfortunately, Git decided to set those two during pre-commit
+unset GIT_DIR
+unset GIT_INDEX_FILE
+
+prove