본문으로 건너뛰기

상태

Pitmaster는 세 가지 상태, 즉 HEAD 커밋의 트리, 인덱스(스테이징 영역), 작업 트리(디스크의 실제 파일)를 비교해 작업 트리 상태를 계산합니다. CLI는 이를 바탕으로 git status 형식의 요약을 출력하고, statusPorcelainV2()는 git의 porcelain v2 형식을 출력합니다.

기본 사용법

PHP
$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로 표시됩니다:

PHP
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 열거형

PHP
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와 일치하는 기계 판독 가능 상태 출력을 얻으려면:

PHP
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 클래스는 세 단계 비교를 수행합니다:

PHP
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 파일을 파싱해 추적되지 않는 파일 중 무시된 파일로 보고할 항목을 결정합니다.

PHP
use Pitmaster\Status\GitIgnore;

GitIgnore 클래스는 다음 위치에서 gitignore 패턴을 파싱합니다:

  • 저장소 루트의 .gitignore
  • 하위 디렉터리의 .gitignore
  • .git/info/exclude

지원되는 패턴 구문:

  • Glob 패턴(*.log, build/)
  • 부정(!important.log)
  • 디렉터리 전용 패턴(끝에 / 사용)
  • 저장소 루트 기준 패턴을 위한 선행 /
  • 재귀 매칭을 위한 **

상태 항목 분류

UI 표시의 일반적인 패턴:

PHP
$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 프로토콜을 위한 헬퍼가 포함되어 있습니다:

PHP
use Pitmaster\Status\Fsmonitor;

Fsmonitor 클래스는 core.fsmonitor 훅을 조회해 토큰 이후 변경된 파일을 확인할 수 있습니다(실패하면 수정 시간 스캔으로 대체). ['processes' => false]로 연 핸들에서는 이 기능이 자동으로 꺼집니다. 현재 status()는 이를 호출하지 않고 stat 데이터와 콘텐츠를 직접 비교합니다.