I don't see a problem with worrying about git any more than I see one with worrying about Python. Change for the sake of change is bad, but change for the sake of an improved workflow is good.
I guess the real goal is proper separation of responsibilities. When I cook a meal, I use devices that run on electricity. I want to be able to power them up by plugging them in without thinking much about it. The people who work at my power company need to think about the intricacies of generating and transmitting electricity, but I don't want to. On the other end, the people who eat the food I cook should not have to worry about the use of a stove timer or a rice cooker.
Similarly, when I put together a software package, I am functioning as a programmer/software designer. I am interested in the code, how it is structured, and what it is supposed to do. Time spent worrying about storage & version management is generally time spent away from my primary task. Someone needs to worry about that, but, for the most part, I don't think it should be me.
The users of the package I write just want to use it. They care that it does what they want. The fact that it is written in Python, developed using agile methods, etc. are irrelevant to them. (But not to me, as a programmer.)
And maybe for the users, the software is a tool to help them in their business. The customers of that business probably should not care about the software at all; they just want whatever service the business provides.
These are things the consumer has to worry about. Of course in practice "worry about" is an exaggeration; this is all pretty elementary stuff and no reasonably intelligent consumer actually loses sleep over it.
The matter of what version control to use? The consumer never has to worry about that. That concern is something that only developers (and related professionals) will have to worry about. I don't think it is a big deal. Just pick whatever fits your needs and that you prefer.
Should the developer have to know anything about version control? I don't know, should the electrical have to know anything about multimeters, outlet testers, and wire cutters?
This isn't accurate as to the electronics that I use. All the adapters say "input 120 - 240V". Non-portable electronics tend to be compatible with the plugs in the same area where you buy them... since they're not portable.
120V = NMEA-5, 240V = NMEA-6 http://en.wikipedia.org/wiki/NEMA_connector
When you install a washing machine (or, for example a circular saw in your workshop) you'll have to make sure that the proper socket is available at the place where you want to put it (or you'll have to install one at that location).
In Europe, the corresponding comparison would be between 1-phase (230V) power and 3-phase (400V) power, e.g. normal household socket and the red, round 5-prong CEE connectors.
The interesting question is, how much can you automate? Git is the "very little" department, because Linus prefers a deterministic and simple process to an easy, but less reliable one.
This is my mindset. I do have my preferences, but it is all about what technologies our customers require.
So I tend to say I am language and OS agnostic.
The hard lesson about this came from the time I was still trying to get into the game industry and was spending more time thinking about FOSS technologies for game development, than the game design itself. After getting a foot into the industry, it became clear to me that what matters is getting a game released, the technology religion has no place.
So nowadays I always advocate the goal is to have a project done and solve the customer problems. The technology used for it is secondary.
Then you add in stuff like experimental features (refactors, porting to new framework versions, etc.) that need to be developed alongside regular work without clobbering it, or features that get shelved while they are half-done, and things get just downright messy fast in something like SVN.
So my guess is that you aren't stupid at all, but that you just haven't had to deal with that sort of garbage.
(It's also possible your teammates simple deal with all this other crap for you, and don't bother you with the details.)
For instance, when refactoring something quite complex with good test coverage, you want each commit to be the smallest atomic commit that can pass all tests. But you also want to very quickly and "carelessly" add debug logs, assertions, changes in many files. For this kind of task I have found the following workflow to be very helpful and fast:
1. edit files relentlessly running a few tests cases
2. when you feel you "got" something run full test suite
3. if 2. pass, use `git add -p` to add the smallest changeset doing the thing.
4. Use `git stash --keep-index` to remove all other changes
5. Run full test suite
6. If 5. fails `git add -p` to continue editing your commit, or `git reset` if too far off
7. If 5. pass, `git commit` and `git reset --hard`.
Edit: When using `git add -p` you can even use 'e' command to manually edit your patch.
1. (same)
2. (same)
3. put all changes that you are not interested in on shelve: `bzr shelve` (or qshelve if you want QT gui)
4. Run full test suite
5. If 4. fails keep editing
6. If 4. pass `bzr commit` (or `bzr ci`), and to revert shelving use `bzr unshelve`
You need to remember 6+ git command to accomplish this tasks, and only 3 with bzr. Moreover there is symmetry in bzr (fe: shelve - unshelve, commit - uncommit) that is no present in git.
edit: formatting
Usually what I want is the opposite: cherry pick a few changes, increasingly adding them to the staging area (or index in gitspeak), because oftentimes I have a change that I am not sure is required for this patch.
I was very unconvinced by the staging area thing when starting using git and tried to avoid it, but in fact it is very powerful and not that complex. I do not know bzr and only used hg for a few months so maybe they have similar tools, but my main point is not git against the other, it is learn power uses of the tools to help improve workflow, against the claim that dcvs should be not our concern.
This is not something specific to git. Also, this example as a whole is nowhere near an improvement over an hg + mq workflow:
1. `hg qinit; hg qnew refactoring' to add a patchset
2. Make changes, add to patch with `hg qrefresh'
3. Run tests, if tests fail, pop a patch from the queue with `hg qpop'
4. Repeat until everything is fine, then `hg qfinish' to commit the patch to the history.
And yet, even those simple operations are different between different DVCS. 'hg pull' and 'git pull' are not equivalent, same with push. I try to stay away from git but when I can't avoid it, I have to remember that the sane/safe way to pull in git is apparently 'git pull --ff-only'.. #fail
I have in the past worked on larger teams (~15 developers), that project used svn and we never seemed to really run into any issues even though we had branches for mainline dev work, and support branches for each "released" version. I'd get the occasional conflict to resolve but it generally wasn't too bad, and I get those with Git also.
I've never worked on a project where dozens or hundreds of remote developers were contributing, but I'd say that outside of a small number of high-profile open-source projects, most people don't. I understand that's what git was built for; maybe that's why all those features just seem like overkill for anything I've never worked on.
The issues are really in dealing with multiple concurrent streams of development (multiple developers, or different branches of your own development if you have to switch between tasks). It's also useful having good tools to look at diffs and history to try to diagnose any problems.
There is of course a lot of simple tasks which DVCS can and do apply near perfectly but I suppose managing a complex project you're at some point going to have to have a basic understanding of how the system works.
I've used IBM's RTC which is an excellent GUI VCS tool that I believe internally works similar to git/hg but it attempts to hide how its internals works so on a large merge 500+ changesets and then remerging more commits it refused to push despite saying no incoming changesets. We ended up fixing it by pulling to a different repository based of the branch we were trying to merge from based of advice from support. But I'd prefer a deterministic cli interface over a gui interface anyday.
Version control systems also define how you branch and merge, which are are hugely important concerns if you're working on a team, and still pretty important if you're working alone.
Git handles branches and history management better than Mercurial does for my needs, and it makes a huge difference to me.
I've been able to successfully replicate all the Git use cases I can think of in Mercurial even if I think they are bad practices. Conversely, nothing I do makes git's cli anywhere near as good as hg. For me, that is the single biggest glaring problem with Git. I spend a very small minority of my time handling complicated history/branch issues as part of my major workflow and I spend an inordinate amount of time working with the interface to my source control. Git seems optimized for the minority case.
I may be _entirely_ off base here.
(personally I find git's command line to be fantastic, but I often feel like I'm the only one.)
Mutating history is front and center in the changeset evolution framework people have been working on for some years now. The first step is that Mercurial tracks when it's safe to rebase or edit a commit: each commit has a "phase" which is "draft" initially, but changes to "public" when you push the commit somewhere. The history editing tools ('hg rebase', 'hg histedit', 'hg commit --amend') will then tell you when it's unsafe to edit a commit.
Really, it would be best if there was some way to retain the original commits while rebasing to clean the history. Time for a new DVCS?
When you rebase, commits are not lost. If there is a ref pointing at them then they will continue to stick around. If there isn't then the next time that gc is run they would be removed.
The solution to what you are looking for is to precede each rebase with a command to 'anchor' the current commit under a custom ref. If you wanted to look back in time, you'd use a corresponding command. This is all, say, 20 lines of shell, primarily using the git plumbing..
Of course this is just recreating a permanent reflog-work-alike, reflog of course already having this usecase covered for individual devs working on their machines...
If it is the other usecase of rebasing, rebasing public code, say on a centralized repo or the repo of your build fleet, that has you concerned, then instead of just set a policy of only permitting fast-forward commits in those cases. That is a reasonable thing to do, it is a legitimate workflow that git supports. There is no reason that you cannot keep auditable logs of exactly what has been going on with your git repo.
I think people hear "rewrites history" and let their imaginations run wild with sci-fi tales of wonder, only then to think of the grave horrors such power would enable... but forget to look at what actually is happening when you "rewrite history" in git. There is no reason to fear it.
Yeah, I very much agree with this. Rewriting history is a tool, a very powerful tool. It's something you can use if you want to.
It reminds me a little of a discussion I had recently with a developer who mostly used statically typed languages. I'm using to dynamically typed languages like Python and JavaScript, so it was puzzling for me to hear him talk about the horrors of dynamic types. He said things like "I pass a Person object to a function and the function might do anything with it -- like adding new methods and fields to it!". Yes, it is true that you can add a new method to an object in most dynamically typed languages. No, adding methods and fields by accident is not really a problem in real life.
Just because you have the option of doing something, doesn't mean that you must do it.
My git workflow is probably replicable in Mercurial, but git does it by default.
Bookmarks stay local by default, but they can be exported to the server if you like. There's nothing to enable any longer since it's a core feature.
I don't think you need to install those extensions, you just enable them by putting a line in .hgrc
This of them as major modes for Emacs, if you're familiar with that. Emacs comes with syntax highlighting support for a lot of languages and the mode is turned on automatically. Sometimes you need to install a new major mode yourself, but the bundled modes get you a long way.
In both cases the answer is pretty much nothing.
Git is not optimized for the minority case, it is optimized for simple implementation. It basically leaks implementation details left and right. I believe git users come to like this, because the core model is so simple (for a computer scientist). Git internally is just snapshots of the code connected with prev-version edges forming a directed acyclic graph and then some named pointers into this DAG.
I don't know which it better, but at least different: git has automatic garbage collection for dangling commits (after 30 days or so by default).
With Mercurial, if you want to remove dangling commits, you have to do it by hand. And if they have been pushed, you have to go to the remote repo and manually remove them there too. And everyone else who has pulled them, will need to manually remove them.
It breaks down with more advanced usage like integrations which can be very difficult with large teams.
I manage a VCS with thousands of developers committing to a large code base. The VC system starts to really matter and you have to understand how it handles things like conflict resolution or things can get out of hand really quickly.
To continue your filesystem analogy, filesystems were invented sometime around 1960, but it was over 20 years before everyone settled on Unix-style filesystems, where files are just a sequence of bytes. Eventually, they realized implementing version control or record structures at the filesystem level was unnecessary. DVCS implementations may similarly grow more alike and become simpler.
I wouldn't say 'unnecessary'; it's more the case that the quick and dirty Unix and DOS solutions 'won' by deign of being easy for implementers & users.
And ever since then we've been hacking-on the features that were lost because of this.
Two features we lost:
1. Generational data groups, as on MVS. The OS automatically keeping a history of changes to the 'file'
2. Addressing any file as an RDBMS table, as on OS/400. Amazingly flexible.
("in the OS" probably always means "in the kernel" in this context, not "in system user-space libraries")
No, but you do see thousands upon thousands of pages of text written about how to best use a shell to interface with the file system. This is what I think we are dealing with, we are on the cusp of actually having competent tools for the task of this collaborative, everybody works on their own computer but everything needs to be merged together in the end, and still work, thing that we have been doing for years. Give it a few years to settle down and either csh (Hg) or bash (Git) will win out and there will still be odd birds out there using sh (SVN) or zsh (Darcs) (feel free to permute those assignments to your taste).
I've used tools that are "simpler" than git: subversion for one. My experience has been that this simply means that they don't handle more difficult version control scenarios that do occur in practice. Subversion, in particular, just has a tendency to throw up it's hands and leave you to manually merge changes in any non-trivial merge scenarios.
It is probably impossible to package this complexity into an easy UI. I like git, because it has a simple core model, but the UI could certainly be easier. Mercurials model is not so simple (e.g. multiple types of branches and commits), but the UI is easier. Subversions UI is even easier, but the model is so simple that some things are impossible (the distributed stuff).
(can we assume on HN that people have understood "simple != easy"?)
The commits form a directed acyclic graph (a DAG) and you expand the graph when you make new commits. Subsets of the graph can be said to belong to the same branch (a named branch, the ones you create with "hg branch"). By default all commits belong to the branch named "default".
Any given subset of the commit DAG might have multiple heads (commits with no children), e.g., the subset of the DAG that is the "default" branch might have multiple heads representing multiple features that haven't been merged yet.
To help you pick the right head when you update, diff, etc, you can give it a name — you add a bookmark to the head. The bookmark is just like a post-it you stick on your monitor saying "commit e9ade5b11421 is better known as fix-broken-build". It's just an alias for the commit ID, in the same way that a Git branch name is a convenient name for a commit.
To be useful, bookmarks move when you make new commits. After 'hg update fix-broken-build', a 'hg commit' will move the "fix-broken-build" bookmark so it points to the newly created commit. This is again very similar to how a Git branch pointer will advance when you run 'git commit'.
I hope that helps a bit!
A DVCS is a tool we use to track and store data related to a project, collections of that data, changes in that data over time, changes in that data made by others, pointers to certain states, and the relationship of all of those things.
What you're really saying is that the filesystem API/UI is simpler than a DVCS API/UI.
My argument is that, a filesystem can be reduced to a simpler UI because it does fewer things.
We may not have found the simplest possible DVCS API yet, but it by nature is going to have to be more complicated.
For your filesystem analogy, if your Python app uses the filesystem as a storage layer you should be clear about the features you expect. When a DOS user will come telling you his data is not stored, you'll have to explain you use long filenames with non compatible characters. And perhaps symlinks for your folders, or access control for user management. And suddenly "just store my data" is not good enough, you'll have to care how and with what limitations.
For any abstraction you heavily rely on, eventually you'll have to understand where it leaks.
Tools are important to the craftsman. Plus, some people care about the entire process of building and not just the final product.
And it shows when you move out of the ultra comfort zone. If you want to drill a hole in the wall you need to take into consideration the size of the hole, the power of the drill and what are you drilling in. You cannot abstract them.
And then one day someone decides to use your python code not on ReiserFS but on Ext2 that has no journaling and all hell could break loose.
Most of this post leaves me thinking, "Why should I be worrying about things like this?" A fair amount of it leaves me at least somewhat boggled; I suspect I'm not alone here. The idea that a user of a DVCS needs to be familiar with issues like these tells me that something is seriously wrong with the design of DVCSs.
Remember, a DVCS is a tool we use to track and store data related to a project. The project is what we are interested in: the Python or C++ or LaTeX or whatever. Git, Mercurial, etc. are just there to help us keep track of the real work. Time spent dealing with the intricacies of Git is time not spent on the primary task -- the thing that Git is supposed to help us with.
Consider filesystems, which are also tools used to manage stored data. If I'm writing some Python thing, I don't proclaim to everyone that I'm storing my work on a ReiserFS volume, and I'm thrilled by the fact that ReiserFS indexes its metadata using a B+ Tree. I just store my data.
I think a well-designed DVCS would be thought of in much the same way. Clearly, current DVCSs aren't. Something is very much amiss, folks.