summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorVincent Driessen <me@nvie.com>2016-04-19 21:35:39 +0200
committerVincent Driessen <me@nvie.com>2016-04-19 21:35:39 +0200
commit4adafc5a99947301ca0ce40511991d6d54c57a41 (patch)
treee7cf8a66b178baf8fa4fcfddc46f2134c48042ab
parent76e19e4221684f24ef881415ec6ccb6bab6eb8e8 (diff)
parent3297fe50067da728eb6f3f47764efb223e0d6ea4 (diff)
downloadgitpython-4adafc5a99947301ca0ce40511991d6d54c57a41.tar.gz
Merge pull request #408 from nvie/master
Add support for diffing against root commit
-rw-r--r--doc/source/changes.rst3
-rw-r--r--git/compat.py14
-rw-r--r--git/diff.py21
-rw-r--r--git/repo/base.py2
-rw-r--r--git/test/fixtures/diff_initial10
-rw-r--r--git/test/test_diff.py20
-rw-r--r--tox.ini3
7 files changed, 55 insertions, 18 deletions
diff --git a/doc/source/changes.rst b/doc/source/changes.rst
index 23954c7f..4fdf39ca 100644
--- a/doc/source/changes.rst
+++ b/doc/source/changes.rst
@@ -4,6 +4,9 @@ Changelog
1.0.3 - Fixes
=============
+
+* `Commit.diff()` now supports diffing the root commit via `Commit.diff(NULL_TREE)`.
+* `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.
* IMPORTANT: This release drops support for python 2.6, which is officially deprecated by the python maintainers.
1.0.2 - Fixes
diff --git a/git/compat.py b/git/compat.py
index 146bfd4b..7bd8e494 100644
--- a/git/compat.py
+++ b/git/compat.py
@@ -8,7 +8,6 @@
# flake8: noqa
import sys
-import six
from gitdb.utils.compat import (
PY3,
@@ -34,6 +33,7 @@ if PY3:
return bytes([n])
def mviter(d):
return d.values()
+ range = xrange
unicode = str
else:
FileType = file
@@ -44,21 +44,17 @@ else:
byte_ord = ord
bchr = chr
unicode = unicode
+ range = xrange
def mviter(d):
return d.itervalues()
-PRE_PY27 = sys.version_info < (2, 7)
-
def safe_decode(s):
"""Safely decodes a binary string to unicode"""
- if isinstance(s, six.text_type):
+ if isinstance(s, unicode):
return s
- elif isinstance(s, six.binary_type):
- if PRE_PY27:
- return s.decode(defenc) # we're screwed
- else:
- return s.decode(defenc, errors='replace')
+ elif isinstance(s, bytes):
+ return s.decode(defenc, errors='replace')
raise TypeError('Expected bytes or text, but got %r' % (s,))
diff --git a/git/diff.py b/git/diff.py
index 062220df..de3aa1e8 100644
--- a/git/diff.py
+++ b/git/diff.py
@@ -16,7 +16,10 @@ from git.compat import (
)
-__all__ = ('Diffable', 'DiffIndex', 'Diff')
+__all__ = ('Diffable', 'DiffIndex', 'Diff', 'NULL_TREE')
+
+# Special object to compare against the empty tree in diffs
+NULL_TREE = object()
class Diffable(object):
@@ -49,6 +52,7 @@ class Diffable(object):
If None, we will be compared to the working tree.
If Treeish, it will be compared against the respective tree
If Index ( type ), it will be compared against the index.
+ If git.NULL_TREE, it will compare against the empty tree.
It defaults to Index to assure the method will not by-default fail
on bare repositories.
@@ -87,10 +91,17 @@ class Diffable(object):
if paths is not None and not isinstance(paths, (tuple, list)):
paths = [paths]
- if other is not None and other is not self.Index:
- args.insert(0, other)
+ diff_cmd = self.repo.git.diff
if other is self.Index:
- args.insert(0, "--cached")
+ args.insert(0, '--cached')
+ elif other is NULL_TREE:
+ args.insert(0, '-r') # recursive diff-tree
+ args.insert(0, '--root')
+ diff_cmd = self.repo.git.diff_tree
+ elif other is not None:
+ args.insert(0, '-r') # recursive diff-tree
+ args.insert(0, other)
+ diff_cmd = self.repo.git.diff_tree
args.insert(0, self)
@@ -101,7 +112,7 @@ class Diffable(object):
# END paths handling
kwargs['as_process'] = True
- proc = self.repo.git.diff(*self._process_diff_args(args), **kwargs)
+ proc = diff_cmd(*self._process_diff_args(args), **kwargs)
diff_method = Diff._index_from_raw_format
if create_patch:
diff --git a/git/repo/base.py b/git/repo/base.py
index 9d013230..f74e0b59 100644
--- a/git/repo/base.py
+++ b/git/repo/base.py
@@ -54,12 +54,12 @@ from git.compat import (
defenc,
PY3,
safe_decode,
+ range,
)
import os
import sys
import re
-from six.moves import range
DefaultDBType = GitCmdObjectDB
if sys.version_info[:2] < (2, 5): # python 2.4 compatiblity
diff --git a/git/test/fixtures/diff_initial b/git/test/fixtures/diff_initial
new file mode 100644
index 00000000..6037c677
--- /dev/null
+++ b/git/test/fixtures/diff_initial
@@ -0,0 +1,10 @@
+--- /dev/null
++++ b/CHANGES
+@@ -0,0 +1,7 @@
++=======
++CHANGES
++=======
++
++0.1.0
++=====
++initial release
diff --git a/git/test/test_diff.py b/git/test/test_diff.py
index b0d98248..56e395fd 100644
--- a/git/test/test_diff.py
+++ b/git/test/test_diff.py
@@ -21,7 +21,8 @@ from git import (
Repo,
GitCommandError,
Diff,
- DiffIndex
+ DiffIndex,
+ NULL_TREE,
)
@@ -128,6 +129,21 @@ class TestDiff(TestBase):
assert res[0].deleted_file
assert res[0].b_path == ''
+ def test_diff_initial_commit(self):
+ initial_commit = self.rorepo.commit('33ebe7acec14b25c5f84f35a664803fcab2f7781')
+
+ # Without creating a patch...
+ diff_index = initial_commit.diff(NULL_TREE)
+ assert diff_index[0].b_path == 'CHANGES'
+ assert diff_index[0].new_file
+ assert diff_index[0].diff == ''
+
+ # ...and with creating a patch
+ diff_index = initial_commit.diff(NULL_TREE, create_patch=True)
+ assert diff_index[0].b_path == 'CHANGES'
+ assert diff_index[0].new_file
+ assert diff_index[0].diff == fixture('diff_initial')
+
def test_diff_patch_format(self):
# test all of the 'old' format diffs for completness - it should at least
# be able to deal with it
@@ -149,7 +165,7 @@ class TestDiff(TestBase):
diff_item = commit.tree
# END use tree every second item
- for other in (None, commit.Index, commit.parents[0]):
+ for other in (None, NULL_TREE, commit.Index, commit.parents[0]):
for paths in (None, "CHANGES", ("CHANGES", "lib")):
for create_patch in range(2):
diff_index = diff_item.diff(other=other, paths=paths, create_patch=create_patch)
diff --git a/tox.ini b/tox.ini
index da624b5e..9f03872b 100644
--- a/tox.ini
+++ b/tox.ini
@@ -1,10 +1,11 @@
[tox]
-envlist = py26,py27,py33,py34,flake8
+envlist = py26,py27,py33,py34,py35,flake8
[testenv]
commands = nosetests {posargs}
deps = -r{toxinidir}/requirements.txt
-r{toxinidir}/test-requirements.txt
+passenv = HOME
[testenv:cover]
commands = nosetests --with-coverage {posargs}