레슨 6 · 일상 업무
변화를 판단하기 전에 비교를 읽어보세요
Hero를 실행 가능한 정적 프로젝트로 전환한 다음 작업, 단계 및 기록된 차이점을 구별합니다. 지속적인 과정 기록에 이미지 커밋을 추가하지 않고 별도의 결정적 이미지 변형을 검사합니다.
- 레벨: 초보자
- 12분 읽음
- 5분 동영상
- 업데이트됨
- 이 수업 전에: 의도한 스냅샷을 준비하고 첫 번째 커밋을 수행합니다.
이 브라우저에 진행 상황이 저장되었습니다.
재생하면 YouTube에서 동영상이 로드됩니다(개인정보 보호 강화 모드).
무엇을 배울 것인가
- 텍스트 비교의 양쪽 이름을 지정하고 추가/제거를 해석합니다.
- 추적되지 않은 파일이 일반 git diff에 없을 수 있는 이유를 설명하세요.
- Git이 텍스트 이미지 패치를 제공하는 것처럼 가장하지 않고 이미지를 시각적으로 비교합니다.
- 실행 가능한 페이지를 커밋하기 전에 작은 로컬 검사를 추가하고 확인하세요.
시작하기 전에
5과가 끝난 곳에서 시작합니다. 즉, 하나의 영웅 커밋이 있는 원래 메인입니다. HEAD/색인에는 HTML-01이 포함되어 있습니다. 작업 index.html에는 HTML-01-WORKING이 포함되어 있습니다. 리모컨이 존재하지 않습니다. HTML-02에서 해당 지원 행 편집을 유지합니다. 그것을 버리지 마십시오.
동영상은 Ubuntu 24.04에서 Git 2.52.0, Node 22.22.0, npm 10.9.4 및 GitTree 2.0으로 녹화되었습니다. 10개의 파일은 GitTree의 자체 편집기에 저장되고, 앱에서 스테이징 및 커밋되었으며, 터미널 검사는 앱이 생성한 내용이나 스테이징 전 상태 및 이미지에 대한 별도의 복사본에 대해 실행되었습니다. 프로젝트가 선언한 버전인 Node 22에서 노드 검사가 통과되었습니다. macOS 또는 Windows에서는 아무것도 실행되지 않았으며 Ubuntu는 기록된 유일한 Linux 시스템입니다. GitTree의 검사된 Git 플로어는 2.39.0입니다. GitTree에 로그인하면 로컬 Git은 무료 요금제이므로 공급자나 API 자격 증명이 필요하지 않습니다.
개념
차이점은 파일이 "양호"한지 여부가 아니라 two snapshots에 대한 질문에 답변합니다. 일반적인 git diff는 인덱스 → 작업 트리를 비교합니다. git diff --cached는 HEAD → 인덱스를 비교합니다. git diff HEAD는 HEAD → 작업 트리를 비교합니다. 플러스는 새로운 쪽 텍스트를 표시하고 마이너스는 승인이나 비난이 아닌 이전 쪽 텍스트를 표시합니다. 비교 의미에 대해서는 Git의 diff 참조를 읽어보세요.
추적되지 않은 파일에는 일반 색인 항목이 없습니다. 따라서 빈 일반 diff는 새 파일이 존재하지 않음을 증명하지 않습니다. 상태와 새로 추가된 파일 내용도 검토하세요. 새 파일을 준비한 후 캐시된 비교에서 전체 추가 내용을 검토할 수 있습니다.
인라인/분할/헝크, 래핑, 이미지 모드 또는 숨겨진 공백 표시를 변경하면 파일 바이트, 인덱스, 커밋 또는 원격 참조가 아닌 view가 변경됩니다. 스테이징은 인덱스를 변경합니다. 최종 일반 커밋은 로컬 메인을 이동합니다. 서버 상태는 변경되지 않습니다.
전체 실행 가능한 프로젝트 입력
README-01을 변경하지 않고 유지하세요. index.html을 HTML-02로 바꾸고 UTF-8/LF와 최종 개행 문자를 사용하여 아래의 나머지 파일을 모두 만듭니다. 최소 .gitignore는 의도적인 것입니다. 빌드 출력이 실수로 이 첫 번째 실행 가능한 커밋을 입력해서는 안 됩니다. 더 광범위한 무시 정책은 나중에 제공됩니다. 이는 웹 저장소에 설치된 애플리케이션 파일이 아닌 코스 문서 페이로드입니다.
index.html - HTML-02
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1">
<title>GitTree Features — course demo</title>
<link rel="stylesheet" href="styles.css">
</head>
<body>
<header class="site-header">
<a href="#main">GitTree Features</a>
</header>
<main id="main">
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Understand every change.</h1>
<p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
<section class="features" aria-labelledby="features-title">
<h2 id="features-title">Follow your work</h2>
<div class="cards">
<article class="feature-card">
<h3>History</h3>
<p>Read commits and branches together.</p>
</article>
<article class="feature-card">
<h3>Changes</h3>
<p>Review the exact content selected for a commit.</p>
</article>
<article class="feature-card">
<h3>Recovery</h3>
<p>Inspect the scope of a recovery point before using it.</p>
</article>
</div>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn.</p></footer>
<script type="module" src="site.js"></script>
</body>
</html>styles.css — CSS-01
:root {
color-scheme: light;
--page: #f7f8fa;
--surface: #ffffff;
--text: #17212e;
--link: #154ab5;
--line: #bac4d0;
}
* {
box-sizing: border-box;
}
body {
margin: 0;
background: var(--page);
color: var(--text);
font: 1rem/1.6 system-ui, sans-serif;
}
a {
color: var(--link);
}
.site-header,
main,
footer {
width: min(68rem, 100% - 2rem);
margin-inline: auto;
}
.site-header {
display: flex;
flex-wrap: wrap;
justify-content: space-between;
gap: 1rem;
padding-block: 1rem;
}
.hero {
max-width: 44rem;
padding-block: 3rem;
}
h1 {
font-size: clamp(2rem, 5vw, 3.5rem);
line-height: 1.2;
}
.cards {
display: grid;
grid-template-columns: repeat(auto-fit, minmax(min(16rem, 100%), 1fr));
gap: 1rem;
}
.feature-card {
padding: 1rem;
border: 1px solid var(--line);
border-radius: 0.5rem;
background: var(--surface);
}
section {
margin-block-end: 2rem;
}
button,
input {
font: inherit;
}
button,
input {
padding: 0.5rem 0.75rem;
}
:focus-visible {
outline: 3px solid var(--link);
outline-offset: 3px;
}
form {
display: grid;
max-width: 28rem;
gap: 0.5rem;
}site.js - JS-01
export function validateEmail(value) {
return /^[^\s@]+@[^\s@]+\.[^\s@]+$/.test(value.trim());
}
if (typeof document !== 'undefined') {
const form = document.querySelector('#signup-form');
const email = document.querySelector('#demo-email');
const result = document.querySelector('#signup-result');
const toggle = document.querySelector('#theme-toggle');
if (form && email && result) {
form.addEventListener('submit', (event) => {
event.preventDefault();
result.textContent = validateEmail(email.value)
? 'Valid format. This demo sent nothing.'
: 'Enter a complete fictional email address.';
});
}
if (toggle) {
toggle.addEventListener('click', () => {
const enabled = document.documentElement.dataset.theme !== 'dark';
document.documentElement.dataset.theme = enabled ? 'dark' : 'light';
toggle.setAttribute('aria-pressed', String(enabled));
toggle.textContent = enabled ? 'Use light mode' : 'Use dark mode';
});
}
}package.json - 패키지-01
{
"name": "gittree-features",
"version": "0.1.0",
"private": true,
"type": "module",
"engines": {
"node": ">=22"
},
"scripts": {
"lint": "node scripts/lint.mjs",
"test": "node --test",
"build": "node scripts/build.mjs",
"start": "node scripts/serve.mjs"
}
}패키지-lock.json — LOCK-01
{
"name": "gittree-features",
"version": "0.1.0",
"lockfileVersion": 3,
"requires": true,
"packages": {
"": {
"name": "gittree-features",
"version": "0.1.0",
"engines": {
"node": ">=22"
}
}
}
}테스트/site.test.mjs — TEST-01
import assert from 'node:assert/strict';
import test from 'node:test';
import { validateEmail } from '../site.js';
test('accepts the fictional team address', () => {
assert.equal(validateEmail('maya@example.com'), true);
});
test('trims surrounding whitespace', () => {
assert.equal(validateEmail(' leo@example.com '), true);
});
test('rejects a missing domain', () => {
assert.equal(validateEmail('omar@'), false);
});
test('rejects a missing local part', () => {
assert.equal(validateEmail('@example.com'), false);
});
test('rejects spaces inside an address', () => {
assert.equal(validateEmail('sara name@example.com'), false);
});
test('rejects input without an at sign', () => {
assert.equal(validateEmail('priya.example.com'), false);
});scripts/lint.mjs — LINT-01
import { readFile } from 'node:fs/promises';
const files = ['index.html', 'styles.css', 'site.js'];
const problems = [];
for (const file of files) {
const source = await readFile(file, 'utf8');
if (!source.endsWith('\n')) problems.push(file + ': missing final newline');
const lines = source.split('\n');
for (const [index, line] of lines.entries()) {
if (/[\t ]+$/.test(line)) {
problems.push(file + ':' + (index + 1) + ': trailing whitespace');
}
}
}
if (problems.length > 0) {
process.stderr.write(problems.join('\n') + '\n');
process.exitCode = 1;
} else {
process.stdout.write('Source formatting checks passed.\n');
}scripts/build.mjs — BUILD-01
import { copyFile, mkdir, readdir, stat } from 'node:fs/promises';
import path from 'node:path';
const output = path.resolve('dist');
const queue = ['index.html', 'styles.css', 'site.js', 'assets', 'vendor/snippets'];
await mkdir(output, { recursive: true });
while (queue.length > 0) {
const source = queue.pop();
let details;
try {
details = await stat(source);
} catch (error) {
if (error.code === 'ENOENT' && (source === 'assets' || source === 'vendor/snippets')) continue;
throw error;
}
if (details.isDirectory()) {
const entries = await readdir(source, { withFileTypes: true });
for (const entry of entries) {
if (entry.name !== '.git') queue.push(path.join(source, entry.name));
}
continue;
}
const target = path.join(output, source);
await mkdir(path.dirname(target), { recursive: true });
await copyFile(source, target);
}
process.stdout.write('Built the static site in dist/.\n');scripts/serve.mjs — SERVE-01
import { readFile, stat } from 'node:fs/promises';
import http from 'node:http';
import path from 'node:path';
const root = path.resolve('dist');
const port = Number(process.env.PORT ?? 8080);
const types = {
'.html': 'text/html; charset=utf-8',
'.css': 'text/css; charset=utf-8',
'.js': 'text/javascript; charset=utf-8',
'.bmp': 'image/bmp',
};
await stat(path.join(root, 'index.html'));
const server = http.createServer(async (request, response) => {
try {
const address = new URL(request.url, 'http://localhost');
const pathname = decodeURIComponent(address.pathname);
const target = path.resolve(root, '.' + (pathname === '/' ? '/index.html' : pathname));
const extension = path.extname(target);
if (!target.startsWith(root + path.sep) || !Object.hasOwn(types, extension)) {
response.writeHead(404).end('Not found');
return;
}
const body = await readFile(target);
response.writeHead(200, {
'Content-Type': types[extension],
'X-Content-Type-Options': 'nosniff',
}).end(body);
} catch {
response.writeHead(404).end('Not found');
}
});
server.listen(port, '127.0.0.1', () => {
process.stdout.write('Demo site: http://127.0.0.1:' + port + '\n');
});
process.on('SIGINT', () => server.close());
process.on('SIGTERM', () => server.close());.gitignore — 무시-빌드
dist/GitTree에서
- 원본 저장소에서는 Command Palette…(Command/Ctrl+Shift+P) → Show Working Changes를 사용합니다. Unstaged Files에서 index.html을 클릭하세요. 교체하기 전에 5과에서 유지된 보조선 편집 내용을 확인하세요.
- Show Files(Command/Ctrl+Shift+E)를 사용합니다. 파일 트리에서 index.html에 초점을 맞추고 Enter를 누르세요. 작업 내용을 HTML-02로 바꾼 다음 Save(편집기에서 Command/Ctrl+S)로 바꿉니다. 저장되지 않은 표시가 사라질 때까지 기다리십시오.
- 위의 서로 다른 전체 파일에 대해: 팔레트 New File… → Path from the project folder, 정확한 루트 상대 경로 입력 → Create, 자체 전체 본문 붙여넣기 → Save. 중첩된 경로는 누락된 디렉터리를 생성합니다. 기존 파일 거부는 알 수 없는 작업을 덮어쓰지 않고 해당 파일을 검사하는 것을 의미합니다.
- Back to Graph → 팔레트 Show Working Changes. 추적되지 않은 파일과 index.html을 검토하세요. 생성된 dist 출력이 아닌 위에서 이름을 지정한 정확히 10개의 변경된 경로에 Stage File를 사용하세요. 기존 README를 그대로 둡니다.
- Staged Files 아래의 각 경로를 클릭하세요. Diff view에서 사용 가능한 Hunk, Inline 및 Split를 사용하세요. 팔레트에 해당하는 항목은 Show Diff as Hunks, Show Diff Inline, Show Diff Side by Side입니다. Next change은 F7입니다. Previous change는 Shift+F7입니다. 아랍어에서도 스플리트에는 오래된 것이 왼쪽으로 남아 있고 오른쪽으로 새 것이 남아 있습니다.
- Ignore whitespace / 팔레트 Ignore Whitespace in Diffs을(를) 검사한 후 복원하세요. 숨겨진 공백은 콘텐츠가 없는 것이 아닙니다. 공백 변경 사항이 숨겨져 있으면 부분 선택을 사용할 수 없습니다. 깨끗한 인덱스의 증거로 디스플레이 필터를 사용하지 마십시오.
- 원본 폴더에서 아래의 기본 검사를 실행하세요. 그런 다음 요약
feat: add styling and local project checks을 입력하고 수정/푸시/비어 있음/후크 건너뛰기를 해제한 다음 Commit Changes to 10 Files을 선택합니다. Command/Ctrl+Enter는 두 번째 단계가 아닌 대체 제출입니다. 두 개의 커밋을 확인하고 추적된 상태를 정리합니다.
터미널에서
input 체크포인트에서 이 읽기 전용 쿼리는 아직 커밋되지 않은 5과 편집 내용을 캡처합니다.
git diff -- index.html관찰된 전체 출력:
diff --git a/index.html b/index.html
index 5470374..27f8718 100644
--- a/index.html
+++ b/index.html
@@ -13,7 +13,7 @@
<section class="hero" aria-labelledby="hero-title">
<p class="eyebrow">GitTree Learn demo project</p>
<h1 id="hero-title">Understand every change.</h1>
- <p id="hero-copy">A clear view of Git history.</p>
+ <p id="hero-copy">Choose one change, then check what Git saved.</p>
</section>
</main>
<footer><p>Built by a fictional team for GitTree Learn.</p></footer>모든 페이로드를 저장한 후 스테이징하기 전에 다음을 수행합니다.
git status --short M index.html
?? .gitignore
?? package-lock.json
?? package.json
?? scripts/
?? site.js
?? styles.css
?? tests/디렉토리 항목 스크립트/ 및 테스트/는 추적되지 않은 상태로 그룹화되어 있으며 해당 파일 본문이 검토되었다는 증거는 아닙니다.
점검을 실행하십시오. 이 스크립트는 Node 내장 기능만 사용하므로 종속성 설치나 네트워크가 필요하지 않습니다.
npm run --silent lint
npm test -- --test-reporter=tap
npm run --silent build
git check-ignore dist/index.html관찰된 린트 출력:
Source formatting checks passed.테스트당 타이밍을 제외하고 관찰된 test-summary excerpt:
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0관찰된 빌드 및 출력 무시, 각각 하나의 명령:
Built the static site in dist/.
dist/index.html작성된 npm 시작 스크립트는 루프백을 바인딩하고 dist를 제공합니다. 장기간 실행됩니다. 서버 프로세스와 테스트 통과를 혼동하지 마십시오. 라이브 HTTP 동작에는 여전히 녹음 환경 확인이 필요합니다. 여기서는 서버 테이크가 주장되지 않습니다.
앱이 해당 변형을 아직 수행하지 않은 경우에만 기본 단계/커밋 대안:
git add -- .gitignore index.html styles.css site.js package.json package-lock.json tests/site.test.mjs scripts/lint.mjs scripts/build.mjs scripts/serve.mjs
git diff --cached --stat
git commit --quiet -m "feat: add styling and local project checks"
git rev-list --count HEAD
git status --short조용한 커밋은 자동으로 성공했습니다. count는 2을 인쇄하고 최종 짧은 상태는 비어 있습니다. 통계는 검토 보조 도구이지 10개의 파일 본문을 모두 읽는 것을 대체하는 것이 아닙니다. dist는 무시되고 커밋되지 않습니다. 리모컨이 추가되지 않았습니다.
별도의 이미지 비교 변형
두 번째 관련 없는 예나 계속되는 원본이 아닌 분리된 copy of this same GitTree Features checkpoint을(를) 준비하세요. 이전 바이트와 함께 자산/diff-card.png를 추가하고 명확하게 레이블이 지정된 고정 장치 전용 커밋을 만든 다음 작업 바이트를 이후로 바꿉니다. 이러한 Markdown 파일은 이미지 파일이나 최종 미디어를 제공하지 않습니다.
두 PNG 모두 왼쪽 절반이 파란색입니다. 이전에는 오른쪽 절반이 흰색이었습니다. 오른쪽 하단에 녹색 분기가 있습니다. 정확한 전체 바이트:
| 버전 | 치수 | 바이트 | SHA-256 |
|---|---|---|---|
| 전에 | 64 × 64 | 162 | 9a09ba97c890da0d542166ba17882bea8f7bf9b9bd4f5ec068a156f6b7256773 |
| 이후 | 64 × 64 | 171 | 2ddabb4b9859aa53ff9c433a48cb7db0213e184b425a86fef20d8502eed8974f |
before — full PNG Base64 bytes
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAaUlEQVR4nO3QAQkAAAjAMEtYyr7m0xgi7PACi6yey68LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4D/AAqNletEZdhfWAAAAAElFTkSuQmCCafter — full PNG Base64 bytes
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAcklEQVR4nO3QQQ0AIBAEsTOBA9QQ1OANfaCC7INOMgZabeyTPF0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ7f14wOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfABwAT8dDllEqFx1AAAAAElFTkSuQmCC녹음 운영자는 격리된 복사본에서 한 번에 하나의 페이로드를 디코딩할 수 있습니다.
node --input-type=module -e "import {mkdirSync,writeFileSync} from 'node:fs'; mkdirSync('assets',{recursive:true}); writeFileSync('assets/diff-card.png',Buffer.from('<selected-full-base64>','base64'));"꺾쇠 괄호 자리 표시자를 괄호 없이 하나의 전체 페이로드로 교체합니다. 이전에 디코딩하고, 픽스쳐를 스테이징/커밋한 다음, 스테이징 없이 이후에 디코딩합니다. 제공된 바이트 수/다이제스트는 각 상태를 식별합니다. 조작된 이미지 스크린샷을 절대 재사용하지 마세요.
해당 변형에서는 기본적으로 다음과 같습니다.
git diff --numstat -- assets/diff-card.png바이너리 프로브에서 관찰된 내용은 다음과 같습니다.
- - assets/diff-card.png대시는 Git이 변경된 픽셀이 0이 아닌 바이너리 데이터를 보고한다는 것을 의미합니다.
실제 앱에서: Show Working Changes → Unstaged Files에서 Assets/diff-card.png 클릭 → Side by side → Swipe, 화살표 키로 Swipe position 이동 → Onion skin, After image opacity 변경. 팔레트에 해당하는 항목: Show Image Changes Side by Side, Show Image Changes with a Swipe, Show Image Changes as Onion Skin. 양쪽 모두 실제로 디코딩해야 합니다. 없음/너무 크거나 이미지가 아님은 다른 유효한 상태이며 이미지를 위조할 이유가 아닙니다. 소스는 PNG/JPEG/GIF/WebP, not BMP를 인식합니다. 최신 LFS BMP 고정 장치는 이 이미지 보기를 약속해서는 안 됩니다.
다음 수업의 체크포인트인 원본으로 돌아가세요. 이미지 변형의 추가 커밋/자산은 정식 기록에 입력되지 않습니다.
결과
메인에 두 개의 커밋이 있습니다. README와 10개의 선언된 입력이 추적되었습니다. 색인/작업 파일은 HEAD와 일치합니다. 생성된 dist가 존재할 수 있지만 무시됩니다. 표준 트리에는 이미지 고정 장치나 원격 장치가 없습니다.
일반적인 실수
- 새 파일이 추적되지 않는 동안 일반 diff를 비웁니다. 상태 및 단계적 추가를 검사합니다.
- --stat를 정확성으로 읽기: 실제 콘텐츠와 두 비교 끝점을 모두 검사합니다.
- 공백 숨기기를 공백 삭제로 처리: 이는 단지 뷰일 뿐입니다.
- dist 또는 이미지측 픽스처 커밋: 정확한 정식 목록을 준비합니다.
뭔가 잘못되면
실패한 린트/테스트/빌드는 실제 신호입니다. 출력을 유지하고 명시된 데모 입력만 수정합니다. 확인을 건너뛰거나 알 수 없는 폴더를 삭제하지 마십시오. 차단되거나 지원되지 않는 이미지는 실제 형식/크기가 조정될 때까지 정직한 바이너리/크기 알림으로 유지되어야 합니다. 오래된 부분 선택 요청을 취소하고 패치를 강제하는 대신 현재 diff를 다시 로드합니다.
이해도를 확인해보세요
각 질문에 답한 후 그 이유를 읽어보세요. '필수'라고 표시된 질문은 수업 완료에 반영됩니다.
6개 중 0개 정답
수업을 완료하려면 필수 질문에 올바르게 답하세요.
이 브라우저에서 확인했습니다.
연습
원본에서는 개수 2, 비어 있는 작업/캐시된 diff 및 무시된 dist를 확인합니다. 별도의 이미지 변형에서 어떤 사분면이 변경되었는지, 그리고 기본 numstat가 대시를 보고하는 이유를 설명합니다. 변경된 입력: 새 파일이 스테이지되지 않고 추적되지 않은 상태로 남아 있으면 일반 diff가 여전히 이를 생략할 수 있다고 예측합니다.
귀하의 확인: 사이트에서 귀하의 컴퓨터를 볼 수 없습니다.
수업을 완료하려면 필수 질문에 올바르게 답하고 실제 연습을 확인하세요.
요약
- 차이점을 읽기 전에 두 끝점의 이름을 모두 지정하세요.
- 텍스트, 바이너리 및 디코딩된 이미지 보기는 다양한 증거를 제공합니다.
- 검사와 정확한 스테이징은 실행 가능한 검사점을 보호합니다.
관련된
용어집 소개
Diff - 차이점; 큰 덩어리 - كتلة; 색인 — البهرس; 작업 트리 — مجلد العمل; 이진법 — انائي; 추적되지 않음 — بُتبَّع.
비디오 대본
영상의 나레이션, 큐별로.
성적표 표시
- 비교 읽기 변화를 판단하기 전에.
- 이후의 영웅 라인은 여전히 새로운 커밋이 아닌 작업 콘텐츠입니다.
- 일반 및 단계적 차이점 다양한 스냅샷을 비교해 보세요.
- 전체 실행 가능한 입력을 추가하고 유지합니다. 기존 지원 라인 편집.
- 일반 파일에서 새 파일이 누락될 수 있습니다. 인덱스에 들어갈 때까지 비교합니다.
- 선언된 입력을 준비합니다. 빌드 출력이 생성되지 않았습니다.
- 레이아웃이 변경됩니다 비교된 바이트가 아닌 보기입니다.
- 전에 주변 텍스트를 따르세요. 추가 또는 제거를 해석합니다.
- 공백을 숨기는 것은 아닙니다 공백 변경을 삭제합니다.
- 로컬 서식 실행 커밋하기 전에 확인하세요.
- 6개 입력 검증 모두 이 고정 장치에서 테스트가 통과되었습니다.
- 빌드 출력은 다음에 속합니다. 커밋이 아닌 디렉터리를 무시했습니다.
- 검토한 내용을 커밋합니다. 로컬에서 실행 가능한 프로젝트.
- 두 개의 커밋을 확인하고 확인하지 않음 남은 추적 차이.
- 이미지 비교를 위해 별도의 사본을 사용하고, 계속되는 체크포인트가 아닙니다.
- 두 개의 정확한 PNG 페이로드 이미지 상태를 식별합니다.
- 명명된 면을 비교하고 실제 치수.
- 없이 칸막이를 이동하세요. 두 파일 중 하나를 변경합니다.
- 불투명도는 비교를 변경합니다. 저장된 픽셀이 아닙니다.
- Git의 바이너리 요약은 그렇지 않습니다. 변경된 픽셀의 수입니다.
- 지원되지 않거나 크기가 큰 파일 정직하게 통지해야 합니다.
- 이미지 고정물 유지 정식 역사 밖에서.
- 어떤 비교를 할지 예측해 보세요 새로 준비된 파일을 보여줍니다.
- 다음으로 덩어리와 줄을 선택하십시오. 다른 작업을 버리지 않고.