threads / discuss / 13301

Yet another Git tutorial

Subject: Yet another Git tutorial

## tl;dr

14 messages between Apr 28, 2008 and Apr 30, 2008.

replies: 13people: 10as markdown or json

John Wiegley· Apr 28, 2008, 06:39 UTC · lore

I published another tutorial on Git today, this one describing the system from a "bottom up" perspective. I know it's been written about this way before, but I was aiming at a bit more thoroughness, and a paced introduction to the basics.

There's a link to the PDF is in the following blog post:
   http://www.newartisans.com/blog_files/git.from.bottom.up.php
Thanks,
   John

p.s. My thanks to the folks on IRC who read it and gave comments, especially reuss, com4 and drewr.

Johan Herland· Apr 28, 2008, 09:27 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

On Monday 28 April 2008, John Wiegley wrote:
Show 8 quoted lines
> I published another tutorial on Git today, this one describing the  
> system from a "bottom up" perspective.  I know it's been written about  
> this way before, but I was aiming at a bit more thoroughness, and a  
> paced introduction to the basics.
> 
> There's a link to the PDF is in the following blog post:
> 
>    http://www.newartisans.com/blog_files/git.from.bottom.up.php
Some comments after a quick read-through:

(in general) In you examples, you are using the "git foo" notation, while you're using the "git-foo" notation when referring to git commands elsewhere in the text. This is probably OK; just be aware that the dashed form of the commands will disappear in a future git version.

(in general II) You mention "git prune" a couple of places. I think "git gc" is the command we encourage new users to use, so you might want to use that instead.

(p.2 (and p.19-20)) I think most people say "index" and not "index cache". In the git codebase, "index" and "cache" are often confused (I think Linus initially named it "cache"), but I think from a user perspective, we try to use the term "index".

(p.3) In the simple diagram, you show the 'checkout' activity as an arrow directly from 'Repository' to 'Working Tree'. What actually happens on checkout is copying the appropriate tree object into the index, and then applying the index onto the working tree. IOW if you want to be 100% correct the checkout arrow should go through the index. But this is only a minor issue; if you feel understanding is better conveyed by the existing diagram, please don't change.

(p.9) "But if I pass the -f flag to git-checkout, it becomes identical to git-reset --hard": In the context of the command above (resetting the working tree to 5f1bc85) there are in fact no difference between the two commands. However, in general, there is one crucial difference between "git reset --hard" and "git checkout -f": "git reset --hard" will rewrite which commit the current branch points at, whereas "git checkout -f" will not. (I see you treat this later in "To reset, or not to reset", but I think it should be fixed on p.9 as well.)

(p.10) In the diagram at the top, the arrow from the root tree object to HEAD commit is labelled "parent". I think this label rather belongs on the arrow from the HEAD commit to its parent.

(p.11) "name~10" Just to make things perfectly clear, I would state that "name~10" is equivalent to "name^^^^^^^^^^".

(p.11-12) This entire list is prefixed with "nam[ing] commits - and ranges of commits", so in a strict sense "name:file" and "name{tree}" does not belong here. But you have to put them somewhere...

(p.15) "Even the transformation from X to W is changed": I think this should be the other way around: "W to X".

(p.16) "For every commit this that involves conflicts": s/ this//? Also, in the preceding sentence, I'd prefer "...to its (now rewritten) parent commit" instead of the current "...to its (now) rewritten parent commit".

Otherwise, I think it's informative and well-written. Nice work.
Have fun! :)
...Johan
-- 
Johan Herland, <johan@herland.net>
www.herland.net
John Wiegley· Apr 28, 2008, 20:11 UTC · re: Johan Herland · lore

Re: Yet another Git tutorial

On Apr 28, 2008, at 5:27 AM, Johan Herland wrote:
> Some comments after a quick read-through:

My thanks to everyone for the excellent feedback! You've made some great points and I will try to incorporate them all during this week. I'll post to the list when a final version is available.

In the meantime, if you haven't sent edits yet, please do. I'm not sure if this tutorial should grow any further, or if -- as someone suggested -- I should just add a springboard note at the end linking to other articles, which do a fine job of introducing the user to typical usage scenarios. I guess it can't quite be called a "tutorial" if it never mentions the "clone" command. Perhaps calling it a "design intro" or "meta-tutorial" would be better.

John
Jeff King· Apr 28, 2008, 09:36 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

On Mon, Apr 28, 2008 at 02:39:46AM -0400, John Wiegley wrote:
> I published another tutorial on Git today, this one describing the
> system from a "bottom up" perspective.  I know it's been written about
> this way before, but I was aiming at a bit more thoroughness, and a
> paced introduction to the basics.

I like the "bottom up" approach as well (and in fact, I gave a similarly structured talk to some computer scientists a month or two ago). But I have seen some comments from some users that imply to me they prefer a "top down" approach.

So I'm curious: did you write this to show to some specific audience, and if so, how did the audience receive it? IOW, did they like the "bottom up" technique?

-Peff
Brian Gernhardt· Apr 28, 2008, 16:30 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

On Apr 28, 2008, at 2:39 AM, John Wiegley wrote:
> I published another tutorial on Git today, this one describing the  
> system from a "bottom up" perspective.  I know it's been written  
> about this way before, but I was aiming at a bit more thoroughness,  
> and a paced introduction to the basics.

Very interesting tutorial. Doesn't teach me anything, of course, but I've been using git for a good long time. But I'm going to save this and point it out to my technical friends who are interesting in git, as this does a better job of teaching them what it's actually doing "behind the scenes" than most tutorials I've seen.

That said, my comments:

(p.4) On my system, `echo "Hello, world\!" > greeting` puts the backslash into greeting, which in turn changes my SHA1. (Using bash 3.1.17.) Of course, leaving it out leaves an error. To avoid problems with different shells perhaps you should use something like:

$ cat > greeting <<EOF Hello, world! EOF

Of course, this issue could also be solved by leaving out the exclamation point, as long as you update the hashes of the objects from that point on.

(p.4-5) You determine the hash for your file as "af5626b4a114abcb82d63db7c8082c3c4756e51b", then use `git cat-file -t af5626b` to find it, and print the type. You should use this as an opportunity to mention the convenience of git expanding SHA1 abbreviations, rather than leave it implicit. In documentation, it's a good idea to never use something you haven't explained.

(p.5) Your reference to hand waving is unnecessary, as you defined HEAD in your lexicon on p.2. Reinforcing that your current commit is HEAD is fine, but the apology is unneeded and distracting. Perhaps something like: "If we want to see the contents of our commit, all we have to do is list the tree for HEAD (which always refers to the last commit on the current branch):"

(p.5) Instead of using `git rev-list HEAD | head -1`, you can also just use `git rev-list -1 HEAD`. And instead of that, what you really want to be using is `git rev-parse HEAD` since you're trying to convert HEAD to a SHA1, not get HEAD's history.

(p.7) I can't help but feel that telling the user to do `rm -fr *` is a bad plan. `rm -rf greeting .git` is better: It will remove all the files you've told them to create anyway, without causing huge headaches if they type it in the wrong terminal. Plus, removing and recreating the greeting file isn't really necessary, so why do it?

(p.8) Mentioning again that the commit SHA1 is going to be different would be a good idea. And at this point you should mention why: different authors and dates.

On Apr 28, 2008, at 5:27 AM, Johan Herland wrote:
Show 14 quoted lines
> (p.9) "But if I pass the -f flag to git-checkout, it becomes  
> identical to
> git-reset --hard": In the context of the command above (resetting the
> working tree to 5f1bc85) there are in fact no difference between the  
> two
> commands. However, in general, there is one crucial difference  
> between "git
> reset --hard" and "git checkout -f": "git reset --hard" will rewrite  
> which
> commit the current branch points at, whereas "git checkout -f" will  
> not.
> (I see you treat this later in "To reset, or not to reset", but I  
> think it
> should be fixed on p.9 as well.)

I really want to agree with this comment. `git reset --hard` and `git checkout -f` are not identical, and you shouldn't put that misconception into place. It may be enough to call them similar and say you will explain the difference later.

(p.10) Is there a particular reason why one blob is white and the others have a gradient? It makes that one square stand out for no apparent purpose.

On Apr 28, 2008, at 5:27 AM, Johan Herland wrote:
Show 5 quoted lines
> (p.11-12) This entire list is prefixed with "nam[ing] commits - and  
> ranges
> of commits", so in a strict sense "name:file" and "name{tree}" does  
> not
> belong here. But you have to put them somewhere...

Perhaps you should say: "There are many way to name objects -- commits, ranges of commits, trees, and blobs --"

(p.12) "name{tree}" should be "name^{tree}".

(p.12) "If either name1 or name2 may be omitted, HEAD is used in its place." This should be "If either name1 or name2 is omitted, HEAD is used in its place."

(p.12) You describe --author and --committer without describing why these may be different. You could introduce the difference when talking about rebase.

(p.12) I'd also add an example that mixes several of these options, just to demonstrate that it can be done. For example: `--no-merges -- grep="bug fix" --since="1 month ago"`. A sentence or two about using approximate dates and full dates would be nice as well.

(p.14) Spelling: "asterices" should be "asterisks". Your spelling may be considered technically correct but is not the common pluralization by any means. (And it threw me for a loop when I saw it.)

This is a good place to really learn the guts of Git. But as a tutorial, it lacks any description of how to do the D part of DVCS. Sections on pull/push, remotes, and patches would be useful for a new user. You could get a new user working on a copy of the git repo and sending a patch to the list in only a few pages describing clone, format-patch, and possibly send-email. If you were ambitious you could add the receiving side of dealing patches working up from apply to am. And of course, describing clone should also involve using init, remote, and pull.

But of course, there are other places to learn these things. At the least adding URLs to tutorials that do describe pull, pull, and patches would be nice ending.

~~ Brian
Paolo Bonzini· Apr 28, 2008, 16:40 UTC · re: Brian Gernhardt · lore

Re: Yet another Git tutorial

> (p.4) On my system, `echo "Hello, world\!" > greeting` puts the 
> backslash into greeting.  Of course, leaving it out leaves an error.
Using single quotes, as in `echo 'Hello, world!'`, should work fine.
Paolo
Brian Gernhardt· Apr 28, 2008, 16:42 UTC · re: Paolo Bonzini · lore

Re: Yet another Git tutorial

On Apr 28, 2008, at 12:40 PM, Paolo Bonzini wrote:
>> (p.4) On my system, `echo "Hello, world\!" > greeting` puts the  
>> backslash into greeting.  Of course, leaving it out leaves an error.
>
> Using single quotes, as in `echo 'Hello, world!'`, should work fine.
Of course, I forget this simple option.
~~ Brian
Bob Hiestand· Apr 28, 2008, 19:45 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

On Mon, Apr 28, 2008 at 1:39 AM, John Wiegley <johnw@newartisans.com> wrote:
>   http://www.newartisans.com/blog_files/git.from.bottom.up.php
  Under the section "Doing a mixed reset" you mention that "It doesn't
change the working tree, and it doesn't change any of
the repository's references."  However, doing a --mixed reset does
change your references, just not your working tree.
Thank you,
bob
Dmitry Potapov· Apr 28, 2008, 22:27 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

On Mon, Apr 28, 2008 at 02:39:46AM -0400, John Wiegley wrote:
Show 8 quoted lines
> I published another tutorial on Git today, this one describing the  
> system from a "bottom up" perspective.  I know it's been written about  
> this way before, but I was aiming at a bit more thoroughness, and a  
> paced introduction to the basics.
> 
> There's a link to the PDF is in the following blog post:
> 
>   http://www.newartisans.com/blog_files/git.from.bottom.up.php
In addition to what was mentioned before me:

On page 6, instead of `git show --pretty=format:%T HEAD | head -1`, it is better to use `git log -1 --pretty=format:'%T' HEAD`. In general, `git show <commit-object>` is `git log -1 -p <commit-object>`, and you do not need diff here.

On page 7:
> This blob doesn't live in a tree yet, nor are there any commits.

It is probably nit-picking, but blobs never live in trees. They may only be referenced by trees, while they always reside in 'objects'. At this point, the blob is already placed into 'objects', but it is not referenced by any tree, but only by index. So if you decide not to commit this file then this blob will become dangling.

On page 10:
> circles are commit objects, and all but the first link to one or more
> parent commits, thus forming a "history"

Though typically there is only one commit object in Git repository without a parent, it could be more than one.

> every commit holds a tree, and every tree must have at least one blob
> in its leaves

If there is no files in the current commit then the commit object will reference to an empty tree, i.e. without any blob in it.

On page 12:
> name1..name2
> 
> The syntax to the le refers to all the commits between name1
> and name2, inclusive.

Actually, inclusive name2 but excluding name1. IMHO, it is better to describe it as: `name1..name2` is a short-hand for `^name1 name2`, which is equivalent to `name2 --not name1`, i.e. all commits in name1 excluding those that are part of name2.

Show 5 quoted lines
> name1...name2
> 
> For example, if you had two development branches, "foo" and
> "bar", you could show all the commits which had happened on
> bar since their common ancestor using this command:

Not true. It shows all commits on both "foo" and "bar" that's happened since their common ancestors. In other words, `name1...name2` is equivalent to `name1 name2 --not $(git-merge-base --all name1 name2)`. The '--all' flag means to consider their all ancestors, not just first one.

BTW, maybe it would be useful to mention `git log -S<string>` somewhere as a better alternative to `git blame`, because people with CVS/SVN background tend to abuse `git blame` while `git log -S` is usually more convenient and more efficient.

Dmitry
Junio C Hamano· Apr 28, 2008, 23:34 UTC · re: Dmitry Potapov · lore

Re: Yet another Git tutorial

Dmitry Potapov <dpotapov@gmail.com> writes:
Show 16 quoted lines
> On Mon, Apr 28, 2008 at 02:39:46AM -0400, John Wiegley wrote:
>> I published another tutorial on Git today, this one describing the  
>> system from a "bottom up" perspective.  I know it's been written about  
>> this way before, but I was aiming at a bit more thoroughness, and a  
>> paced introduction to the basics.
>> 
>> There's a link to the PDF is in the following blog post:
>> 
>>   http://www.newartisans.com/blog_files/git.from.bottom.up.php
>
> In addition to what was mentioned before me:
>
> On page 6, instead of `git show --pretty=format:%T HEAD | head -1`, it
> is better to use `git log -1 --pretty=format:'%T' HEAD`. In general,
> `git show <commit-object>` is `git log -1 -p <commit-object>`, and
> you do not need diff here.

I may be misunderstanding what the discussion is about as I was not following the thread, but is this a contest to find the most expensive way to spell "git rev-parse HEAD^{tree}"?

Junio C Hamano· Apr 29, 2008, 00:17 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

Page #5; after teaching "cat-file -t" it would make sense to teach "cat-file blob" to view what was stored.

Page #5; likewise, "cat-file -t HEAD" to inspect and "cat-file commit HEAD" to show its contents would be a much better "bottom-up" way to show how the pieces fit together, instead of doing "show --pretty=format:%T".

Page #6; "HEAD tag"???

Page #6; s/my system/my repository/, as you use that word a few lines later.

You use "id", "hash id", "hash number", "hash" etc. and have your readers guess that you are talking about the same thing. It would be better to use a single word consistently (the official name of this number is the "object name").

s/index cache/the index/.
s/tree owns blob/tree holds blob/, perhaps.

Page #9; before this point, your tree owned blobs but now suddenly it references trees and blobs. There should be a mention of this recursive construction of a tree earlier soon after you introduced the tree objects.

Page #11: s/name:file/name:path/; notice that it can be non-files such as symlinks and trees.

Page #12: s/name{tree}/name^{tree}/.

Page #12: name1..name2; "between name1 and name2, inclusive"? This excludes the left end. "Everything reachable from name2 except the ones reachable from name1".

Page #12: name1...name2. This is a symmetric difference for "git log" family of commands (iow when you talk about set of commits) which means "Reachable either from name1 or name2 but not from both". When used with "git diff" to name two endpoints, this means what you described (differences since the common ancestor of these two to name2).

Page #12: master..; it would also be useful to mention ..other here.

Page #17: The example makes me wonder what you did exactly to commit I. It would contain roughly an equivalent of squashed B+C together, which may or may not be what you want.

Page #18: There is no "two different things" reason behind the name. It was originally called "directory cache" and then renamed to "the index". These days, most of the time we use these two words interchangeably, but when we are picky, index tends to mean the file on the filesystem (i.e. $GIT_INDEX_FILE aka $GIT_DIR/index) while cache tends to mean the in-core structure (i.e. the_index.cache aka active_cache).

Page #22: "git reset --mixed" will remove blobs??? You surely did not mean that. It just reverts the staged contents to that of the HEAD (or whichever commit you named and moved your HEAD to).

Page #24: saves your work in the stash "for the current branch"??? There is no per-branch stash. You can stash, switch branches and then apply the stashed change to the other branch.

Matt Graham· Apr 29, 2008, 01:25 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

On Mon, Apr 28, 2008 at 2:39 AM, John Wiegley <johnw@newartisans.com> wrote:
Show 8 quoted lines
> I published another tutorial on Git today, this one describing the system
> from a "bottom up" perspective.  I know it's been written about this way
> before, but I was aiming at a bit more thoroughness, and a paced
> introduction to the basics.
>
>  There's a link to the PDF is in the following blog post:
>
>   http://www.newartisans.com/blog_files/git.from.bottom.up.php

The arrows in your diagrams go the opposite way I expected, but I might have been execting the wrong thing.

John Wiegley· Apr 30, 2008, 01:40 UTC · re: Matt Graham · lore

Re: Yet another Git tutorial

I've applied nearly everyone's corrections and uploaded the new version of the PDF. Thanks again to everyone for such conscientious reading!

   http://www.newartisans.com/blog_files/git.from.bottom.up.php
John
Robert Haines· Apr 30, 2008, 23:17 UTC · re: John Wiegley · lore

Re: Yet another Git tutorial

John Wiegley wrote:
> I've applied nearly everyone's corrections and uploaded the new version 
> of the PDF.  Thanks again to everyone for such conscientious reading!
> 
>   http://www.newartisans.com/blog_files/git.from.bottom.up.php

Very good tutorial. I'm working through it to fill in gaps in my git knowledge (of which there are many - stash for instance, very cool).

On page 5 your second git cat-file example is incorrect I think. It should be: $ git cat-file blob af5626b

i.e. you're missing the "blob" bit!

Cheers, Rob

← back to recent threads