Merge branch 'development' into error-handling

The code in this branch has been modified so it works with the global
state introduced in development.
diff --git a/README.md b/README.md
index 82517bc..6ba9e64 100644
--- a/README.md
+++ b/README.md
@@ -36,7 +36,7 @@
 ==============================
 
 libgit2 builds cleanly on most platforms without any external dependencies.
-Under Unix-like systems, like Linux, * BSD and Mac OS X, libgit2 expects `pthreads` to be available;
+Under Unix-like systems, like Linux, \*BSD and Mac OS X, libgit2 expects `pthreads` to be available;
 they should be installed by default on all systems. Under Windows, libgit2 uses the native Windows API
 for threading.
 
diff --git a/examples/general.c b/examples/general.c
index 9bfbc40..8b58fa6 100644
--- a/examples/general.c
+++ b/examples/general.c
@@ -430,14 +430,14 @@
   printf("\n*Config Listing*\n");
 
   const char *email;
-  int j;
+  int32_t j;
 
   git_config *cfg;
 
   // Open a config object so we can read global values from it.
   git_config_open_ondisk(&cfg, "~/.gitconfig");
 
-  git_config_get_int(cfg, "help.autocorrect", &j);
+  git_config_get_int32(cfg, "help.autocorrect", &j);
   printf("Autocorrect: %d\n", j);
 
   git_config_get_string(cfg, "user.email", &email);
diff --git a/examples/network/.gitignore b/examples/network/.gitignore
new file mode 100644
index 0000000..1b48e66
--- /dev/null
+++ b/examples/network/.gitignore
@@ -0,0 +1 @@
+/git2
diff --git a/examples/network/git2.c b/examples/network/git2.c
index 0468c8a..def56e8 100644
--- a/examples/network/git2.c
+++ b/examples/network/git2.c
@@ -44,7 +44,8 @@
 	int i, error;
 
 	if (argc < 2) {
-		fprintf(stderr, "usage: %s <cmd> [repo]", argv[0]);
+		fprintf(stderr, "usage: %s <cmd> [repo]\n", argv[0]);
+		exit(EXIT_FAILURE);
 	}
 
 	for (i = 0; commands[i].name != NULL; ++i) {
@@ -53,5 +54,5 @@
 	}
 
 	fprintf(stderr, "Command not found: %s\n", argv[1]);
-  
+	return 1;
 }
diff --git a/include/git2.h b/include/git2.h
index ad92809..14c090e 100644
--- a/include/git2.h
+++ b/include/git2.h
@@ -11,6 +11,7 @@
 #include "git2/version.h"
 
 #include "git2/common.h"
+#include "git2/threads.h"
 #include "git2/errors.h"
 #include "git2/zlib.h"
 
diff --git a/include/git2/common.h b/include/git2/common.h
index ef279ea..eee918a 100644
--- a/include/git2/common.h
+++ b/include/git2/common.h
@@ -7,7 +7,6 @@
 #ifndef INCLUDE_git_common_h__
 #define INCLUDE_git_common_h__
 
-#include "thread-utils.h"
 #include <time.h>
 #include <stdlib.h>
 
@@ -38,18 +37,6 @@
 # define GIT_EXTERN(type) extern type
 #endif
 
-/** Declare a public TLS symbol exported for application use. */
-#if __GNUC__ >= 4
-# define GIT_EXTERN_TLS(type) extern \
-					__attribute__((visibility("default"))) \
-					GIT_TLS \
-					type
-#elif defined(_MSC_VER)
-# define GIT_EXTERN_TLS(type) __declspec(dllexport) GIT_TLS type
-#else
-# define GIT_EXTERN_TLS(type) extern GIT_TLS type
-#endif
-
 /** Declare a function as always inlined. */
 #if defined(_MSC_VER)
 # define GIT_INLINE(type) static __inline type
diff --git a/include/git2/indexer.h b/include/git2/indexer.h
index bd9b9b6..1e5eb38 100644
--- a/include/git2/indexer.h
+++ b/include/git2/indexer.h
@@ -7,8 +7,8 @@
 #ifndef _INCLUDE_git_indexer_h__
 #define _INCLUDE_git_indexer_h__
 
-#include "git2/common.h"
-#include "git2/oid.h"
+#include "common.h"
+#include "oid.h"
 
 GIT_BEGIN_DECL
 
diff --git a/include/git2/oid.h b/include/git2/oid.h
index b9824b8..9cebda9 100644
--- a/include/git2/oid.h
+++ b/include/git2/oid.h
@@ -100,7 +100,7 @@
  *
  * @param oid the oid structure to format
  * @return the c-string; NULL if memory is exhausted. Caller must
- *			deallocate the string with free().
+ *			deallocate the string with git__free().
  */
 GIT_EXTERN(char *) git_oid_allocfmt(const git_oid *oid);
 
diff --git a/include/git2/refs.h b/include/git2/refs.h
index c319bfb..82c5d88 100644
--- a/include/git2/refs.h
+++ b/include/git2/refs.h
@@ -23,8 +23,7 @@
 /**
  * Lookup a reference by its name in a repository.
  *
- * The generated reference is owned by the repository and
- * should not be freed by the user.
+ * The generated reference must be freed by the user.
  *
  * @param reference_out pointer to the looked-up reference
  * @param repo the repository to look up the reference
@@ -39,8 +38,7 @@
  * The reference will be created in the repository and written
  * to the disk.
  *
- * This reference is owned by the repository and shall not
- * be free'd by the user.
+ * The generated reference must be freed by the user.
  *
  * If `force` is true and there already exists a reference
  * with the same name, it will be overwritten.
@@ -60,8 +58,7 @@
  * The reference will be created in the repository and written
  * to the disk.
  *
- * This reference is owned by the repository and shall not
- * be free'd by the user.
+ * The generated reference must be freed by the user.
  *
  * If `force` is true and there already exists a reference
  * with the same name, it will be overwritten.
@@ -119,8 +116,13 @@
  * Thie method iteratively peels a symbolic reference
  * until it resolves to a direct reference to an OID.
  *
+ * The peeled reference is returned in the `resolved_ref`
+ * argument, and must be freed manually once it's no longer
+ * needed.
+ *
  * If a direct reference is passed as an argument,
- * that reference is returned immediately
+ * a copy of that reference is returned. This copy must
+ * be manually freed too.
  *
  * @param resolved_ref Pointer to the peeled reference
  * @param ref The reference
@@ -173,9 +175,19 @@
  * The new name will be checked for validity and may be
  * modified into a normalized form.
  *
- * The refernece will be immediately renamed in-memory
+ * The given git_reference will be updated in place.
+ *
+ * The reference will be immediately renamed in-memory
  * and on disk.
  *
+ * If the `force` flag is not enabled, and there's already
+ * a reference with the given name, the renaming will fail.
+ *
+ * @param ref The reference to rename
+ * @param new_name The new name for the reference
+ * @param force Overwrite an existing reference
+ * @return GIT_SUCCESS or an error code
+ *
  */
 GIT_EXTERN(int) git_reference_rename(git_reference *ref, const char *new_name, int force);
 
@@ -187,6 +199,8 @@
  * The reference will be immediately removed on disk and from
  * memory. The given reference pointer will no longer be valid.
  *
+ * @param ref The reference to remove
+ * @return GIT_SUCCESS or an error code
  */
 GIT_EXTERN(int) git_reference_delete(git_reference *ref);
 
@@ -200,9 +214,6 @@
  * Once the `packed-refs` file has been written properly,
  * the loose references will be removed from disk.
  *
- * WARNING: calling this method may invalidate any existing
- * references previously loaded on the cache.
- *
  * @param repo Repository where the loose refs will be packed
  * @return GIT_SUCCESS or an error code
  */
@@ -253,6 +264,41 @@
  */
 GIT_EXTERN(int) git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload);
 
+/**
+ * Check if a reference has been loaded from a packfile
+ *
+ * @param ref A git reference
+ * @return 0 in case it's not packed; 1 otherwise
+ */
+GIT_EXTERN(int) git_reference_is_packed(git_reference *ref);
+
+/**
+ * Reload a reference from disk
+ *
+ * Reference pointers may become outdated if the Git
+ * repository is accessed simultaneously by other clients
+ * whilt the library is open.
+ *
+ * This method forces a reload of the reference from disk,
+ * to ensure that the provided information is still
+ * reliable.
+ *
+ * If the reload fails (e.g. the reference no longer exists
+ * on disk, or has become corrupted), an error code will be
+ * returned and the reference pointer will be invalidated.
+ *
+ * @param ref The reference to reload
+ * @return GIT_SUCCESS on success, or an error code
+ */
+GIT_EXTERN(int) git_reference_reload(git_reference *ref);
+
+/**
+ * Free the given reference
+ *
+ * @param ref git_reference
+ */
+GIT_EXTERN(void) git_reference_free(git_reference *ref);
+
 /** @} */
 GIT_END_DECL
 #endif
diff --git a/include/git2/refspec.h b/include/git2/refspec.h
index eccbeaa..0f8b13c 100644
--- a/include/git2/refspec.h
+++ b/include/git2/refspec.h
@@ -7,7 +7,7 @@
 #ifndef INCLUDE_git_refspec_h__
 #define INCLUDE_git_refspec_h__
 
-#include "git2/types.h"
+#include "types.h"
 
 /**
  * @file git2/refspec.h
diff --git a/include/git2/remote.h b/include/git2/remote.h
index e0be937..54116c2 100644
--- a/include/git2/remote.h
+++ b/include/git2/remote.h
@@ -7,9 +7,9 @@
 #ifndef INCLUDE_git_remote_h__
 #define INCLUDE_git_remote_h__
 
-#include "git2/common.h"
-#include "git2/repository.h"
-#include "git2/refspec.h"
+#include "common.h"
+#include "repository.h"
+#include "refspec.h"
 /**
  * @file git2/remote.h
  * @brief Git remote management functions
diff --git a/include/git2/thread-utils.h b/include/git2/thread-utils.h
deleted file mode 100644
index 81c62d1..0000000
--- a/include/git2/thread-utils.h
+++ /dev/null
@@ -1,60 +0,0 @@
-/*
- * Copyright (C) 2009-2011 the libgit2 contributors
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-#ifndef INCLUDE_git_thread_utils_h__
-#define INCLUDE_git_thread_utils_h__
-
-/*
- * How TLS works is compiler+platform dependant
- * Sources: http://en.wikipedia.org/wiki/Thread-Specific_Storage
- *			http://predef.sourceforge.net/precomp.html
- */
-
-#ifdef GIT_THREADS
-#	define GIT_HAS_TLS 1
-
-/* No TLS in Cygwin */
-#	if defined(__CHECKER__) || defined(__CYGWIN__)
-#		undef GIT_HAS_TLS
-#		define GIT_TLS
-
-/* No TLS in Mach binaries for Mac OS X */
-#	elif defined(__APPLE__) && defined(__MACH__)
-#		undef GIT_TLS
-#		define GIT_TLS
-
-/* Normal TLS for GCC */
-#	elif defined(__GNUC__) || \
-		defined(__SUNPRO_C) || \
-		defined(__SUNPRO_CC) || \
-		defined(__xlc__) || \
-		defined(__xlC__)
-#		define GIT_TLS __thread
-
-/* ICC may run on Windows or Linux */
-#	elif defined(__INTEL_COMPILER)
-#		if defined(_WIN32) || defined(_WIN32_CE)
-#		define GIT_TLS __declspec(thread)
-#		else
-#		define GIT_TLS __thread
-#		endif
-
-/* Declspec for MSVC in Win32 */
-#	elif defined(_WIN32) || \
-		defined(_WIN32_CE) || \
-		defined(__BORLANDC__)
-#		define GIT_TLS __declspec(thread)
-
-/* Other platform; no TLS */
-#	else
-#		undef GIT_HAS_TLS
-#		define GIT_TLS /* nothing: tls vars are thread-global */
-#	endif
-#else /* Disable TLS if libgit2 is not threadsafe */
-#	define GIT_TLS
-#endif /* GIT_THREADS */
-
-#endif /* INCLUDE_git_thread_utils_h__ */
diff --git a/include/git2/threads.h b/include/git2/threads.h
new file mode 100644
index 0000000..85472a4
--- /dev/null
+++ b/include/git2/threads.h
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_threads_h__
+#define INCLUDE_git_threads_h__
+
+#include "common.h"
+
+/**
+ * @file git2/threads.h
+ * @brief Library level thread functions
+ * @defgroup git_thread Threading functions
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Init the threading system.
+ *
+ * If libgit2 has been built with GIT_THREADS
+ * on, this function must be called once before
+ * any other library functions.
+ *
+ * If libgit2 has been built without GIT_THREADS
+ * support, this function is a no-op.
+ */
+GIT_EXTERN(void) git_threads_init(void);
+
+/**
+ * Shutdown the threading system.
+ *
+ * If libgit2 has been built with GIT_THREADS
+ * on, this function must be called before shutting
+ * down the library.
+ *
+ * If libgit2 has been built without GIT_THREADS
+ * support, this function is a no-op.
+ */
+GIT_EXTERN(void) git_threads_shutdown(void);
+
+/** @} */
+GIT_END_DECL
+#endif
+
diff --git a/include/git2/tree.h b/include/git2/tree.h
index 8d638f7..bd89de3 100644
--- a/include/git2/tree.h
+++ b/include/git2/tree.h
@@ -269,19 +269,49 @@
 GIT_EXTERN(int) git_treebuilder_write(git_oid *oid, git_repository *repo, git_treebuilder *bld);
 
 /**
- * Retrieve the tree object containing a tree entry, given
- * a relative path to this tree entry
+ * Retrieve a subtree contained in a tree, given its
+ * relative path.
  *
  * The returned tree is owned by the repository and
  * should be closed with the `git_object_close` method.
  *
- * @param parent_out Pointer where to store the parent tree
+ * @param subtree Pointer where to store the subtree
  * @param root A previously loaded tree which will be the root of the relative path
- * @param treeentry_path Path to the tree entry from which to extract the last tree object
- * @return GIT_SUCCESS on success; GIT_ENOTFOUND if the path does not lead to an
- * entry, GIT_EINVALIDPATH or an error code
+ * @param subtree_path Path to the contained subtree
+ * @return GIT_SUCCESS on success; GIT_ENOTFOUND if the path does not lead to a
+ * subtree, GIT_EINVALIDPATH or an error code
  */
-GIT_EXTERN(int) git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path);
+GIT_EXTERN(int) git_tree_get_subtree(git_tree **subtree, git_tree *root, const char *subtree_path);
+
+/** Callback for the tree traversal method */
+typedef int (*git_treewalk_cb)(const char *root, git_tree_entry *entry, void *payload);
+
+/** Tree traversal modes */
+enum git_treewalk_mode {
+	GIT_TREEWALK_PRE = 0, /* Pre-order */
+	GIT_TREEWALK_POST = 1, /* Post-order */
+};
+
+/**
+ * Traverse the entries in a tree and its subtrees in
+ * post or pre order
+ *
+ * The entries will be traversed in the specified order,
+ * children subtrees will be automatically loaded as required,
+ * and the `callback` will be called once per entry with
+ * the current (relative) root for the entry and the entry
+ * data itself.
+ *
+ * If the callback returns a negative value, the passed entry
+ * will be skiped on the traversal.
+ *
+ * @param tree The tree to walk
+ * @param callback Function to call on each tree entry
+ * @param mode Traversal mode (pre or post-order)
+ * @return GIT_SUCCESS or an error code
+ */
+GIT_EXTERN(int) git_tree_walk(git_tree *walk, git_treewalk_cb callback, int mode, void *payload);
+
 /** @} */
 GIT_END_DECL
 #endif
diff --git a/include/git2/windows.h b/include/git2/windows.h
new file mode 100644
index 0000000..6a2e9e2
--- /dev/null
+++ b/include/git2/windows.h
@@ -0,0 +1,59 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_git_windows_h__
+#define INCLUDE_git_windows_h__
+
+#include "common.h"
+
+/**
+ * @file git2/windows.h
+ * @brief Windows-specific functions
+ * @ingroup Git
+ * @{
+ */
+GIT_BEGIN_DECL
+
+/**
+ * Set the active codepage for Windows syscalls
+ *
+ * All syscalls performed by the library will assume
+ * this codepage when converting paths and strings
+ * to use by the Windows kernel.
+ *
+ * The default value of UTF-8 will work automatically
+ * with most Git repositories created on Unix systems.
+ *
+ * This settings needs only be changed when working
+ * with repositories that contain paths in specific,
+ * non-UTF codepages.
+ *
+ * A full list of all available codepage identifiers may
+ * be found at:
+ *
+ * http://msdn.microsoft.com/en-us/library/windows/desktop/dd317756(v=vs.85).aspx
+ *
+ * @param codepage numeric codepage identifier
+ */
+GIT_EXTERN(void) gitwin_set_codepage(unsigned int codepage);
+
+/**
+ * Return the active codepage for Windows syscalls
+ *
+ * @return numeric codepage identifier
+ */
+GIT_EXTERN(unsigned int) gitwin_get_codepage(void);
+
+/**
+ * Set the active Windows codepage to UTF-8 (this is
+ * the default value)
+ */
+GIT_EXTERN(void) gitwin_set_utf8(void);
+
+/** @} */
+GIT_END_DECL
+#endif
+
diff --git a/src/blob.c b/src/blob.c
index 42564ab..f13a5be 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -27,7 +27,7 @@
 void git_blob__free(git_blob *blob)
 {
 	git_odb_object_close(blob->odb_object);
-	free(blob);
+	git__free(blob);
 }
 
 int git_blob__parse(git_blob *blob, git_odb_object *odb_obj)
diff --git a/src/buffer.c b/src/buffer.c
index 0eeeecf..1fb848e 100644
--- a/src/buffer.c
+++ b/src/buffer.c
@@ -97,7 +97,7 @@
 
 void git_buf_free(git_buf *buf)
 {
-	free(buf->ptr);
+	git__free(buf->ptr);
 }
 
 void git_buf_clear(git_buf *buf)
diff --git a/src/cache.c b/src/cache.c
index 79f3eae..6ba4d21 100644
--- a/src/cache.c
+++ b/src/cache.c
@@ -53,7 +53,7 @@
 		git_mutex_free(&cache->nodes[i].lock);
 	}
 
-	free(cache->nodes);
+	git__free(cache->nodes);
 }
 
 void *git_cache_get(git_cache *cache, const git_oid *oid)
diff --git a/src/commit.c b/src/commit.c
index ced457e..83bc9fc 100644
--- a/src/commit.c
+++ b/src/commit.c
@@ -32,7 +32,7 @@
 
 	for (i = 0; i < commit->parent_oids.length; ++i) {
 		git_oid *parent = git_vector_get(&commit->parent_oids, i);
-		free(parent);
+		git__free(parent);
 	}
 
 	git_vector_clear(&commit->parent_oids);
@@ -46,9 +46,9 @@
 	git_signature_free(commit->author);
 	git_signature_free(commit->committer);
 
-	free(commit->message);
-	free(commit->message_encoding);
-	free(commit);
+	git__free(commit->message);
+	git__free(commit->message_encoding);
+	git__free(commit);
 }
 
 const git_oid *git_commit_id(git_commit *c)
@@ -84,7 +84,7 @@
 		message_encoding, message,
 		tree, parent_count, parents);
 
-	free((void *)parents);
+	git__free((void *)parents);
 
 	return error;
 }
@@ -137,15 +137,18 @@
 
 	if (error == GIT_SUCCESS && update_ref != NULL) {
 		git_reference *head;
+		git_reference *target;
 
 		error = git_reference_lookup(&head, repo, update_ref);
 		if (error < GIT_SUCCESS)
 			return git__rethrow(error, "Failed to create commit");
 
-		error = git_reference_resolve(&head, head);
+		error = git_reference_resolve(&target, head);
 		if (error < GIT_SUCCESS) {
-			if (error != GIT_ENOTFOUND)
+			if (error != GIT_ENOTFOUND) {
+				git_reference_free(head);
 				return git__rethrow(error, "Failed to create commit");
+			}
 		/*
 		 * The target of the reference was not found. This can happen
 		 * just after a repository has been initialized (the master
@@ -153,10 +156,19 @@
 		 * point to) or after an orphan checkout, so if the target
 		 * branch doesn't exist yet, create it and return.
 		 */
-			return git_reference_create_oid(&head, repo, git_reference_target(head), oid, 1);
+			error = git_reference_create_oid(&target, repo, git_reference_target(head), oid, 1);
+
+			git_reference_free(head);
+			if (error == GIT_SUCCESS)
+				git_reference_free(target);
+
+			return error;
 		}
 
-		error = git_reference_set_oid(head, oid);
+		error = git_reference_set_oid(target, oid);
+
+		git_reference_free(head);
+		git_reference_free(target);
 	}
 
 	if (error < GIT_SUCCESS)
diff --git a/src/common.h b/src/common.h
index 475edc5..f4dcc1c 100644
--- a/src/common.h
+++ b/src/common.h
@@ -8,7 +8,6 @@
 #define INCLUDE_common_h__
 
 #include "git2/common.h"
-#include "git2/thread-utils.h"
 #include "cc-compat.h"
 
 #include <assert.h>
diff --git a/src/config.c b/src/config.c
index f53afa1..4e48ff7 100644
--- a/src/config.c
+++ b/src/config.c
@@ -35,11 +35,11 @@
 		internal = git_vector_get(&cfg->files, i);
 		file = internal->file;
 		file->free(file);
-		free(internal);
+		git__free(internal);
 	}
 
 	git_vector_free(&cfg->files);
-	free(cfg);
+	git__free(cfg);
 }
 
 static int config_backend_cmp(const void *a, const void *b)
@@ -61,7 +61,7 @@
 	memset(cfg, 0x0, sizeof(git_config));
 
 	if (git_vector_init(&cfg->files, 3, config_backend_cmp) < 0) {
-		free(cfg);
+		git__free(cfg);
 		return GIT_ENOMEM;
 	}
 
@@ -125,7 +125,7 @@
 	internal->priority = priority;
 
 	if (git_vector_insert(&cfg->files, internal) < 0) {
-		free(internal);
+		git__free(internal);
 		return GIT_ENOMEM;
 	}
 
@@ -366,20 +366,20 @@
 		return git__throw(GIT_ERROR, "Failed to expand environment strings");
 
 	if (_waccess(apphome_utf16, F_OK) < 0) {
-		free(apphome_utf16);
+		git__free(apphome_utf16);
 		return GIT_ENOTFOUND;
 	}
 
-	apphome_utf8 = conv_utf16_to_utf8(apphome_utf16);
-	free(apphome_utf16);
+	apphome_utf8 = gitwin_from_utf16(apphome_utf16);
+	git__free(apphome_utf16);
 
 	if (strlen(apphome_utf8) >= GIT_PATH_MAX) {
-		free(apphome_utf8);
+		git__free(apphome_utf8);
 		return git__throw(GIT_ESHORTBUFFER, "Path is too long");
 	}
 
 	strcpy(system_config_path, apphome_utf8);
-	free(apphome_utf8);
+	git__free(apphome_utf8);
 	return GIT_SUCCESS;
 }
 #endif
diff --git a/src/config.h b/src/config.h
index 7749a9c..43574a5 100644
--- a/src/config.h
+++ b/src/config.h
@@ -14,6 +14,7 @@
 
 #define GIT_CONFIG_FILENAME ".gitconfig"
 #define GIT_CONFIG_FILENAME_INREPO "config"
+#define GIT_CONFIG_FILE_MODE 0666
 
 struct git_config {
 	git_vector files;
diff --git a/src/config_file.c b/src/config_file.c
index a85ae15..aec29d4 100644
--- a/src/config_file.c
+++ b/src/config_file.c
@@ -90,10 +90,10 @@
 	if (var == NULL)
 		return;
 
-	free(var->section);
-	free(var->name);
-	free(var->value);
-	free(var);
+	git__free(var->section);
+	git__free(var->name);
+	git__free(var->value);
+	git__free(var);
 }
 
 static void cvar_list_free(cvar_t_list *list)
@@ -188,7 +188,7 @@
 	if (section_sp == NULL) {
 		ret = p_snprintf(name, len + 1, "%s.%s", var->section, var->name);
 		if (ret < 0) {
-			free(name);
+			git__free(name);
 			return git__throw(GIT_EOSERR, "Failed to normalize name. OS err: %s", strerror(errno));
 		}
 
@@ -281,10 +281,10 @@
 	if (backend == NULL)
 		return;
 
-	free(backend->file_path);
+	git__free(backend->file_path);
 	cvar_list_free(&backend->var_list);
 
-	free(backend);
+	git__free(backend);
 }
 
 static int file_foreach(git_config_file *backend, int (*fn)(const char *, const char *, void *), void *data)
@@ -301,7 +301,7 @@
 			return ret;
 
 		ret = fn(normalized, var->value, data);
-		free(normalized);
+		git__free(normalized);
 		if (ret)
 			break;
 	}
@@ -326,7 +326,7 @@
 		if (tmp == NULL && value != NULL)
 			return GIT_ENOMEM;
 
-		free(existing->value);
+		git__free(existing->value);
 		existing->value = tmp;
 
 		return config_write(b, existing);
@@ -411,7 +411,7 @@
 
 	backend->file_path = git__strdup(path);
 	if (backend->file_path == NULL) {
-		free(backend);
+		git__free(backend);
 		return GIT_ENOMEM;
 	}
 
@@ -653,13 +653,13 @@
 	/* find the end of the variable's name */
 	name_end = strchr(line, ']');
 	if (name_end == NULL) {
-		free(line);
+		git__free(line);
 		return git__throw(GIT_EOBJCORRUPTED, "Failed to parse header. Can't find header name end");
 	}
 
 	name = (char *)git__malloc((size_t)(name_end - line) + 1);
 	if (name == NULL) {
-		free(line);
+		git__free(line);
 		return GIT_ENOMEM;
 	}
 
@@ -679,8 +679,8 @@
 		if (isspace(c)){
 			name[name_length] = '\0';
 			error = parse_section_header_ext(line, name, section_out);
-			free(line);
-			free(name);
+			git__free(line);
+			git__free(name);
 			return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse header");
 		}
 
@@ -699,14 +699,14 @@
 	}
 
 	name[name_length] = 0;
-	free(line);
+	git__free(line);
 	git__strtolower(name);
 	*section_out = name;
 	return GIT_SUCCESS;
 
 error:
-	free(line);
-	free(name);
+	git__free(line);
+	git__free(name);
 	return error;
 }
 
@@ -810,7 +810,7 @@
 			break;
 
 		case '[': /* section header, new section begins */
-			free(current_section);
+			git__free(current_section);
 			current_section = NULL;
 			error = parse_section_header(cfg_file, &current_section);
 			break;
@@ -826,7 +826,7 @@
 			if (error < GIT_SUCCESS)
 				break;
 
-			var = malloc(sizeof(cvar_t));
+			var = git__malloc(sizeof(cvar_t));
 			if (var == NULL) {
 				error = GIT_ENOMEM;
 				break;
@@ -837,7 +837,7 @@
 			var->section = git__strdup(current_section);
 			if (var->section == NULL) {
 				error = GIT_ENOMEM;
-				free(var);
+				git__free(var);
 				break;
 			}
 
@@ -851,7 +851,7 @@
 		}
 	}
 
-	free(current_section);
+	git__free(current_section);
 
 	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse config");
 }
@@ -915,7 +915,7 @@
 			 */
 			pre_end = post_start = cfg->reader.read_ptr;
 			if (current_section)
-				free(current_section);
+				git__free(current_section);
 			error = parse_section_header(cfg, &current_section);
 			if (error < GIT_SUCCESS)
 				break;
@@ -953,8 +953,8 @@
 				if ((error = parse_variable(cfg, &var_name, &var_value)) == GIT_SUCCESS)
 					cmp = strcasecmp(var->name, var_name);
 
-				free(var_name);
-				free(var_value);
+				git__free(var_name);
+				git__free(var_value);
 
 				if (cmp != 0)
 					break;
@@ -1029,12 +1029,12 @@
 		git__rethrow(error, "Failed to write new section");
 
  cleanup:
-	free(current_section);
+	git__free(current_section);
 
 	if (error < GIT_SUCCESS)
 		git_filebuf_cleanup(&file);
 	else
-		error = git_filebuf_commit(&file);
+		error = git_filebuf_commit(&file, GIT_CONFIG_FILE_MODE);
 
 	git_futils_freebuffer(&cfg->reader.buffer);
 	return error;
@@ -1093,7 +1093,7 @@
 	ret = p_snprintf(buf, len, "%s %s", first, line);
 	if (ret < 0) {
 		error = git__throw(GIT_EOSERR, "Failed to parse multiline var. Failed to put together two lines. OS err: %s", strerror(errno));
-		free(buf);
+		git__free(buf);
 		goto out;
 	}
 
@@ -1105,14 +1105,14 @@
 	if (is_multiline_var(buf)) {
 		char *final_val;
 		error = parse_multiline_variable(cfg, buf, &final_val);
-		free(buf);
+		git__free(buf);
 		buf = final_val;
 	}
 
 	*out = buf;
 
  out:
-	free(line);
+	git__free(line);
 	return error;
 }
 
@@ -1158,19 +1158,25 @@
 		while (isspace(value_start[0]))
 			value_start++;
 
-		if (value_start[0] == '\0')
-			goto out;
-
-		if (is_multiline_var(value_start)) {
-			error = parse_multiline_variable(cfg, value_start, var_value);
-			if (error < GIT_SUCCESS)
-				free(*var_name);
+		if (value_start[0] == '\0') {
+			*var_value = NULL;
 			goto out;
 		}
 
-		tmp = strdup(value_start);
+		if (is_multiline_var(value_start)) {
+			error = parse_multiline_variable(cfg, value_start, var_value);
+			if (error != GIT_SUCCESS)
+			{
+				*var_value = NULL;
+				git__free(*var_name);
+			}
+			goto out;
+		}
+
+		tmp = git__strdup(value_start);
 		if (tmp == NULL) {
-			free(*var_name);
+			git__free(*var_name);
+			*var_value = NULL;
 			error = GIT_ENOMEM;
 			goto out;
 		}
@@ -1182,6 +1188,6 @@
 	}
 
  out:
-	free(line);
+	git__free(line);
 	return error;
 }
diff --git a/src/delta-apply.c b/src/delta-apply.c
index e1fb15b..3e40bf8 100644
--- a/src/delta-apply.c
+++ b/src/delta-apply.c
@@ -109,7 +109,7 @@
 	return GIT_SUCCESS;
 
 fail:
-	free(out->data);
+	git__free(out->data);
 	out->data = NULL;
 	return git__throw(GIT_ERROR, "Failed to apply delta");
 }
diff --git a/src/errors.c b/src/errors.c
index 923cb35..22b8ae7 100644
--- a/src/errors.c
+++ b/src/errors.c
@@ -7,14 +7,10 @@
 
 #include "common.h"
 #include "errors.h"
-#include "git2/thread-utils.h" /* for GIT_TLS */
-#include "thread-utils.h" /* for GIT_TLS */
 #include "posix.h"
-
+#include "global.h"
 #include <stdarg.h>
 
-GIT_TLS git_error *git_errno;
-
 static struct {
 	int num;
 	const char *str;
@@ -115,11 +111,11 @@
 	va_end(ap);
 
 	err->code  = code;
-	err->child = git_errno;
+	err->child = GIT_GLOBAL->git_errno;
 	err->file  = file;
 	err->line  = line;
 
-	git_errno = err;
+	GIT_GLOBAL->git_errno = err;
 
 	return err;
 }
@@ -149,13 +145,13 @@
 
 void git_clearerror(void)
 {
-	git_error_free(git_errno);
-	git_errno = NULL;
+	git_error_free(GIT_GLOBAL->git_errno);
+	GIT_GLOBAL->git_errno = NULL;
 }
 
 const char *git_lasterror(void)
 {
-	return git_errno == NULL ? NULL : git_errno->msg;
+	return GIT_GLOBAL->git_errno == NULL ? NULL : GIT_GLOBAL->git_errno->msg;
 }
 
 void git_error_print_stack(git_error *error_in)
@@ -163,7 +159,7 @@
 	git_error *error;
 
 	if (error_in == NULL)
-		error_in = git_errno;
+		error_in = GIT_GLOBAL->git_errno;
 
 	for (error = error_in; error; error = error->child)
 		fprintf(stderr, "%s:%u %s\n", error->file, error->line, error->msg);
diff --git a/src/fetch.c b/src/fetch.c
index ac72828..af7dbaf 100644
--- a/src/fetch.c
+++ b/src/fetch.c
@@ -14,6 +14,7 @@
 #include "transport.h"
 #include "remote.h"
 #include "refspec.h"
+#include "pack.h"
 #include "fetch.h"
 #include "netops.h"
 
@@ -181,7 +182,7 @@
 	}
 
 	/* A bit dodgy, but we need to keep the pack at the temporary path */
-	error = git_filebuf_commit_at(&file, file.path_lock);
+	error = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE);
 cleanup:
 	if (error < GIT_SUCCESS)
 		git_filebuf_cleanup(&file);
diff --git a/src/filebuf.c b/src/filebuf.c
index 1a98e3f..1994180 100644
--- a/src/filebuf.c
+++ b/src/filebuf.c
@@ -10,6 +10,8 @@
 #include "filebuf.h"
 #include "fileops.h"
 
+#define GIT_LOCK_FILE_MODE 0644
+
 static const size_t WRITE_BUFFER_SIZE = (4096 * 2);
 
 static int lock_file(git_filebuf *file, int flags)
@@ -23,9 +25,10 @@
 
 	/* create path to the file buffer is required */
 	if (flags & GIT_FILEBUF_FORCE) {
-		file->fd = git_futils_creat_locked_withpath(file->path_lock, 0644);
+		/* XXX: Should dirmode here be configurable? Or is 0777 always fine? */
+		file->fd = git_futils_creat_locked_withpath(file->path_lock, 0777, GIT_LOCK_FILE_MODE);
 	} else {
-		file->fd = git_futils_creat_locked(file->path_lock, 0644);
+		file->fd = git_futils_creat_locked(file->path_lock, GIT_LOCK_FILE_MODE);
 	}
 
 	if (file->fd < 0)
@@ -63,13 +66,13 @@
 	if (file->digest)
 		git_hash_free_ctx(file->digest);
 
-	free(file->buffer);
-	free(file->z_buf);
+	git__free(file->buffer);
+	git__free(file->z_buf);
 
 	deflateEnd(&file->zs);
 
-	free(file->path_original);
-	free(file->path_lock);
+	git__free(file->path_original);
+	git__free(file->path_lock);
 }
 
 GIT_INLINE(int) flush_buffer(git_filebuf *file)
@@ -246,17 +249,17 @@
 	return GIT_SUCCESS;
 }
 
-int git_filebuf_commit_at(git_filebuf *file, const char *path)
+int git_filebuf_commit_at(git_filebuf *file, const char *path, mode_t mode)
 {
-	free(file->path_original);
+	git__free(file->path_original);
 	file->path_original = git__strdup(path);
 	if (file->path_original == NULL)
 		return GIT_ENOMEM;
 
-	return git_filebuf_commit(file);
+	return git_filebuf_commit(file, mode);
 }
 
-int git_filebuf_commit(git_filebuf *file)
+int git_filebuf_commit(git_filebuf *file, mode_t mode)
 {
 	int error;
 
@@ -270,7 +273,12 @@
 	p_close(file->fd);
 	file->fd = -1;
 
-	error = git_futils_mv_atomic(file->path_lock, file->path_original);
+	if (p_chmod(file->path_lock, mode)) {
+		error = git__throw(GIT_EOSERR, "Failed to chmod locked file before committing");
+		goto cleanup;
+	}
+
+	error = p_rename(file->path_lock, file->path_original);
 
 cleanup:
 	git_filebuf_cleanup(file);
@@ -368,12 +376,12 @@
 	va_end(arglist);
 
 	if (len < 0) {
-		free(tmp_buffer);
+		git__free(tmp_buffer);
 		return git__throw(GIT_EOSERR, "Failed to format string");
 	}
 
 	error = git_filebuf_write(file, tmp_buffer, len);
-	free(tmp_buffer);
+	git__free(tmp_buffer);
 
 	return error;
 }
diff --git a/src/filebuf.h b/src/filebuf.h
index 525ca3c..d08505e 100644
--- a/src/filebuf.h
+++ b/src/filebuf.h
@@ -49,8 +49,8 @@
 int git_filebuf_printf(git_filebuf *file, const char *format, ...) GIT_FORMAT_PRINTF(2, 3);
 
 int git_filebuf_open(git_filebuf *lock, const char *path, int flags);
-int git_filebuf_commit(git_filebuf *lock);
-int git_filebuf_commit_at(git_filebuf *lock, const char *path);
+int git_filebuf_commit(git_filebuf *lock, mode_t mode);
+int git_filebuf_commit_at(git_filebuf *lock, const char *path, mode_t mode);
 void git_filebuf_cleanup(git_filebuf *lock);
 int git_filebuf_hash(git_oid *oid, git_filebuf *file);
 
diff --git a/src/fileops.c b/src/fileops.c
index 203cce0..955bb1b 100644
--- a/src/fileops.c
+++ b/src/fileops.c
@@ -8,32 +8,8 @@
 #include "fileops.h"
 #include <ctype.h>
 
-int git_futils_mv_atomic(const char *from, const char *to)
+int git_futils_mkpath2file(const char *file_path, const mode_t mode)
 {
-#ifdef GIT_WIN32
-	/*
-	 * Win32 POSIX compilance my ass. If the destination
-	 * file exists, the `rename` call fails. This is as
-	 * close as it gets with the Win32 API.
-	 */
-	return MoveFileEx(from, to, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
-#else
-	/* Don't even try this on Win32 */
-	if (!link(from, to)) {
-		p_unlink(from);
-		return GIT_SUCCESS;
-	}
-
-	if (!rename(from, to))
-		return GIT_SUCCESS;
-
-	return GIT_ERROR;
-#endif
-}
-
-int git_futils_mkpath2file(const char *file_path)
-{
-	const int mode = 0755; /* or 0777 ? */
 	int error = GIT_SUCCESS;
 	char target_folder_path[GIT_PATH_MAX];
 
@@ -67,23 +43,23 @@
 	return fd;
 }
 
-int git_futils_creat_withpath(const char *path, int mode)
+int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode)
 {
-	if (git_futils_mkpath2file(path) < GIT_SUCCESS)
+	if (git_futils_mkpath2file(path, dirmode) < GIT_SUCCESS)
 		return git__throw(GIT_EOSERR, "Failed to create file %s", path);
 
 	return p_creat(path, mode);
 }
 
-int git_futils_creat_locked(const char *path, int mode)
+int git_futils_creat_locked(const char *path, const mode_t mode)
 {
 	int fd = open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY | O_EXCL, mode);
 	return fd >= 0 ? fd : git__throw(GIT_EOSERR, "Failed to create locked file. Could not open %s", path);
 }
 
-int git_futils_creat_locked_withpath(const char *path, int mode)
+int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode)
 {
-	if (git_futils_mkpath2file(path) < GIT_SUCCESS)
+	if (git_futils_mkpath2file(path, dirmode) < GIT_SUCCESS)
 		return git__throw(GIT_EOSERR, "Failed to create locked file %s", path);
 
 	return git_futils_creat_locked(path, mode);
@@ -181,7 +157,7 @@
 
 	if (p_read(fd, buff, len) < 0) {
 		p_close(fd);
-		free(buff);
+		git__free(buff);
 		return git__throw(GIT_ERROR, "Failed to read file `%s`", path);
 	}
 	buff[len] = '\0';
@@ -207,17 +183,17 @@
 void git_futils_freebuffer(git_fbuffer *obj)
 {
 	assert(obj);
-	free(obj->data);
+	git__free(obj->data);
 	obj->data = NULL;
 }
 
 
-int git_futils_mv_withpath(const char *from, const char *to)
+int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode)
 {
-	if (git_futils_mkpath2file(to) < GIT_SUCCESS)
+	if (git_futils_mkpath2file(to, dirmode) < GIT_SUCCESS)
 		return GIT_EOSERR;	/* The callee already takes care of setting the correct error message. */
 
-	return git_futils_mv_atomic(from, to);	/* The callee already takes care of setting the correct error message. */
+	return p_rename(from, to); /* The callee already takes care of setting the correct error message. */
 }
 
 int git_futils_mmap_ro(git_map *out, git_file fd, git_off_t begin, size_t len)
@@ -289,7 +265,7 @@
 	return GIT_SUCCESS;
 }
 
-int git_futils_mkdir_r(const char *path, int mode)
+int git_futils_mkdir_r(const char *path, const mode_t mode)
 {
 	int error, root_path_offset;
 	char *pp, *sp;
@@ -326,7 +302,7 @@
 			error = GIT_SUCCESS;
 	}
 
-	free(path_copy);
+	git__free(path_copy);
 
 	if (error < GIT_SUCCESS)
 		return git__throw(error, "Failed to recursively create `%s` tree structure", path);
diff --git a/src/fileops.h b/src/fileops.h
index 5b69199..56c4770 100644
--- a/src/fileops.h
+++ b/src/fileops.h
@@ -48,18 +48,18 @@
  * Create and open a file, while also
  * creating all the folders in its path
  */
-extern int git_futils_creat_withpath(const char *path, int mode);
+extern int git_futils_creat_withpath(const char *path, const mode_t dirmode, const mode_t mode);
 
 /**
  * Create an open a process-locked file
  */
-extern int git_futils_creat_locked(const char *path, int mode);
+extern int git_futils_creat_locked(const char *path, const mode_t mode);
 
 /**
  * Create an open a process-locked file, while
  * also creating all the folders in its path
  */
-extern int git_futils_creat_locked_withpath(const char *path, int mode);
+extern int git_futils_creat_locked_withpath(const char *path, const mode_t dirmode, const mode_t mode);
 
 /**
  * Check if the given path points to a directory
@@ -74,13 +74,13 @@
 /**
  * Create a path recursively
  */
-extern int git_futils_mkdir_r(const char *path, int mode);
+extern int git_futils_mkdir_r(const char *path, const mode_t mode);
 
 /**
  * Create all the folders required to contain
  * the full path of a file
  */
-extern int git_futils_mkpath2file(const char *path);
+extern int git_futils_mkpath2file(const char *path, const mode_t mode);
 
 extern int git_futils_rmdir_r(const char *path, int force);
 
@@ -98,7 +98,7 @@
  * Move a file on the filesystem, create the
  * destination path if it doesn't exist
  */
-extern int git_futils_mv_withpath(const char *from, const char *to);
+extern int git_futils_mv_withpath(const char *from, const char *to, const mode_t dirmode);
 
 
 /**
diff --git a/src/global.c b/src/global.c
new file mode 100644
index 0000000..8ef286e
--- /dev/null
+++ b/src/global.c
@@ -0,0 +1,134 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#include "common.h"
+#include "global.h"
+#include "git2/threads.h" 
+#include "thread-utils.h"
+
+/**
+ * Handle the global state with TLS
+ *
+ * If libgit2 is built with GIT_THREADS enabled,
+ * the `git_threads_init()` function must be called
+ * before calling any other function of the library.
+ *
+ * This function allocates a TLS index (using pthreads
+ * or the native Win32 API) to store the global state
+ * on a per-thread basis.
+ *
+ * Any internal method that requires global state will
+ * then call `git__global_state()` which returns a pointer
+ * to the global state structure; this pointer is lazily
+ * allocated on each thread.
+ *
+ * Before shutting down the library, the
+ * `git_threads_shutdown` method must be called to free
+ * the previously reserved TLS index.
+ *
+ * If libgit2 is built without threading support, the
+ * `git__global_statestate()` call returns a pointer to a single,
+ * statically allocated global state. The `git_thread_`
+ * functions are not available in that case.
+ */
+
+#if defined(GIT_THREADS) && defined(GIT_WIN32)
+
+static DWORD _tls_index;
+static int _tls_init = 0;
+
+void git_threads_init(void)
+{
+	if (_tls_init)
+		return;
+
+	_tls_index = TlsAlloc();
+	_tls_init = 1;
+}
+
+void git_threads_shutdown(void)
+{
+	TlsFree(_tls_index);
+	_tls_init = 0;
+}
+
+git_global_st *git__global_state(void)
+{
+	void *ptr;
+
+	if ((ptr = TlsGetValue(_tls_index)) != NULL)
+		return ptr;
+
+	ptr = malloc(sizeof(git_global_st));
+	if (!ptr)
+		return NULL;
+
+	memset(ptr, 0x0, sizeof(git_global_st));
+	TlsSetValue(_tls_index, ptr);
+	return ptr;
+}
+
+#elif defined(GIT_THREADS) && defined(_POSIX_THREADS)
+
+static pthread_key_t _tls_key;
+static int _tls_init = 0;
+
+static void cb__free_status(void *st)
+{
+	free(st);
+}
+
+void git_threads_init(void)
+{
+	if (_tls_init)
+		return;
+
+	pthread_key_create(&_tls_key, &cb__free_status);
+	_tls_init = 1;
+}
+
+void git_threads_shutdown(void)
+{
+	pthread_key_delete(_tls_key);
+	_tls_init = 0;
+}
+
+git_global_st *git__global_state(void)
+{
+	void *ptr;
+
+	if ((ptr = pthread_getspecific(_tls_key)) != NULL)
+		return ptr;
+
+	ptr = malloc(sizeof(git_global_st));
+	if (!ptr)
+		return NULL;
+
+	memset(ptr, 0x0, sizeof(git_global_st));
+	pthread_setspecific(_tls_key, ptr);
+	return ptr;
+}
+
+#else
+
+static git_global_st __state;
+
+void git_threads_init(void)
+{
+	/* noop */ 
+}
+
+void git_threads_shutdown(void)
+{
+	/* noop */
+}
+
+git_global_st *git__global_state(void)
+{
+	return &__state;
+}
+
+#endif /* GIT_THREADS */
diff --git a/src/global.h b/src/global.h
new file mode 100644
index 0000000..6a15a8d
--- /dev/null
+++ b/src/global.h
@@ -0,0 +1,22 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+#ifndef INCLUDE_global_h__
+#define INCLUDE_global_h__
+
+#include "mwindow.h"
+#include "git2/types.h"
+
+typedef struct {
+	git_error *git_errno;
+	git_mwindow_ctl mem_ctl;
+} git_global_st;
+
+git_global_st *git__global_state(void);
+
+#define GIT_GLOBAL (git__global_state())
+
+#endif
diff --git a/src/hash.c b/src/hash.c
index ff85ca9..56063cc 100644
--- a/src/hash.c
+++ b/src/hash.c
@@ -32,7 +32,7 @@
 
 void git_hash_free_ctx(git_hash_ctx *ctx)
 {
-	free(ctx);
+	git__free(ctx);
 }
 
 void git_hash_init(git_hash_ctx *ctx)
diff --git a/src/hashtable.c b/src/hashtable.c
index 1382eab..15d1739 100644
--- a/src/hashtable.c
+++ b/src/hashtable.c
@@ -39,17 +39,17 @@
 			self->is_resizing = 0;
 		else {
 			new_size *= 2;
-			free(self->nodes);
+			git__free(self->nodes);
 		}
 	} while(self->is_resizing);
 
-	free(old_nodes);
+	git__free(old_nodes);
 	return GIT_SUCCESS;
 }
 
 static int set_size(git_hashtable *self, size_t new_size)
 {
-	self->nodes = realloc(self->nodes, new_size * sizeof(git_hashtable_node));
+	self->nodes = git__realloc(self->nodes, new_size * sizeof(git_hashtable_node));
 	if (self->nodes == NULL)
 		return GIT_ENOMEM;
 
@@ -156,8 +156,8 @@
 {
 	assert(self);
 
-	free(self->nodes);
-	free(self);
+	git__free(self->nodes);
+	git__free(self);
 }
 
 
diff --git a/src/index.c b/src/index.c
index 7bf5daf..1a9745a 100644
--- a/src/index.c
+++ b/src/index.c
@@ -138,7 +138,7 @@
 
 	index->index_file_path = git__strdup(index_path);
 	if (index->index_file_path == NULL) {
-		free(index);
+		git__free(index);
 		return GIT_ENOMEM;
 	}
 
@@ -179,8 +179,8 @@
 	git_vector_free(&index->entries);
 	git_vector_free(&index->unmerged);
 
-	free(index->index_file_path);
-	free(index);
+	git__free(index->index_file_path);
+	git__free(index);
 }
 
 void git_index_clear(git_index *index)
@@ -192,15 +192,15 @@
 	for (i = 0; i < index->entries.length; ++i) {
 		git_index_entry *e;
 		e = git_vector_get(&index->entries, i);
-		free(e->path);
-		free(e);
+		git__free(e->path);
+		git__free(e);
 	}
 
 	for (i = 0; i < index->unmerged.length; ++i) {
 		git_index_entry_unmerged *e;
 		e = git_vector_get(&index->unmerged, i);
-		free(e->path);
-		free(e);
+		git__free(e->path);
+		git__free(e);
 	}
 
 	git_vector_clear(&index->entries);
@@ -262,7 +262,7 @@
 		return git__rethrow(error, "Failed to write index");
 	}
 
-	if ((error = git_filebuf_commit(&file)) < GIT_SUCCESS)
+	if ((error = git_filebuf_commit(&file, GIT_INDEX_FILE_MODE)) < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to write index");
 
 	if (p_stat(index->index_file_path, &indexst) == 0) {
@@ -334,7 +334,7 @@
 	entry->flags |= (stage << GIT_IDXENTRY_STAGESHIFT);
 	entry->path = git__strdup(rel_path);
 	if (entry->path == NULL) {
-		free(entry);
+		git__free(entry);
 		return GIT_ENOMEM;
 	}
 
@@ -364,8 +364,8 @@
 {
 	if (!entry)
 		return;
-	free(entry->path);
-	free(entry);
+	git__free(entry->path);
+	git__free(entry);
 }
 
 static int index_insert(git_index *index, git_index_entry *entry, int replace)
@@ -416,8 +416,8 @@
 
 	/* exists, replace it */
 	entry_array = (git_index_entry **) index->entries.contents;
-	free(entry_array[position]->path);
-	free(entry_array[position]);
+	git__free(entry_array[position]->path);
+	git__free(entry_array[position]);
 	entry_array[position] = entry;
 
 	return GIT_SUCCESS;
diff --git a/src/index.h b/src/index.h
index e912770..a1cd340 100644
--- a/src/index.h
+++ b/src/index.h
@@ -14,6 +14,9 @@
 #include "git2/odb.h"
 #include "git2/index.h"
 
+#define GIT_INDEX_FILE "index"
+#define GIT_INDEX_FILE_MODE 0666
+
 struct git_index {
 	git_repository *repository;
 	char *index_file_path;
diff --git a/src/indexer.c b/src/indexer.c
index d5f605f..a69ab85 100644
--- a/src/indexer.c
+++ b/src/indexer.c
@@ -272,7 +272,7 @@
 	/* Figure out what the final name should be */
 	index_path(filename, idx);
 	/* Commit file */
-	error = git_filebuf_commit_at(&idx->file, filename);
+	error = git_filebuf_commit_at(&idx->file, filename, GIT_PACK_FILE_MODE);
 
 cleanup:
 	git_mwindow_free_all(&idx->pack->mwf);
@@ -367,7 +367,7 @@
 			idx->fanout[i]++;
 		}
 
-		free(obj.data);
+		git__free(obj.data);
 
 		stats->processed = ++processed;
 	}
@@ -390,12 +390,12 @@
 
 	p_close(idx->pack->mwf.fd);
 	git_vector_foreach(&idx->objects, i, e)
-		free(e);
+		git__free(e);
 	git_vector_free(&idx->objects);
 	git_vector_foreach(&idx->pack->cache, i, pe)
-		free(pe);
+		git__free(pe);
 	git_vector_free(&idx->pack->cache);
-	free(idx->pack);
-	free(idx);
+	git__free(idx->pack);
+	git__free(idx);
 }
 
diff --git a/src/mwindow.c b/src/mwindow.c
index e53477e..8dc4573 100644
--- a/src/mwindow.c
+++ b/src/mwindow.c
@@ -10,6 +10,7 @@
 #include "vector.h"
 #include "fileops.h"
 #include "map.h"
+#include "global.h"
 
 #define DEFAULT_WINDOW_SIZE \
 	(sizeof(void*) >= 8 \
@@ -20,21 +21,15 @@
 	((1024 * 1024) * (sizeof(void*) >= 8 ? 8192ULL : 256UL))
 
 /*
- * We need this because each process is only allowed a specific amount
- * of memory. Making it writable should generate one instance per
- * process, but we still need to set a couple of variables.
+ * These are the global options for mmmap limits.
+ * TODO: allow the user to change these
  */
-
-static git_mwindow_ctl ctl = {
-	0,
-	0,
+static struct {
+	size_t window_size;
+	size_t mapped_limit;
+} _mw_options = {
 	DEFAULT_WINDOW_SIZE,
 	DEFAULT_MAPPED_LIMIT,
-	0,
-	0,
-	0,
-	0,
-	{0, 0, 0, 0, 0}
 };
 
 /*
@@ -43,33 +38,34 @@
  */
 void git_mwindow_free_all(git_mwindow_file *mwf)
 {
+	git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
 	unsigned int i;
 	/*
 	 * Remove these windows from the global list
 	 */
-	for (i = 0; i < ctl.windowfiles.length; ++i){
-		if (git_vector_get(&ctl.windowfiles, i) == mwf) {
-			git_vector_remove(&ctl.windowfiles, i);
+	for (i = 0; i < ctl->windowfiles.length; ++i){
+		if (git_vector_get(&ctl->windowfiles, i) == mwf) {
+			git_vector_remove(&ctl->windowfiles, i);
 			break;
 		}
 	}
 
-	if (ctl.windowfiles.length == 0) {
-		git_vector_free(&ctl.windowfiles);
-		ctl.windowfiles.contents = NULL;
+	if (ctl->windowfiles.length == 0) {
+		git_vector_free(&ctl->windowfiles);
+		ctl->windowfiles.contents = NULL;
 	}
 
 	while (mwf->windows) {
 		git_mwindow *w = mwf->windows;
 		assert(w->inuse_cnt == 0);
 
-		ctl.mapped -= w->window_map.len;
-		ctl.open_windows--;
+		ctl->mapped -= w->window_map.len;
+		ctl->open_windows--;
 
 		git_futils_mmap_free(&w->window_map);
 
 		mwf->windows = w->next;
-		free(w);
+		git__free(w);
 	}
 }
 
@@ -115,6 +111,7 @@
  */
 static int git_mwindow_close_lru(git_mwindow_file *mwf)
 {
+	git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
 	unsigned int i;
 	git_mwindow *lru_w = NULL, *lru_l = NULL, **list = &mwf->windows;
 
@@ -122,16 +119,16 @@
 	if(mwf->windows)
 		git_mwindow_scan_lru(mwf, &lru_w, &lru_l);
 
-	for (i = 0; i < ctl.windowfiles.length; ++i) {
+	for (i = 0; i < ctl->windowfiles.length; ++i) {
 		git_mwindow *last = lru_w;
-		git_mwindow_file *cur = git_vector_get(&ctl.windowfiles, i);
+		git_mwindow_file *cur = git_vector_get(&ctl->windowfiles, i);
 		git_mwindow_scan_lru(cur, &lru_w, &lru_l);
 		if (lru_w != last)
 			list = &cur->windows;
 	}
 
 	if (lru_w) {
-		ctl.mapped -= lru_w->window_map.len;
+		ctl->mapped -= lru_w->window_map.len;
 		git_futils_mmap_free(&lru_w->window_map);
 
 		if (lru_l)
@@ -139,8 +136,8 @@
 		else
 			*list = lru_w->next;
 
-		free(lru_w);
-		ctl.open_windows--;
+		git__free(lru_w);
+		ctl->open_windows--;
 
 		return GIT_SUCCESS;
 	}
@@ -148,9 +145,14 @@
 	return git__throw(GIT_ERROR, "Failed to close memory window. Couln't find LRU");
 }
 
-static git_mwindow *new_window(git_mwindow_file *mwf, git_file fd, git_off_t size, git_off_t offset)
+static git_mwindow *new_window(
+	git_mwindow_file *mwf,
+	git_file fd,
+	git_off_t size,
+	git_off_t offset)
 {
-	size_t walign = ctl.window_size / 2;
+	git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
+	size_t walign = _mw_options.window_size / 2;
 	git_off_t len;
 	git_mwindow *w;
 
@@ -162,16 +164,16 @@
 	w->offset = (offset / walign) * walign;
 
 	len = size - w->offset;
-	if (len > (git_off_t)ctl.window_size)
-		len = (git_off_t)ctl.window_size;
+	if (len > (git_off_t)_mw_options.window_size)
+		len = (git_off_t)_mw_options.window_size;
 
-	ctl.mapped += (size_t)len;
+	ctl->mapped += (size_t)len;
 
-	while(ctl.mapped_limit < ctl.mapped &&
-			git_mwindow_close_lru(mwf) == GIT_SUCCESS) {}
+	while (_mw_options.mapped_limit < ctl->mapped &&
+			git_mwindow_close_lru(mwf) == GIT_SUCCESS) /* nop */;
 
 	/*
-	 * We treat ctl.mapped_limit as a soft limit. If we can't find a
+	 * We treat _mw_options.mapped_limit as a soft limit. If we can't find a
 	 * window to close and are above the limit, we still mmap the new
 	 * window.
 	 */
@@ -179,19 +181,19 @@
 	if (git_futils_mmap_ro(&w->window_map, fd, w->offset, (size_t)len) < GIT_SUCCESS)
 		goto cleanup;
 
-	ctl.mmap_calls++;
-	ctl.open_windows++;
+	ctl->mmap_calls++;
+	ctl->open_windows++;
 
-	if (ctl.mapped > ctl.peak_mapped)
-		ctl.peak_mapped = ctl.mapped;
+	if (ctl->mapped > ctl->peak_mapped)
+		ctl->peak_mapped = ctl->mapped;
 
-	if (ctl.open_windows > ctl.peak_open_windows)
-		ctl.peak_open_windows = ctl.open_windows;
+	if (ctl->open_windows > ctl->peak_open_windows)
+		ctl->peak_open_windows = ctl->open_windows;
 
 	return w;
 
 cleanup:
-	free(w);
+	git__free(w);
 	return NULL;
 }
 
@@ -199,9 +201,14 @@
  * Open a new window, closing the least recenty used until we have
  * enough space. Don't forget to add it to your list
  */
-unsigned char *git_mwindow_open(git_mwindow_file *mwf, git_mwindow **cursor,
-								git_off_t offset, int extra, unsigned int *left)
+unsigned char *git_mwindow_open(
+	git_mwindow_file *mwf,
+	git_mwindow **cursor,
+	git_off_t offset,
+	int extra,
+	unsigned int *left)
 {
+	git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
 	git_mwindow *w = *cursor;
 
 	if (!w || !git_mwindow_contains(w, offset + extra)) {
@@ -229,7 +236,7 @@
 
 	/* If we changed w, store it in the cursor */
 	if (w != *cursor) {
-		w->last_used = ctl.used_ctr++;
+		w->last_used = ctl->used_ctr++;
 		w->inuse_cnt++;
 		*cursor = w;
 	}
@@ -245,13 +252,14 @@
 
 int git_mwindow_file_register(git_mwindow_file *mwf)
 {
+	git_mwindow_ctl *ctl = &GIT_GLOBAL->mem_ctl;
 	int error;
 
-	if (ctl.windowfiles.length == 0 &&
-		(error = git_vector_init(&ctl.windowfiles, 8, NULL)) < GIT_SUCCESS)
+	if (ctl->windowfiles.length == 0 &&
+		(error = git_vector_init(&ctl->windowfiles, 8, NULL)) < GIT_SUCCESS)
 		return error;
 
-	return git_vector_insert(&ctl.windowfiles, mwf);
+	return git_vector_insert(&ctl->windowfiles, mwf);
 }
 
 void git_mwindow_close(git_mwindow **window)
diff --git a/src/mwindow.h b/src/mwindow.h
index ec75f90..11c3aa8 100644
--- a/src/mwindow.h
+++ b/src/mwindow.h
@@ -10,7 +10,6 @@
 
 #include "map.h"
 #include "vector.h"
-#include "fileops.h"
 
 typedef struct git_mwindow {
 	struct git_mwindow *next;
@@ -29,8 +28,6 @@
 typedef struct git_mwindow_ctl {
 	size_t mapped;
 	unsigned int open_windows;
-	size_t window_size; /* needs default value */
-	size_t mapped_limit; /* needs default value */
 	unsigned int mmap_calls;
 	unsigned int peak_open_windows;
 	size_t peak_mapped;
diff --git a/src/netops.c b/src/netops.c
index dad296a..73375d7 100644
--- a/src/netops.c
+++ b/src/netops.c
@@ -190,7 +190,7 @@
 	delim = colon == NULL ? slash : colon;
 	*host = git__strndup(url, delim - url);
 	if (*host == NULL) {
-		free(*port);
+		git__free(*port);
 		error = GIT_ENOMEM;
 	}
 
diff --git a/src/object.c b/src/object.c
index edc2d80..c84e94b 100644
--- a/src/object.c
+++ b/src/object.c
@@ -213,7 +213,7 @@
 		break;
 
 	default:
-		free(object);
+		git__free(object);
 		break;
 	}
 }
diff --git a/src/odb.c b/src/odb.c
index 60789cf..69fdba0 100644
--- a/src/odb.c
+++ b/src/odb.c
@@ -83,8 +83,8 @@
 	git_odb_object *object = (git_odb_object *)o;
 
 	if (object != NULL) {
-		free(object->raw.data);
-		free(object);
+		git__free(object->raw.data);
+		git__free(object);
 	}
 }
 
@@ -205,8 +205,8 @@
 {
 	fake_wstream *stream = (fake_wstream *)_stream;
 
-	free(stream->buffer);
-	free(stream);
+	git__free(stream->buffer);
+	git__free(stream);
 }
 
 static int init_fake_wstream(git_odb_stream **stream_p, git_odb_backend *backend, size_t size, git_otype type)
@@ -221,7 +221,7 @@
 	stream->type = type;
 	stream->buffer = git__malloc(size);
 	if (stream->buffer == NULL) {
-		free(stream);
+		git__free(stream);
 		return GIT_ENOMEM;
 	}
 
@@ -265,12 +265,12 @@
 
 	error = git_cache_init(&db->cache, GIT_DEFAULT_CACHE_SIZE, &free_odb_object);
 	if (error < GIT_SUCCESS) {
-		free(db);
+		git__free(db);
 		return git__rethrow(error, "Failed to create object database");
 	}
 
 	if ((error = git_vector_init(&db->backends, 4, backend_sort_cmp)) < GIT_SUCCESS) {
-		free(db);
+		git__free(db);
 		return git__rethrow(error, "Failed to create object database");
 	}
 
@@ -296,7 +296,7 @@
 	internal->is_alternate = is_alternate;
 
 	if (git_vector_insert(&odb->backends, internal) < 0) {
-		free(internal);
+		git__free(internal);
 		return GIT_ENOMEM;
 	}
 
@@ -421,14 +421,14 @@
 		git_odb_backend *backend = internal->backend;
 
 		if (backend->free) backend->free(backend);
-		else free(backend);
+		else git__free(backend);
 
-		free(internal);
+		git__free(internal);
 	}
 
 	git_vector_free(&db->backends);
 	git_cache_free(&db->cache);
-	free(db);
+	git__free(db);
 }
 
 int git_odb_exists(git_odb *db, const git_oid *id)
diff --git a/src/odb.h b/src/odb.h
index 4e85091..833739e 100644
--- a/src/odb.h
+++ b/src/odb.h
@@ -14,6 +14,10 @@
 #include "vector.h"
 #include "cache.h"
 
+#define GIT_OBJECTS_DIR "objects/"
+#define GIT_OBJECT_DIR_MODE 0777
+#define GIT_OBJECT_FILE_MODE 0444
+
 /* DO NOT EXPORT */
 typedef struct {
 	void *data;			/**< Raw, decompressed object data. */
diff --git a/src/odb_loose.c b/src/odb_loose.c
index dbfe18b..57a0b0a 100644
--- a/src/odb_loose.c
+++ b/src/odb_loose.c
@@ -277,7 +277,7 @@
 	else {
 		set_stream_output(s, buf + used, hdr->size - used);
 		if (finish_inflate(s)) {
-			free(buf);
+			git__free(buf);
 			return NULL;
 		}
 	}
@@ -317,7 +317,7 @@
 	in = ((unsigned char *)obj->data) + used;
 	len = obj->len - used;
 	if (inflate_buffer(in, len, buf, hdr.size)) {
-		free(buf);
+		git__free(buf);
 		return git__throw(GIT_ERROR, "Failed to inflate loose object. Could not inflate buffer");
 	}
 	buf[hdr.size] = '\0';
@@ -666,11 +666,22 @@
 	if (object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid))
 		return GIT_ENOMEM;
 
-	if ((error = git_futils_mkpath2file(final_path)) < GIT_SUCCESS)
+	if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to write loose backend");
 
 	stream->finished = 1;
-	return git_filebuf_commit_at(&stream->fbuf, final_path);
+
+	/*
+	 * Don't try to add an existing object to the repository. This
+	 * is what git does and allows us to sidestep the fact that
+	 * we're not allowed to overwrite a read-only file on Windows.
+	 */
+	if (git_futils_exists(final_path) == GIT_SUCCESS) {
+		git_filebuf_cleanup(&stream->fbuf);
+		return GIT_SUCCESS;
+	}
+
+	return git_filebuf_commit_at(&stream->fbuf, final_path, GIT_OBJECT_FILE_MODE);
 }
 
 static int loose_backend__stream_write(git_odb_stream *_stream, const char *data, size_t len)
@@ -686,7 +697,7 @@
 	if (!stream->finished)
 		git_filebuf_cleanup(&stream->fbuf);
 
-	free(stream);
+	git__free(stream);
 }
 
 static int format_object_header(char *hdr, size_t n, size_t obj_len, git_otype obj_type)
@@ -739,14 +750,14 @@
 		(backend->object_zlib_level << GIT_FILEBUF_DEFLATE_SHIFT));
 
 	if (error < GIT_SUCCESS) {
-		free(stream);
+		git__free(stream);
 		return git__rethrow(error, "Failed to create loose backend stream");
 	}
 
 	error = stream->stream.write((git_odb_stream *)stream, hdr, hdrlen);
 	if (error < GIT_SUCCESS) {
 		git_filebuf_cleanup(&stream->fbuf);
-		free(stream);
+		git__free(stream);
 		return git__rethrow(error, "Failed to create loose backend stream");
 	}
 
@@ -787,10 +798,10 @@
 	if ((error = object_file_name(final_path, sizeof(final_path), backend->objects_dir, oid)) < GIT_SUCCESS)
 		goto cleanup;
 
-	if ((error = git_futils_mkpath2file(final_path)) < GIT_SUCCESS)
+	if ((error = git_futils_mkpath2file(final_path, GIT_OBJECT_DIR_MODE)) < GIT_SUCCESS)
 		goto cleanup;
 
-	return git_filebuf_commit_at(&fbuf, final_path);
+	return git_filebuf_commit_at(&fbuf, final_path, GIT_OBJECT_FILE_MODE);
 
 cleanup:
 	git_filebuf_cleanup(&fbuf);
@@ -803,8 +814,8 @@
 	assert(_backend);
 	backend = (loose_backend *)_backend;
 
-	free(backend->objects_dir);
-	free(backend);
+	git__free(backend->objects_dir);
+	git__free(backend);
 }
 
 int git_odb_backend_loose(
@@ -821,7 +832,7 @@
 
 	backend->objects_dir = git__strdup(objects_dir);
 	if (backend->objects_dir == NULL) {
-		free(backend);
+		git__free(backend);
 		return GIT_ENOMEM;
 	}
 
diff --git a/src/odb_pack.c b/src/odb_pack.c
index a8f8542..800e7b0 100644
--- a/src/odb_pack.c
+++ b/src/odb_pack.c
@@ -231,7 +231,7 @@
 		return git__rethrow(error, "Failed to load packfile");
 
 	if (git_vector_insert(&backend->packs, pack) < GIT_SUCCESS) {
-		free(pack);
+		git__free(pack);
 		return GIT_ENOMEM;
 	}
 
@@ -445,8 +445,8 @@
 	}
 
 	git_vector_free(&backend->packs);
-	free(backend->pack_folder);
-	free(backend);
+	git__free(backend->pack_folder);
+	git__free(backend);
 }
 
 int git_odb_backend_pack(git_odb_backend **backend_out, const char *objects_dir)
@@ -459,7 +459,7 @@
 		return GIT_ENOMEM;
 
 	if (git_vector_init(&backend->packs, 8, packfile_sort__cb) < GIT_SUCCESS) {
-		free(backend);
+		git__free(backend);
 		return GIT_ENOMEM;
 	}
 
@@ -469,7 +469,7 @@
 		backend->pack_folder_mtime = 0;
 
 		if (backend->pack_folder == NULL) {
-			free(backend);
+			git__free(backend);
 			return GIT_ENOMEM;
 		}
 	}
diff --git a/src/oid.c b/src/oid.c
index bbf19ea..4b30804 100644
--- a/src/oid.c
+++ b/src/oid.c
@@ -223,7 +223,7 @@
 
 static int resize_trie(git_oid_shorten *self, size_t new_size)
 {
-	self->nodes = realloc(self->nodes, new_size * sizeof(trie_node));
+	self->nodes = git__realloc(self->nodes, new_size * sizeof(trie_node));
 	if (self->nodes == NULL)
 		return GIT_ENOMEM;
 
@@ -270,7 +270,7 @@
 	memset(os, 0x0, sizeof(git_oid_shorten));
 
 	if (resize_trie(os, 16) < GIT_SUCCESS) {
-		free(os);
+		git__free(os);
 		return NULL;
 	}
 
@@ -282,8 +282,8 @@
 
 void git_oid_shorten_free(git_oid_shorten *os)
 {
-	free(os->nodes);
-	free(os);
+	git__free(os->nodes);
+	git__free(os);
 }
 
 
diff --git a/src/pack.c b/src/pack.c
index 2516bea..ae954b9 100644
--- a/src/pack.c
+++ b/src/pack.c
@@ -5,11 +5,13 @@
  * a Linking Exception. For full terms see the included COPYING file.
  */
 
-#include "mwindow.h"
+#include "common.h"
 #include "odb.h"
 #include "pack.h"
 #include "delta-apply.h"
 #include "sha1_lookup.h"
+#include "mwindow.h"
+#include "fileops.h"
 
 #include "git2/oid.h"
 #include "git2/zlib.h"
@@ -181,7 +183,7 @@
 	strcpy(idx_name + strlen(idx_name) - strlen(".pack"), ".idx");
 
 	error = pack_index_check(idx_name, p);
-	free(idx_name);
+	git__free(idx_name);
 
 	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to open index");
 }
@@ -297,7 +299,7 @@
 
 	error = packfile_unpack_compressed(&delta, p, w_curs, curpos, delta_size, delta_type);
 	if (error < GIT_SUCCESS) {
-		free(base.data);
+		git__free(base.data);
 		return git__rethrow(error, "Corrupted delta");
 	}
 
@@ -306,8 +308,8 @@
 			base.data, base.len,
 			delta.data, delta.len);
 
-	free(base.data);
-	free(delta.data);
+	git__free(base.data);
+	git__free(delta.data);
 
 	/* TODO: we might want to cache this shit. eventually */
 	//add_delta_base_cache(p, base_offset, base, base_size, *type);
@@ -390,7 +392,7 @@
 
 	st = inflateInit(&stream);
 	if (st != Z_OK) {
-		free(buffer);
+		git__free(buffer);
 		return git__throw(GIT_EZLIB, "Error in zlib");
 	}
 
@@ -408,7 +410,7 @@
 	inflateEnd(&stream);
 
 	if ((st != Z_STREAM_END) || stream.total_out != size) {
-		free(buffer);
+		git__free(buffer);
 		return git__throw(GIT_EZLIB, "Error in zlib");
 	}
 
@@ -504,8 +506,8 @@
 
 	pack_index_free(p);
 
-	free(p->bad_object_sha1);
-	free(p);
+	git__free(p->bad_object_sha1);
+	git__free(p);
 }
 
 static int packfile_open(struct git_pack_file *p)
@@ -598,7 +600,7 @@
 	 */
 	path_len -= strlen(".idx");
 	if (path_len < 1) {
-		free(p);
+		git__free(p);
 		return git__throw(GIT_ENOTFOUND, "Failed to check packfile. Wrong path name");
 	}
 
@@ -610,7 +612,7 @@
 
 	strcpy(p->pack_name + path_len, ".pack");
 	if (p_stat(p->pack_name, &st) < GIT_SUCCESS || !S_ISREG(st.st_mode)) {
-		free(p);
+		git__free(p);
 		return git__throw(GIT_ENOTFOUND, "Failed to check packfile. File not found");
 	}
 
diff --git a/src/pack.h b/src/pack.h
index 0fddd9d..aecf580 100644
--- a/src/pack.h
+++ b/src/pack.h
@@ -15,6 +15,8 @@
 #include "mwindow.h"
 #include "odb.h"
 
+#define GIT_PACK_FILE_MODE 0444
+
 #define PACK_SIGNATURE 0x5041434b	/* "PACK" */
 #define PACK_VERSION 2
 #define pack_version_ok(v) ((v) == htonl(2) || (v) == htonl(3))
diff --git a/src/path.c b/src/path.c
index 2c6b76d..a8851df 100644
--- a/src/path.c
+++ b/src/path.c
@@ -144,7 +144,7 @@
 		return NULL;
 
 	if (git_path_dirname_r(dname, len, path) < GIT_SUCCESS) {
-		free(dname);
+		git__free(dname);
 		return NULL;
 	}
 
@@ -162,7 +162,7 @@
 		return NULL;
 
 	if (git_path_basename_r(bname, len, path) < GIT_SUCCESS) {
-		free(bname);
+		git__free(bname);
 		return NULL;
 	}
 
diff --git a/src/pkt.c b/src/pkt.c
index 9471df2..ff8c56e 100644
--- a/src/pkt.c
+++ b/src/pkt.c
@@ -149,7 +149,7 @@
 
 out:
 	if (error < GIT_SUCCESS)
-		free(pkt);
+		git__free(pkt);
 	else
 		*out = (git_pkt *)pkt;
 
@@ -260,10 +260,10 @@
 {
 	if(pkt->type == GIT_PKT_REF) {
 		git_pkt_ref *p = (git_pkt_ref *) pkt;
-		free(p->head.name);
+		git__free(p->head.name);
 	}
 
-	free(pkt);
+	git__free(pkt);
 }
 
 int git_pkt_buffer_flush(git_buf *buf)
diff --git a/src/posix.c b/src/posix.c
index 1b85b05..8c19588 100644
--- a/src/posix.c
+++ b/src/posix.c
@@ -17,7 +17,7 @@
 	return open(path, flags | O_BINARY);
 }
 
-int p_creat(const char *path, int mode)
+int p_creat(const char *path, mode_t mode)
 {
 	return open(path, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, mode);
 }
@@ -39,6 +39,20 @@
 	return GIT_SUCCESS;
 }
 
+int p_rename(const char *from, const char *to)
+{
+	if (!link(from, to)) {
+		p_unlink(from);
+		return GIT_SUCCESS;
+	}
+
+	if (!rename(from, to))
+		return GIT_SUCCESS;
+
+	return GIT_ERROR;
+
+}
+
 #endif
 
 int p_read(git_file fd, void *buf, size_t cnt)
diff --git a/src/posix.h b/src/posix.h
index 59bec27..c12b413 100644
--- a/src/posix.h
+++ b/src/posix.h
@@ -40,10 +40,12 @@
 #define p_fstat(f,b) fstat(f, b)
 #define p_lseek(f,n,w) lseek(f, n, w)
 #define p_close(fd) close(fd)
+#define p_umask(m) umask(m)
 
 extern int p_open(const char *path, int flags);
-extern int p_creat(const char *path, int mode);
+extern int p_creat(const char *path, mode_t mode);
 extern int p_getcwd(char *buffer_out, size_t size);
+extern int p_rename(const char *from, const char *to);
 
 #ifndef GIT_WIN32
 
diff --git a/src/pqueue.c b/src/pqueue.c
index b5ddab8..80713fb 100644
--- a/src/pqueue.c
+++ b/src/pqueue.c
@@ -17,7 +17,7 @@
 	assert(q);
 
 	/* Need to allocate n+1 elements since element 0 isn't used. */
-	if ((q->d = malloc((n + 1) * sizeof(void *))) == NULL)
+	if ((q->d = git__malloc((n + 1) * sizeof(void *))) == NULL)
 		return GIT_ENOMEM;
 
 	q->size = 1;
@@ -30,7 +30,7 @@
 
 void git_pqueue_free(git_pqueue *q)
 {
-	free(q->d);
+	git__free(q->d);
 	q->d = NULL;
 }
 
@@ -102,7 +102,7 @@
 	/* allocate more memory if necessary */
 	if (q->size >= q->avail) {
 		newsize = q->size + q->step;
-		if ((tmp = realloc(q->d, sizeof(void *) * newsize)) == NULL)
+		if ((tmp = git__realloc(q->d, sizeof(void *) * newsize)) == NULL)
 			return GIT_ENOMEM;
 
 		q->d = tmp;
diff --git a/src/reflog.c b/src/reflog.c
index 594963c..e0fa7a0 100644
--- a/src/reflog.c
+++ b/src/reflog.c
@@ -25,8 +25,8 @@
 	log->ref_name = git__strdup(ref->name);
 
 	if (git_vector_init(&log->entries, 0, NULL) < 0) {
-		free(log->ref_name);
-		free(log);
+		git__free(log->ref_name);
+		git__free(log);
 		return GIT_ENOMEM;
 	}
 
@@ -71,7 +71,7 @@
 	}
 
 	git_filebuf_write(&fbuf, log.ptr, log.size);
-	error = git_filebuf_commit(&fbuf);
+	error = git_filebuf_commit(&fbuf, GIT_REFLOG_FILE_MODE);
 
 	git_buf_free(&log);
 	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write reflog");
@@ -86,8 +86,8 @@
 #define seek_forward(_increase) { \
 	if (_increase >= buf_size) { \
 		if (entry->committer) \
-			free(entry->committer); \
-		free(entry); \
+			git__free(entry->committer); \
+		git__free(entry); \
 		return git__throw(GIT_ERROR, "Failed to seek forward. Buffer size exceeded"); \
 	} \
 	buf += _increase; \
@@ -101,13 +101,13 @@
 		entry->committer = NULL;
 
 		if (git_oid_fromstrn(&entry->oid_old, buf, GIT_OID_HEXSZ) < GIT_SUCCESS) {
-			free(entry);
+			git__free(entry);
 			return GIT_ERROR;
 		}
 		seek_forward(GIT_OID_HEXSZ + 1);
 
 		if (git_oid_fromstrn(&entry->oid_cur, buf, GIT_OID_HEXSZ) < GIT_SUCCESS) {
-			free(entry);
+			git__free(entry);
 			return GIT_ERROR;
 		}
 		seek_forward(GIT_OID_HEXSZ + 1);
@@ -120,13 +120,13 @@
 
 		entry->committer = git__malloc(sizeof(git_signature));
 		if (entry->committer == NULL) {
-			free(entry);
+			git__free(entry);
 			return GIT_ENOMEM;
 		}
 
 		if ((error = git_signature__parse(entry->committer, &ptr, buf + 1, NULL, *buf)) < GIT_SUCCESS) {
-			free(entry->committer);
-			free(entry);
+			git__free(entry->committer);
+			git__free(entry);
 			return git__rethrow(error, "Failed to parse reflog. Could not parse signature");
 		}
 
@@ -164,13 +164,13 @@
 
 		git_signature_free(entry->committer);
 
-		free(entry->msg);
-		free(entry);
+		git__free(entry->msg);
+		git__free(entry);
 	}
 
 	git_vector_free(&reflog->entries);
-	free(reflog->ref_name);
-	free(reflog);
+	git__free(reflog->ref_name);
+	git__free(reflog);
 }
 
 int git_reflog_read(git_reflog **reflog, git_reference *ref)
@@ -215,23 +215,37 @@
 	const git_oid *oid;
 
 	if ((error = git_reference_resolve(&r, ref)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write reflog. Cannot resolve reference `%s`", ref->name);
+		return git__rethrow(error,
+			"Failed to write reflog. Cannot resolve reference `%s`", ref->name);
 
 	oid = git_reference_oid(r);
-	if (oid == NULL)
-		return git__throw(GIT_ERROR, "Failed to write reflog. Cannot resolve reference `%s`", r->name);
+	if (oid == NULL) {
+		git_reference_free(r);
+		return git__throw(GIT_ERROR,
+			"Failed to write reflog. Cannot resolve reference `%s`", r->name);
+	}
 
 	git_oid_to_string(new, GIT_OID_HEXSZ+1, oid);
 
-	git_path_join_n(log_path, 3, ref->owner->path_repository, GIT_REFLOG_DIR, ref->name);
+	git_path_join_n(log_path, 3,
+		ref->owner->path_repository, GIT_REFLOG_DIR, ref->name);
+
+	git_reference_free(r);
 
 	if (git_futils_exists(log_path)) {
-		if ((error = git_futils_mkpath2file(log_path)) < GIT_SUCCESS)
-			return git__rethrow(error, "Failed to write reflog. Cannot create reflog directory");
+		error = git_futils_mkpath2file(log_path, GIT_REFLOG_DIR_MODE);
+		if (error < GIT_SUCCESS)
+			return git__rethrow(error,
+				"Failed to write reflog. Cannot create reflog directory");
+
 	} else if (git_futils_isfile(log_path)) {
-		return git__throw(GIT_ERROR, "Failed to write reflog. `%s` is directory", log_path);
-	} else if (oid_old == NULL)
-		return git__throw(GIT_ERROR, "Failed to write reflog. Old OID cannot be NULL for existing reference");
+		return git__throw(GIT_ERROR,
+			"Failed to write reflog. `%s` is directory", log_path);
+
+	} else if (oid_old == NULL) {
+		return git__throw(GIT_ERROR,
+			"Failed to write reflog. Old OID cannot be NULL for existing reference");
+	}
 
 	if (oid_old)
 		git_oid_to_string(old, GIT_OID_HEXSZ+1, oid_old);
diff --git a/src/reflog.h b/src/reflog.h
index 093874e..44b0637 100644
--- a/src/reflog.h
+++ b/src/reflog.h
@@ -12,6 +12,8 @@
 #include "vector.h"
 
 #define GIT_REFLOG_DIR "logs/"
+#define GIT_REFLOG_DIR_MODE 0777
+#define GIT_REFLOG_FILE_MODE 0666
 
 #define GIT_REFLOG_SIZE_MIN (2*GIT_OID_HEXSZ+2+17)
 
diff --git a/src/refs.c b/src/refs.c
index fcf771b..569efbf 100644
--- a/src/refs.c
+++ b/src/refs.c
@@ -9,22 +9,24 @@
 #include "hash.h"
 #include "repository.h"
 #include "fileops.h"
+#include "pack.h"
 
 #include <git2/tag.h>
 #include <git2/object.h>
 
 #define MAX_NESTING_LEVEL 5
 
-typedef struct {
-	git_reference ref;
-	git_oid oid;
-	git_oid peel_target;
-} reference_oid;
+enum {
+	GIT_PACKREF_HAS_PEEL = 1,
+	GIT_PACKREF_WAS_LOOSE = 2
+};
 
-typedef struct {
-	git_reference ref;
-	char *target;
-} reference_symbolic;
+struct packref {
+	git_oid oid;
+	git_oid peel;
+	char flags;
+	char name[GIT_FLEX_ARRAY];
+};
 
 static const int default_table_size = 32;
 
@@ -39,97 +41,83 @@
 	return git__hash(key, strlen((const char *)key), hash_seeds[hash_id]);
 }
 
-static void reference_free(git_reference *reference);
-static int reference_create(git_reference **ref_out, git_repository *repo, const char *name, git_rtype type);
-static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated);
+static int reference_read(
+	git_fbuffer *file_content,
+	time_t *mtime,
+	const char *repo_path,
+	const char *ref_name,
+	int *updated);
 
 /* loose refs */
 static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content);
-static int loose_parse_oid(git_reference *ref, git_fbuffer *file_content);
-static int loose_lookup(git_reference **ref_out, git_repository *repo, const char *name, int skip_symbolic);
+static int loose_parse_oid(git_oid *ref, git_fbuffer *file_content);
+static int loose_lookup(git_reference *ref);
+static int loose_lookup_to_packfile(struct packref **ref_out,
+	git_repository *repo, const char *name);
 static int loose_write(git_reference *ref);
-static int loose_update(git_reference *ref);
 
 /* packed refs */
-static int packed_parse_peel(reference_oid *tag_ref, const char **buffer_out, const char *buffer_end);
-static int packed_parse_oid(reference_oid **ref_out, git_repository *repo, const char **buffer_out, const char *buffer_end);
+static int packed_parse_peel(struct packref *tag_ref,
+	const char **buffer_out, const char *buffer_end);
+static int packed_parse_oid(struct packref **ref_out,
+	const char **buffer_out, const char *buffer_end);
 static int packed_load(git_repository *repo);
 static int packed_loadloose(git_repository *repository);
-static int packed_write_ref(reference_oid *ref, git_filebuf *file);
-static int packed_find_peel(reference_oid *ref);
+static int packed_write_ref(struct packref *ref, git_filebuf *file);
+static int packed_find_peel(git_repository *repo, struct packref *ref);
 static int packed_remove_loose(git_repository *repo, git_vector *packing_list);
 static int packed_sort(const void *a, const void *b);
+static int packed_lookup(git_reference *ref);
 static int packed_write(git_repository *repo);
 
 /* internal helpers */
-static int reference_available(git_repository *repo, const char *ref, const char *old_ref);
+static int reference_available(git_repository *repo,
+	const char *ref, const char *old_ref);
+static int reference_delete(git_reference *ref);
+static int reference_lookup(git_reference *ref);
 
 /* name normalization */
-static int check_valid_ref_char(char ch);
-static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref);
+static int normalize_name(char *buffer_out, size_t out_size,
+	const char *name, int is_oid_ref);
 
-/*****************************************
- * Internal methods - Constructor/destructor
- *****************************************/
-static void reference_free(git_reference *reference)
+
+void git_reference_free(git_reference *reference)
 {
 	if (reference == NULL)
 		return;
 
-	if (reference->name)
-		free(reference->name);
+	git__free(reference->name);
 
-	if (reference->type == GIT_REF_SYMBOLIC)
-		free(((reference_symbolic *)reference)->target);
+	if (reference->flags & GIT_REF_SYMBOLIC)
+		git__free(reference->target.symbolic);
 
-	free(reference);
+	git__free(reference);
 }
 
 static int reference_create(
 	git_reference **ref_out,
 	git_repository *repo,
-	const char *name,
-	git_rtype type)
+	const char *name)
 {
-	char normalized[GIT_REFNAME_MAX];
-	int error = GIT_SUCCESS, size;
 	git_reference *reference = NULL;
 
 	assert(ref_out && repo && name);
 
-	if (type == GIT_REF_SYMBOLIC)
-		size = sizeof(reference_symbolic);
-	else if (type == GIT_REF_OID)
-		size = sizeof(reference_oid);
-	else
-		return git__throw(GIT_EINVALIDARGS,
-			"Invalid reference type. Use either GIT_REF_OID or GIT_REF_SYMBOLIC as type specifier");
-
-	reference = git__malloc(size);
+	reference = git__malloc(sizeof(git_reference));
 	if (reference == NULL)
 		return GIT_ENOMEM;
 
-	memset(reference, 0x0, size);
+	memset(reference, 0x0, sizeof(git_reference));
 	reference->owner = repo;
-	reference->type = type;
 
-	error = normalize_name(normalized, sizeof(normalized), name, (type & GIT_REF_OID));
-	if (error < GIT_SUCCESS)
-		goto cleanup;
-
-	reference->name = git__strdup(normalized);
+	reference->name = git__strdup(name);
 	if (reference->name == NULL) {
-		error = GIT_ENOMEM;
-		goto cleanup;
+		free(reference);
+		return GIT_ENOMEM;
 	}
 
 	*ref_out = reference;
-
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference");
-
-cleanup:
-	reference_free(reference);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference");
+	return GIT_SUCCESS;
 }
 
 static int reference_read(git_fbuffer *file_content, time_t *mtime, const char *repo_path, const char *ref_name, int *updated)
@@ -144,62 +132,13 @@
 	return git_futils_readbuffer_updated(file_content, path, mtime, updated);
 }
 
-
-
-
-/*****************************************
- * Internal methods - Loose references
- *****************************************/
-static int loose_update(git_reference *ref)
-{
-	int error, updated;
-	git_fbuffer ref_file = GIT_FBUFFER_INIT;
-
-	if (ref->type & GIT_REF_PACKED)
-		return packed_load(ref->owner);
-
-/*	error = reference_read(NULL, &ref_time, ref->owner->path_repository, ref->name);
-	if (error < GIT_SUCCESS)
-		goto cleanup;
-
-	if (ref_time == ref->mtime)
-		return GIT_SUCCESS;
-*/
-	error = reference_read(&ref_file, &ref->mtime, ref->owner->path_repository, ref->name, &updated);
-	if (error < GIT_SUCCESS)
-		goto cleanup;
-
-	if (!updated)
-		goto cleanup;
-
-	if (ref->type == GIT_REF_SYMBOLIC)
-		error = loose_parse_symbolic(ref, &ref_file);
-	else if (ref->type == GIT_REF_OID)
-		error = loose_parse_oid(ref, &ref_file);
-	else
-		error = git__throw(GIT_EOBJCORRUPTED,
-			"Invalid reference type (%d) for loose reference", ref->type);
-
-
-cleanup:
-	git_futils_freebuffer(&ref_file);
-	if (error != GIT_SUCCESS) {
-		reference_free(ref);
-		git_hashtable_remove(ref->owner->references.loose_cache, ref->name);
-	}
-
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to update loose reference");
-}
-
 static int loose_parse_symbolic(git_reference *ref, git_fbuffer *file_content)
 {
 	const unsigned int header_len = strlen(GIT_SYMREF);
 	const char *refname_start;
 	char *eol;
-	reference_symbolic *ref_sym;
 
 	refname_start = (const char *)file_content->data;
-	ref_sym = (reference_symbolic *)ref;
 
 	if (file_content->len < (header_len + 1))
 		return git__throw(GIT_EOBJCORRUPTED,
@@ -212,13 +151,12 @@
 
 	refname_start += header_len;
 
-	free(ref_sym->target);
-	ref_sym->target = git__strdup(refname_start);
-	if (ref_sym->target == NULL)
+	ref->target.symbolic = git__strdup(refname_start);
+	if (ref->target.symbolic == NULL)
 		return GIT_ENOMEM;
 
 	/* remove newline at the end of file */
-	eol = strchr(ref_sym->target, '\n');
+	eol = strchr(ref->target.symbolic, '\n');
 	if (eol == NULL)
 		return git__throw(GIT_EOBJCORRUPTED,
 			"Failed to parse loose reference. Missing EOL");
@@ -230,21 +168,19 @@
 	return GIT_SUCCESS;
 }
 
-static int loose_parse_oid(git_reference *ref, git_fbuffer *file_content)
+static int loose_parse_oid(git_oid *oid, git_fbuffer *file_content)
 {
 	int error;
-	reference_oid *ref_oid;
 	char *buffer;
 
 	buffer = (char *)file_content->data;
-	ref_oid = (reference_oid *)ref;
 
 	/* File format: 40 chars (OID) + newline */
 	if (file_content->len < GIT_OID_HEXSZ + 1)
 		return git__throw(GIT_EOBJCORRUPTED,
 			"Failed to parse loose reference. Reference too short");
 
-	if ((error = git_oid_fromstr(&ref_oid->oid, buffer)) < GIT_SUCCESS)
+	if ((error = git_oid_fromstr(oid, buffer)) < GIT_SUCCESS)
 		return git__rethrow(GIT_EOBJCORRUPTED, "Failed to parse loose reference.");
 
 	buffer = buffer + GIT_OID_HEXSZ;
@@ -258,7 +194,6 @@
 	return GIT_SUCCESS;
 }
 
-
 static git_rtype loose_guess_rtype(const char *full_path)
 {
 	git_fbuffer ref_file = GIT_FBUFFER_INIT;
@@ -277,52 +212,75 @@
 	return type;
 }
 
-static int loose_lookup(
-		git_reference **ref_out,
+static int loose_lookup(git_reference *ref)
+{
+	int error = GIT_SUCCESS, updated;
+	git_fbuffer ref_file = GIT_FBUFFER_INIT;
+
+	if (reference_read(&ref_file, &ref->mtime,
+			ref->owner->path_repository, ref->name, &updated) < GIT_SUCCESS)
+		return git__throw(GIT_ENOTFOUND, "Failed to lookup loose reference");
+
+	if (!updated)
+		return GIT_SUCCESS;
+
+	if (ref->flags & GIT_REF_SYMBOLIC)
+		free(ref->target.symbolic);
+
+	ref->flags = 0;
+
+	if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) {
+		ref->flags |= GIT_REF_SYMBOLIC;
+		error = loose_parse_symbolic(ref, &ref_file);
+	} else {
+		ref->flags |= GIT_REF_OID;
+		error = loose_parse_oid(&ref->target.oid, &ref_file);
+	}
+
+	git_futils_freebuffer(&ref_file);
+
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "Failed to lookup loose reference");
+
+	return GIT_SUCCESS;
+}
+
+static int loose_lookup_to_packfile(
+		struct packref **ref_out,
 		git_repository *repo,
-		const char *name,
-		int skip_symbolic)
+		const char *name)
 {
 	int error = GIT_SUCCESS;
 	git_fbuffer ref_file = GIT_FBUFFER_INIT;
-	git_reference *ref = NULL;
-	time_t ref_time = 0;
+	struct packref *ref = NULL;
+	size_t name_len;
 
 	*ref_out = NULL;
 
-	error = reference_read(&ref_file, &ref_time, repo->path_repository, name, NULL);
+	error = reference_read(&ref_file, NULL, repo->path_repository, name, NULL);
 	if (error < GIT_SUCCESS)
 		goto cleanup;
 
-	if (git__prefixcmp((const char *)(ref_file.data), GIT_SYMREF) == 0) {
-		if (skip_symbolic)
-			return GIT_SUCCESS;
+	name_len = strlen(name);
+	ref = git__malloc(sizeof(struct packref) + name_len + 1);
 
-		error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
+	memcpy(ref->name, name, name_len);
+	ref->name[name_len] = 0;
 
-		error = loose_parse_symbolic(ref, &ref_file);
-	} else {
-		error = reference_create(&ref, repo, name, GIT_REF_OID);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
-
-		error = loose_parse_oid(ref, &ref_file);
-	}
-
+	error = loose_parse_oid(&ref->oid, &ref_file);
 	if (error < GIT_SUCCESS)
 		goto cleanup;
 
-	ref->mtime = ref_time;
+	ref->flags = GIT_PACKREF_WAS_LOOSE;
+
 	*ref_out = ref;
 	git_futils_freebuffer(&ref_file);
 	return GIT_SUCCESS;
 
 cleanup:
 	git_futils_freebuffer(&ref_file);
-	reference_free(ref);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to lookup loose reference");
+	free(ref);
+	return git__rethrow(error, "Failed to lookup loose reference");
 }
 
 static int loose_write(git_reference *ref)
@@ -337,49 +295,36 @@
 	if ((error = git_filebuf_open(&file, ref_path, GIT_FILEBUF_FORCE)) < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to write loose reference");
 
-	if (ref->type & GIT_REF_OID) {
-		reference_oid *ref_oid = (reference_oid *)ref;
+	if (ref->flags & GIT_REF_OID) {
 		char oid[GIT_OID_HEXSZ + 1];
 
-		memset(oid, 0x0, sizeof(oid));
+		git_oid_fmt(oid, &ref->target.oid);
+		oid[GIT_OID_HEXSZ] = '\0';
 
-		git_oid_fmt(oid, &ref_oid->oid);
 		error = git_filebuf_printf(&file, "%s\n", oid);
 		if (error < GIT_SUCCESS)
 			goto unlock;
 
-	} else if (ref->type & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */
-		reference_symbolic *ref_sym = (reference_symbolic *)ref;
-
-		error = git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref_sym->target);
+	} else if (ref->flags & GIT_REF_SYMBOLIC) { /* GIT_REF_SYMBOLIC */
+		error = git_filebuf_printf(&file, GIT_SYMREF "%s\n", ref->target.symbolic);
 	} else {
-		error = git__throw(GIT_EOBJCORRUPTED, "Failed to write reference. Invalid reference type");
+		error = git__throw(GIT_EOBJCORRUPTED,
+			"Failed to write reference. Invalid reference type");
 		goto unlock;
 	}
 
-	error = git_filebuf_commit(&file);
-
 	if (p_stat(ref_path, &st) == GIT_SUCCESS)
 		ref->mtime = st.st_mtime;
 
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write loose reference");
+	return git_filebuf_commit(&file, GIT_REFS_FILE_MODE);
 
 unlock:
 	git_filebuf_cleanup(&file);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write loose reference");
+	return git__rethrow(error, "Failed to write loose reference");
 }
 
-
-
-
-
-
-/*****************************************
- * Internal methods - Packed references
- *****************************************/
-
 static int packed_parse_peel(
-		reference_oid *tag_ref,
+		struct packref *tag_ref,
 		const char **buffer_out,
 		const char *buffer_end)
 {
@@ -389,47 +334,48 @@
 
 	/* Ensure it's not the first entry of the file */
 	if (tag_ref == NULL)
-		return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Reference is the first entry of the file");
+		return git__throw(GIT_EPACKEDREFSCORRUPTED,
+			"Failed to parse packed reference. "
+			"Reference is the first entry of the file");
 
 	/* Ensure reference is a tag */
-	if (git__prefixcmp(tag_ref->ref.name, GIT_REFS_TAGS_DIR) != 0)
-		return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Reference is not a tag");
+	if (git__prefixcmp(tag_ref->name, GIT_REFS_TAGS_DIR) != 0)
+		return git__throw(GIT_EPACKEDREFSCORRUPTED,
+			"Failed to parse packed reference. Reference is not a tag");
 
 	if (buffer + GIT_OID_HEXSZ >= buffer_end)
-		return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Buffer too small");
+		return git__throw(GIT_EPACKEDREFSCORRUPTED,
+			"Failed to parse packed reference. Buffer too small");
 
 	/* Is this a valid object id? */
-	if (git_oid_fromstr(&tag_ref->peel_target, buffer) < GIT_SUCCESS)
-		return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Not a valid object ID");
+	if (git_oid_fromstr(&tag_ref->peel, buffer) < GIT_SUCCESS)
+		return git__throw(GIT_EPACKEDREFSCORRUPTED,
+			"Failed to parse packed reference. Not a valid object ID");
 
 	buffer = buffer + GIT_OID_HEXSZ;
 	if (*buffer == '\r')
 		buffer++;
 
 	if (*buffer != '\n')
-		return git__throw(GIT_EPACKEDREFSCORRUPTED, "Failed to parse packed reference. Buffer not terminated correctly");
+		return git__throw(GIT_EPACKEDREFSCORRUPTED,
+			"Failed to parse packed reference. Buffer not terminated correctly");
 
 	*buffer_out = buffer + 1;
-	tag_ref->ref.type |= GIT_REF_HAS_PEEL;
-
 	return GIT_SUCCESS;
 }
 
 static int packed_parse_oid(
-		reference_oid **ref_out,
-		git_repository *repo,
+		struct packref **ref_out,
 		const char **buffer_out,
 		const char *buffer_end)
 {
-	git_reference *_ref = NULL;
-	reference_oid *ref = NULL;
+	struct packref *ref = NULL;
 
 	const char *buffer = *buffer_out;
 	const char *refname_begin, *refname_end;
 
 	int error = GIT_SUCCESS;
-	int refname_len;
-	char refname[GIT_REFNAME_MAX];
+	size_t refname_len;
 	git_oid id;
 
 	refname_begin = (buffer + GIT_OID_HEXSZ + 1);
@@ -449,22 +395,19 @@
 		goto cleanup;
 	}
 
+	if (refname_end[-1] == '\r')
+		refname_end--;
+
 	refname_len = refname_end - refname_begin;
 
-	memcpy(refname, refname_begin, refname_len);
-	refname[refname_len] = 0;
+	ref = git__malloc(sizeof(struct packref) + refname_len + 1);
 
-	if (refname[refname_len - 1] == '\r')
-		refname[refname_len - 1] = 0;
-
-	error = reference_create(&_ref, repo, refname, GIT_REF_OID);
-	if (error < GIT_SUCCESS)
-		goto cleanup;
-
-	ref = (reference_oid *)_ref;
+	memcpy(ref->name, refname_begin, refname_len);
+	ref->name[refname_len] = 0;
 
 	git_oid_cpy(&ref->oid, &id);
-	ref->ref.type |= GIT_REF_PACKED;
+
+	ref->flags = 0;
 
 	*ref_out = ref;
 	*buffer_out = refname_end + 1;
@@ -472,8 +415,8 @@
 	return GIT_SUCCESS;
 
 cleanup:
-	reference_free((git_reference *)ref);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to parse OID of packed reference");
+	free(ref);
+	return git__rethrow(error, "Failed to parse OID of packed reference");
 }
 
 static int packed_load(git_repository *repo)
@@ -488,7 +431,7 @@
 		ref_cache->packfile = git_hashtable_alloc(
 			default_table_size,
 			reftable_hash,
-			(git_hash_keyeq_ptr)(&git__strcmp_cb));
+			(git_hash_keyeq_ptr)&git__strcmp_cb);
 
 		if (ref_cache->packfile == NULL) {
 			error = GIT_ENOMEM;
@@ -497,7 +440,7 @@
 	}
 
 	error = reference_read(&packfile, &ref_cache->packfile_time,
-							repo->path_repository, GIT_PACKEDREFS_FILE, &updated);
+		repo->path_repository, GIT_PACKEDREFS_FILE, &updated);
 
 	/*
 	 * If we couldn't find the file, we need to clear the table and
@@ -535,9 +478,9 @@
 	}
 
 	while (buffer_start < buffer_end) {
-		reference_oid *ref = NULL;
+		struct packref *ref = NULL;
 
-		error = packed_parse_oid(&ref, repo, &buffer_start, buffer_end);
+		error = packed_parse_oid(&ref, &buffer_start, buffer_end);
 		if (error < GIT_SUCCESS)
 			goto cleanup;
 
@@ -547,9 +490,9 @@
 				goto cleanup;
 		}
 
-		error = git_hashtable_insert(ref_cache->packfile, ref->ref.name, ref);
+		error = git_hashtable_insert(ref_cache->packfile, ref->name, ref);
 		if (error < GIT_SUCCESS) {
-			reference_free((git_reference *)ref);
+			free(ref);
 			goto cleanup;
 		}
 	}
@@ -561,12 +504,10 @@
 	git_hashtable_free(ref_cache->packfile);
 	ref_cache->packfile = NULL;
 	git_futils_freebuffer(&packfile);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to load packed references");
+	return git__rethrow(error, "Failed to load packed references");
 }
 
 
-
-
 struct dirent_list_data {
 	git_repository *repo;
 	size_t repo_path_len;
@@ -582,7 +523,8 @@
 	char *file_path = full_path + data->repo_path_len;
 
 	if (git_futils_isdir(full_path) == GIT_SUCCESS)
-		return git_futils_direach(full_path, GIT_PATH_MAX, _dirent_loose_listall, _data);
+		return git_futils_direach(full_path, GIT_PATH_MAX,
+			_dirent_loose_listall, _data);
 
 	/* do not add twice a reference that exists already in the packfile */
 	if ((data->list_flags & GIT_REF_PACKED) != 0 &&
@@ -600,29 +542,35 @@
 static int _dirent_loose_load(void *data, char *full_path)
 {
 	git_repository *repository = (git_repository *)data;
-	git_reference *reference;
 	void *old_ref = NULL;
+	struct packref *ref;
 	char *file_path;
 	int error;
 
 	if (git_futils_isdir(full_path) == GIT_SUCCESS)
-		return git_futils_direach(full_path, GIT_PATH_MAX, _dirent_loose_load, repository);
+		return git_futils_direach(
+			full_path, GIT_PATH_MAX,
+			_dirent_loose_load, repository);
 
 	file_path = full_path + strlen(repository->path_repository);
-	error = loose_lookup(&reference, repository, file_path, 1);
-	if (error == GIT_SUCCESS && reference != NULL) {
-		reference->type |= GIT_REF_PACKED;
+	error = loose_lookup_to_packfile(&ref, repository, file_path);
 
-		if (git_hashtable_insert2(repository->references.packfile, reference->name, reference, &old_ref) < GIT_SUCCESS) {
-			reference_free(reference);
+	if (error == GIT_SUCCESS) {
+
+		if (git_hashtable_insert2(
+			repository->references.packfile,
+			ref->name, ref, &old_ref) < GIT_SUCCESS) {
+			free(ref);
 			return GIT_ENOMEM;
 		}
 
 		if (old_ref != NULL)
-			reference_free((git_reference *)old_ref);
+			free(old_ref);
 	}
 
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to load loose dirent");
+	return error == GIT_SUCCESS ?
+		GIT_SUCCESS :
+		git__rethrow(error, "Failed to load loose references into packfile");
 }
 
 /*
@@ -640,30 +588,20 @@
 
 	git_path_join(refs_path, repository->path_repository, GIT_REFS_DIR);
 
-	/* Remove any loose references from the cache */
-	{
-		const void *GIT_UNUSED(_unused);
-		git_reference *reference;
-
-		GIT_HASHTABLE_FOREACH(repository->references.loose_cache, _unused, reference,
-			reference_free(reference);
-		);
-	}
-
-	git_hashtable_clear(repository->references.loose_cache);
-
 	/*
 	 * Load all the loose files from disk into the Packfile table.
 	 * This will overwrite any old packed entries with their
 	 * updated loose versions
 	 */
-	return git_futils_direach(refs_path, GIT_PATH_MAX, _dirent_loose_load, repository);
+	return git_futils_direach(
+		refs_path, GIT_PATH_MAX,
+		_dirent_loose_load, repository);
 }
 
 /*
  * Write a single reference into a packfile
  */
-static int packed_write_ref(reference_oid *ref, git_filebuf *file)
+static int packed_write_ref(struct packref *ref, git_filebuf *file)
 {
 	int error;
 	char oid[GIT_OID_HEXSZ + 1];
@@ -681,17 +619,19 @@
 	 * This obviously only applies to tags.
 	 * The required peels have already been loaded into `ref->peel_target`.
 	 */
-	if (ref->ref.type & GIT_REF_HAS_PEEL) {
+	if (ref->flags & GIT_PACKREF_HAS_PEEL) {
 		char peel[GIT_OID_HEXSZ + 1];
-		git_oid_fmt(peel, &ref->peel_target);
+		git_oid_fmt(peel, &ref->peel);
 		peel[GIT_OID_HEXSZ] = 0;
 
-		error = git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->ref.name, peel);
+		error = git_filebuf_printf(file, "%s %s\n^%s\n", oid, ref->name, peel);
 	} else {
-		error = git_filebuf_printf(file, "%s %s\n", oid, ref->ref.name);
+		error = git_filebuf_printf(file, "%s %s\n", oid, ref->name);
 	}
 
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write packed reference");
+	return error == GIT_SUCCESS ?
+		GIT_SUCCESS :
+		git__rethrow(error, "Failed to write packed reference");
 }
 
 /*
@@ -702,25 +642,25 @@
  * cache on the packfile the OID of the object to
  * which that 'big tag' is pointing to.
  */
-static int packed_find_peel(reference_oid *ref)
+static int packed_find_peel(git_repository *repo, struct packref *ref)
 {
 	git_object *object;
 	int error;
 
-	if (ref->ref.type & GIT_REF_HAS_PEEL)
+	if (ref->flags & GIT_PACKREF_HAS_PEEL)
 		return GIT_SUCCESS;
 
 	/*
 	 * Only applies to tags, i.e. references
 	 * in the /refs/tags folder
 	 */
-	if (git__prefixcmp(ref->ref.name, GIT_REFS_TAGS_DIR) != 0)
+	if (git__prefixcmp(ref->name, GIT_REFS_TAGS_DIR) != 0)
 		return GIT_SUCCESS;
 
 	/*
 	 * Find the tagged object in the repository
 	 */
-	error = git_object_lookup(&object, ref->ref.owner, &ref->oid, GIT_OBJ_ANY);
+	error = git_object_lookup(&object, repo, &ref->oid, GIT_OBJ_ANY);
 	if (error < GIT_SUCCESS)
 		return git__throw(GIT_EOBJCORRUPTED, "Failed to find packed reference");
 
@@ -735,8 +675,8 @@
 		/*
 		 * Find the object pointed at by this tag
 		 */
-		git_oid_cpy(&ref->peel_target, git_tag_target_oid(tag));
-		ref->ref.type |= GIT_REF_HAS_PEEL;
+		git_oid_cpy(&ref->peel, git_tag_target_oid(tag));
+		ref->flags |= GIT_PACKREF_HAS_PEEL;
 
 		/*
 		 * The reference has now cached the resolved OID, and is
@@ -746,7 +686,6 @@
 	}
 
 	git_object_close(object);
-
 	return GIT_SUCCESS;
 }
 
@@ -766,16 +705,11 @@
 	unsigned int i;
 	char full_path[GIT_PATH_MAX];
 	int error = GIT_SUCCESS;
-	git_reference *reference;
 
 	for (i = 0; i < packing_list->length; ++i) {
-		git_reference *ref = git_vector_get(packing_list, i);
+		struct packref *ref = git_vector_get(packing_list, i);
 
-		/* Ensure the packed reference doesn't exist
-		 * in a (more up-to-date?) state as a loose reference
-		 */
-		reference = git_hashtable_lookup(ref->owner->references.loose_cache, ref->name);
-		if (reference != NULL)
+		if ((ref->flags & GIT_PACKREF_WAS_LOOSE) == 0)
 			continue;
 
 		git_path_join(full_path, repo->path_repository, ref->name);
@@ -789,19 +723,18 @@
 		 * but we should keep going and remove as many as possible.
 		 * After we've removed as many files as possible, we return
 		 * the error code anyway.
-		 *
-		 * TODO: mark this with a very special error code?
-		 * GIT_EFAILTORMLOOSE
 		 */
 	}
 
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to remove loose packed reference");
+	return error == GIT_SUCCESS ?
+		GIT_SUCCESS :
+		git__rethrow(error, "Failed to remove loose packed reference");
 }
 
 static int packed_sort(const void *a, const void *b)
 {
-	const git_reference *ref_a = (const git_reference *)a;
-	const git_reference *ref_b = (const git_reference *)b;
+	const struct packref *ref_a = (const struct packref *)a;
+	const struct packref *ref_b = (const struct packref *)b;
 
 	return strcmp(ref_a->name, ref_b->name);
 }
@@ -822,16 +755,18 @@
 	assert(repo && repo->references.packfile);
 
 	total_refs = repo->references.packfile->key_count;
-	if ((error = git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write packed reference");
+	if ((error =
+		git_vector_init(&packing_list, total_refs, packed_sort)) < GIT_SUCCESS)
+		return git__rethrow(error, "Failed to init packed refernces list");
 
 	/* Load all the packfile into a vector */
 	{
-		git_reference *reference;
+		struct packref *reference;
 		const void *GIT_UNUSED(_unused);
 
 		GIT_HASHTABLE_FOREACH(repo->references.packfile, _unused, reference,
-			git_vector_insert(&packing_list, reference); /* cannot fail: vector already has the right size */
+			/* cannot fail: vector already has the right size */
+			git_vector_insert(&packing_list, reference);
 		);
 	}
 
@@ -841,27 +776,24 @@
 	/* Now we can open the file! */
 	git_path_join(pack_file_path, repo->path_repository, GIT_PACKEDREFS_FILE);
 	if ((error = git_filebuf_open(&pack_file, pack_file_path, 0)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write packed reference");
+		return git__rethrow(error, "Failed to write open packed references file");
 
 	/* Packfiles have a header... apparently
 	 * This is in fact not required, but we might as well print it
 	 * just for kicks */
-	if ((error = git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to write packed reference");
+	if ((error =
+		git_filebuf_printf(&pack_file, "%s\n", GIT_PACKEDREFS_HEADER)) < GIT_SUCCESS)
+		return git__rethrow(error, "Failed to write packed references file header");
 
 	for (i = 0; i < packing_list.length; ++i) {
-		reference_oid *ref = (reference_oid *)git_vector_get(&packing_list, i);
+		struct packref *ref = (struct packref *)git_vector_get(&packing_list, i);
 
-		/* only direct references go to the packfile; otherwise
-		 * this is a disaster */
-		assert(ref->ref.type & GIT_REF_OID);
-
-		if ((error = packed_find_peel(ref)) < GIT_SUCCESS) {
-			error = git__throw(GIT_EOBJCORRUPTED, "A reference cannot be peeled");
+		if ((error = packed_find_peel(repo, ref)) < GIT_SUCCESS) {
+			error = git__throw(GIT_EOBJCORRUPTED,
+				"A reference cannot be peeled");
 			goto cleanup;
 		}
 
-
 		if ((error = packed_write_ref(ref, &pack_file)) < GIT_SUCCESS)
 			goto cleanup;
 	}
@@ -870,7 +802,7 @@
 	/* if we've written all the references properly, we can commit
 	 * the packfile to make the changes effective */
 	if (error == GIT_SUCCESS) {
-		error = git_filebuf_commit(&pack_file);
+		error = git_filebuf_commit(&pack_file, GIT_PACKEDREFS_FILE_MODE);
 
 		/* when and only when the packfile has been properly written,
 		 * we can go ahead and remove the loose refs */
@@ -887,20 +819,22 @@
 
 	git_vector_free(&packing_list);
 
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to write packed reference");
+	return error == GIT_SUCCESS ?
+		GIT_SUCCESS :
+		git__rethrow(error, "Failed to write packed references file");
 }
 
 static int _reference_available_cb(const char *ref, void *data)
 {
 	const char *new, *old;
-	git_vector *refs;
+	const char **refs;
 
 	assert(ref && data);
 
-	refs = (git_vector *)data;
+	refs = (const char **)data;
 
-	new = (const char *)git_vector_get(refs, 0);
-	old = (const char *)git_vector_get(refs, 1);
+	new = (const char *)refs[0];
+	old = (const char *)refs[1];
 
 	if (!old || strcmp(old, ref)) {
 		int reflen = strlen(ref);
@@ -916,35 +850,168 @@
 	return GIT_SUCCESS;
 }
 
-static int reference_available(git_repository *repo, const char *ref, const char* old_ref)
+static int reference_available(
+	git_repository *repo,
+	const char *ref,
+	const char* old_ref)
 {
-	int error;
-	git_vector refs;
+	const char *refs[2];
 
-	if (git_vector_init(&refs, 2, NULL) < GIT_SUCCESS)
-		return GIT_ENOMEM;
+	refs[0] = ref;
+	refs[1] = old_ref;
 
-	git_vector_insert(&refs, (void *)ref);
-	git_vector_insert(&refs, (void *)old_ref);
+	if (git_reference_foreach(repo, GIT_REF_LISTALL,
+		_reference_available_cb, (void *)refs) < 0) {
+		return git__throw(GIT_EEXISTS,
+			"Reference name `%s` conflicts with existing reference", ref);
+	}
 
-	error = git_reference_foreach(repo, GIT_REF_LISTALL, _reference_available_cb, (void *)&refs);
-
-	git_vector_free(&refs);
-
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__throw(GIT_EEXISTS, "Reference name `%s` conflicts with existing reference", ref);
+	return GIT_SUCCESS;
 }
 
-/*****************************************
- * External Library API
- *****************************************/
+static int reference_exists(int *exists, git_repository *repo, const char *ref_name)
+{
+	int error;
+	char ref_path[GIT_PATH_MAX];
 
-/**
- * Constructors
+	error = packed_load(repo);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "Cannot resolve if a reference exists");
+
+	git_path_join(ref_path, repo->path_repository, ref_name);
+
+	if (git_futils_isfile(ref_path) == GIT_SUCCESS ||
+		git_hashtable_lookup(repo->references.packfile, ref_path) != NULL) {
+		*exists = 1;
+	} else {
+		*exists = 0;
+	}
+
+	return GIT_SUCCESS;
+}
+
+static int packed_lookup(git_reference *ref)
+{
+	int error;
+	struct packref *pack_ref = NULL;
+
+	error = packed_load(ref->owner);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error,
+			"Failed to lookup reference from packfile");
+
+	if (ref->flags & GIT_REF_PACKED &&
+		ref->mtime == ref->owner->references.packfile_time)
+		return GIT_SUCCESS;
+
+	if (ref->flags & GIT_REF_SYMBOLIC)
+		free(ref->target.symbolic);
+
+	/* Look up on the packfile */
+	pack_ref = git_hashtable_lookup(ref->owner->references.packfile, ref->name);
+	if (pack_ref == NULL)
+		return git__throw(GIT_ENOTFOUND,
+			"Failed to lookup reference from packfile");
+
+	ref->flags = GIT_REF_OID | GIT_REF_PACKED;
+	ref->mtime = ref->owner->references.packfile_time;
+	git_oid_cpy(&ref->target.oid, &pack_ref->oid);
+
+	return GIT_SUCCESS;
+}
+
+static int reference_lookup(git_reference *ref)
+{
+	int error_loose, error_packed;
+
+	error_loose = loose_lookup(ref);
+	if (error_loose == GIT_SUCCESS)
+		return GIT_SUCCESS;
+
+	error_packed = packed_lookup(ref);
+	if (error_packed == GIT_SUCCESS)
+		return GIT_SUCCESS;
+
+	git_reference_free(ref);
+
+	if (error_loose != GIT_ENOTFOUND)
+		return git__rethrow(error_loose, "Failed to lookup reference");
+
+	if (error_packed != GIT_ENOTFOUND)
+		return git__rethrow(error_packed, "Failed to lookup reference");
+
+	return git__throw(GIT_ENOTFOUND, "Reference not found");
+}
+
+/*
+ * Delete a reference.
+ * This is an internal method; the reference is removed
+ * from disk or the packfile, but the pointer is not freed
  */
-int git_reference_lookup(git_reference **ref_out, git_repository *repo, const char *name)
+static int reference_delete(git_reference *ref)
+{
+	int error;
+
+	assert(ref);
+
+	/* If the reference is packed, this is an expensive operation.
+	 * We need to reload the packfile, remove the reference from the
+	 * packing list, and repack */
+	if (ref->flags & GIT_REF_PACKED) {
+		/* load the existing packfile */
+		if ((error = packed_load(ref->owner)) < GIT_SUCCESS)
+			return git__rethrow(error, "Failed to delete reference");
+
+		if (git_hashtable_remove(ref->owner->references.packfile,
+				ref->name) < GIT_SUCCESS)
+			return git__throw(GIT_ENOTFOUND, "Reference not found");
+
+		error = packed_write(ref->owner);
+
+	/* If the reference is loose, we can just remove the reference
+	 * from the filesystem */
+	} else {
+		char full_path[GIT_PATH_MAX];
+		git_reference *ref_in_pack;
+
+		git_path_join(full_path, ref->owner->path_repository, ref->name);
+
+		error = p_unlink(full_path);
+		if (error < GIT_SUCCESS)
+			goto cleanup;
+
+		/* When deleting a loose reference, we have to ensure that an older
+		 * packed version of it doesn't exist */
+		if (git_reference_lookup(&ref_in_pack, ref->owner,
+				ref->name) == GIT_SUCCESS) {
+			assert((ref_in_pack->flags & GIT_REF_PACKED) != 0);
+			error = git_reference_delete(ref_in_pack);
+		}
+	}
+
+cleanup:
+	return error == GIT_SUCCESS ?
+		GIT_SUCCESS :
+		git__rethrow(error, "Failed to delete reference");
+}
+
+int git_reference_delete(git_reference *ref)
+{
+	int error = reference_delete(ref);
+	if (error < GIT_SUCCESS)
+		return error;
+
+	git_reference_free(ref);
+	return GIT_SUCCESS;
+}
+
+
+int git_reference_lookup(git_reference **ref_out,
+	git_repository *repo, const char *name)
 {
 	int error;
 	char normalized_name[GIT_REFNAME_MAX];
+	git_reference *ref = NULL;
 
 	assert(ref_out && repo && name);
 
@@ -954,39 +1021,16 @@
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to lookup reference");
 
-	/* First, check has been previously loaded and cached */
-	*ref_out = git_hashtable_lookup(repo->references.loose_cache, normalized_name);
-	if (*ref_out != NULL)
-		return loose_update(*ref_out);
-
-	/* Then check if there is a loose file for that reference.*/
-	error = loose_lookup(ref_out, repo, normalized_name, 0);
-
-	/* If the file exists, we store it on the cache */
-	if (error == GIT_SUCCESS)
-		return git_hashtable_insert(repo->references.loose_cache, (*ref_out)->name, (*ref_out));
-
-	/* The loose lookup has failed, but not because the reference wasn't found;
-	 * probably the loose reference is corrupted. this is bad. */
-	if (error != GIT_ENOTFOUND)
-		return git__rethrow(error, "Failed to lookup reference");
-
-	/*
-	 * If we cannot find a loose reference, we look into the packfile
-	 * Load the packfile first if it hasn't been loaded
-	 */
-	/* load all the packed references */
-	error = packed_load(repo);
+	error = reference_create(&ref, repo, normalized_name);
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to lookup reference");
 
-	/* Look up on the packfile */
-	*ref_out = git_hashtable_lookup(repo->references.packfile, normalized_name);
-	if (*ref_out != NULL)
-		return GIT_SUCCESS;
+	error = reference_lookup(ref);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "Failed to lookup reference");
 
-	/* The reference doesn't exist anywhere */
-	return git__throw(GIT_ENOTFOUND, "Failed to lookup reference. Reference doesn't exist");
+	*ref_out = ref;
+	return GIT_SUCCESS;
 }
 
 /**
@@ -996,15 +1040,21 @@
 {
 	assert(ref);
 
-	if (ref->type & GIT_REF_OID)
+	if (ref->flags & GIT_REF_OID)
 		return GIT_REF_OID;
 
-	if (ref->type & GIT_REF_SYMBOLIC)
+	if (ref->flags & GIT_REF_SYMBOLIC)
 		return GIT_REF_SYMBOLIC;
 
 	return GIT_REF_INVALID;
 }
 
+int git_reference_is_packed(git_reference *ref)
+{
+	assert(ref);
+	return !!(ref->flags & GIT_REF_PACKED);
+}
+
 const char *git_reference_name(git_reference *ref)
 {
 	assert(ref);
@@ -1021,219 +1071,154 @@
 {
 	assert(ref);
 
-	if ((ref->type & GIT_REF_OID) == 0)
+	if ((ref->flags & GIT_REF_OID) == 0)
 		return NULL;
 
-	if (loose_update(ref) < GIT_SUCCESS)
-		return NULL;
-
-	return &((reference_oid *)ref)->oid;
+	return &ref->target.oid;
 }
 
 const char *git_reference_target(git_reference *ref)
 {
 	assert(ref);
 
-	if ((ref->type & GIT_REF_SYMBOLIC) == 0)
+	if ((ref->flags & GIT_REF_SYMBOLIC) == 0)
 		return NULL;
 
-	if (loose_update(ref) < GIT_SUCCESS)
-		return NULL;
-
-	return ((reference_symbolic *)ref)->target;
+	return ref->target.symbolic;
 }
 
-int git_reference_create_symbolic(git_reference **ref_out, git_repository *repo, const char *name, const char *target, int force)
+int git_reference_create_symbolic(
+	git_reference **ref_out,
+	git_repository *repo,
+	const char *name,
+	const char *target,
+	int force)
 {
 	char normalized[GIT_REFNAME_MAX];
-	int error = GIT_SUCCESS, updated = 0;
+	int ref_exists, error = GIT_SUCCESS;
 	git_reference *ref = NULL;
-	void *old_ref = NULL;
 
-	if (git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
-		return git__throw(GIT_EEXISTS, "Failed to create symbolic reference. Reference already exists");
+	error = normalize_name(normalized, sizeof(normalized), name, 0);
+	if (error < GIT_SUCCESS)
+		goto cleanup;
 
-	/*
-	 * If they old ref was of the same type, then we can just update
-	 * it (once we've checked that the target is valid). Otherwise we
-	 * need a new reference because we can't make a symbolic ref out
-	 * of an oid one.
-	 * If if didn't exist, then we need to create a new one anyway.
-		*/
-	if (ref && ref->type & GIT_REF_SYMBOLIC){
-		updated = 1;
+	if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS))
+		return git__rethrow(error, "Failed to create symbolic reference");
+
+	if (ref_exists && !force)
+		return git__throw(GIT_EEXISTS,
+			"Failed to create symbolic reference. Reference already exists");
+
+	error = reference_create(&ref, repo, normalized);
+	if (error < GIT_SUCCESS)
+		goto cleanup;
+
+	ref->flags |= GIT_REF_SYMBOLIC;
+
+	/* set the target; this will normalize the name automatically
+	 * and write the reference on disk */
+	error = git_reference_set_target(ref, target);
+	if (error < GIT_SUCCESS)
+		goto cleanup;
+
+	if (ref_out == NULL) {
+		git_reference_free(ref);
 	} else {
-		ref = NULL;
-		error = reference_create(&ref, repo, name, GIT_REF_SYMBOLIC);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
+		*ref_out = ref;
 	}
 
-	/* The target can aither be the name of an object id reference or the name of another symbolic reference */
-	error = normalize_name(normalized, sizeof(normalized), target, 0);
-	if (error < GIT_SUCCESS)
-		goto cleanup;
-
-	/* set the target; this will write the reference on disk */
-	error = git_reference_set_target(ref, normalized);
-	if (error < GIT_SUCCESS)
-		goto cleanup;
-
-	/*
-	 * If we didn't update the ref, then we need to insert or replace
-	 * it in the loose cache. If we replaced a ref, free it.
-	 */
-	if (!updated){
-		error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, &old_ref);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
-
-		if (old_ref != NULL)
-			reference_free((git_reference *)old_ref);
-	}
-
-	*ref_out = ref;
-
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference");
+	return GIT_SUCCESS;
 
 cleanup:
-	reference_free(ref);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create symbolic reference");
+	git_reference_free(ref);
+	return git__rethrow(error, "Failed to create symbolic reference");
 }
 
-int git_reference_create_oid(git_reference **ref_out, git_repository *repo, const char *name, const git_oid *id, int force)
+int git_reference_create_oid(
+	git_reference **ref_out,
+	git_repository *repo,
+	const char *name,
+	const git_oid *id,
+	int force)
 {
-	int error = GIT_SUCCESS, updated = 0;
+	int error = GIT_SUCCESS, ref_exists;
 	git_reference *ref = NULL;
-	void *old_ref = NULL;
+	char normalized[GIT_REFNAME_MAX];
 
-	if(git_reference_lookup(&ref, repo, name) == GIT_SUCCESS && !force)
-		return git__throw(GIT_EEXISTS, "Failed to create reference OID. Reference already exists");
+	error = normalize_name(normalized, sizeof(normalized), name, 1);
+	if (error < GIT_SUCCESS)
+		goto cleanup;
+
+	if ((error = reference_exists(&ref_exists, repo, normalized) < GIT_SUCCESS))
+		return git__rethrow(error, "Failed to create OID reference");
+
+	if (ref_exists && !force)
+		return git__throw(GIT_EEXISTS,
+			"Failed to create OID reference. Reference already exists");
 
 	if ((error = reference_available(repo, name, NULL)) < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to create reference");
 
-	/*
-	 * If they old ref was of the same type, then we can just update
-	 * it (once we've checked that the target is valid). Otherwise we
-	 * need a new reference because we can't make a symbolic ref out
-	 * of an oid one.
-	 * If if didn't exist, then we need to create a new one anyway.
-		*/
-	if (ref && ref-> type & GIT_REF_OID){
-		updated = 1;
-	} else {
-		ref = NULL;
-		error = reference_create(&ref, repo, name, GIT_REF_OID);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
-	}
+	error = reference_create(&ref, repo, name);
+	if (error < GIT_SUCCESS)
+		goto cleanup;
+
+	ref->flags |= GIT_REF_OID;
 
 	/* set the oid; this will write the reference on disk */
 	error = git_reference_set_oid(ref, id);
 	if (error < GIT_SUCCESS)
 		goto cleanup;
 
-	if(!updated){
-		error = git_hashtable_insert2(repo->references.loose_cache, ref->name, ref, &old_ref);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
-
-		if (old_ref != NULL)
-			reference_free((git_reference *)old_ref);
+	if (ref_out == NULL) {
+		git_reference_free(ref);
+	} else {
+		*ref_out = ref;
 	}
 
-	*ref_out = ref;
-
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID");
+	return GIT_SUCCESS;
 
 cleanup:
-	reference_free(ref);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create reference OID");
+	git_reference_free(ref);
+	return git__rethrow(error, "Failed to create reference OID");
 }
 
-/**
- * Setters
- */
-
 /*
  * Change the OID target of a reference.
  *
- * For loose references, just change the oid in memory
- * and overwrite the file in disk.
+ * For both loose and packed references, just change
+ * the oid in memory and (over)write the file in disk.
  *
- * For packed files, this is not pretty:
- * For performance reasons, we write the new reference
- * loose on disk (it replaces the old on the packfile),
- * but we cannot invalidate the pointer to the reference,
- * and most importantly, the `packfile` object must stay
- * consistent with the representation of the packfile
- * on disk. This is what we need to:
- *
- * 1. Copy the reference
- * 2. Change the oid on the original
- * 3. Write the original to disk
- * 4. Write the original to the loose cache
- * 5. Replace the original with the copy (old reference) in the packfile cache
+ * We do not repack packed references because of performance
+ * reasons.
  */
 int git_reference_set_oid(git_reference *ref, const git_oid *id)
 {
-	reference_oid *ref_oid;
-	reference_oid *ref_old = NULL;
 	int error = GIT_SUCCESS;
 
-	if ((ref->type & GIT_REF_OID) == 0)
-		return git__throw(GIT_EINVALIDREFSTATE, "Failed to set OID target of reference. Not an OID reference");
-
-	ref_oid = (reference_oid *)ref;
+	if ((ref->flags & GIT_REF_OID) == 0)
+		return git__throw(GIT_EINVALIDREFSTATE,
+			"Failed to set OID target of reference. Not an OID reference");
 
 	assert(ref->owner);
 
 	/* Don't let the user create references to OIDs that
 	 * don't exist in the ODB */
 	if (!git_odb_exists(git_repository_database(ref->owner), id))
-		return git__throw(GIT_ENOTFOUND, "Failed to set OID target of reference. OID doesn't exist in ODB");
+		return git__throw(GIT_ENOTFOUND,
+			"Failed to set OID target of reference. OID doesn't exist in ODB");
 
-	/* duplicate the reference;
-	 * this copy will stay on the packfile cache */
-	if (ref->type & GIT_REF_PACKED) {
-		ref_old = git__malloc(sizeof(reference_oid));
-		if (ref_old == NULL)
-			return GIT_ENOMEM;
-
-		ref_old->ref.name = git__strdup(ref->name);
-		if (ref_old->ref.name == NULL) {
-			free(ref_old);
-			return GIT_ENOMEM;
-		}
-	}
-
-	git_oid_cpy(&ref_oid->oid, id);
-	ref->type &= ~GIT_REF_HAS_PEEL;
+	/* Update the OID value on `ref` */
+	git_oid_cpy(&ref->target.oid, id);
 
 	error = loose_write(ref);
 	if (error < GIT_SUCCESS)
 		goto cleanup;
 
-	if (ref->type & GIT_REF_PACKED) {
-		/* insert the original on the loose cache */
-		error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
-
-		ref->type &= ~GIT_REF_PACKED;
-
-		/* replace the original in the packfile with the copy */
-		error = git_hashtable_insert(ref->owner->references.packfile, ref_old->ref.name, ref_old);
-		if (error < GIT_SUCCESS)
-			goto cleanup;
-	}
-
 	return GIT_SUCCESS;
 
 cleanup:
-	reference_free((git_reference *)ref_old);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to set OID target of reference");
+	return git__rethrow(error, "Failed to set OID target of reference");
 }
 
 /*
@@ -1245,99 +1230,85 @@
  */
 int git_reference_set_target(git_reference *ref, const char *target)
 {
-	reference_symbolic *ref_sym;
+	int error;
+	char normalized[GIT_REFNAME_MAX];
 
-	if ((ref->type & GIT_REF_SYMBOLIC) == 0)
-		return git__throw(GIT_EINVALIDREFSTATE, "Failed to set reference target. Not a symbolic reference");
+	if ((ref->flags & GIT_REF_SYMBOLIC) == 0)
+		return git__throw(GIT_EINVALIDREFSTATE,
+			"Failed to set reference target. Not a symbolic reference");
 
-	ref_sym = (reference_symbolic *)ref;
+	error = normalize_name(normalized, sizeof(normalized), target, 0);
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error,
+			"Failed to set reference target. Invalid target name");
 
-	free(ref_sym->target);
-	ref_sym->target = git__strdup(target);
-	if (ref_sym->target == NULL)
+	git__free(ref->target.symbolic);
+	ref->target.symbolic = git__strdup(normalized);
+	if (ref->target.symbolic == NULL)
 		return GIT_ENOMEM;
 
 	return loose_write(ref);
 }
 
-/**
- * Other
- */
-
 int git_reference_rename(git_reference *ref, const char *new_name, int force)
 {
 	int error;
-	char *old_name = NULL;
 
 	char aux_path[GIT_PATH_MAX];
 	char normalized[GIT_REFNAME_MAX];
 
-	const char *target_ref = NULL;
 	const char *head_target = NULL;
-	const git_oid *target_oid = NULL;
-	git_reference *new_ref = NULL, *head = NULL;
+	git_reference *existing_ref = NULL, *head = NULL;
 
-	assert(ref);
+	error = normalize_name(normalized, sizeof(normalized),
+		new_name, ref->flags & GIT_REF_OID);
 
-	error = normalize_name(normalized, sizeof(normalized), new_name, ref->type & GIT_REF_OID);
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to rename reference. Invalid name");
 
 	new_name = normalized;
 
-	error = git_reference_lookup(&new_ref, ref->owner, new_name);
-	if (error == GIT_SUCCESS) {
-		if (!force)
-			return git__throw(GIT_EEXISTS, "Failed to rename reference. Reference already exists");
+	/* If we are forcing the rename, try to lookup a reference with the
+	 * new one. If the lookup succeeds, we need to delete that ref
+	 * before the renaming can proceed */
+	if (force) {
+		error = git_reference_lookup(&existing_ref, ref->owner, new_name);
 
-		error = git_reference_delete(new_ref);
-	}
-
-	if (error < GIT_SUCCESS) {
-		git_path_join(aux_path, ref->owner->path_repository, new_name);
-		/* If we couldn't read the reference because it doesn't
-		 * exist it's ok - otherwise return */
-		if (git_futils_isfile(aux_path) == GIT_SUCCESS)
+		if (error == GIT_SUCCESS) {
+			error = git_reference_delete(existing_ref);
+			if (error < GIT_SUCCESS)
+				return git__rethrow(error,
+					"Failed to rename reference. "
+					"The existing reference cannot be deleted");
+		} else if (error != GIT_ENOTFOUND)
 			goto cleanup;
+
+	/* If we're not forcing the rename, check if the reference exists.
+	 * If it does, renaming cannot continue */
+	} else {
+		int exists;
+
+		error = reference_exists(&exists, ref->owner, normalized);
+		if (error < GIT_SUCCESS)
+			goto cleanup;
+
+		if (exists)
+			return git__throw(GIT_EEXISTS,
+				"Failed to rename reference. Reference already exists");
 	}
 
 	if ((error = reference_available(ref->owner, new_name, ref->name)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to rename reference. Reference already exists");
-
-	/*
-	 * First, we backup the reference targets. Just keeping the old
-	 * reference won't work, since we may have to remove it to create
-	 * the new reference, e.g. when renaming foo/bar -> foo.
-	 */
-
-	old_name = git__strdup(ref->name);
-
-	if (ref->type & GIT_REF_SYMBOLIC) {
-		if ((target_ref = git_reference_target(ref)) == NULL)
-			goto cleanup;
-	} else {
-		if ((target_oid = git_reference_oid(ref)) == NULL)
-			goto cleanup;
-	}
+		return git__rethrow(error,
+			"Failed to rename reference. Reference already exists");
 
 	/*
 	 * Now delete the old ref and remove an possibly existing directory
-	 * named `new_name`.
+	 * named `new_name`. Note that using the internal `reference_delete`
+	 * method deletes the ref from disk but doesn't free the pointer, so
+	 * we can still access the ref's attributes for creating the new one
 	 */
-
-	if (ref->type & GIT_REF_PACKED) {
-		ref->type &= ~GIT_REF_PACKED;
-
-		git_hashtable_remove(ref->owner->references.packfile, old_name);
-		if ((error = packed_write(ref->owner)) < GIT_SUCCESS)
-			goto rollback;
-	} else {
-		git_path_join(aux_path, ref->owner->path_repository, old_name);
-		if ((error = p_unlink(aux_path)) < GIT_SUCCESS)
-			goto cleanup;
-
-		git_hashtable_remove(ref->owner->references.loose_cache, old_name);
-	}
+	if ((error = reference_delete(ref)) < GIT_SUCCESS)
+		goto cleanup;
 
 	git_path_join(aux_path, ref->owner->path_repository, new_name);
 	if (git_futils_exists(aux_path) == GIT_SUCCESS) {
@@ -1363,8 +1334,7 @@
 	 * TODO
 	 *
 	 */
-
-	git_path_join_n(aux_path, 3, ref->owner->path_repository, "logs", old_name);
+	git_path_join_n(aux_path, 3, ref->owner->path_repository, "logs", ref->name);
 	if (git_futils_isfile(aux_path) == GIT_SUCCESS) {
 		if ((error = p_unlink(aux_path)) < GIT_SUCCESS)
 			goto rollback;
@@ -1373,138 +1343,107 @@
 	/*
 	 * Finally we can create the new reference.
 	 */
-	if (ref->type & GIT_REF_SYMBOLIC) {
-		if ((error = git_reference_create_symbolic(&new_ref, ref->owner, new_name, target_ref, 0)) < GIT_SUCCESS)
-			goto rollback;
+	if (ref->flags & GIT_REF_SYMBOLIC) {
+		error = git_reference_create_symbolic(
+			NULL, ref->owner, new_name, ref->target.symbolic, 0);
 	} else {
-		if ((error = git_reference_create_oid(&new_ref, ref->owner, new_name, target_oid, 0)) < GIT_SUCCESS)
-			goto rollback;
+		error = git_reference_create_oid(
+			NULL, ref->owner, new_name, &ref->target.oid, 0);
 	}
 
-	free(ref->name);
-	ref->name = new_ref->name;
-
-	/*
-	 * No need in new_ref anymore. We created it to fix the change on disk.
-	 * TODO: Refactoring required.
-	 */
-	new_ref->name = NULL;
-	reference_free(new_ref);
-
-	if ((error = git_hashtable_insert(ref->owner->references.loose_cache, ref->name, ref)) < GIT_SUCCESS)
-		goto rollback;
+	if (error < GIT_SUCCESS)
+		goto cleanup;
 
 	/*
 	 * Check if we have to update HEAD.
 	 */
-
-	if ((error = git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE)) < GIT_SUCCESS)
+	error = git_reference_lookup(&head, ref->owner, GIT_HEAD_FILE);
+	if (error < GIT_SUCCESS)
 		goto cleanup;
 
 	head_target = git_reference_target(head);
 
-	if (head_target && !strcmp(head_target, old_name))
-		if ((error = git_reference_create_symbolic(&head, ref->owner, "HEAD", ref->name, 1)) < GIT_SUCCESS)
-			goto rollback;
+	if (head_target && !strcmp(head_target, ref->name)) {
+		error = git_reference_create_symbolic(
+			&head, ref->owner, "HEAD", new_name, 1);
+
+		if (error < GIT_SUCCESS)
+			goto cleanup;
+	}
+
+	/*
+	 * Change the name of the reference given by the user.
+	 */
+	git__free(ref->name);
+	ref->name = git__strdup(new_name);
+
+	/* The reference is no longer packed */
+	ref->flags &= ~GIT_REF_PACKED;
 
 cleanup:
-	free(old_name);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference");
+	/* We no longer need the newly created reference nor the head */
+	git_reference_free(head);
+	return error == GIT_SUCCESS ?
+		GIT_SUCCESS :
+		git__rethrow(error, "Failed to rename reference");
 
 rollback:
 	/*
 	 * Try to create the old reference again.
 	 */
-	if (ref->type & GIT_REF_SYMBOLIC)
-		error = git_reference_create_symbolic(&new_ref, ref->owner, old_name, target_ref, 0);
+	if (ref->flags & GIT_REF_SYMBOLIC)
+		error = git_reference_create_symbolic(
+			NULL, ref->owner, ref->name, ref->target.symbolic, 0);
 	else
-		error = git_reference_create_oid(&new_ref, ref->owner, old_name, target_oid, 0);
+		error = git_reference_create_oid(
+			NULL, ref->owner, ref->name, &ref->target.oid, 0);
 
-	ref->name = old_name;
-
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to rename reference. Failed to rollback");
+	return error == GIT_SUCCESS ?
+		git__rethrow(GIT_ERROR, "Failed to rename reference. Did rollback") :
+		git__rethrow(error, "Failed to rename reference. Failed to rollback");
 }
 
-/*
- * Delete a reference.
- *
- * If the reference is packed, this is an expensive
- * operation. We need to remove the reference from
- * the memory cache and then rewrite the whole pack
- *
- * If the reference is loose, we remove it on
- * the filesystem and update the in-memory cache
- * accordingly. We also make sure that an older version
- * of it doesn't exist as a packed reference. If this
- * is the case, this packed reference is removed as well.
- *
- * This obviously invalidates the `ref` pointer.
- */
-int git_reference_delete(git_reference *ref)
+int git_reference_resolve(git_reference **ref_out, git_reference *ref)
 {
-	int error;
-	git_reference *reference;
+	int error, i = 0;
+	git_repository *repo;
 
 	assert(ref);
 
-	if (ref->type & GIT_REF_PACKED) {
-		/* load the existing packfile */
-		if ((error = packed_load(ref->owner)) < GIT_SUCCESS)
-			return git__rethrow(error, "Failed to delete reference");
+	*ref_out = NULL;
+	repo = ref->owner;
 
-		if (git_hashtable_remove(ref->owner->references.packfile, ref->name) < GIT_SUCCESS)
-			return git__throw(GIT_ENOTFOUND, "Reference not found");
+	/* If the reference is already resolved, we need to return a
+	 * copy. Instead of duplicating `ref`, we look it up again to
+	 * ensure the copy is out to date */
+	if (ref->flags & GIT_REF_OID)
+		return git_reference_lookup(ref_out, ref->owner, ref->name);
 
-		error = packed_write(ref->owner);
-	} else {
-		char full_path[GIT_PATH_MAX];
-		git_path_join(full_path, ref->owner->path_repository, ref->name);
-		git_hashtable_remove(ref->owner->references.loose_cache, ref->name);
-		error = p_unlink(full_path);
+	/* Otherwise, keep iterating until the reference is resolved */
+	for (i = 0; i < MAX_NESTING_LEVEL; ++i) {
+		git_reference *new_ref;
+
+		error = git_reference_lookup(&new_ref, repo, ref->target.symbolic);
 		if (error < GIT_SUCCESS)
-			goto cleanup;
+			return git__rethrow(error, "Failed to resolve reference");
 
-		/* When deleting a loose reference, we have to ensure that an older
-		 * packed version of it doesn't exist
-		 */
-		if (!git_reference_lookup(&reference, ref->owner, ref->name)) {
-			assert((reference->type & GIT_REF_PACKED) != 0);
-			error = git_reference_delete(reference);
+		/* Free intermediate references, except for the original one
+		 * we've received */
+		if (i > 0)
+			git_reference_free(ref);
+
+		ref = new_ref;
+
+		/* When the reference we've just looked up is an OID, we've
+		 * successfully resolved the symbolic ref */
+		if (ref->flags & GIT_REF_OID) {
+			*ref_out = ref;
+			return GIT_SUCCESS;
 		}
 	}
 
-cleanup:
-	reference_free(ref);
-	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to delete reference");
-}
-
-int git_reference_resolve(git_reference **resolved_ref, git_reference *ref)
-{
-	git_repository *repo;
-	int error, i;
-
-	assert(resolved_ref && ref);
-	*resolved_ref = NULL;
-
-	if ((error = loose_update(ref)) < GIT_SUCCESS)
-		return git__rethrow(error, "Failed to resolve reference");
-
-	repo = ref->owner;
-
-	for (i = 0; i < MAX_NESTING_LEVEL; ++i) {
-		reference_symbolic *ref_sym;
-
-		*resolved_ref = ref;
-
-		if (ref->type & GIT_REF_OID)
-			return GIT_SUCCESS;
-
-		ref_sym = (reference_symbolic *)ref;
-		if ((error = git_reference_lookup(&ref, repo, ref_sym->target)) < GIT_SUCCESS)
-			return error;
-	}
-
-	return git__throw(GIT_ENOMEM, "Failed to resolve reference. Reference is too nested");
+	return git__throw(GIT_ENOMEM,
+		"Failed to resolve reference. Reference is too nested");
 }
 
 int git_reference_packall(git_repository *repo)
@@ -1523,7 +1462,11 @@
 	return packed_write(repo);
 }
 
-int git_reference_foreach(git_repository *repo, unsigned int list_flags, int (*callback)(const char *, void *), void *payload)
+int git_reference_foreach(
+	git_repository *repo,
+	unsigned int list_flags,
+	int (*callback)(const char *, void *),
+	void *payload)
 {
 	int error;
 	struct dirent_list_data data;
@@ -1539,7 +1482,8 @@
 
 		GIT_HASHTABLE_FOREACH(repo->references.packfile, ref_name, _unused,
 			if ((error = callback(ref_name, payload)) < GIT_SUCCESS)
-				return git__throw(error, "Failed to list references. User callback failed");
+				return git__throw(error,
+					"Failed to list references. User callback failed");
 		);
 	}
 
@@ -1552,7 +1496,6 @@
 	data.callback = callback;
 	data.callback_payload = payload;
 
-
 	git_path_join(refs_path, repo->path_repository, GIT_REFS_DIR);
 	return git_futils_direach(refs_path, GIT_PATH_MAX, _dirent_loose_listall, &data);
 }
@@ -1562,7 +1505,10 @@
 	return git_vector_insert((git_vector *)data, git__strdup(ref));
 }
 
-int git_reference_listall(git_strarray *array, git_repository *repo, unsigned int list_flags)
+int git_reference_listall(
+	git_strarray *array,
+	git_repository *repo,
+	unsigned int list_flags)
 {
 	int error;
 	git_vector ref_list;
@@ -1575,7 +1521,8 @@
 	if (git_vector_init(&ref_list, 8, NULL) < GIT_SUCCESS)
 		return GIT_ENOMEM;
 
-	error = git_reference_foreach(repo, list_flags, &cb__reflist_add, (void *)&ref_list);
+	error = git_reference_foreach(
+		repo, list_flags, &cb__reflist_add, (void *)&ref_list);
 
 	if (error < GIT_SUCCESS) {
 		git_vector_free(&ref_list);
@@ -1587,59 +1534,39 @@
 	return GIT_SUCCESS;
 }
 
-
-
-
-/*****************************************
- * Init/free (repository API)
- *****************************************/
-int git_repository__refcache_init(git_refcache *refs)
+int git_reference_reload(git_reference *ref)
 {
-	assert(refs);
+	int error = reference_lookup(ref);
 
-	refs->loose_cache = git_hashtable_alloc(
-		default_table_size,
-		reftable_hash,
-		(git_hash_keyeq_ptr)(&git__strcmp_cb));
+	if (error < GIT_SUCCESS) {
+		git_reference_free(ref);
+		return git__rethrow(error, "Failed to reload reference");
+	}
 
-	/* packfile loaded lazily */
-	refs->packfile = NULL;
-	refs->packfile_time = 0;
-
-	return (refs->loose_cache) ? GIT_SUCCESS : GIT_ENOMEM;
+	return GIT_SUCCESS;
 }
 
+
 void git_repository__refcache_free(git_refcache *refs)
 {
-	git_reference *reference;
-	const void *GIT_UNUSED(_unused);
-
 	assert(refs);
 
-	GIT_HASHTABLE_FOREACH(refs->loose_cache, _unused, reference,
-		reference_free(reference);
-	);
-
-	git_hashtable_free(refs->loose_cache);
-
 	if (refs->packfile) {
+		const void *GIT_UNUSED(_unused);
+		struct packref *reference;
+
 		GIT_HASHTABLE_FOREACH(refs->packfile, _unused, reference,
-			reference_free(reference);
+			free(reference);
 		);
 
 		git_hashtable_free(refs->packfile);
 	}
 }
 
-
-
-/*****************************************
- * Name normalization
- *****************************************/
-static int check_valid_ref_char(char ch)
+static int is_valid_ref_char(char ch)
 {
 	if ((unsigned) ch <= ' ')
-		return GIT_ERROR;
+		return 0;
 
 	switch (ch) {
 	case '~':
@@ -1649,13 +1576,17 @@
 	case '?':
 	case '[':
 	case '*':
-		return GIT_ERROR;
+		return 0;
 	default:
-		return GIT_SUCCESS;
+		return 1;
 	}
 }
 
-static int normalize_name(char *buffer_out, size_t out_size, const char *name, int is_oid_ref)
+static int normalize_name(
+	char *buffer_out,
+	size_t out_size,
+	const char *name,
+	int is_oid_ref)
 {
 	const char *name_end, *buffer_out_start;
 	const char *current;
@@ -1672,26 +1603,33 @@
 
 	/* A refname can not be empty */
 	if (name_end == name)
-		return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name is empty");
+		return git__throw(GIT_EINVALIDREFNAME,
+			"Failed to normalize name. Reference name is empty");
 
 	/* A refname can not end with a dot or a slash */
 	if (*(name_end - 1) == '.' || *(name_end - 1) == '/')
-		return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name ends with dot or slash");
+		return git__throw(GIT_EINVALIDREFNAME,
+			"Failed to normalize name. Reference name ends with dot or slash");
 
 	while (current < name_end && out_size) {
-		if (check_valid_ref_char(*current))
-			return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains invalid characters");
+		if (!is_valid_ref_char(*current))
+			return git__throw(GIT_EINVALIDREFNAME,
+				"Failed to normalize name. "
+				"Reference name contains invalid characters");
 
 		if (buffer_out > buffer_out_start) {
 			char prev = *(buffer_out - 1);
 
 			/* A refname can not start with a dot nor contain a double dot */
 			if (*current == '.' && ((prev == '.') || (prev == '/')))
-				return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name starts with a dot or contains a double dot");
+				return git__throw(GIT_EINVALIDREFNAME,
+					"Failed to normalize name. "
+					"Reference name starts with a dot or contains a double dot");
 
 			/* '@{' is forbidden within a refname */
 			if (*current == '{' && prev == '@')
-				return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains '@{'");
+				return git__throw(GIT_EINVALIDREFNAME,
+					"Failed to normalize name. Reference name contains '@{'");
 
 			/* Prevent multiple slashes from being added to the output */
 			if (*current == '/' && prev == '/') {
@@ -1713,13 +1651,18 @@
 	/* Object id refname have to contain at least one slash, except
 	 * for HEAD in a detached state or MERGE_HEAD if we're in the
 	 * middle of a merge */
-	if (is_oid_ref && !contains_a_slash && (strcmp(name, GIT_HEAD_FILE) && strcmp(name, GIT_MERGE_HEAD_FILE)
-	                                        && strcmp(name, GIT_FETCH_HEAD_FILE)))
-		return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name contains no slashes");
+	if (is_oid_ref &&
+		!contains_a_slash &&
+		strcmp(name, GIT_HEAD_FILE) != 0 &&
+		strcmp(name, GIT_MERGE_HEAD_FILE) != 0 &&
+		strcmp(name, GIT_FETCH_HEAD_FILE) != 0)
+		return git__throw(GIT_EINVALIDREFNAME,
+			"Failed to normalize name. Reference name contains no slashes");
 
 	/* A refname can not end with ".lock" */
 	if (!git__suffixcmp(name, GIT_FILELOCK_EXTENSION))
-		return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name ends with '.lock'");
+		return git__throw(GIT_EINVALIDREFNAME,
+			"Failed to normalize name. Reference name ends with '.lock'");
 
 	*buffer_out = '\0';
 
@@ -1729,17 +1672,25 @@
 	 */
 	if (is_oid_ref && !(git__prefixcmp(buffer_out_start, GIT_REFS_DIR) ||
 		strcmp(buffer_out_start, GIT_HEAD_FILE)))
-		return git__throw(GIT_EINVALIDREFNAME, "Failed to normalize name. Reference name does not start with 'refs/'");
+		return git__throw(GIT_EINVALIDREFNAME,
+			"Failed to normalize name. "
+			"Reference name does not start with 'refs/'");
 
 	return GIT_SUCCESS;
 }
 
-int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name)
+int git_reference__normalize_name(
+	char *buffer_out,
+	size_t out_size,
+	const char *name)
 {
 	return normalize_name(buffer_out, out_size, name, 0);
 }
 
-int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name)
+int git_reference__normalize_name_oid(
+	char *buffer_out,
+	size_t out_size,
+	const char *name)
 {
 	return normalize_name(buffer_out, out_size, name, 1);
 }
diff --git a/src/refs.h b/src/refs.h
index c4b0b0e..c90f5bc 100644
--- a/src/refs.h
+++ b/src/refs.h
@@ -16,12 +16,15 @@
 #define GIT_REFS_HEADS_DIR GIT_REFS_DIR "heads/"
 #define GIT_REFS_TAGS_DIR GIT_REFS_DIR "tags/"
 #define GIT_REFS_REMOTES_DIR GIT_REFS_DIR "remotes/"
+#define GIT_REFS_DIR_MODE 0777
+#define GIT_REFS_FILE_MODE 0666
 
 #define GIT_RENAMED_REF_FILE GIT_REFS_DIR "RENAMED-REF"
 
 #define GIT_SYMREF "ref: "
 #define GIT_PACKEDREFS_FILE "packed-refs"
 #define GIT_PACKEDREFS_HEADER "# pack-refs with: peeled "
+#define GIT_PACKEDREFS_FILE_MODE 0666
 
 #define GIT_HEAD_FILE "HEAD"
 #define GIT_FETCH_HEAD_FILE "FETCH_HEAD"
@@ -31,21 +34,23 @@
 #define GIT_REFNAME_MAX 1024
 
 struct git_reference {
+	unsigned int flags;
 	git_repository *owner;
 	char *name;
-	unsigned int type;
 	time_t mtime;
+
+	union {
+		git_oid oid;
+		char *symbolic;
+	} target;
 };
 
 typedef struct {
 	git_hashtable *packfile;
-	git_hashtable *loose_cache;
 	time_t packfile_time;
 } git_refcache;
 
-
 void git_repository__refcache_free(git_refcache *refs);
-int git_repository__refcache_init(git_refcache *refs);
 
 int git_reference__normalize_name(char *buffer_out, size_t out_size, const char *name);
 int git_reference__normalize_name_oid(char *buffer_out, size_t out_size, const char *name);
diff --git a/src/refspec.c b/src/refspec.c
index ed4b5e6..e60e8f5 100644
--- a/src/refspec.c
+++ b/src/refspec.c
@@ -32,7 +32,7 @@
 
 	refspec->dst = git__strdup(delim + 1);
 	if (refspec->dst == NULL) {
-		free(refspec->src);
+		git__free(refspec->src);
 		refspec->src = NULL;
 		return GIT_ENOMEM;
 	}
diff --git a/src/remote.c b/src/remote.c
index 10303b4..51e77e5 100644
--- a/src/remote.c
+++ b/src/remote.c
@@ -37,7 +37,7 @@
 
 	refspec->dst = git__strdup(delim + 1);
 	if (refspec->dst == NULL) {
-		free(refspec->src);
+		git__free(refspec->src);
 		refspec->src = NULL;
 		return GIT_ENOMEM;
 	}
@@ -69,7 +69,7 @@
 	remote->repo = repo;
 	remote->url = git__strdup(url);
 	if (remote->url == NULL) {
-		free(remote);
+		git__free(remote);
 		return GIT_ENOMEM;
 	}
 
@@ -151,7 +151,7 @@
 	*out = remote;
 
 cleanup:
-	free(buf);
+	git__free(buf);
 	if (error < GIT_SUCCESS)
 		git_remote_free(remote);
 
@@ -261,17 +261,17 @@
 	if (remote == NULL)
 		return;
 
-	free(remote->fetch.src);
-	free(remote->fetch.dst);
-	free(remote->push.src);
-	free(remote->push.dst);
-	free(remote->url);
-	free(remote->name);
+	git__free(remote->fetch.src);
+	git__free(remote->fetch.dst);
+	git__free(remote->push.src);
+	git__free(remote->push.dst);
+	git__free(remote->url);
+	git__free(remote->name);
 	if (remote->transport != NULL) {
 		if (remote->transport->connected)
 			remote->transport->close(remote->transport);
 
 		remote->transport->free(remote->transport);
 	}
-	free(remote);
+	git__free(remote);
 }
diff --git a/src/repository.c b/src/repository.c
index 328bc0d..f8195e2 100644
--- a/src/repository.c
+++ b/src/repository.c
@@ -168,12 +168,7 @@
 
 	error = git_cache_init(&repo->objects, GIT_DEFAULT_CACHE_SIZE, &git_object__free);
 	if (error < GIT_SUCCESS) {
-		free(repo);
-		return NULL;
-	}
-
-	if (git_repository__refcache_init(&repo->references) < GIT_SUCCESS) {
-		free(repo);
+		git__free(repo);
 		return NULL;
 	}
 
@@ -467,13 +462,13 @@
 
 static void git_repository__free_dirs(git_repository *repo)
 {
-	free(repo->path_workdir);
+	git__free(repo->path_workdir);
 	repo->path_workdir = NULL;
-	free(repo->path_index);
+	git__free(repo->path_index);
 	repo->path_index = NULL;
-	free(repo->path_repository);
+	git__free(repo->path_repository);
 	repo->path_repository = NULL;
-	free(repo->path_odb);
+	git__free(repo->path_odb);
 	repo->path_odb = NULL;
 }
 
@@ -489,7 +484,7 @@
 	if (repo->db != NULL)
 		git_odb_close(repo->db);
 
-	free(repo);
+	git__free(repo);
 }
 
 int git_repository_discover(char *repository_path, size_t size, const char *start_path, int across_fs, const char *ceiling_dirs)
@@ -603,18 +598,23 @@
 
 static int repo_init_createhead(git_repository *repo)
 {
+	int error;
 	git_reference *head_reference;
-	return git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0);
+
+	error = git_reference_create_symbolic(&head_reference, repo, GIT_HEAD_FILE, GIT_REFS_HEADS_MASTER_FILE, 0);
+
+	git_reference_free(head_reference);
+
+	return error;
 }
 
 static int repo_init_structure(const char *git_dir, int is_bare)
 {
-	const int mode = 0755; /* or 0777 ? */
 	int error;
 
 	char temp_path[GIT_PATH_MAX];
 
-	if (git_futils_mkdir_r(git_dir, mode))
+	if (git_futils_mkdir_r(git_dir, is_bare ? GIT_BARE_DIR_MODE : GIT_DIR_MODE))
 		return git__throw(GIT_ERROR, "Failed to initialize repository structure. Could not mkdir");
 
 	/* Hides the ".git" directory */
@@ -628,25 +628,25 @@
 
 	/* Creates the '/objects/info/' directory */
 	git_path_join(temp_path, git_dir, GIT_OBJECTS_INFO_DIR);
-	error = git_futils_mkdir_r(temp_path, mode);
+	error = git_futils_mkdir_r(temp_path, GIT_OBJECT_DIR_MODE);
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to initialize repository structure");
 
 	/* Creates the '/objects/pack/' directory */
 	git_path_join(temp_path, git_dir, GIT_OBJECTS_PACK_DIR);
-	error = p_mkdir(temp_path, mode);
+	error = p_mkdir(temp_path, GIT_OBJECT_DIR_MODE);
 	if (error < GIT_SUCCESS)
 		return git__throw(error, "Unable to create `%s` folder", temp_path);
 
 	/* Creates the '/refs/heads/' directory */
 	git_path_join(temp_path, git_dir, GIT_REFS_HEADS_DIR);
-	error = git_futils_mkdir_r(temp_path, mode);
+	error = git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE);
 	if (error < GIT_SUCCESS)
 		return git__rethrow(error, "Failed to initialize repository structure");
 
 	/* Creates the '/refs/tags/' directory */
 	git_path_join(temp_path, git_dir, GIT_REFS_TAGS_DIR);
-	error = p_mkdir(temp_path, mode);
+	error = p_mkdir(temp_path, GIT_REFS_DIR_MODE);
 	if (error < GIT_SUCCESS)
 		return git__throw(error, "Unable to create `%s` folder", temp_path);
 
@@ -716,10 +716,15 @@
 	if (error < GIT_SUCCESS)
 		return error;
 
-	if (git_reference_type(ref) == GIT_REF_SYMBOLIC)
+	if (git_reference_type(ref) == GIT_REF_SYMBOLIC) {
+		git_reference_free(ref);
 		return 0;
+	}
 
 	error = git_odb_read_header(&_size, &type, repo->db, git_reference_oid(ref));
+
+	git_reference_free(ref);
+
 	if (error < GIT_SUCCESS)
 		return error;
 
@@ -731,7 +736,7 @@
 
 int git_repository_head(git_reference **head_out, git_repository *repo)
 {
-	git_reference *ref;
+	git_reference *ref, *resolved_ref;
 	int error;
 
 	*head_out = NULL;
@@ -740,11 +745,15 @@
 	if (error < GIT_SUCCESS)
 		return git__rethrow(GIT_ENOTAREPO, "Failed to locate the HEAD");
 
-	error = git_reference_resolve(&ref, ref);
-	if (error < GIT_SUCCESS)
+	error = git_reference_resolve(&resolved_ref, ref);
+	if (error < GIT_SUCCESS) {
+		git_reference_free(ref);
 		return git__rethrow(error, "Failed to resolve the HEAD");
+	}
 
-	*head_out = ref;
+	git_reference_free(ref);
+
+	*head_out = resolved_ref;
 	return GIT_SUCCESS;
 }
 
@@ -755,25 +764,36 @@
 
 	error = git_repository_head(&ref, repo);
 
+	if (error == GIT_SUCCESS)
+		git_reference_free(ref);
+
 	return error == GIT_ENOTFOUND ? 1 : error;
 }
 
 int git_repository_is_empty(git_repository *repo)
 {
-	git_reference *head, *branch;
+	git_reference *head = NULL, *branch = NULL;
 	int error;
 
 	error = git_reference_lookup(&head, repo, "HEAD");
 	if (error < GIT_SUCCESS)
 		return git__throw(error, "Corrupted repository. HEAD does not exist");
 
-	if (git_reference_type(head) != GIT_REF_SYMBOLIC)
+	if (git_reference_type(head) != GIT_REF_SYMBOLIC) {
+		git_reference_free(head);
 		return 0;
+	}
 
-	if (strcmp(git_reference_target(head), "refs/heads/master") != 0)
+	if (strcmp(git_reference_target(head), "refs/heads/master") != 0) {
+		git_reference_free(head);
 		return 0;
+	}
 
 	error = git_reference_resolve(&branch, head);
+
+	git_reference_free(head);
+	git_reference_free(branch);
+
 	return error == GIT_ENOTFOUND ? 1 : error;
 }
 
diff --git a/src/repository.h b/src/repository.h
index 99217e5..0c17958 100644
--- a/src/repository.h
+++ b/src/repository.h
@@ -18,11 +18,12 @@
 #include "cache.h"
 #include "refs.h"
 #include "buffer.h"
+#include "odb.h"
 
 #define DOT_GIT ".git"
 #define GIT_DIR DOT_GIT "/"
-#define GIT_OBJECTS_DIR "objects/"
-#define GIT_INDEX_FILE "index"
+#define GIT_DIR_MODE 0755
+#define GIT_BARE_DIR_MODE 0777
 
 struct git_object {
 	git_cached_obj cached;
diff --git a/src/revwalk.c b/src/revwalk.c
index 2d70d40..7e31650 100644
--- a/src/revwalk.c
+++ b/src/revwalk.c
@@ -68,7 +68,7 @@
 	while (list) {
 		commit_list *temp = list;
 		list = temp->next;
-		free(temp);
+		git__free(temp);
 	}
 
 	*list_p = NULL;
@@ -81,7 +81,7 @@
 
 	if (top) {
 		*stack = top->next;
-		free(top);
+		git__free(top);
 	}
 	return item;
 }
@@ -156,7 +156,7 @@
 	git_oid_cpy(&commit->oid, oid);
 
 	if (git_hashtable_insert(walk->commits, &commit->oid, commit) < GIT_SUCCESS) {
-		free(commit);
+		git__free(commit);
 		return NULL;
 	}
 
@@ -442,7 +442,7 @@
 			(git_hash_keyeq_ptr)git_oid_cmp);
 
 	if (walk->commits == NULL) {
-		free(walk);
+		git__free(walk);
 		return GIT_ENOMEM;
 	}
 
@@ -475,17 +475,17 @@
 	 * make sure it's being free'd */
 	GIT_HASHTABLE_FOREACH(walk->commits, _unused, commit, {
 		if (commit->out_degree > PARENTS_PER_COMMIT)
-			free(commit->parents);
+			git__free(commit->parents);
 	});
 
 	git_hashtable_free(walk->commits);
 	git_pqueue_free(&walk->iterator_time);
 
 	for (i = 0; i < walk->memory_alloc.length; ++i)
-		free(git_vector_get(&walk->memory_alloc, i));
+		git__free(git_vector_get(&walk->memory_alloc, i));
 
 	git_vector_free(&walk->memory_alloc);
-	free(walk);
+	git__free(walk);
 }
 
 git_repository *git_revwalk_repository(git_revwalk *walk)
diff --git a/src/signature.c b/src/signature.c
index 388e8d9..832d643 100644
--- a/src/signature.c
+++ b/src/signature.c
@@ -15,9 +15,9 @@
 	if (sig == NULL)
 		return;
 
-	free(sig->name);
-	free(sig->email);
-	free(sig);
+	git__free(sig->name);
+	git__free(sig->email);
+	git__free(sig);
 }
 
 static const char *skip_leading_spaces(const char *buffer, const char *buffer_end)
diff --git a/src/status.c b/src/status.c
index 1deade9..d50199d 100644
--- a/src/status.c
+++ b/src/status.c
@@ -142,16 +142,14 @@
 	*tree_out = NULL;
 
 	error = git_repository_head(&resolved_head_ref, repo);
-	if (error != GIT_SUCCESS && error != GIT_ENOTFOUND)
-		return git__rethrow(error, "HEAD can't be resolved");
-
 	/*
 	 * We assume that a situation where HEAD exists but can not be resolved is valid.
 	 * A new repository fits this description for instance.
 	 */
-
 	if (error == GIT_ENOTFOUND)
 		return GIT_SUCCESS;
+	if (error < GIT_SUCCESS)
+		return git__rethrow(error, "HEAD can't be resolved");
 
 	if ((error = git_commit_lookup(&head_commit, repo, git_reference_oid(resolved_head_ref))) < GIT_SUCCESS)
 		return git__rethrow(error, "The tip of HEAD can't be retrieved");
@@ -168,41 +166,45 @@
 	return error;
 }
 
-#define GIT_STATUS_PATH_NULL	-2
-#define GIT_STATUS_PATH_IGNORE	-1
-#define GIT_STATUS_PATH_FILE	0
-#define GIT_STATUS_PATH_FOLDER	1
+enum path_type {
+	GIT_STATUS_PATH_NULL,
+	GIT_STATUS_PATH_IGNORE,
+	GIT_STATUS_PATH_FILE,
+	GIT_STATUS_PATH_FOLDER,
+};
 
 static int dirent_cb(void *state, char *full_path);
 static int alphasorted_futils_direach(
 	char *path, size_t path_sz,
 	int (*fn)(void *, char *), void *arg);
 
-static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, int path_type)
+static int process_folder(struct status_st *st, const git_tree_entry *tree_entry, char *full_path, enum path_type path_type)
 {
 	git_object *subtree = NULL;
 	git_tree *pushed_tree = NULL;
 	int error, pushed_tree_position = 0;
-	git_otype tree_entry_type;
+	git_otype tree_entry_type = GIT_OBJ_BAD;
 
-	tree_entry_type = git_tree_entry_type(tree_entry);
+	if (tree_entry != NULL) {
+		tree_entry_type = git_tree_entry_type(tree_entry);
 
-	switch (tree_entry_type) {
-	case GIT_OBJ_TREE:
-		error = git_tree_entry_2object(&subtree, ((git_object *)(st->tree))->repo, tree_entry);
-		pushed_tree = st->tree;
-		pushed_tree_position = st->tree_position;
-		st->tree = (git_tree *)subtree;
-		st->tree_position = 0;
-		st->head_tree_relative_path_len += 1 + tree_entry->filename_len; /* path + '/' + name */
-		break;
+		switch (tree_entry_type) {
+		case GIT_OBJ_TREE:
+			error = git_tree_entry_2object(&subtree, ((git_object *)(st->tree))->repo, tree_entry);
+			pushed_tree = st->tree;
+			pushed_tree_position = st->tree_position;
+			st->tree = (git_tree *)subtree;
+			st->tree_position = 0;
+			st->head_tree_relative_path_len += 1 + tree_entry->filename_len; /* path + '/' + name */
+			break;
 
-	case GIT_OBJ_BLOB:
-		/* No op */
-		break;
+		case GIT_OBJ_BLOB:
+			/* No op */
+			break;
 
-	default:
-		error = git__throw(GIT_EINVALIDTYPE, "Unexpected tree entry type");	/* TODO: How should we deal with submodules? */
+		default:
+			error = git__throw(GIT_EINVALIDTYPE, "Unexpected tree entry type");	/* TODO: How should we deal with submodules? */
+		}
 	}
 
 	if (full_path != NULL && path_type == GIT_STATUS_PATH_FOLDER)
@@ -229,7 +231,7 @@
 			return git__throw(error, "Failed to process the file '%s'. It doesn't exist in the workdir, in the HEAD nor in the index", e->path);
 
 	if (e->status_flags == GIT_STATUS_CURRENT) {
-		free(e);
+		git__free(e);
 		return GIT_SUCCESS;
 	}
 
@@ -242,7 +244,7 @@
 	const git_index_entry *index_entry,
 	char *full_path,
 	const char *status_path,
-	int path_type)
+	enum path_type path_type)
 {
 	struct status_entry *e;
 	int error = GIT_SUCCESS;
@@ -289,7 +291,7 @@
 	if (!is_dir)
 		return GIT_STATUS_PATH_FILE;
 
-	if (!git__suffixcmp(full_path, "/" DOT_GIT))
+	if (!git__suffixcmp(full_path, "/" DOT_GIT "/"))
 		return GIT_STATUS_PATH_IGNORE;
 
 	return GIT_STATUS_PATH_FOLDER;
@@ -324,30 +326,6 @@
 	return strcmp(left, right);
 }
 
-/*
- * Convenience method to enumerate a tree. Contrarily to the git_tree_entry_byindex()
- * method, it allows the tree to be enumerated to be NULL. In this case, every returned
- * tree entry will be NULL as well.
- */
-static const git_tree_entry *git_tree_entry_bypos(git_tree *tree, unsigned int idx)
-{
-	if (tree == NULL)
-		return NULL;
-
-	return git_vector_get(&tree->entries, idx);
-}
-
-/*
- * Convenience method to enumerate the index. This method is not supposed to be exposed
- * as part of the index API because it precludes that the index will not be altered
- * while the enumeration is being processed. Which wouldn't be very API friendly :)
- */
-static const git_index_entry *git_index_entry_bypos(git_index *index, unsigned int idx)
-{
-	assert(index);
-	return git_vector_get(&index->entries, idx);
-}
-
 /* Greatly inspired from JGit IndexTreeWalker */
 /* https://github.com/spearce/jgit/blob/ed47e29c777accfa78c6f50685a5df2b8f5b8ff5/org.spearce.jgit/src/org/spearce/jgit/lib/IndexTreeWalker.java#L88 */
 
@@ -355,7 +333,7 @@
 {
 	const git_tree_entry *m;
 	const git_index_entry *entry;
-	int path_type;
+	enum path_type path_type;
 	int cmpma, cmpmi, cmpai, error;
 	const char *pm, *pa, *pi;
 	const char *m_name, *i_name, *a_name;
@@ -370,15 +348,25 @@
 	a_name = (path_type != GIT_STATUS_PATH_NULL) ? a + st->workdir_path_len : NULL;
 
 	while (1) {
-		m = git_tree_entry_bypos(st->tree, st->tree_position);
-		entry = git_index_entry_bypos(st->index, st->index_position);
+		if (st->tree == NULL)
+			m = NULL;
+		else
+			m = git_tree_entry_byindex(st->tree, st->tree_position);
+
+		entry = git_index_get(st->index, st->index_position);
 
 		if ((m == NULL) && (a == NULL) && (entry == NULL))
 			return GIT_SUCCESS;
 
 		if (m != NULL) {
 			st->head_tree_relative_path[st->head_tree_relative_path_len] = '\0';
-			git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename);
+
+			/* When the tree entry is a folder, append a forward slash to its name */
+			if (git_tree_entry_type(m) == GIT_OBJ_TREE)
+				git_path_join_n(st->head_tree_relative_path, 3, st->head_tree_relative_path, m->filename, "");
+			else
+				git_path_join(st->head_tree_relative_path, st->head_tree_relative_path, m->filename);
+		
 			m_name = st->head_tree_relative_path;
 		} else
 			m_name = NULL;
@@ -396,7 +384,7 @@
 		if((error = determine_status(st, pm != NULL, pi != NULL, pa != NULL, m, entry, a, status_path(pm, pi, pa), path_type)) < GIT_SUCCESS)
 			return git__rethrow(error, "An error occured while determining the status of '%s'", a);
 
-		if (pa != NULL)
+		if ((pa != NULL) || (path_type == GIT_STATUS_PATH_FOLDER))
 			return GIT_SUCCESS;
 	}
 }
@@ -466,7 +454,7 @@
 				error = git__rethrow(error, "Failed to determine statuses. User callback failed");
 		}
 
-		free(e);
+		git__free(e);
 	}
 
 exit:
@@ -570,7 +558,7 @@
 
 exit:
 	git_tree_close(tree);
-	free(e);
+	git__free(e);
 	return error;
 }
 
@@ -589,19 +577,32 @@
 
 static struct alphasorted_dirent_info *alphasorted_dirent_info_new(const char *path)
 {
-	int is_dir;
+	int is_dir, size;
 	struct alphasorted_dirent_info *di;
 
 	is_dir = git_futils_isdir(path) == GIT_SUCCESS ? 1 : 0;
+	size = sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 2;
 
-	di = git__malloc(sizeof(*di) + (is_dir ? GIT_PATH_MAX : strlen(path)) + 1);
+	di = git__malloc(size);
 	if (di == NULL)
 		return NULL;
 
-	memset(di, 0x0, sizeof(*di));
+	memset(di, 0x0, size);
 
 	strcpy(di->path, path);
-	di->is_dir = is_dir;
+
+	if (is_dir) {
+		di->is_dir = 1;
+
+		/* 
+		 * Append a forward slash to the name to force folders 
+		 * to be ordered in a similar way than in a tree
+		 *
+		 * The file "subdir" should appear before the file "subdir.txt"
+		 * The folder "subdir" should appear after the file "subdir.txt"
+		 */
+		di->path[strlen(path)] = '/';
+	}
 
 	return di;
 }
@@ -626,7 +627,7 @@
 		return GIT_ENOMEM;
 
 	if (git_vector_insert(entry_names, entry) < GIT_SUCCESS) {
-		free(entry);
+		git__free(entry);
 		return GIT_ENOMEM;
 	}
 
@@ -659,7 +660,7 @@
 			error = fn(arg, entry->path);
 		}
 
-		free(entry);
+		git__free(entry);
 	}
 
 	git_vector_free(&entry_names);
diff --git a/src/tag.c b/src/tag.c
index ba75104..7372e68 100644
--- a/src/tag.c
+++ b/src/tag.c
@@ -16,9 +16,9 @@
 void git_tag__free(git_tag *tag)
 {
 	git_signature_free(tag->tagger);
-	free(tag->message);
-	free(tag->tag_name);
-	free(tag);
+	git__free(tag->message);
+	git__free(tag->tag_name);
+	git__free(tag);
 }
 
 const git_oid *git_tag_id(git_tag *c)
@@ -153,6 +153,8 @@
 	git_reference *tag_ref;
 	int error;
 
+	*tag_reference_out = NULL;
+
 	git_path_join(ref_name_out, GIT_REFS_TAGS_DIR, tag_name);
 	error = git_reference_lookup(&tag_ref, repo, ref_name_out);
 	if (error < GIT_SUCCESS)
@@ -224,6 +226,7 @@
 			break;
 
 		default:
+			git_reference_free(new_ref);
 			return git__rethrow(error, "Failed to create tag");
 	}
 
@@ -232,6 +235,7 @@
 	if (new_ref != NULL) {
 		if (!allow_ref_overwrite) {
 			git_oid_cpy(oid, git_reference_oid(new_ref));
+			git_reference_free(new_ref);
 			return git__throw(GIT_EEXISTS, "Tag already exists");
 		} else {
 			should_update_ref = 1;
@@ -239,8 +243,10 @@
 	}
 
 	if (create_tag_annotation) {
-		if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS)
+		if ((error = write_tag_annotation(oid, repo, tag_name, target, tagger, message)) < GIT_SUCCESS) {
+			git_reference_free(new_ref);
 			return error;
+		}
 	} else
 		git_oid_cpy(oid, git_object_id(target));
 
@@ -249,6 +255,8 @@
 	else
 		error = git_reference_set_oid(new_ref, oid);
 
+	git_reference_free(new_ref);
+
 	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
 }
 
@@ -281,7 +289,7 @@
 	git_odb_stream *stream;
 	git_odb_object *target_obj;
 
-	git_reference *new_ref;
+	git_reference *new_ref = NULL;
 	char ref_name[GIT_REFNAME_MAX];
 
 	assert(oid && buffer);
@@ -309,6 +317,7 @@
 			break;
 
 		default:
+			git_reference_free(new_ref);
 			return git__rethrow(error, "Failed to create tag");
 	}
 
@@ -317,6 +326,7 @@
 	if (new_ref != NULL) {
 		if (!allow_ref_overwrite) {
 			git_oid_cpy(oid, git_reference_oid(new_ref));
+			git_reference_free(new_ref);
 			return git__throw(GIT_EEXISTS, "Tag already exists");
 		} else {
 			should_update_ref = 1;
@@ -324,25 +334,31 @@
 	}
 
 	/* write the buffer */
-	if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS)
+	if ((error = git_odb_open_wstream(&stream, repo->db, strlen(buffer), GIT_OBJ_TAG)) < GIT_SUCCESS) {
+		git_reference_free(new_ref);
 		return git__rethrow(error, "Failed to create tag");
+	}
 
 	stream->write(stream, buffer, strlen(buffer));
 
 	error = stream->finalize_write(oid, stream);
 	stream->free(stream);
 
-	if (error < GIT_SUCCESS)
+	if (error < GIT_SUCCESS) {
+		git_reference_free(new_ref);
 		return git__rethrow(error, "Failed to create tag");
+	}
 
 	if (!should_update_ref)
 		error = git_reference_create_oid(&new_ref, repo, ref_name, oid, 0);
 	else
 		error = git_reference_set_oid(new_ref, oid);
 
+	git_reference_free(new_ref);
+
 	git_signature_free(tag.tagger);
-	free(tag.tag_name);
-	free(tag.message);
+	git__free(tag.tag_name);
+	git__free(tag.message);
 
 	return error == GIT_SUCCESS ? GIT_SUCCESS : git__rethrow(error, "Failed to create tag");
 }
diff --git a/src/thread-utils.h b/src/thread-utils.h
index 3361ed8..c555479 100644
--- a/src/thread-utils.h
+++ b/src/thread-utils.h
@@ -7,7 +7,7 @@
 #ifndef INCLUDE_thread_utils_h__
 #define INCLUDE_thread_utils_h__
 
-
+#include "common.h"
 
 /* Common operations even if threading has been disabled */
 typedef struct {
diff --git a/src/transports/git.c b/src/transports/git.c
index 4898078..c201452 100644
--- a/src/transports/git.c
+++ b/src/transports/git.c
@@ -109,8 +109,8 @@
 	error = send_request(s, NULL, url);
 	t->socket = s;
 
-	free(host);
-	free(port);
+	git__free(host);
+	git__free(port);
 
 	if (error < GIT_SUCCESS && s > 0)
 		close(s);
@@ -357,11 +357,11 @@
 				gitno_consume(buf, line_end);
 
 				if (pkt->type == GIT_PKT_ACK) {
-					free(pkt);
+					git__free(pkt);
 					error = GIT_SUCCESS;
 					goto done;
 				} else if (pkt->type == GIT_PKT_NAK) {
-					free(pkt);
+					git__free(pkt);
 					break;
 				} else {
 					error = git__throw(GIT_ERROR, "Got unexpected pkt type");
@@ -424,12 +424,12 @@
 				return error;
 
 			if (pkt->type == GIT_PKT_PACK) {
-				free(pkt);
+				git__free(pkt);
 				return git_fetch__download_pack(out, buf->data, buf->offset, t->socket, repo);
 			}
 
 			/* For now we don't care about anything */
-			free(pkt);
+			git__free(pkt);
 			gitno_consume(buf, line_end);
 		}
 
@@ -475,9 +475,9 @@
 	}
 
 	git_vector_free(refs);
-	free(t->heads);
-	free(t->parent.url);
-	free(t);
+	git__free(t->heads);
+	git__free(t->parent.url);
+	git__free(t);
 }
 
 int git_transport_git(git_transport **out)
diff --git a/src/transports/http.c b/src/transports/http.c
index 680354b..66b6f25 100644
--- a/src/transports/http.c
+++ b/src/transports/http.c
@@ -15,6 +15,7 @@
 #include "buffer.h"
 #include "pkt.h"
 #include "refs.h"
+#include "pack.h"
 #include "fetch.h"
 #include "filebuf.h"
 #include "repository.h"
@@ -389,18 +390,18 @@
 		git_buf_consume(buf, line_end);
 
 		if (pkt->type == GIT_PKT_PACK) {
-			free(pkt);
+			git__free(pkt);
 			t->pack_ready = 1;
 			return 0;
 		}
 
 		if (pkt->type == GIT_PKT_NAK) {
-			free(pkt);
+			git__free(pkt);
 			return 0;
 		}
 
 		if (pkt->type != GIT_PKT_ACK) {
-			free(pkt);
+			git__free(pkt);
 			continue;
 		}
 
@@ -702,7 +703,7 @@
 	}
 
 	/* A bit dodgy, but we need to keep the pack at the temporary path */
-	error = git_filebuf_commit_at(&file, file.path_lock);
+	error = git_filebuf_commit_at(&file, file.path_lock, GIT_PACK_FILE_MODE);
 
 cleanup:
 	if (error < GIT_SUCCESS)
@@ -749,13 +750,13 @@
 	}
 	git_vector_free(common);
 	git_buf_free(&t->buf);
-	free(t->heads);
-	free(t->content_type);
-	free(t->host);
-	free(t->port);
-	free(t->service);
-	free(t->parent.url);
-	free(t);
+	git__free(t->heads);
+	git__free(t->content_type);
+	git__free(t->host);
+	git__free(t->port);
+	git__free(t->service);
+	git__free(t->parent.url);
+	git__free(t);
 }
 
 int git_transport_http(git_transport **out)
diff --git a/src/transports/local.c b/src/transports/local.c
index 3f47e9b..058ed7e 100644
--- a/src/transports/local.c
+++ b/src/transports/local.c
@@ -54,7 +54,7 @@
 {
 	const char peeled[] = "^{}";
 	git_remote_head *head;
-	git_reference *ref;
+	git_reference *ref, *resolved_ref;
 	git_object *obj = NULL;
 	int error = GIT_SUCCESS, peel_len, ret;
 
@@ -72,7 +72,7 @@
 	if (error < GIT_SUCCESS)
 		goto out;
 
-	error = git_reference_resolve(&ref, ref);
+	error = git_reference_resolve(&resolved_ref, ref);
 	if (error < GIT_SUCCESS)
 		goto out;
 
@@ -111,10 +111,13 @@
 		goto out;
 
  out:
+	git_reference_free(ref);
+	git_reference_free(resolved_ref);
+
 	git_object_close(obj);
 	if (error < GIT_SUCCESS) {
-		free(head->name);
-		free(head);
+		git__free(head->name);
+		git__free(head);
 	}
 	return error;
 }
@@ -190,16 +193,16 @@
 
 	if (t->refs != NULL) {
 		git_vector_foreach (vec, i, h) {
-			free(h->name);
-			free(h);
+			git__free(h->name);
+			git__free(h);
 		}
 		git_vector_free(vec);
-		free(vec);
+		git__free(vec);
 	}
 
 	git_repository_free(t->repo);
-	free(t->parent.url);
-	free(t);
+	git__free(t->parent.url);
+	git__free(t);
 }
 
 /**************
diff --git a/src/tree-cache.c b/src/tree-cache.c
index 5a32575..ea8b7bf 100644
--- a/src/tree-cache.c
+++ b/src/tree-cache.c
@@ -196,6 +196,6 @@
 	for (i = 0; i < tree->children_count; ++i)
 		git_tree_cache_free(tree->children[i]);
 
-	free(tree->children);
-	free(tree);
+	git__free(tree->children);
+	git__free(tree);
 }
diff --git a/src/tree.c b/src/tree.c
index 00aefc2..92ca5ab 100644
--- a/src/tree.c
+++ b/src/tree.c
@@ -15,6 +15,8 @@
 #define MAX_FILEMODE 0777777
 #define MAX_FILEMODE_BYTES 6
 
+#define ENTRY_IS_TREE(e) ((e)->attr & 040000)
+
 static int valid_attributes(const int attributes)
 {
 	return attributes >= 0 && attributes <= MAX_FILEMODE;
@@ -31,8 +33,8 @@
 	const git_tree_entry *entry_b = (const git_tree_entry *)(b);
 
 	return git_futils_cmp_path(
-		entry_a->filename, entry_a->filename_len, entry_a->attr & 040000,
-		entry_b->filename, entry_b->filename_len, entry_b->attr & 040000);
+		entry_a->filename, entry_a->filename_len, ENTRY_IS_TREE(entry_a),
+		entry_b->filename, entry_b->filename_len, ENTRY_IS_TREE(entry_b));
 }
 
 
@@ -128,12 +130,12 @@
 		git_tree_entry *e;
 		e = git_vector_get(&tree->entries, i);
 
-		free(e->filename);
-		free(e);
+		git__free(e->filename);
+		git__free(e);
 	}
 
 	git_vector_free(&tree->entries);
-	free(tree);
+	git__free(tree);
 }
 
 const git_oid *git_tree_id(git_tree *c)
@@ -376,7 +378,7 @@
 				last_comp = subdir;
 			}
 			error = append_entry(bld, last_comp, &sub_oid, S_IFDIR);
-			free(subdir);
+			git__free(subdir);
 			if (error < GIT_SUCCESS) {
 				error = git__rethrow(error, "Failed to insert dir");
 				goto cleanup;
@@ -439,7 +441,7 @@
 		source_entries = source->entries.length;
 
 	if (git_vector_init(&bld->entries, source_entries, entry_sort_cmp) < GIT_SUCCESS) {
-		free(bld);
+		git__free(bld);
 		return GIT_ENOMEM;
 	}
 
@@ -594,8 +596,8 @@
 
 	for (i = 0; i < bld->entries.length; ++i) {
 		git_tree_entry *e = bld->entries.contents[i];
-		free(e->filename);
-		free(e);
+		git__free(e->filename);
+		git__free(e);
 	}
 
 	git_vector_clear(&bld->entries);
@@ -605,10 +607,14 @@
 {
 	git_treebuilder_clear(bld);
 	git_vector_free(&bld->entries);
-	free(bld);
+	git__free(bld);
 }
 
-static int tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path, int offset)
+static int tree_frompath(
+	git_tree **parent_out,
+	git_tree *root,
+	const char *treeentry_path,
+	int offset)
 {
 	char *slash_pos = NULL;
 	const git_tree_entry* entry;
@@ -616,15 +622,21 @@
 	git_tree *subtree;
 
 	if (!*(treeentry_path + offset))
-		return git__rethrow(GIT_EINVALIDPATH, "Invalid relative path to a tree entry '%s'.", treeentry_path);
+		return git__rethrow(GIT_EINVALIDPATH,
+			"Invalid relative path to a tree entry '%s'.", treeentry_path);
 
 	slash_pos = (char *)strchr(treeentry_path + offset, '/');
 
 	if (slash_pos == NULL)
-		return git_tree_lookup(parent_out, root->object.repo, git_object_id((const git_object *)root));
+		return git_tree_lookup(
+			parent_out,
+			root->object.repo,
+			git_object_id((const git_object *)root)
+		);
 
 	if (slash_pos == treeentry_path + offset)
-		return git__rethrow(GIT_EINVALIDPATH, "Invalid relative path to a tree entry '%s'.", treeentry_path);
+		return git__rethrow(GIT_EINVALIDPATH,
+			"Invalid relative path to a tree entry '%s'.", treeentry_path);
 
 	*slash_pos = '\0';
 
@@ -634,23 +646,95 @@
 		*slash_pos = '/';
 
 	if (entry == NULL)
-		return git__rethrow(GIT_ENOTFOUND, "No tree entry can be found from the given tree and relative path '%s'.", treeentry_path);
+		return git__rethrow(GIT_ENOTFOUND,
+			"No tree entry can be found from "
+			"the given tree and relative path '%s'.", treeentry_path);
 
-	if ((error = git_tree_lookup(&subtree, root->object.repo, &entry->oid)) < GIT_SUCCESS)
+
+	error = git_tree_lookup(&subtree, root->object.repo, &entry->oid);
+	if (error < GIT_SUCCESS)
 		return error;
 
-	error = tree_frompath(parent_out, subtree, treeentry_path, slash_pos - treeentry_path + 1);
+	error = tree_frompath(
+		parent_out,
+		subtree,
+		treeentry_path,
+		slash_pos - treeentry_path + 1
+	);
 
 	git_tree_close(subtree);
 	return error;
 }
 
-int git_tree_frompath(git_tree **parent_out, git_tree *root, const char *treeentry_path)
+int git_tree_get_subtree(
+	git_tree **subtree,
+	git_tree *root,
+	const char *subtree_path)
 {
 	char buffer[GIT_PATH_MAX];
 
-	assert(root && treeentry_path);
+	assert(subtree && root && subtree_path);
 
-	strcpy(buffer, treeentry_path);
-	return tree_frompath(parent_out, root, buffer, 0);
+	strncpy(buffer, subtree_path, GIT_PATH_MAX);
+	return tree_frompath(subtree, root, buffer, 0);
+}
+
+static int tree_walk_post(
+	git_tree *tree,
+	git_treewalk_cb callback,
+	char *root,
+	size_t root_len,
+	void *payload)
+{
+	int error;
+	unsigned int i;
+
+	for (i = 0; i < tree->entries.length; ++i) {
+		git_tree_entry *entry = tree->entries.contents[i];
+
+		root[root_len] = '\0';
+
+		if (callback(root, entry, payload) < 0)
+			continue;
+
+		if (ENTRY_IS_TREE(entry)) {
+			git_tree *subtree;
+
+			if ((error = git_tree_lookup(
+				&subtree, tree->object.repo, &entry->oid)) < 0)
+				return error;
+
+			strcpy(root + root_len, entry->filename);
+			root[root_len + entry->filename_len] = '/';
+
+			tree_walk_post(subtree,
+				callback, root,
+				root_len + entry->filename_len + 1,
+				payload
+			);
+
+			git_tree_close(subtree);
+		}
+	}
+
+	return GIT_SUCCESS;
+}
+
+int git_tree_walk(git_tree *tree, git_treewalk_cb callback, int mode, void *payload)
+{
+	char root_path[GIT_PATH_MAX];
+
+	root_path[0] = '\0';
+	switch (mode) {
+		case GIT_TREEWALK_POST:
+			return tree_walk_post(tree, callback, root_path, 0, payload);
+
+		case GIT_TREEWALK_PRE:
+			return git__throw(GIT_ENOTIMPLEMENTED,
+				"Preorder tree walking is still not implemented");
+
+		default:
+			return git__throw(GIT_EINVALIDARGS,
+				"Invalid walking mode for tree walk");
+	}
 }
diff --git a/src/tsort.c b/src/tsort.c
index 5dd99cc..df230b5 100644
--- a/src/tsort.c
+++ b/src/tsort.c
@@ -178,7 +178,7 @@
 static int resize(struct tsort_store *store, size_t new_size)
 {
 	if (store->alloc < new_size) {
-		void **tempstore = realloc(store->storage, new_size * sizeof(void *));
+		void **tempstore = git__realloc(store->storage, new_size * sizeof(void *));
 
 		/**
 		 * Do not propagate on OOM; this will abort the sort and
@@ -319,7 +319,7 @@
 			stack_curr--; \
 		} \
 		if (store->storage != NULL) {\
-			free(store->storage);\
+			git__free(store->storage);\
 			store->storage = NULL;\
 		}\
 		return;\
diff --git a/src/util.c b/src/util.c
index c81ed2d..b3af7ff 100644
--- a/src/util.c
+++ b/src/util.c
@@ -26,9 +26,9 @@
 {
 	size_t i;
 	for (i = 0; i < array->count; ++i)
-		free(array->strings[i]);
+		git__free(array->strings[i]);
 
-	free(array->strings);
+	git__free(array->strings);
 }
 
 int git__fnmatch(const char *pattern, const char *name, int flags)
diff --git a/src/util.h b/src/util.h
index 4de91b4..fbf9012 100644
--- a/src/util.h
+++ b/src/util.h
@@ -72,6 +72,8 @@
 	return new_ptr;
 }
 
+#define git__free(ptr) free(ptr)
+
 extern int git__prefixcmp(const char *str, const char *prefix);
 extern int git__suffixcmp(const char *str, const char *suffix);
 
diff --git a/src/vector.c b/src/vector.c
index 8b20bb8..123aae8 100644
--- a/src/vector.c
+++ b/src/vector.c
@@ -18,7 +18,7 @@
 	if (v->_alloc_size < minimum_size)
 		v->_alloc_size = minimum_size;
 
-	v->contents = realloc(v->contents, v->_alloc_size * sizeof(void *));
+	v->contents = git__realloc(v->contents, v->_alloc_size * sizeof(void *));
 	if (v->contents == NULL)
 		return GIT_ENOMEM;
 
@@ -29,7 +29,7 @@
 void git_vector_free(git_vector *v)
 {
 	assert(v);
-	free(v->contents);
+	git__free(v->contents);
 }
 
 int git_vector_init(git_vector *v, unsigned int initial_size, git_vector_cmp cmp)
diff --git a/src/win32/dir.c b/src/win32/dir.c
index ab50318..01aaaaa 100644
--- a/src/win32/dir.c
+++ b/src/win32/dir.c
@@ -6,7 +6,8 @@
  */
 #define GIT__WIN32_NO_WRAP_DIR
 #include "dir.h"
-#include "utf8-conv.h"
+#include "utf-conv.h"
+#include "git2/windows.h"
 
 static int init_filter(char *filter, size_t n, const char *dir)
 {
@@ -38,18 +39,18 @@
 
 	new->dir = git__malloc(strlen(dir)+1);
 	if (!new->dir) {
-		free(new);
+		git__free(new);
 		return NULL;
 	}
 	strcpy(new->dir, dir);
 
-	filter_w = conv_utf8_to_utf16(filter);
+	filter_w = gitwin_to_utf16(filter);
 	new->h = FindFirstFileW(filter_w, &new->f);
-	free(filter_w);
+	git__free(filter_w);
 
 	if (new->h == INVALID_HANDLE_VALUE) {
-		free(new->dir);
-		free(new);
+		git__free(new->dir);
+		git__free(new);
 		return NULL;
 	}
 	new->first = 1;
@@ -73,7 +74,7 @@
 		return NULL;
 
 	d->entry.d_ino = 0;
-	WideCharToMultiByte(CP_UTF8, 0, d->f.cFileName, -1, d->entry.d_name, GIT_PATH_MAX, NULL, NULL);
+	WideCharToMultiByte(gitwin_get_codepage(), 0, d->f.cFileName, -1, d->entry.d_name, GIT_PATH_MAX, NULL, NULL);
 
 	return &d->entry;
 }
@@ -90,9 +91,9 @@
 		d->first = 0;
 
 		if (init_filter(filter, sizeof(filter), d->dir)) {
-			filter_w = conv_utf8_to_utf16(filter);
+			filter_w = gitwin_to_utf16(filter);
 			d->h = FindFirstFileW(filter_w, &d->f);
-			free(filter_w);
+			git__free(filter_w);
 
 			if (d->h != INVALID_HANDLE_VALUE)
 				d->first = 1;
@@ -106,8 +107,8 @@
 		if (d->h != INVALID_HANDLE_VALUE)
 			FindClose(d->h);
 		if (d->dir)
-			free(d->dir);
-		free(d);
+			git__free(d->dir);
+		git__free(d);
 	}
 	return 0;
 }
diff --git a/src/win32/posix.h b/src/win32/posix.h
index 442717e..ae63236 100644
--- a/src/win32/posix.h
+++ b/src/win32/posix.h
@@ -9,7 +9,7 @@
 
 #include "common.h"
 #include "fnmatch.h"
-#include "utf8-conv.h"
+#include "utf-conv.h"
 
 GIT_INLINE(int) p_link(const char *GIT_UNUSED(old), const char *GIT_UNUSED(new))
 {
@@ -19,14 +19,14 @@
 	return -1;
 }
 
-GIT_INLINE(int) p_mkdir(const char *path, int GIT_UNUSED(mode))
+GIT_INLINE(int) p_mkdir(const char *path, mode_t GIT_UNUSED(mode))
 {
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 	int ret = _wmkdir(buf);
 
 	GIT_UNUSED_ARG(mode)
 
-	free(buf);
+	git__free(buf);
 	return ret;
 }
 
@@ -41,12 +41,13 @@
 extern int p_setenv(const char* name, const char* value, int overwrite);
 extern int p_stat(const char* path, struct stat* buf);
 extern int p_chdir(const char* path);
-extern int p_chmod(const char* path, int mode);
+extern int p_chmod(const char* path, mode_t mode);
 extern int p_rmdir(const char* path);
-extern int p_access(const char* path, int mode);
+extern int p_access(const char* path, mode_t mode);
 extern int p_fsync(int fd);
 extern int p_open(const char *path, int flags);
-extern int p_creat(const char *path, int mode);
+extern int p_creat(const char *path, mode_t mode);
 extern int p_getcwd(char *buffer_out, size_t size);
+extern int p_rename(const char *from, const char *to);
 
 #endif
diff --git a/src/win32/posix_w32.c b/src/win32/posix_w32.c
index cc17cc7..6f72258 100644
--- a/src/win32/posix_w32.c
+++ b/src/win32/posix_w32.c
@@ -6,7 +6,7 @@
  */
 #include "posix.h"
 #include "path.h"
-#include "utf8-conv.h"
+#include "utf-conv.h"
 #include <errno.h>
 #include <io.h>
 #include <fcntl.h>
@@ -17,10 +17,10 @@
 	int ret = 0;
 	wchar_t* buf;
 
-	buf = conv_utf8_to_utf16(path);
+	buf = gitwin_to_utf16(path);
 	_wchmod(buf, 0666);
 	ret = _wunlink(buf);
-	free(buf);
+	git__free(buf);
 
 	return ret;
 }
@@ -59,7 +59,7 @@
 static int do_lstat(const char *file_name, struct stat *buf)
 {
 	WIN32_FILE_ATTRIBUTE_DATA fdata;
-	wchar_t* fbuf = conv_utf8_to_utf16(file_name);
+	wchar_t* fbuf = gitwin_to_utf16(file_name);
 
 	if (GetFileAttributesExW(fbuf, GetFileExInfoStandard, &fdata)) {
 		int fMode = S_IREAD;
@@ -86,11 +86,11 @@
 		buf->st_mtime = filetime_to_time_t(&(fdata.ftLastWriteTime));
 		buf->st_ctime = filetime_to_time_t(&(fdata.ftCreationTime));
 
-		free(fbuf);
+		git__free(fbuf);
 		return GIT_SUCCESS;
 	}
 
-	free(fbuf);
+	git__free(fbuf);
 
 	switch (GetLastError()) {
 		case ERROR_ACCESS_DENIED:
@@ -161,7 +161,7 @@
 				"'GetFinalPathNameByHandleW' is not available in this platform");
 	}
 
-	link_w = conv_utf8_to_utf16(link);
+	link_w = gitwin_to_utf16(link);
 
 	hFile = CreateFileW(link_w,			// file to open
 			GENERIC_READ,			// open for reading
@@ -171,7 +171,7 @@
 			FILE_FLAG_BACKUP_SEMANTICS, // normal file
 			NULL);					// no attr. template
 
-	free(link_w);
+	git__free(link_w);
 
 	if (hFile == INVALID_HANDLE_VALUE)
 		return GIT_EOSERR;
@@ -184,17 +184,17 @@
 
 	dwRet = pGetFinalPath(hFile, target_w, target_len, 0x0);
 	if (dwRet >= target_len) {
-		free(target_w);
+		git__free(target_w);
 		CloseHandle(hFile);
 		return GIT_ENOMEM;
 	}
 
 	if (!WideCharToMultiByte(CP_UTF8, 0, target_w, -1, target, target_len * sizeof(char), NULL, NULL)) {
-		free(target_w);
+		git__free(target_w);
 		return GIT_EOSERR;
 	}
 
-	free(target_w);
+	git__free(target_w);
 	CloseHandle(hFile);
 
 	if (dwRet > 4) {
@@ -223,20 +223,20 @@
 int p_open(const char *path, int flags)
 {
 	int fd;
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 	fd = _wopen(buf, flags | _O_BINARY);
 
-	free(buf);
+	git__free(buf);
 	return fd;
 }
 
-int p_creat(const char *path, int mode)
+int p_creat(const char *path, mode_t mode)
 {
 	int fd;
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 	fd = _wopen(buf, _O_WRONLY | _O_CREAT | _O_TRUNC | _O_BINARY, mode);
 
-	free(buf);
+	git__free(buf);
 	return fd;
 }
 
@@ -246,11 +246,11 @@
 	_wgetcwd(buf, (int)size);
 
 	if (!WideCharToMultiByte(CP_UTF8, 0, buf, -1, buffer_out, size, NULL, NULL)) {
-		free(buf);
+		git__free(buf);
 		return GIT_EOSERR;
 	}
 
-	free(buf);
+	git__free(buf);
 	return GIT_SUCCESS;
 }
 
@@ -261,40 +261,40 @@
 
 int p_chdir(const char* path)
 {
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 	int ret = _wchdir(buf);
 
-	free(buf);
+	git__free(buf);
 	return ret;
 }
 
-int p_chmod(const char* path, int mode)
+int p_chmod(const char* path, mode_t mode)
 {
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 	int ret = _wchmod(buf, mode);
 
-	free(buf);
+	git__free(buf);
 	return ret;
 }
 
 int p_rmdir(const char* path)
 {
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 	int ret = _wrmdir(buf);
 
-	free(buf);
+	git__free(buf);
 	return ret;
 }
 
 int p_hide_directory__w32(const char *path)
 {
 	int error;
-	wchar_t* buf = conv_utf8_to_utf16(path);
+	wchar_t* buf = gitwin_to_utf16(path);
 
 	error = SetFileAttributesW(buf, FILE_ATTRIBUTE_HIDDEN) != 0 ?
 		GIT_SUCCESS : GIT_ERROR; /* MSDN states a "non zero" value indicates a success */
 
-	free(buf);
+	git__free(buf);
 
 	if (error < GIT_SUCCESS)
 		error = git__throw(GIT_EOSERR, "Failed to hide directory '%s'", path);
@@ -305,7 +305,7 @@
 char *p_realpath(const char *orig_path, char *buffer)
 {
 	int ret, alloc = 0;
-	wchar_t* orig_path_w = conv_utf8_to_utf16(orig_path);
+	wchar_t* orig_path_w = gitwin_to_utf16(orig_path);
 	wchar_t* buffer_w = (wchar_t*)git__malloc(GIT_PATH_MAX * sizeof(wchar_t));
 
 	if (buffer == NULL) {
@@ -314,21 +314,21 @@
 	}
 
 	ret = GetFullPathNameW(orig_path_w, GIT_PATH_MAX, buffer_w, NULL);
-	free(orig_path_w);
+	git__free(orig_path_w);
 
 	if (!ret || ret > GIT_PATH_MAX) {
-		free(buffer_w);
-		if (alloc) free(buffer);
+		git__free(buffer_w);
+		if (alloc) git__free(buffer);
 
 		return NULL;
 	}
 
 	if (!WideCharToMultiByte(CP_UTF8, 0, buffer_w, -1, buffer, GIT_PATH_MAX, NULL, NULL)) {
-		free(buffer_w);
-		if (alloc) free(buffer);
+		git__free(buffer_w);
+		if (alloc) git__free(buffer);
 	}
 	
-	free(buffer_w);
+	git__free(buffer_w);
 	git_path_mkposix(buffer);
 	return buffer;
 }
@@ -355,7 +355,7 @@
 	return r;
 }
 
-extern int p_creat(const char *path, int mode);
+extern int p_creat(const char *path, mode_t mode);
 
 int p_mkstemp(char *tmp_path)
 {
@@ -378,13 +378,27 @@
 	return (SetEnvironmentVariableA(name, value) == 0 ? GIT_EOSERR : GIT_SUCCESS);
 }
 
-int p_access(const char* path, int mode)
+int p_access(const char* path, mode_t mode)
 {
-	wchar_t *buf = conv_utf8_to_utf16(path);
+	wchar_t *buf = gitwin_to_utf16(path);
 	int ret;
 
 	ret = _waccess(buf, mode);
-	free(buf);
+	git__free(buf);
+
+	return ret;
+}
+
+extern int p_rename(const char *from, const char *to)
+{
+	wchar_t *wfrom = gitwin_to_utf16(from);
+	wchar_t *wto = gitwin_to_utf16(to);
+	int ret;
+
+	ret = MoveFileExW(wfrom, wto, MOVEFILE_REPLACE_EXISTING | MOVEFILE_COPY_ALLOWED) ? GIT_SUCCESS : GIT_EOSERR;
+
+	git__free(wfrom);
+	git__free(wto);
 
 	return ret;
 }
diff --git a/src/win32/utf-conv.c b/src/win32/utf-conv.c
new file mode 100644
index 0000000..b41c78f
--- /dev/null
+++ b/src/win32/utf-conv.c
@@ -0,0 +1,88 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include "common.h"
+#include "utf-conv.h"
+
+/*
+ * Default codepage value
+ */
+static int _active_codepage = CP_UTF8;
+
+void gitwin_set_codepage(unsigned int codepage)
+{
+	_active_codepage = codepage;
+}
+
+unsigned int gitwin_get_codepage(void)
+{
+	return _active_codepage;
+}
+
+void gitwin_set_utf8(void)
+{
+	_active_codepage = CP_UTF8;
+}
+
+wchar_t* gitwin_to_utf16(const char* str)
+{
+	wchar_t* ret;
+	int cb;
+
+	if (!str) {
+		return NULL;
+	}
+
+	cb = strlen(str) * sizeof(wchar_t);
+	if (cb == 0) {
+		ret = (wchar_t*)git__malloc(sizeof(wchar_t));
+		ret[0] = 0;
+		return ret;
+	}
+
+	/* Add space for null terminator */
+	cb += sizeof(wchar_t);
+
+	ret = (wchar_t*)git__malloc(cb);
+
+	if (MultiByteToWideChar(_active_codepage, 0, str, -1, ret, cb) == 0) {
+		git__free(ret);
+		ret = NULL;
+	}
+
+	return ret;
+}
+
+char* gitwin_from_utf16(const wchar_t* str)
+{
+	char* ret;
+	int cb;
+
+	if (!str) {
+		return NULL;
+	}
+
+	cb = wcslen(str) * sizeof(char);
+	if (cb == 0) {
+		ret = (char*)git__malloc(sizeof(char));
+		ret[0] = 0;
+		return ret;
+	}
+
+	/* Add space for null terminator */
+	cb += sizeof(char);
+
+	ret = (char*)git__malloc(cb);
+
+	if (WideCharToMultiByte(_active_codepage, 0, str, -1, ret, cb, NULL, NULL) == 0) {
+		git__free(ret);
+		ret = NULL;
+	}
+
+	return ret;
+
+}
diff --git a/src/win32/utf-conv.h b/src/win32/utf-conv.h
new file mode 100644
index 0000000..da03e33
--- /dev/null
+++ b/src/win32/utf-conv.h
@@ -0,0 +1,17 @@
+/*
+ * Copyright (C) 2009-2011 the libgit2 contributors
+ *
+ * This file is part of libgit2, distributed under the GNU GPL v2 with
+ * a Linking Exception. For full terms see the included COPYING file.
+ */
+
+#include <wchar.h>
+
+#ifndef INCLUDE_git_utfconv_h__
+#define INCLUDE_git_utfconv_h__
+
+wchar_t* gitwin_to_utf16(const char* str);
+char* gitwin_from_utf16(const wchar_t* str);
+
+#endif
+
diff --git a/src/win32/utf8-conv.c b/src/win32/utf8-conv.c
deleted file mode 100644
index dec6f8e..0000000
--- a/src/win32/utf8-conv.c
+++ /dev/null
@@ -1,68 +0,0 @@
-/*
- * Copyright (C) 2009-2011 the libgit2 contributors
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include "common.h"
-#include "utf8-conv.h"
-
-wchar_t* conv_utf8_to_utf16(const char* str)
-{
-	wchar_t* ret;
-	int cb;
-
-	if (!str) {
-		return NULL;
-	}
-
-	cb = strlen(str) * sizeof(wchar_t);
-	if (cb == 0) {
-		ret = (wchar_t*)git__malloc(sizeof(wchar_t));
-		ret[0] = 0;
-		return ret;
-	}
-
-	/* Add space for null terminator */
-	cb += sizeof(wchar_t);
-
-	ret = (wchar_t*)git__malloc(cb);
-
-	if (MultiByteToWideChar(CP_UTF8, 0, str, -1, ret, cb) == 0) {
-		free(ret);
-		ret = NULL;
-	}
-
-	return ret;
-}
-
-char* conv_utf16_to_utf8(const wchar_t* str)
-{
-	char* ret;
-	int cb;
-
-	if (!str) {
-		return NULL;
-	}
-
-	cb = wcslen(str) * sizeof(char);
-	if (cb == 0) {
-		ret = (char*)git__malloc(sizeof(char));
-		ret[0] = 0;
-		return ret;
-	}
-
-	/* Add space for null terminator */
-	cb += sizeof(char);
-
-	ret = (char*)git__malloc(cb);
-
-	if (WideCharToMultiByte(CP_UTF8, 0, str, -1, ret, cb, NULL, NULL) == 0) {
-		free(ret);
-		ret = NULL;
-	}
-
-	return ret;
-
-}
diff --git a/src/win32/utf8-conv.h b/src/win32/utf8-conv.h
deleted file mode 100644
index 1967ac3..0000000
--- a/src/win32/utf8-conv.h
+++ /dev/null
@@ -1,17 +0,0 @@
-/*
- * Copyright (C) 2009-2011 the libgit2 contributors
- *
- * This file is part of libgit2, distributed under the GNU GPL v2 with
- * a Linking Exception. For full terms see the included COPYING file.
- */
-
-#include <wchar.h>
-
-#ifndef INCLUDE_git_utf8conv_h__
-#define INCLUDE_git_utf8conv_h__
-
-wchar_t* conv_utf8_to_utf16(const char* str);
-char* conv_utf16_to_utf8(const wchar_t* str);
-
-#endif
-
diff --git a/tests-clay/README.md b/tests-clay/README.md
index 4939f57..6b5a659 100644
--- a/tests-clay/README.md
+++ b/tests-clay/README.md
@@ -11,7 +11,7 @@
 
 * Mix the tests:
 
-        ./clay
+        ./clay -vtap .
 
 * Make sure you actually build the tests by setting:
 
diff --git a/tests-clay/clay b/tests-clay/clay
index d042a2a..a40f660 100755
--- a/tests-clay/clay
+++ b/tests-clay/clay
@@ -4,13 +4,13 @@
 from string import Template
 import re, fnmatch, os
 
-VERSION = "0.8.0"
+VERSION = "0.9.0"
 
-TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*(void)?\s*\))\s*\{"
+TEST_FUNC_REGEX = r"^(void\s+(test_%s__(\w+))\(\s*void\s*\))\s*\{"
 
 CLAY_HEADER = """
 /*
- * Clay v0.7.0
+ * Clay v0.9.0
  *
  * This is an autogenerated file. Do not modify.
  * To add new unit tests or suites, regenerate the whole
@@ -18,7 +18,81 @@
  */
 """
 
-TEMPLATE_SUITE = Template(
+def main():
+    from optparse import OptionParser
+
+    parser = OptionParser()
+
+    parser.add_option('-c', '--clay-path', dest='clay_path')
+    parser.add_option('-v', '--report-to', dest='print_mode', default='default')
+
+    options, args = parser.parse_args()
+
+    for folder in args or ['.']:
+        builder = ClayTestBuilder(folder,
+            clay_path = options.clay_path,
+            print_mode = options.print_mode)
+
+        builder.render()
+
+
+class ClayTestBuilder:
+    def __init__(self, path, clay_path = None, print_mode = 'default'):
+        self.declarations = []
+        self.suite_names = []
+        self.callback_data = {}
+        self.suite_data = {}
+
+        self.clay_path = os.path.abspath(clay_path) if clay_path else None
+
+        self.path = os.path.abspath(path)
+        self.modules = [
+            "clay_sandbox.c",
+            "clay_fixtures.c",
+            "clay_fs.c"
+        ]
+
+        self.modules.append("clay_print_%s.c" % print_mode)
+
+        print("Loading test suites...")
+
+        for root, dirs, files in os.walk(self.path):
+            module_root = root[len(self.path):]
+            module_root = [c for c in module_root.split(os.sep) if c]
+
+            tests_in_module = fnmatch.filter(files, "*.c")
+
+            for test_file in tests_in_module:
+                full_path = os.path.join(root, test_file)
+                test_name = "_".join(module_root + [test_file[:-2]])
+
+                with open(full_path) as f:
+                    self._process_test_file(test_name, f.read())
+
+        if not self.suite_data:
+            raise RuntimeError(
+                'No tests found under "%s"' % folder_name)
+
+    def render(self):
+        main_file = os.path.join(self.path, 'clay_main.c')
+        with open(main_file, "w") as out:
+            out.write(self._render_main())
+
+        header_file = os.path.join(self.path, 'clay.h')
+        with open(header_file, "w") as out:
+            out.write(self._render_header())
+
+        print ('Written Clay suite to "%s"' % self.path)
+
+    #####################################################
+    # Internal methods
+    #####################################################
+
+    def _render_cb(self, cb):
+        return '{"%s", &%s}' % (cb['short_name'], cb['symbol'])
+
+    def _render_suite(self, suite):
+        template = Template(
 r"""
     {
         "${clean_name}",
@@ -28,98 +102,74 @@
     }
 """)
 
-def main():
-    from optparse import OptionParser
+        callbacks = {}
+        for cb in ['initialize', 'cleanup']:
+            callbacks[cb] = (self._render_cb(suite[cb])
+                if suite[cb] else "{NULL, NULL}")
 
-    parser = OptionParser()
+        return template.substitute(
+            clean_name = suite['name'].replace("_", "::"),
+            initialize = callbacks['initialize'],
+            cleanup = callbacks['cleanup'],
+            cb_ptr = "_clay_cb_%s" % suite['name'],
+            cb_count = suite['cb_count']
+        ).strip()
 
-    parser.add_option('-c', '--clay-path', dest='clay_path')
-    parser.add_option('-v', '--report-to', dest='print_mode', default='stdout')
+    def _render_callbacks(self, suite_name, callbacks):
+        template = Template(
+r"""
+static const struct clay_func _clay_cb_${suite_name}[] = {
+    ${callbacks}
+};
+""")
+        callbacks = [
+            self._render_cb(cb)
+            for cb in callbacks
+            if cb['short_name'] not in ('initialize', 'cleanup')
+        ]
 
-    options, args = parser.parse_args()
+        return template.substitute(
+            suite_name = suite_name,
+            callbacks = ",\n\t".join(callbacks)
+        ).strip()
 
-    for folder in args:
-        builder = ClayTestBuilder(folder,
-            clay_path = options.clay_path,
-            print_mode = options.print_mode)
+    def _render_header(self):
+        template = Template(self._load_file('clay.h'))
 
-        builder.render()
+        declarations = "\n".join(
+            "extern %s;" % decl
+            for decl in sorted(self.declarations)
+        )
 
+        return template.substitute(
+            extern_declarations = declarations,
+        )
 
-class ClayTestBuilder:
-    def __init__(self, path, clay_path = None, print_mode = 'stdout'):
-        self.declarations = []
-        self.callbacks = []
-        self.suites = []
-        self.suite_list = []
+    def _render_main(self):
+        template = Template(self._load_file('clay.c'))
+        suite_names = sorted(self.suite_names)
 
-        self.clay_path = os.path.abspath(clay_path) if clay_path else None
-        self.print_mode = print_mode
+        suite_data = [
+            self._render_suite(self.suite_data[s])
+            for s in suite_names
+        ]
 
-        self.path = os.path.abspath(path)
-        self.modules = ["clay_sandbox.c", "clay_fixtures.c", "clay_fs.c"]
+        callbacks = [
+            self._render_callbacks(s, self.callback_data[s])
+            for s in suite_names
+        ]
 
-        print("Loading test suites...")
+        callback_count = sum(
+            len(cbs) for cbs in self.callback_data.values()
+        )
 
-        for root, dirs, files in os.walk(self.path):
-            module_root = root[len(self.path):]
-            module_root = [c for c in module_root.split(os.sep) if c]
-
-            tests_in_module = fnmatch.filter(files, "*.c")
-            tests_in_module.sort()
-
-            for test_file in tests_in_module:
-                full_path = os.path.join(root, test_file)
-                test_name = "_".join(module_root + [test_file[:-2]])
-
-                with open(full_path) as f:
-                    self._process_test_file(test_name, f.read())
-
-        if not self.suites:
-            raise RuntimeError(
-                'No tests found under "%s"' % folder_name)
-
-    def render(self):
-        main_file = os.path.join(self.path, 'clay_main.c')
-        with open(main_file, "w") as out:
-            template = Template(self._load_file('clay.c'))
-
-            output = template.substitute(
-                clay_print = self._get_print_method(),
-                clay_modules = self._get_modules(),
-
-                suites_str = ", ".join(self.suite_list),
-
-                test_callbacks = ",\n\t".join(self.callbacks),
-                cb_count = len(self.callbacks),
-
-                test_suites = ",\n\t".join(self.suites),
-                suite_count = len(self.suites),
-            )
-
-            out.write(output)
-
-        header_file = os.path.join(self.path, 'clay.h')
-        with open(header_file, "w") as out:
-            template = Template(self._load_file('clay.h'))
-
-            output = template.substitute(
-                extern_declarations = "\n".join(self.declarations),
-            )
-
-            out.write(output)
-
-        print ('Written Clay suite to "%s"' % self.path)
-
-    #####################################################
-    # Internal methods
-    #####################################################
-    def _get_print_method(self):
-        return {
-                'stdout' : 'printf(__VA_ARGS__)',
-                'stderr' : 'fprintf(stderr, __VA_ARGS__)',
-                'silent' : ''
-        }[self.print_mode]
+        return template.substitute(
+            clay_modules = self._get_modules(),
+            clay_callbacks = "\n".join(callbacks),
+            clay_suites = ",\n\t".join(suite_data),
+            clay_suite_count = len(suite_data),
+            clay_callback_count = callback_count,
+        )
 
     def _load_file(self, filename):
         if self.clay_path:
@@ -151,52 +201,67 @@
 
         return comment
 
-    def _process_test_file(self, test_name, contents):
-        regex_string = TEST_FUNC_REGEX % test_name
+    def _process_test_file(self, suite_name, contents):
+        regex_string = TEST_FUNC_REGEX % suite_name
         regex = re.compile(regex_string, re.MULTILINE)
 
         callbacks = []
-        initialize = cleanup = "{NULL, NULL, 0}"
+        initialize = cleanup = None
 
-        for (declaration, symbol, short_name, _) in regex.findall(contents):
-            self.declarations.append("extern %s;" % declaration)
-            func_ptr = '{"%s", &%s, %d}' % (
-                short_name, symbol, len(self.suites)
-            )
+        for (declaration, symbol, short_name) in regex.findall(contents):
+            data = {
+                "short_name" : short_name,
+                "declaration" : declaration,
+                "symbol" : symbol
+            }
 
             if short_name == 'initialize':
-                initialize = func_ptr
+                initialize = data
             elif short_name == 'cleanup':
-                cleanup = func_ptr
+                cleanup = data
             else:
-                callbacks.append(func_ptr)
+                callbacks.append(data)
 
         if not callbacks:
             return
 
-        clean_name = test_name.replace("_", "::")
+        tests_in_suite = len(callbacks)
 
-        suite = TEMPLATE_SUITE.substitute(
-            clean_name = clean_name,
-            initialize = initialize,
-            cleanup = cleanup,
-            cb_ptr = "&_all_callbacks[%d]" % len(self.callbacks),
-            cb_count = len(callbacks)
-        ).strip()
+        suite = {
+            "name" : suite_name,
+            "initialize" : initialize,
+            "cleanup" : cleanup,
+            "cb_count" : tests_in_suite
+        }
 
-        self.callbacks += callbacks
-        self.suites.append(suite)
-        self.suite_list.append(clean_name)
+        if initialize:
+            self.declarations.append(initialize['declaration'])
 
-        print("  %s (%d tests)" % (clean_name, len(callbacks)))
+        if cleanup:
+            self.declarations.append(cleanup['declaration'])
+
+        self.declarations += [
+            callback['declaration']
+            for callback in callbacks
+        ]
+
+        callbacks.sort(key=lambda x: x['short_name'])
+        self.callback_data[suite_name] = callbacks
+        self.suite_data[suite_name] = suite
+        self.suite_names.append(suite_name)
+
+        print("  %s (%d tests)" % (suite_name, tests_in_suite))
+
 
 
 CLAY_FILES = {
-"clay.c" : r"""eJy9GWtT20jys/wrZk3AEggHyDd74SqVu1xRl2WrAqlsFaFUsjTGc9HDqxkFONb//brnpdHLux+uji+gnu6efndPc8CKJKtTSn6OOaeVmG+uJgcWxqn4d77twESasVUPxsouqGLFYxuWx2KDkMnbY1LR32tW0ZSsy4rwuEhX5TMQkOO3LpMX/la8bCnv8AYwF7EUdnKQ0jUrKEmy+CXawqXCn8/nAXnz2kB2gMbWgEiir9c37y4mB55l9sSKtHxSNzRQrU4D4BuaZfGWdcAp6JBoQTwtSfTL++ub6MMHEkVJSpPMOUKp/S2YIYQ/AxK1vxu8/Dsw1gd5mVJAbUAOXrKxQBI5Hw1GnCSU8zarPsyVsErrrQ+/pHj2A5Vg60LaMPrl+uafX99dRBEAvW0VP+YxSco8p2B8CI6QTKW53l1MkbPDuki2L74oQ7Kuyjwkoow4+w+IpI8iLg812GBFd5+/3Hx4f/cPl9nX6Nd/kbMLB3IbXd/+/fqz/xwQ338mRyQCyEeABOSnS3LmEuffBc23kTFBRgtp4B4QSGiRsvXEwyhE3UHQOhHKceT27v1ddLecHNCM01awQIA+xQzjgkCs459blvoXgQzvBq8uGKSOCqlO8PSu7NwoxWpyYorBPt9MJxPEYwn5UTLILR5VuZ+UBRcQKnFFjiNe1lVCg2UXLynBMwOYIXGBKYUwXdpL3KPJmj2LuqIRmq/FaRXzDhuDWsQ5VeykijJhaVVBRXideC6BgHuXEzCcIPhnVNT5ilbLNhKvmaAd2JplVBNmYN5hQnlllPNHhBs9k4ptBSsLEM/ry3dc0GeQaNfYQuN0BI8TwX7QSMs/cKKFViLKD3UDN+qWIs4syDFBUtaFGBHOchg4y2Igln8jsXS/f5yVCdySZDQu6m3gS+gxeEadt4/BwS9ZGadIDt0hWtVrIqo435ZoYSO2BUS0iFcZBfQdlCgQpOPvdV0kXathXCytcFsoP1IkFAgLQ2QsVRgPNOzkwQi/3rWsYILFGbAcOtX6Wr/1EGRY8kYo1y8oF6T+R6hgWjDV4+YJ1gA3+eRpXehzo6jGQFu65ObY5TCRCFVdyDDz94sbjh831tiDZGJk8qocrXIHUC+Vd+ftGJ54CtqPByA4lwG9Jr6aM/wuakAusXCjNyVaI+DpFQQFlvWbL58+BXDsdc58tJHnocb229vtF+fMiKNwWkHv3jVwPERi8iQwbDW8J7sLV3JrIW04nZwgVE5NefkDmnrxQuRdp2A5E6ckp2JTphzja0hGom5cDh4aYS0SREAzUE0Pk2lo7OI6mFzZAAjI38js44wsyGw+Ay12AzEquSlSH4MHqrFpDGNVTAaaKwohh2lAPsYsgw6y+FaAYMAm6EnMF4tDTvxDHpB7+DhMH8j9qYBfSAJWl9xPr6Q2zrfOEW9alMTpAi4J9hTn0+krHT4a2pMNVOBScI1r+48NFX3gCNAOmHFeDknvXsAbcUxFt2WlPcNVjTEJzlSijraZ0PTCiVLdFgLbhJ42YDCtk1VDJjUSAr4WXbFx1TOhcnKi9cMs9tYVpQMW6pzJTyORZr0bVh4qpwwDvx+Kqp2o0UKF4p7aChdJROV9pzGwJqndtt/g6wY1kGC6LOEryWfyCzzys3uP7jjk5IQpq7Yu0nLhr3v2MNcXee2WcaSPQ3KkGTu9wMJM6d9vSHjEZUOW/JMW1DP0mC3+uh37FjAIk47+Uqq/qPuQ4jWPH2lr5o2rR6mFDOO1P/2CGAvIVXJfymjlUIdk3iLmskH8VZ0uVK5aMCGn4rffvolv4nNdkLLIXojYUKkUUVWGwHGPhg/QKJN1iegzE/7p+VjhjitOIxCV+6oqwJ9JqHVFZX/sGxniLFvFyXce2oRIVipq/zQUHBoVCpKsKU6t3DhXuYGyOelgHVLj+xTQUFwI9qU5wzjBOd/zdE+SowOWYUN0f/aAhWt2OpOzhuNzyevsQU0bipG6QdGdy1uAJYaoqESZWZ7khFxAfJnPkJyfBfbiRly89tvZjPzxB0oG2p3tFYE/MZFsQHIpijYAvL/ITMwWck4C7r6yaIAMry6tMxQ21FAdQPA0hcSDx/ydE2WHKUlLyklRwuz3DM/XudOCkboJJPjAiavdr25FXAkYt3zVoAPdjUFy6e57Gyz3wPJB53+hCpdC7GCYN6TnFDVdhI7aqCabRy9RMq8qGn+XDJXh+Kjh3Igcs92tm23/U+MdS9sRrZJri5YpZGM7crC6WqZ0HdeZWIyGFUrSqvggiyoL+r2xvyA4j3OOG6X/f6VwTfgJhlywIHhCUS3M/IQDaeBQGsuiyM4I7zzFApmN0vEdt6Mppziiwk2iNOvNpmKDYwpaofMlJuYX7j6fWJaRbVUmFOggkTdlLZzd6FyX6p0WBk0OA/i5zvJOnVYO0Z5wsiZsTKo1DFsGQ1V3BDdakm0zwQyGohIJLTA0oPRGkz0+BFITpao2d2OYN6HYHWu1YQZG2WYGbl7YiFpRUVeFnlTbOxZg3zS+SK3FdZCD9CnDwhr2t0xhs2UKR9ZLHbgzu2piDh7P0ihegQYycseGbhuPRiBsCkondxBHp5eJfw4eBjeWGJ8dfkHQfvSaSav72rUTWOt6/ZC0G6WBV7I9U/O9y6FH7Zw5ryj7oGjv0vrvLIvo7mFa77wuK7MxdB52gKJ3hv3nHZzpFVf34WZEV0tEZZyRx9vA0+7SbN27j7f+DIybAK8ftWpBIFcpbgjZzclPY2sPnZYD9QsLGFyg9FqQuLNmIFXMOJSpuIBOllAp83yqeovbxWQTy8ricWjBExKFtTNJB5dEnAq7VtEbwO5iMlSbs+NyG/9eu8+F7sKjWeHt33koRjL39f+N8jKtM8p3nV13r2dFkGJRM088ALPXCYGfN68qDM3Rzl0Wj5VByU1XwR4rBR/gI8tJ1LQrSTp989pAdlOgwQpj/zeVx6zwu41b9vwHtCdeq2uk0+mJ/nF6i3tvaBHaVgnxn3G66ew6SKYFaWk1ksSRb5H/AuhDZ38=""",
+"clay.c" : r"""eJydWVtv3DYWftb8CnayjTW2PL7kzdMYCLKbwtjWBRIHKRAbAkfieLiRSFWkYnvT+e89PCQl6jJO0bx4dG48PJePh8wLLrKiyRn5iSrFar3cXs5etDTF9P/KakDTecHXIxqXQ1LNxX2fVlK9HSnSGqVmJ4ekZn80vGY52ciaKCrytXwEI+TwJFR5Uif6qWJqYAnISlPcAJA3OduQ9NPV9avz2YuolXrgIpcPVrWjOt87gtqyoqAVH5BzcC5zK0SwABeMpL++ubpO374laZrlLCsClnEnrmDPCfxckLT/3cmVX8CwY5QyZyDakQK5bNsSSRp8dBI0y5hSfVNjWuhhnTdVDH/QvfbDbIJvBMYw/fXq+udPr87TFIhRVdP7kpJMliUTOoZKSMgcw/XqfG4sB6ZFVj3FWiZkU8syIVqmiv8fXHKsVCHTkb1UevP+4/XbNzf/CY19Sn/7Lzk9Dygf0qsP/756Hz8uSBw/kpckBco7oCzID6/JaahcftGsrFIfgoIJDPCICCpM5Hwzi0x5mb2Do02mbeLIh5s3N+nNavaCFYr1igUq74FyUxcEitj8rHgeny+wbju5RnAod1tSg+IZLTlYEd3qin2eFfRpuZ3PZkaOZ+Sr5NA0Kq3LOJNCaSgVWpPDVMmmzthiNZTLJGRmQjIhITFnUKardpGQNdvwR93ULDXh61laUzUw40UFLZk1h1s0e0hZXUOrf5tFoYKGdVczCJwm5mcqmnLN6lVfSDVcswFtwwvmFAsI77QiLpmW6t7Q/T6zmleaSwHuRWP/DgV7BI92XSyczMBxmmn+laXO/wmOc9q6iB92BeW3KzUtWlIQgkw2Qu9xrrUwwSsoKONvo4zpjw8LmcEqWcGoaKpFjNRDyIzl99mQ4KdC0tyow1GQrpsN0TUtK2ki7N1uCSkTdF0wEN8BRIEjg3xvGpENo2bqYtU6VwH8oEsLH/BOGyO2R320Chdcc1oAtExx3fbaNI0EsAoxqmAh7afB+AWd/g4Ay2pUcNbp9HCZmZYPey3gGn/ifkIT0tWBI4xKHNtGDVo4MKu2jYYjTXzftCHY4kfCfpMohPaggbxL+wpvvxkpjDvxsLNxQ9aboLstYUOhg/PnTOKO4ukoPadH17Lu+wIIkJDlcrkYJtMNHnuS2QjH90XqJIz7obpnG9tvGi3vmWA11TDcmF2TnGpK1k+oYtb51zdUhs4r1jT7onYD2B23Qdr9Vp/vyGvoCwL/nCFL3/UwyxZyoGcLAVRDJUvcrSbVvH9DzT7d9cdbWTO7W9NRBl7VIKQzVK4bgZgZP9+MyX521+vPCHnAm32zqGV7QZld4OaWfUCeRZY6BjdQOEN03pDYTsjxUHRBXpspxGAVinUOHl8CwpkZ5frjL78sgB0NeLEpmigyO26/o93z7px6d6xMD8HDtSbYUyoe9BferKOPfA/p1m/nZItDR0eGirN9Kb/ChCqeCK51DJHzKExKprcyx+qY8pHYFVeTTO9sKwQVMAKhNqAIPm0kArwEWjwuA3LZlgns1xxJs4n6ZRWAi9Owfe9rjNta2XtsJ362mEWW7GuxPdQftgCJJLZcH3qsK6MI8siBjaGZKNy7w/Gjo4R4qI6iTc1Y7HSCwWfAw0/vkTPd1aCLjfe1GzLaHEyGCdo8hO8xpFksx+A9BwSwCgoeXw7OaD5Kvl3PSfsB1O0inMk6k26cmCgF12bmbhpz/IL0/hS64uYDcnTEbYp6CznXzZ/P/G7pFor6EPjSsRPy0hkOsK2leSjDrOzwvktOzeXDXGpkTWtePJGcK4sP+zBXwd26mMrGdzB3lKx9wfr7gR6HyAvMBgFCr/5mcHbt1Wm0/0bR+/4cQet73AyWziaefzQSF+RHRT5LbBF1dytuxTwhRnLVCf5muRfAA/LJScsg5Fj//vutvtXvG0GkgJzorTsR7dRDgI1aoY6a0LGxGyqxRxgpj8/2wFJFa8VScFbhLAc/ssTt1Wz2awdSvbI+s2VtxINKbmPUmHs/iBkLUKcrz6OZvT9FkRsc8RQzh4dX+nx6ZwDs4PgAj70gDWjr9M4efNaQXcHqneEqYNIUj661LFqb5IicQ+b9Z0LOThftwp27Ztnb0wPy55/GM9jd6bMuqAeusy14jq64AMC9lhyogws8ssF6bEFnYQxevh6PVVYt6uORHUPnH8J0/piTXDJFhISZ5JErvcQqAy6icBSkGT4MCgegYQHuZW8YBM07K7yuGf2CW8rZhjaFvti7bWPZgkk30No6wrbbX0HDK445SOFjMTUwJn1meD0BznyOR6wfOYJZeoEpw4BuXKconQPUGLVo/g6vDXB79o+GXZ9BjGDuNhFFyRugmRfFB14UpKplxkAPsr2VjQ5eHJeuwXbOGbNzGAXOXCkMusvGBQNidIh5IELB7liKRsfGKAK22b6bXH7nHZu6BP7z4LuBKHiAcMkY3HrM6jXTTS3IWAWBqEOg1L4pxxZmAGxzbhoqGb/aJN2rTbLnuWZAD2YXp6wgiUWeYothZe4butoS8w6ZqNs9hYOYiZ7M4rMEr0DSlNzA3mLRn7v92TccuNszsbf8aHgaD+otz853oYWJ0avlORV3mo5O2FVPwl3AW8HwocPL+aN7fJ53MiaNIOLe4BwxeIYDnnsycrw2s951+yhngxOkN4zLeHC1Z4J5uO5Ps1NTibmMTBS6vaPgbS4sofby9sO+m5eD+AmER9wGXIJF7N4uCB3cdkhNuQL0oQJQP2Po93JucTtEfAT8Qor7qXtmQqzUzjceLJLCzaq93blXteFjX2JfNA5lRf9owiFueO/q3smev3pZQ9j/7kmglHlTmCeImWnO9r9JSsrF6DTBY+jOuGGeMBy8dIdPD2B3s78AAFrlyw==""",
+"clay_print_default.c" : r"""eJyFU01P4zAQPSe/YqgU1a5Cuafa3RunistqT4AiEztgKbUje9LVCvHfsccpOGhbTs48z3t+85HSo0DdwdFqCd0g/rWj0wZbbTSy8AGoPLadnQzWEGM/aVQnoLPGI3QvwsEmXRhxUJ6Xr2XBoiT/pO/KgqR7ttpbIZWESiY130DlH8yqhvgiX7yQq2YKv1E4VDKQAvpWlmeq8C8TSvvXfF9JBJRz1iXgXAUJypgfWEbelZ9GH0zyWJArp0brsKVczy5apxzybabDqdMe3dRhSqME2NBBdk9PQmgsh1uhh8mphvoaJHjuqvJNU3lgledwH4JKPsL9NYYjppdFQarXP6nQLI69iOHKWJDKd06PqO2C0ushZwzahPFNhyflvujM6MIXnBZhzktNPfhnytI9sPkiexyufsDdn/2eB/lzOlk6X07n8v5YE52yfM2T9bCPaWeyShLQh74r+XV/ImG3RIiTrXTVBb+JDb9gfbuGBtbb9Tf+aELs//8hmbjZgLF2hM3NcnuTo0vS4ins6kI6DKKG7XZLwkfRDjpcCfc87ij08adkMa4hzaw49nN5HmWYBeE1UXjiKCPZHL6V7yZUhjs=""",
+"clay_print_tap.c" : r"""eJyFU8Fu2zAMPUdfwXoIYBuxgWK3Btuwnotih/U2wFBtORXmSIEkZyiG/ntJylnkNFlOMh+fyMdnSvggg25hb3UH7SBfm53TJjTa6JDjBwTlQ9Pa0YQVUOxHHdQBaK3xAdoX6aCMCSO3yhfir1jkVLJI0PUc4xKIcb8+z35+/wF75by2Bm4//zJZkSRv63rZIbZK9GD+TYgL+v3LGDr7x1yfgQDlnHVT1aP247UL0iOWXF6Lo+Q4wWWFfI3lmXF7sNIHN7Yh0pgAJR+JKmSnbQCqqjpxCwDt9nKj4A6Wnm3jKtXXqHXrN3O6V+i8Dq930Es9fKjGUwN8qMb4nEqewRkq4XNmrwd1jkn4nDloc2B2KZPwBu14Vq4gS3QP+ZTqlG+d3gVappsv8Pj08FCIRVIzIZwKSFLF3Om6rq/9VWto0jx9GLxG9ALirsWQVUeALFcd/+FDq6XHUaGahKHwyIFvkBkbwP7O0IwMD8qlBf+F2E4sWD6Lc2pn3bRzPr8yAf/W/Pzbnsn8BGVZokg62MGE9/8W8hnlzFrgTq7IYG6wl82gMSXdZrfmECvhBYpXMK1vP8nw+NBHfMjZPZoE+HkDvL/7UwK3oBJFrKlMl0/hm3gHeFWmnA==""",
 "clay_sandbox.c" : r"""eJyNVV1P20AQfLZ/xRIkYpNATItaVSkPlaBVVEoiEgQSRJaxz+SEfY7uLmkD4r931+fEHwRahBST3Zudmb0xSgeahxDOAgl+mAQrfx7o2e2x9+XTtG/bypS50DZX/jJIeOTrdJ43OWEmlDZH9+kL1362rfHk28SfgNJ42uIxOAThULkLe0q7sHMCnmtblmR6IQV4676dsT8Ynw4u8cCh0n6aRcxt9hXPThCGTKkC9dof/nThhGD79kuNc8xFlW/O9H4Rx0x2QfEn5mtImHgw1Hd5LCIWg389uPj4wbYKHKOy6F4G0g+zhdBwAsf9Ro/BZ2KJRkl1O8UeNMRqTX6NUFerC/SUf5yZz6vx2eXocvh9cH7WssF6QYlgFZM46Y0zCQ5HHK8PHL6W4/vQ6XA3h2/MxuYHpvHB2RDhUzTGMibjl2QqndJcLBhNySuv10utZgTKlCKcr5y1d1jqrp0j6MqSLOvFxl/b6u3DIAY9Y9TNZSZShrZFGVOijX4GKwjESs+4eOiClivQGSwUgx7Oh/2e/QapFtVbBa8mLVOsMasQQ1K7LFHMQP9gesLS+YhAndPr4eWpa451wcA1Lt8uExGPja7JjCtQK6VZuhGU8EeGAmpaSHy4kDIXziULdYbFd8Qdvqns8D1Z6z8PjqoBWGY8gjzSC6ECEd1nfxz6Lo8pEajk3ZtSgNp3XrtUjVcDI1FNRDhDFcgSaVYMiZUv0wpYM4XoJ08iv6BglG54VG4vFXwd8CRPTivHI2tu8p8WpW0T2fVLox7wkoOJdxZXabkYoOqbh9yyLQTDaeg3PtRFNNU/A65eZDLFpT2xnC4tejQcD24Ak/o7kBGoJFAzpvIlV6JsvYoyiShD3NwHL/Zxl+/DsholaPfam6htFtHAIGUHcDSlNy72m0H1eqdTgtE9Wl+7sgs6xLRbLmebszgGm7ZYRozSR4zJ3Ff/3E7jH4NZj0Gga1c97n32vK0HKgHHUzS4xhM9vbg6P391qDCwTFX9AucI/x8h2Nvbdue33z9CMbmqEt3qRY3eX120XBI=""",
 "clay_fixtures.c" : r"""eJyFUV1LwzAUfW5+xZU9rLUVJ4ggZQ9DFAUfRCZMRglZmrBAl5Qkk03xv9v0a82U+Zabc+45595rLLGCAlXSWKBrouEccbGzW81wSew6HCIrYljicTuqJBsWoS8UmFbPobXA8npye5OlFSI+GbaglbK4YDJFKOjeMAVjdfUInUPkyFZLWu7DWiKBxtgpKN78RZETEByactlLXcBVBmdTGF+OIxQEPhrHGdRQ1zzMv5xUYN84ROLY8b1MEPeTJEdsV3tRq0wdt06tWcWVzXpS9I3QSPCccbh7nr3jh6fF/O31Hr/M5o9ouGpa4NYlPHmBVt074i/lBLy+OsWHEjkcXLAhMl+p3Wk3bjBV1VIG6TxOApgWZN8s4k8bWjAit+W/NnoTejMddI+GqW1GTOaCox8pOffr""",
 "clay_fs.c" : r"""eJylVdtu20YQfSa/YkAD8TKWY8dJX6L0wXDEVqgsBhINN7UFhiGX1qIkl9hd+dLG/57ZCynJUWEkfZE0s7NnZufMGe2xsqAlpJfj6ZsT399DgzUUojhKo8npb3Mg+ud8PBlNE/hq/NP4LJ5G49n5aTKOp71zNJvFs4vx06DzPz6MZ6HvS5UplkO+zAS89EtWUd7KtM3UkuS8kcqdGE/o/+t71tYm/ArTi8lk6HuS/UNTBRVtbtRyAGzo+x4rgaQ2zMaFvucJqlaicdd8z15AHKkE/rbxIQI6+DqrKp4TF3YAJ2GH/AxwTeu8fTBRA0jtl0Xp0K+sucAsx9suzPPauX2v5AIIMxYweO9AhnBwwELAbvTFXLGFrmf/aF+X4/Uu2L++3scEjwjmitRnQ/+x7/0tZ0XXecIaBTUv6AC22i/5SuRPnQWVynAy/z3CSYg/zpPZxVkCJQLp4m2YvYqVbJHrEHU7bJgG+y7IZNBQf1HBz2nNxQN5oeEHoDnnJdlOHYa2aa18dRetmlxziI8ZOl8bCV5ruk3u3ptw9OlUnaeMquxGorOfd/OcKs2kpEKlBFuMibHUuKUCm8gbW1aoOTge4HFwyZqC30l4EgdlhmYR+J4tVVBK1q0wpnv0U4JkKmqygxTDQEdfFKcfRpNRMsKx6zgzM7oLL+c4oz9A80aSs/jjp40U6bpmA46t0vgVzZpVS7TLApg3lOwe55A6ivMqe3AKCV4GoQXZo5WkXbk4kr5c0qpK+UoRW5SrMBM3t1cLg60HV19YSS0nVuA+wE/dY/zSg8XF32StX/S9h2OrobIVeLskUhVUCM2eF8wfpKI1oM3FO/hsb3+GHDeCo/DVdRNozjx6zxQ5fB06lXXwehIsPr2n+S0xtR4vBqboLvguYwqD9YUBvLD1D/DesFfr5ejPcTJPTpOLObHn/4PLnkprmpJ+WQy3pbpeqNZOcenovvVCxm1ZIK0bEl4Hrpdpf2pbYs2rjchDs+f6nfVfAXYRuu6hGRx9Yc1R3gZD5zVBweGsd5wsNjVuXG+0y81O6KRuDt4u+r8Ro/B6JRWOo5RG5OuxM6QZYUeGfVAcdM9B6b3lRlpqr8ya4gu/363wZ0W9oekNjt4udvVA1N/1oNxuQvfiHc342TdbTYNa0u2XPiN9I/NV464Qs/e1a8PxiLJvClb63wD3Q6FA""",
-"clay.h" : r"""eJy9Vctu2zAQPEdfsbV6sAQhTq9pGsAIbMSAERStg7YngqZWEVGZVEmqcVH030NSfkm2qqYHn0wtOTuzu0M65JlIMQNC7ubjb2Qx+bwg94QEoQ1ygUfxIOSCFVWKcKNNWvDlZX4bBD8lT4EV9BchVGtUZhhccGGASZFyw6VIggu71jaSUwVxxgtM6iOFZWntolJStWIpaqZ4ucnlgDqXVZESupTKRO93GohGQ1iBVFTl0MeG8eYzqr/jKIF6IUv6o0IL3mIz3YC6tCHPXH98F6azr4vHTxPycby4Dw7VOShfm0rhsFmmjxFBVw2WTVhTkS7l+jWQrbq/QEK0Pc+CYBTHAcQw9vOwbYMVZUpqeOYmB1yXBWfcgO81rFBr+oT2/Gg3ecu6qrQhpZ0oGVqASsBNIWoO2u9EcPsBrhLrlulsPiHEreazB78aTCvBvABGiwIyamefXsMAwn3OBN5FR8TuZD/xTSfvZF0iM5hC1hBgpNfQo6Am6ad/01235Ve2r46YaxDSgFEVnuLdzuouR/b9P+bEHO5Mg7qKjpnPPKlTEs4wqKuo51IJ+Y/XaSOpecPqYAIPj/P56cvQgtVd74Rtyt9hto5uArqt11fN3nR7jkMjdgrbe6YN7KnIH2pjOuqZSsWcoWxG+zaOnqkSXDy1a/AiTnimyykLtK9ufTEuB6cfjg3Ta7J+qSGQVsr9GEeCa2SVc9j14IT/vI4VmlymdtOSKOrOal/f29+4NqgEOdz5E2z/GF4ABeagMA=="""
+"clay.h" : r"""eJy9Vctu2zAQPEdfwVo9WIIQp9c0DWAENmLACIrWQdsTQZOriKhMqiTVqCj67yUp+aGH46YHn0wtdzizu0M65KlgkCKM75bTb3g1+7zC9xgHoQ1yAb14EHJB85IButGG5Xx9md0GwU/JGaI5+YUx0RqUGQcXXBhEpWDccCmS4MKutY1kRKE45TkkdUpuWTq7oJRUnRgDTRUvmrMcUGeyzBkma6lM9H6nAWswmOZARFmMfWwcN59R/R1HCaoXsiA/SrDgLTbVLag7NuSp64/vwnzxdfX4aYY/Tlf3waE6B+WVKRWM22X6GBZk02JpwpoItpbVayBbdS9AQrA9T4NgEscBitHUz8O2DW0IVVKjZ24yBFWRc8oN8r1GG9CaPIHNn+wmb1k3pTa4sBPFYwtQCXJTiNqD9jsRuv2ArhLrlvliOcPYrZaLB78azUtBvQBK8hylxM6eXaMRCvdnJuhd1CN2maeJb47yzqoCqAGG0pYAI72GEwpqktP0b47XbfmV7asj5hoJaZBRJQzxbmd1lwH9/h9zog53pkFdRX3mM09qSMIZBnUVnbhUQv7jdWokDd2wh8flcvgqdECHPe+BmtJ3iLab6/TjpjtVx95ue4a+BXui9l7pwl6sxad0EYOVzKWizkT2NPseTp6JElw8ddV7AQM+OeaOFdiXtr4Ml6Phx6Jhes2pX2oIYqVyP8aRQAW0dK66Hg14zuvYgMkks5uWRBGXq319b39DZUAJfLjzJ9j+GfwFGCyeSg=="""
 }
 if __name__ == '__main__':
     main()
diff --git a/tests-clay/clay.h b/tests-clay/clay.h
index bc4267b..db3a475 100644
--- a/tests-clay/clay.h
+++ b/tests-clay/clay.h
@@ -37,16 +37,16 @@
 /**
  * Assertion macros with no error message
  */
-#define cl_must_pass(expr) cl_must_pass_((expr), NULL)
-#define cl_must_fail(expr) cl_must_fail_((expr), NULL)
-#define cl_assert(expr) cl_assert_((expr), NULL)
+#define cl_must_pass(expr) cl_must_pass_(expr, NULL)
+#define cl_must_fail(expr) cl_must_fail_(expr, NULL)
+#define cl_assert(expr) cl_assert_(expr, NULL)
 
 /**
  * Check macros with no error message
  */
-#define cl_check_pass(expr) cl_check_pass_((expr), NULL)
-#define cl_check_fail(expr) cl_check_fail_((expr), NULL)
-#define cl_check(expr) cl_check_((expr), NULL)
+#define cl_check_pass(expr) cl_check_pass_(expr, NULL)
+#define cl_check_fail(expr) cl_check_fail_(expr, NULL)
+#define cl_check(expr) cl_check_(expr, NULL)
 
 /**
  * Forced failure/warning
@@ -57,10 +57,13 @@
 /**
  * Test method declarations
  */
+extern void test_config_stress__cleanup(void);
+extern void test_config_stress__dont_break_on_invalid_input(void);
+extern void test_config_stress__initialize(void);
 extern void test_core_dirent__dont_traverse_dot(void);
-extern void test_core_dirent__traverse_subfolder(void);
-extern void test_core_dirent__traverse_slash_terminated_folder(void);
 extern void test_core_dirent__dont_traverse_empty_folders(void);
+extern void test_core_dirent__traverse_slash_terminated_folder(void);
+extern void test_core_dirent__traverse_subfolder(void);
 extern void test_core_dirent__traverse_weird_filenames(void);
 extern void test_core_filebuf__0(void);
 extern void test_core_filebuf__1(void);
@@ -72,9 +75,9 @@
 extern void test_core_path__2(void);
 extern void test_core_path__5(void);
 extern void test_core_path__6(void);
-extern void test_core_rmdir__initialize(void);
 extern void test_core_rmdir__delete_recursive(void);
 extern void test_core_rmdir__fail_to_delete_non_empty_dir(void);
+extern void test_core_rmdir__initialize(void);
 extern void test_core_string__0(void);
 extern void test_core_string__1(void);
 extern void test_core_strtol__int32(void);
@@ -82,21 +85,52 @@
 extern void test_core_vector__0(void);
 extern void test_core_vector__1(void);
 extern void test_core_vector__2(void);
-extern void test_network_remotes__initialize(void);
+extern void test_index_rename__single_file(void);
 extern void test_network_remotes__cleanup(void);
+extern void test_network_remotes__fnmatch(void);
+extern void test_network_remotes__initialize(void);
 extern void test_network_remotes__parsing(void);
 extern void test_network_remotes__refspec_parsing(void);
-extern void test_network_remotes__fnmatch(void);
 extern void test_network_remotes__transform(void);
-extern void test_object_tree_frompath__initialize(void);
+extern void test_object_raw_chars__build_valid_oid_from_raw_bytes(void);
+extern void test_object_raw_chars__find_invalid_chars_in_oid(void);
+extern void test_object_raw_compare__compare_allocfmt_oids(void);
+extern void test_object_raw_compare__compare_fmt_oids(void);
+extern void test_object_raw_compare__compare_pathfmt_oids(void);
+extern void test_object_raw_compare__succeed_on_copy_oid(void);
+extern void test_object_raw_compare__succeed_on_oid_comparison_equal(void);
+extern void test_object_raw_compare__succeed_on_oid_comparison_greater(void);
+extern void test_object_raw_compare__succeed_on_oid_comparison_lesser(void);
+extern void test_object_raw_convert__succeed_on_oid_to_string_conversion(void);
+extern void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void);
+extern void test_object_raw_fromstr__fail_on_invalid_oid_string(void);
+extern void test_object_raw_fromstr__succeed_on_valid_oid_string(void);
+extern void test_object_raw_hash__hash_buffer_in_single_call(void);
+extern void test_object_raw_hash__hash_by_blocks(void);
+extern void test_object_raw_hash__hash_commit_object(void);
+extern void test_object_raw_hash__hash_junk_data(void);
+extern void test_object_raw_hash__hash_multi_byte_object(void);
+extern void test_object_raw_hash__hash_one_byte_object(void);
+extern void test_object_raw_hash__hash_tag_object(void);
+extern void test_object_raw_hash__hash_tree_object(void);
+extern void test_object_raw_hash__hash_two_byte_object(void);
+extern void test_object_raw_hash__hash_vector(void);
+extern void test_object_raw_hash__hash_zero_length_object(void);
+extern void test_object_raw_short__oid_shortener_no_duplicates(void);
+extern void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void);
+extern void test_object_raw_size__validate_oid_size(void);
+extern void test_object_raw_type2string__check_type_is_loose(void);
+extern void test_object_raw_type2string__convert_string_to_type(void);
+extern void test_object_raw_type2string__convert_type_to_string(void);
 extern void test_object_tree_frompath__cleanup(void);
-extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void);
-extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void);
 extern void test_object_tree_frompath__fail_when_processing_an_invalid_path(void);
+extern void test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment(void);
+extern void test_object_tree_frompath__initialize(void);
+extern void test_object_tree_frompath__retrieve_tree_from_path_to_treeentry(void);
 extern void test_status_single__hash_single_file(void);
-extern void test_status_worktree__initialize(void);
 extern void test_status_worktree__cleanup(void);
-extern void test_status_worktree__whole_repository(void);
 extern void test_status_worktree__empty_repository(void);
+extern void test_status_worktree__initialize(void);
+extern void test_status_worktree__whole_repository(void);
 
 #endif
diff --git a/tests-clay/clay_libgit2.h b/tests-clay/clay_libgit2.h
index ab3cf67..a520896 100644
--- a/tests-clay/clay_libgit2.h
+++ b/tests-clay/clay_libgit2.h
@@ -23,6 +23,6 @@
  * just for consistency. Use with `git_` library
  * calls that are supposed to fail!
  */
-#define cl_git_fail(expr) cl_must_fail((expr))
+#define cl_git_fail(expr) cl_must_fail(expr)
 
 #endif
diff --git a/tests-clay/clay_main.c b/tests-clay/clay_main.c
index da90872..4ad6fc4 100644
--- a/tests-clay/clay_main.c
+++ b/tests-clay/clay_main.c
@@ -4,13 +4,12 @@
 #include <stdio.h>
 #include <string.h>
 #include <math.h>
+#include <stdarg.h>
 
 /* required for sandboxing */
 #include <sys/types.h>
 #include <sys/stat.h>
 
-#define clay_print(...) printf(__VA_ARGS__)
-
 #ifdef _WIN32
 #	include <windows.h>
 #	include <io.h>
@@ -82,7 +81,6 @@
 struct clay_func {
 	const char *name;
 	void (*ptr)(void);
-	size_t suite_n;
 };
 
 struct clay_suite {
@@ -93,10 +91,268 @@
 	size_t test_count;
 };
 
+/* From clay_print_*.c */
+static void clay_print_init(int test_count, int suite_count, const char *suite_names);
+static void clay_print_shutdown(int test_count, int suite_count, int error_count);
+static void clay_print_error(int num, const struct clay_error *error);
+static void clay_print_ontest(const char *test_name, int test_number, int failed);
+static void clay_print_onsuite(const char *suite_name);
+static void clay_print_onabort(const char *msg, ...);
+
 /* From clay_sandbox.c */
 static void clay_unsandbox(void);
 static int clay_sandbox(void);
 
+/* Autogenerated test data by clay */
+static const struct clay_func _clay_cb_config_stress[] = {
+    {"dont_break_on_invalid_input", &test_config_stress__dont_break_on_invalid_input}
+};
+static const struct clay_func _clay_cb_core_dirent[] = {
+    {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot},
+	{"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders},
+	{"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder},
+	{"traverse_subfolder", &test_core_dirent__traverse_subfolder},
+	{"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames}
+};
+static const struct clay_func _clay_cb_core_filebuf[] = {
+    {"0", &test_core_filebuf__0},
+	{"1", &test_core_filebuf__1},
+	{"2", &test_core_filebuf__2}
+};
+static const struct clay_func _clay_cb_core_oid[] = {
+    {"streq", &test_core_oid__streq}
+};
+static const struct clay_func _clay_cb_core_path[] = {
+    {"0", &test_core_path__0},
+	{"1", &test_core_path__1},
+	{"2", &test_core_path__2},
+	{"5", &test_core_path__5},
+	{"6", &test_core_path__6}
+};
+static const struct clay_func _clay_cb_core_rmdir[] = {
+    {"delete_recursive", &test_core_rmdir__delete_recursive},
+	{"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir}
+};
+static const struct clay_func _clay_cb_core_string[] = {
+    {"0", &test_core_string__0},
+	{"1", &test_core_string__1}
+};
+static const struct clay_func _clay_cb_core_strtol[] = {
+    {"int32", &test_core_strtol__int32},
+	{"int64", &test_core_strtol__int64}
+};
+static const struct clay_func _clay_cb_core_vector[] = {
+    {"0", &test_core_vector__0},
+	{"1", &test_core_vector__1},
+	{"2", &test_core_vector__2}
+};
+static const struct clay_func _clay_cb_index_rename[] = {
+    {"single_file", &test_index_rename__single_file}
+};
+static const struct clay_func _clay_cb_network_remotes[] = {
+    {"fnmatch", &test_network_remotes__fnmatch},
+	{"parsing", &test_network_remotes__parsing},
+	{"refspec_parsing", &test_network_remotes__refspec_parsing},
+	{"transform", &test_network_remotes__transform}
+};
+static const struct clay_func _clay_cb_object_raw_chars[] = {
+    {"build_valid_oid_from_raw_bytes", &test_object_raw_chars__build_valid_oid_from_raw_bytes},
+	{"find_invalid_chars_in_oid", &test_object_raw_chars__find_invalid_chars_in_oid}
+};
+static const struct clay_func _clay_cb_object_raw_compare[] = {
+    {"compare_allocfmt_oids", &test_object_raw_compare__compare_allocfmt_oids},
+	{"compare_fmt_oids", &test_object_raw_compare__compare_fmt_oids},
+	{"compare_pathfmt_oids", &test_object_raw_compare__compare_pathfmt_oids},
+	{"succeed_on_copy_oid", &test_object_raw_compare__succeed_on_copy_oid},
+	{"succeed_on_oid_comparison_equal", &test_object_raw_compare__succeed_on_oid_comparison_equal},
+	{"succeed_on_oid_comparison_greater", &test_object_raw_compare__succeed_on_oid_comparison_greater},
+	{"succeed_on_oid_comparison_lesser", &test_object_raw_compare__succeed_on_oid_comparison_lesser}
+};
+static const struct clay_func _clay_cb_object_raw_convert[] = {
+    {"succeed_on_oid_to_string_conversion", &test_object_raw_convert__succeed_on_oid_to_string_conversion},
+	{"succeed_on_oid_to_string_conversion_big", &test_object_raw_convert__succeed_on_oid_to_string_conversion_big}
+};
+static const struct clay_func _clay_cb_object_raw_fromstr[] = {
+    {"fail_on_invalid_oid_string", &test_object_raw_fromstr__fail_on_invalid_oid_string},
+	{"succeed_on_valid_oid_string", &test_object_raw_fromstr__succeed_on_valid_oid_string}
+};
+static const struct clay_func _clay_cb_object_raw_hash[] = {
+    {"hash_buffer_in_single_call", &test_object_raw_hash__hash_buffer_in_single_call},
+	{"hash_by_blocks", &test_object_raw_hash__hash_by_blocks},
+	{"hash_commit_object", &test_object_raw_hash__hash_commit_object},
+	{"hash_junk_data", &test_object_raw_hash__hash_junk_data},
+	{"hash_multi_byte_object", &test_object_raw_hash__hash_multi_byte_object},
+	{"hash_one_byte_object", &test_object_raw_hash__hash_one_byte_object},
+	{"hash_tag_object", &test_object_raw_hash__hash_tag_object},
+	{"hash_tree_object", &test_object_raw_hash__hash_tree_object},
+	{"hash_two_byte_object", &test_object_raw_hash__hash_two_byte_object},
+	{"hash_vector", &test_object_raw_hash__hash_vector},
+	{"hash_zero_length_object", &test_object_raw_hash__hash_zero_length_object}
+};
+static const struct clay_func _clay_cb_object_raw_short[] = {
+    {"oid_shortener_no_duplicates", &test_object_raw_short__oid_shortener_no_duplicates},
+	{"oid_shortener_stresstest_git_oid_shorten", &test_object_raw_short__oid_shortener_stresstest_git_oid_shorten}
+};
+static const struct clay_func _clay_cb_object_raw_size[] = {
+    {"validate_oid_size", &test_object_raw_size__validate_oid_size}
+};
+static const struct clay_func _clay_cb_object_raw_type2string[] = {
+    {"check_type_is_loose", &test_object_raw_type2string__check_type_is_loose},
+	{"convert_string_to_type", &test_object_raw_type2string__convert_string_to_type},
+	{"convert_type_to_string", &test_object_raw_type2string__convert_type_to_string}
+};
+static const struct clay_func _clay_cb_object_tree_frompath[] = {
+    {"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path},
+	{"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment},
+	{"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry}
+};
+static const struct clay_func _clay_cb_status_single[] = {
+    {"hash_single_file", &test_status_single__hash_single_file}
+};
+static const struct clay_func _clay_cb_status_worktree[] = {
+    {"empty_repository", &test_status_worktree__empty_repository},
+	{"whole_repository", &test_status_worktree__whole_repository}
+};
+
+static const struct clay_suite _clay_suites[] = {
+    {
+        "config::stress",
+        {"initialize", &test_config_stress__initialize},
+        {"cleanup", &test_config_stress__cleanup},
+        _clay_cb_config_stress, 1
+    },
+	{
+        "core::dirent",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_core_dirent, 5
+    },
+	{
+        "core::filebuf",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_core_filebuf, 3
+    },
+	{
+        "core::oid",
+        {"initialize", &test_core_oid__initialize},
+        {NULL, NULL},
+        _clay_cb_core_oid, 1
+    },
+	{
+        "core::path",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_core_path, 5
+    },
+	{
+        "core::rmdir",
+        {"initialize", &test_core_rmdir__initialize},
+        {NULL, NULL},
+        _clay_cb_core_rmdir, 2
+    },
+	{
+        "core::string",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_core_string, 2
+    },
+	{
+        "core::strtol",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_core_strtol, 2
+    },
+	{
+        "core::vector",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_core_vector, 3
+    },
+	{
+        "index::rename",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_index_rename, 1
+    },
+	{
+        "network::remotes",
+        {"initialize", &test_network_remotes__initialize},
+        {"cleanup", &test_network_remotes__cleanup},
+        _clay_cb_network_remotes, 4
+    },
+	{
+        "object::raw::chars",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_chars, 2
+    },
+	{
+        "object::raw::compare",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_compare, 7
+    },
+	{
+        "object::raw::convert",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_convert, 2
+    },
+	{
+        "object::raw::fromstr",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_fromstr, 2
+    },
+	{
+        "object::raw::hash",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_hash, 11
+    },
+	{
+        "object::raw::short",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_short, 2
+    },
+	{
+        "object::raw::size",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_size, 1
+    },
+	{
+        "object::raw::type2string",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_object_raw_type2string, 3
+    },
+	{
+        "object::tree::frompath",
+        {"initialize", &test_object_tree_frompath__initialize},
+        {"cleanup", &test_object_tree_frompath__cleanup},
+        _clay_cb_object_tree_frompath, 3
+    },
+	{
+        "status::single",
+        {NULL, NULL},
+        {NULL, NULL},
+        _clay_cb_status_single, 1
+    },
+	{
+        "status::worktree",
+        {"initialize", &test_status_worktree__initialize},
+        {"cleanup", &test_status_worktree__cleanup},
+        _clay_cb_status_worktree, 2
+    }
+};
+
+static size_t _clay_suite_count = 22;
+static size_t _clay_callback_count = 65;
+
+/* Core test functions */
 static void
 clay_run_test(
 	const struct clay_func *test,
@@ -128,28 +384,11 @@
 	_clay.local_cleanup = NULL;
 	_clay.local_cleanup_payload = NULL;
 
-	clay_print("%c", (_clay.suite_errors > error_st) ? 'F' : '.');
-}
-
-static void
-clay_print_error(int num, const struct clay_error *error)
-{
-	clay_print("  %d) Failure:\n", num);
-
-	clay_print("%s::%s (%s) [%s:%d] [-t%d]\n",
-		error->suite,
-		error->test,
-		"no description",
-		error->file,
-		error->line_number,
-		error->test_number);
-
-	clay_print("  %s\n", error->error_msg);
-
-	if (error->description != NULL)
-		clay_print("  %s\n", error->description);
-
-	clay_print("\n");
+	clay_print_ontest(
+		test->name,
+		_clay.test_count,
+		(_clay.suite_errors > error_st)
+	);
 }
 
 static void
@@ -166,6 +405,8 @@
 		free(error);
 		error = next;
 	}
+
+	_clay.errors = _clay.last_error = NULL;
 }
 
 static void
@@ -174,6 +415,8 @@
 	const struct clay_func *test = suite->tests;
 	size_t i;
 
+	clay_print_onsuite(suite->name);
+
 	_clay.active_suite = suite->name;
 	_clay.suite_errors = 0;
 
@@ -183,6 +426,7 @@
 	}
 }
 
+#if 0 /* temporarily disabled */
 static void
 clay_run_single(const struct clay_func *test,
 	const struct clay_suite *suite)
@@ -193,24 +437,20 @@
 
 	clay_run_test(test, &suite->initialize, &suite->cleanup);
 }
+#endif
 
 static void
 clay_usage(const char *arg)
 {
 	printf("Usage: %s [options]\n\n", arg);
 	printf("Options:\n");
-	printf("  -tXX\t\tRun only the test number XX\n");
+//	printf("  -tXX\t\tRun only the test number XX\n");
 	printf("  -sXX\t\tRun only the suite number XX\n");
 	exit(-1);
 }
 
 static void
-clay_parse_args(
-	int argc, char **argv,
-	const struct clay_func *callbacks,
-	size_t cb_count,
-	const struct clay_suite *suites,
-	size_t suite_count)
+clay_parse_args(int argc, char **argv)
 {
 	int i;
 
@@ -229,27 +469,13 @@
 			clay_usage(argv[0]);
 
 		switch (action) {
-		case 't':
-			if ((size_t)num >= cb_count) {
-				fprintf(stderr, "Test number %d does not exist.\n", num);
-				exit(-1);
-			}
-
-			clay_print("Started (%s::%s)\n",
-				suites[callbacks[num].suite_n].name,
-				callbacks[num].name);
-
-			clay_run_single(&callbacks[num], &suites[callbacks[num].suite_n]);
-			break;
-
 		case 's':
-			if ((size_t)num >= suite_count) {
-				fprintf(stderr, "Suite number %d does not exist.\n", num);
+			if ((size_t)num >= _clay_suite_count) {
+				clay_print_onabort("Suite number %d does not exist.\n", num);
 				exit(-1);
 			}
 
-			clay_print("Started (%s::*)\n", suites[num].name);
-			clay_run_suite(&suites[num]);
+			clay_run_suite(&_clay_suites[num]);
 			break;
 
 		default:
@@ -259,15 +485,13 @@
 }
 
 static int
-clay_test(
-	int argc, char **argv,
-	const char *suites_str,
-	const struct clay_func *callbacks,
-	size_t cb_count,
-	const struct clay_suite *suites,
-	size_t suite_count)
+clay_test(int argc, char **argv)
 {
-	clay_print("Loaded %d suites: %s\n", (int)suite_count, suites_str);
+	clay_print_init(
+		(int)_clay_callback_count,
+		(int)_clay_suite_count,
+		""
+	);
 
 	if (clay_sandbox() < 0) {
 		fprintf(stderr,
@@ -276,21 +500,18 @@
 	}
 
 	if (argc > 1) {
-		clay_parse_args(argc, argv,
-			callbacks, cb_count, suites, suite_count);
-
+		clay_parse_args(argc, argv);
 	} else {
 		size_t i;
-		clay_print("Started\n");
-
-		for (i = 0; i < suite_count; ++i) {
-			const struct clay_suite *s = &suites[i];
-			clay_run_suite(s);
-		}
+		for (i = 0; i < _clay_suite_count; ++i)
+			clay_run_suite(&_clay_suites[i]);
 	}
 
-	clay_print("\n\n");
-	clay_report_errors();
+	clay_print_shutdown(
+		(int)_clay_callback_count,
+		(int)_clay_suite_count,
+		_clay.total_errors
+	);
 
 	clay_unsandbox();
 	return _clay.total_errors;
@@ -335,7 +556,7 @@
 
 	if (should_abort) {
 		if (!_clay.trampoline_enabled) {
-			fprintf(stderr,
+			clay_print_onabort(
 				"Fatal error: a cleanup method raised an exception.");
 			exit(-1);
 		}
@@ -659,124 +880,68 @@
 #endif
 
 
-static const struct clay_func _all_callbacks[] = {
-    {"dont_traverse_dot", &test_core_dirent__dont_traverse_dot, 0},
-	{"traverse_subfolder", &test_core_dirent__traverse_subfolder, 0},
-	{"traverse_slash_terminated_folder", &test_core_dirent__traverse_slash_terminated_folder, 0},
-	{"dont_traverse_empty_folders", &test_core_dirent__dont_traverse_empty_folders, 0},
-	{"traverse_weird_filenames", &test_core_dirent__traverse_weird_filenames, 0},
-	{"0", &test_core_filebuf__0, 1},
-	{"1", &test_core_filebuf__1, 1},
-	{"2", &test_core_filebuf__2, 1},
-	{"streq", &test_core_oid__streq, 2},
-	{"0", &test_core_path__0, 3},
-	{"1", &test_core_path__1, 3},
-	{"2", &test_core_path__2, 3},
-	{"5", &test_core_path__5, 3},
-	{"6", &test_core_path__6, 3},
-	{"delete_recursive", &test_core_rmdir__delete_recursive, 4},
-	{"fail_to_delete_non_empty_dir", &test_core_rmdir__fail_to_delete_non_empty_dir, 4},
-	{"0", &test_core_string__0, 5},
-	{"1", &test_core_string__1, 5},
-	{"int32", &test_core_strtol__int32, 6},
-	{"int64", &test_core_strtol__int64, 6},
-	{"0", &test_core_vector__0, 7},
-	{"1", &test_core_vector__1, 7},
-	{"2", &test_core_vector__2, 7},
-	{"parsing", &test_network_remotes__parsing, 8},
-	{"refspec_parsing", &test_network_remotes__refspec_parsing, 8},
-	{"fnmatch", &test_network_remotes__fnmatch, 8},
-	{"transform", &test_network_remotes__transform, 8},
-	{"retrieve_tree_from_path_to_treeentry", &test_object_tree_frompath__retrieve_tree_from_path_to_treeentry, 9},
-	{"fail_when_processing_an_unknown_tree_segment", &test_object_tree_frompath__fail_when_processing_an_unknown_tree_segment, 9},
-	{"fail_when_processing_an_invalid_path", &test_object_tree_frompath__fail_when_processing_an_invalid_path, 9},
-	{"hash_single_file", &test_status_single__hash_single_file, 10},
-	{"whole_repository", &test_status_worktree__whole_repository, 11},
-	{"empty_repository", &test_status_worktree__empty_repository, 11}
-};
+static void clay_print_init(int test_count, int suite_count, const char *suite_names)
+{
+	(void)suite_names;
+	(void)suite_count;
+	printf("TAP version 13\n");
+	printf("1..%d\n", test_count);
+}
 
-static const struct clay_suite _all_suites[] = {
-    {
-        "core::dirent",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[0], 5
-    },
-	{
-        "core::filebuf",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[5], 3
-    },
-	{
-        "core::oid",
-        {"initialize", &test_core_oid__initialize, 2},
-        {NULL, NULL, 0},
-        &_all_callbacks[8], 1
-    },
-	{
-        "core::path",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[9], 5
-    },
-	{
-        "core::rmdir",
-        {"initialize", &test_core_rmdir__initialize, 4},
-        {NULL, NULL, 0},
-        &_all_callbacks[14], 2
-    },
-	{
-        "core::string",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[16], 2
-    },
-	{
-        "core::strtol",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[18], 2
-    },
-	{
-        "core::vector",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[20], 3
-    },
-	{
-        "network::remotes",
-        {"initialize", &test_network_remotes__initialize, 8},
-        {"cleanup", &test_network_remotes__cleanup, 8},
-        &_all_callbacks[23], 4
-    },
-	{
-        "object::tree::frompath",
-        {"initialize", &test_object_tree_frompath__initialize, 9},
-        {"cleanup", &test_object_tree_frompath__cleanup, 9},
-        &_all_callbacks[27], 3
-    },
-	{
-        "status::single",
-        {NULL, NULL, 0},
-        {NULL, NULL, 0},
-        &_all_callbacks[30], 1
-    },
-	{
-        "status::worktree",
-        {"initialize", &test_status_worktree__initialize, 11},
-        {"cleanup", &test_status_worktree__cleanup, 11},
-        &_all_callbacks[31], 2
-    }
-};
+static void clay_print_shutdown(int test_count, int suite_count, int error_count)
+{
+	(void)test_count;
+	(void)suite_count;
+	(void)error_count;
 
-static const char _suites_str[] = "core::dirent, core::filebuf, core::oid, core::path, core::rmdir, core::string, core::strtol, core::vector, network::remotes, object::tree::frompath, status::single, status::worktree";
+	printf("\n");
+}
+
+static void clay_print_error(int num, const struct clay_error *error)
+{
+	(void)num;
+
+	printf("  ---\n");
+	printf("  message : %s\n", error->error_msg);
+	printf("  severity: fail\n");
+	printf("  suite   : %s\n", error->suite);
+	printf("  test    : %s\n", error->test);
+	printf("  file    : %s\n", error->file);
+	printf("  line    : %d\n", error->line_number);
+
+	if (error->description != NULL)
+		printf("  description: %s\n", error->description);
+
+	printf("  ...\n");
+}
+
+static void clay_print_ontest(const char *test_name, int test_number, int failed)
+{
+	printf("%s %d - %s\n",
+		failed ? "not ok" : "ok",
+		test_number,
+		test_name
+	);
+
+	clay_report_errors();
+}
+
+static void clay_print_onsuite(const char *suite_name)
+{
+	printf("# *** %s ***\n", suite_name);
+}
+
+static void clay_print_onabort(const char *msg, ...)
+{
+	va_list argp;
+	va_start(argp, msg);
+	fprintf(stdout, "Bail out! ");
+	vfprintf(stdout, msg, argp);
+	va_end(argp);
+}
+
 
 int _MAIN_CC main(int argc, char *argv[])
 {
-    return clay_test(
-        argc, argv, _suites_str,
-        _all_callbacks, 33,
-        _all_suites, 12
-    );
+    return clay_test(argc, argv);
 }
diff --git a/tests-clay/config/stress.c b/tests-clay/config/stress.c
new file mode 100644
index 0000000..7b81400
--- /dev/null
+++ b/tests-clay/config/stress.c
@@ -0,0 +1,41 @@
+#include "clay_libgit2.h"
+
+#include "filebuf.h"
+#include "fileops.h"
+#include "posix.h"
+
+#define TEST_CONFIG "git-test-config"
+
+void test_config_stress__initialize(void)
+{
+	git_filebuf file;
+
+	git_filebuf_open(&file, TEST_CONFIG, 0);
+
+	git_filebuf_printf(&file, "[color]\n\tui = auto\n");
+	git_filebuf_printf(&file, "[core]\n\teditor = \n");
+
+	git_filebuf_commit(&file, 0666);
+}
+
+void test_config_stress__cleanup(void)
+{
+	p_unlink(TEST_CONFIG);
+}
+
+void test_config_stress__dont_break_on_invalid_input(void)
+{
+	const char *editor, *color;
+	struct git_config_file *file;
+	git_config *config;
+
+	cl_git_pass(git_futils_exists(TEST_CONFIG));
+	cl_git_pass(git_config_file__ondisk(&file, TEST_CONFIG));
+	cl_git_pass(git_config_new(&config));
+	cl_git_pass(git_config_add_file(config, file, 0));
+
+	cl_git_pass(git_config_get_string(config, "color.ui", &color));
+	cl_git_pass(git_config_get_string(config, "core.editor", &editor));
+
+	git_config_free(config);
+}
diff --git a/tests-clay/core/dirent.c b/tests-clay/core/dirent.c
index 73f5715..105e8d8 100644
--- a/tests-clay/core/dirent.c
+++ b/tests-clay/core/dirent.c
@@ -20,18 +20,18 @@
 {
 	name_data *n;
 
-	cl_must_pass(p_mkdir(top_dir, 0755));
+	cl_must_pass(p_mkdir(top_dir, 0777));
 
 	cl_must_pass(p_chdir(top_dir));
 
 	if (strcmp(d->sub, ".") != 0)
-		cl_must_pass(p_mkdir(d->sub, 0755));
+		cl_must_pass(p_mkdir(d->sub, 0777));
 
 	strcpy(path_buffer, d->sub);
 	state_loc = d;
 
 	for (n = d->names; n->name; n++) {
-		git_file fd = p_creat(n->name, 0600);
+		git_file fd = p_creat(n->name, 0666);
 		cl_assert(fd >= 0);
 		p_close(fd);
 		n->count = 0;
diff --git a/tests-clay/core/filebuf.c b/tests-clay/core/filebuf.c
index e00e204..e1ecb27 100644
--- a/tests-clay/core/filebuf.c
+++ b/tests-clay/core/filebuf.c
@@ -27,14 +27,14 @@
 	int fd;
 	char test[] = "test";
 
-	fd = p_creat(test, 0644);
+	fd = p_creat(test, 0666);
 	cl_must_pass(fd);
 	cl_must_pass(p_write(fd, "libgit2 rocks\n", 14));
 	cl_must_pass(p_close(fd));
 
 	cl_git_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND));
 	cl_git_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
-	cl_git_pass(git_filebuf_commit(&file));
+	cl_git_pass(git_filebuf_commit(&file, 0666));
 
 	cl_must_pass(p_unlink(test));
 }
@@ -51,7 +51,7 @@
 
 	cl_git_pass(git_filebuf_open(&file, test, 0));
 	cl_git_pass(git_filebuf_write(&file, buf, sizeof(buf)));
-	cl_git_pass(git_filebuf_commit(&file));
+	cl_git_pass(git_filebuf_commit(&file, 0666));
 
 	cl_must_pass(p_unlink(test));
 }
diff --git a/tests-clay/core/path.c b/tests-clay/core/path.c
index db8f33d..c394c72 100644
--- a/tests-clay/core/path.c
+++ b/tests-clay/core/path.c
@@ -11,7 +11,7 @@
 	cl_assert((dir2 = git_path_dirname(A)) != NULL);
 	cl_assert(strcmp(dir2, B) == 0);
 
-	free(dir2);
+	git__free(dir2);
 }
 
 static void
@@ -24,7 +24,7 @@
 	cl_assert((base2 = git_path_basename(A)) != NULL);
 	cl_assert(strcmp(base2, B) == 0);
 
-	free(base2);
+	git__free(base2);
 }
 
 static void
diff --git a/tests-clay/core/rmdir.c b/tests-clay/core/rmdir.c
index aa21c6a..20cc8f5 100644
--- a/tests-clay/core/rmdir.c
+++ b/tests-clay/core/rmdir.c
@@ -7,22 +7,22 @@
 {
 	char path[GIT_PATH_MAX];
 
-	cl_must_pass(p_mkdir(empty_tmp_dir, 0755));
+	cl_must_pass(p_mkdir(empty_tmp_dir, 0777));
 
 	git_path_join(path, empty_tmp_dir, "/one");
-	cl_must_pass(p_mkdir(path, 0755));
+	cl_must_pass(p_mkdir(path, 0777));
 
 	git_path_join(path, empty_tmp_dir, "/one/two_one");
-	cl_must_pass(p_mkdir(path, 0755));
+	cl_must_pass(p_mkdir(path, 0777));
 
 	git_path_join(path, empty_tmp_dir, "/one/two_two");
-	cl_must_pass(p_mkdir(path, 0755));
+	cl_must_pass(p_mkdir(path, 0777));
 
 	git_path_join(path, empty_tmp_dir, "/one/two_two/three");
-	cl_must_pass(p_mkdir(path, 0755));
+	cl_must_pass(p_mkdir(path, 0777));
 
 	git_path_join(path, empty_tmp_dir, "/two");
-	cl_must_pass(p_mkdir(path, 0755));
+	cl_must_pass(p_mkdir(path, 0777));
 }
 
 /* make sure empty dir can be deleted recusively */
@@ -39,7 +39,7 @@
 
 	git_path_join(file, empty_tmp_dir, "/two/file.txt");
 
-	fd = p_creat(file, 0755);
+	fd = p_creat(file, 0666);
 	cl_assert(fd >= 0);
 
 	cl_must_pass(p_close(fd));
diff --git a/tests-clay/core/vector.c b/tests-clay/core/vector.c
index 44e6d87..b8a853c 100644
--- a/tests-clay/core/vector.c
+++ b/tests-clay/core/vector.c
@@ -59,8 +59,8 @@
 
 	git_vector_free(&x);
 
-	free(ptrs[0]);
-	free(ptrs[1]);
+	git__free(ptrs[0]);
+	git__free(ptrs[1]);
 }
 
 
diff --git a/tests-clay/index/rename.c b/tests-clay/index/rename.c
new file mode 100644
index 0000000..ba72b62
--- /dev/null
+++ b/tests-clay/index/rename.c
@@ -0,0 +1,60 @@
+#include "clay_libgit2.h"
+#include "posix.h"
+
+static void file_create(const char *filename, const char *content)
+{
+	int fd;
+
+	fd = p_creat(filename, 0666);
+	cl_assert(fd != 0);
+	cl_git_pass(p_write(fd, content, strlen(content)));
+	cl_git_pass(p_close(fd))
+}
+
+void test_index_rename__single_file(void)
+{
+	git_repository *repo;
+	git_index *index;
+	int position;
+	git_oid expected;
+	git_index_entry *entry;
+
+	p_mkdir("rename", 0700);
+
+	cl_git_pass(git_repository_init(&repo, "./rename", 0));
+	cl_git_pass(git_repository_index(&index, repo));
+
+	cl_assert(git_index_entrycount(index) == 0);
+
+	file_create("./rename/lame.name.txt", "new_file\n");
+
+	/* This should add a new blob to the object database in 'd4/fa8600b4f37d7516bef4816ae2c64dbf029e3a' */
+	cl_git_pass(git_index_add(index, "lame.name.txt", 0));
+	cl_assert(git_index_entrycount(index) == 1);
+
+	cl_git_pass(git_oid_fromstr(&expected, "d4fa8600b4f37d7516bef4816ae2c64dbf029e3a"));
+
+	position = git_index_find(index, "lame.name.txt");
+
+	entry = git_index_get(index, position);
+	cl_assert(git_oid_cmp(&expected, &entry->oid) == 0);
+
+	/* This removes the entry from the index, but not from the object database */
+	cl_git_pass(git_index_remove(index, position));
+	cl_assert(git_index_entrycount(index) == 0);
+
+	p_rename("./rename/lame.name.txt", "./rename/fancy.name.txt");
+
+	cl_git_pass(git_index_add(index, "fancy.name.txt", 0));
+	cl_assert(git_index_entrycount(index) == 1);
+
+	position = git_index_find(index, "fancy.name.txt");
+
+	entry = git_index_get(index, position);
+	cl_assert(git_oid_cmp(&expected, &entry->oid) == 0);
+
+	git_index_free(index);
+	git_repository_free(repo);
+
+	cl_fixture_cleanup("rename");
+}
diff --git a/tests-clay/object/raw/chars.c b/tests-clay/object/raw/chars.c
new file mode 100644
index 0000000..eba352b
--- /dev/null
+++ b/tests-clay/object/raw/chars.c
@@ -0,0 +1,52 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+
+static int from_hex(unsigned int i)
+{
+	if (i >= '0' && i <= '9')
+		return i - '0';
+	if (i >= 'a' && i <= 'f')
+		return 10 + (i - 'a');
+	if (i >= 'A' && i <= 'F')
+		return 10 + (i - 'A');
+	return -1;
+}
+
+void test_object_raw_chars__find_invalid_chars_in_oid(void)
+{
+	git_oid out;
+	unsigned char exp[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+	char in[41] = "16a67770b7d8d72317c4b775213c23a8bd74f5e0";
+	unsigned int i;
+
+	for (i = 0; i < 256; i++) {
+		in[38] = (char)i;
+		if (from_hex(i) >= 0) {
+			exp[19] = (unsigned char)(from_hex(i) << 4);
+			cl_git_pass(git_oid_fromstr(&out, in));
+			cl_assert(memcmp(out.id, exp, sizeof(out.id)) == 0);
+		} else {
+			cl_git_fail(git_oid_fromstr(&out, in));
+		}
+	}
+}
+
+void test_object_raw_chars__build_valid_oid_from_raw_bytes(void)
+{
+	git_oid out;
+	unsigned char exp[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+	git_oid_fromraw(&out, exp);
+	cl_git_pass(memcmp(out.id, exp, sizeof(out.id)));
+}
diff --git a/tests-clay/object/raw/compare.c b/tests-clay/object/raw/compare.c
new file mode 100644
index 0000000..94b1969
--- /dev/null
+++ b/tests-clay/object/raw/compare.c
@@ -0,0 +1,124 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+
+void test_object_raw_compare__succeed_on_copy_oid(void)
+{
+	git_oid a, b;
+	unsigned char exp[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+	memset(&b, 0, sizeof(b));
+	git_oid_fromraw(&a, exp);
+	git_oid_cpy(&b, &a);
+	cl_git_pass(memcmp(a.id, exp, sizeof(a.id)));
+}
+
+void test_object_raw_compare__succeed_on_oid_comparison_lesser(void)
+{
+	git_oid a, b;
+	unsigned char a_in[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+	unsigned char b_in[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xf0,
+	};
+	git_oid_fromraw(&a, a_in);
+	git_oid_fromraw(&b, b_in);
+	cl_assert(git_oid_cmp(&a, &b) < 0);
+}
+
+void test_object_raw_compare__succeed_on_oid_comparison_equal(void)
+{
+	git_oid a, b;
+	unsigned char a_in[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+	git_oid_fromraw(&a, a_in);
+	git_oid_fromraw(&b, a_in);
+	cl_assert(git_oid_cmp(&a, &b) == 0);
+}
+
+void test_object_raw_compare__succeed_on_oid_comparison_greater(void)
+{
+	git_oid a, b;
+	unsigned char a_in[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+	unsigned char b_in[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xd0,
+	};
+	git_oid_fromraw(&a, a_in);
+	git_oid_fromraw(&b, b_in);
+	cl_assert(git_oid_cmp(&a, &b) > 0);
+}
+
+void test_object_raw_compare__compare_fmt_oids(void)
+{
+	const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+	git_oid in;
+	char out[GIT_OID_HEXSZ + 1];
+
+	cl_git_pass(git_oid_fromstr(&in, exp));
+
+	/* Format doesn't touch the last byte */
+	out[GIT_OID_HEXSZ] = 'Z';
+	git_oid_fmt(out, &in);
+	cl_assert(out[GIT_OID_HEXSZ] == 'Z');
+
+	/* Format produced the right result */
+	out[GIT_OID_HEXSZ] = '\0';
+	cl_assert(strcmp(exp, out) == 0);
+}
+
+void test_object_raw_compare__compare_allocfmt_oids(void)
+{
+	const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+	git_oid in;
+	char *out;
+
+	cl_git_pass(git_oid_fromstr(&in, exp));
+
+	out = git_oid_allocfmt(&in);
+	cl_assert(out);
+	cl_assert(strcmp(exp, out) == 0);
+	git__free(out);
+}
+
+void test_object_raw_compare__compare_pathfmt_oids(void)
+{
+	const char *exp1 = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+	const char *exp2 = "16/a0123456789abcdef4b775213c23a8bd74f5e0";
+	git_oid in;
+	char out[GIT_OID_HEXSZ + 2];
+
+	cl_git_pass(git_oid_fromstr(&in, exp1));
+
+	/* Format doesn't touch the last byte */
+	out[GIT_OID_HEXSZ + 1] = 'Z';
+	git_oid_pathfmt(out, &in);
+	cl_assert(out[GIT_OID_HEXSZ + 1] == 'Z');
+
+	/* Format produced the right result */
+	out[GIT_OID_HEXSZ + 1] = '\0';
+	cl_assert(strcmp(exp2, out) == 0);
+}
diff --git a/tests-clay/object/raw/convert.c b/tests-clay/object/raw/convert.c
new file mode 100644
index 0000000..f69f5f9
--- /dev/null
+++ b/tests-clay/object/raw/convert.c
@@ -0,0 +1,75 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+
+void test_object_raw_convert__succeed_on_oid_to_string_conversion(void)
+{
+	const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+	git_oid in;
+	char out[GIT_OID_HEXSZ + 1];
+	char *str;
+	int i;
+
+	cl_git_pass(git_oid_fromstr(&in, exp));
+
+	/* NULL buffer pointer, returns static empty string */
+	str = git_oid_to_string(NULL, sizeof(out), &in);
+	cl_assert(str && *str == '\0' && str != out);
+
+	/* zero buffer size, returns static empty string */
+	str = git_oid_to_string(out, 0, &in);
+	cl_assert(str && *str == '\0' && str != out);
+
+	/* NULL oid pointer, returns static empty string */
+	str = git_oid_to_string(out, sizeof(out), NULL);
+	cl_assert(str && *str == '\0' && str != out);
+
+	/* n == 1, returns out as an empty string */
+	str = git_oid_to_string(out, 1, &in);
+	cl_assert(str && *str == '\0' && str == out);
+
+	for (i = 1; i < GIT_OID_HEXSZ; i++) {
+		out[i+1] = 'Z';
+		str = git_oid_to_string(out, i+1, &in);
+		/* returns out containing c-string */
+		cl_assert(str && str == out);
+		/* must be '\0' terminated */
+		cl_assert(*(str+i) == '\0');
+		/* must not touch bytes past end of string */
+		cl_assert(*(str+(i+1)) == 'Z');
+		/* i == n-1 charaters of string */
+		cl_git_pass(strncmp(exp, out, i));
+	}
+
+	/* returns out as hex formatted c-string */
+	str = git_oid_to_string(out, sizeof(out), &in);
+	cl_assert(str && str == out && *(str+GIT_OID_HEXSZ) == '\0');
+	cl_assert(strcmp(exp, out) == 0);
+}
+
+void test_object_raw_convert__succeed_on_oid_to_string_conversion_big(void)
+{
+	const char *exp = "16a0123456789abcdef4b775213c23a8bd74f5e0";
+	git_oid in;
+	char big[GIT_OID_HEXSZ + 1 + 3]; /* note + 4 => big buffer */
+	char *str;
+
+	cl_git_pass(git_oid_fromstr(&in, exp));
+
+	/* place some tail material */
+	big[GIT_OID_HEXSZ+0] = 'W'; /* should be '\0' afterwards */
+	big[GIT_OID_HEXSZ+1] = 'X'; /* should remain untouched   */
+	big[GIT_OID_HEXSZ+2] = 'Y'; /* ditto */
+	big[GIT_OID_HEXSZ+3] = 'Z'; /* ditto */
+
+	/* returns big as hex formatted c-string */
+	str = git_oid_to_string(big, sizeof(big), &in);
+	cl_assert(str && str == big && *(str+GIT_OID_HEXSZ) == '\0');
+	cl_assert(strcmp(exp, big) == 0);
+
+	/* check tail material is untouched */
+	cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+1) == 'X');
+	cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+2) == 'Y');
+	cl_assert(str && str == big && *(str+GIT_OID_HEXSZ+3) == 'Z');
+}
diff --git a/tests-clay/object/raw/data.h b/tests-clay/object/raw/data.h
new file mode 100644
index 0000000..cf23819
--- /dev/null
+++ b/tests-clay/object/raw/data.h
@@ -0,0 +1,323 @@
+
+/*
+ * Raw data
+ */
+static unsigned char commit_data[] = {
+    0x74, 0x72, 0x65, 0x65, 0x20, 0x64, 0x66, 0x66,
+    0x32, 0x64, 0x61, 0x39, 0x30, 0x62, 0x32, 0x35,
+    0x34, 0x65, 0x31, 0x62, 0x65, 0x62, 0x38, 0x38,
+    0x39, 0x64, 0x31, 0x66, 0x31, 0x66, 0x31, 0x32,
+    0x38, 0x38, 0x62, 0x65, 0x31, 0x38, 0x30, 0x33,
+    0x37, 0x38, 0x32, 0x64, 0x66, 0x0a, 0x61, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x20, 0x41, 0x20, 0x55,
+    0x20, 0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61,
+    0x75, 0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78,
+    0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f,
+    0x6d, 0x3e, 0x20, 0x31, 0x32, 0x32, 0x37, 0x38,
+    0x31, 0x34, 0x32, 0x39, 0x37, 0x20, 0x2b, 0x30,
+    0x30, 0x30, 0x30, 0x0a, 0x63, 0x6f, 0x6d, 0x6d,
+    0x69, 0x74, 0x74, 0x65, 0x72, 0x20, 0x43, 0x20,
+    0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,
+    0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
+    0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,
+    0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,
+    0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34,
+    0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30,
+    0x30, 0x0a, 0x0a, 0x41, 0x20, 0x6f, 0x6e, 0x65,
+    0x2d, 0x6c, 0x69, 0x6e, 0x65, 0x20, 0x63, 0x6f,
+    0x6d, 0x6d, 0x69, 0x74, 0x20, 0x73, 0x75, 0x6d,
+    0x6d, 0x61, 0x72, 0x79, 0x0a, 0x0a, 0x54, 0x68,
+    0x65, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x20, 0x6f,
+    0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,
+    0x6d, 0x6d, 0x69, 0x74, 0x20, 0x6d, 0x65, 0x73,
+    0x73, 0x61, 0x67, 0x65, 0x2c, 0x20, 0x63, 0x6f,
+    0x6e, 0x74, 0x61, 0x69, 0x6e, 0x69, 0x6e, 0x67,
+    0x20, 0x66, 0x75, 0x72, 0x74, 0x68, 0x65, 0x72,
+    0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x6e, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x6f, 0x66, 0x20,
+    0x74, 0x68, 0x65, 0x20, 0x70, 0x75, 0x72, 0x70,
+    0x6f, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x74,
+    0x68, 0x65, 0x20, 0x63, 0x68, 0x61, 0x6e, 0x67,
+    0x65, 0x73, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f,
+    0x64, 0x75, 0x63, 0x65, 0x64, 0x20, 0x62, 0x79,
+    0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6d,
+    0x6d, 0x69, 0x74, 0x2e, 0x0a, 0x0a, 0x53, 0x69,
+    0x67, 0x6e, 0x65, 0x64, 0x2d, 0x6f, 0x66, 0x2d,
+    0x62, 0x79, 0x3a, 0x20, 0x41, 0x20, 0x55, 0x20,
+    0x54, 0x68, 0x6f, 0x72, 0x20, 0x3c, 0x61, 0x75,
+    0x74, 0x68, 0x6f, 0x72, 0x40, 0x65, 0x78, 0x61,
+    0x6d, 0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d,
+    0x3e, 0x0a,
+};
+
+
+static unsigned char tree_data[] = {
+    0x31, 0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x6f,
+    0x6e, 0x65, 0x00, 0x8b, 0x13, 0x78, 0x91, 0x79,
+    0x1f, 0xe9, 0x69, 0x27, 0xad, 0x78, 0xe6, 0x4b,
+    0x0a, 0xad, 0x7b, 0xde, 0xd0, 0x8b, 0xdc, 0x31,
+    0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x73, 0x6f,
+    0x6d, 0x65, 0x00, 0xfd, 0x84, 0x30, 0xbc, 0x86,
+    0x4c, 0xfc, 0xd5, 0xf1, 0x0e, 0x55, 0x90, 0xf8,
+    0xa4, 0x47, 0xe0, 0x1b, 0x94, 0x2b, 0xfe, 0x31,
+    0x30, 0x30, 0x36, 0x34, 0x34, 0x20, 0x74, 0x77,
+    0x6f, 0x00, 0x78, 0x98, 0x19, 0x22, 0x61, 0x3b,
+    0x2a, 0xfb, 0x60, 0x25, 0x04, 0x2f, 0xf6, 0xbd,
+    0x87, 0x8a, 0xc1, 0x99, 0x4e, 0x85, 0x31, 0x30,
+    0x30, 0x36, 0x34, 0x34, 0x20, 0x7a, 0x65, 0x72,
+    0x6f, 0x00, 0xe6, 0x9d, 0xe2, 0x9b, 0xb2, 0xd1,
+    0xd6, 0x43, 0x4b, 0x8b, 0x29, 0xae, 0x77, 0x5a,
+    0xd8, 0xc2, 0xe4, 0x8c, 0x53, 0x91,
+};
+
+static unsigned char tag_data[] = {
+    0x6f, 0x62, 0x6a, 0x65, 0x63, 0x74, 0x20, 0x33,
+    0x64, 0x37, 0x66, 0x38, 0x61, 0x36, 0x61, 0x66,
+    0x30, 0x37, 0x36, 0x63, 0x38, 0x63, 0x33, 0x66,
+    0x32, 0x30, 0x30, 0x37, 0x31, 0x61, 0x38, 0x39,
+    0x33, 0x35, 0x63, 0x64, 0x62, 0x65, 0x38, 0x32,
+    0x32, 0x38, 0x35, 0x39, 0x34, 0x64, 0x31, 0x0a,
+    0x74, 0x79, 0x70, 0x65, 0x20, 0x63, 0x6f, 0x6d,
+    0x6d, 0x69, 0x74, 0x0a, 0x74, 0x61, 0x67, 0x20,
+    0x76, 0x30, 0x2e, 0x30, 0x2e, 0x31, 0x0a, 0x74,
+    0x61, 0x67, 0x67, 0x65, 0x72, 0x20, 0x43, 0x20,
+    0x4f, 0x20, 0x4d, 0x69, 0x74, 0x74, 0x65, 0x72,
+    0x20, 0x3c, 0x63, 0x6f, 0x6d, 0x6d, 0x69, 0x74,
+    0x74, 0x65, 0x72, 0x40, 0x65, 0x78, 0x61, 0x6d,
+    0x70, 0x6c, 0x65, 0x2e, 0x63, 0x6f, 0x6d, 0x3e,
+    0x20, 0x31, 0x32, 0x32, 0x37, 0x38, 0x31, 0x34,
+    0x32, 0x39, 0x37, 0x20, 0x2b, 0x30, 0x30, 0x30,
+    0x30, 0x0a, 0x0a, 0x54, 0x68, 0x69, 0x73, 0x20,
+    0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74,
+    0x61, 0x67, 0x20, 0x6f, 0x62, 0x6a, 0x65, 0x63,
+    0x74, 0x20, 0x66, 0x6f, 0x72, 0x20, 0x72, 0x65,
+    0x6c, 0x65, 0x61, 0x73, 0x65, 0x20, 0x76, 0x30,
+    0x2e, 0x30, 0x2e, 0x31, 0x0a,
+};
+
+/*
+ * Dummy data
+ */
+static unsigned char zero_data[] = {
+    0x00,
+};
+
+static unsigned char one_data[] = {
+    0x0a,
+};
+
+static unsigned char two_data[] = {
+    0x61, 0x0a,
+};
+
+static unsigned char some_data[] = {
+    0x2f, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x54, 0x68,
+    0x69, 0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20,
+    0x69, 0x73, 0x20, 0x66, 0x72, 0x65, 0x65, 0x20,
+    0x73, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+    0x3b, 0x20, 0x79, 0x6f, 0x75, 0x20, 0x63, 0x61,
+    0x6e, 0x20, 0x72, 0x65, 0x64, 0x69, 0x73, 0x74,
+    0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x20, 0x69,
+    0x74, 0x20, 0x61, 0x6e, 0x64, 0x2f, 0x6f, 0x72,
+    0x20, 0x6d, 0x6f, 0x64, 0x69, 0x66, 0x79, 0x0a,
+    0x20, 0x2a, 0x20, 0x69, 0x74, 0x20, 0x75, 0x6e,
+    0x64, 0x65, 0x72, 0x20, 0x74, 0x68, 0x65, 0x20,
+    0x74, 0x65, 0x72, 0x6d, 0x73, 0x20, 0x6f, 0x66,
+    0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55,
+    0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+    0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+    0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x2c,
+    0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f, 0x6e,
+    0x20, 0x32, 0x2c, 0x0a, 0x20, 0x2a, 0x20, 0x61,
+    0x73, 0x20, 0x70, 0x75, 0x62, 0x6c, 0x69, 0x73,
+    0x68, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x74,
+    0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20,
+    0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+    0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x2e, 0x0a, 0x20, 0x2a, 0x0a,
+    0x20, 0x2a, 0x20, 0x49, 0x6e, 0x20, 0x61, 0x64,
+    0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74,
+    0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x65,
+    0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f, 0x6e,
+    0x73, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65,
+    0x20, 0x47, 0x4e, 0x55, 0x20, 0x47, 0x65, 0x6e,
+    0x65, 0x72, 0x61, 0x6c, 0x20, 0x50, 0x75, 0x62,
+    0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69, 0x63, 0x65,
+    0x6e, 0x73, 0x65, 0x2c, 0x0a, 0x20, 0x2a, 0x20,
+    0x74, 0x68, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68,
+    0x6f, 0x72, 0x73, 0x20, 0x67, 0x69, 0x76, 0x65,
+    0x20, 0x79, 0x6f, 0x75, 0x20, 0x75, 0x6e, 0x6c,
+    0x69, 0x6d, 0x69, 0x74, 0x65, 0x64, 0x20, 0x70,
+    0x65, 0x72, 0x6d, 0x69, 0x73, 0x73, 0x69, 0x6f,
+    0x6e, 0x20, 0x74, 0x6f, 0x20, 0x6c, 0x69, 0x6e,
+    0x6b, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f,
+    0x6d, 0x70, 0x69, 0x6c, 0x65, 0x64, 0x0a, 0x20,
+    0x2a, 0x20, 0x76, 0x65, 0x72, 0x73, 0x69, 0x6f,
+    0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69,
+    0x73, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x20, 0x69,
+    0x6e, 0x74, 0x6f, 0x20, 0x63, 0x6f, 0x6d, 0x62,
+    0x69, 0x6e, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73,
+    0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x6f, 0x74,
+    0x68, 0x65, 0x72, 0x20, 0x70, 0x72, 0x6f, 0x67,
+    0x72, 0x61, 0x6d, 0x73, 0x2c, 0x0a, 0x20, 0x2a,
+    0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x6f, 0x20,
+    0x64, 0x69, 0x73, 0x74, 0x72, 0x69, 0x62, 0x75,
+    0x74, 0x65, 0x20, 0x74, 0x68, 0x6f, 0x73, 0x65,
+    0x20, 0x63, 0x6f, 0x6d, 0x62, 0x69, 0x6e, 0x61,
+    0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x77, 0x69,
+    0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e,
+    0x79, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72, 0x69,
+    0x63, 0x74, 0x69, 0x6f, 0x6e, 0x0a, 0x20, 0x2a,
+    0x20, 0x63, 0x6f, 0x6d, 0x69, 0x6e, 0x67, 0x20,
+    0x66, 0x72, 0x6f, 0x6d, 0x20, 0x74, 0x68, 0x65,
+    0x20, 0x75, 0x73, 0x65, 0x20, 0x6f, 0x66, 0x20,
+    0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c,
+    0x65, 0x2e, 0x20, 0x20, 0x28, 0x54, 0x68, 0x65,
+    0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+    0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+    0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a,
+    0x20, 0x2a, 0x20, 0x72, 0x65, 0x73, 0x74, 0x72,
+    0x69, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20,
+    0x64, 0x6f, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x79,
+    0x20, 0x69, 0x6e, 0x20, 0x6f, 0x74, 0x68, 0x65,
+    0x72, 0x20, 0x72, 0x65, 0x73, 0x70, 0x65, 0x63,
+    0x74, 0x73, 0x3b, 0x20, 0x66, 0x6f, 0x72, 0x20,
+    0x65, 0x78, 0x61, 0x6d, 0x70, 0x6c, 0x65, 0x2c,
+    0x20, 0x74, 0x68, 0x65, 0x79, 0x20, 0x63, 0x6f,
+    0x76, 0x65, 0x72, 0x0a, 0x20, 0x2a, 0x20, 0x6d,
+    0x6f, 0x64, 0x69, 0x66, 0x69, 0x63, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74,
+    0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65, 0x2c,
+    0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x73,
+    0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x69, 0x6f,
+    0x6e, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x6e,
+    0x6f, 0x74, 0x20, 0x6c, 0x69, 0x6e, 0x6b, 0x65,
+    0x64, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x0a, 0x20,
+    0x2a, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6d, 0x62,
+    0x69, 0x6e, 0x65, 0x64, 0x20, 0x65, 0x78, 0x65,
+    0x63, 0x75, 0x74, 0x61, 0x62, 0x6c, 0x65, 0x2e,
+    0x29, 0x0a, 0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20,
+    0x54, 0x68, 0x69, 0x73, 0x20, 0x66, 0x69, 0x6c,
+    0x65, 0x20, 0x69, 0x73, 0x20, 0x64, 0x69, 0x73,
+    0x74, 0x72, 0x69, 0x62, 0x75, 0x74, 0x65, 0x64,
+    0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20,
+    0x68, 0x6f, 0x70, 0x65, 0x20, 0x74, 0x68, 0x61,
+    0x74, 0x20, 0x69, 0x74, 0x20, 0x77, 0x69, 0x6c,
+    0x6c, 0x20, 0x62, 0x65, 0x20, 0x75, 0x73, 0x65,
+    0x66, 0x75, 0x6c, 0x2c, 0x20, 0x62, 0x75, 0x74,
+    0x0a, 0x20, 0x2a, 0x20, 0x57, 0x49, 0x54, 0x48,
+    0x4f, 0x55, 0x54, 0x20, 0x41, 0x4e, 0x59, 0x20,
+    0x57, 0x41, 0x52, 0x52, 0x41, 0x4e, 0x54, 0x59,
+    0x3b, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75,
+    0x74, 0x20, 0x65, 0x76, 0x65, 0x6e, 0x20, 0x74,
+    0x68, 0x65, 0x20, 0x69, 0x6d, 0x70, 0x6c, 0x69,
+    0x65, 0x64, 0x20, 0x77, 0x61, 0x72, 0x72, 0x61,
+    0x6e, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x0a, 0x20,
+    0x2a, 0x20, 0x4d, 0x45, 0x52, 0x43, 0x48, 0x41,
+    0x4e, 0x54, 0x41, 0x42, 0x49, 0x4c, 0x49, 0x54,
+    0x59, 0x20, 0x6f, 0x72, 0x20, 0x46, 0x49, 0x54,
+    0x4e, 0x45, 0x53, 0x53, 0x20, 0x46, 0x4f, 0x52,
+    0x20, 0x41, 0x20, 0x50, 0x41, 0x52, 0x54, 0x49,
+    0x43, 0x55, 0x4c, 0x41, 0x52, 0x20, 0x50, 0x55,
+    0x52, 0x50, 0x4f, 0x53, 0x45, 0x2e, 0x20, 0x20,
+    0x53, 0x65, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20,
+    0x47, 0x4e, 0x55, 0x0a, 0x20, 0x2a, 0x20, 0x47,
+    0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c, 0x20, 0x50,
+    0x75, 0x62, 0x6c, 0x69, 0x63, 0x20, 0x4c, 0x69,
+    0x63, 0x65, 0x6e, 0x73, 0x65, 0x20, 0x66, 0x6f,
+    0x72, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x64,
+    0x65, 0x74, 0x61, 0x69, 0x6c, 0x73, 0x2e, 0x0a,
+    0x20, 0x2a, 0x0a, 0x20, 0x2a, 0x20, 0x59, 0x6f,
+    0x75, 0x20, 0x73, 0x68, 0x6f, 0x75, 0x6c, 0x64,
+    0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x72, 0x65,
+    0x63, 0x65, 0x69, 0x76, 0x65, 0x64, 0x20, 0x61,
+    0x20, 0x63, 0x6f, 0x70, 0x79, 0x20, 0x6f, 0x66,
+    0x20, 0x74, 0x68, 0x65, 0x20, 0x47, 0x4e, 0x55,
+    0x20, 0x47, 0x65, 0x6e, 0x65, 0x72, 0x61, 0x6c,
+    0x20, 0x50, 0x75, 0x62, 0x6c, 0x69, 0x63, 0x20,
+    0x4c, 0x69, 0x63, 0x65, 0x6e, 0x73, 0x65, 0x0a,
+    0x20, 0x2a, 0x20, 0x61, 0x6c, 0x6f, 0x6e, 0x67,
+    0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68,
+    0x69, 0x73, 0x20, 0x70, 0x72, 0x6f, 0x67, 0x72,
+    0x61, 0x6d, 0x3b, 0x20, 0x73, 0x65, 0x65, 0x20,
+    0x74, 0x68, 0x65, 0x20, 0x66, 0x69, 0x6c, 0x65,
+    0x20, 0x43, 0x4f, 0x50, 0x59, 0x49, 0x4e, 0x47,
+    0x2e, 0x20, 0x20, 0x49, 0x66, 0x20, 0x6e, 0x6f,
+    0x74, 0x2c, 0x20, 0x77, 0x72, 0x69, 0x74, 0x65,
+    0x20, 0x74, 0x6f, 0x0a, 0x20, 0x2a, 0x20, 0x74,
+    0x68, 0x65, 0x20, 0x46, 0x72, 0x65, 0x65, 0x20,
+    0x53, 0x6f, 0x66, 0x74, 0x77, 0x61, 0x72, 0x65,
+    0x20, 0x46, 0x6f, 0x75, 0x6e, 0x64, 0x61, 0x74,
+    0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x35, 0x31, 0x20,
+    0x46, 0x72, 0x61, 0x6e, 0x6b, 0x6c, 0x69, 0x6e,
+    0x20, 0x53, 0x74, 0x72, 0x65, 0x65, 0x74, 0x2c,
+    0x20, 0x46, 0x69, 0x66, 0x74, 0x68, 0x20, 0x46,
+    0x6c, 0x6f, 0x6f, 0x72, 0x2c, 0x0a, 0x20, 0x2a,
+    0x20, 0x42, 0x6f, 0x73, 0x74, 0x6f, 0x6e, 0x2c,
+    0x20, 0x4d, 0x41, 0x20, 0x30, 0x32, 0x31, 0x31,
+    0x30, 0x2d, 0x31, 0x33, 0x30, 0x31, 0x2c, 0x20,
+    0x55, 0x53, 0x41, 0x2e, 0x0a, 0x20, 0x2a, 0x2f,
+    0x0a,
+};
+
+/*
+ * SHA1 Hashes
+ */
+static char *commit_id = "3d7f8a6af076c8c3f20071a8935cdbe8228594d1";
+static char *tree_id = "dff2da90b254e1beb889d1f1f1288be1803782df";
+static char *tag_id = "09d373e1dfdc16b129ceec6dd649739911541e05";
+static char *zero_id = "e69de29bb2d1d6434b8b29ae775ad8c2e48c5391";
+static char *one_id = "8b137891791fe96927ad78e64b0aad7bded08bdc";
+static char *two_id = "78981922613b2afb6025042ff6bd878ac1994e85";
+static char *some_id = "fd8430bc864cfcd5f10e5590f8a447e01b942bfe";
+
+/*
+ * In-memory objects
+ */
+static git_rawobj tree_obj = {
+	tree_data,
+	sizeof(tree_data),
+	GIT_OBJ_TREE
+};
+
+static git_rawobj tag_obj = {
+	tag_data,
+	sizeof(tag_data),
+	GIT_OBJ_TAG
+};
+
+static git_rawobj zero_obj = {
+	zero_data,
+	0,
+	GIT_OBJ_BLOB
+};
+
+static git_rawobj one_obj = {
+	one_data,
+	sizeof(one_data),
+	GIT_OBJ_BLOB
+};
+
+static git_rawobj two_obj = {
+	two_data,
+	sizeof(two_data),
+	GIT_OBJ_BLOB
+};
+
+static git_rawobj commit_obj = {
+	commit_data,
+	sizeof(commit_data),
+	GIT_OBJ_COMMIT
+};
+
+static git_rawobj some_obj = {
+	some_data,
+	sizeof(some_data),
+	GIT_OBJ_BLOB
+};
+
+static git_rawobj junk_obj = {
+	NULL,
+	0,
+	GIT_OBJ_BAD
+};
diff --git a/tests-clay/object/raw/fromstr.c b/tests-clay/object/raw/fromstr.c
new file mode 100644
index 0000000..6d732d4
--- /dev/null
+++ b/tests-clay/object/raw/fromstr.c
@@ -0,0 +1,30 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+
+void test_object_raw_fromstr__fail_on_invalid_oid_string(void)
+{
+	git_oid out;
+	cl_git_fail(git_oid_fromstr(&out, ""));
+	cl_git_fail(git_oid_fromstr(&out, "moo"));
+	cl_git_fail(git_oid_fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5ez"));
+}
+
+void test_object_raw_fromstr__succeed_on_valid_oid_string(void)
+{
+	git_oid out;
+	unsigned char exp[] = {
+		0x16, 0xa6, 0x77, 0x70, 0xb7,
+		0xd8, 0xd7, 0x23, 0x17, 0xc4,
+		0xb7, 0x75, 0x21, 0x3c, 0x23,
+		0xa8, 0xbd, 0x74, 0xf5, 0xe0,
+	};
+
+	cl_git_pass(git_oid_fromstr(&out, "16a67770b7d8d72317c4b775213c23a8bd74f5e0"));
+	cl_git_pass(memcmp(out.id, exp, sizeof(out.id)));
+
+	cl_git_pass(git_oid_fromstr(&out, "16A67770B7D8D72317C4b775213C23A8BD74F5E0"));
+	cl_git_pass(memcmp(out.id, exp, sizeof(out.id)));
+
+}
diff --git a/tests-clay/object/raw/hash.c b/tests-clay/object/raw/hash.c
new file mode 100644
index 0000000..9974ed6
--- /dev/null
+++ b/tests-clay/object/raw/hash.c
@@ -0,0 +1,162 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+#include "hash.h"
+
+#include "data.h"
+
+static int hash_object(git_oid *oid, git_rawobj *obj)
+{
+	return git_odb_hash(oid, obj->data, obj->len, obj->type);
+}
+
+static char *hello_id = "22596363b3de40b06f981fb85d82312e8c0ed511";
+static char *hello_text = "hello world\n";
+
+static char *bye_id = "ce08fe4884650f067bd5703b6a59a8b3b3c99a09";
+static char *bye_text = "bye world\n";
+
+void test_object_raw_hash__hash_by_blocks(void)
+{
+    git_hash_ctx *ctx;
+    git_oid id1, id2;
+
+    cl_assert((ctx = git_hash_new_ctx()) != NULL);
+
+	/* should already be init'd */
+    git_hash_update(ctx, hello_text, strlen(hello_text));
+    git_hash_final(&id2, ctx);
+    cl_git_pass(git_oid_fromstr(&id1, hello_id));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+
+	/* reinit should permit reuse */
+    git_hash_init(ctx);
+    git_hash_update(ctx, bye_text, strlen(bye_text));
+    git_hash_final(&id2, ctx);
+    cl_git_pass(git_oid_fromstr(&id1, bye_id));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+
+    git_hash_free_ctx(ctx);
+}
+
+void test_object_raw_hash__hash_buffer_in_single_call(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, hello_id));
+    git_hash_buf(&id2, hello_text, strlen(hello_text));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_vector(void)
+{
+    git_oid id1, id2;
+    git_buf_vec vec[2];
+
+    cl_git_pass(git_oid_fromstr(&id1, hello_id));
+
+    vec[0].data = hello_text;
+    vec[0].len  = 4;
+    vec[1].data = hello_text+4;
+    vec[1].len  = strlen(hello_text)-4;
+
+    git_hash_vec(&id2, vec, 2);
+
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_junk_data(void)
+{
+    git_oid id, id_zero;
+
+    cl_git_pass(git_oid_fromstr(&id_zero, zero_id));
+
+    /* invalid types: */
+    junk_obj.data = some_data;
+    cl_git_fail(hash_object(&id, &junk_obj));
+
+    junk_obj.type = GIT_OBJ__EXT1;
+    cl_git_fail(hash_object(&id, &junk_obj));
+
+    junk_obj.type = GIT_OBJ__EXT2;
+    cl_git_fail(hash_object(&id, &junk_obj));
+
+    junk_obj.type = GIT_OBJ_OFS_DELTA;
+    cl_git_fail(hash_object(&id, &junk_obj));
+
+    junk_obj.type = GIT_OBJ_REF_DELTA;
+    cl_git_fail(hash_object(&id, &junk_obj));
+
+    /* data can be NULL only if len is zero: */
+    junk_obj.type = GIT_OBJ_BLOB;
+    junk_obj.data = NULL;
+    cl_git_pass(hash_object(&id, &junk_obj));
+    cl_assert(git_oid_cmp(&id, &id_zero) == 0);
+
+    junk_obj.len = 1;
+    cl_git_fail(hash_object(&id, &junk_obj));
+}
+
+void test_object_raw_hash__hash_commit_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, commit_id));
+    cl_git_pass(hash_object(&id2, &commit_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_tree_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, tree_id));
+    cl_git_pass(hash_object(&id2, &tree_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_tag_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, tag_id));
+    cl_git_pass(hash_object(&id2, &tag_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_zero_length_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, zero_id));
+    cl_git_pass(hash_object(&id2, &zero_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_one_byte_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, one_id));
+    cl_git_pass(hash_object(&id2, &one_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_two_byte_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, two_id));
+    cl_git_pass(hash_object(&id2, &two_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
+
+void test_object_raw_hash__hash_multi_byte_object(void)
+{
+    git_oid id1, id2;
+
+    cl_git_pass(git_oid_fromstr(&id1, some_id));
+    cl_git_pass(hash_object(&id2, &some_obj));
+    cl_assert(git_oid_cmp(&id1, &id2) == 0);
+}
diff --git a/tests-clay/object/raw/short.c b/tests-clay/object/raw/short.c
new file mode 100644
index 0000000..996f3f7
--- /dev/null
+++ b/tests-clay/object/raw/short.c
@@ -0,0 +1,94 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+#include "hash.h"
+
+void test_object_raw_short__oid_shortener_no_duplicates(void)
+{
+	git_oid_shorten *os;
+	int min_len;
+
+	os = git_oid_shorten_new(0);
+	cl_assert(os != NULL);
+
+	git_oid_shorten_add(os, "22596363b3de40b06f981fb85d82312e8c0ed511");
+	git_oid_shorten_add(os, "ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
+	git_oid_shorten_add(os, "16a0123456789abcdef4b775213c23a8bd74f5e0");
+	min_len = git_oid_shorten_add(os, "ce08fe4884650f067bd5703b6a59a8b3b3c99a09");
+
+	cl_assert(min_len == GIT_OID_HEXSZ + 1);
+
+	git_oid_shorten_free(os);
+}
+
+void test_object_raw_short__oid_shortener_stresstest_git_oid_shorten(void)
+{
+#define MAX_OIDS 1000
+
+	git_oid_shorten *os;
+	char *oids[MAX_OIDS];
+	char number_buffer[16];
+	git_oid oid;
+	size_t i, j;
+
+	int min_len = 0, found_collision;
+
+	os = git_oid_shorten_new(0);
+	cl_assert(os != NULL);
+
+	/*
+	 * Insert in the shortener 1000 unique SHA1 ids
+	 */
+	for (i = 0; i < MAX_OIDS; ++i) {
+		char *oid_text;
+
+		sprintf(number_buffer, "%u", (unsigned int)i);
+		git_hash_buf(&oid, number_buffer, strlen(number_buffer));
+
+		oid_text = git__malloc(GIT_OID_HEXSZ + 1);
+		git_oid_fmt(oid_text, &oid);
+		oid_text[GIT_OID_HEXSZ] = 0;
+
+		min_len = git_oid_shorten_add(os, oid_text);
+		cl_assert(min_len >= 0);
+
+		oids[i] = oid_text;
+	}
+
+	/*
+	 * Compare the first `min_char - 1` characters of each
+	 * SHA1 OID. If the minimizer worked, we should find at
+	 * least one collision
+	 */
+	found_collision = 0;
+	for (i = 0; i < MAX_OIDS; ++i) {
+		for (j = 0; j < MAX_OIDS; ++j) {
+			if (i != j && memcmp(oids[i], oids[j], min_len - 1) == 0)
+				found_collision = 1;
+		}
+	}
+	cl_assert(found_collision == 1);
+
+	/*
+	 * Compare the first `min_char` characters of each
+	 * SHA1 OID. If the minimizer worked, every single preffix
+	 * should be unique.
+	 */
+	found_collision = 0;
+	for (i = 0; i < MAX_OIDS; ++i) {
+		for (j = 0; j < MAX_OIDS; ++j) {
+			if (i != j && memcmp(oids[i], oids[j], min_len) == 0)
+				found_collision = 1;
+		}
+	}
+	cl_assert(found_collision == 0);
+
+	/* cleanup */
+	for (i = 0; i < MAX_OIDS; ++i)
+		git__free(oids[i]);
+
+	git_oid_shorten_free(os);
+
+#undef MAX_OIDS
+}
diff --git a/tests-clay/object/raw/size.c b/tests-clay/object/raw/size.c
new file mode 100644
index 0000000..44c5b6c
--- /dev/null
+++ b/tests-clay/object/raw/size.c
@@ -0,0 +1,13 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+
+void test_object_raw_size__validate_oid_size(void)
+{
+	git_oid out;
+	cl_assert(20 == GIT_OID_RAWSZ);
+	cl_assert(40 == GIT_OID_HEXSZ);
+	cl_assert(sizeof(out) == GIT_OID_RAWSZ);
+	cl_assert(sizeof(out.id) == GIT_OID_RAWSZ);
+}
diff --git a/tests-clay/object/raw/type2string.c b/tests-clay/object/raw/type2string.c
new file mode 100644
index 0000000..109bc11
--- /dev/null
+++ b/tests-clay/object/raw/type2string.c
@@ -0,0 +1,54 @@
+
+#include "clay_libgit2.h"
+
+#include "odb.h"
+#include "hash.h"
+
+void test_object_raw_type2string__convert_type_to_string(void)
+{
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_BAD), ""));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ__EXT1), ""));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_COMMIT), "commit"));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_TREE), "tree"));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_BLOB), "blob"));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_TAG), "tag"));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ__EXT2), ""));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_OFS_DELTA), "OFS_DELTA"));
+	cl_assert(!strcmp(git_object_type2string(GIT_OBJ_REF_DELTA), "REF_DELTA"));
+
+	cl_assert(!strcmp(git_object_type2string(-2), ""));
+	cl_assert(!strcmp(git_object_type2string(8), ""));
+	cl_assert(!strcmp(git_object_type2string(1234), ""));
+}
+
+void test_object_raw_type2string__convert_string_to_type(void)
+{
+	cl_assert(git_object_string2type(NULL) == GIT_OBJ_BAD);
+	cl_assert(git_object_string2type("") == GIT_OBJ_BAD);
+	cl_assert(git_object_string2type("commit") == GIT_OBJ_COMMIT);
+	cl_assert(git_object_string2type("tree") == GIT_OBJ_TREE);
+	cl_assert(git_object_string2type("blob") == GIT_OBJ_BLOB);
+	cl_assert(git_object_string2type("tag") == GIT_OBJ_TAG);
+	cl_assert(git_object_string2type("OFS_DELTA") == GIT_OBJ_OFS_DELTA);
+	cl_assert(git_object_string2type("REF_DELTA") == GIT_OBJ_REF_DELTA);
+
+	cl_assert(git_object_string2type("CoMmIt") == GIT_OBJ_BAD);
+	cl_assert(git_object_string2type("hohoho") == GIT_OBJ_BAD);
+}
+
+void test_object_raw_type2string__check_type_is_loose(void)
+{
+	cl_assert(git_object_typeisloose(GIT_OBJ_BAD) == 0);
+	cl_assert(git_object_typeisloose(GIT_OBJ__EXT1) == 0);
+	cl_assert(git_object_typeisloose(GIT_OBJ_COMMIT) == 1);
+	cl_assert(git_object_typeisloose(GIT_OBJ_TREE) == 1);
+	cl_assert(git_object_typeisloose(GIT_OBJ_BLOB) == 1);
+	cl_assert(git_object_typeisloose(GIT_OBJ_TAG) == 1);
+	cl_assert(git_object_typeisloose(GIT_OBJ__EXT2) == 0);
+	cl_assert(git_object_typeisloose(GIT_OBJ_OFS_DELTA) == 0);
+	cl_assert(git_object_typeisloose(GIT_OBJ_REF_DELTA) == 0);
+
+	cl_assert(git_object_typeisloose(-2) == 0);
+	cl_assert(git_object_typeisloose(8) == 0);
+	cl_assert(git_object_typeisloose(1234) == 0);
+}
diff --git a/tests-clay/object/tree/frompath.c b/tests-clay/object/tree/frompath.c
index 23cb416..651a86d 100644
--- a/tests-clay/object/tree/frompath.c
+++ b/tests-clay/object/tree/frompath.c
@@ -30,7 +30,7 @@
 {
 	git_tree *containing_tree = NULL;
 
-	cl_assert(git_tree_frompath(&containing_tree, root, path) == expected_result);
+	cl_assert(git_tree_get_subtree(&containing_tree, root, path) == expected_result);
 	
 	if (containing_tree == NULL && expected_result != GIT_SUCCESS)
 		return;
diff --git a/tests-clay/status/single.c b/tests-clay/status/single.c
index ea1c77f..4fd6e6f 100644
--- a/tests-clay/status/single.c
+++ b/tests-clay/status/single.c
@@ -10,7 +10,7 @@
 static void
 file_create(const char *filename, const char *content)
 {
-	int fd = p_creat(filename, 0644);
+	int fd = p_creat(filename, 0666);
 	cl_assert(fd >= 0);
 	cl_must_pass(p_write(fd, content, strlen(content)));
 	cl_must_pass(p_close(fd));
diff --git a/tests-clay/status/worktree.c b/tests-clay/status/worktree.c
index 74dfd48..7d120ec 100644
--- a/tests-clay/status/worktree.c
+++ b/tests-clay/status/worktree.c
@@ -71,7 +71,7 @@
 	 * inside the fixtures folder in our libgit2 repo.
 	 */
 	cl_git_pass(
-		git_futils_mv_atomic("status/.gitted", "status/.git")
+		p_rename("status/.gitted", "status/.git")
 	);
 
 	/*
diff --git a/tests/resources/status/.gitted/COMMIT_EDITMSG b/tests/resources/status/.gitted/COMMIT_EDITMSG
index ff887ba..1a25cd4 100644
--- a/tests/resources/status/.gitted/COMMIT_EDITMSG
+++ b/tests/resources/status/.gitted/COMMIT_EDITMSG
@@ -1 +1 @@
-add subdir
+Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker
diff --git a/tests/resources/status/.gitted/ORIG_HEAD b/tests/resources/status/.gitted/ORIG_HEAD
index c2805f4..b46871f 100644
--- a/tests/resources/status/.gitted/ORIG_HEAD
+++ b/tests/resources/status/.gitted/ORIG_HEAD
@@ -1 +1 @@
-0017bd4ab1ec30440b17bae1680cff124ab5f1f6
+735b6a258cd196a8f7c9428419b02c1dca93fd75
diff --git a/tests/resources/status/.gitted/index b/tests/resources/status/.gitted/index
index 5c4b188..d793791 100644
--- a/tests/resources/status/.gitted/index
+++ b/tests/resources/status/.gitted/index
Binary files differ
diff --git a/tests/resources/status/.gitted/logs/HEAD b/tests/resources/status/.gitted/logs/HEAD
index e876bd8..7b95b3c 100644
--- a/tests/resources/status/.gitted/logs/HEAD
+++ b/tests/resources/status/.gitted/logs/HEAD
@@ -1,2 +1,3 @@
 0000000000000000000000000000000000000000 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 Jason Penny <jasonpenny4@gmail.com> 1308050070 -0400	commit (initial): initial
 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 735b6a258cd196a8f7c9428419b02c1dca93fd75 Jason Penny <jasonpenny4@gmail.com> 1308954538 -0400	commit: add subdir
+735b6a258cd196a8f7c9428419b02c1dca93fd75 26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f nulltoken <emeric.fermas@gmail.com> 1319911544 +0200	commit: Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker
diff --git a/tests/resources/status/.gitted/logs/refs/heads/master b/tests/resources/status/.gitted/logs/refs/heads/master
index e876bd8..7b95b3c 100644
--- a/tests/resources/status/.gitted/logs/refs/heads/master
+++ b/tests/resources/status/.gitted/logs/refs/heads/master
@@ -1,2 +1,3 @@
 0000000000000000000000000000000000000000 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 Jason Penny <jasonpenny4@gmail.com> 1308050070 -0400	commit (initial): initial
 0017bd4ab1ec30440b17bae1680cff124ab5f1f6 735b6a258cd196a8f7c9428419b02c1dca93fd75 Jason Penny <jasonpenny4@gmail.com> 1308954538 -0400	commit: add subdir
+735b6a258cd196a8f7c9428419b02c1dca93fd75 26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f nulltoken <emeric.fermas@gmail.com> 1319911544 +0200	commit: Add a file which name should appear before the "subdir/" folder while being dealt with by the treewalker
diff --git a/tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f b/tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f
new file mode 100644
index 0000000..f7dddc4
--- /dev/null
+++ b/tests/resources/status/.gitted/objects/26/a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f
Binary files differ
diff --git a/tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0 b/tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0
new file mode 100644
index 0000000..b75481b
--- /dev/null
+++ b/tests/resources/status/.gitted/objects/37/fcb02ccc1a85d1941e7f106d52dc3702dcf0d0
Binary files differ
diff --git a/tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e b/tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e
new file mode 100644
index 0000000..cfc2413
--- /dev/null
+++ b/tests/resources/status/.gitted/objects/e8/ee89e15bbe9b20137715232387b3de5b28972e
Binary files differ
diff --git a/tests/resources/status/.gitted/refs/heads/master b/tests/resources/status/.gitted/refs/heads/master
index b46871f..3e2e2a0 100644
--- a/tests/resources/status/.gitted/refs/heads/master
+++ b/tests/resources/status/.gitted/refs/heads/master
@@ -1 +1 @@
-735b6a258cd196a8f7c9428419b02c1dca93fd75
+26a125ee1bfc5df1e1b2e9441bbe63c8a7ae989f
diff --git a/tests/resources/status/subdir.txt b/tests/resources/status/subdir.txt
new file mode 100644
index 0000000..e8ee89e
--- /dev/null
+++ b/tests/resources/status/subdir.txt
@@ -0,0 +1,2 @@
+Is it a bird?
+Is it a plane?
diff --git a/tests/t00-core.c b/tests/t00-core.c
index 703504b..94824b4 100644
--- a/tests/t00-core.c
+++ b/tests/t00-core.c
@@ -99,8 +99,8 @@
 	must_be_true(x.length == 2);
 	git_vector_free(&x);
 
-	free(ptrs[0]);
-	free(ptrs[1]);
+	git__free(ptrs[0]);
+	git__free(ptrs[1]);
 END_TEST
 
 
@@ -112,7 +112,7 @@
 	must_be_true(strcmp(dir, B) == 0);				\
 	must_be_true((dir2 = git_path_dirname(A)) != NULL);	\
 	must_be_true(strcmp(dir2, B) == 0);				\
-	free(dir2);										\
+	git__free(dir2);										\
 }
 
 	DIRNAME_TEST(NULL, ".");
@@ -141,7 +141,7 @@
 	must_be_true(strcmp(base, B) == 0);					\
 	must_be_true((base2 = git_path_basename(A)) != NULL);	\
 	must_be_true(strcmp(base2, B) == 0);				\
-	free(base2);										\
+	git__free(base2);										\
 }
 
 	BASENAME_TEST(NULL, ".");
@@ -250,21 +250,21 @@
 {
 	name_data *n;
 
-	if (p_mkdir(top_dir, 0755) < 0)
+	if (p_mkdir(top_dir, 0777) < 0)
 		return error("can't mkdir(\"%s\")", top_dir);
 
 	if (p_chdir(top_dir) < 0)
 		return error("can't chdir(\"%s\")", top_dir);
 
 	if (strcmp(d->sub, ".") != 0)
-		if (p_mkdir(d->sub, 0755) < 0)
+		if (p_mkdir(d->sub, 0777) < 0)
 			return error("can't mkdir(\"%s\")", d->sub);
 
 	strcpy(path_buffer, d->sub);
 	state_loc = d;
 
 	for (n = d->names; n->name; n++) {
-		git_file fd = p_creat(n->name, 0600);
+		git_file fd = p_creat(n->name, 0666);
 		if (fd < 0)
 			return GIT_ERROR;
 		p_close(fd);
@@ -479,14 +479,14 @@
 	int fd;
 	char test[] = "test";
 
-	fd = p_creat(test, 0644);
+	fd = p_creat(test, 0666);
 	must_pass(fd);
 	must_pass(p_write(fd, "libgit2 rocks\n", 14));
 	must_pass(p_close(fd));
 
 	must_pass(git_filebuf_open(&file, test, GIT_FILEBUF_APPEND));
 	must_pass(git_filebuf_printf(&file, "%s\n", "libgit2 rocks"));
-	must_pass(git_filebuf_commit(&file));
+	must_pass(git_filebuf_commit(&file, 0666));
 
 	must_pass(p_unlink(test));
 END_TEST
@@ -499,7 +499,7 @@
 	memset(buf, 0xfe, sizeof(buf));
 	must_pass(git_filebuf_open(&file, test, 0));
 	must_pass(git_filebuf_write(&file, buf, sizeof(buf)));
-	must_pass(git_filebuf_commit(&file));
+	must_pass(git_filebuf_commit(&file, 0666));
 
 	must_pass(p_unlink(test));
 END_TEST
@@ -510,27 +510,27 @@
 {
 	char path[GIT_PATH_MAX];
 
-	if (p_mkdir(empty_tmp_dir, 0755))
+	if (p_mkdir(empty_tmp_dir, 0777))
 		return -1;
 
 	git_path_join(path, empty_tmp_dir, "/one");
-	if (p_mkdir(path, 0755))
+	if (p_mkdir(path, 0777))
 		return -1;
 
 	git_path_join(path, empty_tmp_dir, "/one/two_one");
-	if (p_mkdir(path, 0755))
+	if (p_mkdir(path, 0777))
 		return -1;
 
 	git_path_join(path, empty_tmp_dir, "/one/two_two");
-	if (p_mkdir(path, 0755))
+	if (p_mkdir(path, 0777))
 		return -1;
 
 	git_path_join(path, empty_tmp_dir, "/one/two_two/three");
-	if (p_mkdir(path, 0755))
+	if (p_mkdir(path, 0777))
 		return -1;
 
 	git_path_join(path, empty_tmp_dir, "/two");
-	if (p_mkdir(path, 0755))
+	if (p_mkdir(path, 0777))
 		return -1;
 
 	return 0;
@@ -547,7 +547,7 @@
 
 	must_pass(setup_empty_tmp_dir());
 	git_path_join(file, empty_tmp_dir, "/two/file.txt");
-	fd = p_creat(file, 0755);
+	fd = p_creat(file, 0777);
 	must_pass(fd);
 	must_pass(p_close(fd));
 	must_fail(git_futils_rmdir_r(empty_tmp_dir, 0));
diff --git a/tests/t01-rawobj.c b/tests/t01-rawobj.c
index 2552085..8b05f33 100644
--- a/tests/t01-rawobj.c
+++ b/tests/t01-rawobj.c
@@ -217,7 +217,7 @@
 	out = git_oid_allocfmt(&in);
 	must_be_true(out);
 	must_be_true(strcmp(exp, out) == 0);
-	free(out);
+	git__free(out);
 END_TEST
 
 BEGIN_TEST(oid13, "compare oids (path format)")
@@ -390,7 +390,7 @@
 
 	/* cleanup */
 	for (i = 0; i < MAX_OIDS; ++i)
-		free(oids[i]);
+		git__free(oids[i]);
 
 	git_oid_shorten_free(os);
 
diff --git a/tests/t03-objwrite.c b/tests/t03-objwrite.c
index 31f611a..7563d0e 100644
--- a/tests/t03-objwrite.c
+++ b/tests/t03-objwrite.c
@@ -31,7 +31,7 @@
 
 static int make_odb_dir(void)
 {
-	if (p_mkdir(odb_dir, 0755) < 0) {
+	if (p_mkdir(odb_dir, GIT_OBJECT_DIR_MODE) < 0) {
 		int err = errno;
 		fprintf(stderr, "can't make directory \"%s\"", odb_dir);
 		if (err == EEXIST)
diff --git a/tests/t04-commit.c b/tests/t04-commit.c
index 3fb4d37..d0bb1b5 100644
--- a/tests/t04-commit.c
+++ b/tests/t04-commit.c
@@ -162,7 +162,7 @@
 	must_be_true(strcmp(_email, person.email) == 0);\
 	must_be_true(_time == person.when.time);\
 	must_be_true(_offset == person.when.offset);\
-	free(person.name); free(person.email);\
+	git__free(person.name); git__free(person.email);\
 }
 
 #define TEST_SIGNATURE_FAIL(_string, _header) { \
@@ -170,7 +170,7 @@
 	size_t len = strlen(_string);\
 	git_signature person = {NULL, NULL, {0, 0}}; \
 	must_fail(git_signature__parse(&person, &ptr, ptr + len, _header, '\n'));\
-	free(person.name); free(person.email);\
+	git__free(person.name); git__free(person.email);\
 }
 
 	TEST_SIGNATURE_PASS(
@@ -690,6 +690,10 @@
 
 	must_be_true(strcmp(git_commit_message(commit), COMMIT_MESSAGE) == 0);
 
+#ifndef GIT_WIN32
+	must_be_true((loose_object_mode(REPOSITORY_FOLDER, (git_object *)commit) & 0777) == GIT_OBJECT_FILE_MODE);
+#endif
+
 	must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
 
 	git_commit_close(commit);
@@ -759,9 +763,11 @@
 	must_pass(git_reference_set_target(head, head_old));
 	must_pass(git_reference_delete(branch));
 	must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)commit));
-	free(head_old);
+	git__free(head_old);
 	git_commit_close(commit);
 	git_repository_free(repo);
+
+	git_reference_free(head);
 END_TEST
 
 BEGIN_SUITE(commit)
diff --git a/tests/t06-index.c b/tests/t06-index.c
index 621e742..44562d0 100644
--- a/tests/t06-index.c
+++ b/tests/t06-index.c
@@ -176,10 +176,10 @@
 	must_pass(git_index_entrycount(index) == 0);
 
 	/* Create a new file in the working directory */
-	must_pass(git_futils_mkpath2file(TEMP_REPO_FOLDER "myrepo/test.txt"));
+	must_pass(git_futils_mkpath2file(TEMP_REPO_FOLDER "myrepo/test.txt", 0777));
 	must_pass(git_filebuf_open(&file, TEMP_REPO_FOLDER "myrepo/test.txt", 0));
 	must_pass(git_filebuf_write(&file, "hey there\n", 10));
-	must_pass(git_filebuf_commit(&file));
+	must_pass(git_filebuf_commit(&file, 0666));
 
 	/* Store the expected hash of the file/blob
 	 * This has been generated by executing the following
diff --git a/tests/t07-hashtable.c b/tests/t07-hashtable.c
index c0e8522..41d52af 100644
--- a/tests/t07-hashtable.c
+++ b/tests/t07-hashtable.c
@@ -103,7 +103,7 @@
 	}
 
 	git_hashtable_free(table);
-	free(objects);
+	git__free(objects);
 
 END_TEST
 
@@ -145,7 +145,7 @@
 	}
 
 	git_hashtable_free(table);
-	free(objects);
+	git__free(objects);
 
 END_TEST
 
@@ -179,7 +179,7 @@
 		must_be_true(objects[i].visited);
 
 	git_hashtable_free(table);
-	free(objects);
+	git__free(objects);
 END_TEST
 
 
diff --git a/tests/t08-tag.c b/tests/t08-tag.c
index 216fb9d..44efb58 100644
--- a/tests/t08-tag.c
+++ b/tests/t08-tag.c
@@ -189,12 +189,14 @@
 	must_pass(git_reference_lookup(&ref_tag, repo, "refs/tags/the-tag"));
 	must_be_true(git_oid_cmp(git_reference_oid(ref_tag), &tag_id) == 0);
 	must_pass(git_reference_delete(ref_tag));
+#ifndef GIT_WIN32
+	must_be_true((loose_object_mode(REPOSITORY_FOLDER, (git_object *)tag) & 0777) == GIT_OBJECT_FILE_MODE);
+#endif
 
 	must_pass(remove_loose_object(REPOSITORY_FOLDER, (git_object *)tag));
 
 	git_tag_close(tag);
 	git_repository_free(repo);
-
 END_TEST
 
 BEGIN_TEST(write2, "Attempt to write a tag bearing the same name than an already existing tag")
@@ -263,6 +265,7 @@
 
 	close_temp_repo(repo);
 
+	git_reference_free(ref_tag);
 END_TEST
 
 BEGIN_TEST(write4, "write a lightweight tag to the repository and read it again")
@@ -293,6 +296,8 @@
 	must_pass(git_tag_delete(repo, "light-tag"));
 
 	git_repository_free(repo);
+
+	git_reference_free(ref_tag);
 END_TEST
 
 BEGIN_TEST(write5, "Attempt to write a lightweight tag bearing the same name than an already existing tag")
@@ -331,6 +336,8 @@
 	must_fail(git_reference_lookup(&ref_tag, repo, "refs/tags/e90810b"));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref_tag);
 END_TEST
 
 BEGIN_SUITE(tag)
diff --git a/tests/t09-tree.c b/tests/t09-tree.c
index 3af06ea..2341a1c 100644
--- a/tests/t09-tree.c
+++ b/tests/t09-tree.c
@@ -200,6 +200,10 @@
 	// check data is correct
 	must_pass(git_tree_lookup(&tree, repo, &id_hiearar));
 	must_be_true(2 == git_tree_entrycount(tree));
+#ifndef GIT_WIN32
+	must_be_true((loose_object_dir_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_DIR_MODE);
+	must_be_true((loose_object_mode(TEMP_REPO_FOLDER, (git_object *)tree) & 0777) == GIT_OBJECT_FILE_MODE);
+#endif
 	git_tree_close(tree);
 
 	close_temp_repo(repo);
diff --git a/tests/t10-refs.c b/tests/t10-refs.c
index c7bfe4e..e5e7229 100644
--- a/tests/t10-refs.c
+++ b/tests/t10-refs.c
@@ -42,8 +42,8 @@
 	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name));
-	must_be_true(reference->type & GIT_REF_OID);
-	must_be_true((reference->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_type(reference) & GIT_REF_OID);
+	must_be_true(git_reference_is_packed(reference) == 0);
 	must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
 
 	must_pass(git_object_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY));
@@ -56,6 +56,8 @@
 
 	git_object_close(object);
 	git_repository_free(repo);
+
+	git_reference_free(reference);
 END_TEST
 
 BEGIN_TEST(readtag1, "lookup a loose tag reference that doesn't exist")
@@ -66,6 +68,8 @@
 	must_fail(git_reference_lookup(&reference, repo, non_existing_tag_ref_name));
 
 	git_repository_free(repo);
+
+	git_reference_free(reference);
 END_TEST
 
 static const char *head_tracker_sym_ref_name = "head-tracker";
@@ -81,12 +85,12 @@
 	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE));
-	must_be_true(reference->type & GIT_REF_SYMBOLIC);
-	must_be_true((reference->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_type(reference) & GIT_REF_SYMBOLIC);
+	must_be_true(git_reference_is_packed(reference) == 0);
 	must_be_true(strcmp(reference->name, GIT_HEAD_FILE) == 0);
 
 	must_pass(git_reference_resolve(&resolved_ref, reference));
-	must_be_true(resolved_ref->type == GIT_REF_OID);
+	must_be_true(git_reference_type(resolved_ref) == GIT_REF_OID);
 
 	must_pass(git_object_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY));
 	must_be_true(object != NULL);
@@ -97,6 +101,9 @@
 
 	git_object_close(object);
 	git_repository_free(repo);
+
+	git_reference_free(reference);
+	git_reference_free(resolved_ref);
 END_TEST
 
 BEGIN_TEST(readsym1, "lookup a nested symbolic reference")
@@ -108,12 +115,12 @@
 	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&reference, repo, head_tracker_sym_ref_name));
-	must_be_true(reference->type & GIT_REF_SYMBOLIC);
-	must_be_true((reference->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_type(reference) & GIT_REF_SYMBOLIC);
+	must_be_true(git_reference_is_packed(reference) == 0);
 	must_be_true(strcmp(reference->name, head_tracker_sym_ref_name) == 0);
 
 	must_pass(git_reference_resolve(&resolved_ref, reference));
-	must_be_true(resolved_ref->type == GIT_REF_OID);
+	must_be_true(git_reference_type(resolved_ref) == GIT_REF_OID);
 
 	must_pass(git_object_lookup(&object, repo, git_reference_oid(resolved_ref), GIT_OBJ_ANY));
 	must_be_true(object != NULL);
@@ -124,6 +131,9 @@
 
 	git_object_close(object);
 	git_repository_free(repo);
+
+	git_reference_free(reference);
+	git_reference_free(resolved_ref);
 END_TEST
 
 BEGIN_TEST(readsym2, "lookup the HEAD and resolve the master branch")
@@ -133,17 +143,22 @@
 	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&reference, repo, head_tracker_sym_ref_name));
-	must_pass(git_reference_resolve(&resolved_ref, reference));
-	comp_base_ref = resolved_ref;
+	must_pass(git_reference_resolve(&comp_base_ref, reference));
+	git_reference_free(reference);
 
 	must_pass(git_reference_lookup(&reference, repo, GIT_HEAD_FILE));
 	must_pass(git_reference_resolve(&resolved_ref, reference));
 	must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref)));
+	git_reference_free(reference);
+	git_reference_free(resolved_ref);
 
 	must_pass(git_reference_lookup(&reference, repo, current_head_target));
 	must_pass(git_reference_resolve(&resolved_ref, reference));
 	must_pass(git_oid_cmp(git_reference_oid(comp_base_ref), git_reference_oid(resolved_ref)));
+	git_reference_free(reference);
+	git_reference_free(resolved_ref);
 
+	git_reference_free(comp_base_ref);
 	git_repository_free(repo);
 END_TEST
 
@@ -160,6 +175,10 @@
 	must_pass(git_oid_cmp(git_reference_oid(master_ref), git_reference_oid(resolved_ref)));
 
 	git_repository_free(repo);
+
+	git_reference_free(reference);
+	git_reference_free(resolved_ref);
+	git_reference_free(master_ref);
 END_TEST
 
 static const char *packed_head_name = "refs/heads/packed";
@@ -173,8 +192,8 @@
 	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&reference, repo, packed_head_name));
-	must_be_true(reference->type & GIT_REF_OID);
-	must_be_true((reference->type & GIT_REF_PACKED) != 0);
+	must_be_true(git_reference_type(reference) & GIT_REF_OID);
+	must_be_true(git_reference_is_packed(reference));
 	must_be_true(strcmp(reference->name, packed_head_name) == 0);
 
 	must_pass(git_object_lookup(&object, repo, git_reference_oid(reference), GIT_OBJ_ANY));
@@ -183,6 +202,8 @@
 
 	git_object_close(object);
 	git_repository_free(repo);
+
+	git_reference_free(reference);
 END_TEST
 
 BEGIN_TEST(readpacked1, "assure that a loose reference is looked up before a packed reference")
@@ -192,11 +213,13 @@
 	must_pass(git_repository_open(&repo, REPOSITORY_FOLDER));
 	must_pass(git_reference_lookup(&reference, repo, packed_head_name));
 	must_pass(git_reference_lookup(&reference, repo, packed_test_head_name));
-	must_be_true(reference->type & GIT_REF_OID);
-	must_be_true((reference->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_type(reference) & GIT_REF_OID);
+	must_be_true(git_reference_is_packed(reference) == 0);
 	must_be_true(strcmp(reference->name, packed_test_head_name) == 0);
 
 	git_repository_free(repo);
+
+	git_reference_free(reference);
 END_TEST
 
 BEGIN_TEST(create0, "create a new symbolic reference")
@@ -219,13 +242,13 @@
 
 	/* Ensure the reference can be looked-up... */
 	must_pass(git_reference_lookup(&looked_up_ref, repo, new_head_tracker));
-	must_be_true(looked_up_ref->type & GIT_REF_SYMBOLIC);
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_type(looked_up_ref) & GIT_REF_SYMBOLIC);
+	must_be_true(git_reference_is_packed(looked_up_ref) == 0);
 	must_be_true(strcmp(looked_up_ref->name, new_head_tracker) == 0);
 
 	/* ...peeled.. */
 	must_pass(git_reference_resolve(&resolved_ref, looked_up_ref));
-	must_be_true(resolved_ref->type == GIT_REF_OID);
+	must_be_true(git_reference_type(resolved_ref) == GIT_REF_OID);
 
 	/* ...and that it points to the current master tip */
 	must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
@@ -240,6 +263,10 @@
 	must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
 
 	close_temp_repo(repo2);
+
+	git_reference_free(new_reference);
+	git_reference_free(looked_up_ref);
+	git_reference_free(resolved_ref);
 END_TEST
 
 BEGIN_TEST(create1, "create a deep symbolic reference")
@@ -261,6 +288,10 @@
 	must_be_true(git_oid_cmp(&id, git_reference_oid(resolved_ref)) == 0);
 
 	close_temp_repo(repo);
+
+	git_reference_free(new_reference);
+	git_reference_free(looked_up_ref);
+	git_reference_free(resolved_ref);
 END_TEST
 
 BEGIN_TEST(create2, "create a new OID reference")
@@ -283,8 +314,8 @@
 
 	/* Ensure the reference can be looked-up... */
 	must_pass(git_reference_lookup(&looked_up_ref, repo, new_head));
-	must_be_true(looked_up_ref->type & GIT_REF_OID);
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_type(looked_up_ref) & GIT_REF_OID);
+	must_be_true(git_reference_is_packed(looked_up_ref) == 0);
 	must_be_true(strcmp(looked_up_ref->name, new_head) == 0);
 
 	/* ...and that it points to the current master tip */
@@ -299,6 +330,9 @@
 	must_be_true(git_oid_cmp(&id, git_reference_oid(looked_up_ref)) == 0);
 
 	close_temp_repo(repo2);
+
+	git_reference_free(new_reference);
+	git_reference_free(looked_up_ref);
 END_TEST
 
 BEGIN_TEST(create3, "Can not create a new OID reference which targets at an unknown id")
@@ -349,6 +383,9 @@
 	must_be_true(!strcmp(git_reference_target(ref), ref_master_name));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
+	git_reference_free(branch_ref);
 END_TEST
 
 BEGIN_TEST(overwrite1, "Overwrite an existing object id reference")
@@ -359,14 +396,14 @@
 	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&ref, repo, ref_master_name));
-	must_be_true(ref->type & GIT_REF_OID);
+	must_be_true(git_reference_type(ref) & GIT_REF_OID);
 	git_oid_cpy(&id, git_reference_oid(ref));
 
 	/* Create it */
 	must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 0));
 
 	must_pass(git_reference_lookup(&ref, repo, ref_test_name));
-	must_be_true(ref->type & GIT_REF_OID);
+	must_be_true(git_reference_type(ref) & GIT_REF_OID);
 	git_oid_cpy(&id, git_reference_oid(ref));
 
 	/* Ensure we can't overwrite unless we force it */
@@ -378,6 +415,8 @@
 	must_be_true(!git_oid_cmp(&id, git_reference_oid(ref)));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
 END_TEST
 
 BEGIN_TEST(overwrite2, "Overwrite an existing object id reference with a symbolic one")
@@ -388,7 +427,7 @@
 	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&ref, repo, ref_master_name));
-	must_be_true(ref->type & GIT_REF_OID);
+	must_be_true(git_reference_type(ref) & GIT_REF_OID);
 	git_oid_cpy(&id, git_reference_oid(ref));
 
 	must_pass(git_reference_create_oid(&ref, repo, ref_name, &id, 0));
@@ -401,6 +440,8 @@
 	must_be_true(!strcmp(git_reference_target(ref), ref_master_name));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
 END_TEST
 
 BEGIN_TEST(overwrite3, "Overwrite an existing symbolic reference with an object id one")
@@ -411,7 +452,7 @@
 	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&ref, repo, ref_master_name));
-	must_be_true(ref->type & GIT_REF_OID);
+	must_be_true(git_reference_type(ref) & GIT_REF_OID);
 	git_oid_cpy(&id, git_reference_oid(ref));
 
 	/* Create the symbolic ref */
@@ -426,17 +467,18 @@
 	must_be_true(!git_oid_cmp(git_reference_oid(ref), &id));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
 END_TEST
 
 BEGIN_TEST(pack0, "create a packfile for an empty folder")
 	git_repository *repo;
 	char temp_path[GIT_PATH_MAX];
-	const int mode = 0755; /* or 0777 ? */
 
 	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
 	git_path_join_n(temp_path, 3, repo->path_repository, GIT_REFS_HEADS_DIR, "empty_dir");
-	must_pass(git_futils_mkdir_r(temp_path, mode));
+	must_pass(git_futils_mkdir_r(temp_path, GIT_REFS_DIR_MODE));
 
 	must_pass(git_reference_packall(repo));
 
@@ -452,7 +494,7 @@
 
 	/* Ensure a known loose ref can be looked up */
 	must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name));
-	must_be_true((reference->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(reference) == 0);
 	must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
 
 	/*
@@ -468,7 +510,7 @@
 
 	/* Ensure the known ref can still be looked up but is now packed */
 	must_pass(git_reference_lookup(&reference, repo, loose_tag_ref_name));
-	must_be_true((reference->type & GIT_REF_PACKED) != 0);
+	must_be_true(git_reference_is_packed(reference));
 	must_be_true(strcmp(reference->name, loose_tag_ref_name) == 0);
 
 	/* Ensure the known ref has been removed from the loose folder structure */
@@ -476,6 +518,8 @@
 	must_pass(!git_futils_exists(temp_path));
 
 	close_temp_repo(repo);
+
+	git_reference_free(reference);
 END_TEST
 
 BEGIN_TEST(rename0, "rename a loose reference")
@@ -494,7 +538,7 @@
 	must_pass(git_reference_lookup(&looked_up_ref, repo, loose_tag_ref_name));
 
 	/* ... which is indeed loose */
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(looked_up_ref) == 0);
 
 	/* Now that the reference is renamed... */
 	must_pass(git_reference_rename(looked_up_ref, new_name, 0));
@@ -508,14 +552,17 @@
 	must_be_true(!strcmp(another_looked_up_ref->name, new_name));
 
 	/* .. the ref is still loose... */
-	must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0);
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(another_looked_up_ref) == 0);
+	must_be_true(git_reference_is_packed(looked_up_ref) == 0);
 
 	/* ...and the ref can be found in the file system */
 	git_path_join(temp_path, repo->path_repository, new_name);
 	must_pass(git_futils_exists(temp_path));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
+	git_reference_free(another_looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename1, "rename a packed reference (should make it loose)")
@@ -534,7 +581,7 @@
 	must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name));
 
 	/* .. and it's packed */
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) != 0);
+	must_be_true(git_reference_is_packed(looked_up_ref) != 0);
 
 	/* Now that the reference is renamed... */
 	must_pass(git_reference_rename(looked_up_ref, brand_new_name, 0));
@@ -548,14 +595,17 @@
 	must_be_true(!strcmp(another_looked_up_ref->name, brand_new_name));
 
 	/* .. the ref is no longer packed... */
-	must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0);
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(another_looked_up_ref) == 0);
+	must_be_true(git_reference_is_packed(looked_up_ref) == 0);
 
 	/* ...and the ref now happily lives in the file system */
 	git_path_join(temp_path, repo->path_repository, brand_new_name);
 	must_pass(git_futils_exists(temp_path));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
+	git_reference_free(another_looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename2, "renaming a packed reference does not pack another reference which happens to be in both loose and pack state")
@@ -574,13 +624,13 @@
 	must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name));
 
 	/* Ensure it's loose */
-	must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(another_looked_up_ref) == 0);
 
 	/* Lookup the reference to rename */
 	must_pass(git_reference_lookup(&looked_up_ref, repo, packed_head_name));
 
 	/* Ensure it's packed */
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) != 0);
+	must_be_true(git_reference_is_packed(looked_up_ref) != 0);
 
 	/* Now that the reference is renamed... */
 	must_pass(git_reference_rename(looked_up_ref, brand_new_name, 0));
@@ -589,12 +639,15 @@
 	must_pass(git_reference_lookup(&another_looked_up_ref, repo, packed_test_head_name));
 
 	/* Ensure it's loose */
-	must_be_true((another_looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(another_looked_up_ref) == 0);
 
 	/* Ensure the other ref still exists on the file system */
 	must_pass(git_futils_exists(temp_path));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
+	git_reference_free(another_looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename3, "can not rename a reference with the name of an existing reference")
@@ -614,6 +667,8 @@
 	must_be_true(!strcmp(looked_up_ref->name, packed_head_name));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename4, "can not rename a reference with an invalid name")
@@ -636,6 +691,8 @@
 	must_be_true(!strcmp(looked_up_ref->name, packed_test_head_name));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename5, "can force-rename a packed reference with the name of an existing loose and packed reference")
@@ -661,6 +718,8 @@
 	must_fail(git_reference_lookup(&looked_up_ref, repo, packed_head_name));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename6, "can force-rename a loose reference with the name of an existing loose reference")
@@ -686,6 +745,8 @@
 	must_fail(git_reference_lookup(&looked_up_ref, repo, "refs/heads/br2"));
 
 	close_temp_repo(repo);
+
+	git_reference_free(looked_up_ref);
 END_TEST
 
 static const char *ref_one_name = "refs/heads/one/branch";
@@ -700,7 +761,7 @@
 	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&ref, repo, ref_master_name));
-	must_be_true(ref->type & GIT_REF_OID);
+	must_be_true(git_reference_type(ref) & GIT_REF_OID);
 
 	git_oid_cpy(&id, git_reference_oid(ref));
 
@@ -718,6 +779,11 @@
 	must_fail(git_reference_lookup(&ref_one_new, repo, ref_one_name_new));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
+	git_reference_free(ref_one);
+	git_reference_free(ref_one_new);
+	git_reference_free(ref_two);
 END_TEST
 
 static const char *ref_two_name_new = "refs/heads/two/two";
@@ -730,7 +796,7 @@
 	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
 	must_pass(git_reference_lookup(&ref, repo, ref_master_name));
-	must_be_true(ref->type & GIT_REF_OID);
+	must_be_true(git_reference_type(ref) & GIT_REF_OID);
 
 	git_oid_cpy(&id, git_reference_oid(ref));
 
@@ -749,6 +815,10 @@
 	must_fail(git_reference_lookup(&looked_up_ref, repo, ref_two_name));
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
+	git_reference_free(ref_two);
+	git_reference_free(looked_up_ref);
 END_TEST
 
 BEGIN_TEST(rename9, "can move a reference to a upper reference hierarchy")
@@ -759,7 +829,7 @@
     must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
 
     must_pass(git_reference_lookup(&ref, repo, ref_master_name));
-    must_be_true(ref->type & GIT_REF_OID);
+    must_be_true(git_reference_type(ref) & GIT_REF_OID);
 
     git_oid_cpy(&id, git_reference_oid(ref));
 
@@ -795,7 +865,7 @@
 	must_pass(git_reference_lookup(&looked_up_ref, repo, packed_test_head_name));
 
 	/* Ensure it's the loose version that has been found */
-	must_be_true((looked_up_ref->type & GIT_REF_PACKED) == 0);
+	must_be_true(git_reference_is_packed(looked_up_ref) == 0);
 
 	/* Now that the reference is deleted... */
 	must_pass(git_reference_delete(looked_up_ref));
@@ -807,6 +877,42 @@
 	must_pass(!git_futils_exists(temp_path));
 
 	close_temp_repo(repo);
+
+	git_reference_free(another_looked_up_ref);
+END_TEST
+
+BEGIN_TEST(delete1, "can delete a just packed reference")
+	git_reference *ref;
+	git_repository *repo;
+	git_oid id;
+	const char *new_ref = "refs/heads/new_ref";
+
+	git_oid_fromstr(&id, current_master_tip);
+
+	must_pass(open_temp_repo(&repo, REPOSITORY_FOLDER));
+
+	/* Create and write the new object id reference */
+	must_pass(git_reference_create_oid(&ref, repo, new_ref, &id, 0));
+
+	/* Lookup the reference */
+	must_pass(git_reference_lookup(&ref, repo, new_ref));
+
+	/* Ensure it's a loose reference */
+	must_be_true(git_reference_is_packed(ref) == 0);
+
+	/* Pack all existing references */
+	must_pass(git_reference_packall(repo));
+
+	/* Reload the reference from disk */
+	must_pass(git_reference_reload(ref));
+
+	/* Ensure it's a packed reference */
+	must_be_true(git_reference_is_packed(ref) == 1);
+
+	/* This should pass */
+	must_pass(git_reference_delete(ref));
+
+	close_temp_repo(repo);
 END_TEST
 
 static int ensure_refname_normalized(int is_oid_ref, const char *input_refname, const char *expected_refname)
@@ -1102,6 +1208,9 @@
 	git_signature_free(committer);
 	git_reflog_free(reflog);
 	close_temp_repo(repo2);
+
+	git_reference_free(ref);
+	git_reference_free(lookedup_ref);
 END_TEST
 
 BEGIN_TEST(reflog1, "avoid writing an obviously wrong reflog")
@@ -1130,6 +1239,8 @@
 	git_signature_free(committer);
 
 	close_temp_repo(repo);
+
+	git_reference_free(ref);
 END_TEST
 
 BEGIN_SUITE(refs)
@@ -1173,6 +1284,7 @@
 	ADD_TEST(rename9);
 
 	ADD_TEST(delete0);
+	ADD_TEST(delete1);
 
 	ADD_TEST(list0);
 	ADD_TEST(list1);
diff --git a/tests/t12-repo.c b/tests/t12-repo.c
index de921f9..47dc852 100644
--- a/tests/t12-repo.c
+++ b/tests/t12-repo.c
@@ -173,7 +173,7 @@
 BEGIN_TEST(init2, "Initialize and open a bare repo with a relative path escaping out of the current working directory")
 	char path_repository[GIT_PATH_MAX];
 	char current_workdir[GIT_PATH_MAX];
-	const int mode = 0755; /* or 0777 ? */
+	const mode_t mode = 0777;
 	git_repository* repo;
 
 	must_pass(p_getcwd(current_workdir, sizeof(current_workdir)));
@@ -232,7 +232,7 @@
 	char current_workdir[GIT_PATH_MAX];
 	char path_repository[GIT_PATH_MAX];
 
-	const int mode = 0755; /* or 0777 ? */
+	const mode_t mode = 0777;
 	git_repository* repo;
 
 	/* Setup the repository to open */
@@ -286,6 +286,8 @@
 	must_be_true(git_repository_head_detached(repo) == 0);
 
 	git_repository_free(repo);
+
+	git_reference_free(ref);
 END_TEST
 
 BEGIN_TEST(orphan0, "test if HEAD is orphan")
@@ -305,6 +307,8 @@
 	must_be_true(git_repository_head_orphan(repo) == 0);
 
 	git_repository_free(repo);
+
+	git_reference_free(ref);
 END_TEST
 
 #define DISCOVER_FOLDER TEMP_REPO_FOLDER "discover.git"
@@ -351,7 +355,7 @@
 			return error;
 	}
 
-	file = git_futils_creat_withpath(path, 0644);
+	file = git_futils_creat_withpath(path, 0777, 0666);
 	if (file < GIT_SUCCESS)
 		return file;
 
@@ -384,7 +388,7 @@
 	char repository_path[GIT_PATH_MAX];
 	char sub_repository_path[GIT_PATH_MAX];
 	char found_path[GIT_PATH_MAX];
-	int mode = 0755;
+	const mode_t mode = 0777;
 
 	git_futils_mkdir_r(DISCOVER_FOLDER, mode);
 	must_pass(append_ceiling_dir(ceiling_dirs, TEMP_REPO_FOLDER));
diff --git a/tests/t15-config.c b/tests/t15-config.c
index c4cb590..a97f820 100644
--- a/tests/t15-config.c
+++ b/tests/t15-config.c
@@ -319,7 +319,7 @@
 	/* As the section wasn't removed, owerwrite the file */
 	must_pass(git_filebuf_open(&buf, CONFIG_BASE "/config10", 0));
 	must_pass(git_filebuf_write(&buf, "[empty]\n", strlen("[empty]\n")));
-	must_pass(git_filebuf_commit(&buf));
+	must_pass(git_filebuf_commit(&buf, 0666));
 END_TEST
 
 BEGIN_TEST(config17, "prefixes aren't broken")
diff --git a/tests/t18-status.c b/tests/t18-status.c
index ee9c5c6..3b75472 100644
--- a/tests/t18-status.c
+++ b/tests/t18-status.c
@@ -37,7 +37,7 @@
 {
 	int fd;
 
-	fd = p_creat(filename, 0644);
+	fd = p_creat(filename, 0666);
 	if (fd == 0)
 		return GIT_ERROR;
 	if (p_write(fd, content, strlen(content)) != 0)
@@ -136,7 +136,7 @@
 	struct status_entry_counts counts;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	memset(&counts, 0x0, sizeof(struct status_entry_counts));
@@ -223,7 +223,7 @@
 	struct status_entry_counts counts;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	/* Purging the working */
@@ -309,12 +309,12 @@
 	struct status_entry_counts counts;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
-	must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap"));
-	must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file"));
-	must_pass(git_futils_mv_atomic(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir"));
+	must_pass(p_rename(TEMP_REPO_FOLDER "current_file", TEMP_REPO_FOLDER "swap"));
+	must_pass(p_rename(TEMP_REPO_FOLDER "subdir", TEMP_REPO_FOLDER "current_file"));
+	must_pass(p_rename(TEMP_REPO_FOLDER "swap", TEMP_REPO_FOLDER "subdir"));
 
 	must_pass(file_create(TEMP_REPO_FOLDER ".HEADER", "dummy"));
 	must_pass(file_create(TEMP_REPO_FOLDER "42-is-not-prime.sigh", "dummy"));
@@ -341,7 +341,7 @@
 	int i;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	for (i = 0; i < ENTRY_COUNT0; ++i) {
@@ -360,7 +360,7 @@
 	int error;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	// "nonexistent" does not exist in HEAD, Index or the worktree
@@ -400,7 +400,7 @@
 	must_pass(remove_placeholders(TEST_STD_REPO_FOLDER, "dummy-marker.txt"));
 
 	git_path_join(file_path, TEMP_REPO_FOLDER, filename);
-	fd = p_creat(file_path, 0644);
+	fd = p_creat(file_path, 0666);
 	must_pass(fd);
 	must_pass(p_write(fd, "new_file\n", 9));
 	must_pass(p_close(fd));
@@ -421,7 +421,7 @@
 	int error;
 
 	must_pass(copydir_recurs(STATUS_WORKDIR_FOLDER, TEMP_REPO_FOLDER));
-	must_pass(git_futils_mv_atomic(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
+	must_pass(p_rename(STATUS_REPOSITORY_TEMP_FOLDER, TEST_STD_REPO_FOLDER));
 	must_pass(git_repository_open(&repo, TEST_STD_REPO_FOLDER));
 
 	error = git_status_file(&status_flags, repo, "subdir");
diff --git a/tests/test_helpers.c b/tests/test_helpers.c
index cb95607..31e38bf 100644
--- a/tests/test_helpers.c
+++ b/tests/test_helpers.c
@@ -42,7 +42,7 @@
 
 int write_object_files(const char *odb_dir, object_data *d)
 {
-	if (p_mkdir(odb_dir, 0755) < 0) {
+	if (p_mkdir(odb_dir, GIT_OBJECT_DIR_MODE) < 0) {
 		int err = errno;
 		fprintf(stderr, "can't make directory \"%s\"", odb_dir);
 		if (err == EEXIST)
@@ -51,7 +51,7 @@
 		return -1;
 	}
 
-	if ((p_mkdir(d->dir, 0755) < 0) && (errno != EEXIST)) {
+	if ((p_mkdir(d->dir, GIT_OBJECT_DIR_MODE) < 0) && (errno != EEXIST)) {
 		fprintf(stderr, "can't make object directory \"%s\"\n", d->dir);
 		return -1;
 	}
@@ -82,7 +82,7 @@
 	return 0;
 }
 
-int remove_loose_object(const char *repository_folder, git_object *object)
+void locate_loose_object(const char *repository_folder, git_object *object, char **out, char **out_folder)
 {
 	static const char *objects_folder = "objects/";
 
@@ -104,6 +104,54 @@
 	ptr += GIT_OID_HEXSZ + 1;
 	*ptr = 0;
 
+	*out = full_path;
+
+	if (out_folder)
+		*out_folder = top_folder;
+}
+
+int loose_object_mode(const char *repository_folder, git_object *object)
+{
+	char *object_path;
+	struct stat st;
+
+	locate_loose_object(repository_folder, object, &object_path, NULL);
+	if (p_stat(object_path, &st) < 0)
+		return 0;
+	free(object_path);
+
+	return st.st_mode;
+}
+
+int loose_object_dir_mode(const char *repository_folder, git_object *object)
+{
+	char *object_path;
+	size_t pos;
+	struct stat st;
+
+	locate_loose_object(repository_folder, object, &object_path, NULL);
+
+	pos = strlen(object_path);
+	while (pos--) {
+		if (object_path[pos] == '/') {
+			object_path[pos] = 0;
+			break;
+		}
+	}
+
+	if (p_stat(object_path, &st) < 0)
+		return 0;
+	free(object_path);
+
+	return st.st_mode;
+}
+
+int remove_loose_object(const char *repository_folder, git_object *object)
+{
+	char *full_path, *top_folder;
+
+	locate_loose_object(repository_folder, object, &full_path, &top_folder);
+
 	if (p_unlink(full_path) < 0) {
 		fprintf(stderr, "can't delete object file \"%s\"\n", full_path);
 		return -1;
@@ -116,7 +164,7 @@
 		return -1;
 	}
 
-	free(full_path);
+	git__free(full_path);
 
 	return GIT_SUCCESS;
 }
@@ -141,7 +189,7 @@
 	if (git_futils_readbuffer(&source_buf, src) < GIT_SUCCESS)
 		return GIT_ENOTFOUND;
 
-	dst_fd = git_futils_creat_withpath(dst, 0644);
+	dst_fd = git_futils_creat_withpath(dst, 0777, 0666);
 	if (dst_fd < 0)
 		goto cleanup;
 
diff --git a/tests/test_helpers.h b/tests/test_helpers.h
index 53361b7..16a3a2c 100644
--- a/tests/test_helpers.h
+++ b/tests/test_helpers.h
@@ -63,6 +63,11 @@
 
 extern int cmp_objects(git_rawobj *o, object_data *d);
 
+extern void locate_loose_object(const char *odb_dir, git_object *object, char **out, char **out_folder);
+
+extern int loose_object_mode(const char *odb_dir, git_object *object);
+extern int loose_object_dir_mode(const char *odb_dir, git_object *object);
+
 extern int remove_loose_object(const char *odb_dir, git_object *object);
 
 extern int cmp_files(const char *a, const char *b);
diff --git a/tests/test_lib.c b/tests/test_lib.c
index e67ad34..9d3cba1 100755
--- a/tests/test_lib.c
+++ b/tests/test_lib.c
@@ -88,8 +88,8 @@
 	tc->failed = 1;
 	tc->message = strdup(message);
 	tc->failed_pos = strdup(buf);
-	tc->error_stack = git_errno;
-	git_errno = NULL;
+	tc->error_stack = GIT_GLOBAL->git_errno;
+	GIT_GLOBAL->git_errno = NULL;
 
 	if (last_error)
 		tc->error_message = strdup(last_error);
diff --git a/tests/test_lib.h b/tests/test_lib.h
index 9d90e48..7552ebf 100755
--- a/tests/test_lib.h
+++ b/tests/test_lib.h
@@ -7,6 +7,7 @@
 #include <string.h>
 
 #include "common.h"
+#include "global.h"
 #include <git2.h>
 
 #define DECLARE_SUITE(SNAME) extern git_testsuite *libgit2_suite_##SNAME(void)
diff --git a/tests/test_main.c b/tests/test_main.c
index c9f8da3..9961ffd 100644
--- a/tests/test_main.c
+++ b/tests/test_main.c
@@ -26,6 +26,8 @@
 #include <string.h>
 #include <git2.h>
 
+#include "posix.h"
+
 #include "test_lib.h"
 #include "test_helpers.h"
 
@@ -81,6 +83,8 @@
 	GIT_UNUSED_ARG(argc);
 	GIT_UNUSED_ARG(argv);
 
+	p_umask(0);
+
 	failures = 0;
 
 	for (i = 0; i < GIT_SUITE_COUNT; ++i)