Skip to content

Commit

To get a Commit, resolve a revision: a branch, a tag, HEAD, master~2, an abbreviated hash...

use Gitonomy\Git\Repository;

$repository = new Repository('/path/to/repository');
$commit = $repository->getRevision('master')->getCommit();

Repository::getCommit() takes the full hash of a commit, its 40 characters. It throws a ReferenceNotFoundException for anything else, an abbreviated hash included:

$commit = $repository->getCommit('7e9ba14939b0ce67ab95d83e03bd64710db91ef4');

The commit is read when you first need it: a hash naming no commit throws a ReferenceNotFoundException then.

Hashes

$commit->getHash();      // "7e9ba14939b0ce67ab95d83e03bd64710db91ef4"
$commit->getShortHash(); // "7e9ba14", abbreviated and unique in the repository

getFixedShortHash() is deprecated since 1.7: use substr($commit->getHash(), 0, 6).

Browsing parents

A commit has:

  • no parent: it's a root commit, the first one of a history;
  • one parent: it's a regular commit;
  • several parents: it's a merge commit. Its first parent is the commit the other ones were merged into.
// The hashes of the parents
$hashes = $commit->getParentHashes();

// The parents, Commit objects
$parents = $commit->getParents();

For example, to display the first parents of a commit, like git log --first-parent:

for ($current = $commit; null !== $current; $current = $current->getParents()[0] ?? null) {
    echo $current->getShortHash().' '.$current->getSubjectMessage().PHP_EOL;
}

To list a history in order, with every parent, use a log: see log.md.

Accessing the tree

The tree of a commit holds its files and folders, as the commit recorded them. Every commit has exactly one tree. See tree.md to browse it.

// The hash of the tree
$hash = $commit->getTreeHash();

// The Tree object
$tree = $commit->getTree();

Author and committer

A commit has an author and a committer. The author wrote the change. The committer recorded it in the repository: they can differ when a commit is rebased, cherry-picked or applied from a patch.

// Author
$commit->getAuthorName();
$commit->getAuthorEmail();
$commit->getAuthorDate(); // A DateTimeImmutable

// Committer
$commit->getCommitterName();
$commit->getCommitterEmail();
$commit->getCommitterDate(); // A DateTimeImmutable

Like git log, a date is at the UTC offset of its author or committer: 2012-12-31T15:21:03+01:00 for a commit made in Paris in winter. Use setTimezone() to show it in another timezone. Comparing dates doesn't depend on their offsets. An offset of more than 14 hours or 59 minutes, which no timezone has, gives UTC.

Message

The message of a commit can have several lines. Like git, gitlib splits it in a subject and a body:

// The whole message
$commit->getMessage();

// The first paragraph, on one line, like "git log --format=%s"
$commit->getSubjectMessage();

// What follows the first paragraph and its empty lines, like "git log --format=%b"
$commit->getBodyMessage();

For a message "Fix the parser\nof dates\n\nIt failed on leap years.\n", the subject is "Fix the parser of dates", and the body "It failed on leap years.\n". A message without an empty line has no body.

getShortMessage() is deprecated since 1.7: truncate the subject with symfony/string, a dependency of gitlib, instead:

use function Symfony\Component\String\u;

echo u($commit->getSubjectMessage())->truncate(50, '...').PHP_EOL;

Diff of a commit

getDiff() returns the changes a commit made:

  • against its first parent, for a regular commit or a merge commit. For a merge, these are the changes it brought into the branch it was merged into, like GitHub shows a merge commit;
  • against nothing, for a root commit: every file is a creation.
$diff = $commit->getDiff();

To compare any two commits, use Repository::getDiff($from, $to). See diff.md for the diff API.

Last modification of a file

getLastModification() returns the last commit, in the history of this one, that changed a path. It throws a ReferenceNotFoundException when no commit changed it. The path is relative to the root of the repository.

$last = $commit->getLastModification('README.md');

echo 'Last README.md modification'.PHP_EOL;
echo '  Author: '.$last->getAuthorName().PHP_EOL;
echo '    Date: '.$last->getAuthorDate()->format('d/m/Y').PHP_EOL;
echo ' Message: '.$last->getSubjectMessage().PHP_EOL;

References pointing to a commit

resolveReferences() returns the branches and tags pointing to the commit, annotated tags included:

foreach ($commit->resolveReferences() as $reference) {
    echo $reference->getFullname().PHP_EOL; // "refs/heads/master", "refs/tags/1.0"...
}

See references.md.

Branches containing a commit

getIncludingBranches() returns the local and remote branches whose history contains the commit, as Branch objects. Filter them with isLocal() or isRemote():

use Gitonomy\Git\Reference\Branch;

$branches = $commit->getIncludingBranches();
$localBranches = array_filter($branches, static fn (Branch $branch): bool => $branch->isLocal());
$remoteBranches = array_filter($branches, static fn (Branch $branch): bool => $branch->isRemote());

Passing arguments to getIncludingBranches(), to keep the local or the remote branches only, is deprecated since 1.7.