Skip to content

Commit 4adafc5

Browse files
committed
Merge pull request #408 from nvie/master
Add support for diffing against root commit
2 parents 76e19e4 + 3297fe5 commit 4adafc5

File tree

7 files changed

+55
-18
lines changed

7 files changed

+55
-18
lines changed

doc/source/changes.rst

+3
Original file line numberDiff line numberDiff line change
@@ -4,6 +4,9 @@ Changelog
44

55
1.0.3 - Fixes
66
=============
7+
8+
* `Commit.diff()` now supports diffing the root commit via `Commit.diff(NULL_TREE)`.
9+
* `Repo.blame()` now respects `incremental=True`, supporting incremental blames. Incremental blames are slightly faster since they don't include the file's contents in them.
710
* IMPORTANT: This release drops support for python 2.6, which is officially deprecated by the python maintainers.
811

912
1.0.2 - Fixes

git/compat.py

+5-9
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,6 @@
88
# flake8: noqa
99

1010
import sys
11-
import six
1211

1312
from gitdb.utils.compat import (
1413
PY3,
@@ -34,6 +33,7 @@ def bchr(n):
3433
return bytes([n])
3534
def mviter(d):
3635
return d.values()
36+
range = xrange
3737
unicode = str
3838
else:
3939
FileType = file
@@ -44,21 +44,17 @@ def mviter(d):
4444
byte_ord = ord
4545
bchr = chr
4646
unicode = unicode
47+
range = xrange
4748
def mviter(d):
4849
return d.itervalues()
4950

50-
PRE_PY27 = sys.version_info < (2, 7)
51-
5251

5352
def safe_decode(s):
5453
"""Safely decodes a binary string to unicode"""
55-
if isinstance(s, six.text_type):
54+
if isinstance(s, unicode):
5655
return s
57-
elif isinstance(s, six.binary_type):
58-
if PRE_PY27:
59-
return s.decode(defenc) # we're screwed
60-
else:
61-
return s.decode(defenc, errors='replace')
56+
elif isinstance(s, bytes):
57+
return s.decode(defenc, errors='replace')
6258
raise TypeError('Expected bytes or text, but got %r' % (s,))
6359

6460

git/diff.py

+16-5
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,10 @@
1616
)
1717

1818

19-
__all__ = ('Diffable', 'DiffIndex', 'Diff')
19+
__all__ = ('Diffable', 'DiffIndex', 'Diff', 'NULL_TREE')
20+
21+
# Special object to compare against the empty tree in diffs
22+
NULL_TREE = object()
2023

2124

2225
class Diffable(object):
@@ -49,6 +52,7 @@ def diff(self, other=Index, paths=None, create_patch=False, **kwargs):
4952
If None, we will be compared to the working tree.
5053
If Treeish, it will be compared against the respective tree
5154
If Index ( type ), it will be compared against the index.
55+
If git.NULL_TREE, it will compare against the empty tree.
5256
It defaults to Index to assure the method will not by-default fail
5357
on bare repositories.
5458
@@ -87,10 +91,17 @@ def diff(self, other=Index, paths=None, create_patch=False, **kwargs):
8791
if paths is not None and not isinstance(paths, (tuple, list)):
8892
paths = [paths]
8993

90-
if other is not None and other is not self.Index:
91-
args.insert(0, other)
94+
diff_cmd = self.repo.git.diff
9295
if other is self.Index:
93-
args.insert(0, "--cached")
96+
args.insert(0, '--cached')
97+
elif other is NULL_TREE:
98+
args.insert(0, '-r') # recursive diff-tree
99+
args.insert(0, '--root')
100+
diff_cmd = self.repo.git.diff_tree
101+
elif other is not None:
102+
args.insert(0, '-r') # recursive diff-tree
103+
args.insert(0, other)
104+
diff_cmd = self.repo.git.diff_tree
94105

95106
args.insert(0, self)
96107

@@ -101,7 +112,7 @@ def diff(self, other=Index, paths=None, create_patch=False, **kwargs):
101112
# END paths handling
102113

103114
kwargs['as_process'] = True
104-
proc = self.repo.git.diff(*self._process_diff_args(args), **kwargs)
115+
proc = diff_cmd(*self._process_diff_args(args), **kwargs)
105116

106117
diff_method = Diff._index_from_raw_format
107118
if create_patch:

git/repo/base.py

+1-1
Original file line numberDiff line numberDiff line change
@@ -54,12 +54,12 @@
5454
defenc,
5555
PY3,
5656
safe_decode,
57+
range,
5758
)
5859

5960
import os
6061
import sys
6162
import re
62-
from six.moves import range
6363

6464
DefaultDBType = GitCmdObjectDB
6565
if sys.version_info[:2] < (2, 5): # python 2.4 compatiblity

git/test/fixtures/diff_initial

+10
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
--- /dev/null
2+
+++ b/CHANGES
3+
@@ -0,0 +1,7 @@
4+
+=======
5+
+CHANGES
6+
+=======
7+
+
8+
+0.1.0
9+
+=====
10+
+initial release

git/test/test_diff.py

+18-2
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,8 @@
2121
Repo,
2222
GitCommandError,
2323
Diff,
24-
DiffIndex
24+
DiffIndex,
25+
NULL_TREE,
2526
)
2627

2728

@@ -128,6 +129,21 @@ def test_diff_index_raw_format(self):
128129
assert res[0].deleted_file
129130
assert res[0].b_path == ''
130131

132+
def test_diff_initial_commit(self):
133+
initial_commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781')
134+
135+
# Without creating a patch...
136+
diff_index = initial_commit.diff(NULL_TREE)
137+
assert diff_index[0].b_path == 'CHANGES'
138+
assert diff_index[0].new_file
139+
assert diff_index[0].diff == ''
140+
141+
# ...and with creating a patch
142+
diff_index = initial_commit.diff(NULL_TREE, create_patch=True)
143+
assert diff_index[0].b_path == 'CHANGES'
144+
assert diff_index[0].new_file
145+
assert diff_index[0].diff == fixture('diff_initial')
146+
131147
def test_diff_patch_format(self):
132148
# test all of the 'old' format diffs for completness - it should at least
133149
# be able to deal with it
@@ -149,7 +165,7 @@ def test_diff_interface(self):
149165
diff_item = commit.tree
150166
# END use tree every second item
151167

152-
for other in (None, commit.Index, commit.parents[0]):
168+
for other in (None, NULL_TREE, commit.Index, commit.parents[0]):
153169
for paths in (None, "CHANGES", ("CHANGES", "lib")):
154170
for create_patch in range(2):
155171
diff_index = diff_item.diff(other=other, paths=paths, create_patch=create_patch)

tox.ini

+2-1
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
[tox]
2-
envlist = py26,py27,py33,py34,flake8
2+
envlist = py26,py27,py33,py34,py35,flake8
33

44
[testenv]
55
commands = nosetests {posargs}
66
deps = -r{toxinidir}/requirements.txt
77
-r{toxinidir}/test-requirements.txt
8+
passenv = HOME
89

910
[testenv:cover]
1011
commands = nosetests --with-coverage {posargs}

0 commit comments

Comments
 (0)