diff --git a/src/blob.c b/src/blob.c
index 83c7ece..1b2840f 100644
--- a/src/blob.c
+++ b/src/blob.c
@@ -27,10 +27,105 @@
 
 #define PY_SSIZE_T_CLEAN
 #include <Python.h>
+#include "diff.h"
+#include "error.h"
 #include "utils.h"
 #include "object.h"
 #include "blob.h"
 
+extern PyObject *GitError;
+
+extern PyTypeObject BlobType;
+
+PyDoc_STRVAR(Blob_diff__doc__,
+  "diff([blob, flag, old_as_path, new_as_path] -> Patch\n"
+  "\n"
+  "Directly generate a :py:class:`pygit2.Patch` from the difference\n"
+  "  between two blobs.\n"
+  "\n"
+  "Arguments:\n"
+  "\n"
+  "blob: the :py:class:`~pygit2.Blob` to diff.\n"
+  "\n"
+  "flag: a GIT_DIFF_* constant.\n"
+  "\n"
+  "old_as_path: treat old blob as if it had this filename.\n"
+  "\n"
+  "new_as_path: treat new blob as if it had this filename.\n");
+
+PyObject *
+Blob_diff(Blob *self, PyObject *args, PyObject *kwds)
+{
+    git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+    git_patch *patch;
+    char *old_as_path = NULL, *new_as_path = NULL;
+    Blob *py_blob = NULL;
+    int err;
+    char *keywords[] = {"blob", "flag", "old_as_path", "new_as_path", NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|O!ssI", keywords,
+                                     &BlobType, &py_blob, &opts.flags,
+                                     &old_as_path, &new_as_path))
+        return NULL;
+
+    err = git_patch_from_blobs(&patch, self->blob, old_as_path,
+                               py_blob ? py_blob->blob : NULL, new_as_path,
+                               &opts);
+    if (err < 0)
+        return Error_set(err);
+
+    return wrap_patch(patch);
+}
+
+
+PyDoc_STRVAR(Blob_diff_to_buffer__doc__,
+  "diff_to_buffer([buffer, flag, old_as_path, buffer_as_path] -> Patch\n"
+  "\n"
+  "Directly generate a :py:class:`~pygit2.Patch` from the difference\n"
+  "  between a blob and a buffer.\n"
+  "\n"
+  "Arguments:\n"
+  "\n"
+  "buffer: Raw data for new side of diff.\n"
+  "\n"
+  "flag: a GIT_DIFF_* constant.\n"
+  "\n"
+  "old_as_path: treat old blob as if it had this filename.\n"
+  "\n"
+  "buffer_as_path: treat buffer as if it had this filename.\n");
+
+PyObject *
+Blob_diff_to_buffer(Blob *self, PyObject *args, PyObject *kwds)
+{
+    git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
+    git_patch *patch;
+    char *old_as_path = NULL, *buffer_as_path = NULL;
+    const char *buffer = NULL;
+    Py_ssize_t buffer_len;
+    int err;
+    char *keywords[] = {"buffer", "flag", "old_as_path", "buffer_as_path",
+                        NULL};
+
+    if (!PyArg_ParseTupleAndKeywords(args, kwds, "|s#ssI", keywords,
+                                     &buffer, &buffer_len, &opts.flags,
+                                     &old_as_path, &buffer_as_path))
+        return NULL;
+
+    err = git_patch_from_blob_and_buffer(&patch, self->blob, old_as_path,
+                                         buffer, buffer_len, buffer_as_path,
+                                         &opts);
+    if (err < 0)
+        return Error_set(err);
+
+    return wrap_patch(patch);
+}
+
+static PyMethodDef Blob_methods[] = {
+    METHOD(Blob, diff, METH_VARARGS | METH_KEYWORDS),
+    METHOD(Blob, diff_to_buffer, METH_VARARGS | METH_KEYWORDS),
+    {NULL}
+};
+
 
 PyDoc_STRVAR(Blob_size__doc__, "Size.");
 
@@ -94,7 +189,7 @@ PyTypeObject BlobType = {
     0,                                         /* tp_weaklistoffset */
     0,                                         /* tp_iter           */
     0,                                         /* tp_iternext       */
-    0,                                         /* tp_methods        */
+    Blob_methods,                              /* tp_methods        */
     0,                                         /* tp_members        */
     Blob_getseters,                            /* tp_getset         */
     0,                                         /* tp_base           */
diff --git a/src/diff.c b/src/diff.c
index 75df6ac..1609a7d 100644
--- a/src/diff.c
+++ b/src/diff.c
@@ -57,27 +57,24 @@ wrap_diff(git_diff *diff, Repository *repo)
     return (PyObject*) py_diff;
 }
 
-PyObject*
-diff_get_patch_byindex(git_diff* diff, size_t idx)
+PyObject *
+wrap_patch(git_patch *patch)
 {
-    const git_diff_delta* delta;
-    const git_diff_hunk *hunk;
-    const git_diff_line *line;
-    git_patch* patch = NULL;
-    size_t i, j, hunk_amounts, lines_in_hunk, additions, deletions;
-    int err;
-    Hunk *py_hunk = NULL;
-    Patch *py_patch = NULL;
-    PyObject *py_line_origin=NULL, *py_line=NULL;
+    Patch *py_patch;
 
-    err = git_patch_from_diff(&patch, diff, idx);
-    if (err < 0)
-        return Error_set(err);
-
-    delta = git_patch_get_delta(patch);
+    if (!patch)
+        Py_RETURN_NONE;
 
     py_patch = PyObject_New(Patch, &PatchType);
-    if (py_patch != NULL) {
+    if (py_patch) {
+        size_t i, j, hunk_amounts, lines_in_hunk, additions, deletions;
+        const git_diff_delta *delta;
+        const git_diff_hunk *hunk;
+        const git_diff_line *line;
+        int err;
+
+        delta = git_patch_get_delta(patch);
+
         py_patch->old_file_path = delta->old_file.path;
         py_patch->new_file_path = delta->new_file.path;
         py_patch->status = git_diff_status_char(delta->status);
@@ -92,11 +89,12 @@ diff_get_patch_byindex(git_diff* diff, size_t idx)
 
         hunk_amounts = git_patch_num_hunks(patch);
         py_patch->hunks = PyList_New(hunk_amounts);
-        for (i=0; i < hunk_amounts; ++i) {
-            err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, i);
+        for (i = 0; i < hunk_amounts; ++i) {
+            Hunk *py_hunk = NULL;
 
+            err = git_patch_get_hunk(&hunk, &lines_in_hunk, patch, i);
             if (err < 0)
-                goto cleanup;
+                return Error_set(err);
 
             py_hunk = PyObject_New(Hunk, &HunkType);
             if (py_hunk != NULL) {
@@ -106,20 +104,20 @@ diff_get_patch_byindex(git_diff* diff, size_t idx)
                 py_hunk->new_lines = hunk->new_lines;
 
                 py_hunk->lines = PyList_New(lines_in_hunk);
-                for (j=0; j < lines_in_hunk; ++j) {
+                for (j = 0; j < lines_in_hunk; ++j) {
+                    PyObject *py_line_origin = NULL, *py_line = NULL;
+
                     err = git_patch_get_line_in_hunk(&line, patch, i, j);
-
                     if (err < 0)
-                        goto cleanup;
+                        return Error_set(err);
 
-                    py_line_origin = to_unicode_n(&line->origin, 1, NULL, NULL);
-                    py_line = to_unicode_n(line->content, line->content_len, NULL, NULL);
+                    py_line_origin = to_unicode_n(&line->origin, 1,
+                        NULL, NULL);
+                    py_line = to_unicode_n(line->content, line->content_len,
+                        NULL, NULL);
                     PyList_SetItem(py_hunk->lines, j,
-                        Py_BuildValue("OO",
-                            py_line_origin,
-                            py_line
-                        )
-                    );
+                        Py_BuildValue("OO", py_line_origin, py_line));
+
                     Py_DECREF(py_line_origin);
                     Py_DECREF(py_line);
                 }
@@ -130,10 +128,20 @@ diff_get_patch_byindex(git_diff* diff, size_t idx)
         }
     }
 
-cleanup:
-    git_patch_free(patch);
+    return (PyObject*) py_patch;
+}
 
-    return (err < 0) ? Error_set(err) : (PyObject*) py_patch;
+PyObject*
+diff_get_patch_byindex(git_diff *diff, size_t idx)
+{
+    git_patch *patch = NULL;
+    int err;
+
+    err = git_patch_from_diff(&patch, diff, idx);
+    if (err < 0)
+        return Error_set(err);
+
+    return (PyObject*) wrap_patch(patch);
 }
 
 static void
diff --git a/src/diff.h b/src/diff.h
index f32c930..9ba3a9e 100644
--- a/src/diff.h
+++ b/src/diff.h
@@ -42,5 +42,6 @@ PyObject* Diff_changes(Diff *self);
 PyObject* Diff_patch(Diff *self);
 
 PyObject* wrap_diff(git_diff *diff, Repository *repo);
+PyObject* wrap_patch(git_patch *patch);
 
 #endif
diff --git a/test/test_blob.py b/test/test_blob.py
index 4e7a6cd..30faee4 100644
--- a/test/test_blob.py
+++ b/test/test_blob.py
@@ -105,5 +105,16 @@ class BlobTest(utils.RepoTestCase):
         self.assertTrue(isinstance(blob, pygit2.Blob))
         self.assertEqual(pygit2.GIT_OBJ_BLOB, blob.type)
 
+    def test_diff_blob(self):
+        blob = self.repo[BLOB_SHA]
+        old_blob = self.repo['3b18e512dba79e4c8300dd08aeb37f8e728b8dad']
+        patch = blob.diff(old_blob, old_as_path="hello.txt")
+        self.assertEqual(len(patch.hunks), 1)
+
+    def test_diff_blob_to_buffer(self):
+        blob = self.repo[BLOB_SHA]
+        patch = blob.diff_to_buffer("hello world")
+        self.assertEqual(len(patch.hunks), 1)
+
 if __name__ == '__main__':
     unittest.main()