Repository navigation
Commit d8c0e7b
committed
fix(diff): read raw diff records field by field
`Diff._handle_diff_line` parses `git diff --raw -z` output by splitting
it at every NUL followed by a colon, and `Diff._index_from_raw_format`
called it once per line of stdout. With `-z`, git writes paths verbatim,
so a path may start with `:` or contain a line feed, and either one
breaks the record framing:
- A path starting with `:` is taken as the start of a new record. Its
remainder is parsed as metadata, the resulting `ValueError` is raised
inside the stdout pump thread, and the caller gets back a `DiffIndex`
with a pathless entry followed by nothing: every later entry is
dropped, and only a log message records the failure. For a commit
adding `:planted`, `docs/b` and `setup.py`, `commit.diff(NULL_TREE)`
returned a single entry with `a_path == None`.
- A path containing a line feed is truncated at the line feed. If the
rest of the path contains a colon, it is parsed as a separate record:
`docs/a\n:100644 100644 111... 222... M` produced an entry `docs/a`
plus a fabricated `M` entry whose blob ids came from the file name.
Paths are chosen by whoever authored the commit. A tool that uses
`Commit.diff` to learn which files a commit touches can therefore be
made to miss changes, or to see changes that were never made.
`_index_from_raw_format` now collects all of stdout before parsing, as
`_index_from_patch_format` already does, and `_handle_diff_line` reads
the NUL-separated fields in order: a metadata field, then one path, or
two for copies and renames. A single trailing line feed is still
stripped so the existing non-`-z` fixtures parse as before.
The new test in `test/test_diff.py` fails before the change and passes
after it. `ruff check`, `ruff format --check` and `mypy` are clean. In a
full clone the suite has 6 failures (`test_diff_with_staged_file`,
`test_index_mutation`, `test_empty_repo`, `test_rebasing` and the two
`test_actor_get_uid_laziness_*` tests), and all 6 also fail without this
change.1 parent 28ab8fb commit d8c0e7b
2 files changed
Lines changed: 35 additions & 17 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
733 | 733 | | |
734 | 734 | | |
735 | 735 | | |
736 | | - | |
737 | | - | |
| 736 | + | |
| 737 | + | |
| 738 | + | |
| 739 | + | |
| 740 | + | |
| 741 | + | |
| 742 | + | |
738 | 743 | | |
739 | 744 | | |
740 | | - | |
741 | | - | |
| 745 | + | |
| 746 | + | |
742 | 747 | | |
743 | 748 | | |
744 | 749 | | |
| |||
748 | 753 | | |
749 | 754 | | |
750 | 755 | | |
751 | | - | |
| 756 | + | |
752 | 757 | | |
753 | 758 | | |
754 | 759 | | |
| |||
767 | 772 | | |
768 | 773 | | |
769 | 774 | | |
770 | | - | |
771 | | - | |
772 | | - | |
| 775 | + | |
773 | 776 | | |
774 | | - | |
775 | | - | |
776 | | - | |
| 777 | + | |
777 | 778 | | |
778 | 779 | | |
779 | 780 | | |
| |||
817 | 818 | | |
818 | 819 | | |
819 | 820 | | |
| 821 | + | |
820 | 822 | | |
821 | 823 | | |
822 | 824 | | |
823 | 825 | | |
824 | 826 | | |
| 827 | + | |
| 828 | + | |
825 | 829 | | |
826 | | - | |
827 | | - | |
828 | | - | |
829 | | - | |
830 | | - | |
| 830 | + | |
831 | 831 | | |
| 832 | + | |
832 | 833 | | |
833 | 834 | | |
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
4 | 4 | | |
5 | 5 | | |
6 | 6 | | |
| 7 | + | |
7 | 8 | | |
8 | 9 | | |
9 | 10 | | |
| |||
12 | 13 | | |
13 | 14 | | |
14 | 15 | | |
15 | | - | |
| 16 | + | |
| 17 | + | |
| 18 | + | |
16 | 19 | | |
17 | 20 | | |
18 | 21 | | |
| 22 | + | |
19 | 23 | | |
20 | 24 | | |
21 | 25 | | |
| |||
253 | 257 | | |
254 | 258 | | |
255 | 259 | | |
| 260 | + | |
| 261 | + | |
| 262 | + | |
| 263 | + | |
| 264 | + | |
| 265 | + | |
| 266 | + | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
256 | 273 | | |
257 | 274 | | |
258 | 275 | | |
| |||
0 commit comments