This looks promising as a teaching aide. At my previous company, I transitioned our project from Clearcase to Git to save us licensing and administration fees. Many of the senior developers, who had never used Git, had a hard time understanding it, and I spent many whiteboard sessions explaining by drawing similar graphs. This would give those developers more autonomy, and stop the “let me blow it away and start over”, which would drive me nuts. Devs spent a lot of time and frustration performing that operation.
I believe the core issue is devs like above never take the time to “grok” Git. I believe part of this is due to the lack of a tool like above to teach easily, but also because devs want to ignore the “how” of their tool working to find out the exact commands they need to run in their current situation.
One could argue users should not need to understand how their tool works to use it effectively and this is a leaky abstraction. Others could argue some commands are not intuitive (git reset can do many things, and git rebase swapping ours/theirs comes to mind). I don’t claim Git is perfect, and sometimes I need to Google to learn more than I wanted to, to get out of an obscure scenario (e.g. someone put classified intelligence into a repository we need to transfer to a lower classification network; how do I rewrite the entire history while correcting this error that occurred 487 commits ago?). However, understanding the tree structure of Git, what git rebase does under the covers, what branches and tags are, how remotes work, how merging works, etc. would go a LONG way. The folk I worked with struggled to pick it up.
> I believe the core issue is devs like above never take the time to “grok” Git.
The problem I have with git us that it's just too complicated. When I'm juggling project complexities and design complexities and implementation complexities, I frequently don't want to have to deal with git too.
I understand how to stage and check in and squash, and branch and merge, and how to manage remotes. But last week I still managed to get a new repo into a state where I couldn't push local changes to github without doing a pull first, and I couldn't do a pull without (apparently) first updating the remote. I had a hard deadline and ended up deleting the repo and starting fresh. Nothing much was lost. I never had this trouble with tfs...
Maybe I'm just not clever enough, but I've never come across a dev tool with as much surface complexity as git.
(Not a git hater. Use it every day. Have had a personal github profile for a decade. Etc etc.)
I've resigned myself to accepting git because I have to use it. But JFC, I've hated it from the first time I tried it.
We now have a large selection of tools that allow you to visualize what's going on (I use git-kraken), as well as google for help on doing something that isn't in muscle memory.
But, really, SO MUCH pain and suffering could have been resolved by refactoring the damn commands to something more coherent and consistent. Git people sometimes call this "porcelain"-- which I guess is an apt name because it makes one think of a toilet (but an improvement to a hole in the ground).
> We now have a large selection of tools that allow you to visualize what's going on (I use git-kraken), as well as google for help on doing something that isn't in muscle memory.
Git Kraken is excellent, though Git has a page on various GUIs, many of which are free with no restrictions: https://git-scm.com/downloads/guis
Then again, the most complex workflow I've worked with was Git Flow and I didn't need anything more advanced than that. Come to think of it, I don't really do rebases often either and mostly just take advantage of squashing commits through GitLab/Gitea and such, when needed. But hey, that's also valid, using Git in a way where you get version control but mostly keep the technical details out of your way (though Git LFS and certain cases with particular line endings being needed does make you drop down occasionally).
Seconded. Git, like Linux is used everywhere, you can't avoid them. And even though I use it externally locally I use subversion, whose commands make a lot more sense to me. But Linus has something going for him: he knows how to establish critical mass for his projects, and how to create viable ecosystems.
i am no apologetic for the messy git UI. But i also know that any competent software engineer can be given a sufficient understanding / mental model of the basic git way of doing things in 1-2 hours, after which they can Google for the exact syntax of the commands they need (if they are doing complicated things). i feel that if they are unwilling to invest even that much time, then they are going to waste an eternity on endless tools and GUIs.
it's like tar or rsync or ffmpeg. Yes, it's hard to keep track of all the command line flags etc. but thanks to the internet we don't need to. it's far more useful to understand the underlying concepts.
Git is intrinsically a graph model. It's well-suited for very rich and effective visual representations.
If the cli "matched up" with a visual way of thinking, for many of us, the cli would become second nature. But it just doesn't match up. It's fugly and needlessly hard to remember and become fluent in at least for us "incompetent" engineers who already have too much to work on.
And how do you KNOW this? My experiences-- and many other's experiences have suggested otherwise.
Also it's foolish to suggest that one of the 21st century's most complex repository management software is just like tar, or rsync. What planet are you from?
This is maybe the most cogent version of my exact feelings on git I’ve ever read. In theory, I have no issues with git! In practice, the UX is often very very bad.
I teach git professionally. I have a 3-day 12-hour course I give.
I'm amazed how many people who have used SVN or CVS just assume git works like that but with different commands. And, of course, they get very screwed up. (GitHub contributes to this problem, too, with their own set of commands like "forks" and "pull requests" that aren't really a part of git.)
One you understand the Merkle DAG that's at the heart of git, understanding the rest is simple. Yes the commands are named badly, but get past that and it's a great system.
These days, with more young people developing, it's less CVS assumptions as such and more a Frankenstein of cargo-culted CVS assumptions they got at a remove from the Internet and Github's truly awful and confusing web interfaces.
You can't even get a simple gitk-style graph visualization on Github. Which is a website. After so many years, I really think all the blame for developer confusion can be laid at Github's feet.
There's been a graph visualization in GitHub for a long time, they've just intentionally buried it. Currently: Insights tab > Network
Arguably they buried it because it isn't actually what people want when they are looking for commit information. I know I've confused many developers by showing them gitk. I've been slowly working on a hypothesis that "subway diagrams" of commits look fantastic (Git Kraken looks great in screenshots) but get in the way of actually getting work done, much less thinking about the git DAG as an important tool beyond just "visualizing branches". (At this point I keep threatening to build a --first-parent based drill-down UI, that would look ugly as all get out in screenshots but might be a joy to actually use, but so far no one has sent me the check to make good on that threat.)
I wondered if someone would mention that this time around; it is a really bad piece of slow javascript that shows completely whacked-out graphs though, because it is trying to show the "fork" feature from github (and doing a poor job), not really the gitk or log --graph output of anything.
Yes, first-parent and expand would be a good way to view history. Github is a website and should be providing new and interesting ways to view information, not failing to provide even the basic lowest-common-denominator view (the gitk view).
It is not outside the realm of possibility that Github itself had a problem. I've seen instances where "git fetch" pulls refs but not the objects pointed to by the refs, then it gets cleared up an hour later and my builds suddenly start working again.
It's almost pure happenstance that Linus's idea of Git being distributed lent itself to the Cloud hosting business model. And the hardest thing to teach is the mental mapping of local and remote refs.
So this isn't just Git being too complicated. It's a confluence of several factors that would never have been possible if Git had never happned.
One thing to remember is that a pull is fetch + merge. I always fetch first which doesn't change any local branches. If that doesn't work fix your remotes. You can always recreate your local branches to track remotes, then reset to specific git hashes (if you take note of them or give them temp branch names).
No, it isn't. It's just a tool designed to work with complex software development workflows, which 90% of software projects do not need. 8 commands (pull, fetch, merge, push, add, commit, checkout and branch) are all you need to get going for git, which is like 2-3 more than what you need for svn/cvs. It's like getting upset that cars that are manual have an extra pedal (clutch) compared to automatic cars with their 2 (brake, accelerator).
* Trying to merge feature branches together (main or other feature branches)
* Trying to remove feature branches
None of which are necessary in a lot of development models. If you have that many feature branches that you have to rebase constantly, it doesn't sound like feature branches as a concept are properly understood.
The idea behind feature branching is one of 2 models:
1) either the main branch always works, and development is done in a feature branch, only to be rebased into main when development, testing, and sign off occurred, or
2) serious bug fixes occur outside the main branch, to be re-incorporated back into the main branch once it's been proven to be effective.
The 1st model should only require a rebase when the feature is complete. The 2nd model MAY require a couple of rebasing, dependent on how extensive the bug fixes are, and how fast the main branch is moving along, but not to the point where constant interactively rebasing your branches is the norm.
If you're writing a local stack of commits, you need to do an interactive rebase to edit the commits in the middle. You can't just check out and amend earlier commits in the stack, since git has a branch-first rather than commit-first model (one of its biggest UI failures).
No, I don't. Again, this seems to be a personal design/preference rather than a behavior git is forcing upon you, which is my point (This isn't a git issue, this is a development workflow that seems needlessly over complicated). When I do development locally, I only commit changes I want to keep. If there is something wrong, or code that needs to be modified, I make those changes, and then commit. When the work is done, if pressed upon me by the team, I rebase the local commits to a single commit before submitting a merge request.
None of my serious workflows require rebases, much less interactive ones.
Not that I don't do interactive rebases sometimes in local branches, but that I absolutely do not make them a part of any more general workflows. I rather try to avoid rewriting shared history where I can, and I'm happy with DAG navigation tools like --first-parent.
How do you manage stacks of commits for code review? (I'm guessing you just don't -- a lot of git users have really messy, unprofessional repository histories. The fact that git doesn't have great tooling for history management is also an embarrassment to our profession)
> Not that I don't do interactive rebases sometimes in local branches
I don't have a problem with rebasing in local branches before code review. I just don't allow rebasing once a branch has started code review, and I especially don't allow rebasing in a public integration branch ever.
(I also rarely feel the need to rebase, personally, even in my own local branches. Working in better tools than git in a past life has given me a lot of the discipline I feel that I need to build good commits as I work. I make much more use of the git staging area than I see most devs generally do and use `git add --patch` and `git add --interactive` far more than `git rebase`. `git add --patch` especially is an under-sung hero that I think a lot of junior developers should learn well in advance of rebase.)
Also, I'm just not that bothered by messy histories in code reviews when I review other developers work. If the idea comes across even if the commit messages don't have the greatest narrative flow or are perfect, I'm perfectly fine with that. I make sure all merges are --no-ff and after that I can browse a "clean" history post code reviews with DAG traversal tools such as --first-parent. But that also gives me an opportunity to dig back into the mess months or years later after the code review if I need to research a bug or a regression. That sort of "sewage archeology" isn't "fun" by any means, but the number of problems I've been able to solve with it is high enough I appreciate keeping that mess around in source control. It's source control's job to keep the mess for me and present me pretty views for more regular work. That's why I prefer to trust tools like --no-ff and --first-parent over --squash, because that's what source control is built to do, control old histories messy or not.
What can I say. You're locked into a significantly worse maximum than is possible (and exists) using better tools. In a normal workflow your commits are small enough that you don't have to do "sewage archeology".
I don't think you are reading me correctly. That is a rare occurrence, but it is possible when using merge commits to correctly describe the DAG. It's entirely impossible if you overly rebase/squash. Those rare times that I've needed to do it it have "saved" a project a lot of time from a major bug or regression. My normal workflow I look at a "clean" faux linear view, but it's just the "--first-parent" view of merge commits, which gives me a "PR focused" or "integration focused" view of source control first.
If your average commit size is 30-40 lines of code, this isn't an issue. Stacks of small commits is a time-tested workflow, used by the Linux kernel among many other projects.
I think we are talking about different things at this point, but I may be losing the thread of your argument here.
I love a code review to consist of lots of small commits. I'm mostly fine if even some of them from developers more junior than me are just named "commit" if they are small.
When I finish the code review I prefer to only `git merge --no-ff`. All those small commits stay in the code history in the exact form they were reviewed under.
If I'm looking at history I'm most often using something like `git log --first-parent`. In my --no-ff integration branch that just shows me an integrated change list (PR list). Git gives me a "straight line" view down the DAG and hides irrelevant information I don't want in that moment like all the small "commit" commits.
If for some reason I find a bug or issue in some code, I may need to drill down into specific small commits including the "commit" commits, and I have that ability because all those commits are still in the DAG.
Finally someone comes out and says it - I totally agree. I don't recall ever having to have a "tutorial" on Subversion. Git solves a problem the average dev really doesn't have in the first place.
Branching was just a copy? What was so hard about that?
As for check-out locks. you only had to ask them to do that if they'd requested a lock on the file which was not the default. I hope people weren't doing that too often at your workplace.
Merging is an operation which takes three inputs: left, right, and common ancestor. This is a very old algorithm, the diff3 utility on Unix is at least from the 70s I think? The reason history is a graph is to walk the graph and find common ancestors. Subversion's model cannot do this (screw off, pedants, I know they added an attempt at detecting common ancestors after Git had long since supplanted Subversion in relevance).
And if you can't merge, you can't branch. And if you can't branch, you need locks.
I'm just saying, as someone who has used subversion quite a lot over the years, the situation he is describing where you have an exclusive lock where they have to check in before you can, does not happen. Exclusive locks are very rarely used in subversion. If you and your coworker are working on a file, and he checks in before you, you will simply have to update and merge. Similar to if you were both working on a local git or mercurial tree.
Oh, and in that situation the 3 way merge is between the version he checked into the repo, your local version you are trying to commit, and your parent revision.
Well put! And it demonstrates why people (like the HN'ers who think they're 10xers) have trouble with git. They fundamentally don't understand the problem and how git solves it.
To be fair, Subversion had plenty of serious limitations. Local commits are a really good thing. It's just that Git itself is a terrible UI around a bunch of decent ideas.
I organized the migration from CVS -> Mercurial at my last job, and finally after several years when it became clear Git was where industry was headed we switched from Mercurial -> Git. After resisting it for a long time and then being forced to use it for a collaborative project with another firm, I have to say git is way better at being a DVCS than Mercurial.
I think, as other have mentioned, that once you truly "grok" git you begin to understand the elegance and simplicity of the system and how its layered. Ultimately git's use of branch pointers was a way better solution than encoding branch data in the commit itself. To it's credit Mercurial did attempt to rectify this later with bookmarks, but ultimately DVCSs are about branch management, and git has always excelled at it.
Mercurial's branch management makes more sense. If you want to know which branch a commit originated from in git, good luck.
Many things in git, are frankly anti-patterns in any other sane versioning system - comitting partial changesets because of the index? gross. Rewriting history and force pushing? absolutely insane.
The fact that I don't have to "grok" mercurial like you need to git is actually a plus. Mercurial can do everything that git does (and more: check out changeset evolution in mercurial, it blows anything you can do with git rebase out of the water) and it doesn't require Ph.D. level knowledge in directed acyclic graphs to do it either.
> Mercurial's branch management makes more sense. If you want to know which branch a commit originated from in git, good luck.
`git merge --no-ff former-branch` by default includes "former-branch" in the auto-generated merge commit name. When it matters what branch a commit "originated" on, it's very easy to use `--no-ff` (which doesn't rewrite history and won't need any sort of force push!) and most PR tools used to default to that before "rebase" and "squash merge" became some people's favorites because of some weird (in some cases OCD) wish to see SVN-like straight lines only in their commit history.
It isn't a "weird ... wish", a linear history is the correct default. Merges have always been, and should continue to be, a tool of last resort. In general it is good to minimize complexity in life.
Merges are the default state of life in any source control system with more than one person or machine involved. They are a regular, required need. Sweeping them under the rug, pretending that they don't happen, acting like they are rare is exactly the sorts of things that added complexity to systems such as CVS, SVN, TFS, Perforce and much more. It is exactly what adds complexity to so many of these rebase-only and squash-only workflows people like to constantly post about using in git.
Linear history is a punchline that ignores the reality of source control. The only truly "linear" history I'm aware of in source control is systems built on patch theory/operational transforms/CRDTs and that form of linear is subject to reordering and still needs explicit merge commits with (implicit) multi-commit dependencies even if there are few stated needs to visualize that as a DAG.
I agree with you, in general it is good to minimize complexity in life, which I why I eliminate rebase workflows and squash merges from mine. I prefer to see the evidence of where merges happened (and they should happen early and often), and graph data structures are very familiar to me as a software developer, including traversing them. (And git offers useful traversal tools such as --first-parent for when you want to view the DAG more like a linear history and ignore some of the noise. There's no reason to artificially simplify the DAG when DAG traversal is easy and accurate.)
> I believe the core issue is devs like above never take the time to “grok” Git. I believe part of this is due to the lack of a tool like above to teach easily, but also because devs want to ignore the “how” of their tool working to find out the exact commands they need to run in their current situation.
Github is largely to "blame" for this. It mostly only exposes the happy path and using git kind of like any other VCS, but above all it ossifies the idea of git repositories being centralized (both because the canonical repo is always on github.com but also because of the forking/ownership model). A lot of the power (and sharp edges, and messiness) of git are in scenarios where everybody has a local repo and nobody's is really "canonical".
Git is really well-suited to development of the linux kernel. It's not.. amazingly well-suited for the job that 95% of people these days press it into?
I think that the bigger problem is the misuse of Tags as the sole method of marking a commit for release for example.
Tags could be utilised for naming commits which would make it much easier to reason about where in the process of your development you are instead of referencing commits by hash. Hashes are hard to remember after all.
Mutable names should be branches, in my opinion, but not because I think tags are only for releases. I will absolutely use local-only "light weight" tags to name immutable points in time that look nothing like releases (and try not to push them accidentally; this is something that I think git's UI could be better about, it's an expected pattern which is why `git push --tags` or `git push --follow-tags` is a separate action by default from normal push, but `git push --tags` which is mostly all-or-none is much more convenient than patterns that push individual, specific tags). I just feel strongly if it is a mutable reference point it needs to be a branch.
Branches are so cheap in git that there's little to no reason to not use a million branches to name every step in a process if you need to, and yeah if you need a long-term name for a specific commit local-only lightweight tags are handy for that. (I find lightweight versus annotated an often easy enough distinction between tags intended for local development and tags intended for release markers. This also seems to be intentional in git UX because of the way `git describe` by default skips lightweight tags.)
Except, if you rebase, your tags get "lost" (not really, but they still point to the same old commit unless explicitly changed). Log is your friend, and making sure that the commits make sense (they do a single well-defined thing) helps a lot, because you always know which commit does what. But yes, that means using `git commit --fixup <commit id> && git -i --autosquash <commit id>^1` frequently to fix existing (older) commits instead of making new trivial ones.
in my opinion (the one where i don't care what anyone else thinks kind) you shouldn't be using tags on your working branches and your mainline/release branches should only be the ones where tags exists.
This then means that the only place you should be rebasing is your working/feature/pr branches and that when you merge your working/feature/pr branch, it should get squashed into the target branch... No one cares about your fifty gazillion 'wip' commits.
I guess that's the parent's annoyance. It'd be nice to be able to use something like tags or labels for other things than releases, but since they're commit referents, they're pretty much only useful for releases and nothing else.
I agree with your position. Our use case at the company I mentioned above was ten developers, all physically co-located, actually all operating on the same 3 or 4 servers. A centralized VCS was a better fit to our development needs. In situations where the problem space is centralized, applying a distributed tool is using the wrong tool for the job.
> I believe the core issue is devs like above never take the time to “grok” Git
I believe the same, and it's not just a problem you see with git, it's all over the place. Some developers seems eager to use something so they just skim the documentation in order to do the least amount of reading and understanding in order to implement something, but often miss some fundamental detail and have to jump back. Or, they fundamentally misunderstand the tool at all, but push forward with their own idea what the tool is, rather than stepping back and start learning again.
You say that like it's bad, but that's just life. We're trying to fit a whole universe into 3 pounds of meat. If we stopped to truly understand anything before taking action, we'd never get anywhere.
That's especially true in technology, where whole armies of people are working to complicate things as fast as possible. For the best of reasons, of course. But when I started out, I could read one short book and have a pretty good understanding of my computer's processor, and from there it wasn't much further to understanding the whole computer. Now I could spend days just understanding, say, processor cache strategies [1]. A field that is super interesting, but if I am to get any of my actual work done, I can't afford to dig into that and the many, many other similar subtopics. I'm going to get a casual understanding of something, do my best to make something useful, and only dig in further when I'm forced to.
When I do have to dig in, it comes in two cases for me. One is where there is something necessary complexity that I would have to learn about regardless. E.g., if something is too slow, I need to learn about what happens under the hood to do proper performance tuning. Great, fine, I will learn it.
But then there's the other bucket, which includes unnecessary complexity, bad abstractions, poorly considered UX, and the like. For me, git is clearly in that bucket. I intentionally have very simple development flows. Git can do a great deal, 98% of which I not only don't need, I actively don't want. [2] So I'm going do my best to remain ignorant of its inner workings, stick with my small number of commands, and very occasionally refer to "Oh Shit, Git!?!" [3] And I'm perfectly happy with that until it gets replaced with a technology that better matches the domain.
I'm very happy to fundamentally misunderstand GIT's internals because I want to do a finite (and small) set of operations with it, not HOW it operates under the covers.
Conflating the two, like you do, is elitism.
"If you just stopped and read to understand...", a-ha, sure, I'll do that for every one of the no less than 500 tools I've used over the course of my career and will never get anything done on time.
There's no time. We got real work to do and no we can't switch to a company that gives us this time. There's a big world outside the Silicon Valley.
GIT is a huge UX failure and seeing people pretend otherwise makes me question my -- or their -- sanity.
You won't have to put your entire life on break in order to understand the fundamentals of git and why it works the way it works. Going through https://jwiegley.github.io/git-from-the-bottom-up/ and really understanding the material will take you a couple of hours at max, but will save you a lot of time in the future.
Wanting to understand things before using them is hardly elitism, not sure why you would think that.
Just like you probably don't want to fix bugs without understand the cause, it's hard to use a tool correctly unless you know how the tool works.
Git is one (egregious) example though; Do I need to understand the fundamentals of every tool that I use/interact with every day? That's just not feasible. If not, where do you draw the line? To many, git is a means to an end, in the same way that $(insert_internal_tool_here) is. Nobody expects you to know the details of a B-tree and an R-tree to use MySql, so why is it ok to expect people understand the implementation details of git to use centralized version control?
I like your analogy because it outlines the flaw of GIT: we have to "fix bugs" in its UX so we can get our job done with it. :\
Also yeah, I agree learning GIT is not a huge sacrifice but with time I built a huge internal resistance against it so... dunno. ¯\_(ツ)_/¯
Maybe I'll get to it one day, in the meantime I am OK relearning cherry-pick and a few others every time I need them. I don't know, it just doesn't make sense to me. Guess to this day I don't see why it had to be a graph DB.
This article contains some very dangerous advice. In particular it says that the difference between reset--hard and checkout is merely down to the working tree changes not being preserved. What it does not mention is that reset will obliterate commit history subsequent to the requested revision 5f1bc85.
From the source:
Here’s me being straight up loco and resetting the head of my working tree to a particular commit:
$ git reset --hard 5f1bc85
The –hard option says to erase all changes currently in my working tree, whether they’ve been registered for a checkin or not (more will be said about this command later). A safer way to do the same thing is by using checkout:
$ git checkout 5f1bc85
The difference here is that changed files in my working tree are preserved.
> reset will obliterate commit history subsequent to the requested revision 5f1bc85.
It's not obliterated. It is still in the reflog, and in the history of any other branches or tags then have those commits in their history.
You have to try quite hard or wait 2 months to obliterate something that was committed or stashed into a repo.
You can even recover changes that were only staged.
Compare this to most other programs (word processors, GIMP, etc) which will happily genuinely obliterate if you undo multiple times and then do anything other than immediately redo.
This language is, IMO, damaging to the professionalism and image of software engineering. IIRC, I am echoing content from "Clean Coder", but in "professional" careers, it is expected that the practitioner is competent and stays up-to-date on the latest tools and techniques in their field.
When I see a doctor, I expect them to be familiar with the latest medical research. I expect they will treat my illnesses with modern medicines and employ the right tools, correctly, and understand how they work at a sufficient level of depth to do the job correctly. For example, I used to make electrical medical staplers; surgeons need not care about how RTOSes work, but they need to know how to interact with the software enough to do their job. Similarly, I'm not saying we all ought to be able to build Git from scratch. I'm saying we ought to master it to the extent necessary. If your use case is committing alone on a single branch, learn "git commit". But for most devs, understanding the tree structure that Git uses to store data and what basic operations are doing "under the covers" builds a mental model that makes Git easy.
We have to have the time to learn the tools that help us do our jobs well. You can neglect that duty to do "real work", as much as a doctor can neglect learning how to use a scalpel so they can "get on with the surgery".
> it is expected that the practitioner is competent and stays up-to-date on the latest tools and techniques in their field.
Even when the tools themselves suck?
The thing about our profession is that anyone can build better tools. Just like Linus took a week or two to sketch Git with some C code and a bunch of shell scripts (seriously, that was what happened - but he had the BitKeeper design in mind and how to improve on it). There is not regulation that says that in order to build a tool for millions of people to use you need to have a certification or anything.
Citing it as if it's something that's even needed to be said is kind of ironic on a forum with mostly programmers in it who, I am pretty sure, by and large possess a fair amount of critical thinking and quick analysis skills.
A ton of people have to make do with partial schedules. And I mean a ton, likely no less than 85% of all programmers everywhere.
You might want to make a good deep analysis on whether you're not coming from a position of severe privilege and a very positive filter bubble.
I agree with you, but I also have the thought of "well, git is one of the _top_ tools of the 500 I use," so I think I'm a bit more inclined to fill in a few more gaps as I encounter them. Ultimately though if you have the right balance of knowledge about the tool, you can always stop learning more about it until you learn otherwise…
Also true, and I agree. As mentioned in a sibling comment, with time I kind of started loathing the idea of learning GIT's internals so here we are. We'll see, these things tend to fall away with time.
You can either learn the tools of the trade, or you can go online and complain about how your hammer is too hard to use and so you refuse to hold it right. How is that not complaining?
You tell the guy using a brick as hammer that it isn’t actually a good hammer, no matter how many other people are also using bricks as terrible hammers. Git is a brick.
That's not a good analogy. A better analogy is someone telling you that you need to understand material sciences to be able to use an impact driver properly.
No, and you can't learn git in an afternoon either. Here's a very very simple scenario. You and I are working on a fork of a project. You make a branch and push it. I want to update an unrelated branch with the changes from the fork, so I follow [0] (note all of the various adjustments in the comments), and suddenly git switch doesn't work for your branch anymore.
Git has dozens of failure modes like this where the behaviour is completely unintuitive unless you understand the internals of git.
No, it doesn't. It does make learning it practical considering it's what everyone uses.
If you think you can do better, please do! Let me know when you've gotten a few projects to switch over and I'll gladly learn that, too. Not a lot of projects using mercurial these days.
Practically speaking, anything mainstream that I actually use. And the "still" qualifier there is the problem. That number should be growing, not shrinking.
Ok. Mainstream... you use it..
How about:
nginx, sudo, pypy, mozilla/firefox, facebook?
And. totally agreed, the number should be growing (especially for such a nice piece of tech with a far better toolset). Now that you've signed on to learning, hopefully that will be the case.
This is all Stockholm syndrome. Git has a lot of random accidental complexity, from reset and checkout doing too many things (yes I'm aware of switch and restore), to stacks being a pain to work with. The idea that you're supposed to just be in the middle of an interactive rebase most of the time is mind-boggling.
A better thing to say is "yeah we've been saddled with this horrible tool, yeah we know it sucks, but it'll suck a bit less when you learn it. Oh and sorry if you're not a professional developer and have to use git, I hope we can do better next time."
Yes, we all know it has some rough edges and could be more convenient. Unless someone actually makes that idyllic more convenient tool and it becomes widespread, none of that matters. We're stuck with the hammer that everyone else is using. No sense refusing to learn how to use it just because you're stubborn, everyone else managed just fine.
Well no, that's not the case. In fact many projects (gitless for example) clearly show that a consistent UI for git is possible, but unless git developers decide to rework the tool completely, we are stuck with what we have. And no, using a 3rd party tool and convincing every team that gitless is better is simply not going to happen. The way out is for someone to swallow their pride, admit they did a half-assed job and fix it. Not holding my breath though.
I say that as someone who uses git daily, who has learned git internals, who uses cli almost exclusively, who helps the teammates out of their git problems and who still hates the cli inconsistencies.
I've seen this phenomenon as well. I've noticed a few factors that I hypothesize contribute to this:
1) Making Computer Science programs in universities overly simple. When I was in college, I tutored students in CS. When I started college, the CS 101 course was taught in Java, and when I finished, it was being taught in Python. There was an immense gap between the understanding of the Python-first vs. Java-first students.
The Java-first students understood fundamental concepts like arrays, passing parameters by reference vs. by value, "OOP" concepts, and other common paradigms in languages. The Python-first students would use "lists" and "dictionaries" for many problems without understanding that those structures impacted the time complexity of their solutions, or that they used memory allocation, reallocation, hashing, etc. Python is great for hacking together a non-fault-tolerant program that does X as quickly as possible, but I saw it damage the way the students thought about computing.
It made the students think it ought to be easy. It made them think that they should be able to write, in nearly plain English, what they wanted the computer to do, and that it ought to do it. It made them think they should be able to intuitively be able to code without spending any amount of time learning the craft, and that they could do anything an advanced programmer could do by typing a few lines of simple code. They were less willing to accept that sometimes problems are hard, sometimes they would have to think, and sometimes they would have to write more than a for loop to solve problems. The Java students' problem sets covered implementation of data structures and complex applications, while the Python students struggled to put together even the implementation.
For a humorous and broader explanation of this subject, see James Mickens' excellent article The Night Watch [0]. For example: "That being said, if you find yourself drinking a martini and writing programs in garbage-collected, object-oriented Esperanto, be aware that the only reason that the Esperanto runtime works is because there are systems people who have exchanged any hope of losing their virginity for the exciting opportunity to think about hex numbers and their relationships with the operating system, the hardware, and ancient blood rituals that Bjarne Stroustrup performed at Stonehenge."
2) Bad documentation, and bad users of documentation. I dislike documentation that neglects how the tool works and instead creates a cookbook that its users can copy verbatim. It has similar effects to what I described above. Developers that use this type of documentation find themselves helpless when they encounter a problem they've not memorized the solution to. I think it also creates a learned helplessness wherein users cannot question the model the tool uses or think outside that model to solve complex problems. I prefer documentation that teaches the ethos of the subject in question so that I can understand better and imagine new solutions.
I've also heard the complaint that Git's documentation is awful; some say that it is only useful if you know already know where what you are looking for is, and useless if not. In other words, it lacks an "apropos" (aka "man -k") equivalent. This is my gripe with "wiki" style documentation. It is scattered and unsearchable and has no cohesion. We as developers need to do a better job creating documentation that is searchable, coherent, and useful to new and experienced users alike. Various sections of documentation should have ample cross-references to help users understand the connection between parts of the system to help them form a mental model of how tooling works.
Git is an amazing tool with terrible UX. It's very difficult to know what the right thing to do is and the mental model is a bit weird. For example, undoing an operation is another, new commit.
That is the option of last resort, when you have already pushed _and_ you cannot mess with the history anymore.
The other one being reseting your local branch to a previous commit and force pushing if needed.
I learned git at 45yo after many years using ClearCase (even licensed as CC admin) and .. I really liked learning git, I do admit that it took me two full days of self study to start groking git but I wouldn't call it 'struggling'.
Obviously it depends a lot of your background.. git is the 5th version controls I've used , while it is far from being perfect (submodules.. :-( ), it's my favourite.
Were you trying to teach them with the CLI though? That's a terrible approach. The CLI is awful and Git is a visual thing.
It's like teaching someone to drive a car using LOGO.
The way to teach Git is:
1. Explain the mental model (correctly). Basically a commit is a snapshot with deduplication to avoid huge file sizes.
2. Show them how to use a good Git GUI. There are a lot of bad ones. I would recommend Git Extensions (terrible name but it's actually quite good). Or maybe GitX on Mac.
3. Let them learn the CLI slowly in their own time.
I never found a GUI that was more intuitive than the CLI, personally. I am a bad person to consult for this, since I live in vim and tmux (my coworkers hid my mouse for April Fool’s Day and I went the day without it to make a point) while others blaze ahead in VS Code and know the bare minimum command line to get their job done.
I’ll take a look at Git Extensions, thanks for the recommendation! Some of our devs took to using the integration with VS Code, which I didn’t like because I didn’t understand how its terminology (e.g. “sync” mapped to underlying Git operations). Others tried the Git GUI which I found very confusing.
I focused on the graphical operations and then tried to show them what commands they could run to execute those operations. Next time I’m in the situation, maybe I’ll adopt a GUI-first approach.
My issue with gui is that sometimes I need to work with git in terminal, over ssh, so I need to know it. Once I learned it, what's the point of using a gui? [0]
[0] there is one operation where gui is more convenient for me - exploring branches in gui or GitLab ("repository -> graph") has no equivalent in cli that I know of (interestingly, GitHub doesn't have that either, but many gui tools do).
> Once I learned it, what's the point of using a gui?
The first point is that it makes it easier to learn the concept of Git, which is most of the difficulty. Yes Git's CLI is really terrible, but if you know the concepts you can mostly just google the CLI options and learn through repetition.
The second point is that GUIs make it easier to see the state of the repo. There's a reason that even the CLI includes a basic GUI. Don't tell me you never use `git log --oneline --decorate=all --graph`.
The problem is that every git UI I've tried of the past ~10 years abstracts core concepts in order to (try to) simplify things, then people make a mess and don't have the slightest clue why or how to fix it.
The git CLI for the vast majority of things isn't difficult once you have a basic understanding of DVCS. 95% of the time fetch, pull, push, checkout and commit are all you need.
I admit that Hg had a far nicer an more consistent CLI, and it was my preference back in the day. But it lost for a few reasons - one of which was that it made the 90% easier, but the 10% far harder.
Terrible advice, you should absolutely start with the official UI, which is the CLI. Avoiding it because "it's hard" will just complicate everything down the line.
I wasn't saying otherwise. It's an analogy. In case you struggle with those, in non-analogy form it would be "Do you start teaching a new concept using its most advanced incarnation?" No, you start from the basics.
A big reason I wanted to pursue this idea is exactly what you mentioned - a lack of ability to easily create presentation-quality Git structures that can apply specifically to the situation a user is in, NOW.
A super annoying thing about troubleshooting Git issues is when you find a similar solution online but it's done in someone's random repo which could be very different that yours. Your whiteboard sessions are another good example down this line of thought.
More like a backed-up abstraction, simpler on the inside.
Though that's only true of the core, with tags being additional decorations and renames inferred. The simple core delegates complexity.
I think designing a nicer git UX is not easy. Even if we oversimplify commit to cp your working directory together with a path to the previous commit (to form a tree of "branches"), then the abstraction for operations like rebase to manipulate that tree is not quite intrinsically simple.
BTW Tools can be used without proper understanding, like arithmetic without commuting, associating or distributing. While a workable pidgin aids adoption, it's fair to argue for the power of understanding, especially of something clean and coherent and whole. Git's core is like that; the add-ons (like tags) aren't; and the UX seems arbitrary and accreted.
My company is currently transitioning from a 20+ year old Perforce depot to a git workflow. We're certainly having issues like you describe, where people don't know (and don't care to learn) the mechanics of git. And I agree, git is the kind of tool where once you understand the primitives, you can quickly start making lateral leaps to solve problems.
But I do think that there's room for a better mechanism for orchestrating "macros" or building other workflows on top of git. I know a lot of developers who'd love the ability to pretend they're using p4.
My company wanted to "script away" all the "pain" of using Git to make it equivalent to Clearcase. I think it's a smell. If you want to use Clearcase, use Clearcase. etc.
I believe the core issue is devs like above never take the time to “grok” Git. I believe part of this is due to the lack of a tool like above to teach easily, but also because devs want to ignore the “how” of their tool working to find out the exact commands they need to run in their current situation.
One could argue users should not need to understand how their tool works to use it effectively and this is a leaky abstraction. Others could argue some commands are not intuitive (git reset can do many things, and git rebase swapping ours/theirs comes to mind). I don’t claim Git is perfect, and sometimes I need to Google to learn more than I wanted to, to get out of an obscure scenario (e.g. someone put classified intelligence into a repository we need to transfer to a lower classification network; how do I rewrite the entire history while correcting this error that occurred 487 commits ago?). However, understanding the tree structure of Git, what git rebase does under the covers, what branches and tags are, how remotes work, how merging works, etc. would go a LONG way. The folk I worked with struggled to pick it up.