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.
You have access to the command git uses to do this: `$git diff -M`. The command `$git diff` shows you the individual changes in a file, a branch, or the whole repo if you want, depending on what you pass in. The `-M` flag stands for “detect move” or, for our purposes, detect a rename. Detect renames.
In Git's case, it will try to auto-detect renames or moves on git add or git commit; if a file is deleted and a new file is created, and those files have a majority of lines in common, Git will automatically detect that the file was moved and git mv isn't necessary.
Git tracks content, not files, so it doesn't matter how you get your index into the proper state - add+rm or mv - it produces the same result. Git then uses its rename/copy detection to let you know it was a rename.
Git has a configuration setting that tells it whether to expect a case-sensitive or insensitive file system: core. ignorecase . To tell Git to be case-senstive, simply set this setting to false . (Be careful if you have already pushed the files, then you should first move them given the other answers).
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
.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With