Vai al contenuto
GitTree

Lezione 6 · Lavoro quotidiano

Leggere il confronto prima di giudicare un cambiamento

Trasforma l'eroe in un progetto statico eseguibile, quindi distingui le differenze di lavoro, messe in scena e registrate. Ispeziona una variante deterministica separata dell'immagine senza aggiungere un commit dell'immagine alla cronologia continua del corso.

Avanzamenti salvati in questo browser.

La riproduzione carica il video da YouTube (modalità ottimizzata per la privacy).

Narrazione in inglese · English and Arabic didascalie

Apri la pagina del videoGuarda su YouTube

Cosa imparerai

  • Nomina entrambi i lati di un confronto testuale e interpreta aggiunte/rimozioni.
  • Spiega perché un file non tracciato può essere assente dal normale git diff.
  • Confronta visivamente le immagini senza pretendere che Git fornisca una patch testuale dell'immagine.
  • Aggiungi e verifica i piccoli controlli locali prima di eseguire il commit della pagina eseguibile.

Prima di iniziare

Inizi da dove è terminata la lezione 5: il main originale con un eroe impegnato. HEAD/indice contiene HTML-01; working index.html contiene HTML-01-WORKING. Non esiste alcun telecomando. Conserva la modifica della riga di supporto in HTML-02; non scartarlo.

Il video è stato registrato con Git 2.52.0, Node 22.22.0, npm 10.9.4 e GitTree 2.0 su Ubuntu 24.04: i dieci file sono stati salvati nell'editor di GitTree, messi in scena e inseriti nell'app, e i controlli del terminale sono stati eseguiti rispetto a ciò che l'app ha creato o rispetto a copie separate per lo stato prima della messa in scena e per l'immagine. I controlli del nodo sono passati sul nodo 22, la versione dichiarata dal progetto. Non è stato eseguito nulla su macOS o Windows e Ubuntu è l'unico sistema Linux registrato. Il Git floor ispezionato di GitTree è 2.39.0. Una volta effettuato l'accesso a GitTree, Git locale utilizza il piano gratuito e non necessita di provider o credenziali API.

Concetto

Una differenza risponde a una domanda su two snapshots, non se un file è "buono". Il normale git diff confronta indice → albero di lavoro; git diff --cached confronta HEAD → indice; git diff HEAD confronta HEAD → albero di lavoro. Un più contrassegna il testo sul nuovo lato e un meno contrassegna il testo sul vecchio lato, non l'approvazione o la colpa. Leggi riferimento alle differenze di Git per la semantica di confronto.

Un file non tracciato non ha una voce di indice ordinaria. Diff ordinario vuoto quindi non prova che non esista alcun nuovo file. Controlla anche lo stato e il contenuto dei file appena aggiunti. Dopo aver preparato un nuovo file, la sua aggiunta completa può essere rivista nel confronto memorizzato nella cache.

La modifica di Inline/Split/Hunk, wrap, modalità immagine o visualizzazione di spazi bianchi nascosti modifica view, non byte di file, indice, commit o riferimenti remoti. La messa in scena modifica l'indice. Il commit normale finale sposta il main locale; nessuna modifica allo stato del server.

Input di progetto completamente eseguibili

Mantieni README-01 invariato. Sostituisci index.html con HTML-02 e crea tutti i file rimanenti di seguito con UTF-8/LF e un ritorno a capo finale. Il file .gitignore minimo è intenzionale: l'output della build non deve entrare accidentalmente in questo primo commit eseguibile. Una politica di ignoranza più ampia verrà dopo. Si tratta di payload di documenti del corso, non di file di applicazioni installati nel repository web.

indice.html — HTML-02

Estratto del file · html
<!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>

stili.css — CSS-01

Estratto del file · css
: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;
}

sito.js — JS-01

Estratto del file · javascript
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';
    });
  }
}

pacchetto.json — PACCHETTO-01

Estratto del file · json
{
  "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"
  }
}

pacchetto-lock.json — LOCK-01

Estratto del file · json
{
  "name": "gittree-features",
  "version": "0.1.0",
  "lockfileVersion": 3,
  "requires": true,
  "packages": {
    "": {
      "name": "gittree-features",
      "version": "0.1.0",
      "engines": {
        "node": ">=22"
      }
    }
  }
}

tests/site.test.mjs — TEST-01

Estratto del file · javascript
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);
});

script/lint.mjs — LINT-01

Estratto del file · javascript
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

Estratto del file · javascript
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');

script/serve.mjs — SERVE-01

Estratto del file · javascript
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 — IGNORA-BUILD

Estratto del file · gitignore
dist/

Tra GitTree

  1. Nel repository originale, utilizza Command Palette… (Comando/Ctrl+Maiusc+P) → Show Working Changes. Fai clic su index.html in Unstaged Files. Prima di sostituirlo, identifica la modifica della linea di supporto mantenuta dalla lezione 5.
  2. Utilizza Show Files (Comando/Ctrl+Maiusc+E); mettere a fuoco index.html nell'albero dei file e premere Invio. Sostituisci i suoi contenuti funzionanti con HTML-02, quindi Save (Comando/Ctrl+S nell'editor). Attendi che l'indicatore non salvato venga cancellato.
  3. Per ogni altro file completo sopra: tavolozza New File… → Path from the project folder, digita l'esatto percorso relativo alla radice → Create, incolla il proprio corpo completo → Save. I percorsi nidificati creano le directory mancanti. Il rifiuto del file esistente significa ispezionare quel file, non sovrascrivere il lavoro sconosciuto.
  4. Back to Graph → tavolozza Show Working Changes. Esamina i file non tracciati e il file index.html. Utilizza Stage File esattamente sui dieci percorsi modificati indicati sopra, non sull'output dist generato. Lasciare intatto il file README esistente.
  5. Fai clic su ciascun percorso sotto Staged Files. Utilizza Hunk, Inline e Split come disponibili in Diff view. Gli equivalenti della tavolozza sono Show Diff as Hunks, Show Diff Inline, Show Diff Side by Side. Next change è F7; Previous change è Maiusc+F7. Il vecchio rimane a sinistra e il nuovo a destra a Spalato anche in arabo.
  6. Ispeziona Ignore whitespace / tavolozza Ignore Whitespace in Diffs, quindi ripristinala. Gli spazi bianchi nascosti non sono contenuti assenti; la selezione parziale può non essere disponibile quando le modifiche agli spazi bianchi sono nascoste. Non utilizzare un filtro di visualizzazione come prova di un indice pulito.
  7. Esegui i controlli nativi di seguito nella cartella originale. Quindi inserisci Riepilogo feat: add styling and local project checks, mantieni amend/push/empty/skip-hooks disattivati ​​e scegli Commit Changes to 10 Files. Comando/Ctrl+Invio è un invio alternativo, non un secondo passaggio. Verifica due commit e pulisci lo stato tracciato.

Nel terminale

Al punto di controllo input, questa query di sola lettura acquisisce la modifica della lezione 5 ancora non confermata:

Command · bash
git diff -- index.html

Uscita completa osservata:

Uscita
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>

Dopo aver salvato tutti i payload, prima dello staging:

Command · bash
git status --short
Uscita
 M index.html
?? .gitignore
?? package-lock.json
?? package.json
?? scripts/
?? site.js
?? styles.css
?? tests/

Le voci della directory script/ e test/ sono raggruppate con stato non tracciato, non con prova che il corpo dei file sia stato rivisto.

Eseguire controlli; non è necessaria alcuna installazione o rete di dipendenze perché questi script utilizzano solo i componenti integrati di Node:

Command · bash
npm run --silent lint
npm test -- --test-reporter=tap
npm run --silent build
git check-ignore dist/index.html

Produzione di lanugine osservata:

Uscita
Source formatting checks passed.

Osservato test-summary excerpt, esclusa la tempistica per test:

Uscita
# tests 6
# suites 0
# pass 6
# fail 0
# cancelled 0
# skipped 0
# todo 0

Compilazione osservata e ignora gli output, un comando ciascuno:

Uscita
Built the static site in dist/.
dist/index.html

Lo script di avvio npm scritto associa il loopback e serve dist. È di lunga durata; non confondere un processo del server con un test superato. Il suo comportamento HTTP live necessita ancora di un controllo dell'ambiente di registrazione; qui non viene affermata alcuna presa del server.

Alternativa stage/commit nativa, solo se l'app non ha già eseguito tali mutazioni:

Command · bash
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

Il commit silenzioso è riuscito silenziosamente; il conteggio stampa 2 e lo stato breve finale è vuoto. La statistica è un ausilio alla revisione, non un sostituto della lettura di tutti e dieci i corpi dei fascicoli. dist viene ignorato, non impegnato; non è stato aggiunto alcun telecomando.

Variante separata di confronto delle immagini

Prepara un copy of this same GitTree Features checkpoint isolato, mai un secondo esempio non correlato o l'originale che continua. Aggiungi asset/diff-card.png con i byte prima, effettua un commit solo per il dispositivo chiaramente etichettato, quindi sostituisci i suoi byte di lavoro con dopo. Nessun file di immagine o supporto finale viene fornito da questi file Markdown.

Entrambi i PNG hanno la metà sinistra blu. Prima ha la metà destra bianca; dopo ha un quarto verde in basso a destra. Byte completi esatti:

VersioneDimensioniByteSHA-256
prima64 × 641629a09ba97c890da0d542166ba17882bea8f7bf9b9bd4f5ec068a156f6b7256773
dopo64 × 641712ddabb4b9859aa53ff9c433a48cb7db0213e184b425a86fef20d8502eed8974f

before — full PNG Base64 bytes

Uscita
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAaUlEQVR4nO3QAQkAAAjAMEtYyr7m0xgi7PACi6yey68LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4D/AAqNletEZdhfWAAAAAElFTkSuQmCC

after — full PNG Base64 bytes

Uscita
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAcklEQVR4nO3QQQ0AIBAEsTOBA9QQ1OANfaCC7INOMgZabeyTPF0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ7f14wOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfABwAT8dDllEqFx1AAAAAElFTkSuQmCC

Un operatore di registrazione può decodificare un payload alla volta nella copia isolata:

Command · bash
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'));"

Sostituisci il segnaposto della parentesi angolare con un carico utile completo, senza parentesi. Decodifica prima, metti in stage/commit il dispositivo, quindi decodifica dopo senza mettere in scena. I conteggi/digest di byte forniti identificano ciascuno stato; non riutilizzare mai uno screenshot di un'immagine fabbricata.

In quella variante, nativa:

Command · bash
git diff --numstat -- assets/diff-card.png

Osservato nella sonda binaria:

Uscita
-	-	assets/diff-card.png

I trattini indicano che Git riporta dati binari, non zero pixel modificati.

Nell'app reale: Show Working Changes → fai clic su asset/diff-card.png in File non messi in scena → Side by side → Swipe, sposta Swipe position con i tasti freccia → Onion skin, cambia After image opacity. Equivalenti della tavolozza: Show Image Changes Side by Side, Show Image Changes with a Swipe, Show Image Changes as Onion Skin. Entrambe le parti devono effettivamente decodificare; assente/troppo grande/non-immagine è uno stato valido diverso, non un motivo per falsificare l'immagine. La sorgente riconosce PNG/JPEG/GIF/WebP, not BMP; al successivo apparecchio LFS BMP non deve essere promessa questa visualizzazione dell'immagine.

Ritorna all'originale, il punto di controllo per la lezione successiva. Il commit/risorse extra della variante dell'immagine non entrano mai nella cronologia canonica.

Risultato

Due commit su main; README più i dieci input dichiarati tracciati; i file indice/di lavoro concordano con HEAD; il dist generato può esistere ma viene ignorato. Nessun dispositivo per l'immagine o remoto nell'albero canonico.

Errori comuni

  • Svuota il differenziale ordinario mentre i nuovi file non vengono tracciati: controlla lo stato e le aggiunte graduali.
  • Lettura --stat come correttezza: ispeziona il contenuto effettivo ed entrambi gli endpoint di confronto.
  • Trattare l'occultamento degli spazi bianchi come l'eliminazione degli spazi bianchi: è solo una vista.
  • Impegno dist o del dispositivo lato immagine: metti in scena l'esatto elenco canonico.

Se qualcosa va storto

Un lint/test/build fallito è un segnale reale; mantenere il suo output e correggere solo l'input demo indicato. Non saltare i controlli o eliminare cartelle sconosciute. Un'immagine bloccata/non supportata dovrebbe rimanere un avviso onesto di formato/dimensione finché il suo formato/dimensione effettiva non viene riconciliato. Annulla una richiesta di selezione parziale obsoleta e ricarica la differenza corrente invece di forzare una patch.

Controlla la tua comprensione

Rispondi a ciascuna domanda, quindi leggi il motivo. Le domande contrassegnate come "Obbligatorio" contano ai fini del completamento della lezione.

  1. Domanda 1 di 6

    Cosa confronta il normale git diff?

    Scegli una risposta.

  2. Domanda 2 di 6

    Quali azioni lasciano invariati gli snapshot del repository?

    Scegli ogni risposta applicabile.

  3. Domanda 3 di 6
    Obbligatorio

    Il nuovo site.js non è tracciato. Il differenziale ordinario è vuoto per questo. È assente?

    Scegli una risposta.

  4. Domanda 4 di 6
    Obbligatorio

    Se si mette in scena il nuovo file, dove è possibile rivedere la sua aggiunta completa?

    Scegli una risposta.

  5. Domanda 5 di 6

    Image numstat stampa due trattini. Cosa puoi concludere?

    Scegli una risposta.

  6. Domanda 6 di 6
    Obbligatorio

    Verificare il checkpoint completato. Quali fatti sono richiesti insieme?

    Scegli ogni risposta applicabile.

0 di 6 corretto

Rispondi correttamente alle domande richieste per completare la lezione.

Controllato in questo browser.

Pratica

Nell'originale, verificare il conteggio 2, svuotare il diff funzionante/memorizzato nella cache e ignorare il dist. Nella variante dell'immagine separata, indica quale quadrante è cambiato e perché il numstat nativo riporta i trattini. Input modificato: se un nuovo file rimane non tracciato anziché messo in scena, prevede che il diff ordinario possa ancora ometterlo.

La tua conferma: il sito non può vedere il tuo computer.

Per completare la lezione rispondere correttamente alle domande richieste e confermare l'esercizio pratico.

Riepilogo

  • Assegna un nome a entrambi gli endpoint prima di leggere una differenza.
  • Le visualizzazioni di testo, binarie e immagini decodificate forniscono prove diverse.
  • Controlli e messa in scena esatta proteggono il checkpoint percorribile.

Termini del glossario introdotti

Diff: فروق; pezzo: كتلة; indice: الفهرس; albero funzionante — مجلد العمل; binario: ثنائي; non tracciato — غير مُتتبَّع.

Trascrizione video

La narrazione del video, spunto per spunto.

Mostra la trascrizione
  1. Leggi il confronto prima di giudicare il cambiamento.
  2. La linea successiva dell'eroe è ancora contenuto funzionante, non un nuovo commit.
  3. Differenze ordinarie e graduali confrontare diverse istantanee.
  4. Aggiungi gli input eseguibili completi, mantenendo la modifica della linea di supporto esistente.
  5. Nuovi file possono mancare dall'ordinario diff finché non entrano nell'indice.
  6. Mettere in scena gli input dichiarati, output di build non generato.
  7. Il layout cambia il tuo vista, non i byte confrontati.
  8. Segui il testo circostante prima interpretare un'aggiunta o una rimozione.
  9. Nascondere gli spazi bianchi non lo è eliminando una modifica di spazio bianco.
  10. Esegui la formattazione locale controllare prima di impegnarsi.
  11. Tutte e sei le validazioni degli input i test passano in questo dispositivo.
  12. L'output della build appartiene a directory ignorata, non il commit.
  13. Impegna la revisione progetto eseguibile localmente.
  14. Verifica due commit e no differenza tracciata rimanente.
  15. Utilizzare una copia separata per il confronto delle immagini, non il checkpoint continuo.
  16. I due payload PNG esatti identificare gli stati dell'immagine.
  17. Confronta i lati nominati e le loro reali dimensioni.
  18. Spostare il divisore senza modificando uno dei due file.
  19. L'opacità cambia il confronto, non i pixel salvati.
  20. Il riepilogo binario di Git non lo è un conteggio di pixel modificati.
  21. Un file non supportato o di grandi dimensioni deve mantenere la sua onesta comunicazione.
  22. Conservare l'apparecchio per l'immagine fuori dalla storia canonica.
  23. Prevedere quale confronto mostra un file appena messo in scena.
  24. Quindi, seleziona pezzi e linee senza scartare altri lavori.