diff --git a/.clang-format b/.clang-format
new file mode 100644
index 0000000000000000000000000000000000000000..6facf9c54a719c1b9818dc666307991cad10d77f
--- /dev/null
+++ b/.clang-format
@@ -0,0 +1,19 @@
+---
+# We'll use defaults from the Google style, but with 4 columns indentation.
+BasedOnStyle: Google
+# Never allow single-line functions
+AllowShortFunctionsOnASingleLine: None
+# Put "else" on a new line
+BreakBeforeBraces: Custom
+BraceWrapping:
+    BeforeElse: true
+# Allow lines up to 90 characters
+ColumnLimit: 90
+# Indent each block by 4 spaces
+IndentWidth: 4
+TabWidth: 4
+# Require 1 space before a comment on the same line
+SpacesBeforeTrailingComments: 1
+# Put a space after a cast, e.g. `(void) arg;`
+SpaceAfterCStyleCast: true
+---
diff --git a/.githooks/pre-commit b/.githooks/pre-commit
new file mode 100755
index 0000000000000000000000000000000000000000..dd547755658807c943cfe47a67b73e0cfc127ea3
--- /dev/null
+++ b/.githooks/pre-commit
@@ -0,0 +1,12 @@
+#!/bin/bash
+
+if loc="$(type -p "clang-format")" && [[ -x $loc ]]; then
+    for name in $(git diff --cached --name-only --diff-filter=ACM); do
+        if echo $name | grep -Eq "\.[ch]$"; then
+            echo "Formatting ${name}..."
+            clang-format -i $name
+        fi
+    done
+else
+    echo "You do not have clang-format installed; so, we were unable to unify the formatting in your files."
+fi
diff --git a/include/ast.h b/include/ast.h
index 85f50b6532029450272e3f1083c3927e822bd78e..8e0fe3552cbdad720c2f6fa06858edea874e33b3 100644
--- a/include/ast.h
+++ b/include/ast.h
@@ -11,16 +11,7 @@
 #include <stdint.h>
 
 /** The types of AST nodes */
-typedef enum {
-    NUM,
-    BINARY_OP,
-    VAR,
-    SEQUENCE,
-    PRINT,
-    LET,
-    IF,
-    WHILE
-} node_type_t;
+typedef enum { NUM, BINARY_OP, VAR, SEQUENCE, PRINT, LET, IF, WHILE } node_type_t;
 
 /** The type of a TeenyBASIC variable name */
 typedef char var_name_t;
diff --git a/include/parser.h b/include/parser.h
index ace4d02f13606c112f19ef9b33094f02c18cb413..2653fdfbd2fca1669632298d387a9c08ad870b96 100644
--- a/include/parser.h
+++ b/include/parser.h
@@ -1,6 +1,8 @@
 #ifndef PARSER_H
 #define PARSER_H
 
+#include <stdio.h>
+
 #include "ast.h"
 
 /** Parses the next statement from the provided TeenyBASIC file into an AST */
diff --git a/runtime/print_int.c b/runtime/print_int.c
index a4f93067d5b2d46b804cad5260abddaaab323673..970191fe9168b95cad25e83de3de03a29e41444b 100644
--- a/runtime/print_int.c
+++ b/runtime/print_int.c
@@ -1,13 +1,13 @@
 #include <inttypes.h>
 #include <stdio.h>
+
 #include "ast.h"
 
 // A function that can be called from assembly to print an integer
 void print_int(value_t value) {
     printf("%" PRId64 "\n", value);
     // Clobber all caller-save registers
-    asm(
-        "movq $0x6A2CFE91073BD845, %%rax\n"
+    asm("movq $0x6A2CFE91073BD845, %%rax\n"
         "movq $0x03BAD7C14F2E6589, %%rdi\n"
         "movq $0x5D41EA960C72F8B3, %%rsi\n"
         "movq $0xEC364B2D5A7F9810, %%rdx\n"
@@ -16,6 +16,7 @@ void print_int(value_t value) {
         "movq $0x92E1587A4BDCF630, %%r9\n"
         "movq $0x47DC36501F89AEB2, %%r10\n"
         "movq $0xAF4B29785C61ED30, %%r11\n"
-        : : : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11"
-    );
+        :
+        :
+        : "rax", "rdi", "rsi", "rdx", "rcx", "r8", "r9", "r10", "r11");
 }
diff --git a/runtime/timing.c b/runtime/timing.c
index bd1a4f5042557cc419885d947871b671c0ca86a3..d076e4f3a4e9e42f9ecf19f9c5ee4e7d22dc70c2 100644
--- a/runtime/timing.c
+++ b/runtime/timing.c
@@ -1,8 +1,8 @@
 #include <assert.h>
 #include <math.h>
 #include <stdint.h>
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 #include <string.h>
 #include <time.h>
 
@@ -51,9 +51,7 @@ int main(int argc, char *argv[]) {
     printf(
         "test_name,mean_log_duration,variance_log_duration\n"
         "%s,%f,%e\n",
-        test_name, mean_log_duration, variance_log_duration
-    );
-    fprintf(stderr, "%s mean duration: %e seconds (+/- %e x)\n",
-        test_name, exp(mean_log_duration), expm1(sqrt(variance_log_duration))
-    );
+        test_name, mean_log_duration, variance_log_duration);
+    fprintf(stderr, "%s mean duration: %e seconds (+/- %e x)\n", test_name,
+            exp(mean_log_duration), expm1(sqrt(variance_log_duration)));
 }
diff --git a/src/ast.c b/src/ast.c
index 7b39ec142255f95ec2860ffcb579178538b226f1..6ae1bb0cfbbf921d27bb2aed8b407619a27f151e 100644
--- a/src/ast.c
+++ b/src/ast.c
@@ -1,11 +1,11 @@
+#include "ast.h"
+
 #include <assert.h>
 #include <inttypes.h>
 #include <stdbool.h>
 #include <stdio.h>
 #include <stdlib.h>
 
-#include "ast.h"
-
 node_t *init_num_node(value_t value) {
     num_node_t *node = malloc(sizeof(num_node_t));
     assert(node != NULL);
diff --git a/src/compile.c b/src/compile.c
index 1554ad75e00a7ff46582fbd23d42d17966d13bbe..ae52d90179cc72774199b6b92c58acc4b7acc412 100644
--- a/src/compile.c
+++ b/src/compile.c
@@ -1,8 +1,8 @@
-#include <stdlib.h>
-#include <stdio.h>
-
 #include "compile.h"
 
+#include <stdio.h>
+#include <stdlib.h>
+
 bool compile_ast(node_t *node) {
     /* You should remove this cast to void in your solution.
      * It is just here so the code compiles without warnings. */
diff --git a/src/compiler.c b/src/compiler.c
index b0a1170aaf2bfc5633de7676d4baa3a7d1d1b8ef..25b6ceba87b72f625770c3f1f0dcc63f1f4ed427 100644
--- a/src/compiler.c
+++ b/src/compiler.c
@@ -1,8 +1,8 @@
-#include <stdlib.h>
 #include <stdio.h>
+#include <stdlib.h>
 
-#include "parser.h"
 #include "compile.h"
+#include "parser.h"
 
 void usage(char *program) {
     fprintf(stderr, "USAGE: %s <program file>\n", program);
@@ -20,8 +20,7 @@ void header(void) {
         ".text\n"
         ".globl basic_main\n"
         "basic_main:\n"
-        "    # The main() function\n"
-    );
+        "    # The main() function\n");
 }
 
 /**
@@ -30,9 +29,7 @@ void header(void) {
  * goes between the header and the footer.
  */
 void footer(void) {
-    printf(
-        "    ret\n"
-    );
+    printf("    ret\n");
 }
 
 int main(int argc, char *argv[]) {
diff --git a/src/parser.c b/src/parser.c
index aa01624980517b98e71fd561533731141792e7af..fcc5eb1470417b824a4148fca273aa99e89d6347 100644
--- a/src/parser.c
+++ b/src/parser.c
@@ -1,3 +1,5 @@
+#include "parser.h"
+
 #include <assert.h>
 #include <ctype.h>
 #include <errno.h>
@@ -6,8 +8,6 @@
 #include <stdlib.h>
 #include <string.h>
 
-#include "parser.h"
-
 // maxint = -9223372036854775808
 const size_t MAX_KEYWORD_LENGTH = 100;
 const value_t DEFAULT_STEP = 1;
@@ -35,8 +35,8 @@ bool is_comparison_op(char c) {
     return c == '<' || c == '=' || c == '>';
 }
 bool is_operator(char c) {
-    return is_open_paren(c) || is_close_paren(c) ||
-        is_factor_op(c) || is_term_op(c) || is_comparison_op(c);
+    return is_open_paren(c) || is_close_paren(c) || is_factor_op(c) || is_term_op(c) ||
+           is_comparison_op(c);
 }
 bool is_comment_start(char c) {
     return c == '#';
@@ -340,7 +340,7 @@ node_t *sequence(parser_state_t *state) {
 
         if (statement_count == statement_capacity) {
             statement_capacity = statement_capacity > 0 ? statement_capacity * 2 : 1;
-            statements = realloc(statements, sizeof(node_t*[statement_capacity]));
+            statements = realloc(statements, sizeof(node_t *[statement_capacity]));
             assert(statements != NULL);
         }
         statements[statement_count++] = next;
@@ -354,7 +354,7 @@ node_t *sequence(parser_state_t *state) {
     }
 
     if (statement_count > 0) {
-        statements = realloc(statements, sizeof(node_t*[statement_count]));
+        statements = realloc(statements, sizeof(node_t *[statement_count]));
         assert(statements != NULL);
     }
     return init_sequence_node(statement_count, statements);