Maybe I am biased because I did a CS degree, but I don't think so. Using the word DAG sure requires having heard of it, which a CS degree would give you, fair enough. I don't think that word is needed, nor most (any I would argue) of the things you learn about DAGs while doing a CS degree. I definitely forgot most of that by now because I never needed it again.

If you ask me, there's very little actual git to grok. Version control existed before git and many of the same things applied for "grokking" it. It just so happened that the implementations of other systems were worse and made certain operations expensive and error or conflict prone, while in git they're easy, safe and fast. Lots of developers have always been "bad" at version control and in some places I've been there was an entire team of people that did nothing but resolve merge conflicts (stupid idea if you ask me but hey).

Version control 101: It's just a graph of commits.

If it helps, think of it like a tree in the park or your yard. Just that trees don't have branches growing back into the trunk but if you only ever rebase without merging that's actually what your commit graph looks like.

What personally made me realize how git is so awesome is that it's all just labels. This is where some of the implementation details do come in but you don't need to go deeper than realizing that a branch is nothing but a label, not special or different from the main branch at all. You can freely relabel the graph any way you want. Think of the tree in your yard and buy a label-maker. Attach a label to the top of the trunk with `master` on it. Every few inches on the trunk imagine a commit (with a hash identifying it, on an actual tree, use the number of inches it's away from the ground). Where a branch goes off, do the same thing, tip of the branch gets a label. All operations in git you can imagine as using a saw and wood glue and your label maker now.

More implementation detail: go to the `.git` folder and take a look around. You can see this in action right there. Ignore the binary blobs part. Look at the other files and you see that each of the labels in the graph is just a file w/ the exact name of the label and the contents is nothing but the commit hash that the label is stuck to. It doesn't get easier than that. Now you know how to move labels around in the graph without even using git commands! Any old editor works but I recommend `vi`. Try it!

Remotes are easy as well. They're just another source of labels. You have your own set of labels locally (and don't need a server) and remotes allow you to see other people's sets of labels. By default most people probably only have one other set of labels, which is where they cloned stuff from, but you can set up any number of remotes and see any other person's personal set of labels and have a copy of it on your local machine. Think of it as your neighbour coming over with his own label maker. He's also brought some branches from his tree and started gluing them to your trunk ;)

`git fetch` just retrieves the latest copy of labels from a remote including any commits that are not present on your end yet. `git push` pushes your opinion of what the labels should be to a remote, including any actual commits that are not present on the other side yet. The remote can reject that because it thinks it knows better (i.e. only allowing fast-forwards). This is where the analogy falls apart a bit because it's hard to make copies of commits (parts of your tree you sawed out) but imagine you could walk over to your neighbour and give them a copy of parts of your tree just like they gave you parts of theirs.

Fast-forwards are also relatively easy to explain I think. It's nothing other than only allowing labels to be pushed along a path on the graph instead of freely moving labels around. For that to work, both you and the remote have to agree on what the graph looks like for this to be possible. Otherwise what looks like a pushing along of the label for you is pulling a label off a branch "somewhere over there on the tree" and sticking it onto a part of the trunk.

`git pull` is just a combination of fetching and rebasing/merging to deal with the fact that the commits and labeling on the remote side may have incompatibly changed vs. what you have. It's a way to resolve those conflicts. Personally I like the rebasing version of resolving them, because it results in an easy to read and follow straight line commit history.

I have yet to loose anything with git and there's one (and a half) rule that has helped me with that: before you do anything, always commit. The half rule is to always use the terminal/command line to interact with git and keep it open at all time. If you create a commit before trying to manipulate the tree, it's very hard to loose anything. You can always go back to that commit. Heck, if you happen to relabel your graph incorrectly and "lost" your commit you very probably have the commit hash of the lost part of your graph still in your terminal output. Just find it and stick a label on it. There, "recovered". In live tree analogy, branches you took all labels off of are still there. As long as you can find it you can stick a label on it again. When you were sawing and gluing you just let the parts/copies you didn't need any longer fall to the ground. They're also still there in a messy pile until you clean up. `git gc` cleans up the ground and automatically saws off and burns any branch tips that don't have a label.

You made a big boo boo while rebasing something and having lots of conflicts? Just abort the rebase and try again w/ the knowledge you gained during the first conflict resolution round. W/ something like SVN you're SOL unless you made a copy the repo, which you probably didn't do because making that copy takes 15 minutes because of all the small files. Or you have 17 copies lying around.

Rebasing is where I think most people have difficulty but I think very little deeper understanding is needed, not to get into trouble. I.e. the implementation details of how git does it so well are not important to be able to work with it efficiently and without destroying things in most situations you will encounter at work. Rebasing is nothing but taking a branch off the graph and attaching it somewhere else. In the live tree analogy you saw off a branch somewhere on the bottom and then you re-attach it somewhere else on the trunk. That's basically it. If your branch was long lived, it's a very thick and heavy branch. If you try to attach it at the top of the trunk you'll likely have problems (conflicts). If you had a short lived branch (or it was only making changes to parts of the code that seldom change) you can easily attach it without conflicts. There are some special scenarios here depending on how you work and branch where you may be able to solve conflicts very easily by skipping commits, which feels like loosing something - and you can if you skip the wrong commits and don't know a commit hash to recover things like mentioned above. I admit, this can be a bit hard to understand and it helps to see it visually. It's also not needed if you don't get yourself into this situation in the first place. In the analogy of the live tree, while trying to attach your sawed off branch to the trunk you notice that the lower parts of your branch look exactly like parts of the trunk already. So you saw your branch in half and attach only the top part.