The Repository
==============

After this introduction, let's start directly with code::

  >>> 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 '/tmp/myrepo/'>

You can already look a the structure of the "myrepo/.git" folder, though it
is mostly empty for now.

Initial commit
==============

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::

  >>> from dulwich.objects import Blob
  >>> blob = Blob.from_string("My file content\n")
  >>> blob.id
  'c55063a4d5d37aa1af2b2dad3a70aa34dae54dc6'

Of course you could create a blob from an existing file using ``from_file``
instead.

As said in the introduction, file content is separed from file name. Let's
give this content a name::

  >>> from dulwich.objects import Tree
  >>> tree = Tree()
  >>> tree.add(0100644, "spam", blob.id)

Note that "0100644" is the octal form for a regular file with common
permissions. You can hardcode them or you can use the ``stat`` module.

The tree state of our repository still needs to be placed in time. That's the
job of the commit::

  >>> from dulwich.objects import Commit, parse_timezone
  >>> from time import time
  >>> commit = Commit()
  >>> commit.tree = tree.id
  >>> author = "Your Name <your.email@example.com>"
  >>> commit.author = commit.committer = author
  >>> commit.commit_time = commit.author_time = int(time())
  >>> tz = parse_timezone('-0200')
  >>> commit.commit_timezone = commit.author_timezone = tz
  >>> commit.encoding = "UTF-8"
  >>> commit.message = "Initial commit"

Note that the initial commit has no parents.

At this point, the repository is still empty because all operations happen in
memory. Let's "commit" it.

  >>> object_store = repo.object_store
  >>> object_store.add_object(blob)

Now the ".git/objects" folder contains a first SHA-1 file. Let's continue
saving the changes::

  >>> object_store.add_object(tree)
  >>> object_store.add_object(commit)

Now the physical repository contains three objects but still has no branch.
Let's create the master branch like Git would::

  >>> repo.refs['refs/heads/master'] = commit.id

The master branch now has a commit where to start, but Git itself would not
known what is the current branch. That's another reference::

  >>> repo.refs['HEAD'] = 'ref: refs/heads/master'

Now our repository is officialy tracking a branch named "master" refering to a
single commit.

Playing again with Git
======================

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
branch "master".

Git will tell you that the file "spam" is deleted, which is normal because
Git is comparing the repository state with the current working copy. And we
have absolutely no working copy using Dulwich because we don't need it at
all!

You can checkout the last state using ``git checkout -f``. The force flag
will prevent Git from complaining that there are uncommitted changes in the
working copy.

The file ``spam`` appears and with no surprise contains the same bytes as the
blob::

  $ cat spam
  My file content

.. attention:: Remember to recreate the repo object when you modify the
               repository outside of Dulwich!