Added: Repository.diff() - porcelain method similiar to
This commit is contained in:
@@ -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")
|
||||
|
||||
@@ -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
|
||||
|
||||
@@ -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}
|
||||
};
|
||||
|
||||
|
||||
@@ -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]
|
||||
|
||||
Reference in New Issue
Block a user