Passer au contenu
GitTree

Leçon 6 · Travail quotidien

Lisez la comparaison avant de juger un changement

Transformez le héros en un projet statique exécutable, puis distinguez les différences de travail, mises en scène et enregistrées. Inspectez une variante d’image déterministe distincte sans ajouter de validation d’image à l’historique continu du cours.

Progression enregistrée dans ce navigateur.

La lecture charge la vidéo depuis YouTube (mode de confidentialité amélioré).

Narration en anglais · English and Arabic légendes

Ouvrez la page vidéoRegarder sur YouTube

Ce que vous apprendrez

  • Nommer les deux côtés d’une comparaison de texte et interpréter les ajouts/suppressions.
  • Expliquez pourquoi un fichier non suivi peut être absent du git diff ordinaire.
  • Comparez les images visuellement sans prétendre que Git fournit un patch d'image textuelle.
  • Ajoutez et vérifiez les petites vérifications locales avant de valider la page exécutable.

Avant de commencer

Vous commencez là où la leçon 5 s'est terminée : la leçon principale originale avec un engagement de héros. HEAD/index contient HTML-01 ; working index.html contient HTML-01-WORKING. Aucune télécommande n'existe. Conservez cette modification de ligne de support dans HTML-02 ; ne le jetez pas.

La vidéo a été enregistrée avec Git 2.52.0, Node 22.22.0, npm 10.9.4 et GitTree 2.0 sur Ubuntu 24.04 : les dix fichiers ont été enregistrés dans le propre éditeur de GitTree, préparés et validés dans l'application, et les vérifications du terminal ont été effectuées par rapport à ce que l'application a créé, ou par rapport à des copies distinctes pour l'état avant la mise en scène et pour l'image. Les vérifications Node ont réussi sur le nœud 22, la version déclarée par le projet. Rien n'a été exécuté sur macOS ou Windows, et Ubuntu est le seul système Linux enregistré. L'étage Git inspecté de GitTree est 2.39.0. Une fois que vous êtes connecté à GitTree, Git local est sur le plan gratuit et n'a besoin d'aucun fournisseur ni d'informations d'identification d'API.

Concept

Une différence répond à une question sur two snapshots, et non à savoir si un fichier est « bon ». Un git diff ordinaire compare index → ​​arbre de travail ; git diff --cached compare HEAD → index ; git diff HEAD compare HEAD → arbre de travail. Un plus marque le nouveau texte et un moins marque l'ancien texte, et non l'approbation ou le blâme. Lisez Référence diff de Git pour la sémantique de comparaison.

Un fichier non suivi n'a pas d'entrée d'index ordinaire. Un diff ordinaire vide ne prouve donc pas qu'aucun nouveau fichier n'existe. Vérifiez également l'état et le contenu des fichiers nouvellement ajoutés. Après avoir préparé un nouveau fichier, son ajout complet peut être examiné dans la comparaison mise en cache.

La modification d'Inline/Split/Hunk, d'habillage, de mode image ou d'affichage d'espaces cachés modifie le view, et non les octets du fichier, l'index, les validations ou les références distantes. La mise en scène modifie l'index. Le commit normal final déplace le principal local ; aucun changement d'état du serveur.

Entrées de projet entièrement exécutables

Gardez le fichier README-01 inchangé. Remplacez index.html par HTML-02 et créez tous les fichiers restants ci-dessous avec UTF-8/LF et une nouvelle ligne finale. Le .gitignore minimal est intentionnel : la sortie de build ne doit pas entrer accidentellement dans ce premier commit exécutable. Une politique d’ignorance plus large vient plus tard. Il s'agit de charges utiles de documents de cours, et non de fichiers d'application installés dans le référentiel Web.

index.html — HTML-02

Extrait de fichier · 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>

styles.css — CSS-01

Extrait de fichier · 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;
}

site.js — JS-01

Extrait de fichier · 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';
    });
  }
}

package.json — PAQUET-01

Extrait de fichier · 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"
  }
}

package-lock.json — LOCK-01

Extrait de fichier · 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

Extrait de fichier · 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);
});

scripts/lint.mjs — LINT-01

Extrait de fichier · 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 — CONSTRUIRE-01

Extrait de fichier · 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');

scripts/serve.mjs — SERVER-01

Extrait de fichier · 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 — IGNORER-CONSTRUCTION

Extrait de fichier · gitignore
dist/

Dans GitTree

  1. Dans le référentiel d'origine, utilisez Command Palette… (Command/Ctrl+Shift+P) → Show Working Changes. Cliquez sur index.html dans Unstaged Files. Avant de le remplacer, identifiez la modification de ligne de support conservée de la leçon 5.
  2. Utilisez Show Files (Commande/Ctrl+Maj+E) ; focus index.html dans l’arborescence des fichiers et appuyez sur Entrée. Remplacez son contenu de travail par HTML-02, puis Save (Command/Ctrl+S dans l'éditeur). Attendez que l'indicateur non enregistré disparaisse.
  3. Pour chaque autre fichier complet ci-dessus : palette New File… → Path from the project folder, tapez le chemin relatif exact à la racine → Create, collez son propre corps complet → Save. Les chemins imbriqués créent leurs répertoires manquants. Le refus d'un fichier existant signifie inspecter ce fichier et non écraser le travail inconnu.
  4. Back to Graph → palette Show Working Changes. Examinez les fichiers non suivis ainsi que index.html. Utilisez Stage File exactement sur les dix chemins modifiés nommés ci-dessus, et non sur la sortie dist générée. Laissez le fichier README existant intact.
  5. Cliquez sur chaque chemin sous Staged Files. Utilisez Hunk, Inline et Split comme disponibles dans Diff view. Les équivalents de palette sont Show Diff as Hunks, Show Diff Inline, Show Diff Side by Side. Next change est F7 ; Previous change est Maj+F7. L'ancien reste à gauche et le nouveau à droite à Split, même en arabe.
  6. Inspectez Ignore whitespace / palette Ignore Whitespace in Diffs, puis restaurez-la. Les espaces cachés ne sont pas un contenu absent ; la sélection partielle peut être indisponible lorsque les modifications des espaces sont masquées. N'utilisez pas de filtre d'affichage comme preuve d'un index propre.
  7. Exécutez les vérifications natives ci-dessous dans le dossier d'origine. Saisissez ensuite le résumé feat: add styling and local project checks, désactivez amend/push/empty/skip-hooks et choisissez Commit Changes to 10 Files. Commande/Ctrl+Entrée est une soumission alternative, pas une deuxième étape. Vérifiez deux commits et nettoyez le statut de suivi.

Dans la borne

Au point de contrôle input, cette requête en lecture seule capture la modification de la leçon 5 encore non validée :

Command · bash
git diff -- index.html

Sortie complète observée :

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

Après avoir enregistré toutes les charges utiles, avant la préparation :

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

Les entrées de répertoire scripts/ et tests/ sont regroupées avec un statut non suivi, ce qui ne prouve pas que le corps de leur fichier a été examiné.

Effectuer des contrôles ; aucune installation de dépendance ou réseau n'est nécessaire car ces scripts utilisent uniquement les éléments intégrés de Node :

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

Sortie de peluches observée :

Sortie
Source formatting checks passed.

Observé test-summary excerpt, à l'exclusion du timing par test :

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

Sorties build et ignore observées, une commande chacune :

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

Le script de démarrage npm écrit lie le bouclage et sert dist. Cela dure depuis longtemps ; ne confondez pas un processus serveur avec un test de réussite. Son comportement HTTP en direct nécessite toujours une vérification de l'environnement d'enregistrement ; aucune prise de serveur n'est affirmée ici.

Alternative d'étape/commit native, uniquement si l'application n'a pas déjà effectué ces mutations :

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

La validation silencieuse a réussi silencieusement ; count prints 2 et le statut court final est vide. La statistique est une aide à la révision et ne remplace pas la lecture des dix corps de fichiers. dist est ignoré, non validé ; aucune télécommande n'a été ajoutée.

Variante de comparaison d'images séparée

Préparez un copy of this same GitTree Features checkpoint isolé, jamais un deuxième exemple sans rapport ou l'original continu. Ajoutez Assets/diff-card.png avec les octets avant, effectuez un commit clairement étiqueté pour les appareils uniquement, puis remplacez ses octets de travail par après. Aucun fichier image ou média final n'est livré par ces fichiers Markdown.

Les deux PNG ont une moitié gauche bleue. Avant a une moitié droite blanche ; après a un quart vert en bas à droite. Octets complets exacts :

VersionDimensionsOctetsSHA-256
avant64 × 641629a09ba97c890da0d542166ba17882bea8f7bf9b9bd4f5ec068a156f6b7256773
après64 × 641712ddabb4b9859aa53ff9c433a48cb7db0213e184b425a86fef20d8502eed8974f

before — full PNG Base64 bytes

Sortie
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAaUlEQVR4nO3QAQkAAAjAMEtYyr7m0xgi7PACi6yey68LAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAA4D/AAqNletEZdhfWAAAAAElFTkSuQmCC

after — full PNG Base64 bytes

Sortie
iVBORw0KGgoAAAANSUhEUgAAAEAAAABACAYAAACqaXHeAAAAcklEQVR4nO3QQQ0AIBAEsTOBA9QQ1OANfaCC7INOMgZabeyTPF0BAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAJ7f14wOAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAfABwAT8dDllEqFx1AAAAAElFTkSuQmCC

Un opérateur d'enregistrement peut décoder une charge utile à la fois dans la copie isolée :

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

Remplacez l'espace réservé du support d'angle par une charge utile complète, sans les supports. Décodez avant, préparez/commettez le luminaire, puis décodez après sans mise en scène. Les décomptes/résumés d’octets fournis identifient chaque état ; ne réutilisez jamais une capture d’écran d’image fabriquée.

Dans cette variante, native :

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

Observé dans la sonde binaire :

Sortie
-	-	assets/diff-card.png

Les tirets signifient que Git rapporte des données binaires, et non aucun pixel modifié.

Dans la vraie application : Show Working Changes → cliquez sur assets/diff-card.png dans Unstaged Files → Side by side → Swipe, déplacez Swipe position avec les touches fléchées → Onion skin, modifiez After image opacity. Équivalents de palette : Show Image Changes Side by Side, Show Image Changes with a Swipe, Show Image Changes as Onion Skin. Les deux côtés doivent réellement décoder ; absent/trop grand/pas une image est un état valide différent, pas une raison pour simuler l'image. La source reconnaît PNG/JPEG/GIF/WebP, not BMP ; le dernier appareil LFS BMP ne doit pas se voir promettre cette vue d'image.

Revenez à l'original, le point de contrôle pour la leçon suivante. Les commits/actifs supplémentaires de la variante d'image n'entrent jamais dans l'historique canonique.

Résultat

Deux commits sur main ; README plus les dix entrées déclarées suivies ; les fichiers d'index/de travail sont conformes à HEAD ; La distribution générée peut exister mais est ignorée. Aucun appareil d'image ni télécommande dans l'arborescence canonique.

Erreurs courantes

  • Videz les différences ordinaires pendant que les nouveaux fichiers ne sont pas suivis : inspectez l'état et les ajouts par étapes.
  • Lecture de --stat comme étant correct : inspectez le contenu réel et les deux points finaux de comparaison.
  • Traiter le masquage des espaces comme la suppression des espaces : ce n'est qu'une vue.
  • Validation de dist ou du luminaire côté image : mettez en scène la liste canonique exacte.

Si quelque chose ne va pas

Un échec de lint/test/build est un vrai signal ; conserver sa sortie et corriger uniquement l'entrée de démonstration indiquée. Ne sautez pas les vérifications et ne supprimez pas les dossiers inconnus. Une image bloquée/non prise en charge doit rester un avis binaire/taille honnête jusqu'à ce que son format/taille réel soit réconcilié. Annulez une demande de sélection partielle obsolète et rechargez la comparaison actuelle plutôt que de forcer un correctif.

Vérifiez votre compréhension

Répondez à chaque question, puis lisez pourquoi. Les questions marquées « Obligatoire » comptent pour terminer la leçon.

  1. Question 1 de 6

    À quoi se compare le git diff ordinaire ?

    Choisissez une réponse.

  2. Question 2 de 6

    Quelles actions laissent les instantanés du référentiel inchangés ?

    Choisissez chaque réponse qui s'applique.

  3. Question 3 de 6
    Obligatoire

    Le nouveau site.js n'est pas suivi. Le diff ordinaire est vide pour cela. Est-il absent ?

    Choisissez une réponse.

  4. Question 4 de 6
    Obligatoire

    Si vous préparez ce nouveau fichier, où son ajout complet peut-il être examiné ?

    Choisissez une réponse.

  5. Question 5 de 6

    L'image numstat imprime deux tirets. Que pouvez-vous conclure ?

    Choisissez une réponse.

  6. Question 6 de 6
    Obligatoire

    Vérifiez le point de contrôle terminé. Quels faits sont requis ensemble ?

    Choisissez chaque réponse qui s'applique.

0 sur 6 corrects

Répondez correctement aux questions requises pour terminer la leçon.

Vérifié dans ce navigateur.

Pratique

À l'original, vérifiez le compte 2, le diff de travail/mis en cache vide et la dist ignorée. Dans la variante d'image séparée, nommez quel quadrant a changé et pourquoi numstat natif rapporte des tirets. Entrée modifiée : si un nouveau fichier reste non suivi au lieu d'être mis en scène, prédisez que le diff ordinaire peut toujours l'omettre.

Votre propre confirmation : le site ne peut pas voir votre ordinateur.

Pour terminer la leçon, répondez correctement aux questions demandées et confirmez l'exercice pratique.

Récapitulatif

  • Nommez les deux points de terminaison avant de lire un diff.
  • Les vues de texte, d'images binaires et décodées fournissent des preuves différentes.
  • Les contrôles et la mise en scène exacte protègent le point de contrôle exécutable.

Termes du glossaire introduits

Diff — فروق; morceau — كتلة; index — الفهرس; arbre de travail — مجلد العمل; binaire — ثنائي; non suivi — غير مُتتبَّع.

Transcription vidéo

La narration de la vidéo, repère par repère.

Afficher la transcription
  1. Lire le comparatif avant de juger du changement.
  2. La dernière ligne de héros est toujours contenu de travail, pas un nouveau commit.
  3. Diffs ordinaires et échelonnés comparer différents instantanés.
  4. Ajoutez les entrées exécutables complètes, en gardant la modification de ligne de support existante.
  5. De nouveaux fichiers peuvent manquer dans les fichiers ordinaires diff jusqu'à ce qu'ils entrent dans l'index.
  6. Mettre en scène les entrées déclarées, pas généré de sortie de build.
  7. La mise en page change votre vue, pas les octets comparés.
  8. Suivez le texte environnant avant interpréter un ajout ou une suppression.
  9. Cacher les espaces n'est pas suppression d'un changement d'espace.
  10. Exécutez le formatage local vérifiez avant de vous engager.
  11. Les six entrées-validation les tests réussissent dans ce luminaire.
  12. La sortie de build appartient au répertoire ignoré, pas le commit.
  13. Valider l'examen projet exécutable localement.
  14. Vérifiez deux commits et non différence suivie restante.
  15. Utilisez une copie séparée pour la comparaison des images, pas le point de contrôle continu.
  16. Les deux charges utiles PNG exactes identifier les états de l’image.
  17. Comparez les côtés nommés et leurs dimensions réelles.
  18. Déplacez le diviseur sans changer l'un ou l'autre fichier.
  19. L'opacité change la comparaison, pas les pixels enregistrés.
  20. Le résumé binaire de Git n'est pas un nombre de pixels modifiés.
  21. Un fichier non pris en charge ou surdimensionné doit garder son avis honnête.
  22. Gardez le luminaire d'image en dehors de l'histoire canonique.
  23. Prédire quelle comparaison affiche un fichier récemment mis en scène.
  24. Ensuite, sélectionnez des morceaux et des lignes sans abandonner d'autres travaux.