Though many sources describe distributed version control systems as having no central storage the truth is that most projects do have a central repository. The difference compared to a traditional version control system like Subversion or CVS is that you also have a local repository and commits are done in two stages. First you commit your changes to your local repository, then you push those changes to the central repository.
The two biggest distributed version control systems today are Git and Mercurial. I’m going to describe them here by using them in a short test and comparing them side by side. The command line command for Mercurial is hg, from the chemical symbol for mercury.
git clone https://Gieron:Password hg clone https://Gieron:Password
cd test cd test
For this test I have created accounts on GitHub and BitBucket. These sites offer free hosting for software projects that use Git and Mercurial respectively.
When you start working with an existing repository you clone the entire repository to your computer. The resulting directory holds both your local repository and your working copy.
(create initial files) (create initial files)
git add * hg addremove
git commit -m "First commit" hg commit -m "First commit"
git push origin master hg push
Here we add some files to the project. One of the files is in a different directory. Git and Mercurial track directories implicitly. By that I mean they only remember directories as file paths. This has two consequences when compared to Subversion. First you can’t add empty directories. Secondly if you commit from a sub directory you will commit the entire project.
After the files are added we commit them to the local repository and then push them to the central repository. When making the first push in Git I had to tell it which remote repository and which branch I wanted to push to.
git branch stable hg branch stable
git checkout stable
hg commit -m "Stable branch"
git push origin stable hg push --new-branch
(deploy code) (deploy code)
git checkout master hg update default
git branch hg summary
In Subversion I have been used to having a stable branch for code that I want to deploy so I can keep it separate from the latest development. I think this should still be a valid way to handle it. So we create a stable branch here and make sure we push it to the central repository as well.
One small difference here is that Mercurial automatically put us in the new branch while Git does not. In Mercurial we have to commit the new branch to our local repository. Git doesn’t see branches this way, so there is nothing to commit. The last command is just a convenient way to check which branch we are currently in as it can be easy to get lost.
(create/remove/change files) (create/remove/change files)
git status hg status
Changes not staged for commit: M index.html
modified: index.html ! images\logo.png
deleted: images/logo.png ? images\newlogo.png
git rm images/logo.png removing images/logo.png
git add images\newlogo.png adding images/newlogo.png
git commit -a -m "Some changes" hg commit -m "Some changes"
git push hg push
Back in the main branch (master in Git, default in Mercurial) we make some file changes that we want to commit. The status command is an easy way to see what changes are available.
Mercurial has a nice addremove command that automatically adds any untracked files and removes all missing files. In Git we have to do this manually. But here is also a very odd feature of Git, it will not automatically send changed files when we commit even if they are tracked. You have to either add them explicitly with the add command or you can give the -a argument to commit which will add all modified tracked files to the commit.
Finally we push the changes. If there are other people working on the project and you want to have their changes you use the pull command.
git checkout stable hg update stable
git merge master hg merge default
hg commit -m "Merged to stable"
git push hg push
Finally we merge the changes to our stable branch. Again Mercurial requires us to commit the merged changes while Git has a different way of thinking.
So which one is better?
Oh look, a pony. But seriously, I wont touch that question. But I can tell you what I perceive to be different.
- has better Windows support
- has an easier learning curve
- is more widely used
- is more flexible