Git is the C of Version Control Tools
ericsink.com
ericsink.com
Beacuse Eric Sink is a smart guy, but he doesn't understand git yet. He's still following the Subversion workflow. The secret is that "git commit" is not a sacred act. Don't be fooled by the words. When you do an "svn commit", the result is written in stone in some centralized repository where it can break everyone else's builds, now and forever. When you do a "git commit" the result sits on your machine. It goes nowhere. This is distributed version control -- a commit just changes your local repo, and if it doesn't work you just undo it. (Or, alternatively, make seven more commits in your efforts to fix it, then use the mighty "git rebase --interactive" to smash all of them together into a single, perfect commit. Then you pretend that it was correct all along. Nobody else will be the wiser. You'll look like a genius!)
So, if you want to pull half the hunks out of a previous commit, make a branch (you can make branches more easily than blinking -- this is git), pull out half the hunks, commit the result. Then compile and test. (If you like, you can probably use a post-commit hook to compile and test automatically.) If the tests pass, merge your experimental branch back into your development branch, then do the "git push" to the central repository. It is that push -- not any of your commits -- that is the point where you have to be sure that you're not breaking anything. And you can't use git's index to push files that have never been visible to your compiler and your tests.
UPDATE: I have yet to actually use them, but another one of Sink's commenters reminds me that git has pre-commit hooks that seem to solve his specific problem. Here's something I googled up on that subject:
http://www.nabble.com/git-pre-commit-hook--best-place-to-mak...
Again, I don't use such a thing, because I think it's kind of silly to insist that every local commit pass all tests. That's a recipe for failing to make enough local commits. I've been finding that it's better to make a commit every time you make any change that can be described in an English sentence. Then you have a little log of everything that you've done that you can rearrange with "git rebase -i" and turn into your final, pushable commits.
That's true w/in your scenario but a little misleading because it's not always true.
If you don't use the experimental branch, you can add and commit pieces of files, yet the tests will run not on what's committed but what's in your directory. So if you had
print password_to_the_admin_interface
for some reason, and then you comment that out/delete it and forget to add that part of the file, you test it and see that it's not printing the pass, but then you push and deploy and bad shit goes down.Just clarifying so no one's like "I can't push code I didn't test! Git is so safe!" and then allows disaster to occur.
I'm guessing that you could fiddle with git's hooks to discourage or even prevent this problem, if you wanted to. For example, you could refuse to allow "git push" to be run from within a repository that contains uncommitted changes, and also include a requirement that your tests pass before the push commences.
Usually it's when I do one thing, then start another, then realize that I really should push the old thing first.
So I add the old thing I did, commit, test (when I test. sometimes I'm bad and don't have real tests.) and push, leaving this half-finished method uncommitted.
I guess I really should just git stash.
C does not have nearly as many useful things built in as git.
His article makes it seem like he doesn't have his head all the way around git's internals, but I think his problem with git is a valid one: it makes it _much easier_ to do the wrong thing to the build than the relatively simplistic svn does, and it can be a drag to use tools that make breaking the build quite so easy. For big team projects it is, in that sense, very much like C programming, and even more like C++ programming: it's a lot of power, but it's way more than enough rope to hang yourself with, or for the guy in the next cube to accidentally hang you with:
> ...you need to act differently than you do when you're in an environment that attempts to protect you from your own mistakes.
But then a DVCS user comes along, just sort of wandering around in two dimensions. Because DVCS isn't like a tightrope; it's more like a flat parking lot with a line painted on it. You can stroll wherever you like, so long as you're standing on the line when you type git push. But the sight of a git user makes the SVN user freak out: "Watch out! You're going to fall off that level parking lot!"
And when someone compares the use of git to C, they are not being profound. They are just freaking out. Because that metaphor is poor. The problem with C is that you can easily write code that contains memory leaks or buffer overflows that are invisible to you, and invisible to your peers, and invisible to your automated tests, but that will cause a severe emergency weeks, months, or years from now. This is a problem that is orders of magnitude more serious than any of these alleged problems with git. git is not secretly introducing long-term time bombs into your code, even if you do manage to find a way to make it break the build.
I'm saying not that git shouldn't be used because it offers power. (Quite the contary: I use git-svn at work exactly because it's more powerful.) I'm pointing out that, "Oh shit, I better be careful with this different and more powerful tool," is a reasonable attitude for Sink to have.
That wouldn't be my first guess for the source control product of choice for the CEO of a company which makes a source control product.
Those of us who don't know git are now confused.
We're used to having "the result" on our local machine without interacting with our source control system. So, why do git users use its "commit" command to accomplish that?
We're used to "commit" meaning something like "publish". We're pretty sure that git has something similar, so we're wondering what it's called and why it wasn't called commit.
To refer to another discussion, this example makes it look like git requires more user actions to accomplish what we want to do and it uses idiosyncratic terminology. It's unclear why we'd view either of those as an improvement....
Git is a distributed system, where every user gets their own repository, so "commit" alters the repository on the local machine. This means you can use version control with impunity and not worry about giving bad code to colleagues. You can commit a broken work-in-progress without harming anything. You can also create branches with impunity and not have to worry about naming conflicts, polluting the space of branch names, etc. If something turns out to be a bad idea, you just zap it and nobody ever has to know.
When you reach a version that needs to go out to the wider world, you use "git push" to send it to a shared server. By default git remembers where you used "git pull" to obtain the source from in the first place, and can automatically push back to that server. (Note that I say shared server, not central server. If you want a single official server, you a free to dictate that for your project. You can also give each work group their own repository.)
I can do all those things without involving the source control system, so what do I get by involving the source control system? For example, why would I want to commit broken code? What does a local commit do for me?
In most cases, "distributed" is a necessary evil that folks work to hide, with varying degrees of success.
rolls eyes
If you don't like a feature, don't use it. I can easily commit crap that doesn't work to CVS or SVN repositories too.
But seriously, some people have the ability to reason about their code without having to run their unit test suite first. Not committing this patch:
(defun foo-bar (baz)
+ "Here is some unrelated documentation that I don't want to commit with my other changes."
(let ((quux 42))
is not going to break anything. But it will keep my doc change isolated, in the history, from other stuff I may be working on.If it does break something, you can always rewrite the history at a later date. (In Git, history is a tool to make development easier -- not an indelible audit trail for the suits.)
Running a full test suite before every commit just means you'll commit less often, which leads to bigger commits that are more likely to contain a smattering of unrelated changes.