From ee6357386d0bfbccd32d6756322743985a9d8fe6 Mon Sep 17 00:00:00 2001 From: Alex Vandiver Date: Wed, 10 Aug 2016 14:32:37 -0700 Subject: [PATCH] Correctly parse file renames and copies from `git diff --raw` Summary: `parseGitRawDiff` dealt with the `A`, `M`, and `D` status flags from `git diff --raw`, for file additions, modifications, and deletions respectively. However, it failed to cope with `C` and `R` flags, for copies and renames. Git version 2.9 and above default to resolving renames, even in `git diff --raw` output, making this lack of support only salient now (though users with Git's `diff.rename` set encountered it previously). Those two flags differ from the other three in that they offer both the source and destination filename, separated by a tab. As `parseGitRawDiff` was not aware of this property, it returned a "filename" of `"oldfile\tnewfile"`. This is surfaced in several places, including as passed to linters as a filename to check. Needless to say, this file is nearly guaranteed to never exist on disk. Detect both the `C` and `R` flag types, and generate either a file addition, or a pair of addition/deletion entries. Test Plan: Renamed a file, with a linter that printed each file it was called with. Reviewers: #blessed_reviewers, epriestley Reviewed By: #blessed_reviewers, epriestley Subscribers: jboning, Korvin Differential Revision: https://secure.phabricator.com/D16387 --- src/repository/api/ArcanistGitAPI.php | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/src/repository/api/ArcanistGitAPI.php b/src/repository/api/ArcanistGitAPI.php index 884d65dc..57078dab 100644 --- a/src/repository/api/ArcanistGitAPI.php +++ b/src/repository/api/ArcanistGitAPI.php @@ -826,6 +826,22 @@ final class ArcanistGitAPI extends ArcanistRepositoryAPI { $mask |= self::FLAG_EXTERNALS; } else if (isset($flags[$flag])) { $mask |= $flags[$flag]; + } else if ($flag[0] == 'R') { + $both = explode("\t", $file); + if ($full) { + $files[$both[0]] = array( + 'mask' => $mask | self::FLAG_DELETED, + 'ref' => str_repeat('0', 40), + ); + } else { + $files[$both[0]] = $mask | self::FLAG_DELETED; + } + $file = $both[1]; + $mask |= self::FLAG_ADDED; + } else if ($flag[0] == 'C') { + $both = explode("\t", $file); + $file = $both[1]; + $mask |= self::FLAG_ADDED; } if ($full) {