views:

1751

answers:

6

How do each of these vcs handle renames?

I have found a lot of contradicting information stating that git tracks loc's instead of files, renames would therfefore have no meaning for it.

A: 

git tracks contents, not files. i’m not sure about mercurial, but svn has to be explicitely told about renames

knittl
+1  A: 

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.

I'm less familiar with Mercurial, but I believe it works essentially the same way as git.

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

swillden
it is not intented to be a shootout. I am using all of these tools, merucrial beeing used as my prefered tool for personal projects where i have a choice.
Johannes Rudolph
Mercurial doesn't work the same way as git. See tonfa's answer above.
Carl Meyer
+16  A: 
  • Git doesn't track renames at all, but uses heuristic to re-discover them during merge etc.
  • Mercurial tracks renames (the origin version and origin file is recorded) and uses that information during merges. So you have to explicitly tell hg about renames with hg mv, or use hg addremove --similarity for auto-discovery. There has been some talk about adding heuristics during merge too.
  • Svn tracks renames, but I don't know how good it deals with them during merges (never actually tested that).
tonfa
SVN generates a tree conflict when you try to merge to a file that has been renamed, so that the user can decide how to handle it correctly. Older versions would merely output a "skipped" warning saying that the merge target doesn't exist.
Wim Coenen
SVN does not track renames. A rename in SVN is recorded as one file being removed and another being added. Rename tracking is planned for SVN 1.8, due out sometime next year, but how effective this will be remains to be seen.
jammycakes
rename tracking in SVN was planned for 1.4, 1.5, and 1.6. I suspect attaching rename tracking to version 1.8 is just clever way of saying *not yet*.
caspin
+3  A: 

Git

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:

  • renames doesn't need to be marked (or detected) explicitely: the renames can come from a patch, or can be done vie filemanager or graphical interface
  • the similarity detection algorithm can be improved, and is not frozen at the time of commit as in the case of detecting renames to mark them before commit, and saving this information in repository; it is also easier to deal with rename detection mistakes if they are not frozen in history
  • it follows Git ophilosophy that it is contents that matters; see how git blame (and graphical frontends to it like "git gui blame") can follow movement of blocks of code across file boundaries, something that is more generic than wholesame renames of files.

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>"

Jakub Narębski
That 'git log --follow' is a hidden gem.
Gregg Lind
+1  A: 

One more thing about git that hasn't been mentioned yet, in addition to using heuristics to determine whether a rename has happened:

If a file or even an entire directory tree is renamed, copied, or moved, and nothing underneath is modified in any way, then the file or tree is actually stored as the same object inside the repository, and doesn't take up any extra space.

If you modify it, then it's stored as a new object, as usual.

I'm not sure about hg and svn, but I suspect their changelist-oriented architectures mean they behave differently in this scenario. It doesn't really have any effect on usage, except it might give you reason to avoid moving or copying huge trees inside your repository.

jleedev
+2  A: 

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.

jammycakes