차이
Pitmaster은 git의 통합 형식으로 diff를 계산합니다. diff 엔진은 여러 알고리즘, 통합 diff 형식 지정, 바이너리 파일 감지 및 트리 수준 재귀 비교를 지원합니다.
모드가 100644인 수정된 텍스트 파일의 경우 format()은 git diff와 동일한 바이트를 생성합니다. 현재는 다른 경우의 형식이 다릅니다(#3):
- 새 파일과 삭제된 파일에는
new file mode/deleted file mode줄,index줄 및/dev/null이 없습니다. 양쪽 모두a/<path>및b/<path>로 표시되고, 비어 있는 쪽의 hunk 범위는 git이-0,0또는+0,0로 쓰는 경우-1,0또는+1,0로 기록됩니다. index줄은 파일 모드와 관계없이 항상100644로 끝납니다.- 모드만 변경된 경우(예:
chmod +x) 결과가 생성되지 않습니다. - 바이너리 파일은
index줄 없이Binary files differ을 출력하며, git은Binary files a/<path> and b/<path> differ를 출력합니다. - 이름이 바뀐 파일은 콘텐츠 diff가 포함된 단일
diff --git a/<old> b/<new>항목으로 표시되며,similarity index,rename from또는rename to줄은 없습니다.
Diff 작업
스테이징되지 않은 변경 사항(작업 트리와 인덱스 비교)
$diffs = $repo->diff();
foreach ($diffs as $diff) {
echo $diff->format();
}
인덱스의 각 파일을 작업 트리의 현재 상태와 비교합니다. 수정, 삭제 및 바이너리 파일을 감지합니다.
스테이징된 변경 사항(인덱스와 HEAD 비교)
$diffs = $repo->diffStaged();
foreach ($diffs as $diff) {
echo $diff->format();
}
현재 인덱스를 HEAD 커밋의 트리와 비교합니다. 다음 커밋에 포함될 항목을 표시합니다. 콘텐츠가 비슷한 삭제 및 추가 파일은 이름이 바뀐 단일 항목으로 보고됩니다. 첫 커밋 전에는 HEAD가 없으므로 결과는 비어 있습니다(#5).
이름이 바뀐 파일의 짝을 찾을 때 마지막 빈 줄이 공유 콘텐츠로 계산되어 서로 관련 없는 한 줄 파일도 현재 일치하는 것으로 처리됩니다(#4).
트리 간 diff
$a = $repo->readObject($repo->resolve('HEAD~1')->hex)->tree;
$b = $repo->head()->tree;
$diffs = $repo->diffTree($a, $b);
두 트리를 재귀적으로 비교합니다. 트리 ID를 전달하세요. 커밋 ID는 해당 트리로 역참조되지 않아 결과가 비어 있습니다. 동일한 TreeDiff 엔진이 diffStaged(), show(), logPath()을 처리합니다.
경로별 필터링
$diffs = $repo->diff('src/specific-file.php');
경로 지정자는 정확한 파일 경로 하나입니다. diffStaged()은 같은 인수를 받지만 현재는 이를 무시하므로 스테이징된 파일을 모두 반환합니다(#5).
알고리즘 선택
$diffs = $repo->diff(null, 'patience');
$diffs = $repo->diffStaged(null, 'histogram');
$diffs = $repo->diffTree($a, $b, 'minimal');
유효한 이름은 myers(기본값), patience, histogram 및 minimal입니다. 다른 이름은 InvalidArgumentException을 발생시킵니다.
DiffResult 구조
각 DiffResult은 단일 파일의 diff를 나타냅니다.
use Pitmaster\Diff\DiffResult;
foreach ($diffs as $diff) {
echo $diff->oldPath; // Path in the old tree
echo $diff->newPath; // Path in the new tree
echo $diff->binary; // true for binary files
echo $diff->oldHash; // Hex hash of the old blob (null for added files)
echo $diff->newHash; // Hex hash of the new blob (null for deleted files)
foreach ($diff->hunks as $hunk) {
echo $hunk->header(); // @@ -1,5 +1,7 @@
foreach ($hunk->lines as $line) {
echo $line . "\n"; // ' context', '+added', '-removed'
}
}
}
형식이 지정된 출력
echo $diff->format();
통합 diff 출력을 생성합니다. 수정된 텍스트 파일의 경우 git diff과 일치합니다:
diff --git a/src/File.php b/src/File.php
index abc1234..def5678 100644
--- a/src/File.php
+++ b/src/File.php
@@ -10,6 +10,8 @@ class File
private string $name;
+ private int $count;
+
public function __construct()
{
변경 사항 확인
if ($diff->hasChanges()) {
// File was modified (or is binary with changes)
}
Hunk 구조
각 Hunk은 컨텍스트 줄이 포함된 연속된 변경 영역을 나타냅니다.
use Pitmaster\Diff\Hunk;
$hunk->oldStart; // Starting line in old file
$hunk->oldCount; // Number of lines from old file
$hunk->newStart; // Starting line in new file
$hunk->newCount; // Number of lines in new file
$hunk->lines; // Array of diff lines (prefixed with ' ', '+', or '-')
$hunk->header(); // "@@ -10,6 +10,8 @@"
Diff 알고리즘
Pitmaster은 네 가지 diff 알고리즘을 구현합니다. 기본값은 Myers입니다.
Myers 차이
표준 O(ND) 알고리즘으로 git의 기본값과 동일합니다. 최소 편집 스크립트를 생성합니다.
use Pitmaster\Diff\MyersDiff;
$hunks = MyersDiff::diff($oldContent, $newContent);
diff() 메서드는 문자열 두 개를 받아 Hunk 객체 배열을 반환합니다. 입력을 줄바꿈으로 나누고, 최단 편집 스크립트를 계산한 뒤, 변경 사항을 컨텍스트 3줄이 포함된 hunk로 묶습니다(git의 기본 동작과 일치).
Patience 차이
코드의 구조를 더 잘 보여 주는 diff입니다. 먼저 고유한 줄을 일치시킨 다음 그 사이를 채웁니다.
use Pitmaster\Diff\PatienceDiff;
$hunks = PatienceDiff::diff($oldContent, $newContent);
Histogram 차이
반복되는 줄을 더 잘 처리하는 Patience diff의 변형입니다. JGit 및 Eclipse에서 사용됩니다.
use Pitmaster\Diff\HistogramDiff;
$hunks = HistogramDiff::diff($oldContent, $newContent);
최소 차이
계산량이 늘어나는 대신 가능한 한 가장 작은 diff(변경된 줄 수가 가장 적음)를 생성합니다.
use Pitmaster\Diff\MinimalDiff;
$hunks = MinimalDiff::diff($oldContent, $newContent);
바이너리 감지
Pitmaster은 처음 8192바이트 안에 NUL 바이트가 있으면 콘텐츠를 바이너리로 처리합니다(git은 처음 8000바이트를 확인함).
if (MyersDiff::isBinary($content)) {
// Binary file, skip line-level diff
}
바이너리 파일은 $binary = true과 빈 $hunks 배열이 포함된 DiffResult을 생성합니다. 형식이 지정된 출력은 다음과 같습니다:
diff --git a/image.png b/image.png
Binary files differ
색상 출력
CLI은 ANSI 색상을 사용해 터미널에 출력할 때 ColorDiff을 사용합니다.
use Pitmaster\Diff\ColorDiff;
$colorized = ColorDiff::colorize($diff->format());
echo $colorized;
- 추가된 줄(
+)은 녹색으로 표시됩니다. - 제거된 줄(
-)은 빨간색으로 표시됩니다. - Hunk 헤더(
@@)는 청록색으로 표시됩니다. - 파일 헤더(
diff --git,index,---,+++)는 굵게 표시됩니다.
pitmaster diff은 출력을 파이프로 전달할 때도 항상 색상을 입힙니다. pitmaster show은 stdout이 터미널일 때만 색상을 입힙니다.
트리 diff(내부)
TreeDiff 클래스는 두 트리 객체를 재귀적으로 비교하고, 변경된 파일마다 DiffResult을 생성합니다.
use Pitmaster\Diff\TreeDiff;
$treeDiff = new TreeDiff($repo->objectDatabase());
$diffs = $treeDiff->diff($oldTreeId, $newTreeId);
트리 diff는 다음을 처리합니다:
- 추가된 파일(새 트리에만 있음)
- 삭제된 파일(이전 트리에만 있음)
- 수정된 파일(경로는 같고 blob 해시는 다름)
- 하위 디렉터리의 재귀적 비교
- 삭제 및 추가된 파일의 이름 바뀜 짝 찾기(해시가 정확히 일치하거나 공유 줄이 50% 이상)
해시가 바뀌지 않은 항목은 건너뛰므로 모드만 변경된 경우 결과가 생성되지 않습니다.
단어 diff
줄 안에서 인라인 단어 수준의 변경 사항을 확인합니다.
use Pitmaster\Diff\WordDiff;
$result = WordDiff::diff('the quick fox', 'the slow fox');
// 'the [-quick-]{+slow+} fox'