Until now we had done as of following code. We would create couples of more functions which would help us in managing our application. As discussed earlier we would now we creating different directories and files present inside .git directory along with directory itself. More or less we would something like following directory structure after doing wag init

  • .git is the git directory itself, which contains:
    • .git/objects/ : the object store, which we’ll introduce in the next section.
    • .git/refs/ the reference store, which we’ll discuss . It contains two subdirectories, heads and tags.
    • .git/HEAD, a reference to the current HEAD (more on that later!)
    • .git/config, the repository’s configuration file.
    • .git/description, the repository’s description file.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
import sys
import argparse
import os

argparser = argparse.ArgumentParser(description="Another Content Tracker")
argsubparsers = argparser.add_subparsers(title="Commands", dest="command")
argsubparsers.required = True
argsp = argsubparsers.add_parser(
    "init", help="Initialize a new, empty repository.")
argsp.add_argument("path", metavar="directory", nargs="?",
                   default=".", help="Where to create the repository.")


def main(argv=sys.argv[1:]):
    args = argparser.parse_args(argv)
    if args.command == "init":
        cmd_init(args)


def cmd_init(args):
    repo_create(args.path)


class GitRepository(object):
    """A git repository"""
    worktree = None
    gitdir = None

    def __init__(self, path, force=False):
        self.worktree = path
        self.gitdir = os.path.join(path, ".git")


def repo_create(path):
    """Create a new repository at path."""
    repo = GitRepository(path)
    # We check whether there exsits a path of worktree
    if os.path.exists(repo.worktree):
        # if path exsits its a directory or not
        if not os.path.isdir(repo.worktree):
            raise Exception("%s is not a directory!" % path)
        # if path exsits its empty or not
        if os.listdir(repo.worktree):
            raise Exception("%s is not empty!" % path)
    else:
        # Create directory as nothing exist with same path
        os.makedirs(repo.worktree)

Now let’s create function which would gives us path of directory after verifying that the directory exist and if it doesn’t it should gives us an error. We would also require mechanism to check whether we need to create the directory or not if it doesn’t exists.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
def repo_dir(repo, *path, mkdir=False):
    # repo is for our GitRepository object as we want to work with repository.
    # *path is the path we want to check
    # mkdir to specify whether we want to create directory or not.

    # this function would give us path we want to check if it exist or not
    path = repo_path(repo, *path)

    # This would check whether path exists and if it does then it would check if it is a directory or not
    if os.path.exists(path):
        if (os.path.isdir(path)):
            return path
        else:
            raise Exception("Not a directory %s" % path)

    # This would check if we need to create directory as it doesn't exists
    if mkdir:
        os.makedirs(path)
        return path
    else:
        return None


def repo_path(repo, *path):
    # This would return us path under repository git directory
    return os.path.join(repo.gitdir, *path)

We have created another repo_path function which is gives us path based on our git directory. Now we would add for these in our repo_create()

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
def repo_create(path):
    """Create a new repository at path."""
    repo = GitRepository(path)
    # We check whether there exists a path of worktree
    if os.path.exists(repo.worktree):
        # if path exists its a directory or not
        if not os.path.isdir(repo.worktree):
            raise Exception("%s is not a directory!" % path)
        # if path exists its empty or not
        if os.listdir(repo.worktree):
            raise Exception("%s is not empty!" % path)
    else:
        # Create directory as nothing exist with same path
        os.makedirs(repo.worktree)
        repo_path(repo, "branches")

    assert(repo_dir(repo, "branches", mkdir=True))
    assert(repo_dir(repo, "objects", mkdir=True))
    assert(repo_dir(repo, "refs", "tags", mkdir=True))
    assert(repo_dir(repo, "refs", "heads", mkdir=True))

Above would create .git directory with braches, objects and refs directory with tags and heads under it. It would look as follows:

  • .git
    • objects
    • branches
    • refs
      • tags
      • heads

Assert() helps us to identify that all these directories are created. If there is some issue and we return None from function it would show assertation error.

Besides directories there are few files which are also created when you do a git init, so those also needs to be created when we wag init. Those files are config, HEAD and description others too but for now we would concentrate on these three.

Now these files could be created anywhere and that directory may or may not exist so we would so let’s create a function which would create these directories if require. Also lets open description file and write “Unnamed repository; edit this file ‘description’ to name the repository.” into that. We need to change this in our repo_create function

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
def repo_create(path):
    """Create a new repository at path."""
    repo = GitRepository(path)
    # We check whether there exists a path of worktree
    if os.path.exists(repo.worktree):
        # if path exists its a directory or not
        if not os.path.isdir(repo.worktree):
            raise Exception("%s is not a directory!" % path)
        # if path exists its empty or not
        if os.listdir(repo.worktree):
            raise Exception("%s is not empty!" % path)
    else:
        # Create directory as nothing exist with same path
        os.makedirs(repo.worktree)
        repo_path(repo, "branches")

    assert(repo_dir(repo, "branches", mkdir=True))
    assert(repo_dir(repo, "objects", mkdir=True))
    assert(repo_dir(repo, "refs", "tags", mkdir=True))
    assert(repo_dir(repo, "refs", "heads", mkdir=True))

    with open(repo_file(repo, "description"), "w") as f:
        f.write("Unnamed repository; edit this file 'description' to name the repository.\n")

def repo_file(repo, *path, mkdir=False):
    if repo_dir(repo, *path[:-1], mkdir=mkdir):
    return repo_path(repo, *path)

For config file we would need to use config parser module which would create a config file in Microsoft’s INI format. So first let’s create a function which would create default config. We would need to import this module with below modules. In default config there are thing fields,

  • repositoryformatversion whose value we would set to 0, for more info visit here. Our program would be compatible with only 0 format version only
  • filemode whose value would be set to false, it disables tacking of file mode changes
  • bare whose value would be false. It indicates that this repository has a work. Git supports an optional worktree key which indicates location of the worktree, if not ..(parent repository)

All these keys are under core section so first we would add section and then set this config.

1
2
3
4
5
6
7
8
9
def repo_default_config():
    ret = configparser.ConfigParser()

    ret.add_section("core")
    ret.set("core", "repositoryformatversion", "0")
    ret.set("core", "filemode", "false")
    ret.set("core", "bare", "false")

    return ret

Now let’s update our repo_create function to create config and Head file.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
def repo_create(path):
    """Create a new repository at path."""
    repo = GitRepository(path)
    # We check whether there exsits a path of worktree
    if os.path.exists(repo.worktree):
        # if path exsits its a directory or not
        if not os.path.isdir(repo.worktree):
            raise Exception("%s is not a directory!" % path)
        # if path exsits its empty or not
        if os.listdir(repo.worktree):
            raise Exception("%s is not empty!" % path)
    else:
        # Create directory as nothing exist with same path
        os.makedirs(repo.worktree)
        repo_path(repo, "branches")

    assert(repo_dir(repo, "branches", mkdir=True))
    assert(repo_dir(repo, "objects", mkdir=True))
    assert(repo_dir(repo, "refs", "tags", mkdir=True))
    assert(repo_dir(repo, "refs", "heads", mkdir=True))

    with open(repo_file(repo, "description"), "w") as f:
        f.write("Unnamed repository; edit this file 'description' to name the repository.\n")

    with open(repo_file(repo, "HEAD"), "w") as f:
        f.write("ref: refs/heads/master\n")

    with open(repo_file(repo, "config"), "w") as f:
        config = repo_default_config()
        config.write(f)

This would complete our init method. YAY