저장소 읽기
Pitmaster은 디스크 형식을 직접 파싱해 git 저장소를 읽습니다. 압축된 loose 객체(.git/objects/의 zlib 압축 파일), pack 파일(.git/objects/pack/), ref(.git/refs/ 및 packed-refs의 파일), 인덱스(.git/index)를 처리합니다.
저장소 열기
use Pitmaster\Pitmaster;
$repo = Pitmaster::open('/path/to/project');
Pitmaster은 세 가지 저장소 레이아웃을 지원합니다:
- 일반 저장소:
.git은 프로젝트 루트의 디렉터리입니다. - 연결된 작업 트리:
.git은gitdir: <path>가 포함되어.git/worktrees/<name>/를 가리키는 파일입니다. - Bare 저장소: 경로 자체에
HEAD,objects/등이 포함됩니다.
// Detection helpers
Pitmaster::isRepository('/path'); // true for any of the above
Pitmaster::isWorktree('/path'); // true only for linked worktrees
객체 읽기
git 저장소의 모든 데이터는 해시로 식별되는 객체로 저장됩니다. 기본적으로 SHA-1(16진수 40자)을 사용하며, Pitmaster::init($path, 'sha256')로 만든 저장소에서는 SHA-256(16진수 64자)을 사용합니다. 객체 유형은 blob, tree, commit, tag 네 가지입니다.
아래 해시 기반 메서드에는 전체 16진수 해시를 전달해야 합니다. 축약 해시는 허용되지 않습니다.
readObject
use Pitmaster\Object\Blob;
use Pitmaster\Object\Tree;
use Pitmaster\Object\Commit;
use Pitmaster\Object\Tag;
$object = $repo->readObject('a1b2c3d4e5f6...');
match (true) {
$object instanceof Blob => handleBlob($object),
$object instanceof Tree => handleTree($object),
$object instanceof Commit => handleCommit($object),
$object instanceof Tag => handleTag($object),
};
객체는 먼저 loose 저장소에서 검색하고, 그다음 pack 파일에서 검색합니다. pack 파일 조회에는 O(log n) 바이너리 검색을 위해 .idx 팬아웃 테이블을 사용합니다.
catFile
유형 확인 없이 간단히 콘텐츠를 가져오려면 다음을 사용하세요:
$content = $repo->catFile('a1b2c3d4e5f6...');
echo $content;
objectExists
if ($repo->objectExists('a1b2c3d4e5f6...')) {
// Object is in the repository
}
listObjects
$hashes = $repo->listObjects();
// ['a1b2c3d4...', 'f6e5d4c3...', ...]
모든 객체(loose 및 packed)의 16진수 해시를 반환합니다.
blob 사용
blob은 원시 파일 콘텐츠를 담습니다.
$blob = $repo->readObject($hash);
echo $blob->content; // Raw file bytes
echo $blob->size(); // Content length
echo $blob->id->hex; // Object hash
tree 사용
트리는 디렉터리 목록입니다. 각 항목에는 모드, 이름, 해시가 있습니다.
$tree = $repo->readObject($hash);
foreach ($tree->entries as $entry) {
echo "{$entry->mode} {$entry->name} {$entry->hash->hex}\n";
// 100644 README.md abc123...
// 40000 src def456...
// 100755 deploy.sh 789012...
if ($entry->isTree()) {
// Recurse into subdirectory (mode 40000)
} elseif ($entry->isExecutable()) {
// Executable file (mode 100755)
} elseif ($entry->isBlob()) {
// Regular file (any 10xxxx mode, so executables match too)
} elseif ($entry->isSymlink()) {
// Symbolic link (mode 120000)
} elseif ($entry->isGitlink()) {
// Submodule (mode 160000)
}
}
커밋 작업
커밋은 트리 스냅샷을 부모 커밋 및 메타데이터와 연결합니다.
$commit = $repo->head();
echo $commit->id->hex; // Full object hash
echo $commit->tree->hex; // Tree object hash
echo $commit->author; // "Name <email> timestamp tz"
echo $commit->committer; // "Name <email> timestamp tz"
echo $commit->message; // Full commit message
// Parent commits
foreach ($commit->parents as $parentId) {
$parent = $repo->readObject($parentId->hex);
}
// Merge detection
if ($commit->isMerge()) {
// Two or more parents
}
태그 작업
주석 태그는 대상, 유형, 이름, 태거, 메시지가 포함된 객체입니다.
$tag = $repo->readObject($hash);
echo $tag->object->hex; // Target object hash
echo $tag->objectType->value; // 'commit', 'tree', 'blob', or 'tag'
echo $tag->name; // Tag name
echo $tag->tagger; // "Name <email> timestamp tz"
echo $tag->message; // Tag message
참조 읽기
현재 HEAD
$commit = $repo->head();
HEAD(HEAD -> refs/heads/main -> commit hash와 같은 심볼릭 참조를 따라)를 해석하고 커밋 객체를 반환합니다.
현재 브랜치
$branch = $repo->branch(); // 'main' or null if detached
브랜치 및 태그 목록
$branches = $repo->branches(); // ['bugfix/typo', 'feature/login', 'main']
$tags = $repo->tags(); // ['v1.0.0', 'v1.1.0']
모든 참조
$refs = $repo->allRefs();
// [
// 'refs/heads/main' => 'abc123...',
// 'refs/heads/feature' => 'def456...',
// 'refs/tags/v1.0.0' => '789012...',
// 'refs/remotes/origin/main' => 'abc123...',
// ]
리비전 해석
$id = $repo->resolve('HEAD');
$id = $repo->resolve('main');
$id = $repo->resolve('v1.0.0');
$id = $repo->resolve('HEAD~3');
$id = $repo->resolve('main^2');
$id = $repo->resolve('3f2c1e0b9d6a4f8e7c5b2a1d0e9f8c7b6a5d4e3f');
리비전 파서는 ~N(조상) 및 ^N(부모) 연산자를 임의로 연결해 사용할 수 있도록 지원합니다. 해시는 전체 값을 지정해야 합니다.
커밋 기록 탐색
로그
커밋은 커미터 타임스탬프를 기준으로 최신순으로 반환됩니다.
// Last 20 commits from HEAD
$commits = $repo->log(20);
foreach ($commits as $commit) {
$short = substr($commit->id->hex, 0, 7);
echo "{$short} {$commit->message}\n";
}
특정 커밋부터 log 보기
$from = $repo->resolve('feature/login');
$commits = $repo->log(10, $from);
파일 경로로 log 필터링
$commits = $repo->logPath('src/Repository.php', 20);
첫 번째 부모와 비교해 지정된 파일이 변경(추가, 수정, 삭제 또는 이름 변경)된 커밋만 반환합니다. 경로는 정확한 파일 경로여야 하며 디렉터리는 일치하지 않습니다. 최신 5 * $limit개 커밋만 살펴보므로 더 오래된 일치 항목은 누락될 수 있습니다(#7).
표시
$result = $repo->show('HEAD');
$commit = $result['commit'];
$diffs = $result['diff'];
echo "Author: {$commit->author}\n";
echo "Message: {$commit->message}\n\n";
foreach ($diffs as $diff) {
echo $diff->format();
}
기본 브랜치 감지
$default = $repo->defaultBranch();
// Checks: remote HEAD symref -> local HEAD -> main/master fallback
remote.origin.url가 설정되어 있고 프로세스가 활성화된 경우, 첫 번째 확인에서 원격에 스마트 HTTP 요청을 보냅니다. 네트워크 오류는 무시하고 로컬 확인을 이어갑니다.
병합 조상 관계
// Is feature fully merged into main?
$merged = $repo->isBranchMerged('feature/done', 'main');
// Find the merge base of two commits
$base = $repo->mergeBase(
$repo->resolve('main'),
$repo->resolve('feature/login'),
);