Hacker News new | past | comments | ask | show | jobs | submit login
A visual Git reference (marklodato.github.com)
238 points by dennis_vartan on June 27, 2012 | hide | past | favorite | 34 comments



This 'reference' is, at best, full of inaccuracies and incorrect terminology, with diagrams that are overly complicated and ridiculous. For example: http://marklodato.github.com/visual-git-guide/merge.svg. What the fuck?

This guide will only make your understanding of Git worse.

It uses incorrect terminology to mislead what Git is actually doing in a number of situations, starting with the first sentence of the first section: The four commands above copy files between the working directory, the stage (also called the index), and the history (in the form of commits).

Git doesn't care about files, but changesets so this should raise a red flag with anyone with even a passing knowledge of how Git works. This is either a fundamental flaw in the understanding of how Git works by the OP or intentionally misleading wording.

In the Commit section, the OP writes: It then points the current branch to this new commit. I don't like this wording because it makes it seem like a branch is something other than a reference to a particular commit (which is available in .git/refs/heads). Really, any reference to "current branch" should be replaced by HEAD, because the current branch is nothing other than HEAD, and HEAD of course is just a commit.

In the Checkout section, the OP writes: The checkout command is used to copy files from the history (or stage) to the working directory, and to optionally switch branches. This is blatantly false. `git checkout` doesn't "copy files"; it may move HEAD or it may get rid of any changes in the working directory, and in doing so may change the state of the files within the local repo.

In the Committing with a Detached HEAD section, the OP writes: Once you check out something else, say master, the commit is (presumably) no longer referenced by anything else, and gets lost. This is only partly true. The commit still remains in the reflog and can be retrieved up to the point that garbage collection is run. It's incorrect to tell someone their commits are lost as soon as they `git checkout` another treeish.

This guide should be binned in favor of EdgeCase's Git Immersion (http://gitimmersion.com/) and Scott Chacon's Pro Git (http://www.git-scm.com/book).


> Git doesn't care about files, but changesets

Git's first class objects are files, trees and commits. Changesets are never stored, only derived. Git stores snapshots, not changesets. So your statement seems to be a complete contradiction to what Git actually does.

> This guide will only make your understanding of Git worse.

I am so shocked by your assertion about git and changesets that I don't know how to begin to respond to this.


Git's first class objects are objects, which you can see on disk: `find .git/objects -type f | head`. These objects represent one of three things: blobs, trees, and commits, wherein a commit is one or more trees, and a tree is one or more blobs and trees.

The statement I quoted when I mentioned changesets was talking about copying files between the working directory and the index, which is certainly not the case. What gets added to the index is the collection of trees and blobs that will make up the next commit when it is created. I mean changeset to be the collection of trees and blobs that will make up the commit. There is no "copying" of files here.


Perhaps you (or someone else with a better understanding of git) can fork https://github.com/MarkLodato/visual-git-guide and clean it up then.

I think that it would be interesting to reread this after it's been worked over by someone to better represent the way that Git actually works.


The thing is, I don't think it's necessary. This guide doesn't aim to add anything that Pro Git or Git Immersion don't already provide. I've tried to avoid adding additional noise to the mountains of Git documentation out there unless I feel there's real value being added, which I hope is the case with my own series of Git-related blog posts (http://pivotallabs.com/users/khicks/blog).


Agree with your amends to op but not with your last point. This article has flaws but has some good parts. If corrected it could be useful for users with some experience of git but want a deeper understanding, and have no patience for a very detailed textbook.


I disagree on most of your points.

> Git doesn't care about files, but changesets so this should raise a red flag with anyone with even a passing knowledge of how Git works. This is either a fundamental flaw in the understanding of how Git works by the OP or intentionally misleading wording.

Git absolutely cares about files. It cares about commits too, but a commit is mostly just a set of files with a pointer to its parent. The commands being discussed operate on individual files except for commit, which operates on the entire index (which is, conceptually, a snapshot of file).

> In the Commit section, the OP writes: It then points the current branch to this new commit. I don't like this wording because it makes it seem like a branch is something other than a reference to a particular commit (which is available in .git/refs/heads). Really, any reference to "current branch" should be replaced by HEAD, because the current branch is nothing other than HEAD, and HEAD of course is just a commit.

I don't understand your objection to this phrasing. A branch is a pointer to a commit; the statement talks about changing which commit the branch points to. I don't see where it implies anything else about what a branch is. As for "current branch"/"HEAD", using HEAD is more precise in terms of the actual implementation, but "current branch" is just as accurate and more (new-)user friendly. The author does discuss the relationship between the two prior to that point: "The current branch is identified by the special reference HEAD, which is "attached" to that branch."

> In the Checkout section, the OP writes: The checkout command is used to copy files from the history (or stage) to the working directory, and to optionally switch branches. This is blatantly false. `git checkout` doesn't "copy files"; it may move HEAD or it may get rid of any changes in the working directory, and in doing so may change the state of the files within the local repo.

When used as "git checkout <ref>", this is correct, but that is not what the author is talking about. "git checkout <ref> <file>" or "git checkout -- <file>" does exactly what the author describes, copying files from the given commit or index to the working directory.

> In the Committing with a Detached HEAD section, the OP writes: Once you check out something else, say master, the commit is (presumably) no longer referenced by anything else, and gets lost. This is only partly true. The commit still remains in the reflog and can be retrieved up to the point that garbage collection is run. It's incorrect to tell someone their commits are lost as soon as they `git checkout` another treeish.

Only partly true, but true enough. The commit isn't irretrievably lost, but the reflog falls more under "advanced usage"; certainly a git beginner shouldn't be making detached commits and relying on the reflog to get back to them.


> Git absolutely cares about files.

In a sense. A commit is not a set of files, it is one or more blobs and one or more trees (which may in turn point to one or more blobs or trees.) A blob does refer to a file, both in content and location, but it's the blob that matters. The OP speaks of the files on disk, which Git doesn't copy around. Git does, however, change the state of the working directory to that which matches the trees referenced in the commit. What I don't like about this is that it tries to make it seem like the files on disk matter in a way that they don't from Git's perspective.

> I don't understand your objection to this phrasing.

I had a chat with a coworker and he agreed that my distaste with the "current branch" terminology is perhaps misplaced.

> When used as "git checkout <ref>", this is correct, but that is not what the author is talking about. "git checkout <ref> <file>" or "git checkout -- <file>" does exactly what the author describes, copying files from the given commit or index to the working directory.

Of course, the files that are being copied are not the files that the OP is talking about. The files being copied are the trees and blobs, not the files in the working directory. The effective result is the same, but thinking in files on disk will not improve one's knowledge of Git.

> Only partly true, but true enough. The commit isn't irretrievably lost, but the reflog falls more under "advanced usage"; certainly a git beginner shouldn't be making detached commits and relying on the reflog to get back to them.

Shunning the reflog doesn't do anyone any good. The OP not even mentioning the reflog is in poor taste, and makes the statement in the guide untrue.

I did a bit of research into the reflog after some questions arose and should update my prior comment about it to say: Any commit that Git determines to be unreachable (a list of which that you can see with `git fsck --unreachable`) will only be removed from the reflog after both the reflog's unreachable expiration time has passed (by default, 30 days for unreachable) and `git gc` has ran. At the very least, without mentioning the reflog, the OP should state that unreachable commits will remain for 30 days.


Awesome! Very clear and well-written reference.

I wish someone would make a reference like this for remote branches and repos, I always keep forgetting commands for setting upstream branches, checking out remote branches and having them tracked, etc.


Very nice set of diagrams.

But every time I see something this I have to ask myself again why I'm just not using CVS (or SVN, i.e. a simpler tool).


Because experience shows that on any sufficiently long-running project, you're going to need some of the power that CVS/SVN don't have.


You're wrong, git is simpler. I mean it has a simpler architecture, a simpler foundation. This simpler architecture means some changes in your habits and, because it is a new tool, an interface that is a bit rough on the edges.


Git simpler? I really don't see how. SVN is focused on having one branch, canonical copy on the server, and you have two big buttons to pull down the newest updates to your copy and also to put your own updates into the master.


That seems intuitive because you're used to such a workflow. As someone who started out with git and then learnt about SVN, I found the non-distributed approach somewhat puzzling and limiting.


I've used git much more than SVN. SVN's model is definitely limiting but it's very simple.


I was going to point you to http://whygitisbetterthanx.com/, but it seems to have been replaced with http://git-scm.com/about/.


My opinion in the svn vs git debate:

Unless you are working across multiple groups with developers in different time zones and a choppy set of releases you'll see almost no benefit from git.

However, if you are in that situation the benefits are large and immediate.


Well, if you enjoy 'log' pulling info over the network (slowly), .svn in every single folder, barely useable branching, no reabase, no stach, no… well maybe you have the point. Otherwise not even comparable. When I first saw Linus' talk on git where he was very harsh toward SVN uers I thought "WTF". Then I tried git and had to admit that the man was right.


Since Subversion 1.7 (2nd half of 2011) it keeps only one .svn folder in the root folder.


Even when working on my own, I get a massive benefit from git. I think people end up being very polarised here.

The biggest benefit I get is that I can work on a set of changes as a set rather than a linear sequence that only ever goes forwards in time. I use microcommits. As I make progress on a feature, I discover necessary refactoring that I would ideally have been done before I started to add the feature. Interactive rebase allows me to make this so, and the result is that when I am done I can review my own work and check it for correctness with much more confidence than otherwise.

When working in open source, you're expected to provide a patch series for easy review. Git lets me produce such a thing with the same workflow.

Developers who don't wish to work this way, or are unaware of the benefits that this can bring, use git linearly and will see no benefit over Subversion.


I love git even for personal single-developer projects.


I do too. I'm just saying the smaller the project the more the benefits tend to lean towards personal preference over empirical evidence.


I think eliminating the need to set up a SVN repository for very small projects is a major boon.


Local commits and huge speed increases are some of the immediately available, tangible benefits of git over SVN.

Plus, you don't have to migrate your codebase to another SCM tool if the project unexpectedly grows into a larger one.


well in my case it's because SVN branches are useless. I still find mercurial much easier to use than git though.


Excellent stuff. Maybe one quick feedback would be to show actual terminal examples to complement what's in the paragraphs.


A nice example that good tech reference doesn't need much stylistic formatting :)


This is cool, but every diagram I've seen for git history uses arrows pointing to the past instead of the future, which is a bit confusing.


It represents the actual way commits are represented. Past commits cannot be modified to add children (this would change their hashes) so new commits contain references to parents. Changing this in diagrams would create even greater confusion later on.


The arrows do not represent time. Instead, they reflect the way git represents the commits internally. Each commit is a set of changes to some starting state, identified by the arrow. You could think of it like a citation in a paper that mentions and then extends some earlier findings.


Just think of it as a commit having a pointer to its parent.


This, in addition to knowing that a commit may have multiple parents (a merge commit, for example).


kisielk got it right, but to add:

A commit knows about its history via its parent(s), thus the arrow pointing to the parent. As far as I know no commit can (or for that matter should) know about its descendants.

Does that help?


Not cool, or even HN worthy, it's just good documentation (assuming it's accurate). Tech writers (assuming they're good) can help a lot.




Consider applying for YC's Spring batch! Applications are open till Feb 11.

Guidelines | FAQ | Lists | API | Security | Legal | Apply to YC | Contact

Search: