Live data from Hacker News

Ask HN: What made you finally grok Git?

news.ycombinator.com

61–70 of 94 posts

Re: Ask HN: What made you finally grok Git?

#61
post #17

Earlier quoted context omitted.

Now I just have to learn what a DAG is

My bad, stands for directed (not acrylic) acyclic graph, which is just a fancy way saying a graph with no loops. Edit: yeah, it's acyclic not acrylic :).

God damn it. I just amazon'd some fancy acrylic paper and wonder how that would help me learn git. You owe me $6.99 + tax. /s

Re: Ask HN: What made you finally grok Git?

#63
post #5

When I realized it's just a DAG and you're just manipulating a graph and pointers. Then it just became a matter of mapping git CLI commands to how they manipulate the graph.

I still don't fully understand what the nodes and edges in this graph "is" though. It's not patches. And I can't believe it is "all of the code" in each commit because that sounds very expensive.

I think the confusion is caused by mixing two things - abstract model of git repository where edges are just deltas between images of file system and implementation where this is all optimized. But you don't have to think about implementation when working with git, just abstract model should be enough most of the times. Sure, you have to think about particular implementation of git when for example getting rid of large files in repository

Re: Ask HN: What made you finally grok Git?

#64
It's super easy to understand how git works — I'm doing it several times per month.

Seriously, low-level git, while not familiar to most devs, is logical and consistent. It's the UI level that is total disaster. Don't worry, you will forget everything in a week.

Re: Ask HN: What made you finally grok Git?

#65
post #39
post #5

When I realized it's just a DAG and you're just manipulating a graph and pointers. Then it just became a matter of mapping git CLI commands to how they manipulate the graph.

This model doesn't cover the staging area though.

I think is healthy to think about staging area as something outside main git model. It's like helpful tool but separate from git repository.

Re: Ask HN: What made you finally grok Git?

#66

Git from the bottom up. A very clear and simple guide to the internals. https://jwiegley.github.io/git-from-the-bottom-up/

This is a great recommendation.

Concise, grounded posts that focus on the "behind the scenes" of git. After reading this I felt a much more grounded understanding of git.

I don't recall if it's explicitly covered in there, but because I'd read this I understood things like what happens to my commits after I "delete" them (e.g. remove the last reference to them / hard reset to an old commit, etc).

Re: Ask HN: What made you finally grok Git?

#67
I started using it around 2008 on the recommendation of a co-worker. I already had a lot of experience with RCS, CVS, and SVN. I understood the problems and frustrations caused by those tools, because I suffered with them for years. After reading the Git documentation I immediately understood how Git solved those problems. Then I just started using it exclusively. The end.

Re: Ask HN: What made you finally grok Git?

#68
post #5

When I realized it's just a DAG and you're just manipulating a graph and pointers. Then it just became a matter of mapping git CLI commands to how they manipulate the graph.

This: my introduction to git involved reading an architectural overview. From that it was obvious that it was a DAG. About an hour of playing with the operations (particularly rebase!) was enough. Just goes to show the power of understanding the fundamentals of CS :-)

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.

Re: Ask HN: What made you finally grok Git?

#69
post #5

When I realized it's just a DAG and you're just manipulating a graph and pointers. Then it just became a matter of mapping git CLI commands to how they manipulate the graph.

I think this is a really compsci major way of saying every "branch" is just a stack of patches on top of whatever you started from. So "rebase" is just you reapplying your patches from a new start point. Perhaps that's what you mean by "DAG"? But for someone who used to work with patch sets against trunk in the old pre-git days, it's easier to think about it all as just a bunch of patches.

Personally I think the most difficult part of git to understand is merges. I get doing the final merge to master in the pull request model, but people merging branches willy nilly is something I find unnecessarily confusing and would prefer git didn't support at all.

Re: Ask HN: What made you finally grok Git?

#70
post #59

Earlier quoted context omitted.

I just ran into this problem last night... if you shouldn't rebase after pushing to remote, how do you update a PR days after you originally created it to be on top of the latest origin/master and be able to resolve merge conflicts locally?

You do that by merging. For people who love a clean, linear history, this can be frustrating, because it creates a new commit that doesn't add anything new, it just merges two branches. At my current project, PRs get merged very slowly, and after every PR gets merged, we merge master back into all the branches, which has lead to a ridiculous number of merge commits, and the guy who loves clean history won't stop comp…

It seems like a lot of headaches could be avoided if you just don’t have people share branches. Then you just rebase master and force push away with reckless abandon,
Post reply on HN