Skip to content

Tree and files

Git stores folders as trees. In gitlib, a tree is a Tree object.

The root tree of a commit is the entry point of all its files:

$tree = $commit->getTree();

Repository::getTree() takes the hash of a tree, abbreviated or not.

Entries of a tree

Iterating a tree gives its entries, keyed by their name. Each one is a TreeEntry object, with the name of the entry, its mode, and its object: a Blob for a file (see blob.md), a Tree for a folder, or a Submodule.

foreach ($tree as $name => $entry) {
    $entry->getName();   // The name of the file or the folder, the same as $name
    $entry->getMode();   // The mode git stores: "100644", "100755" (executable), "120000" (symbolic link), "040000" (tree), "160000" (submodule)
    $entry->getObject(); // A Blob, a Tree or a Submodule
}

To keep one kind of entries only, also keyed by their name:

$files = $tree->getBlobs();
$submodules = $tree->getSubmodules();
$folders = $tree->getTrees();

To get the object of an entry by its name:

$readme = $tree->getEntry('README.md'); // A Blob

It throws an InvalidArgumentException when the tree has no such entry.

Here is a function displaying a tree and its folders, recursively:

use Gitonomy\Git\Submodule;
use Gitonomy\Git\Tree;

function displayTree(Tree $tree, int $depth = 0): void
{
    foreach ($tree as $name => $entry) {
        $object = $entry->getObject();

        echo str_repeat('    ', $depth).match (true) {
            $object instanceof Tree => $name.'/',
            $object instanceof Submodule => $name.' @ '.$object->getHash(),
            default => $name,
        }.PHP_EOL;

        if ($object instanceof Tree) {
            displayTree($object, $depth + 1);
        }
    }
}

displayTree($commit->getTree());

getEntries(), getBlobEntries() and getTreeEntries(), which return the mode and the object of each entry as an array ([$mode, $object]), are deprecated since 1.7: iterate the tree, or use getBlobs() and getTrees().

Submodules

A submodule is a commit of another repository. Its Submodule object only holds the hash of this commit: gitlib doesn't read the submodule. Open it as a repository, from its folder in the working tree, to read it.

foreach ($tree->getSubmodules() as $name => $entry) {
    echo $name.' is at '.$entry->getObject()->getHash().PHP_EOL;
}

CommitReference is deprecated since 1.7: it is Submodule. So is Tree::getCommitReferenceEntries(): use getSubmodules().

Resolve a path

To access a file or a folder from its path, use resolvePath(). It returns a Blob, a Tree or a Submodule:

$folder = $tree->resolvePath('src/Gitonomy/Git'); // A Tree
$file = $tree->resolvePath('src/Gitonomy/Git/Repository.php'); // A Blob
  • The path is relative to the tree.
  • "" and "/" resolve to the tree itself. Leading, trailing and repeated slashes are ignored.
  • A path that doesn't exist throws an InvalidArgumentException, as a path going through a file or a submodule (README.md/foo).