How do each of these VCS handle renames?
I have found a lot of contradicting information stating that git tracks LOC (lines of code) instead of files, renames would therefore have no meaning for it.
hg mv
, or use hg addremove --similarity
for auto-discovery. There has been some talk about adding heuristics during merge too.Git is different in that it doesn't do rename tracking, which means that it doesn't need to be told about renames by using SCM commands to do rename (or run autodetection script to mark renames before commit), and doesn't save such information in the repository, but it does rename detection. This means that it finds renames using filename and file contents similarity based heuristic algorithm, both during merge, and for diff when requested via -M
option (or configured using diff.renames
config option).
The advantages of this method are the following:
Note that pathspec filtering do not work well with rename detection; if you want to follow history of a file across renames use "git log --follow <filename>
"
In practice:
Git detects renames automatically. (Incidentally, I've heard claims that git can detect when you move a function from one file to another. My initial tests seem to indicate that this is not the case, however.)
With Mercurial, you have to explicitly tell it about renames, either by hg mv
, or the --similarity
option of hg addremove
, or TortoiseHg's "guess renames" option, or certain tools e.g. VisualHg will flag the renames for you. If you want to use the Git approach with Mercurial, I've written an extension to detect renames at commit time, but it's at a very experimental stage at the moment.
Subversion doesn't handle renames at all. It records a rename as one file being removed and another file being added. This means, for instance, that if Alice changes a file and Bob renames it, you get a tree conflict. This happens whether you are doing full-blown branching and merging or simply svn update
. Rename tracking is planned for Subversion 1.8, due out next year sometime.
You have heard right, sort of.
Git operates on the contents of the files, not the files themselves, so renames are technically meaningless to it. To git, a rename looks like file A disappeared and file B appeared with the same content as A. But git is actually pretty good at figuring out when a file has actually been renamed.
Try it: rename a file, then run 'git rm oldname' and 'git add newname' to tell git to stage the changes, then run 'git status' to see what git thinks it's doing -- you'll see that it tells you the file has been renamed. I'm not sure that means anything later, though. Look at a commit with 'git show ' and you won't see any mention of a rename, just a bunch of lines removed from one path and added to another.
Alternatively, you can also use the 'git mv' command to rename a file. It doesn't change how git sees the operation, it just effectively does 'mv oldname newname', 'git rm oldname' and 'git add newname' in one step.
For an overview, of Mercurial, see tonfa's answer.
SVN, on the other hand, cannot detect renames but must be told about them with the 'svn mv' command. When told, however, it tracks renames as "first class" changes, so when viewing the changelog later you'll see that the change was a rename.
I wouldn't suggest choosing a SVN over git or mercurial based on this feature, though. There are much larger and more important differences between the tools. I'd first decide whether you want a distributed version control system (git or mercurial) or a centralized version control system (svn).
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