Browse Source

Reorganize the tutorial. This kills some of the duplication and
fixes the testsuite to test all chapters.

It also adds a note in the conclusion indicating that the tutorial only
covers a part of Dulwich' functionality.

Jelmer Vernooij 14 years ago
parent
commit
a383e4501a

+ 1 - 0
.bzrignore

@@ -5,3 +5,4 @@ dist
 apidocs
 apidocs
 *,cover
 *,cover
 .testrepository
 .testrepository
+docs/tutorial/index.html

+ 2 - 0
AUTHORS

@@ -3,4 +3,6 @@ James Westby <jw+debian@jameswestby.net>
 John Carr <john.carr@unrouted.co.uk>
 John Carr <john.carr@unrouted.co.uk>
 Dave Borowitz <dborowitz@google.com>
 Dave Borowitz <dborowitz@google.com>
 
 
+Hervé Cauwelier <herve@itaapy.com> wrote the original tutorial.
+
 See the revision history for a full list of contributors.
 See the revision history for a full list of contributors.

+ 5 - 0
NEWS

@@ -16,8 +16,13 @@
   * Support parsing git mbox patches without a version tail, as generated by
   * Support parsing git mbox patches without a version tail, as generated by
     Mercurial.  (Jelmer Vernooij)
     Mercurial.  (Jelmer Vernooij)
 
 
+ DOCUMENTATION
+
   * Run the tutorial inside the test suite. (Jelmer Vernooij)
   * Run the tutorial inside the test suite. (Jelmer Vernooij)
 
 
+  * Reorganized the tutorial. (Jelmer Vernooij)
+
+
 0.6.2	2010-10-16
 0.6.2	2010-10-16
 
 
  BUG FIXES
  BUG FIXES

+ 10 - 9
docs/tutorial/0-introduction.txt

@@ -45,16 +45,16 @@ tree.
 The Tree
 The Tree
 --------
 --------
 
 
-A tree is a collection of file information, the state of your working copy at
+A tree is a collection of file information, the state of a single directory at
 a given point in time.
 a given point in time.
 
 
 A tree file looks like this::
 A tree file looks like this::
 
 
-  tree <content length><NUL><file mode> <filename><NUL><blob sha>...
+  tree <content length><NUL><file mode> <filename><NUL><item sha>...
 
 
 And repeats for every file in the tree.
 And repeats for every file in the tree.
 
 
-Note that for a unknown reason, the SHA-1 digest is in binary form here.
+Note that the SHA-1 digest is in binary form here.
 
 
 The file mode is like the octal argument you could give to the ``chmod``
 The file mode is like the octal argument you could give to the ``chmod``
 command.  Except it is in extended form to tell regular files from
 command.  Except it is in extended form to tell regular files from
@@ -88,14 +88,15 @@ accelerate operations and reduce space.
 More About Git formats
 More About Git formats
 ----------------------
 ----------------------
 
 
-These three objects make 90 % of a Git repository. The rest is branch
-information and optimizations.
+These three objects make up most of the contents of a Git repository and are
+used for the history. They can either appear as simple files on disk (one file
+per object) or in a ``pack`` file, which is a container for a number of these
+objects.
 
 
-For instance there is an index of the current state of the working copy.
-There are also pack files to group several small objects in a single indexed
-file.
+The is also an index of the current state of the working copy in the
+repository as well as files to track the existing branches and tags.
 
 
-For a more detailled explanation of object formats and SHA-1 digests, see:
+For a more detailed explanation of object formats and SHA-1 digests, see:
 http://www-cs-students.stanford.edu/~blynn/gitmagic/ch08.html
 http://www-cs-students.stanford.edu/~blynn/gitmagic/ch08.html
 
 
 Just note that recent versions of Git compress object files using zlib.
 Just note that recent versions of Git compress object files using zlib.

+ 28 - 0
docs/tutorial/1-repo.txt

@@ -0,0 +1,28 @@
+The Repository
+==============
+
+After this introduction, let's start directly with code::
+
+  >>> from dulwich.repo import Repo
+
+The access to a repository is through the Repo object. You can open an
+existing repository or you can create a new one. There are two types of Git
+repositories:
+
+  Regular Repositories -- They are the ones you create using ``git init`` and
+  you daily use. They contain a ``.git`` folder.
+
+  Bare Repositories -- There is not ".git" folder. The top-level folder
+  contains itself the "branches", "hooks"... folders. These are used for
+  published repositories (mirrors). They do not have a working tree.
+
+Let's create a folder and turn it into a repository, like ``git init`` would::
+
+  >>> from os import mkdir
+  >>> mkdir("myrepo")
+  >>> repo = Repo.init("myrepo")
+  >>> repo
+  <Repo at 'myrepo'>
+
+You can already look a the structure of the "myrepo/.git" folder, though it
+is mostly empty for now.

+ 0 - 88
docs/tutorial/2-change-file.txt

@@ -1,88 +0,0 @@
-Changing a File and Commit it
-=============================
-
-Now we have a first commit, the next one will show a difference.
-
-As seen in the introduction, it's about making a path in a tree point to a
-new blob. The old blob will remain to compute the diff. The tree is altered
-and the new commit'task is to point to this new version.
-
-In the following examples, we will need a ``repo`` and an initial commit
-(``c1``) similar to the one made in the previous chapter::
-
-  >>> from dulwich.repo import Repo
-  >>> from dulwich.objects import Blob, Tree
-  >>> repo = Repo.init("myrepo", mkdir=True)
-  >>> blob = Blob.from_string("My file content\n")
-  >>> tree = Tree()
-  >>> tree.add(0100644, "spam", blob.id)
-  >>> repo.object_store.add_object(blob)
-  >>> repo.object_store.add_object(tree)
-  >>> c1_id = repo.do_commit("Initial commit.",
-  ...     committer="JaneExample <jane@example.com>", tree=tree.id)
-
-Let's first build the blob::
-
-  >>> from dulwich.objects import Blob
-  >>> spam = Blob.from_string("My new file content\n")
-  >>> spam.id
-  '16ee2682887a962f854ebd25a61db16ef4efe49f'
-
-An alternative is to alter the previously constructed blob object::
-
-  >>> blob.data = "My new file content\n"
-  >>> blob.id
-  '16ee2682887a962f854ebd25a61db16ef4efe49f'
-
-In any case, update the blob id known as "spam". You also have the
-opportunity of changing its mode::
-
-  >>> tree["spam"] = (0100644, spam.id)
-
-Now let's record the change::
-
-  >>> from dulwich.objects import Commit
-  >>> from time import time
-  >>> c2 = Commit()
-  >>> c2.tree = tree.id
-  >>> c2.parents = [c1_id]
-  >>> c2.author = c2.committer = "John Doe <john@example.com>"
-  >>> c2.commit_time = c2.author_time = int(time())
-  >>> c2.commit_timezone = c2.author_timezone = 0
-  >>> c2.encoding = "UTF-8"
-  >>> c2.message = 'Changing "spam"'
-
-In this new commit we record the changed tree id, and most important, the
-previous commit as the parent. Parents are actually a list because a commit
-may happen to have several parents after merging branches.
-
-Remain to record this whole new family::
-
-  >>> repo.object_store.add_object(spam)
-  >>> repo.object_store.add_object(tree)
-  >>> repo.object_store.add_object(c2)
-
-You can already ask git to introspect this commit using ``git show`` and the
-value of ``c2.id`` as an argument. You'll see the difference will the
-previous blob recorded as "spam".
-
-The diff between the previous head and the new one can be printed using
-write_tree_diff::
-
-  >>> from dulwich.patch import write_tree_diff
-  >>> import sys
-  >>> write_tree_diff(sys.stdout, repo.object_store, repo[c1_id].tree, tree.id)
-  diff --git a/spam b/spam
-  index c55063a..16ee268 100644
-  --- a/spam
-  +++ b/spam
-  @@ -1,1 +1,1 @@
-  -My file content
-  +My new file content
-
-You won't see it using git log because the head is still the previous
-commit. It's easy to remedy::
-
-  >>> repo.refs['refs/heads/master'] = c2.id
-
-Now all git tools will work as expected.

+ 80 - 29
docs/tutorial/1-initial-commit.txt → docs/tutorial/2-object-store.txt

@@ -1,34 +1,13 @@
-The Repository
-==============
+The object store
+================
 
 
-After this introduction, let's start directly with code::
+The objects are stored in the ``object store`` of the repository.
 
 
   >>> from dulwich.repo import Repo
   >>> from dulwich.repo import Repo
-
-The access to every object is through the Repo object. You can open an
-existing repository or you can create a new one. There are two types of Git
-repositories:
-
-  Regular Repositories -- They are the ones you create using ``git init`` and
-  you daily use. They contain a ``.git`` folder.
-
-  Bare Repositories -- There is not ".git" folder. The top-level folder
-  contains itself the "branches", "hooks"... folders. These are used for
-  published repositories (mirrors).
-
-Let's create a folder and turn it into a repository, like ``git init`` would::
-
-  >>> from os import mkdir
-  >>> mkdir("myrepo")
-  >>> repo = Repo.init("myrepo")
-  >>> repo
-  <Repo at 'myrepo'>
-
-You can already look a the structure of the "myrepo/.git" folder, though it
-is mostly empty for now.
+  >>> repo = Repo.init("myrepo", mkdir=True)
 
 
 Initial commit
 Initial commit
-==============
+--------------
 
 
 When you use Git, you generally add or modify content. As our repository is
 When you use Git, you generally add or modify content. As our repository is
 empty for now, we'll start by adding a new file::
 empty for now, we'll start by adding a new file::
@@ -94,7 +73,7 @@ Now our repository is officialy tracking a branch named "master" refering to a
 single commit.
 single commit.
 
 
 Playing again with Git
 Playing again with Git
-======================
+----------------------
 
 
 At this point you can come back to the shell, go into the "myrepo" folder and
 At this point you can come back to the shell, go into the "myrepo" folder and
 type ``git status`` to let Git confirm that this is a regular repository on
 type ``git status`` to let Git confirm that this is a regular repository on
@@ -115,5 +94,77 @@ blob::
   $ cat spam
   $ cat spam
   My file content
   My file content
 
 
-.. attention:: Remember to recreate the repo object when you modify the
-               repository outside of Dulwich!
+Changing a File and Committing it
+---------------------------------
+
+Now we have a first commit, the next one will show a difference.
+
+As seen in the introduction, it's about making a path in a tree point to a
+new blob. The old blob will remain to compute the diff. The tree is altered
+and the new commit'task is to point to this new version.
+
+Let's first build the blob::
+
+  >>> from dulwich.objects import Blob
+  >>> spam = Blob.from_string("My new file content\n")
+  >>> spam.id
+  '16ee2682887a962f854ebd25a61db16ef4efe49f'
+
+An alternative is to alter the previously constructed blob object::
+
+  >>> blob.data = "My new file content\n"
+  >>> blob.id
+  '16ee2682887a962f854ebd25a61db16ef4efe49f'
+
+In any case, update the blob id known as "spam". You also have the
+opportunity of changing its mode::
+
+  >>> tree["spam"] = (0100644, spam.id)
+
+Now let's record the change::
+
+  >>> from dulwich.objects import Commit
+  >>> from time import time
+  >>> c2 = Commit()
+  >>> c2.tree = tree.id
+  >>> c2.parents = [commit.id]
+  >>> c2.author = c2.committer = "John Doe <john@example.com>"
+  >>> c2.commit_time = c2.author_time = int(time())
+  >>> c2.commit_timezone = c2.author_timezone = 0
+  >>> c2.encoding = "UTF-8"
+  >>> c2.message = 'Changing "spam"'
+
+In this new commit we record the changed tree id, and most important, the
+previous commit as the parent. Parents are actually a list because a commit
+may happen to have several parents after merging branches.
+
+Let's put the objects in the object store::
+
+  >>> repo.object_store.add_object(spam)
+  >>> repo.object_store.add_object(tree)
+  >>> repo.object_store.add_object(c2)
+
+You can already ask git to introspect this commit using ``git show`` and the
+value of ``c2.id`` as an argument. You'll see the difference will the
+previous blob recorded as "spam".
+
+The diff between the previous head and the new one can be printed using
+write_tree_diff::
+
+  >>> from dulwich.patch import write_tree_diff
+  >>> import sys
+  >>> write_tree_diff(sys.stdout, repo.object_store, commit.tree, tree.id)
+  diff --git a/spam b/spam
+  index c55063a..16ee268 100644
+  --- a/spam
+  +++ b/spam
+  @@ -1,1 +1,1 @@
+  -My file content
+  +My new file content
+
+You won't see it using git log because the head is still the previous
+commit. It's easy to remedy::
+
+  >>> repo.refs['refs/heads/master'] = c2.id
+
+Now all git tools will work as expected.

+ 0 - 41
docs/tutorial/3-add-file.txt

@@ -1,41 +0,0 @@
-Adding a file
-=============
-
-If you followed well, the next lesson will be straightforward.
-
-We need a new blob::
-
-    >>> ham = Blob.from_string("Another\nmultiline\nfile\n")
-    >>> ham.id
-    'a3b5eda0b83eb8fb6e5dce91ecafda9e97269c70'
-
-But the same tree::
-
-    >>> tree["ham"] = (0100644, spam.id)
-
-And a new commit::
-
-  >>> c3 = Commit()
-  >>> c3.tree = tree.id
-  >>> c3.parents = [commit.id]
-  >>> c3.author = c3.committer = author
-  >>> c3.commit_time = c3.author_time = int(time())
-  >>> c3.commit_timezone = c3.author_timezone = tz
-  >>> c3.encoding = "UTF-8"
-  >>> c3.message = 'Adding "ham"'
-
-Save it all::
-
-    >>> object_store.add_object(spam)
-    >>> object_store.add_object(tree)
-    >>> object_store.add_object(c3)
-
-Update the head::
-
-    >>> repo.refs['refs/heads/master'] = commit.id
-
-A call to ``git show`` will confirm the addition of "spam".
-
-Remember you can also call ``git checkout -f`` to make it appear.
-
-Well... Adding "spam" was not such a good idea... We'll remove it.

+ 11 - 0
docs/tutorial/3-conclusion.txt

@@ -0,0 +1,11 @@
+Conclusion
+==========
+
+This tutorial currently only covers a small (but important) part of Dulwich.
+It still needs to be extended to cover packs, tags, refs, reflogs and network
+communication.
+
+Dulwich is abstracting much of the Git plumbing, so there would be more to
+see.
+
+For now, that's all folks!

+ 0 - 30
docs/tutorial/4-remove-file.txt

@@ -1,30 +0,0 @@
-Removing a file
-===============
-
-Removing a file just means removing its entry in the tree. The blob won't be
-deleted because Git tries to preserve the history of your repository.
-
-It's all pythonic::
-
-    >>> del tree["ham"]
-
-  >>> c4 = Commit()
-  >>> c4.tree = tree.id
-  >>> c4.parents = [commit.id]
-  >>> c4.author = c4.committer = author
-  >>> c4.commit_time = c4.author_time = int(time())
-  >>> c4.commit_timezone = c4.author_timezone = tz
-  >>> c4.encoding = "UTF-8"
-  >>> c4.message = 'Removing "ham"'
-
-Here we only have the new tree and the commit to save::
-
-    >>> object_store.add_object(spam)
-    >>> object_store.add_object(tree)
-    >>> object_store.add_object(c4)
-
-And of course update the head::
-
-    >>> repo.refs['refs/heads/master'] = commit.id
-
-If you don't trust me, ask ``git show``. ;-)

+ 0 - 33
docs/tutorial/5-rename-file.txt

@@ -1,33 +0,0 @@
-Renaming a file
-===============
-
-Remember you learned that the file name and content are distinct. So renaming
-a file is just about associating a blob id to a new name. We won't store more
-content, and the operation will be painless.
-
-Let's transfer the blob id from the old name to the new one::
-
-    >>> tree["eggs"] = tree["spam"]
-    >>> del tree["spam"]
-
-As usual, we need a commit to store the new tree id::
-
-  >>> c5 = Commit()
-  >>> c5.tree = tree.id
-  >>> c5.parents = [commit.id]
-  >>> c5.author = c5.committer = author
-  >>> c5.commit_time = c5.author_time = int(time())
-  >>> c5.commit_timezone = c5.author_timezone = tz
-  >>> c5.encoding = "UTF-8"
-  >>> c5.message = 'Rename "spam" to "eggs"'
-
-As for a deletion, we only have a tree and a commit to save::
-
-    >>> object_store.add_object(tree)
-    >>> object_store.add_object(c5)
-
-Remains to make the head bleeding-edge::
-
-    >>> repo.refs['refs/heads/master'] = commit.id
-
-As a last exercise, see how ``git show`` illustrates it.

+ 0 - 11
docs/tutorial/6-conclusion.txt

@@ -1,11 +0,0 @@
-Conclusion
-==========
-
-You can also make Tag objects, but this is left as a exercise to the reader.
-
-Dulwich is abstracting much of the Git plumbing, so there would be more to
-see.
-
-Dulwich is also able to clone and push repositories.
-
-That's all folks!

+ 3 - 6
docs/tutorial/index.txt

@@ -5,9 +5,6 @@ Dulwich Tutorial
 .. contents::
 .. contents::
 
 
 .. include:: 0-introduction.txt
 .. include:: 0-introduction.txt
-.. include:: 1-initial-commit.txt
-.. include:: 2-change-file.txt
-.. include:: 3-add-file.txt
-.. include:: 4-remove-file.txt
-.. include:: 5-rename-file.txt
-.. include:: 6-conclusion.txt
+.. include:: 1-repo.txt
+.. include:: 2-object-store.txt
+.. include:: 3-conclusion.txt

+ 3 - 2
dulwich/tests/__init__.py

@@ -80,8 +80,9 @@ def test_suite():
     result.addTests(suite)
     result.addTests(suite)
     tutorial = [
     tutorial = [
         '0-introduction',
         '0-introduction',
-        '1-initial-commit',
-        '2-change-file',
+        '1-repo',
+        '2-object-store',
+        '3-conclusion',
         ]
         ]
     tutorial_files = ["../../docs/tutorial/%s.txt" % name for name in tutorial]
     tutorial_files = ["../../docs/tutorial/%s.txt" % name for name in tutorial]
     def setup(test):
     def setup(test):