상태
Pitmaster는 세 가지 상태, 즉 HEAD 커밋의 트리, 인덱스(스테이징 영역), 작업 트리(디스크의 실제 파일)를 비교해 작업 트리 상태를 계산합니다. CLI는 이를 바탕으로 git status 형식의 요약을 출력하고, statusPorcelainV2()는 git의 porcelain v2 형식을 출력합니다.
기본 사용법
$entries = $repo->status();
foreach ($entries as $entry) {
echo $entry->shortFormat() . "\n";
}
shortFormat()는 git의 짧은 형식을 출력합니다:
M src/Modified.php (staged modification)
M src/WorktreeModified.php (unstaged modification)
A src/NewFile.php (staged new file)
D src/Deleted.php (deleted in worktree)
?? untracked.txt (untracked file)
StatusEntry
각 파일의 상태는 StatusEntry로 표시됩니다:
use Pitmaster\Status\StatusEntry;
$entry->path; // File path relative to repo root
$entry->index; // FileStatus: HEAD-to-index state
$entry->worktree; // FileStatus: index-to-worktree state
$entry->origPath; // Original path for renamed entries, otherwise null
$entry->renameScore; // Similarity score for renamed entries, otherwise null
$entry->shortFormat(); // "XY path", "?? path", or "R old -> new"
FileStatus 열거형
use Pitmaster\Status\FileStatus;
FileStatus::Added; // 'A' - new file
FileStatus::Modified; // 'M' - content changed
FileStatus::Deleted; // 'D' - file removed
FileStatus::Renamed; // 'R' - file renamed
FileStatus::Copied; // 'C' - file copied
FileStatus::Unmerged; // 'U' - unresolved merge conflict
FileStatus::Untracked; // '?' - not in index
FileStatus::Ignored; // '!' - matched by .gitignore
FileStatus::Unmodified; // ' ' - no change
status()는 무시된 파일을 보고하지 않으므로 결과에 Ignored가 나타나지 않습니다.
Porcelain v2 출력
git status --porcelain=v2와 일치하는 기계 판독 가능 상태 출력을 얻으려면:
echo $repo->statusPorcelainV2();
출력:
1 .M N... 100644 100644 100644 ce013625030ba8dba906f756967f9e9ca394464a ce013625030ba8dba906f756967f9e9ca394464a modified-file.txt
? untracked-file.txt
추적 중인 항목이 먼저 나오고 추적되지 않는 항목이 그 뒤에 나옵니다. 이름이 변경된 항목은 2 줄을, 충돌은 u 줄을 사용합니다. git status --porcelain=v2 --branch의 # branch 헤더는 출력되지 않으며, 무시된 파일은 목록에 포함되지 않습니다.
상태 계산 방식
WorkingTreeStatus 클래스는 세 단계 비교를 수행합니다:
use Pitmaster\Status\WorkingTreeStatus;
$status = new WorkingTreeStatus($repo->objectDatabase(), $repo->workDir(), $repo->gitDir());
$entries = $status->compute($repo->index(), $repo->resolve('HEAD'));
1단계: HEAD 트리 맵 작성
HEAD 커밋의 트리를 path => blob hash 맵으로 평탄화합니다. 이는 마지막으로 커밋된 상태를 나타냅니다.
2단계: HEAD와 인덱스 비교
HEAD 트리와 인덱스의 각 파일에 대해:
- HEAD에는 있지만 인덱스에는 없음: 인덱스 열에
Deleted - 인덱스에는 있지만 HEAD에는 없음: 인덱스 열에
Added - 양쪽에 있지만 해시가 다름: 인덱스 열에
Modified - 양쪽에 있고 해시가 같음: 인덱스 열에
Unmodified
3단계: 인덱스와 작업 트리 비교
인덱스와 작업 트리의 각 파일에 대해:
- 인덱스에는 있지만 디스크에는 없음: 작업 트리 열에
Deleted - 양쪽에 있지만 내용이 다름: 작업 트리 열에
Modified - 양쪽에 있고 내용이 같음: 작업 트리 열에
Unmodified
4단계: 추적되지 않는 파일 감지
작업 트리 디렉터리를 탐색하고 .git/와 무시된 경로를 건너뛴 다음, 인덱스에 없는 파일을 양쪽 열에 Untracked로 보고합니다.
.gitignore 지원
Pitmaster는 .gitignore 파일을 파싱해 추적되지 않는 파일 중 무시된 파일로 보고할 항목을 결정합니다.
use Pitmaster\Status\GitIgnore;
GitIgnore 클래스는 다음 위치에서 gitignore 패턴을 파싱합니다:
- 저장소 루트의
.gitignore - 하위 디렉터리의
.gitignore .git/info/exclude
지원되는 패턴 구문:
- Glob 패턴(
*.log,build/) - 부정(
!important.log) - 디렉터리 전용 패턴(끝에
/사용) - 저장소 루트 기준 패턴을 위한 선행
/ - 재귀 매칭을 위한
**
상태 항목 분류
UI 표시의 일반적인 패턴:
$staged = [];
$unstaged = [];
$untracked = [];
foreach ($repo->status() as $entry) {
if ($entry->index === FileStatus::Untracked) {
$untracked[] = $entry;
} elseif ($entry->index !== FileStatus::Unmodified) {
$staged[] = $entry;
}
if ($entry->worktree !== FileStatus::Unmodified
&& $entry->index !== FileStatus::Untracked
) {
$unstaged[] = $entry;
}
}
CLI 사용
./vendor/bin/pitmaster status
출력:
On branch main
Changes to be committed:
new file: src/Feature.php
Changes not staged for commit:
modified: src/Existing.php
Untracked files:
notes.txt
파일 시스템 모니터
Pitmaster에는 git의 fsmonitor 프로토콜을 위한 헬퍼가 포함되어 있습니다:
use Pitmaster\Status\Fsmonitor;
Fsmonitor 클래스는 core.fsmonitor 훅을 조회해 토큰 이후 변경된 파일을 확인할 수 있습니다(실패하면 수정 시간 스캔으로 대체). ['processes' => false]로 연 핸들에서는 이 기능이 자동으로 꺼집니다. 현재 status()는 이를 호출하지 않고 stat 데이터와 콘텐츠를 직접 비교합니다.