Git rename detection when class and filename changed in one commit
What is the best way to handle class renames (e.g. done with Resharper) with Git?
That is, if both the class name and containing file name are changed together and开发者_运维问答 committed without further changes.
It seems the way Git handles renames via a percentage changed heuristic is a bit hit and miss. For large classes it will be recognised as a rename but for small classes the percentage threshold is reached such that it will be seen as a delete and add.
Keep in mind that in Git's history, file renames are not stored as "this was renamed from X to Y". Instead, the file X exists in one revision, and in the next revision Y exists (and X doesn't). For example:
Revision | Files ---------+---------------------------------- HEAD^ | a.cpp x.cpp z.cpp HEAD | a.cpp y.cpp z.cpp
In the above diagram, each revision is a row and each contains three files. Between the two revisions, x.cpp
was renamed to y.cpp
. The only information that the repository stores is the contents of each separate revision.
When Git (or another tool that reads Git repositories) looks at the above history, it notices that y.cpp
is a new file in HEAD
. Then it looks at the previous revision to see whether a similar file existed. In the case of a straight file rename, then yes, a file called x.cpp
with the identical contents existed in the previous revision (and no longer exists in the current revision). So the new file is shown as a rename from x.cpp
to y.cpp
.
In the case of a rename-and-modify, Git will look at the previous revision's files to see if one file looks close to the new file (in terms of its contents). This is where the heuristic comes in. If most of the lines are the same, then Git will show it as a rename, but if there are enough changed lines compared to unchanged lines, then Git will simply say it looks like a new file.
To answer your question, the best way to handle resharper class renames is to simply do it and commit the new files. Git stores the old and the new files in its repository. Rename detection is handled later, at the time you actually ask about the history. This is why commands such as git log
have options like --find-copies
and --find-copies-harder
.
Years later this is still a quirk I guess because it's fundamental to the way git works.
What I do now is do the rename, commit, then do the change. Bit annoying with refactoring tools but no other solution retains history (--find-copies
and --find-copies-harder
don't seem to work).
精彩评论