Skip to content

Commit b4b5ecc

Browse files
committed
2 parents a7f403b + 4896fa2 commit b4b5ecc

15 files changed

+223
-53
lines changed

Diff for: .travis.yml

+1-6
Original file line numberDiff line numberDiff line change
@@ -19,12 +19,7 @@ install:
1919
- pip install coveralls flake8 sphinx
2020

2121
# generate some reflog as git-python tests need it (in master)
22-
- git tag __testing_point__
23-
- git checkout master || git checkout -b master
24-
- git reset --hard HEAD~1
25-
- git reset --hard HEAD~1
26-
- git reset --hard HEAD~1
27-
- git reset --hard __testing_point__
22+
- ./init-tests-after-clone.sh
2823

2924
# as commits are performed with the default user, it needs to be set for travis too
3025
- git config --global user.email "[email protected]"

Diff for: README.md

+13
Original file line numberDiff line numberDiff line change
@@ -34,16 +34,29 @@ Both commands will install the required package dependencies.
3434
A distribution package can be obtained for manual installation at:
3535

3636
http://pypi.python.org/pypi/GitPython
37+
38+
If you like to clone from source, you can do it like so:
39+
40+
```bash
41+
git clone https://github.com/gitpython-developers/GitPython
42+
git submodule update --init --recursive
43+
./init-tests-after-clone.sh
44+
```
3745

3846
### RUNNING TESTS
3947

48+
*Important*: Right after cloning this repository, please be sure to have executed the `init-tests-after-clone.sh` script in the repository root. Otherwise you will encounter test failures.
49+
4050
The easiest way to run test is by using [tox](https://pypi.python.org/pypi/tox) a wrapper around virtualenv. It will take care of setting up environnements with the proper dependencies installed and execute test commands. To install it simply:
4151

4252
pip install tox
4353

4454
Then run:
4555

4656
tox
57+
58+
59+
For more fine-grained control, you can use `nose`.
4760

4861
### Contributions
4962

Diff for: VERSION

+1-1
Original file line numberDiff line numberDiff line change
@@ -1 +1 @@
1-
2.0.6dev0
1+
2.0.7dev0

Diff for: doc/source/changes.rst

+9-3
Original file line numberDiff line numberDiff line change
@@ -2,11 +2,17 @@
22
Changelog
33
=========
44

5-
2.0.6 - Fixes
6-
=============
7-
5+
2.0.6 - Fixes and Features
6+
==========================
7+
8+
* Fix: remote output parser now correctly matches refs with non-ASCII
9+
chars in them
10+
* API: Diffs now have `a_rawpath`, `b_rawpath`, `raw_rename_from`,
11+
`raw_rename_to` properties, which are the raw-bytes equivalents of their
12+
unicode path counterparts.
813
* Fix: TypeError about passing keyword argument to string decode() on
914
Python 2.6.
15+
* Feature: `setUrl API on Remotes <https://github.com/gitpython-developers/GitPython/pull/446#issuecomment-224670539>`_
1016

1117
2.0.5 - Fixes
1218
=============

Diff for: git/cmd.py

+6-6
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
import mmap
1515

1616
from git.odict import OrderedDict
17-
1817
from contextlib import contextmanager
1918
import signal
2019
from subprocess import (
@@ -40,7 +39,8 @@
4039
PY3,
4140
bchr,
4241
# just to satisfy flake8 on py3
43-
unicode
42+
unicode,
43+
safe_decode,
4444
)
4545

4646
execute_kwargs = ('istream', 'with_keep_cwd', 'with_extended_output',
@@ -694,12 +694,12 @@ def _kill_process(pid):
694694
cmdstr = " ".join(command)
695695

696696
def as_text(stdout_value):
697-
return not output_stream and stdout_value.decode(defenc) or '<OUTPUT_STREAM>'
697+
return not output_stream and safe_decode(stdout_value) or '<OUTPUT_STREAM>'
698698
# end
699699

700700
if stderr_value:
701701
log.info("%s -> %d; stdout: '%s'; stderr: '%s'",
702-
cmdstr, status, as_text(stdout_value), stderr_value.decode(defenc))
702+
cmdstr, status, as_text(stdout_value), safe_decode(stderr_value))
703703
elif stdout_value:
704704
log.info("%s -> %d; stdout: '%s'", cmdstr, status, as_text(stdout_value))
705705
else:
@@ -713,11 +713,11 @@ def as_text(stdout_value):
713713
raise GitCommandError(command, status, stderr_value)
714714

715715
if isinstance(stdout_value, bytes) and stdout_as_string: # could also be output_stream
716-
stdout_value = stdout_value.decode(defenc)
716+
stdout_value = safe_decode(stdout_value)
717717

718718
# Allow access to the command's status code
719719
if with_extended_output:
720-
return (status, stdout_value, stderr_value.decode(defenc))
720+
return (status, stdout_value, safe_decode(stderr_value))
721721
else:
722722
return stdout_value
723723

Diff for: git/compat.py

+3-1
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ def mviter(d):
3535
return d.values()
3636
range = xrange
3737
unicode = str
38+
binary_type = bytes
3839
else:
3940
FileType = file
4041
# usually, this is just ascii, which might not enough for our encoding needs
@@ -44,6 +45,7 @@ def mviter(d):
4445
byte_ord = ord
4546
bchr = chr
4647
unicode = unicode
48+
binary_type = str
4749
range = xrange
4850
def mviter(d):
4951
return d.itervalues()
@@ -54,7 +56,7 @@ def safe_decode(s):
5456
if isinstance(s, unicode):
5557
return s
5658
elif isinstance(s, bytes):
57-
return s.decode(defenc, errors='replace')
59+
return s.decode(defenc, 'replace')
5860
raise TypeError('Expected bytes or text, but got %r' % (s,))
5961

6062

Diff for: git/diff.py

+41-17
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77

88
from gitdb.util import hex_to_bin
99

10+
from .compat import binary_type
1011
from .objects.blob import Blob
1112
from .objects.util import mode_str_to_int
1213

@@ -245,18 +246,20 @@ class Diff(object):
245246
NULL_HEX_SHA = "0" * 40
246247
NULL_BIN_SHA = b"\0" * 20
247248

248-
__slots__ = ("a_blob", "b_blob", "a_mode", "b_mode", "a_path", "b_path",
249-
"new_file", "deleted_file", "rename_from", "rename_to", "diff")
249+
__slots__ = ("a_blob", "b_blob", "a_mode", "b_mode", "a_rawpath", "b_rawpath",
250+
"new_file", "deleted_file", "raw_rename_from", "raw_rename_to", "diff")
250251

251-
def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode,
252-
b_mode, new_file, deleted_file, rename_from,
253-
rename_to, diff):
252+
def __init__(self, repo, a_rawpath, b_rawpath, a_blob_id, b_blob_id, a_mode,
253+
b_mode, new_file, deleted_file, raw_rename_from,
254+
raw_rename_to, diff):
254255

255256
self.a_mode = a_mode
256257
self.b_mode = b_mode
257258

258-
self.a_path = a_path
259-
self.b_path = b_path
259+
assert a_rawpath is None or isinstance(a_rawpath, binary_type)
260+
assert b_rawpath is None or isinstance(b_rawpath, binary_type)
261+
self.a_rawpath = a_rawpath
262+
self.b_rawpath = b_rawpath
260263

261264
if self.a_mode:
262265
self.a_mode = mode_str_to_int(self.a_mode)
@@ -266,19 +269,21 @@ def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode,
266269
if a_blob_id is None or a_blob_id == self.NULL_HEX_SHA:
267270
self.a_blob = None
268271
else:
269-
self.a_blob = Blob(repo, hex_to_bin(a_blob_id), mode=self.a_mode, path=a_path)
272+
self.a_blob = Blob(repo, hex_to_bin(a_blob_id), mode=self.a_mode, path=self.a_path)
270273

271274
if b_blob_id is None or b_blob_id == self.NULL_HEX_SHA:
272275
self.b_blob = None
273276
else:
274-
self.b_blob = Blob(repo, hex_to_bin(b_blob_id), mode=self.b_mode, path=b_path)
277+
self.b_blob = Blob(repo, hex_to_bin(b_blob_id), mode=self.b_mode, path=self.b_path)
275278

276279
self.new_file = new_file
277280
self.deleted_file = deleted_file
278281

279282
# be clear and use None instead of empty strings
280-
self.rename_from = rename_from or None
281-
self.rename_to = rename_to or None
283+
assert raw_rename_from is None or isinstance(raw_rename_from, binary_type)
284+
assert raw_rename_to is None or isinstance(raw_rename_to, binary_type)
285+
self.raw_rename_from = raw_rename_from or None
286+
self.raw_rename_to = raw_rename_to or None
282287

283288
self.diff = diff
284289

@@ -344,6 +349,22 @@ def __str__(self):
344349
# end
345350
return res
346351

352+
@property
353+
def a_path(self):
354+
return self.a_rawpath.decode(defenc, 'replace') if self.a_rawpath else None
355+
356+
@property
357+
def b_path(self):
358+
return self.b_rawpath.decode(defenc, 'replace') if self.b_rawpath else None
359+
360+
@property
361+
def rename_from(self):
362+
return self.raw_rename_from.decode(defenc, 'replace') if self.raw_rename_from else None
363+
364+
@property
365+
def rename_to(self):
366+
return self.raw_rename_to.decode(defenc, 'replace') if self.raw_rename_to else None
367+
347368
@property
348369
def renamed(self):
349370
""":returns: True if the blob of our diff has been renamed
@@ -388,6 +409,7 @@ def _index_from_patch_format(cls, repo, stream):
388409
new_file_mode, deleted_file_mode, \
389410
a_blob_id, b_blob_id, b_mode, \
390411
a_path, b_path = header.groups()
412+
391413
new_file, deleted_file = bool(new_file_mode), bool(deleted_file_mode)
392414

393415
a_path = cls._pick_best_path(a_path, rename_from, a_path_fallback)
@@ -404,15 +426,15 @@ def _index_from_patch_format(cls, repo, stream):
404426
a_mode = old_mode or deleted_file_mode or (a_path and (b_mode or new_mode or new_file_mode))
405427
b_mode = b_mode or new_mode or new_file_mode or (b_path and a_mode)
406428
index.append(Diff(repo,
407-
a_path and a_path.decode(defenc),
408-
b_path and b_path.decode(defenc),
429+
a_path,
430+
b_path,
409431
a_blob_id and a_blob_id.decode(defenc),
410432
b_blob_id and b_blob_id.decode(defenc),
411433
a_mode and a_mode.decode(defenc),
412434
b_mode and b_mode.decode(defenc),
413435
new_file, deleted_file,
414-
rename_from and rename_from.decode(defenc),
415-
rename_to and rename_to.decode(defenc),
436+
rename_from,
437+
rename_to,
416438
None))
417439

418440
previous_header = header
@@ -438,8 +460,8 @@ def _index_from_raw_format(cls, repo, stream):
438460
meta, _, path = line[1:].partition('\t')
439461
old_mode, new_mode, a_blob_id, b_blob_id, change_type = meta.split(None, 4)
440462
path = path.strip()
441-
a_path = path
442-
b_path = path
463+
a_path = path.encode(defenc)
464+
b_path = path.encode(defenc)
443465
deleted_file = False
444466
new_file = False
445467
rename_from = None
@@ -455,6 +477,8 @@ def _index_from_raw_format(cls, repo, stream):
455477
new_file = True
456478
elif change_type[0] == 'R': # parses RXXX, where XXX is a confidence value
457479
a_path, b_path = path.split('\t', 1)
480+
a_path = a_path.encode(defenc)
481+
b_path = b_path.encode(defenc)
458482
rename_from, rename_to = a_path, b_path
459483
# END add/remove handling
460484

Diff for: git/ext/gitdb

Diff for: git/index/base.py

+8-3
Original file line numberDiff line numberDiff line change
@@ -931,19 +931,24 @@ def move(self, items, skip_errors=False, **kwargs):
931931
return out
932932

933933
def commit(self, message, parent_commits=None, head=True, author=None,
934-
committer=None, author_date=None, commit_date=None):
934+
committer=None, author_date=None, commit_date=None,
935+
skip_hooks=False):
935936
"""Commit the current default index file, creating a commit object.
936937
For more information on the arguments, see tree.commit.
937938
938939
:note: If you have manually altered the .entries member of this instance,
939940
don't forget to write() your changes to disk beforehand.
941+
Passing skip_hooks=True is the equivalent of using `-n`
942+
or `--no-verify` on the command line.
940943
:return: Commit object representing the new commit"""
941-
run_commit_hook('pre-commit', self)
944+
if not skip_hooks:
945+
run_commit_hook('pre-commit', self)
942946
tree = self.write_tree()
943947
rval = Commit.create_from_tree(self.repo, tree, message, parent_commits,
944948
head, author=author, committer=committer,
945949
author_date=author_date, commit_date=commit_date)
946-
run_commit_hook('post-commit', self)
950+
if not skip_hooks:
951+
run_commit_hook('post-commit', self)
947952
return rval
948953

949954
@classmethod

0 commit comments

Comments
 (0)