The Linux kernel is a very different animal than your average rinky-dink hobby project, which is different from your ten-dev consultancy.
Matter of fact is: the git UX is awful and it punishes everyone who doesn't have have a high level understanding of how the underlying persistence model works.
I believe this is true, but reading through a description of how the underlying persistence model works was for me a revelatory experience. This was presented together with a description of the precise problem git was designed to solve in the O'Reilly book, Version Control with Git. It seemed to be a problem solved in every particular -- an exact solution, that rarest of all things. I did struggle with git before I read about it, which is why I picked up the book in the first place. Since then I have convinced myself that any failures with git are due to my own deficiencies and not its, but my tasks with git are far from exotic; I rarely encounter any difficulties.
The value in the software is not so much the UX, which I consider acceptable (at least with aliases), but in the underlying data model. For me, it is a tool of daily use, and so the knowledge required to use it is a trivial investment. If we were discussing something other than a command-line tool, I think I might be more amenable to the argument that a simpler UX is a better one. With the CLI though, you pretty much need to know what you're doing before you attempt to do it, and any problems with the process are rarely considered UX issues.
In the common case, undo is provided by git commit --amend. For anything more complicated, I don't think that there is an explanation or GUI which could be considered "intuitive". I've used gitk and git-gui, and a variety of other visual interfaces before Reading the Figurative Manual, and while I'll be the first to cry my own ignorance, I have not found any of them to give much information about even the available options. What is cherry-picking? What about reverse cherry-picking? When would you want to use either?
It's not impossible to design a user interface which would translate all of git's graph manipulations into a simple visual system. However, its current textual interface is extremely flexible, and it exposes a very useful scripting interface. It is a tool that rewards knowledge and experience, like emacs or vi(m). Which is not to say that it's necessarily a good value proposition to you, but it is (imo) a good time investment. One of these days I need to invest in vim too :(
Unix geeks, you make my head hurt with your stockholm syndrome.
that is very true imo. reverting a merge once its pushed is a real headache in git compared to mercurial and its caused me problems often enough at critical moments that i simply refuse to use git
it can solve my problem but even 'experts' who like to tell me how to do it and how 'easy' it is seem to miss crucial details - the documentation is a little lacking in that area too...
in short i can learn how to do it with hg from no previous knowledge so quickly that i can not worry about forgetting it. with git the overhead for learning how to perform this one task is far too great - mainly down to ultra configurability and what imo are extremely poor choices of defaults.
Even for my personal projects I have my own work and merge to upstream master when I'm ready with a major feature set.
Sure you can work directly on master for small stuff, but for anything else good luck buddy. Humans make errors and it will catch up to you.
As painful as it is, it is unavoidable in oddball situations. The problem is everyone leaves it as "don't do that" rather than "don't do that, but if you do, here is how to fix it".
Normally trudging through the doco would get you to the fix, but back to problem #1.
I learned Git very recently, and I agree. It took me a while to grasp the basics because they just are not intuitive unless you understand how everything works under the hood.
This has led to me using some truly terrible version control systems, of which the worst was Cadence DesignSync. When using this system I wrote a rant detailing it (which is very offtopic for this thread but might be amusing):
- by default, a "checkout" contains symlinks to (non-writable) files, not the files themselves.
- this means that files can change under you. I suppose it saves a bit of disk space.
- want to edit a file? Mandatory locking!
- yes, that's right, mandatory locking is used instead of merges. No built in merging at all.
- In theory that avoids conflicts. In practice, what happens is: people take their own copy of the file, edit it, get the lock, write their edited version in.
- because it's hand-merged or unmerged, we've frequently lost changes and had to reapply them.
- towards the end of the project, finding out that the file you needed was locked by someone in a different timezone who'd gone home was getting really, really infuriating.
- to top it all, it's very, very slow.
This article from 2002 describes someone else having the same experience and building a "just use Perforce" frontend: http://eetimes.com/electronics-news/4153780/Irritation-promp...
https://github.com/blog/1178-collaborating-on-github-with-su...
The other points are merely the result of not really accepting the distributed nature of git. That distributed nature means that history is never going to be linear, and trying to force it is wasted effort.
I've seen `git pull --rebase` suggested as a common solution to avoid excess merges; is this dangerous or a good idea?
With the issue you're talking about, that's why we have staging environments. If you're going to release A and then B, you should be staging A, and then staging A+B. It's true that if they had ZERO idea on what the other were doing, they could step on each other's toes. But it will get caught before release. And hopefully there's enough communication to at least have a vague idea of who's working on the same parts of the code as you. If you're designing things that span large parts of the codebase without consulting or warning teammates, you have bigger problems.
Without distinct feature branches, you end up in abysmal horror situations where you push something, realize you have a bug in production, but can't roll it back without rolling N other features back. Then you start hacking in code to turn the feature off temporarily, etc, which rapidly turns into a mess.
Yes, you can catch the problem in staging, but you might have caught it before that if you had merged earlier.
> Without distinct feature branches, you end up in abysmal horror situations where you push something, realize you have a bug in production, but can't roll it back without rolling N other features back.
I don't think having a dev branch in an unshippable state is an abysmal horror situation. And even if you use feature branches for everything, that does not mean you can necessarily roll back the commits easily.
Do the developers of feature A and B push their respective feature branches to a repo in the staging environment where they are merged in some local integration branch there? Logistically, who does the merging? Is it this integration branch that is then merged into mainline?
I'm thinking about the scenario where you create a branch to do some dev work. It takes a week or so, during which, other commits are happening on master. Probably at multiple points during your week of dev work, you are going to want to pull in updates from master to make sure you don't hit conflicts or run into issues that weren't found until the day you try to merge your final work.
It sounds like you are saying that every time you want to update, you'd create a new integration branch of your work + master and then switch to that for further work until you are finally ready to commit to master? That feels a bit unwieldy..
And in an open-source community, as you rightly point out, nobody wants to do the dirty work. And merging is as dirty as it gets.
Surely this is a little overly pedantic? The point is that you want developers A and B to work on code bases that are as close to each other as possible, so that any problem in the interaction between these developers' work is caught early. Your project doesn't need to be completed in a day or two, you just need to accept that you have a dev branch which isn't always in a shippable state (which I think is usually unproblematic).
Instead, A and B should be on separate branches. Maintain integration environments where the feature branches are regularly merged together when each gets to the level of doneness that environment represents. The final step is to get promoted to master-candidate, where you are going to launch tomorrow unless we find a problem. If things break there, blow that away and recreate it from master, and fix your problems one integration environment lower.
In those cases, you have to fix the code base, and git wont help you. In my experience, it is much less common to have code that needs to be removed than to have bugs that were introduced because the code bases were synced too late. How much of a problem this is depends on how flexible your release cycle is.
Firstly, it is actually very easy for new work to happen upstream while you're merging your work in. Now you have the same problems the OP is discussing - your git pull will merge the upstream branch in, which you don't want (if you are like the OP). The only solution to this is to fast forward to upstream and re-do the merge (hopefully faster this time, especially if you're using rerere!), which is basically what the OP is suggesting.
Also, it seems to me that the OP's point is more "why using pull with the default options is considered harmful", and I think it's worth noting that the "correct" workflow you're advocating doesn't seem to be the one "advocated" by those defaults. You're saying "you shouldn't be merging upstream in, you should be merging your branch into upstream", but git pull's default behavior is precisely "merge upstream in". I think people can be forgiven for "not using git correctly" when they're using it in the way it seems to be encouraging! I'm being uncharitable to you - I know you mean "not using git in the manner I've found to work the most nicely" (and I agree with you), but I think it's worth pointing out that there a lot of git usage patterns are different than what the tool seems to point people toward.
Usually it's for "silly" things, like updating the readme with the online editor over GitHub (to quickly fix a type for example, when I'm not on my desktop) and then forgetting to do a "git pull" as the next thing on my local branch.
you try to push and it tells you you can't until you do a pull
you do a pull, resolve conflicts if any
where is the problem?
I mean, it's not an huge problem (and that's why I still use git pull), but it does comport some kind of annoyance.
In my experience, on projects with a few developers, --rebase is awesome.
I fix a typo in the README on the server, as that's the window I've got in front of me. I push the change, but don't pull it onto my laptop.
I don't pull the change to my laptop. I fix a different typo, and push it.
I pull down the new version on the server. I fix another typo. Now this commit has two parents: the one from the server earlier, and the new one from my laptop. Because it has two parents, it's a merge commit.
The first point is stronger than it seems, at least for me. It is a bit like requiring a definitive title to a novel I'm starting to write before the first line is there.
The difficult part, I think, is on the one side realizing what power you have and how to use it, and on the other side plain discipline.
Candidate branches for deletion: git branch --merged
Do you think Da Vinci sat at his table and thought "let's invent the helicopter" (with a nice unique memorable name for his work in progress)?
I would rather imagine Da Vinci being supposed to draw some boring architectural work or even writing against his will to his great-grant aunt. And then a paper fell off his table, spinning away. And then I imagine Da Vinci drawing a spinning paper on the margins, and adding equations, schemas, and getting deeply inside this new project, which becomes clearer in his mind as he works on it, without ever having a name.
This is exactly why I hate deciding a branch name before some tasks and I love `git add -p` which allow me to add a bucnh of unrelated things in the work tree and extract the juice later.
http://pragprog.com/screencasts/v-jwsceasy/source-control-ma...
Editted to add "absolutely".
The only time I branch for personal projects is when it is going to be a truck-load of changes, which are going to be hard to forget.
When working with more than 0 other people you should reserve the upstream branches for merging your work and pushing. Do your actual work in a branch and you can easily commit/stash our working tree, switch to the other branch and examine their changes.