From 91e211d4f9b528943ef7bf157fe89c2035934aa9 Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Thu, 13 Sep 2012 13:47:57 -0400
Subject: [PATCH 1/6] error: replace `GIT_REVWALKOVER` with `GIT_ITEROVER`.

This catches up with changes in libgit2:

  commit f335ecd6e126aa9dea28786522c0e6ce71596e91
  Author: Russell Belfer <rb@github.com>
  Date:   Thu Aug 30 14:24:16 2012 -0700
---
 src/pygit2/error.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pygit2/error.c b/src/pygit2/error.c
index 11129a3..dd4138d 100644
--- a/src/pygit2/error.c
+++ b/src/pygit2/error.c
@@ -55,7 +55,7 @@ PyObject * Error_type(int type)
             return GitError;
 
         /** No entries left in ref walker */
-        case GIT_REVWALKOVER:
+        case GIT_ITEROVER:
             return PyExc_StopIteration;
     }
 

From 8e1910281523e28dad4c1eb39c6b6ab92919437d Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Thu, 13 Sep 2012 13:53:37 -0400
Subject: [PATCH 2/6] index: Add NULL `stats` argument to git_index_read_tree
 call.

This catches up with changes in libgit2:

  commit 4bf5115642b64851f9a32a8157010b588bf44103
  Author: Ben Straub <bstraub@github.com>
  Date:   Mon Jul 30 14:52:46 2012 -0700

    Enable stats on git_index_read_tree.

    Replace with the contents of
    git_index_read_tree_with_stats() and improve
    documentation comments.
---
 src/pygit2/index.c | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/src/pygit2/index.c b/src/pygit2/index.c
index 7dec030..d0de48e 100644
--- a/src/pygit2/index.c
+++ b/src/pygit2/index.c
@@ -331,7 +331,7 @@ Index_read_tree(Index *self, PyObject *value)
     if (err < 0)
         return Error_set(err);
 
-    err = git_index_read_tree(self->index, tree);
+    err = git_index_read_tree(self->index, tree, NULL);
     if (err < 0)
         return Error_set(err);
 

From 651aa6a830edbbe9b2f472e25bdceda30a869dd9 Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Thu, 13 Sep 2012 16:14:24 -0400
Subject: [PATCH 3/6] tree: rename Tree.attributes to Tree.filemode.

This catches up with changes in libgit2:

  commit 9d7ac675d06dab2e000ad32f9248631af0191f85
  Author: nulltoken <emeric.fermas@gmail.com>
  Date:   Tue Aug 21 11:45:16 2012 +0200

    tree entry: rename git_tree_entry_attributes() into git_tree_entry_filemode()
---
 README.rst               | 2 +-
 include/pygit2/tree.h    | 2 +-
 src/pygit2/tree.c        | 6 +++---
 test/test_tree.py        | 6 +++---
 test/test_treebuilder.py | 2 +-
 5 files changed, 9 insertions(+), 9 deletions(-)

diff --git a/README.rst b/README.rst
index afdeeb8..bdf6225 100644
--- a/README.rst
+++ b/README.rst
@@ -200,7 +200,7 @@ This is the interface of a tree entry::
     TreeEntry.name        -- name of the tree entry
     TreeEntry.oid         -- the id of the git object
     TreeEntry.hex         -- hexadecimal representation of the oid
-    TreeEntry.attributes  -- the Unix file attributes
+    TreeEntry.filemode    -- the Unix file attributes
     TreeEntry.to_object() -- returns the git object (equivalent to repo[entry.oid])
 
 
diff --git a/include/pygit2/tree.h b/include/pygit2/tree.h
index e4b086f..68218f7 100644
--- a/include/pygit2/tree.h
+++ b/include/pygit2/tree.h
@@ -33,7 +33,7 @@
 #include <git2.h>
 #include <pygit2/types.h>
 
-PyObject* TreeEntry_get_attributes(TreeEntry *self);
+PyObject* TreeEntry_get_filemode(TreeEntry *self);
 PyObject* TreeEntry_get_name(TreeEntry *self);
 PyObject* TreeEntry_get_oid(TreeEntry *self);
 PyObject* TreeEntry_get_hex(TreeEntry *self);
diff --git a/src/pygit2/tree.c b/src/pygit2/tree.c
index 827b1c0..62db682 100644
--- a/src/pygit2/tree.c
+++ b/src/pygit2/tree.c
@@ -46,9 +46,9 @@ TreeEntry_dealloc(TreeEntry *self)
 }
 
 PyObject *
-TreeEntry_get_attributes(TreeEntry *self)
+TreeEntry_get_filemode(TreeEntry *self)
 {
-    return PyInt_FromLong(git_tree_entry_attributes(self->entry));
+    return PyInt_FromLong(git_tree_entry_filemode(self->entry));
 }
 
 PyObject *
@@ -84,7 +84,7 @@ TreeEntry_to_object(TreeEntry *self)
 }
 
 PyGetSetDef TreeEntry_getseters[] = {
-    {"attributes", (getter)TreeEntry_get_attributes, NULL, "attributes", NULL},
+    {"filemode", (getter)TreeEntry_get_filemode, NULL, "filemode", NULL},
     {"name", (getter)TreeEntry_get_name, NULL, "name", NULL},
     {"oid", (getter)TreeEntry_get_oid, NULL, "object id", NULL},
     {"hex", (getter)TreeEntry_get_hex, NULL, "hex oid", NULL},
diff --git a/test/test_tree.py b/test/test_tree.py
index 4ec22a9..eceb7f2 100644
--- a/test/test_tree.py
+++ b/test/test_tree.py
@@ -42,11 +42,11 @@ SUBTREE_SHA = '614fd9a3094bf618ea938fffc00e7d1a54f89ad0'
 
 class TreeTest(utils.BareRepoTestCase):
 
-    def assertTreeEntryEqual(self, entry, sha, name, attributes):
+    def assertTreeEntryEqual(self, entry, sha, name, filemode):
         self.assertEqual(entry.hex, sha)
         self.assertEqual(entry.name, name)
-        self.assertEqual(entry.attributes, attributes,
-                         '0%o != 0%o' % (entry.attributes, attributes))
+        self.assertEqual(entry.filemode, filemode,
+                         '0%o != 0%o' % (entry.filemode, filemode))
 
     def test_read_tree(self):
         tree = self.repo[TREE_SHA]
diff --git a/test/test_treebuilder.py b/test/test_treebuilder.py
index 8dbea77..de6e85d 100644
--- a/test/test_treebuilder.py
+++ b/test/test_treebuilder.py
@@ -57,7 +57,7 @@ class TreeBuilderTest(utils.BareRepoTestCase):
         tree = self.repo[TREE_SHA]
         bld = self.repo.TreeBuilder()
         for e in tree:
-            bld.insert(e.name, e.hex, e.attributes)
+            bld.insert(e.name, e.hex, e.filemode)
 
         result = bld.write()
         self.assertEqual(tree.oid, result)

From 477e48ef6c9a4329fdcd42e06554544b83654fbc Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Thu, 13 Sep 2012 16:30:21 -0400
Subject: [PATCH 4/6] test_diff: hunk.old_lines should be 1 in test_diff_tree
 and test_diff_merge.

In both cases, the file contents change from 'X contents\n' to 'X
contents 2\n' (where 'X' is 'a' or 'b').  This means were removing one
line and adding another.

I'm not sure how this test was passing against libgit2 v0.17.0, so I
may be missing something important.
---
 test/test_diff.py | 8 ++++----
 1 file changed, 4 insertions(+), 4 deletions(-)

diff --git a/test/test_diff.py b/test/test_diff.py
index 7133bb0..5f61b09 100644
--- a/test/test_diff.py
+++ b/test/test_diff.py
@@ -123,9 +123,9 @@ class DiffTest(utils.BareRepoTestCase):
 
         hunk = diff.changes['hunks'][0]
         self.assertEqual(hunk.old_start, 1)
-        self.assertEqual(hunk.old_lines, 0)
+        self.assertEqual(hunk.old_lines, 1)
         self.assertEqual(hunk.new_start, 1)
-        self.assertEqual(hunk.new_lines, 0)
+        self.assertEqual(hunk.new_lines, 1)
 
         self.assertEqual(hunk.old_file, 'a')
         self.assertEqual(hunk.new_file, 'a')
@@ -157,9 +157,9 @@ class DiffTest(utils.BareRepoTestCase):
 
         hunk = diff_b.changes['hunks'][1]
         self.assertEqual(hunk.old_start, 1)
-        self.assertEqual(hunk.old_lines, 0)
+        self.assertEqual(hunk.old_lines, 1)
         self.assertEqual(hunk.new_start, 1)
-        self.assertEqual(hunk.new_lines, 0)
+        self.assertEqual(hunk.new_lines, 1)
 
         self.assertEqual(hunk.old_file, 'b')
         self.assertEqual(hunk.new_file, 'b')

From cc7f137f7b003abb1bd105d7855a8b16d464b451 Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Thu, 13 Sep 2012 16:41:56 -0400
Subject: [PATCH 5/6] object: factor `wrap_object` out of
 `lookup_object_prefix`.

Generating an `Object *` from a `git_object *` may be useful in other
functions (e.g. the upcoming `Repository_revparse_single`).
---
 include/pygit2/object.h |  1 +
 src/pygit2/object.c     | 38 ++++++++++++++++++++++++++++++++++++++
 src/pygit2/repository.c | 28 ++--------------------------
 3 files changed, 41 insertions(+), 26 deletions(-)

diff --git a/include/pygit2/object.h b/include/pygit2/object.h
index 5255996..64bf612 100644
--- a/include/pygit2/object.h
+++ b/include/pygit2/object.h
@@ -37,5 +37,6 @@ PyObject* Object_get_oid(Object *self);
 PyObject* Object_get_hex(Object *self);
 PyObject* Object_get_type(Object *self);
 PyObject* Object_read_raw(Object *self);
+PyObject* wrap_object(git_object *c_object, Repository *repo);
 
 #endif
diff --git a/src/pygit2/object.c b/src/pygit2/object.c
index 12a0855..172cf3f 100644
--- a/src/pygit2/object.c
+++ b/src/pygit2/object.c
@@ -34,6 +34,12 @@
 #include <pygit2/repository.h>
 #include <pygit2/object.h>
 
+extern PyTypeObject TreeType;
+extern PyTypeObject CommitType;
+extern PyTypeObject BlobType;
+extern PyTypeObject TagType;
+
+
 void
 Object_dealloc(Object* self)
 {
@@ -145,3 +151,35 @@ PyTypeObject ObjectType = {
     0,                                         /* tp_alloc          */
     0,                                         /* tp_new            */
 };
+
+PyObject *
+wrap_object(git_object *c_object, Repository *repo)
+{
+    Object *py_obj = NULL;
+
+    switch (git_object_type(c_object)) {
+        case GIT_OBJ_COMMIT:
+            py_obj = PyObject_New(Object, &CommitType);
+            break;
+        case GIT_OBJ_TREE:
+            py_obj = PyObject_New(Object, &TreeType);
+            break;
+        case GIT_OBJ_BLOB:
+            py_obj = PyObject_New(Object, &BlobType);
+            break;
+        case GIT_OBJ_TAG:
+            py_obj = PyObject_New(Object, &TagType);
+            break;
+        default:
+            assert(0);
+    }
+
+    if (py_obj) {
+        py_obj->obj = c_object;
+				if (repo) {
+            py_obj->repo = repo;
+            Py_INCREF(repo);
+        }
+    }
+    return (PyObject *)py_obj;
+}
diff --git a/src/pygit2/repository.c b/src/pygit2/repository.c
index 7650388..30f7030 100644
--- a/src/pygit2/repository.c
+++ b/src/pygit2/repository.c
@@ -31,6 +31,7 @@
 #include <pygit2/types.h>
 #include <pygit2/reference.h>
 #include <pygit2/utils.h>
+#include <pygit2/object.h>
 #include <pygit2/oid.h>
 #include <pygit2/repository.h>
 
@@ -40,9 +41,6 @@ extern PyTypeObject IndexType;
 extern PyTypeObject WalkerType;
 extern PyTypeObject SignatureType;
 extern PyTypeObject TreeType;
-extern PyTypeObject CommitType;
-extern PyTypeObject BlobType;
-extern PyTypeObject TagType;
 extern PyTypeObject TreeBuilderType;
 extern PyTypeObject ConfigType;
 extern PyTypeObject DiffType;
@@ -72,29 +70,7 @@ lookup_object_prefix(Repository *repo, const git_oid *oid, size_t len,
     if (err < 0)
         return Error_set_oid(err, oid, len);
 
-    switch (git_object_type(obj)) {
-        case GIT_OBJ_COMMIT:
-            py_obj = PyObject_New(Object, &CommitType);
-            break;
-        case GIT_OBJ_TREE:
-            py_obj = PyObject_New(Object, &TreeType);
-            break;
-        case GIT_OBJ_BLOB:
-            py_obj = PyObject_New(Object, &BlobType);
-            break;
-        case GIT_OBJ_TAG:
-            py_obj = PyObject_New(Object, &TagType);
-            break;
-        default:
-            assert(0);
-    }
-
-    if (py_obj) {
-        py_obj->obj = obj;
-        py_obj->repo = repo;
-        Py_INCREF(repo);
-    }
-    return (PyObject*)py_obj;
+    return wrap_object(obj, repo);
 }
 
 PyObject *

From 0238fb72dfdf2a2308f2da347717cbaafddc4b83 Mon Sep 17 00:00:00 2001
From: "W. Trevor King" <wking@tremily.us>
Date: Thu, 13 Sep 2012 17:09:12 -0400
Subject: [PATCH 6/6] repository: add Repository.revparse_single().

This provides access to libgit2's 'git_revparse_single'.
---
 README.rst              |  6 ++++++
 src/pygit2/repository.c | 28 ++++++++++++++++++++++++++++
 test/test_repository.py |  4 ++++
 3 files changed, 38 insertions(+)

diff --git a/README.rst b/README.rst
index bdf6225..18ca051 100644
--- a/README.rst
+++ b/README.rst
@@ -270,6 +270,12 @@ The interface for RefLogEntry::
     RefLogEntry.oid_old   -- oid of old reference
     RefLogEntry.oid_new   -- oid of new reference
 
+Revision parsing
+================
+
+You can use any of the fancy `<rev>` forms supported by libgit2::
+
+    >>> commit = repo.revparse_single('HEAD^')
 
 Revision walking
 =================
diff --git a/src/pygit2/repository.c b/src/pygit2/repository.c
index 30f7030..8ba3704 100644
--- a/src/pygit2/repository.c
+++ b/src/pygit2/repository.c
@@ -198,6 +198,30 @@ Repository_getitem(Repository *self, PyObject *value)
     return lookup_object_prefix(self, &oid, len, GIT_OBJ_ANY);
 }
 
+PyObject *
+Repository_revparse_single(Repository *self, PyObject *py_spec)
+{
+    git_object *c_obj;
+    char *c_spec;
+		char *encoding = "ascii";
+    int err;
+
+    /* 1- Get the C revision spec */
+    c_spec = py_str_to_c_str(py_spec, encoding);
+    if (c_spec == NULL)
+        return NULL;
+
+    /* 2- Lookup */
+    err = git_revparse_single(&c_obj, self->repo, c_spec);
+    if (err < 0)  {
+        PyObject *err_obj = Error_set_str(err, c_spec);
+        free(c_spec);
+        return err_obj;
+    }
+
+    return wrap_object(c_obj, self);
+}
+
 git_odb_object *
 Repository_read_raw(git_repository *repo, const git_oid *oid, size_t len)
 {
@@ -792,6 +816,10 @@ PyMethodDef Repository_methods[] = {
       "Return a list with all the references in the repository."},
     {"lookup_reference", (PyCFunction)Repository_lookup_reference, METH_O,
        "Lookup a reference by its name in a repository."},
+    {"revparse_single", (PyCFunction)Repository_revparse_single, METH_O,
+     "Find an object, as specified by a revision string. See "
+     "`man gitrevisions`, or the documentation for `git rev-parse` for "
+     "information on the syntax accepted."},
     {"create_blob", (PyCFunction)Repository_create_blob,
      METH_VARARGS,
      "Create a new blob from memory"},
diff --git a/test/test_repository.py b/test/test_repository.py
index 9164b87..bf74437 100644
--- a/test/test_repository.py
+++ b/test/test_repository.py
@@ -40,6 +40,7 @@ from . import utils
 
 
 HEAD_SHA  = '2cdae28389c059815e951d0bb9eed6533f61a46b'
+PARENT_SHA = '5fe808e8953c12735680c257f56600cb0de44b10'  # HEAD^
 A_HEX_SHA = 'af431f20fc541ed6d5afede3e2dc7160f6f01f16'
 A_BIN_SHA = binascii.unhexlify(A_HEX_SHA.encode('ascii'))
 
@@ -127,6 +128,9 @@ class RepositoryTest(utils.BareRepoTestCase):
     def test_get_workdir(self):
         self.assertEqual(self.repo.workdir, None)
 
+    def test_revparse_single(self):
+        parent = self.repo.revparse_single('HEAD^')
+        self.assertEqual(parent.hex, PARENT_SHA)
 
 
 class RepositoryTest_II(utils.RepoTestCase):