6 ms·
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 manipul
by doix 4y ago
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.
- spencerchubb 4y agoNow I just have to learn what a DAG is
- doix 4y agoMy 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 :).
- paulgb 4y agoacyclic, not acrylic ;)
- beaker52 4y agoBob Ross enters the chat
- TYPE_FASTER 4y ago"and over here, we'll add a few happy little change sets"
- aynyc 4y agoGod 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
- radicalbyte 4y agoThis: 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 :-)
- tharkun__ 4y agoMaybe 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.
- worldsayshi 4y agoI 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.
- cjfd 4y agoNodes are states of indeed "all of the code". Edges are commits. The "all of the code" thing does sound expensive but it actually is not because git does massive caching. That is what all of the directories in .git/objects are about.
- kbr- 4y agoOn a high level, it is "all of the code" in each commit. Node = commit (= all files + some metadata). Edge = pointer to a parent. On a lower level, a commit is itself a bunch of pointers to files. Different commits can share files. Think about copy-on-write.
- kreetx 4y agoGit essentially shares common files & folders. I.e if you change contents of one file in root folder, then a newly created commit would point to a tree that points to this new file and to all the sibling files and folders which git shares with all other commits.
- AndrewDucker 4y agoIt's not 'all the code', it's the directory info, and links to every file, the vast majority of both of which will already be in the repo.
- djtango 4y agoMy mental model is each edge is a diff and each node is the aggregate of all edges + the starting state
- mattbrewsbytes 4y agoI believe the latest commit in a branch is "all the code" and prior commits are reverse diffs internally. So more branches and commits doesn't make a repository grow exponentially or anything like that. I'm talking about code/text here, I have no idea if this works as efficient for binaries.
- kbr- 4y agoThis model doesn't cover the staging area though.
- informalo 4y agoMy basic understanding - Untracked: Files that Git doesn't know about. - Tracked: Files that Git knows about. Further divided into unstaged files (will not be part of the next commit) and staged files (will be part of the next commit). What helped me here was to know that it's possible to track a (yet untracked) file without staging it: git add --intent-to-add <path>
- doix 4y agoYeah, it also doesn't cover remotes and the decentralised model of git. I do think understanding that it's a graph is the first step to grokking git though. The other stuff makes more sense after that (at least in my experience).
- tgaj 4y agoI think is healthy to think about staging area as something outside main git model. It's like helpful tool but separate from git repository.
- globular-toast 4y agoBut note that git's data store (the bit where actual code/content is kept) is fundamentally append only. You can't manipulate anything there. You can only add different versions. The only pointers you can actually change are branches and HEAD. This is really, really important to understanding git and actually trusting it to keep your work safe.
- alisonatwork 4y agoI 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.