Comment by dsp1234
10 years ago
"hey, can you branch the code to commit those changes and push them to the testing server? This thing's really cool and we don't mind playing with the alpha version, but we might scrap it all later."
Are they talking about hg or git here. Because that flow in git is:
git branch
git checkout
git commit
git push
The only thing that git adds to that workflow is that creating a new branch doesn't immediately move you onto it (also that most would use checkout -b to do both). And it's not immediately obvious that a non-technical user would need to know about that in order to get the above point across.
Ahahahahahaha. You think that works!
No. That fails with the following semi-helpful error message:
Actually all of these diagrams for Git need to look substantially more complicated because you first off need to introduce repositories which have a cylinder with a cloud over them (the cloud of course is the staging area) with a sort of recycle-reduce-reuse pattern of arrows `add`, `commit`, `checkout` between these three entities, with the caveat that `checkout` is only kinda-sorta what you're looking for with this. In fact there is a cylinder-to-cylinder `pull`-type operation called `fetch`, but `git fetch; git checkout` will not actually update any files, revealing the gaping hole in this simple picture, and you'll have to type `git status` to find out that you're directed to do a `git pull` anyway, which has to be diagrammed as an arrow pointing from the remote cylinder, bouncing off the local cylinder, and then pointing at the local folder.
To get to talk about `push` you then need to introduce the SVN-style "bare repository" in the diagram, a folder-box with the cylinder now drawn large inside it, and explain that this folder exists only to contain the .git subfolder and act as an SVN-style repository. You can then draw `pull` arrows down from it and `push` arrows up to it.
Then the workflow is more SVN-style:
Now that almost works, except the `git branch; git checkout` flow is not the proper way to push changes in the working directory to the new branch. (The context of the conversation was stuff that was already being developed, presumably on the master branch.) That fails on the checkout with an error message like:
But, I mean, close enough. It's `git stash branch <newbranch>` and it generates an ugly error message but it does exactly what you want it to do, so you can ignore that error message and hack away.
Now, you're missing the point if you think "God, drostie is really pedantically getting on my case for missing the remote-repository-update and the git stash here! Anyone will learn that workflow eventually!"
The point was not any such thing, the point was clean diagrams when explaining the idea to a fellow developer -- in fact a diagram so clean that a nontechnical user asked about it and accidentally learned enough to get some new vocabulary about how a developer's life works, so that they could more effectively communicate what they want to the developer.
It is my contention that the git diagram, as opposed to the git workflow, is sufficiently messy that a nontechnical eye will lose curiosity and most certainly will not get the idea of "make a branch, push the branch to the shared repository, then update the testing repository, then switch to that branch, then discard that branch if things don't work out." That strikes me as too in-depth for nontechnical casual users to express.
I think people have a way too high tolerance for this kind of crap. We're also kidding ourselves if we think we're smart enough to work with this kind of complexity at no cost.
Our job is often to think up new things. It's really hard to come up with new abstractions when your thinking is muddled by all kinds of incidental complexity.
This is buried but in case anyone reads it, the real reason to open source BK is to show the world that SCM doesn't have to be as error prone or as complicated as Git. You need to understand how Git works to use it properly; BK is more like a car, you just get in and drive.
2 replies →
> I think people have a way too high tolerance for this kind of crap.
I agree.
The core problem with Git is that it was designed to serve the needs of the Linux kernel developers. Very, very, very few projects have SCM problems of similar complexity, so why do so many people try to use a tool that solves problems they don't have? Much of that internal complexity extends up into the Git interface, so you're paying for complexity you don't need.
Others in this thread have praised hg and bzr for their relative simplicity for a DVCS. I'd also like to point out Fossil.
In the normal course of daily use, Fossil as simple to use as svn.
About the only time where Fossil is more complex is the clone step before checking out a version from a remote repository.
Other than that, the daily use of Fossil is very nearly command-for-command the same as with svn. Sometimes the subcommands are different (e.g. fossil finfo instead of svn status for per-file info in the current checkout) but muscle memory works that out fairly quickly.
Most of that simplicity comes down to Fossil's autosync feature, which means that local checkout changes are automatically propagated back to the server you cloned from, so Fossil doesn't normally have separate checkin and push steps, as with Git. But if you want a 2-step commit, Fossil will let you turn off autosync.
(But you shouldn't. Local-only checkins with rare pushes is a manifestation of "the guy in the room" problem which we were warned against back in 1971 by Gerald Weinberg. Thus, Fossil fosters teamwork with better defaults than Git.)
Branching is a lot saner in Fossil than svn:
1. Fossil branches automatically include all files in a particular revision, whereas svn's branches are built on top of the per-file copy operation, so you could have a branch containing only one file. This is one of those kinds of flexibility that ends up causing problems, because you can end up with branches that don't parallel one another, making patches and merges difficult. Fossil strongly encourages you to keep related branches parallel. Automatic merges tend to succeed more often in Fossil than svn as a result.
2. Fossil has a built-in web UI with a graphical timeline, so you can see the structure of your branches. You have to install a separate GUI tool to get that with most other VCSes. The fact that you can always get a graphical view of things means that if you ever get confused about the state of a Fossil checkout tree, you'll likely spend less time confused, because you're likely also using its fully-integrated web UI.
3. Whereas svn makes you branch before you start work on a change, Fossil lets you put that off until you're ready to commit. It's at that point that you're ready to decide, "Does this change make sense on the current branch, or do I need a new one?"
Fossil's handling of branches is also a lot simpler than Git's, primarily because the local Fossil repository clone is separate from the checkout tree. Thus, it is easy to have multiple Fossil checkouts from a given local repo clone, whereas the standard Git workflow is to switch among branches in a single tree, making branch switches inexpensive.
(And yes, I'm aware that there is a way to have one local Git checkout refer to another so you can have multiple branches checked out locally without two complete repo clones. The point is that Git has yet again added unnecessary complexity to something that should be simple.)
Why is it that some people get Git naturally and some experience a world of frustration trying to use it? I think the kind of problems you describe usually come up if you approach Git with a mindset formed by another SCM. They are typical for people who are proficient with, say, SVN and who try to use Git thinking that Git must work something like SVN. (I'm using SVN as just an example here; it could be any other SCM, but I most frequently see people coming from SVN to really struggle with Git.) Well, Git is nothing like SVN and you'll always be missing something if you try to understand Git through SVN concepts. It's best to forget what you used before and learn Git from a clean slate. Maybe I was just really lucky to never having to learn SVN (or CSV or ClearCase), so Git concepts and workflows were clear and almost effortless to understand and use. Or maybe it's like the concept of pointers: some people get it right away and others never get it.
> Why is it that some people get Git naturally
The only people I've ever seen "get Git naturally" were developers starting from the implementation details and working their way up (#0)[0].
Everybody else either worked very hard at it(#1)[1] or just rote-learned a list of commands(#2) that pretty much do what they want from which they don't deviate lest the wrath of the Git Gods fall upon them and they have to call upon the resident (#1) or heavens forbid the resident (#0) who'll usually start by berating them for failing to understand the git storage model.
> Well, Git is nothing like SVN and you'll always be missing something if you try to understand Git through SVN concepts.
Mercurial is also nothing like SVN, the problem is not the underlying concepts and storage model, it's that Git's "high-level UI" is a giant abstraction leak so you can't make sense of Git without understanding the underlying concepts and storage model, while you can easily do so for SVN or Mercurial.
[0] because the porcelain sort of makes sense in the context of the plumbing aka the storage model and implementation details
[1] because the porcelain in isolation is an incoherent mess with garbage man pages
> Now that almost works, except the `git branch; git checkout` flow is not the proper way to push changes in the working directory to the new branch. (The context of the conversation was stuff that was already being developed, presumably on the master branch.)
> But, I mean, close enough. It's `git stash branch <newbranch>` and it generates an ugly error message but it does exactly what you want it to do, so you can ignore that error message and hack away.
Isn't
what you are looking for?
And as for the push problem:
1. You aren't going to encounter it in git when pushing a newly created branch, but yes, you then have to ssh in and check it out.
2. I wonder how Mercurial handles pushing to repository with uncommitted changes, does it just nuke them?
Regarding 2 - Do you mean the destination repo has uncommitted changes? There is no need to nuke them, as pushing to this repo will have no influence on the working set: it will just add new changesets in the history!
1 reply →
Regarding your first question: Yes, you can also `git checkout -b newbranch`, rather than stashing the changes and then stashing them into a new branch; I just tend to stash my changes whenever I see that there's updates on the parent repository. Call it a reflex.
Of course, you can also commit your changes and then `git branch`, which sounds insane (that commit is also now on the master branch!) until you remember that branches in git are just Mercurial's pointers-to-heads. This means that you can, on the master branch, just `git reset --hard HEAD~4` or so (if you want the last 4 local commits to be on the new branch and you haven't pushed any of them to the central repo), and your repository is in the state you want it in, as well. (And you'll need that last step even if you `git checkout -b`, I think.)
Regarding your second one, Mercurial's simplified model is actually really smart. You have to understand that Git complects two different things into `pull`: updating the repository in .git/ and updating the working copy from the repository. In Mercurial these are two separate operations: you update/commit between the working copy and the repository; you push/pull between two repositories. The working copies are not part of a push/pull at all. So if you push to a repository with uncommitted changes in its working copy, that's fine. The working copy isn't affected by a push/pull no matter what.
With that said, if that foreign repository has committed those changes, Hg will object to your push on the grounds that it 'creates a new head', and it will ask you to pull those commits into your copy and merge before you can push to the foreign repository. (The manpages also say that you can -f force it, but warn you that this creates Confusion in a team environment. Just to clarify: a 'head' is any revision that has no child revisions. In the directed acyclic graph that is the repository history, heads are any of the pokey bits at the end. You can always ask for a list of these with `hg heads`.)
"OK," you say, "but let's throw some updates into the mix, what happens? Does it nuke my changes?" And the answer is "no, but notice who has the agency now." Let's call our repositories' owners Alice and Bob. Alice pushes some change to Bob's repository. Nothing has changed in Bob's working folder.
Now if Alice tells Bob about the new revision, Bob can run an update, if he wants. Bob has the agency here. So when the update says, "hey, those updates conflict, I'm triggering merge resolution" (if they do indeed conflict), he's present to deal with the crisis. Git's problem was precisely "oh, we can't push to that repository because we might have to mess with the working copy without Bob's knowledge," and it's a totally unnecessary problem.
Bob can also keep committing, blithely unaware of Alice's branch, if Alice doesn't tell him about it. The repository will tell him that there are 'multiple heads' when he creates a new one by committing, so in theory he'll find out about her commits -- though if you're in a rush of course you might not notice.
Bob can keep working on his head with no problem, but can no longer push to Alice (if he was ever allowed to in the first place), because his pushes are not allowed to create new heads either. In fact he'll get a warning if he tries to push anywhere with multiple heads, because by default it will try to push all of the heads. However he can certainly push his active head to anyone who has not received Alice's branch, just by asking Hg to only push the latest commit via `hg push -r tip` -- this only sends the commits needed to understand the last commit, and as long as that doesn't create new heads Bob is good to push.
1 reply →
No, the git equiv of svn up is not git pull, but git pull --rebase.