开发者

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).

0

上一篇:

下一篇:

精彩评论

暂无评论...
验证码 换一张
取 消

最新问答

问答排行榜