The answer basically amounts to: "Git is harder to understand."
Fortunately that difficulty has a huge payoff that SVN simply can't beat. Git has a superset of SVN's functionality - it can act as a central repository, and can also support any granularity of permissions you wish.
And you can pull in, pull out subtrees using Git using the git subtree module.
Git subtree does not cover the same use case as a subtree checkout in SVN. You need a complete clone to create the subtree repository and to push changes from the subtree repo to the main one.
Exactly! Also imagine the situation when you only were working inside one source folder in a large code base, changed 3-4 files significantly and latter decided to revert back to original ones. It just takes svn revert -r revision in that folder to get back original files. With git you can't get away without having to create subtree first
Not an option if the rest of code base is likely different from the original cloned from. For me, this very often has been the case i.e. small changes in like may be 20 files scattered all over the code base just to get my copy run in a specific way debugging an issue.
Oh, i meant the other 20 files all around the code base have just been changed to get my local setup to work. There is no way (without sub branching) in git to have a lot of modified files, but only wanting to revert the ones actually being worked upon. Core concept was still shallow check out in case of svn
Still not sure what's the case exactly. You mean, kind of partially revert a commit, but only the files in the commit which are in a specific subfolder?
Yeah Exactly. Probably i should have worded more appropriately. But given the fact that most of software developers have to maintain large existing code bases, tailor a specific subsection to achieve a goal and only need to commit just a folder in that sub section
Yeah this will definitely do that. Only that mentioning name per file is painful. In large source trees, you often exactly don't know which files have been modified. You just have been following through a debug path making changes where needed. Just having the ability to checkout a folder down the hierarchy is really handy. Git recently added "sparse checkouts" but still they only solve the problem partially
Nothing wrong, just the fact that you cannot latter push ONLY a sub section of code from local branch (while leaving many other changes done in local for local needs) as opposed to svn. This is further mentioned in other comments
I must admit i liked mercurial a lot. The simplicity that is underrated (of svn) is found in tons in mercurial. In fact dvcs initially was hard to get my head around conceptually with git. Keep in mind the unlearn part is harder from years of svn. Then i actually read a tutorial on Joel Spolksky's website about mercurial and how FogCreek uses it. That really helped me conceptually with dvcs.
It is not just about being harder to understand. I would say it is partially self contradicting. First, it teaches you to unlearn the centralized vc. But i am yet to see a commercial git repo which doesn't maintain a central branch. The amount of confusion it puts an average developer into, specially if they are coming from subversion background does eat a lot of energy. I bet the person making the decision to switch to git, didn't foresee that (i didn't). Otherwise, you always would question if it is worth the trouble maintaining the project. Having said that, although there are countless benefits of git, but the one that truly makes it worthwhile in my scenario was the difference in merging capability. SVN needs to go a really long way even to be competitive there.
Though it might be a lot to write, but just a small case as an example. If you have two different variables initialized on same line number in svn, it is possible that in merging two different branches (not revisions), svn quietly puts them BOTH in the code which doesn't even produce a compile time error and it takes ages to find out the actual cause. I have actually been through this since we used to have a dpi product whose separately developed branches for different target platforms needed to be merged and it was all svn. At best svn would give you manual conflicts to resolve. With git, the number of conflicts to be resolved by hand is far less. For a general list, take a look at http://stackoverflow.com/questions/2471606/how-and-or-why-is...
Yes, and I am surprised that this didn't up as answer #1 in response to the original question. This problem is an absolute showstopper if you need to manage binary assets (which for something like video games, you absolutely do -- you want to know that your data is the right data for the current version of the code, because the data is changing all the time too).
Using git-annex would probably fix a lot of these problems.
On the other hand, Perforce is the game industry standard. As much as engineers complain how terrible P4 is in comparison to distributed options, the other teams working on the title (artists, designers, QA/Test) save a huge amount of time by simply not fucking things up for everyone else.
When there's 250 people working on a title, producers will call to lock the entire depot down so that Intern Joe Blow from Test/QA can't check in a broken build and waste the time of everyone who is working on the project.
I've administered depots (along with overseas proxies) with a 1TB head revision. It was amazingly fast despite how huge the data set was. The only exception was syncing a new workspace, which is easy enough to work around with weekly snapshots and rsync.
My last company did just that. The repository wound up being 30gb at the end of the project (which was a 3d facebook game). We tried to host on a company hosted github, but got kicked off because it couldn't deal with a repository that size[1]. Luckily, we only had one person try to check out the repository at the end of the project. It took them 14 hours for the initial check out.
[1] It was never made clear to me whether it was our hardware that had the problem or the github self hosted software. Either way, it was unreasonably slow.
How does mercurial do in that situation? I know it uses a binary diff algorithm under the hood, but are there other showstoppers for storing giant files in mercurial?
They don't store well as compressed binary diffs, and they can cause high memory consumption during various operations. If you absolutely must store large binary files then there's a large files extension.
`git gc` packs files with delta compression. I have a rather big git repository (daily mirroring a 25 gig repository with some large dvd iso images). And it seems to work quite well.
This just happened at work like 2 weeks ago. Someone checked in a large (4g) binary file into SVN repo and it crashed the whole system. Everyone at the company was blocked for half a day before they got it fixed (temporarily to unblock everyone). But it took another 2 days and a lot of heated debates between the release manager and devops before everything went back to normal. There were talks about moving to git before the incident, but this really pushed management to finally pull the trigger.
2 lessons here: 1. SVN is bad at large binary files; 2) centralized source control's one way of doing things also gives you one way of disaster recovery.
I'm not surprised it choked on a 4Gig binary file.
But when we have dozens of multi-MB binary files, which change every week or so, then after a year we're ending up with a massive repository to pull down.
At my company we use both SVN and Git (via GitHub) at the same time. SVN is for the serious dev while Git is for toy project we post online from time to time.
Some of you may say that we may not be doing things right but the only reason SVN is preferred over Git is because of externals. It is just easier to reference an external project and keep it updated all the time. This is important for consistency point of view and we want to spend more time developing features verses merging and resolving merge conflicts, etc. When we tag things we simply svn copy and then flatten the externals making it all the same. It works great for us and we cannot see any reason why we should move away from this.
Git is interesting and definitely very powerful. We love the idea of working on a feature and then commit push and merge it when it is ready. It does make a lot of sense to do this over and over again but there is sooooooo much to type all the timeeeeee. It makes it so inconvenient.
Maybe it is just our model of work. Maybe we are weird and old school.
Loved the part regarding sooo much to type. I learned svn in probably in my first job and after a while, commands just came natural to me both linux command line or toroise svn via GUI. But git which i only learned a couple years back still haunts me in the sense of writing a long command with several parameters to achieve some thing where i have to understand each param and its application in my given scenario. Just a week back, i spent like 30 min getting code base back to the state of some one doing an equivalent of svn update and i was like... Why did we ditch svn?
I always thought the SVN branching model of copying directories with history was kind of interesting. Too bad that it didn't work out too well in practice.
Basically everything is a matter of conventions. Regarding the top-rated answer items: if you have at least one experienced Git person in the team, you can:
1) set up a centralized repo and tell people to use it,
2) use fetch + rebase instead of merge to have a linear history, so managers are happy
3) when you have non-technical people, you can just tell them a standard set of commands to use (ok the hard part is to convince them to the command line). You may set up all the repo (remotes, aliases etc.) for them and tell them exactly the workflow.
4) regarding the locking, IMO it's good to have a number of integrators pushing to master (after the code review) instead of everyone in the team, that way locking shouldn't be really necessary.
The real things for me are:
1) checking out subfolders in SVN - indeed might be convenient in big code bases.
2) empty directories
Not sure about handling blobs, I didn't have big ones yet.
Anyway, I don't know what would make me crave using a non-distributed VCS now after nearly 2 years with Git.
3. Stupid people setting up their email address and username wrong then pushing it. We have AD integrated authentication with SVN so you can't screw that up.
Yes. Nothing particularly odd use case wise. All git operations started to fail if going back in history a few revs. Turns out a rev somewhere was corrupt. It didn't fail with a helpful message either.
Man, I didn't know that git couldn't store empty directories or check out subtrees. Those are pretty substantial shortcomings. Up till now I assumed that git was sort of the bittorrent way to store a filesystem and was close to ideal. But those issues are causing me to reevaluate.
Not storing directories is definitely a political decision, so by default I oppose it (Apple makes these kinds of unilateral decisions all the time, to me it's the ugly side of programming). I'm hopeful that perhaps the subtree issue has something to do with all of the hashes being nested and maybe there is a workaround (perhaps git needs placeholders when the files aren't present?)
I also didn't realize that there is no revision number in git, but since we can use the hash string I'm ok with it. Conceptually they are both just keys anyway. The chronological order of the hashes is encoded in their structure, so hopefully git makes it easy to retrieve the list.
> Not storing directories is definitely a political decision, so by default I oppose it
It's a technical decision. Git doesn't store files or directories. It stores blobs of data identified by arbitrary textural identifiers. These identifiers tend to be paths, but they need not be, for example for a smalltalk-like system. There are advantages to this representation, for example when tracking changes across refactors that merge/split code files.
Hmmm I'm just trying to wrap my head around this. It sounds like git can't store 0-length data, but, it stores empty files (data, wrt your smalltalk example) just fine. So that must mean that it's not distinguishing between files and directories. It's probably also not storing other metadata like executable or permissions flags, labels (like on Mac OS), both creation AND modification dates, etc etc (but that's beyond the scope of this discussion).
Does anyone know if git stores the path separator as part of the path? For example does it store a path reference as a string "/var/log" or as a list {"var", "log"} internally? That gives us 2 options:
1) If git DOESN'T store the path separator, then that means there's no way to represent a directory as "var/", to signify that it's a directory (because a file could contain the path separator character). If that's the case, then perhaps I was wrong to call it a political decision. An argument can be made for purity here.
2) If git DOES store the path separator inside a path string, then a mistake was made, because there was a chance there to distinguish between a directory "var/" and a file "var". Sometimes I refer to these types of mistakes as political decisions, for example if it's easier to make the mistake than work through a full implementation. I can't imagine that git works this way, but I'm throwing it out there because I have seen stranger things.
After I posted that comment, I remembered that I had read one a couple of years ago and it explained trees and blobs. Looking at the tree structure now though, I can't see any reason why a leaf has to be a blob instead of a tree.
So without some new rationale, I have to come to the conclusion that ignoring empty directories was a political decision. Perhaps I missed something in how the hash is computed, for example if the node's name wasn't part of the hash, then empty directories would have no effect on it, which would mean the same hash could represent different directory structures, which would be incorrect. But that can't be right, because git can store empty files.
This all means that git can't represent an arbitrary directory structure. That's a big deal, because it can't be used to say, incrementally back up a hard drive without help. That's all well and good if its main use is version control, but I'll never look at it quite the same way again.
In svn's default configuration, users cannot inadvertently destroy a project's history (one can configure svn to allow users to change commit messages; AFAIK, rewriting history in the git sense requires a dump and a restore from svnadmin)
For many types of users, I think that is a thing that svn does better than git, especially since git makes it so easy to destroy/rewrite history.
will add any currently staged changes to your last commit, and allow you to change the commit message.
In the words of the manpage,
git rebase origin/master
will "forward-port local commits to the updated upstream head." In other words, if you have local commits, it throws them away and replaces them with different commits. This allows you to avoid making merge commits.
Interactive mode rebase, for example:
git rebase -i HEAD~4
will let you rewrite the last commits. You can use it for lots of things like: changing commit messages, changing commit contents, add new commits in the middle of a sequence, squash multiple commits into one.
git filter-branch
can be used to apply a script to all the commits in a branch. Situations where it's useful: "I don't like the username/email I was using, it didn't matter when it was just a local repo for me only, but when I publish it I want to change it", or "Oh crap for 2 years we've had files in our repo we don't own the copyright for, we need to get it out of our history before somebody sues us!"
FYI, when people talk about "destroying/rewriting history," they're usually referring to the above commands that take a bunch of commits and replace them with different commits. I wouldn't call push --force, reset --hard and gc commands that destroy history; instead I think of them as commands that help you work with different views of history. E.g. doing git rebase -i followed by git push -f, the rebase is what actually rewrites history while the git push -f merely propogates the rewritten history to a remote repo.
Disable force-push (receive.denyNonFastForwards) and branch-deletion (receive.denyDeletes) in a central bare git repository and nobody can change history there.
At work we're just switching from a centralised VCS (not Subversion, but of similar capabilities) to Git, using Github as a central repo.
We do in fact need the superiority in branching/merging that you have with git - not having it has been a PITA several times recently. We'd really outgrown CVCS and needed what DVCS had to offer.
That said, we've been having a fun time getting used to git's little ways. Everyone's shot themselves in the foot at least once, me included. If you move from centralised to distributed VCS, you will shoot yourself in the foot unless you have an accurate mental model of what's happening.
A few developers have complained it's all too hard and complicated and they have to use the command line now (they don't) and why can't we go back to the old way. I've been reminding them programmers are supposed to be smart and able to learn things ...
The change is totally worth it, though. The pace of development has accelerated.
I wonder how many of the foot-shootings are due to not being familiar with DVCS, and how many are due to git's awful UI. While DVCS is more complex than centralised VCS, git's presentation of the concepts isn't exactly clean.
The awful, awful command-line interface doesn't help. But quite a few were with the vast and excellent selection of clicky picture tools, so I mostly attribute it to attempting to get by with clicky things without understanding what's going on. Once you do, it's brilliant.
tl;dr you do in fact need a basic understanding of the chain of versions and how branching actually works and stuff.
What I miss most from Subversion is the revision number. Every commit in the repository ordered by one universal simple number that makes all kinds of scripting and automation easy. Being able quickly ask a colleague when debugging "what revision are you using" and get back a simple identifier instead of an opaque hash that tells me nothing.
Of course, this feature exactly is not possible in a DVCS (it is almost the whole point of a DVCS). I certainly appreciate other features of the DVCS and would probably take them on balance. But do still miss the simplicity of it.
It's pretty easy to have a revision number and Mercurial does it the right way: you have a canonical repo and that repo has a local revision number which maps to a particular commit.
It's impossible to have global revision numbers for hopefully obvious reasons.
Indeed, Mercurial does do this very nicely. Even if the local revision number isn't entirely trustworthy (i.e. can't be compared between different repo clones) it sure is nice to have a decent idea how old a revision is... "revision 1000, oh that's ancient; revision 50000, oh that is very new".
I'm not sure I understand #1. Git can still be used (and frequently is) as a centralized repo simply by using commit and push together as an atomic unit.
If you have a super important piece of code that you want to gate access to then you're going to deal with this roughly in the same way under both systems. Probably by breaking it into a separate repo and only granting access to specific people since even under SVN everyone gets a copy of the code on their local machine.
Yes, but i think it initially teaches dvcs by going exactly the opposite route i.e. there is nothing central. Then latter when you get to mix central again into the concept, it gets a little (let's just say) polluted i.e. harder to get around your head specially if you have been used to something simpler in the past conceptually like svn.
SVN being centralized guarantees pre/post commit integration is also centralized. You can't enforce that with Git because people can bypass the integration hooks.
62 comments
[ 3.8 ms ] story [ 119 ms ] threadFortunately that difficulty has a huge payoff that SVN simply can't beat. Git has a superset of SVN's functionality - it can act as a central repository, and can also support any granularity of permissions you wish.
And you can pull in, pull out subtrees using Git using the git subtree module.
What are the advantages that git has over SVN in merging? I've never had any problems merging while using SVN.
If you're bundling in all of your dependencies, or some images/models/sound files then Git gets very big, very quickly.
In The Witness (http://the-witness.net/news) we have 20GB of data checked into svn. Try that with git.
On the other hand, Perforce is the game industry standard. As much as engineers complain how terrible P4 is in comparison to distributed options, the other teams working on the title (artists, designers, QA/Test) save a huge amount of time by simply not fucking things up for everyone else.
When there's 250 people working on a title, producers will call to lock the entire depot down so that Intern Joe Blow from Test/QA can't check in a broken build and waste the time of everyone who is working on the project.
I've administered depots (along with overseas proxies) with a 1TB head revision. It was amazingly fast despite how huge the data set was. The only exception was syncing a new workspace, which is easy enough to work around with weekly snapshots and rsync.
My last company did just that. The repository wound up being 30gb at the end of the project (which was a 3d facebook game). We tried to host on a company hosted github, but got kicked off because it couldn't deal with a repository that size[1]. Luckily, we only had one person try to check out the repository at the end of the project. It took them 14 hours for the initial check out.
[1] It was never made clear to me whether it was our hardware that had the problem or the github self hosted software. Either way, it was unreasonably slow.
http://mercurial.selenic.com/wiki/LargefilesExtension
[edit: this isn't quite a solution, more of a work around -- but one that can be expected to be installed by default.]
But when we have dozens of multi-MB binary files, which change every week or so, then after a year we're ending up with a massive repository to pull down.
Some of you may say that we may not be doing things right but the only reason SVN is preferred over Git is because of externals. It is just easier to reference an external project and keep it updated all the time. This is important for consistency point of view and we want to spend more time developing features verses merging and resolving merge conflicts, etc. When we tag things we simply svn copy and then flatten the externals making it all the same. It works great for us and we cannot see any reason why we should move away from this.
Git is interesting and definitely very powerful. We love the idea of working on a feature and then commit push and merge it when it is ready. It does make a lot of sense to do this over and over again but there is sooooooo much to type all the timeeeeee. It makes it so inconvenient.
Maybe it is just our model of work. Maybe we are weird and old school.
A lot of bad press on SVN branching comes from the TortoiseSVN tooling on windows which TBH can be a bit crappy at times.
1) set up a centralized repo and tell people to use it,
2) use fetch + rebase instead of merge to have a linear history, so managers are happy
3) when you have non-technical people, you can just tell them a standard set of commands to use (ok the hard part is to convince them to the command line). You may set up all the repo (remotes, aliases etc.) for them and tell them exactly the workflow.
4) regarding the locking, IMO it's good to have a number of integrators pushing to master (after the code review) instead of everyone in the team, that way locking shouldn't be really necessary.
The real things for me are:
1) checking out subfolders in SVN - indeed might be convenient in big code bases.
2) empty directories
Not sure about handling blobs, I didn't have big ones yet.
Anyway, I don't know what would make me crave using a non-distributed VCS now after nearly 2 years with Git.
1. One corrupt repository.
2. The Git tooling for windows is horrible.
3. Stupid people setting up their email address and username wrong then pushing it. We have AD integrated authentication with SVN so you can't screw that up.
Not storing directories is definitely a political decision, so by default I oppose it (Apple makes these kinds of unilateral decisions all the time, to me it's the ugly side of programming). I'm hopeful that perhaps the subtree issue has something to do with all of the hashes being nested and maybe there is a workaround (perhaps git needs placeholders when the files aren't present?)
I also didn't realize that there is no revision number in git, but since we can use the hash string I'm ok with it. Conceptually they are both just keys anyway. The chronological order of the hashes is encoded in their structure, so hopefully git makes it easy to retrieve the list.
It's a technical decision. Git doesn't store files or directories. It stores blobs of data identified by arbitrary textural identifiers. These identifiers tend to be paths, but they need not be, for example for a smalltalk-like system. There are advantages to this representation, for example when tracking changes across refactors that merge/split code files.
Does anyone know if git stores the path separator as part of the path? For example does it store a path reference as a string "/var/log" or as a list {"var", "log"} internally? That gives us 2 options:
1) If git DOESN'T store the path separator, then that means there's no way to represent a directory as "var/", to signify that it's a directory (because a file could contain the path separator character). If that's the case, then perhaps I was wrong to call it a political decision. An argument can be made for purity here.
2) If git DOES store the path separator inside a path string, then a mistake was made, because there was a chance there to distinguish between a directory "var/" and a file "var". Sometimes I refer to these types of mistakes as political decisions, for example if it's easier to make the mistake than work through a full implementation. I can't imagine that git works this way, but I'm throwing it out there because I have seen stranger things.
So without some new rationale, I have to come to the conclusion that ignoring empty directories was a political decision. Perhaps I missed something in how the hash is computed, for example if the node's name wasn't part of the hash, then empty directories would have no effect on it, which would mean the same hash could represent different directory structures, which would be incorrect. But that can't be right, because git can store empty files.
This all means that git can't represent an arbitrary directory structure. That's a big deal, because it can't be used to say, incrementally back up a hard drive without help. That's all well and good if its main use is version control, but I'll never look at it quite the same way again.
For many types of users, I think that is a thing that svn does better than git, especially since git makes it so easy to destroy/rewrite history.
Also, you don't need to do the gc; git will run it automatically for you, eventually.
In the words of the manpage,
will "forward-port local commits to the updated upstream head." In other words, if you have local commits, it throws them away and replaces them with different commits. This allows you to avoid making merge commits.Interactive mode rebase, for example:
will let you rewrite the last commits. You can use it for lots of things like: changing commit messages, changing commit contents, add new commits in the middle of a sequence, squash multiple commits into one. can be used to apply a script to all the commits in a branch. Situations where it's useful: "I don't like the username/email I was using, it didn't matter when it was just a local repo for me only, but when I publish it I want to change it", or "Oh crap for 2 years we've had files in our repo we don't own the copyright for, we need to get it out of our history before somebody sues us!"FYI, when people talk about "destroying/rewriting history," they're usually referring to the above commands that take a bunch of commits and replace them with different commits. I wouldn't call push --force, reset --hard and gc commands that destroy history; instead I think of them as commands that help you work with different views of history. E.g. doing git rebase -i followed by git push -f, the rebase is what actually rewrites history while the git push -f merely propogates the rewritten history to a remote repo.
Though this distinction is one of the things brought up in that email, that hg treats it all as one history. That is kind of nice.
We do in fact need the superiority in branching/merging that you have with git - not having it has been a PITA several times recently. We'd really outgrown CVCS and needed what DVCS had to offer.
That said, we've been having a fun time getting used to git's little ways. Everyone's shot themselves in the foot at least once, me included. If you move from centralised to distributed VCS, you will shoot yourself in the foot unless you have an accurate mental model of what's happening.
A few developers have complained it's all too hard and complicated and they have to use the command line now (they don't) and why can't we go back to the old way. I've been reminding them programmers are supposed to be smart and able to learn things ...
The change is totally worth it, though. The pace of development has accelerated.
tl;dr you do in fact need a basic understanding of the chain of versions and how branching actually works and stuff.
Of course, this feature exactly is not possible in a DVCS (it is almost the whole point of a DVCS). I certainly appreciate other features of the DVCS and would probably take them on balance. But do still miss the simplicity of it.
It's impossible to have global revision numbers for hopefully obvious reasons.
If you have a super important piece of code that you want to gate access to then you're going to deal with this roughly in the same way under both systems. Probably by breaking it into a separate repo and only granting access to specific people since even under SVN everyone gets a copy of the code on their local machine.