Comparison of Subversion and Mercurial (HG)

My first acquaintance with the version control system was back in school. It was Subversion. At that time I was very impressed with his strength and capabilities. But time passed. There were not very pleasant moments with renaming files, directories, etc. (yes, long live svn 1.5, 1.6 and its eternal folders .svn). And everything would have continued in the same vein if one day the company had not thought about changing the version control system. Everything happened unexpectedly quickly and Mercurial appeared in front of me. I had to read about its features, ask for experienced tips, and now I myself helped my colleagues figure out the behavior and work of the new tool. The longer I got to know Hg, the more I liked it, or rather, I liked its decentralized approach to version control, while Subversion inevitably faded into the background.
However, at the new place of work, I again had to recall Subversion, which, frankly, did not make me happy. Fortunately, this was not an unconditional policy of the company and it was quite possible to offer an alternative, especially considering that some employees chose Git and successfully work with it. So, the small thing is to demonstrate clearly what are the advantages of working with decentralized version control systems: Git or Mercurial, but, due to my personal experience, I decided to talk about Hg. Actually, this article is a summary of the round table held by me with the aim of comparing and changing the version control system.


There are many opinions on which version control system is better. Of course, each opinion has its own arguments for and against. However, take at least the simplest scenario: 2 or more people are working on the project, and the project involves further support and development, say, as a library, then storing it in svn will bring you much more trouble than storing it in Mercurial.
Let's move on to the specific features that distinguish Mercurial from the rest.

1. Unlike svn commit, with the hg push command you will always find out if someone managed to change something in the project and committed these changes to the server.

svn commit - a command to send local changes to a remote server. It happens atomically. However, it fails only if the version on which the modified files are based is no longer the last on the remote server. That is, if there are two files a.txt and b.txt in the directory and you only changed b.txt, and Petya only the a.txt file, the commit command will complete successfully for you and if you do not execute the svn update command (update all files in directories to the latest version), then you will not know about it. Svn also supports commit (and checkout) from any project folder. Because of this, if you commit in one folder, then you will not know about changes in another.

hg push - a command for sending sets of changes that were made earlier with the hg commit command. The last command captures the current state of the repository, but does it completely locally. Only when the hg push command is executed, changes are sent to the remote server. Since this is a command for forwarding changes, it extends entirely to the entire repository. Thus, with this command, the entire state of the repository will be recorded completely. And if someone managed to do push before you, then this situation is treated as crowbar and by default, hg push will fail, which says that your action will make a new head in the remote storage.
For completeness, let us define the head. This is a revision that is not itself the parent of some other revision in this brunch. Polyhead - a situation where in one brunch there is more than one head.
Let's get back to our situation when someone got ahead of us. After they returned the error, we need to make the hg pull command, which will pull us all the missing revisions to our local storage. Again, it is worth noting that this action will not affect our files in any way. None of them will be changed. This command simply adds to the history a list of changes that we did not have. Thus, if you look at the visualization of the current situation in the repository, we will see that we have formed many heads. Polyhedron in local storage is not scary. After all, we ourselves made it. It is much more dangerous if we create the same situation on the remote storage and someone manages to persuade him to him. This person will no longer be able to understand which version is the most relevant and how to work with them. He will start running, screaming and cursing, that all this is too complicated and incomprehensible. Therefore, we should never push in the current state (Mercurial will only allow us to do this using the hg push --force command, which is better to never do). Thus, we must perform the merge of two goals and get one that Mercurial can safely upload to the remote server.

And now why this might be important. If for some reason another developer changed some common component (logic, interface, or something else), and you did not know about it, then in the case of svn, the remote repository may contain incorrect or even non-compiling code. At the same time, the first such jamb can be detected quite quickly (nevertheless, we do svn update from time to time and run compilation, right?), But the discovery of another jamb can drag on to tests. The logic of Mercurial allows you to immediately learn about the change and do all the checks at once with merge. Of course, if you are not interested in what has been changed in parallel with your work, then you run the risk of getting into the same situation as with svn, but with one difference - in the first case you did not even know about this, and in the second you scored .
It can be argued that if a person does not make the svn update command before the svn commit command and does not check the code, then he is guilty and there is no plus here, but this is an erroneous opinion. The bunch of update / commit commands in svn is not atomic, and hg push is an atomic operation, which greatly simplifies life.

2. With the pull, merge commands, you do not lose your state, which you have not yet managed to transfer to the remote server, unlike svn update.

This has already been mentioned - with pull, you simply get a set of previously unknown changes to the history without changing the files. And since merge in Mercurial is done locally and with local revisions, these revisions are not lost anywhere. And if you wish, you can always delete the merge result and do it again, or completely roll back to the version of the repository that was before all pull / merge. In svn, this is unrealistic. After executing svn update from your working copy, you get a hodgepodge of unchanged, new, automatically contiguous files, files with conflicts and the usual files you changed. In this case, it is impossible to return the state to the repository that you had before svn update. No way.

3.Another small bun - rollback to any version of the repository in Mercurial in seconds. The only limitation is that your local copy must be clean (without uncommitted changes). This can be done using hg update and specifying the desired revision. At the same time, you do not need to connect to a remote server, because you have the whole history locally. In svn, this can only be done with a remote server and only by downloading the repository again in the desired revision.

4.It often happens that you need to urgently do something with the application. For example, they came running to you and urgently want to get a build (since I am engaged in mobile development, this happens, although there is a build server). And your project is completely ruined, since you are cutting some kind of super feature. In svn, you would either have to download all the sorts from the last revision, or try to roll back the code to a more or less working state, or say that you cannot do it now. All options are so-so and usually take a lot of time. In any decentralized version control system, you can make a local commit, and then roll back to any working version of the code and build the project. In this case, after that, you will return exactly to the state of the repository in which you were before you were disturbed!

5.Another common occurrence is the development of a library project. And if you were unexpectedly asked to build a project that was written for a long time and used a library that was connected by external svn, then you can have big problems. It may simply not be collected, because it used the old library, which they managed to rewrite, rebuild, and so on. The only way out is to look for the revision that this project worked with and copy-paste the libraries. We don’t consider the option with a slight finish of the project to support the new version of the library, since the probability of such a possibility decreases exponentially with increasing time. Mercurial has the concept of a sub-repository, which refers not only to the repository itself, but also to its specific version.

6. I already mentioned branch in hg. It is worth recalling how branches are implemented in svn. These are just folders with a full copy of the repository. Starting with version 1.5, a history of such files has appeared, however, these are just folders and files. To work with them, you must adhere to special rules for naming and content. In mercurial, the branches are the named state of the repository and its changes. And when working with branches, everything is exactly the same as when working in the same branch. It is much simpler.

7. Similarly to point 6, we can talk about tags.

8.Finally, I want to say about the history of commits. If in svn it’s purely straightforward and it’s impossible to say that you really were based on revision 2, not 10 and had no idea what was happening from 3 to 10, although your commit follows at number 11 ... In Mercurial it will be clearly visible that you worked with the version 2 repository and committed 3 ', and only after that did you post your 3' changes with revision 10. Such data is important if you want to trace some important events.

Summing up the article, I want to note that for all the time I have been working with Mercurial, I can’t name its minuses. Some sin on its speed, some on the complexity of commit / push commands to commit changes to the server. For me, this is not a problem, since I did not notice any special delays in speed (there were, of course, with the huge size of the repository, but these are little things in life), and the second is a matter of habit.

In general, some of the benefits of Mercurial listed can be transferred to other decentralized version control systems. And with this article, I just would like to collect all the main advantages of using such systems, relying on Mercurial, as an example with which I myself had experience. I hope this article will be useful if you have to experience the torment of choice.

ps In the end, we decided to switch to Git =)

Also popular now: