Die Git Die
github.com
github.com
It tells me I can lose history, but this is a revision control system, surely they don't mean I can actually lose history?
Sorry, but why did you think that they said that except to tell you that you could actually lose history? You ignored the rest of the error message and used --force. And then you were surprised that what the error message told you actually came to pass?
First of all, this is not a matter of me doing something wrong because I didn't learn enough of gits internals or didn't understand the cryptic the error message. The problem is that the error message appeared in the first place. In a sane revision control system, that would never have happened. Or at least, if a push fails because of a conflict, a git pull should have solved that.
This is not a matter of damaging the engine by revving it, or damaging anything else by misusing it. Because the history is not the engine, nor is it a child in a child seat. If you are going to use car similes, and you started it, then git is the car, and the history in your repo is your travels. The error message hence says:
"I'm sorry, you can't press the has pedal hard right now, because your engine is really a dwarf on a bicycle, and he is busy going to the loo. If you press the gas pedal hard now, the car will move, but you will suddenly appear where you were yesterday!"
Is that a sensible error message to you? Now, this is a road where you can take backup of where you are. So I did that, and tried, and to my astonishment the error message was right. The engine in my car was a dwarf on a bike, and I did find myself back where I was yesterday.
And the only way to avoid these things happening is : 1: backups or 2: Learning how the car is built from scratch, so I never press the wrong button or pedal again.
And you know what? That makes the car a crappy car. Requiring intimate knowledge about how to build and repair a car is something you needed in the infancy of automotive power. Not now. And it was something you needed when using RCS and CVS etc. Subversion solved that. Suddenly you could use a revision control system without knowing everything about how it is implemented in detail. But with git, we are suddenly thrown back to the RCS days.
That's the point, and that's why git sucks, and no misguided and incorrect car simile from your point can change that.
I am thereby sorry that my analogy isn't quite working for you (indicating I could have tried harder), but if you could see the number of up votes it got given not-high this story got as a whole, you might consider spending some more time studying it to try to learn from it. I am going to try, though, as this may be valuable to others. Your complaint is that git failed to achieve its stated purpose: to never lose history, so lets examine what that means for the analogy.
In the case of the engine being destroyed, the car also failed to achieve its stated goal: to continue to be a vehicle for transport to new locations. The path the car travelled is thereby not a useful analogy, because it isn't something the car claims to do: it is a side effect of the car existing, and if you lost the path the car had previously travelled somehow you'd blame the space-time continuum, not the car.
The reason why git failed to do this, is because it trusts the user to know better than it in many of the same ways that a performance vehicle does. This is because both git and the car have similar secondary goals: they are willing to violate their primary mission statement to give the user easier access to direct control. Sometimes, direct control is dangerous.
To draw this again laboriously: the people who built the car understand that if it stops being a vehicle capable of moving you from one location to another, that sucks, and they technically could add features that make it very very difficult for you to break that; but, in the case of the performance-oriented vehicle, they chose not to do so, as maybe you actually are "making the call" to destroy the engine to, say, stop faster (I know someone who has done this, incidentally, someone who has a hobby maintaining and racing cars).
To compare, the people who developed git understand that if it stops storing your history in a way where you can always access it, that sucks, and while they technically could have made it more difficult for you to do that (either removing such features entirely or hiding them behind totally unrelated commands, like svnadmin), as they are making a lower-level engineer-focussed tool, they allow you to screw up and expect you to know what you are doing.
The analogy continues to be useful, as no one forced you to use the more advanced, lower-level, "raw", performance-oriented tool: you are welcome to use something that makes it very difficult to screw up. If you don't like Subversion (which has a lot of advantages for this use case) you can use Mercurial, which as far as I remember makes this kind of history manipulation quite difficult.
The situation here is simply that you chose a tool that you should not have and which did not match your expectations, and it isn't because the tool "sucks"... it is just because you aren't in the target market for the tool. The reason why people like myself are using git right now is not because it is somehow fundamentally better than Subversion at simple tasks (most of the complaints about Subversion are about old versions, honestly, and darcs seems to have a much better way of thinking about the concept of patches), it is because sometimes we run into really hard tasks that it makes possible (such as managing a distributed collective of thousands of engineers, some of which are totally disconnected from others).
It is then git's insistence to make some of these hard tasks possible that directly leads to the kind of "I lost my history?" problems you ran into. As as example, I just spent the last two days "manipulating the past" in order to take some code that I had previously been maintaining as part of two separate projects (with three separate copies...), and get it all pulled into a single place with a unified timeline that will allow me (or now others) to more easily maintain and understand it going forward, and that was easy: git is an amazing tool for this very kind of manipulation that arguably is defeating its purpose, but in fact is enabling it to be useful at all (as the distributed engineer case involves a lot of personal rebasing and push forcing).
Again, though, if you want something simple: use Subversion. I'm going to continue to use git. This is despite having been an early adopter of Subversion, despite having contributed patches to Subversion, despite having contributed code to third-party tools built for Subversion, despite having spent time bonding with the developers of Subversion around late-night literal-campfires, and despite disagreeing with much of the anti-Subversion hype.
This tool doesn't suck: you just don't understand the advantages of using a manual transmission currently, nor maybe does a manual (and unguarded) transmission actually offer you any advantages for your unique position in life. I get that, that's fine... but it had a warning label... it had a massive danger notice, as they know sometimes people but the wrong thing, and you seem to have ignored it... your insistence that all cars should be unbreakable workhorses actually trumped your willingness to believe that the people who built the tool were telling you the truth, and you ignored the warning. That isn't as fine ;P.
(topic change)
By the way, you may continue to have the complaint that one engineer using git can damage history for others using "push -f". In fact, I used to have this same complaint, and went on similar rants to this article regarding it, but instead of complaining about me and how I might purposefully or accidentally lose my own work, it was about how I couldn't trust the server to not allow others to accidentally lose my work. You might not be, but just in case, there are two answers to that.
First, that is actually a misuse of a distributed revision control system: GitHub mistrains a bunch of people to share repositories, but git is designed on the premise that you only "push" to repositories you, the sole engineer, are the total owner of. You then send a "pull request" or a "formatted patch" to other people you are collaborating with, who then have you setup as a "remote" (likely with a "tracking branch"), and then they pull from you.
However, just in case you (or whomever is reading this) really don't care and just must use git this way (with a single centralized repository shared between multiple collaborators), as of 1.6 they added some configuration variables "recieve.denyNonFastForwards" and "recieve.denyDeletes" that cause the server to reject destructive activities. Alternatively, you can install custom hooks that provide this kind of behavior only for some branches, some users, or some other specific circumstances (maybe only on Tuesday ;P).
(One last thing: what you wanted to help you undo what you did was "git reflog", for future reference. Unless you manually override it, git actually stores recent--maybe 30 days worth of?--fifth-dimensional history, allowing you to see what you have been doing as you manipulate the fourth-dimensional timeline, and to allow you to somewhat-easily revert mistakes you may have made.)
That's a sharp edge that should be exposed, and its not the only one in git.
History not referenced will eventually be reaped by the garbage collector though.
Git is not really a revision tracking system.
Git is a content tracking file system manager. It happens to be the case that these two uses largely overlap, but what Git really lets you do is take snapshots of your filesystem, annotate each snap shot, and allow you to compare snapshots.
It does not keep track of your changes. You keep track of your changes when you use git by annotating each snapshot.
However on Gits' homepage: "Git is a free and open source distributed version control system".
It's muscle memory and makes everything more explicit and easy to understand. Although, in this case, it sounds like you expect git to be intuitive. (Which it is not)
So this basically amounts to a blog post complaining that git is hard.
And don't even get me started on the nightmare that is submodules.
The whole thing reminds me of the bad old unix days of "if it was hard to write, it should be hard to understand."
git checkout -b new-branch
... is a shortcut for: git branch new-branch
git checkout new-branch
You can create the branch or otherwise manipulate it without actually checking it out, so it's useful to have it separate and have a shortcut.(I agree that git's interface is terrible, but I disagree that this is one of those cases. :) )
I do think this is precisely one of those cases.
"Branch" is a major, repo-modifying operation; "checkout" is a trivial context switch operation. The user interface disaster here was that the major operation is treated as subservient to the trivial operation. It should be the other way around.
Therefore, the shortcut for creating a branch and switching to it should be
git branch -c new-branch
whereby the -c switch checks you into that branch immediately.Creating a branch is non-destructive and cheap, tidying up after accidental creation is also easy.
A common mistake people make when bitching about Git, is assuming that their workflow is the only workflow. Git supports a multitude of different workflows, and that fact is both a strength and a weakness.
But seriously, yes, you have to learn how to use Git in order to use Git. But you don't have to use Git. Click here to renew your Visual Source Safe license, or better, just copy your file to file.1 every time you edit it. No way that can go wrong!
[0] http://visualstudiogallery.msdn.microsoft.com/abafc7d6-dcaa-...
And feminine, at that?
! [rejected] master -> master (non-fast-forward)
And once you've invoked the gods of `push -f`, you're on your own.> Of course, a less good but at least sane behavior would have been if pull also pulled matching branches by default
I don't see any way this could work in the face of potentially having merge conflicts in non-current branches.
This is why git-up was created: https://github.com/aanand/git-up
It's silly that this is necessary, but "gem install git-up" and then run "git up" instead of "git pull" and you'll be much happier.
But don't get me wrong. On the whole, git is fantastic and a real improvement on its predecessors.
If I could change one thing, it would be pushing and pulling between workstations and central repositories. Distributed is nice, but at the end of the day you still want your code to end up somewhere, and Git doesn't make that process feel smooth or robust.
>no matter how proud Torvalds is of the fact that he
>never looked at another version control system for
>inspiration
What gave you that impression? Git was strongly influenced by BitKeeper and to a much lesser extent by Monotone. And, arguably, 'anti-inspired' by several other VCS's Linus would have surely been at least passingly familiar with.I think most of the outside influence came from people who weren't Torvalds, but the command set is just so weirdly different from every other VCS (even where functionality maps nearly 1:1) that it seems likely that it was designed without much consideration for existing use patterns of other VCS'.
http://marc.info/?l=git&m=114685143200012 http://marc.info/?l=git&m=116129092117475
And two basic verbs 'pull' and 'push' are straight from BK.
My impression's been that the crazy command set is in part due to the early design idea that the basic commands represent primitives that operate on the fundamental git model on top of which something, potentially separate and more human-friendly will be built. Except it didn't quite work out that way.
git fetch <remote> <branchname>:refs/remotes/<remote>/<branchname>
git rebase <branchname> <remote>/<branchname> git branch -r
will show all the remote tracking branches I had no idea existed. Thanks a lot, git makes much more sense to me now.Just look at git.kernel.org - over 400 repos only for linux kernel. This is what git designed for - to be Mass Distributed Version Control System.
So are using it as tape archiver and wondering why defaults look so unfrendly.
It's not me, it's post author who makes it sound so. Actually it's up to user to decide what is suitable for him and what is not.
I've been through this exact battle so many times, git pull should only ask you for your branch if you've told it you want it to (as a safety measure i guess)/
1. Not only mention of the rejected `master` branch, but also the successful push of the `gh-pages` branch. Which makes it a lot more clear that git is trying to push multiple branches, and that the rejection has to do with `master` and not `gh-pages`.
2. The push default of `matching` is changing soon in upstream git (because it is suitable for certain types of workflow, but can cause confusion, as seen here), and the last several versions complain loudly if you do not set the default. This is intended to call attention to this common pitfall, and to notify users so that they are not surprised by the change when it happens.
With git v1.8.2, here is the full output of `git push` in his situation (you may note that the non-fast-forward advice has been improved, too):
$ git push
warning: push.default is unset; its implicit value is changing in
Git 2.0 from 'matching' to 'simple'. To squelch this message
and maintain the current behavior after the default changes, use:
git config --global push.default matching
To squelch this message and adopt the new behavior now, use:
git config --global push.default simple
See 'git help config' and search for 'push.default' for further information.
(the 'simple' mode was introduced in Git 1.7.11. Use the similar mode
'current' instead of 'simple' if you sometimes use older versions of Git)
Counting objects: 8, done.
Delta compression using up to 8 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (6/6), 428 bytes, done.
Total 6 (delta 0), reused 0 (delta 0)
To /home/peff/foo/die-git-die/parent.git
148db6f..25cd4ef pages -> pages
! [rejected] master -> master (fetch first)
error: failed to push some refs to '/home/peff/foo/die-git-die/parent.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first merge the remote changes (e.g.,
hint: 'git pull') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.EasyGit also provides better built-in documentation. For example, if you get merge conflits, `eg status` will mention that you can run `eg help topic middle-of-merge`. That command opens a page explaining your options – how to find conflicts, resolve conflicts, etc. I have found EasyGit very useful, and when it’s installed, I always use `eg` instead of `git`. You can download the EasyGit script at the linked website, or install it using Homebrew with `brew install easy-git`.
Code section 5 and 6 are apparently modifying the code branch, and the pages branch, respectively, but doing so in separate local clones of the repo. I think there's a typo in code section 6, where I think he meant to start with
cd ../die-git-die.pages
This doesn't seem like a situation where multiple local git repos are needed. What's wrong with managing both branches from one local repo?A separate folder for the gh-pages branch makes sense because this branch has nothing in common with any of the other branches. It doesn't share any code or commits with your master branch.
The repository actually has two base commits and it's like two repositories contained in one. Thus needing two separate folders.
I think that if you had changed the above to
$ git push -u origin gh-pages
then everything else would have gone smoothly.Moreover, any loss that does occur is recoverable as long as you keep your clone around. Git doesn't garbage collect refs for at least 30 days. So you're pretty protected if you clone to a location that has regular backups.
My point is not that git is impossible to use. It's that the way git behaves by default is insane.
A common mistake people make when bitching about Git, is assuming that their workflow is the only workflow. Git supports a multitude of different workflows, and that fact is both a strength and a weakness.
That it deletes history without somebody issuing an explicit specific command to delete a specific revision is not a matter of workflow, it's bad design.
Looks like it was inspired by a hackernews comment https://news.ycombinator.com/item?id=2684483 and it replaces these commands
It's kinda like you're using wget to surf the web, and complaining that it doesn't have a GUI.
parent comment is arguing that the command-line interface is nontrivial, which is a fair criticism. Contrast with 'cp' or 'mv'
No one (except maybe linus) ever said git is easy. But it is flexible and powerful.
Anyway, this whole thing comes down to the user ignoring clear warnings. It seems clear to me that using "force" can break things.
Git user interface is fine when you finally learn how to use git.
I don't think your reasoning holds. That's why we have abstractions, to make hard things easy.
What makes git so powerful is that it doesn't abstract things as much as other systems. To make git easier would mean making it less powerful. I rather use a tool that is complex than a tool that doesn't let me do what I want.
The result is that it behaves unpredictably and confusingly. And that's a bad UI, no matter how powerful things are below.
"Git developers don't care about newbie users who can't even bother to RTFM."
This is probably true.
"There is just no reason they should."
Yes there is.
Github is the one who wants you to use git. This is why github built you a gui.
man gittutorial