Which free source control system is most preferable with reason for home projects and documents?
I am thinking to use Subversion (as I am familiar with it).
Characteristic of home project:
Most likely single person will be committing changes. (May be one day (not now), it is possible that I share a project with my friend who is in other city)
I would like to store other documents (non-programming files)
Is Mercurial or GIT (distributed version control system) can give me any more advantage over to subversion in Home Projects?
Take a look at part about version control for single developer in my answer to "Difference between GIT and CVS" question here on StackOverflow. Some of those issues do still apply also to Subversion versus Git (or other distributed VCS: Mercurial, Bazaar, or less known: Monotone, Darcs), even if Subversion is an improvement over CVS.
DISCLAIMER: I use Git (so I am biased), and know Subversion only from the documentation (and other resources), never having used it myself. I might then be mistaken about Subversion capabilities.
Below there are list of differences between Git over Subversion for a single developer, on single machine (single account):
.git
directory in top directory of your project. Starting a new project from unversioned tree of files is as easy as doing "git init" in a top directory of your project (and then of course "git add ." to add files, and e.g. git commit -m 'Initial commit'
to create first commit).In Subversion (in any centralized version control system) you need to set up central repository (unless you did that earlier) using svnadmin create
(well, you need to do that only once). Then you have to import files into Subversion using svn import
(or svn add
)... But note that after the import is finished, the original tree is not converted into a working copy. To start working, you still need to "svn checkout" a fresh working copy of the tree.
.git
directory in top directory of your projects.Subversion stores repository in separate area you have to put for that purpose, and stores repository metadata (e.g. where central repository is, identity used to contact central repository, and I think also properties like svn:ignore
) are stored in .svn
directory in each directory of your project. (Note that Subversion stores pristine copy of your checkout, to have fast svn status
and svn diff
)
In Git each version of a project (each commit) has its unique name given by a SHA-1 id with 40 hexadecimal digits; usually first 7-8 characters are enough to identify a commit (you can't use simple numbering scheme for versions in distributed version control system -- that requires central numbering authority). But Git offers also other kinds of revision specifiers, for example HEAD^
means parent of a current commit, master~5
means revision 5 ancestors back (in straight first-parent line) from top commit on a 'master' branch, v1.6.3-rc2
might mean revision tagged v1.6.3-rc2
.
See also Many different kinds of revision specifiers blog post by Elijah Newren.
git merge branchname
)... it had to, because distributed development naturally leads to multiple branches. Git uses heuristic similarity-based rename detection, so while merging it can deal with the case where one side renamed a file (and other similar cases related to renaming). This means that you are able to use topic branches workflow, i.e. develop a separate feature in multiple steps in separate feature branch.Branches have an unusual implementation in Subversion; they are handled by a namespacing convention: a branch is the combination of revisions within the global repository that exist within a certain namespace. Creating a new branch is done by copying an existing set of files from one namespace to another, recorded as a revision itself. Subversion made it easy to create new branch... but up until version 1.5 you had to use extra tools such as SVK or svnmerge
extensions to be able to merge easily. Subversion 1.5 introduced svn:mergeinfo
property, but even then, merging is slightly more complicated than in Git; also, you need to use extra options to show and make use of merge tracking information in tools such as svn log
and svn blame
. I have heard that it doesn't work correctly in more complicated situations (criss-cross merge), and cannot deal currently with renames (there is even chance of silent corruption in such case). See also (for example) this post on git mailing list by Dmitry Potapov, explaining intended use case for svn:mergeinfo
and its (current) limitations.
In Subversion, tags use the same path_info
-like namespace convention as branches (recommended convention is svnroot/project/tags/tagname
), and are not protected against changing. They are made using "svn copy". They can have comment associated with [the commit creating a tag].
'ident'
gitattribute which allows expansion of "$Id$" keyword to SHA-1 identifier of file contents (not identifier of a commit).Both Git and Subversion do keyword expansion only on request.
Binary files. Both Git and Subversion deal correctly with binary files. Git does binary file detection using similar algorithm to the one used by e.g. GNU diff, unless overridden on per-path basis using gitattributes. Subversion does it in slightly different way, by detecting type of file during adding file and setting svn:mime-type
property, which you can then modify. Both Git and Subversion can do end of line character conversion on demand; Git additionally has the core.safecrlf
config option which warn and prevent irreversible change (all CR to all CRLF is reversible, mixed CR and CRLF is not reversible).
Ignoring files. Git stores ignore patterns using in-tree .gitignore
file, which can be put under version control and distributed; it usually contain patterns for build products and other generated files, and in the .git/info/excludes
file, which usually contains ignore patterns specific to user or system, e.g. ignore patterns for backup files of your editor. Git patterns apply recursively, unless pattern contain directory delimiter, i.e. forward slash character '/', then it is anchored to directory .gitignore
file is, or to root directory for .git/info/excludes
. (There is also core.excludesfile
configuration variable; this variable can exist in per-user ~/.gitconfig
configuration file, and point to per-user ignore file).
Subversion uses global-ignores
runtime configuration option (which generally apply to particular computer or by a particular user of a computer), and svn:ignore
property on SVN-versioned directories. However unlike the global-ignores
option (and in .gitignore
), the patterns found in the svn:ignore
property apply only to the directory on which that property is set, and not to any of its subdirectories. Also, Subversion does not recognize the use of the !
prefix to pattern as exception mechanism.
Subversion allows only to modify commit message after the fact, by changing appropriate property.
git bisect
that can be used to find a commit (revision) that introduced a bug; if your commits are small and self-contained, it should be fairly easy then to discover where the bug is.On the other hand, Subversion because exists longer, has perhaps wider set of third party tools, and Subversion support in tools, than Git, or at least more mature, especially on MS Windows.
And there is another issue, which might be quite important later:
I guess it is more complicated with Subversion, if you don't start at software hosting site with Subversion support (like SourceForge) from the beginning, unless you don't want to preserve existing revision history. On the other hand, for example, Google Code suggest to use svnsync
tool (part of the standard Subversion distribution), as explained in Google Products > Project Hosting (the Data Liberation Front) article.
Also, take a look at http://whygitisbetterthanx.com/ site.