94

I have two files index.html and template.html. I moved most of index.html into template.html and now git thinks that I did a rename when I add both files. Is it possible to prevent this in specific cases?

Kit Sunde
  • 35,972
  • 25
  • 125
  • 179
  • 29
    Git doesn't actually store the fact that it thinks you did a rename. The actual object database only stores full snapshots of your project, and there is no concept of a diff/rename/move. The fact that Git is saying you renamed a file comes from post-analysis of the database. – Jacob Groundwater Feb 22 '13 at 19:31
  • 5
    @JacobGroundwater Oh I see, so it simply doesn't matter. Thanks. :) – Kit Sunde Feb 22 '13 at 19:59

4 Answers4

79

Why Git Thinks Your Files Are Copies

Git tracks content, not filenames. As a result, if two files have substantially similar content, git will think you copied or renamed the file. If you read git-log(1), you will learn:

The similarity index is the percentage of unchanged lines, and the dissimilarity index is the percentage of changed lines. It is a rounded down integer, followed by a percent sign. The similarity index value of 100% is thus reserved for two equal files, while 100% dissimilarity means that no line from the old file made it into the new one.

So, assuming your similarity index is 100%, git will think that's a copy. Your best bet is to add a sensible log message or note (see git-notes(1) for more on that) to explain what's going on if you don't think git is doing the right thing.

Adjusting the Similarity Index

You might also try adjusting the values git uses for considering something a copy or rename. The manual for git-log(1) says:

-M[<n>], --find-renames[=<n>]

If generating diffs, detect and report renames for each commit. For
following files across renames while traversing history, see --follow. If
n is specified, it is a threshold on the similarity index (i.e. amount
of addition/deletions compared to the file’s size). For example, -M90%
means git should consider a delete/add pair to be a rename if more than
90% of the file hasn’t changed.

-C[<n>], --find-copies[=<n>]    

Detect copies as well as renames. See also --find-copies-harder.
If n is specified, it has the same meaning as for -M<n>.

Again, this won't help you if the files are mostly similar, but you can certainly use these values to tune how similar they need to be in order to be considered copies or renames. Your mileage may vary.

Todd A. Jacobs
  • 81,402
  • 15
  • 141
  • 199
  • 6
    Would just like to point out that this answer is much more helpful and descriptive than any of the answers on the other question – Kyle Kochis Jul 16 '15 at 20:21
  • 1
    This two stage process before a commit will work: git reset ambiguous file, git commit, git add ambiguous file, git commit. – Basil Musa Dec 26 '15 at 12:13
33

There is an "accepted" answer, but it does not give any hint on how to answer the question.

The correct answer, from git-log(1) and git-diff(1) is:

   --no-renames
       Turn off rename detection, even when the configuration
       file gives the default to do so.
mat
  • 12,943
  • 5
  • 39
  • 44
  • 9
    While this will work for some use cases, the original original question was "Is it possible to prevent this [rename detection] in specific cases?" The flag you're using turns it off everywhere when in *~/.gitconfig*, or for the entire current run when on the command line. Even items with a similarity index of >=99% will not be seen as renames, which is not *usually* what people expect and may violate the principle of least surprise. Nevertheless, there are definitely use cases for the flag, or it wouldn't exist. Thanks for pointing it out here! – Todd A. Jacobs Oct 18 '17 at 14:22
28

If you are in a moment just before a commit and "you feel bad that git went mad", then just undo the addition of the ambiguous file git thought you renamed, perform a commit, then add the ambiguous file again and commit:

git reset ambiguous_file_git_thought_you_renamed
git commit
git add ambiguous_file_git_thought_you_renamed
git commit

This worked for me.

Double check no renaming took place:

git diff --name-status -C HEAD^^ HEAD
M       ambiguous_file_git_thought_you_renamed
M       original_file

"M" at the beginning means modified, "R" mean Renamed. Notice no Renamed exists here.

Basil Musa
  • 8,198
  • 6
  • 64
  • 63
  • 3
    Does the second `git commit` need to have the `--amend` flag, in order to include the change into the same commit? I added the flag, and this worked for me, to bypass the renaming detection. – BillyBBone May 07 '16 at 20:08
  • 2
    If they end up in the same commit then something at some point will decide that they were renames. The only way to truly prevent this is to keep them in separate commits forever. – Miral Sep 06 '19 at 01:35
2

If you have modified file A, B and C; and deleted file D, E and F; there is a chance git thinks D is renamed to A, or something similar.

The simplest solution is to split file modifications and deletions into two commits.

Harry
  • 53
  • 6