Added: Repository.diff() - porcelain method similiar to

This commit is contained in:
Nico von Geyso
2013-05-18 14:42:31 +02:00
parent 8c76a14a99
commit 196d0595b0
4 changed files with 109 additions and 18 deletions

View File

@@ -29,10 +29,11 @@
from string import hexdigits
# Import from pygit2
from utils import text_type
from _pygit2 import Repository as _Repository
from _pygit2 import Oid, GIT_OID_HEXSZ, GIT_OID_MINPREFIXLEN
from _pygit2 import GIT_CHECKOUT_SAFE_CREATE
from _pygit2 import Reference
from _pygit2 import Reference, Tree, Commit, Blob
class Repository(_Repository):
@@ -128,3 +129,68 @@ class Repository(_Repository):
treeish = self[oid]
self.checkout_tree(treeish, strategy)
self.head = refname
#
# Diff
#
def diff(self, a=None, b=None, cached=False, flags=0):
"""
Show changes between the working tree and the index or a tree,
changes between the index and a tree, changes between two trees, or
changes between two blobs.
Examples::
# Changes in the working tree not yet staged for the next commit
>>> diff()
# Changes between the index and your last commit
>>> diff(cached=True)
# Changes in the working tree since your last commit
>>> diff('HEAD')
# Changes between commits
>>> t0 = revparse_single('HEAD')
>>> t1 = revparse_single('HEAD^')
>>> diff(t0, t1)
>>> diff('HEAD', 'HEAD^') # equivalent
If you want to diff a tree against an empty tree, use the low level
API (Tree.diff_to_tree()) directly.
"""
def treeish_to_tree(obj):
if isinstance(obj, text_type):
obj = self.revparse_single(obj)
if isinstance(obj, Commit):
return obj.tree
elif isinstance(obj, Reference):
oid = obj.resolve().target
return self[oid]
a = treeish_to_tree(a) or a
b = treeish_to_tree(b) or b
# Case 1: Diff tree to tree
if isinstance(a, Tree) and isinstance(b, Tree):
return a.diff_to_tree(b, flags=flags)
# Case 2: Index to workdir
elif a is None and b is None:
return self.index.diff()
# Case 3: Diff tree to index or workdir
elif isinstance(a, Tree) and b is None:
if cached:
return a.diff_to_index(self.index, flags=flags)
else:
return a.diff_to_workdir(flags)
# Case 4: Diff blob to blob
if isinstance(a, Blob) and isinstance(b, Blob):
raise NotImplementedError('git_diff_blob_to_blob()')
raise ValueError("Only blobs and treeish can be diffed")

View File

@@ -27,3 +27,13 @@
# feel free to add utils functions here
import sys
# python2/3 compability types for isinstance()
if sys.version < '3':
text_type = unicode
binary_type = str
else:
text_type = str
binary_type = bytes

View File

@@ -300,7 +300,7 @@ Tree_diff_to_workdir(Tree *self, PyObject *args)
PyDoc_STRVAR(Tree_diff_to_index__doc__, "\n");
PyObject *
Tree_diff_to_index(Tree *self, PyObject *args)
Tree_diff_to_index(Tree *self, PyObject *args, PyObject *kwds)
{
git_diff_options opts = GIT_DIFF_OPTIONS_INIT;
git_diff_list *diff;
@@ -383,7 +383,7 @@ PyMappingMethods Tree_as_mapping = {
PyMethodDef Tree_methods[] = {
METHOD(Tree, diff_to_tree, METH_VARARGS | METH_KEYWORDS),
METHOD(Tree, diff_to_workdir, METH_VARARGS),
METHOD(Tree, diff_to_index, METH_VARARGS),
METHOD(Tree, diff_to_index, METH_VARARGS | METH_KEYWORDS),
{NULL}
};

View File

@@ -91,17 +91,25 @@ HUNK_EXPECTED = """- a contents 2
class DiffDirtyTest(utils.DirtyRepoTestCase):
def test_diff_empty_index(self):
repo = self.repo
head = repo[repo.lookup_reference('HEAD').resolve().target]
diff = head.tree.diff_to_index(repo.index)
files = [patch.new_file_path for patch in diff]
self.assertEqual(DIFF_INDEX_EXPECTED, files)
diff = repo.diff('HEAD', cached=True)
files = [patch.new_file_path for patch in diff]
self.assertEqual(DIFF_INDEX_EXPECTED, files)
def test_workdir_to_tree(self):
repo = self.repo
head = repo[repo.lookup_reference('HEAD').resolve().target]
diff = head.tree.diff_to_workdir()
diff = head.tree.diff_to_workdir()
files = [patch.new_file_path for patch in diff]
self.assertEqual(DIFF_WORKDIR_EXPECTED, files)
diff = repo.diff('HEAD')
files = [patch.new_file_path for patch in diff]
self.assertEqual(DIFF_WORKDIR_EXPECTED, files)
@@ -117,8 +125,12 @@ class DiffTest(utils.BareRepoTestCase):
def test_diff_empty_index(self):
repo = self.repo
head = repo[repo.lookup_reference('HEAD').resolve().target]
diff = head.tree.diff_to_index(repo.index)
diff = head.tree.diff_to_index(repo.index)
files = [patch.new_file_path.split('/')[0] for patch in diff]
self.assertEqual([x.name for x in head.tree], files)
diff = repo.diff('HEAD', cached=True)
files = [patch.new_file_path.split('/')[0] for patch in diff]
self.assertEqual([x.name for x in head.tree], files)
@@ -126,22 +138,25 @@ class DiffTest(utils.BareRepoTestCase):
commit_a = self.repo[COMMIT_SHA1_1]
commit_b = self.repo[COMMIT_SHA1_2]
diff = commit_a.tree.diff_to_tree(commit_b.tree)
def _test(diff):
# self.assertIsNotNone is 2.7 only
self.assertTrue(diff is not None)
# self.assertIn is 2.7 only
self.assertEqual(2, sum(map(lambda x: len(x.hunks), diff)))
# self.assertIsNotNone is 2.7 only
self.assertTrue(diff is not None)
# self.assertIn is 2.7 only
self.assertEqual(2, sum(map(lambda x: len(x.hunks), diff)))
patch = diff[0]
hunk = patch.hunks[0]
self.assertEqual(hunk.old_start, 1)
self.assertEqual(hunk.old_lines, 1)
self.assertEqual(hunk.new_start, 1)
self.assertEqual(hunk.new_lines, 1)
patch = diff[0]
hunk = patch.hunks[0]
self.assertEqual(hunk.old_start, 1)
self.assertEqual(hunk.old_lines, 1)
self.assertEqual(hunk.new_start, 1)
self.assertEqual(hunk.new_lines, 1)
self.assertEqual(patch.old_file_path, 'a')
self.assertEqual(patch.new_file_path, 'a')
_test(commit_a.tree.diff_to_tree(commit_b.tree))
_test(self.repo.diff(COMMIT_SHA1_1, COMMIT_SHA1_2))
self.assertEqual(patch.old_file_path, 'a')
self.assertEqual(patch.new_file_path, 'a')
def test_diff_empty_tree(self):
commit_a = self.repo[COMMIT_SHA1_1]