diff --git a/pygit2.c b/pygit2.c
index 51739e8..6efea74 100644
--- a/pygit2.c
+++ b/pygit2.c
@@ -377,7 +377,119 @@ Repository_walk(Repository *self, PyObject *args)
     return (PyObject*)py_walker;
 }
 
+static PyObject *
+build_person(const git_signature *signature) {
+    return Py_BuildValue("(ssLi)", signature->name, signature->email,
+                         signature->when.time, signature->when.offset);
+}
+
+static int
+signature_converter(PyObject *value, git_signature **out) {
+    char *name, *email;
+    long long time;
+    int offset;
+    git_signature *signature;
+
+    if (!PyArg_ParseTuple(value, "ssLi", &name, &email, &time, &offset))
+        return 0;
+
+    signature = git_signature_new(name, email, time, offset);
+    if (signature == NULL) {
+        PyErr_SetNone(PyExc_MemoryError);
+        return 0;
+    }
+
+    *out = signature;
+    return 1;
+}
+
+static PyObject *
+free_parents(git_oid **parents, int n) {
+    int i;
+
+    for (i = 0; i < n; i++)
+        free(parents[i]);
+    free(parents);
+    return NULL;
+}
+
+static PyObject *
+Repository_create_commit(Repository *self, PyObject *args) {
+    git_signature *author, *committer;
+    char *message;
+    git_oid tree_oid, oid;
+    PyObject *py_parents, *py_parent;
+    int parent_count;
+    git_oid **parents;
+    int err, i;
+    char hex[GIT_OID_HEXSZ];
+
+    if (!PyArg_ParseTuple(args, "O&O&sO&O!",
+                          signature_converter, &author,
+                          signature_converter, &committer,
+                          &message,
+                          py_str_to_git_oid, &tree_oid,
+                          &PyList_Type, &py_parents))
+        return NULL;
+
+    parent_count = (int)PyList_Size(py_parents);
+    parents = malloc(parent_count * sizeof(git_oid*));
+    if (parents == NULL) {
+        PyErr_SetNone(PyExc_MemoryError);
+        return NULL;
+    }
+    for (i = 0; i < parent_count; i++) {
+        parents[i] = malloc(sizeof(git_oid));
+        if (parents[i] == NULL) {
+            PyErr_SetNone(PyExc_MemoryError);
+            return free_parents(parents, i);
+        }
+        py_parent = PyList_GET_ITEM(py_parents, i);
+        if (!py_str_to_git_oid(py_parent, parents[i]))
+            return free_parents(parents, i);
+    }
+
+    err = git_commit_create(&oid, self->repo, NULL,
+        author, committer, message, &tree_oid,
+        parent_count, (const git_oid**)parents);
+    free_parents(parents, parent_count);
+    if (err < 0)
+        return Error_set(err);
+
+    git_oid_fmt(hex, &oid);
+    return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ);
+}
+
+static PyObject *
+Repository_create_tag(Repository *self, PyObject *args) {
+    char *tag_name, *message;
+    git_signature *tagger;
+    git_oid target, oid;
+    int err, target_type;
+    char hex[GIT_OID_HEXSZ];
+
+    if (!PyArg_ParseTuple(args, "sO&iO&s",
+                          &tag_name,
+                          py_str_to_git_oid, &target,
+                          &target_type,
+                          signature_converter, &tagger,
+                          &message))
+        return NULL;
+
+    err = git_tag_create(&oid, self->repo,
+        tag_name, &target, target_type, tagger, message);
+    if (err < 0)
+        return NULL;
+
+    git_oid_fmt(hex, &oid);
+    return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ);
+}
+
 static PyMethodDef Repository_methods[] = {
+    {"create_commit", (PyCFunction)Repository_create_commit, METH_VARARGS,
+     "Create a new commit object, return its SHA."},
+    {"create_tag", (PyCFunction)Repository_create_tag, METH_VARARGS,
+     "Create a new tag object, return its SHA."},
     {"walk", (PyCFunction)Repository_walk, METH_VARARGS,
      "Generator that traverses the history starting from the given commit."},
     {"read", (PyCFunction)Repository_read, METH_O,
@@ -556,106 +668,6 @@ static PyTypeObject ObjectType = {
     0,                                         /* tp_new */
 };
 
-static PyObject *
-build_person(const git_signature *signature) {
-    return Py_BuildValue("(ssLi)", signature->name, signature->email,
-                         signature->when.time, signature->when.offset);
-}
-
-static int
-signature_converter(PyObject *value, git_signature **out) {
-    char *name, *email;
-    long long time;
-    int offset;
-    git_signature *signature;
-
-    if (!PyArg_ParseTuple(value, "ssLi", &name, &email, &time, &offset))
-        return 0;
-
-    signature = git_signature_new(name, email, time, offset);
-    if (signature == NULL) {
-        PyErr_SetNone(PyExc_MemoryError);
-        return 0;
-    }
-
-    *out = signature;
-    return 1;
-}
-
-static int
-free_parents(git_oid **parents, int n) {
-    int i;
-
-    for (i = 0; i < n; i++)
-        free(parents[i]);
-    free(parents);
-    return -1;
-}
-
-static int
-Commit_init(Commit *py_commit, PyObject *args, PyObject *kwds) {
-    Repository *repo = NULL;
-    git_signature *author, *committer;
-    char *message;
-    git_oid tree_oid, oid;
-    PyObject *py_parents, *py_parent;
-    int parent_count;
-    git_oid **parents;
-    git_commit *commit;
-    int err, i;
-
-    if (kwds) {
-        PyErr_Format(PyExc_TypeError, "%s takes no keyword arugments",
-                     py_commit->ob_type->tp_name);
-        return -1;
-    }
-
-    if (!PyArg_ParseTuple(args, "O!O&O&sO&O!", &RepositoryType, &repo,
-                          signature_converter, &author,
-                          signature_converter, &committer,
-                          &message,
-                          py_str_to_git_oid, &tree_oid,
-                          &PyList_Type, &py_parents))
-        return -1;
-
-    parent_count = (int)PyList_Size(py_parents);
-    parents = malloc(parent_count * sizeof(git_oid*));
-    if (parents == NULL) {
-        PyErr_SetNone(PyExc_MemoryError);
-        return -1;
-    }
-    for (i = 0; i < parent_count; i++) {
-        parents[i] = malloc(sizeof(git_oid));
-        if (parents[i] == NULL) {
-            PyErr_SetNone(PyExc_MemoryError);
-            return free_parents(parents, i);
-        }
-        py_parent = PyList_GET_ITEM(py_parents, i);
-        if (!py_str_to_git_oid(py_parent, parents[i]))
-            return free_parents(parents, i);
-    }
-
-    err = git_commit_create(&oid, repo->repo, NULL,
-        author, committer, message, &tree_oid,
-        parent_count, (const git_oid**)parents);
-    if (err < 0) {
-        Error_set(err);
-        return free_parents(parents, parent_count);
-    }
-
-    err = git_commit_lookup(&commit, repo->repo, &oid);
-    if (err < 0) {
-        Error_set(err);
-        return free_parents(parents, parent_count);
-    }
-
-    Py_INCREF(repo);
-    py_commit->repo = repo;
-    py_commit->commit = commit;
-    free_parents(parents, parent_count);
-    return 0;
-}
-
 static PyObject *
 Commit_get_message_short(Commit *commit) {
     return PyString_FromString(git_commit_message_short(commit->commit));
@@ -790,7 +802,7 @@ static PyTypeObject CommitType = {
     0,                                         /* tp_descr_get */
     0,                                         /* tp_descr_set */
     0,                                         /* tp_dictoffset */
-    (initproc)Commit_init,                     /* tp_init */
+    0,                                         /* tp_init */
     0,                                         /* tp_alloc */
     0,                                         /* tp_new */
 };
@@ -1096,44 +1108,6 @@ static PyTypeObject BlobType = {
     0,                                         /* tp_new */
 };
 
-static int
-Tag_init(Tag *py_tag, PyObject *args, PyObject *kwds) {
-    Repository *repo = NULL;
-    char *tag_name, *message;
-    git_signature *tagger;
-    git_oid target, oid;
-    git_tag *tag;
-    int err, target_type;
-
-    if (kwds) {
-        PyErr_Format(PyExc_TypeError, "%s takes no keyword arugments",
-                     py_tag->ob_type->tp_name);
-        return -1;
-    }
-
-    if (!PyArg_ParseTuple(args, "O!sO&iO&s", &RepositoryType, &repo,
-                          &tag_name,
-                          py_str_to_git_oid, &target,
-                          &target_type,
-                          signature_converter, &tagger,
-                          &message))
-        return -1;
-
-    err = git_tag_create(&oid, repo->repo,
-        tag_name, &target, target_type, tagger, message);
-    if (err < 0)
-        return -1;
-
-    err = git_tag_lookup(&tag, repo->repo, &oid);
-    if (err < 0)
-        return -1;
-
-    Py_INCREF(repo);
-    py_tag->repo = repo;
-    py_tag->tag = tag;
-    return 0;
-}
-
 static void
 Tag_dealloc(Tag *self) {
     Py_XDECREF(self->target);
@@ -1234,7 +1208,7 @@ static PyTypeObject TagType = {
     0,                                         /* tp_descr_get */
     0,                                         /* tp_descr_set */
     0,                                         /* tp_dictoffset */
-    (initproc)Tag_init,                        /* tp_init */
+    0,                                         /* tp_init */
     0,                                         /* tp_alloc */
     0,                                         /* tp_new */
 };
@@ -1443,28 +1417,14 @@ static PyObject *
 Index_create_tree(Index *self) {
     git_oid oid;
     int err;
-    Tree *py_tree;
-    git_tree *tree;
+    char hex[GIT_OID_HEXSZ];
 
     err = git_tree_create_fromindex(&oid, self->index);
-    if (err < 0) {
+    if (err < 0)
         return Error_set(err);
-    }
 
-    err = git_tree_lookup(&tree, self->repo->repo, &oid);
-    if (err < 0) {
-        return Error_set(err);
-    }
-
-    py_tree = PyObject_New(Tree, &TreeType);
-    if (!py_tree)
-        return NULL;
-
-    Py_INCREF(self->repo);
-    py_tree->repo = self->repo;
-    py_tree->tree = (git_tree*)tree;
-
-    return (PyObject*)py_tree;
+    git_oid_fmt(hex, &oid);
+    return PyString_FromStringAndSize(hex, GIT_OID_HEXSZ);
 }
 
 static PyMethodDef Index_methods[] = {
@@ -1482,7 +1442,7 @@ static PyMethodDef Index_methods[] = {
      "Write an existing index object from memory back to disk using an"
      " atomic file lock."},
     {"create_tree", (PyCFunction)Index_create_tree, METH_NOARGS,
-     "Create a tree from the index entries"},
+     "Create a tree from the index file, return its SHA."},
     {NULL}
 };
 
@@ -1796,28 +1756,27 @@ initpygit2(void)
     RepositoryType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&RepositoryType) < 0)
         return;
-    /* Do not set ObjectType.tp_new, to prevent creating Objects directly. */
+
+    /* Do not set 'tp_new' for Git objects. To create Git objects use the
+     * Repository.create_XXX methods */
     if (PyType_Ready(&ObjectType) < 0)
         return;
     CommitType.tp_base = &ObjectType;
-    CommitType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&CommitType) < 0)
         return;
-    TreeEntryType.tp_new = PyType_GenericNew;
-    if (PyType_Ready(&TreeEntryType) < 0)
-        return;
     TreeType.tp_base = &ObjectType;
-    TreeType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&TreeType) < 0)
         return;
     BlobType.tp_base = &ObjectType;
-    BlobType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&BlobType) < 0)
         return;
     TagType.tp_base = &ObjectType;
-    TagType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&TagType) < 0)
         return;
+
+    TreeEntryType.tp_new = PyType_GenericNew;
+    if (PyType_Ready(&TreeEntryType) < 0)
+        return;
     IndexType.tp_new = PyType_GenericNew;
     if (PyType_Ready(&IndexType) < 0)
         return;
diff --git a/test/test_commit.py b/test/test_commit.py
index 6aea2a6..81aff77 100644
--- a/test/test_commit.py
+++ b/test/test_commit.py
@@ -31,7 +31,7 @@ __author__ = 'dborowitz@google.com (Dave Borowitz)'
 
 import unittest
 
-from pygit2 import Commit, GIT_OBJ_COMMIT
+from pygit2 import GIT_OBJ_COMMIT
 import utils
 
 COMMIT_SHA = '5fe808e8953c12735680c257f56600cb0de44b10'
@@ -62,13 +62,15 @@ class CommitTest(utils.BareRepoTestCase):
             '967fce8df97cc71722d3c2a5930ef3e6f1d27b12', commit.tree.sha)
 
     def test_new_commit(self):
+        repo = self.repo
         message = 'New commit.\n\nMessage.\n'
         committer = ('John Doe', 'jdoe@example.com', 12346, 0)
         author = ('Jane Doe', 'jdoe2@example.com', 12345, 0)
         tree = '967fce8df97cc71722d3c2a5930ef3e6f1d27b12'
 
         parents = [COMMIT_SHA]
-        commit = Commit(self.repo, author, committer, message, tree, parents)
+        sha = repo.create_commit(author, committer, message, tree, parents)
+        commit = repo[sha]
 
         self.assertEqual(GIT_OBJ_COMMIT, commit.type)
         self.assertEqual('30bb126a4959290987fc07ea49f92be276dce9d6',
diff --git a/test/test_index.py b/test/test_index.py
index 99c025f..1da7558 100644
--- a/test/test_index.py
+++ b/test/test_index.py
@@ -86,10 +86,8 @@ class IndexTest(utils.RepoTestCase):
         self.assertTrue('bye.txt' in index)
 
     def test_create_tree(self):
-        sha = 'fd937514cb799514d4b81bb24c5fcfeb6472b245'
-        index = self.repo.index
-        tree = index.create_tree()
-        self.assertEqual(sha, tree.sha)
+        sha = self.repo.index.create_tree()
+        self.assertEqual(sha, 'fd937514cb799514d4b81bb24c5fcfeb6472b245')
 
 
 if __name__ == '__main__':
diff --git a/test/test_tag.py b/test/test_tag.py
index f802b05..a8b447b 100644
--- a/test/test_tag.py
+++ b/test/test_tag.py
@@ -60,8 +60,9 @@ class TagTest(utils.BareRepoTestCase):
         message = 'Tag a blob.\n'
         tagger = ('John Doe', 'jdoe@example.com', 12347, 0)
 
-        tag = pygit2.Tag(self.repo, name, target, pygit2.GIT_OBJ_BLOB,
-                         tagger, message)
+        sha = self.repo.create_tag(name, target, pygit2.GIT_OBJ_BLOB, tagger,
+                                   message)
+        tag = self.repo[sha]
 
         self.assertEqual('3ee44658fd11660e828dfc96b9b5c5f38d5b49bb', tag.sha)
         self.assertEqual(name, tag.name)