In Git:
- History is attached to commits, not to files.
- Commits record a state, not a change.
The first item means that history is never lost, it's just cryptic. Which is not really much help, but git log --follow
(as CodeWizard wrote in his answer) usually does the job (though --follow
has some failings).
One consequence of the second item is that git does not keep track of directory operations like file renames. This means that during merge operations (whether from git merge
, or from git rebase
or git cherry-pick
or git revert
or whatever), git must guess which files were named what.
Git's guesses are based on its similarity index, whose computation is a bit complex. Your main guarantee here is that a file that is bit-for-bit identical to its previous version will be detected as a rename.
This is not necessarily enough by itself, because Git fires up the merge machinery later, at the time of the git merge
or git rebase
or whatever, and the rename (with bit-for-bit identical contents) may be buried in the history. For instance, suppose commit C0 creates the file, C1 modifies it some, C2 renames it, and C3 modifies it again. If you convince git to compare C1 vs C2, it finds the rename—but at the time of the merge operation, git compares C0 against C3, and if the file is not sufficiently similar, git misses the rename.
(We could modify Git so that it iterates through all the commits on the ancestry path from C0 to C3 looking for renames, which would solve this problem completely as long as you commit the rename as a separate operation. This would be somewhat expensive, computationally speaking, but is probably a good idea for some future version of Git. Of course, it also does not help you right now. There is another tool, git-imerge, available today that can help.)
TL;DR answer: try to commit the rename as a standalone commit
Or at least, if you make other changes, make them to other files. Keep the renamed file as similar as possible (bit-for-bit identical = guaranteed rename detection, anything else = similarity index comes into play).
This only helps if those merging know how to convince Git to do the right merges. In the worst case, three merges should do the trick: one up to the point of the rename, one to bring in the rename, and one from there to the end. If a future Git version offers an ancestry-path-rename-detect, use that in the future. Meanwhile the rename-only commit is as good as it gets.