From 25f27c86af9901f0135eac20a37573469a9c26ef Mon Sep 17 00:00:00 2001 From: Jonathan Chu Date: Tue, 15 Mar 2016 12:30:34 -0400 Subject: [PATCH 1/2] Split diff line by '\t' for metadata and path This protects against `.split(None)` which uses consecutive whitespace as a separator to overlook paths where a single space is the filename. For example, in this diff line: line = ':100644 000000 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 D ' The deleted file is a file named ' ' (just one space). It's entirely possible to commit this, remove, and to produce the following output from `git diff`: git diff --name-status D M path/to/another/file.py ... This would cause the initial `.split(None, 5)` to fail as it will count all consecutive whitespace as a separator, disregarding the ' ' (single space) filename. --- git/diff.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/git/diff.py b/git/diff.py index 9059091e6..062220df3 100644 --- a/git/diff.py +++ b/git/diff.py @@ -365,7 +365,8 @@ def _index_from_raw_format(cls, repo, stream): if not line.startswith(":"): continue # END its not a valid diff line - old_mode, new_mode, a_blob_id, b_blob_id, change_type, path = line[1:].split(None, 5) + meta, _, path = line[1:].partition('\t') + old_mode, new_mode, a_blob_id, b_blob_id, change_type = meta.split(None, 4) path = path.strip() a_path = path b_path = path From e328ffddec722be3fba2c9b637378e31e623d58e Mon Sep 17 00:00:00 2001 From: Jonathan Chu Date: Wed, 16 Mar 2016 14:08:31 -0400 Subject: [PATCH 2/2] Add test and fixture for diff index from raw format This tests the edge case of doing a diff against a single whitespace filename and returns the proper change type. All other normal usage of this diff classmethod should remain unchanged. --- git/test/fixtures/diff_index_raw | 1 + git/test/test_diff.py | 6 ++++++ 2 files changed, 7 insertions(+) create mode 100644 git/test/fixtures/diff_index_raw diff --git a/git/test/fixtures/diff_index_raw b/git/test/fixtures/diff_index_raw new file mode 100644 index 000000000..c25f380d3 --- /dev/null +++ b/git/test/fixtures/diff_index_raw @@ -0,0 +1 @@ +:100644 000000 e69de29bb2d1d6434b8b29ae775ad8c2e48c5391 0000000000000000000000000000000000000000 D diff --git a/git/test/test_diff.py b/git/test/test_diff.py index 53bb65dbd..b0d98248f 100644 --- a/git/test/test_diff.py +++ b/git/test/test_diff.py @@ -122,6 +122,12 @@ def test_diff_index(self): dr = res[3] assert dr.diff.endswith(b"+Binary files a/rps and b/rps differ\n") + def test_diff_index_raw_format(self): + output = StringProcessAdapter(fixture('diff_index_raw')) + res = Diff._index_from_raw_format(None, output.stdout) + assert res[0].deleted_file + assert res[0].b_path == '' + 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