Git porcelain stuff's plenty good for probably 95% of users. `rebase -i` comes with a guide on which commands do what, and you could write a couple of paragraphs about how to format `git log`'s output with your own preferences and tradeoffs -- and porcelain usually includes stuff as eclectic as `git gc`, `git fsck`, and `git rev-parse` by most accounts.
Git plumbing's definitely a bit more obscure, and does a bunch of stuff on its own that you can't always easily do with porcelain commands because they're optimized for the common use cases.
TL;DR: while Git's big (huge even), a lot of what it provides is way off the beaten path for most devs.
Commits are snapshots of a tree. They have a list of ancestors (usually, but not always, just one). Tags are named pointers to a commit that don't change. Branches are named pointers to a commit that do change. The index is a tiny proto-commit still in progress that you "add" to before committing.
There. That's git. Want to know more? Don't read the guide, just google "how to I switch to a specific git commit without affecting my tree?", or "how do I commit only some of my changed files?", or "how to I copy this commit from another place into my current tree?".
The base abstractions are minimalist and easy. The things you want to do with them are elaborate and complicated. Learn the former, google the latter. Don't read guides.
Because the C and PL/SQL people are on CVS, I can fix this with vi on the ,v archive.
First on TFS repositories, and now with git grep I can easily find exposed passwords for many things. But it's just SQL Server!
We will never be able to use git responsibly, so I will peruse this guide with academic interest.
Don't even get me started on secrecy management.
I am looking forward to retirement!
tldr: even if you never plan to use anything advanced, you’ll end up in some weird situation where you need to do something even if you’re in the “95% of the users”
no shade, yes ofc you “could this, could that” to make things work and we have been stuck with this for so long that an alternative doesn’t even seem plausible
Learning git like this is honestly just hampering yourself
The evidence that the git UI is awful is _overwhelming_. Yes, yes, I’m sure the people that defend it are very very very very smart, and don’t own a TV, and only listen to albums of Halloween sounds from the 1950s and are happy to type the word “shrug“ and go on to tell us how they’ve always found git transparent and easy. The fact is that brilliant people struggle with git every single day, and would almost certainly be better served by something that makes more sense.
Like others in these comments, I can use it just fine right up until I can’t. Then it’s back to the mini, many, many posts and questions and tutorials, sprawled across the Internet to try and solve whatever the issue is. JJ has shown that a better chrome can be put over the underlying model, And it’s frustrating to me that we are all collectively, apparently, expected to put up with a tool that generates so much confusion seemingly regardless of brilliance or expertise
Listen, I'm not that smart, and I managed to figure out how to solve even gnarly git issues one summer during an internship... 11 years ago? Ish? Now, I know git well, and not just "the three commands". I would be, honestly, so ashamed if it were a decade on and I still hadn't committed to learning this fundamental tool.
Version control is a hard problem, fundamentally, and a tool for experts will always take more effort to understand. I mean, aren't we supposed to be the software experts? If people can't learn git, I wouldn't trust them with the even harder parts of software development.
But this is a common attitude in industry now, unfortunately: a petulant demand for things to be easier, and for someone else to do the learning. Is it any wonder software today is so bad?
It did take maybe a year or so to develop the mental model of the how commands map to the underlying structure of commits, and another few years to avoid footguns (like always "push --force-with-lease").
So I think it is probably too complicated and would be happy to switch to a better alternative if one comes up, but what seems really implausible to me is going back to the bad old days of SVN.
Like so much of the porcelain is those kinds of tricks, and make otherwise tedious work much simpler.
Imagine if you didn't have interactive rebases! You could trudge through the work that is done in interactive rebases by hand, but there's stuff to help you with that specific workflow, because it is both complicated yet common.
I think jujutsu is a great layer over git precisely because you end up with much simpler answers to "how do I change up the commit graph", though.... the extra complication of splitting up changes from commits ends up making other stuff simpler IMO. But I still really appreciate git.
Commits are sets of files. They form a tree. A branch is a named location in this tree. The index aka staging area is a pre-commit that has no message. Workdir is just workdir, it doesn’t go in the repo unless you stage it. HEAD is whereafter commit will put new changes.
Do I understand git? Seems like yes. Let’s run a quiz then! Q? A.
How to make a branch? Git branch -a? Git checkout -b --new? Idk.
How to switch to a branch? Git switch <name>, but not sure what happens to a non-clean workdir. Better make a copy, probably. Also make sure the branch was fetched, or you may create a local branch with the same name.
How to revert a file in a workdir to HEAD? Oh, I know that, git restore <path>! Earlier it was something git reset -hard, but dangerous wrt workdir if you miss a filename, so you just download it from git{hub,lab} and replace it in a workdir.
How to revert a file to what was staged? No idea.
How to return to a few commits back? Hmmm… git checkout <hash>, but then HEAD gets detached, I guess. So you can’t just commit further, you have to… idfk, honestly. Probably move main branch “pointer” to there, no idea how.
If you have b:main with some file and b:br1 with it, and b:br2 with it, and git doesn’t store patches, only files, then when you change b:main/file, then change and merge+resolve b:br1/file, then merge that into b:br2 to make it up-to-date, will these changes, when merged back to already changed b:main become conflicted? Iow, where does git keep track of 3-way diff base for back-and-forth reactualization merges? How does rebase know that? Does it? I have no idea. Better make a copy and /usr/bin/diff [—ignore-pattern] the trees afterwards to make sure the changes were correct.
As demonstrated, knowing the base abstractions doesn’t make you know how to do things in git.
I don’t even disagree, just wanted to say fuck git, I guess. Read guides or not, google or reason, you’re screwed either way.
This idea breaks under pressure. People have limited concentration and the more you demand for daily routine, the less there’s left for the actual job. This argument only makes sense in a relaxed setting with lots of time and coffee breaks. But all these problems tend to happen at friday evening when you’re expected to get your kids in an hour or something and this damn repo got broken again.
Yes, things should be easier. Cause you get what you get. If you want people who have no issues with git, feel free to enjoy the greatly reduced hiring pool and stop whining about someone not being able to juggle fifty things at once in their mind - focus on your hiring process and where to get the budget for inflated compensation instead.
Is it any wonder software today is so bad?
I remember delphi and vb time, when people - who were unable to understand or use CVS and SVN - made full-blown apps for real sectors, and it worked. Because it was easy. Nowadays all we have is important dudes with pseudo-deep knowledge of git, css, framework-of-the-month and a collection of playbooks, who cannot make a db-enabled hello username message box in less than a day. I don’t think you’re moving in the right direction at all with this. This paradigm is going further and further from good software, actually.
The worst part about Git is the bad defaults. Seconded only by mismanaged storage. Or maybe being designed for the use-case most of its users will never have. Or maybe horrible authentication mechanism. Or maybe the lack of bug-tracker or any sensible feedback from its developers.
None of this can be helped by the GUI. In fact, beside Magit, any sort of front-end to Git I've seen is hands down awful and teaches to do the wrong thing, and is usually very difficult to use efficiently, and mystifies how things actually work. But, even with Magit, I'd still advise to get familiar with CLI and configuration files prior to using it: it would make it easier to understand what operations is it trying to improve.
At least, this is what it looks like from your own description. This is, probably, what most people do with it most of the time. And the weird corners will be found when they need to automate things, or when they want to deal with modular repositories, or history rewrites. These aren't everyday tasks / not for everyone on the team, but, these things do happen, especially in smaller teams, where there's no dedicated infra person or group these can be delegated to.
Try to come up with something simpler than git, and you’ll end up with something like SVN or CVS that struggled with more than a couple of people working on the same files.
Try to make something that is more content aware, and you’ll find out how git got its name in the first place.
Git is designed for the case where you have multiple remotes with no central authority. Except that’s not how any project I’ve _ever_ worked on functions in reality. It makes sense for some applications, but if I say that I run Linux, there’s an assumption that I’m running something compiled from https://github.com/torvalds/linux - I.e. there is a central space.
I’ve used git and perforce in anger for a decade, in teams of 1 to 150+ (with a brief blip in the middle where I tried plasticscm which was a mistake), and I’ve been the “git guy” on teams during that time. If git’s defaults were tweaked for “one origin, probably authoritative” and it had better authentication support out of the box it would be a significantly better experience for 99% of people. Those 1% of people who are left over are going to customise their config anyway, so make them add the distributed-defaults=true flag and the rest of us can get on with our work.
I do deal with multiple remotes quite often and haven't encountered issues. You're right about submodules, I avoid setting up projects with them, even at the expense of more manual work or complicated automation.
I'm definitely not using it as a substitute for rsync - I do prefer to put rules in place to avoid editing (shared) history, for obvious reasons.
This is about as useful as "A monad is just a monoid in the category of endofunctors."
It's basically a lot of words which make zero sense for a user starting to use git -- even if it happens to be the most succinct explanation once they've understood git.
> The base abstractions are minimalist and easy. The things you want to do with them are elaborate and complicated. Learn the former, google the latter.
You can't really learn the former -- you can't even see it till you've experienced it for a while. The typical user groks what it means after that experience. Correction, actually: the typical user simply gives up in abject frustration. The user who survived many months of using a tool they don't understand might finally be enlightened about the elegant conceptual model of git.
Facetiousness aside, the things you do often, you learn once and you don't really have to remember/think when doing them. Most of the esoteric operations are mostly unnecessary to burden yourself with until you actually have to do them, when you just read the documentation.
The command line isn't that hard to use if you've ever used the command line before. Beginners trying to learn git and command line at the same time (which is very common) will get utterly confused, though, and for a lot of beginners that's the case. The only difficult part with git over the command line is fixing merge conflicts, I'd recommend anyone to use any IDE rather than doing that manually.
No IDE will be of any help for getting back to normal when you get into a detached HEAD state, which IDEs will gladly let you do if you click the right button.
In my experience people come to git and start using it with the centralised paradigm in their heads: that there is one repo and one DAG etc. They think that their master branch is the same as "the" master branch. You just can't get good at git with this wrong understanding.
The issues most people seem to have with git are common version control issues. Version control is actually hard, even if it's just "what has changed", once you start going beyond two users editing a file at once. When three people edit a file at the same time, there's going to be complexity when those changes need to be applied back, and that's where you start getting into branching/merging/rebasing.
Just like some people simply cannot get functional programming/object oriented programming/imperative programming to click in their head, others will never truly grasp version control. It's a paradigm of its own. People who know lots of data structures like to trivialise version control into data structures ("it's just a list of ...") but the data structures are the chosen solution, not the problem.
Another complexity issue is that git is actually pretty smart, and will fix most problems automatically in the background. Often, when you need to manually operate on a git repo, you're in a situation where git doesn't know what to do either, and leaves it up to you as the expert to fix whatever is going on. And frankly, most people who use git are nowhere close to experts. The better Git tooling gets at fixing these situations for you, the worse your situation will be once you need to manually correct anything, and the worse your perception might get.
I have no good advice for you on how to work Git better. All I can say is that I'm very productive with Jetbrains' IDE integration, others seem to prefer Visual Studio Code's git integration, and then there's the Tortoise people. Find whatever tool works best for you and hope you'll have a random epiphany one day.
If you insist on memorizing commands for all these tasks (of which there are many), indeed, you're going to struggle and decide you need a 30 section guide. But you don't, and want to whine about it.
> I don’t even disagree, just wanted to say fuck git, I guess.
Pretty much.
A powerful Git GUI makes even moderately-complicated actions like cherry-picking, interactive rebasing, and even ref-logging absolutely trivial. In fact it was precisely said GUI tool that allowed me to develop an intuition for how Git worked internally; the CLI does no such thing.
Unfortunately it's been long enough I don't remember details why, just that it was something with how it handled branches.
I find this an odd statement. I mean, no, I don't want to do the work! Not if it isn't necessary in the first place.
Take staging (or the index, because another of Git's foibles is poor naming conventions that stick around and confuse newcomers). It's kind of a commit, right? In the sense that it's a snapshot of work that represents a change to the code. Except we can't really make it behave like a commit, we have to interact with it using special commands until we turn it into a commit. Are these special commands really doing much differently than we might do with another commit? Not really.
Or take stashes. Stashes are more like commits — they even appear in the reflog! But they also aren't real commits either, in the sense that you can't check them out, or rebase them, or manipulate them directly. Again, you need a bunch of extra commands for working with the stash, when really they're just free-standing anonymous commits.
Or take branches. Branches are, as everyone knows, pointers to commits. So why is it important whether I'm checking out a branch or a commit? Why is one of these normal, but the other produces hideous warnings and looks like it loses me data if I haven't learned what a reflog is yet? And if a branch is just a pointer, why can't I move it around freely? I can push it forwards, but I can't move it to another arbitrary commit without fiddling around a lot. Why?
Or take tags, which are like branches, but they don't move. Is "moves" and "doesn't move" such a deeply important distinction that Git needs branches and two different kinds of tag?
---
To be clear, I think Git is a good tool, and I agree that once you've started to familiarise yourself with it, it's not so complicated in day-to-day usage. Yes, you'll probably need to Google a few specific commands every so often, but the general UX of the tool has significantly improved since the early days, and it is getting better.
That said, I also don't like the idea of settling with Git just because it's good. If there are alternatives out there that can do everything that Git can do, but with a simpler conceptual model, then I want to try them! (And, spoiler alert, I think there are better alternatives out there — in particular, I think Jujutsu is just as powerful as Git, if not more so, while simplifying and removing unnecessarily duplicated concepts.)
Interestingly that is exactly the opposite of my experience. Git is a practical tool with practical appeal to people who want to do practical things. Egghead gedankentheorists hate it, as evidenced by this very subthread.
In point of fact I find the ability to accomplish workaday tasks with git to be a far better predictor of someone's success as a developer than stuff like being able to recite Rust minutiae. People who like git are people who like getting stuff done.
You can switch branch also with ‘git checkout’ and you just ‘git stash’ your changes.
‘git reset’ is fine to reset files, but again if you just want to ”clean” repo you can stash.
You can reset staged files again with ‘git reset’
Mo idea why you would want to checkout a random commit and the start committing from that, but you can also just ‘git reset --hard HEAD~x’ where ‘x’ is number of commits you want to go back. Hard is optional, but I assume that is what you want based on your comment.
Depends on the change. If you change different lines there will be no conflicts.
This is all basic stuff you should know if you are developing code with other people
What a stupid series of sentences this is for a piece of software we have to use daily. Even talking about it feels cringe.
Whew, just from the intro this feels like a breath of fresh air. Probably gonna migrate to it right after finishing the tutorial. Thanks for mentioning!
if they're allowed to push somewhere and make it someone else's problem, that's not their fault
What? This made zeroest sense of the day. Like, I should walk to their desk and check if a feature branch is okay to push or what?
Here are some examples:
We have some repositories that are created and maintaned by scripts, mostly for CI purposes. The scripts have to deal with various aspects of how checkouts, commits, automatic rebases etc. are done. For example, I had to write a script that automates "git-rebase -i" (simulating the editor, parsing the contents of the file that git generates in order to configure the rebase etc.)
Another example: generating various statistics for the repository (again, automatically). This is something we used to do to analyze the situation with build servers: how many do we need, how to load-balance them etc.
Another example: automated builds, where the build system needs to integrate with Git, extracting necessary info, rebasing, committing, parsing commit messages for guidance etc.
> rsync
What I mean by this is that most programmers use Git as an append-only database. And, by and large, aren't bothered by the state of the history, never utilize the history for anything. As long as they are all able to access the source code in some sort of sane state, they are fine.
This creates a lot of problems for the automation / infra / release people because they want history to have certain properties, which are lost if it's treated as append-only log, but usually our pleas are ignored if they are even heard.
You can reset staged files again with ‘git reset’
To "revert a file to what was staged" you have to "git checkout" again, it seems, not "reset".
This is all basic stuff you should know if you are developing code with other people
Yeah. It seems that it is basic, until you try using it for something that is not quick one-shot patching of "append-only" code.
I used to work for a large company in the ops department, where a significant portion of my day was spent walking between cubicles and fixing the dev. environment of Intellij IDE programmers. Most of them didn't even know how to find the project they worked on in the filesystem w/o using their editor. The tantalizing task of opening a file with unknown extension was way too much to ask etc.
They would often mess up something in the version control too, using Intellij integration tools, which are really, really bad. But, I don't know whom to blame in this instance. Both the user and the tool were of extremely low quality.
So, if, eg. their Maven build had some sort of an interaction with Git, and they messed up something in their local repository, all work would come to a grinding halt, because they had no idea how to even begin to understand what went wrong.
It's a kind of job where you begin to lose faith in humanity very quickly :D
Though I have to say, for your examples (generating statistics and automated builds), read-only operations generally suffice for me, aside from pushing tags. I prefer to implement pull-based deployment if possible, and only allow release branches to fast-forward.
They are real commits, you can check them out (it detaches your HEAD, the syntax to reference them is `stash{N}`). Although I think this furthers, rather than undermining, your point that there are an unnecessary number of other commands to work with the stash.
I think this is a failure of the git CLI as much as the internal data-structures. I think the idea of a commit tree is very good and a lot of people recognize that. The commands that git exposes to work with that tree can sometimes be miserable.
And I completely agree that this is about the CLI more than the internal data structures. I pointed at Jujutsu earlier, and that uses Git as the underlying data store (at least in its default configuration). It's an effective strategy in large part because Git-as-a-data-structure works really well already, and the distributed aspect means you can interop very effectively with existing tools like Github just by speaking the right protocol.
But while it keeps much of the same data structures, Jujutsu exposes a very different interface to those data structures, and one that I think is significantly simpler in large part because there aren't so many special cases (such as commits vs staging vs stashes vs ...). You end up with a smaller set of commands, but those commands are more consistent and can be applied in more cases. And you still have staging and stashes, it's just that you can build those yourself more naturally out of the tools that Jujutsu gives you.
Right! People often forget git was designed specifically for Linux kernel development which is done by a loosely-knit global base of developers. There are much simpler solutions if you can actually live with exchanging USB sticks.
One nice thing is only needing to know one tool for both open source and centralised development, though. It can seem a little odd if you don't do any open source at all, though.
So really you can choose whatever suits your needs.
Personally the things I love about mercurial are:
more consistent commandline (that's the simple part others bring up)
revsets (awesome query language for revisions, there's also filesets, but I don't use that as much)
absorb (I think someone added a git extension that does something similar a few months ago)
fa --deleted
grep --all
phases ♥
yes, to understand an application, you must also understand the underlying data structures, architectures, models, use cases -- i am not sure what there's to roll eyes at. but there's no requirement that says that understanding has to be deep in order to work on it, or use it.
i think if you treat it like cleaning a large room, by picking out one corner at time and focusing on cleaning that before moving on, you'll find that the room is cleaned in no time, and git isn't anywhere nearly as complicated as it may feel.
there is absolutely no reason to digest a guide this dense for use-cases in every day production settings, bc those usages only make up about 10% of what this guide covers.
yes, learning things can be overwhelming, challenging, full of darkness and terrors, but that's what learning is, until you've learned.
but here is the catch imo: once you've learned, you don't stop learning and the challenges don't go away. you just become better at navigating the darkness, bc you get better at learning and managing feelings of overwhelm and confusion which are by products of complexity -- real or perceived or both.
jump in. it ain't that scary, even if it feels scary. i promise. i've been there, and you can overcome it.
This is just asking for trouble.