Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commite77128e

Browse files
committed
Make diff patch parsing more reliable
The a_path and b_path cannot reliably be read from the first diff lineas it's ambiguous. From the git-diff manpage: > The a/ and b/ filenames are the same unless rename/copy is involved. > Especially, **even for a creation or a deletion**, /dev/null is not > used in place of the a/ or b/ filenames.This patch changes the a_path and b_path detection to read it from themore reliable locations further down the diff headers. Two use casesare fixed by this: - As the man page snippet above states, for new/deleted files the a or b path will now be properly None. - File names with spaces in it are now properly parsed.Working on this patch, I realized the --- and +++ lines really belong tothe diff header, not the diff contents. This means that when parsingthe patch format, the --- and +++ will now be swallowed, and not end upanymore as part of the diff contents. The diff contents now alwaysstart with an @@ line.This may be a breaking change for some users that rely on thisbehaviour. However, those users could now access that information morereliably via the normal Diff properties a_path and b_path now.
1 parent0d7a40f commite77128e

File tree

4 files changed

+38
-14
lines changed

4 files changed

+38
-14
lines changed

‎git/diff.py

Lines changed: 22 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -198,16 +198,18 @@ class Diff(object):
198198
# precompiled regex
199199
re_header=re.compile(r"""
200200
^diff[ ]--git
201-
[ ](?:a/)?(?P<a_path>.+?)[ ](?:b/)?(?P<b_path>.+?)\n
202-
(?:^similarity[ ]index[ ](?P<similarity_index>\d+)%\n
203-
^rename[ ]from[ ](?P<rename_from>\S+)\n
204-
^rename[ ]to[ ](?P<rename_to>\S+)(?:\n|$))?
201+
[ ](?:a/)?(?P<a_path_fallback>.+?)[ ](?:b/)?(?P<b_path_fallback>.+?)\n
202+
(?:^similarity[ ]index[ ]\d+%\n
203+
^rename[ ]from[ ](?P<rename_from>.*)\n
204+
^rename[ ]to[ ](?P<rename_to>.*)(?:\n|$))?
205205
(?:^old[ ]mode[ ](?P<old_mode>\d+)\n
206206
^new[ ]mode[ ](?P<new_mode>\d+)(?:\n|$))?
207207
(?:^new[ ]file[ ]mode[ ](?P<new_file_mode>.+)(?:\n|$))?
208208
(?:^deleted[ ]file[ ]mode[ ](?P<deleted_file_mode>.+)(?:\n|$))?
209209
(?:^index[ ](?P<a_blob_id>[0-9A-Fa-f]+)
210210
\.\.(?P<b_blob_id>[0-9A-Fa-f]+)[ ]?(?P<b_mode>.+)?(?:\n|$))?
211+
(?:^---[ ](?:a/)?(?P<a_path>.*)(?:\n|$))?
212+
(?:^\+\+\+[ ](?:b/)?(?P<b_path>.*)(?:\n|$))?
211213
""".encode('ascii'),re.VERBOSE|re.MULTILINE)
212214
# can be used for comparisons
213215
NULL_HEX_SHA="0"*40
@@ -231,15 +233,14 @@ def __init__(self, repo, a_path, b_path, a_blob_id, b_blob_id, a_mode,
231233
ifself.b_mode:
232234
self.b_mode=mode_str_to_int(self.b_mode)
233235

234-
ifa_blob_idisNone:
236+
ifa_blob_idisNoneora_blob_id==self.NULL_HEX_SHA:
235237
self.a_blob=None
236238
else:
237-
assertself.a_modeisnotNone
238239
self.a_blob=Blob(repo,hex_to_bin(a_blob_id),mode=self.a_mode,path=a_path)
239-
ifb_blob_idisNone:
240+
241+
ifb_blob_idisNoneorb_blob_id==self.NULL_HEX_SHA:
240242
self.b_blob=None
241243
else:
242-
assertself.b_modeisnotNone
243244
self.b_blob=Blob(repo,hex_to_bin(b_blob_id),mode=self.b_mode,path=b_path)
244245

245246
self.new_file=new_file
@@ -329,11 +330,22 @@ def _index_from_patch_format(cls, repo, stream):
329330
index=DiffIndex()
330331
previous_header=None
331332
forheaderincls.re_header.finditer(text):
332-
a_path,b_path,similarity_index,rename_from,rename_to, \
333+
a_path_fallback,b_path_fallback, \
334+
rename_from,rename_to, \
333335
old_mode,new_mode,new_file_mode,deleted_file_mode, \
334-
a_blob_id,b_blob_id,b_mode=header.groups()
336+
a_blob_id,b_blob_id,b_mode, \
337+
a_path,b_path=header.groups()
335338
new_file,deleted_file=bool(new_file_mode),bool(deleted_file_mode)
336339

340+
a_path=a_pathorrename_fromora_path_fallback
341+
b_path=b_pathorrename_toorb_path_fallback
342+
343+
ifa_path==b'/dev/null':
344+
a_path=None
345+
346+
ifb_path==b'/dev/null':
347+
b_path=None
348+
337349
# Our only means to find the actual text is to see what has not been matched by our regex,
338350
# and then retro-actively assin it to our index
339351
ifprevious_headerisnotNone:
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
diff --git a/file with spaces b/file with spaces
2+
new file mode 100644
3+
index 0000000000000000000000000000000000000000..75c620d7b0d3b0100415421a97f553c979d75174
4+
--- /dev/null
5+
+++ b/file with spaces
6+
@@ -0,0 +1 @@
7+
+ohai

‎git/test/fixtures/diff_initial

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,3 @@
1-
--- /dev/null
2-
+++ b/CHANGES
31
@@ -0,0 +1,7 @@
42
+=======
53
+CHANGES

‎git/test/test_diff.py

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -76,7 +76,7 @@ def test_list_from_string_new_mode(self):
7676
self._assert_diff_format(diffs)
7777

7878
assert_equal(1,len(diffs))
79-
assert_equal(10,len(diffs[0].diff.splitlines()))
79+
assert_equal(8,len(diffs[0].diff.splitlines()))
8080

8181
deftest_diff_with_rename(self):
8282
output=StringProcessAdapter(fixture('diff_rename'))
@@ -140,7 +140,8 @@ def test_diff_initial_commit(self):
140140

141141
# ...and with creating a patch
142142
diff_index=initial_commit.diff(NULL_TREE,create_patch=True)
143-
assertdiff_index[0].b_path=='CHANGES'
143+
assertdiff_index[0].a_pathisNone,repr(diff_index[0].a_path)
144+
assertdiff_index[0].b_path=='CHANGES',repr(diff_index[0].b_path)
144145
assertdiff_index[0].new_file
145146
assertdiff_index[0].diff==fixture('diff_initial')
146147

@@ -156,6 +157,12 @@ def test_diff_patch_format(self):
156157
Diff._index_from_patch_format(self.rorepo,diff_proc.stdout)
157158
# END for each fixture
158159

160+
deftest_diff_with_spaces(self):
161+
data=StringProcessAdapter(fixture('diff_file_with_spaces'))
162+
diff_index=Diff._index_from_patch_format(self.rorepo,data.stdout)
163+
assertdiff_index[0].a_pathisNone,repr(diff_index[0].a_path)
164+
assertdiff_index[0].b_path==u'file with spaces',repr(diff_index[0].b_path)
165+
159166
deftest_diff_interface(self):
160167
# test a few variations of the main diff routine
161168
assertion_map=dict()

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp