# 🔍 Diff Engine и слияние данных

CSElement включает мощный движок для вычисления различий между элементами и выполнения трёхстороннего слияния данных.

## 📋 Содержание

- [Основы Diff Engine](#основы-diff-engine)
- [Алгоритмы вычисления различий](#алгоритмы-вычисления-различий)
- [Трёхстороннее слияние](#трёхстороннее-слияние)
- [Визуализация различий](#визуализация-различий)
- [Полный пример](#полный-пример-система-версионирования)

## Основы Diff Engine

### Создание и использование

```typescript
import { 
  DiffEngine, 
  DiffAlgorithm, 
  MergeStrategy,
  DiffResult,
  ThreeWayMergeResult 
} from 'cs-element';

// Создание движка
const diffEngine = new DiffEngine();

// Создание элементов для сравнения
const sourceElement = new CSElement('doc-v1');
await sourceElement.setData('title', 'Документ версии 1');
await sourceElement.setData('content', 'Исходное содержимое документа');
await sourceElement.setData('tags', ['draft', 'important']);

const targetElement = new CSElement('doc-v2');
await targetElement.setData('title', 'Документ версии 2');
await targetElement.setData('content', 'Обновленное содержимое документа');
await targetElement.setData('tags', ['draft', 'important', 'reviewed']);
await targetElement.setData('author', 'John Doe');

// Вычисление различий
const diffResult = diffEngine.computeDiff(sourceElement, targetElement, {
  algorithm: DiffAlgorithm.MYERS,
  ignoreWhitespace: false,
  ignoreCase: false,
  contextLines: 3,
  includeVisualization: true
});

console.log('📊 Результат сравнения:', {
  additions: diffResult.summary.additions,
  deletions: diffResult.summary.deletions,
  modifications: diffResult.summary.modifications
});
```

### Анализ изменений

```typescript
// Подробный анализ изменений
for (const change of diffResult.changes) {
  console.log(`📝 Изменение в ${change.path.join('.')}:`);
  console.log(`  Тип: ${change.type}`);
  console.log(`  Было: ${JSON.stringify(change.oldValue)}`);
  console.log(`  Стало: ${JSON.stringify(change.newValue)}`);
  console.log(`  Уверенность: ${change.confidence}`);
}

// Фильтрация изменений по типу
const additions = diffResult.changes.filter(c => c.type === 'addition');
const deletions = diffResult.changes.filter(c => c.type === 'deletion');
const modifications = diffResult.changes.filter(c => c.type === 'modification');

console.log(`➕ Добавлено: ${additions.length}`);
console.log(`➖ Удалено: ${deletions.length}`);
console.log(`✏️ Изменено: ${modifications.length}`);
```

## Алгоритмы вычисления различий

### Myers Algorithm

```typescript
// Алгоритм Myers (по умолчанию)
const myersDiff = diffEngine.computeDiff(sourceElement, targetElement, {
  algorithm: DiffAlgorithm.MYERS,
  contextLines: 5
});

console.log('Myers Algorithm результат:', myersDiff.summary);
```

### Patience Algorithm

```typescript
// Алгоритм Patience - лучше для структурированных данных
const patienceDiff = diffEngine.computeDiff(sourceElement, targetElement, {
  algorithm: DiffAlgorithm.PATIENCE,
  contextLines: 3
});

console.log('Patience Algorithm результат:', patienceDiff.summary);
```

### Histogram Algorithm

```typescript
// Алгоритм Histogram - оптимизированная версия Patience
const histogramDiff = diffEngine.computeDiff(sourceElement, targetElement, {
  algorithm: DiffAlgorithm.HISTOGRAM,
  contextLines: 3
});

console.log('Histogram Algorithm результат:', histogramDiff.summary);
```

### Сравнение алгоритмов

```typescript
class DiffAlgorithmComparator {
  private diffEngine: DiffEngine;

  constructor() {
    this.diffEngine = new DiffEngine();
  }

  async compareAlgorithms(
    sourceElement: CSElement,
    targetElement: CSElement
  ): Promise<{
    myers: DiffResult;
    patience: DiffResult;
    histogram: DiffResult;
    simple: DiffResult;
    comparison: {
      algorithm: string;
      executionTime: number;
      changesCount: number;
      accuracy: number;
    }[];
  }> {
    const algorithms = [
      DiffAlgorithm.MYERS,
      DiffAlgorithm.PATIENCE,
      DiffAlgorithm.HISTOGRAM,
      DiffAlgorithm.SIMPLE
    ];

    const results: Record<string, DiffResult> = {};
    const comparison = [];

    for (const algorithm of algorithms) {
      const startTime = Date.now();
      
      const result = this.diffEngine.computeDiff(sourceElement, targetElement, {
        algorithm,
        contextLines: 3,
        includeVisualization: false
      });

      const executionTime = Date.now() - startTime;
      const changesCount = result.changes.length;
      const accuracy = this.calculateAccuracy(result);

      results[algorithm] = result;
      comparison.push({
        algorithm,
        executionTime,
        changesCount,
        accuracy
      });
    }

    return {
      myers: results[DiffAlgorithm.MYERS],
      patience: results[DiffAlgorithm.PATIENCE],
      histogram: results[DiffAlgorithm.HISTOGRAM],
      simple: results[DiffAlgorithm.SIMPLE],
      comparison
    };
  }

  private calculateAccuracy(result: DiffResult): number {
    // Простая метрика точности на основе уверенности в изменениях
    const totalConfidence = result.changes.reduce((sum, change) => sum + change.confidence, 0);
    return result.changes.length > 0 ? totalConfidence / result.changes.length : 1;
  }
}

// Использование сравнения
const comparator = new DiffAlgorithmComparator();
const comparison = await comparator.compareAlgorithms(sourceElement, targetElement);

console.log('📊 Сравнение алгоритмов:', comparison.comparison);
```

## Трёхстороннее слияние

### Основы слияния

```typescript
// Создание базовой версии
const baseElement = new CSElement('doc-base');
await baseElement.setData('title', 'Базовый документ');
await baseElement.setData('content', 'Базовое содержимое');
await baseElement.setData('version', 1);

// Создание ветки A
const branchA = new CSElement('doc-branch-a');
await branchA.setData('title', 'Документ ветки A');
await branchA.setData('content', 'Содержимое изменено в ветке A');
await branchA.setData('version', 2);
await branchA.setData('author', 'Alice');

// Создание ветки B
const branchB = new CSElement('doc-branch-b');
await branchB.setData('title', 'Базовый документ');
await branchB.setData('content', 'Базовое содержимое');
await branchB.setData('version', 2);
await branchB.setData('reviewer', 'Bob');

// Выполнение трёхстороннего слияния
const mergeResult = diffEngine.threeWayMerge(baseElement, branchA, branchB, {
  strategy: MergeStrategy.AUTO,
  conflictResolution: 'auto',
  autoResolveThreshold: 0.8
});

console.log('🔀 Результат слияния:', {
  success: mergeResult.success,
  autoResolved: mergeResult.autoResolved,
  manualRequired: mergeResult.manualRequired,
  conflicts: mergeResult.conflicts.length
});
```

### Стратегии слияния

```typescript
// Автоматическое слияние
const autoMerge = diffEngine.threeWayMerge(baseElement, branchA, branchB, {
  strategy: MergeStrategy.AUTO
});

// Приоритет нашей ветки
const oursMerge = diffEngine.threeWayMerge(baseElement, branchA, branchB, {
  strategy: MergeStrategy.OURS
});

// Приоритет их ветки
const theirsMerge = diffEngine.threeWayMerge(baseElement, branchA, branchB, {
  strategy: MergeStrategy.THEIRS
});

// Объединение всех изменений
const unionMerge = diffEngine.threeWayMerge(baseElement, branchA, branchB, {
  strategy: MergeStrategy.UNION
});

console.log('📊 Сравнение стратегий:', {
  auto: autoMerge.success,
  ours: oursMerge.success,
  theirs: theirsMerge.success,
  union: unionMerge.success
});
```

### Разрешение конфликтов

```typescript
class ConflictResolver {
  private diffEngine: DiffEngine;

  constructor() {
    this.diffEngine = new DiffEngine();
  }

  async resolveConflicts(
    baseElement: CSElement,
    sourceElement: CSElement,
    targetElement: CSElement,
    userPreferences: {
      preferSource?: boolean;
      preferTarget?: boolean;
      autoResolveSimple?: boolean;
      customRules?: Array<{
        path: string[];
        strategy: 'source' | 'target' | 'merge' | 'custom';
        customResolver?: (sourceValue: any, targetValue: any, baseValue: any) => any;
      }>;
    } = {}
  ): Promise<{
    mergedElement: CSElement;
    resolvedConflicts: number;
    remainingConflicts: number;
    resolutionLog: string[];
  }> {
    const mergeResult = this.diffEngine.threeWayMerge(baseElement, sourceElement, targetElement, {
      strategy: MergeStrategy.MANUAL
    });

    const resolutionLog: string[] = [];
    let resolvedConflicts = 0;
    let remainingConflicts = 0;

    // Создаем результирующий элемент
    const mergedElement = new CSElement(`merged-${Date.now()}`);
    
    // Копируем базовые данные
    const baseData = baseElement.serialize({ includeChildren: true, includeData: true });
    await this.copyDataToElement(mergedElement, baseData);

    // Обрабатываем конфликты
    for (const conflict of mergeResult.conflicts) {
      const resolved = await this.resolveConflict(
        conflict,
        mergedElement,
        userPreferences,
        resolutionLog
      );

      if (resolved) {
        resolvedConflicts++;
      } else {
        remainingConflicts++;
      }
    }

    return {
      mergedElement,
      resolvedConflicts,
      remainingConflicts,
      resolutionLog
    };
  }

  private async resolveConflict(
    conflict: any,
    mergedElement: CSElement,
    userPreferences: any,
    resolutionLog: string[]
  ): Promise<boolean> {
    const path = conflict.path;
    const pathStr = path.join('.');

    // Проверяем пользовательские правила
    const customRule = userPreferences.customRules?.find(
      (rule: any) => rule.path.join('.') === pathStr
    );

    if (customRule) {
      return await this.applyCustomRule(conflict, mergedElement, customRule, resolutionLog);
    }

    // Автоматическое разрешение простых конфликтов
    if (userPreferences.autoResolveSimple && conflict.severity === 'low') {
      return await this.autoResolveSimpleConflict(conflict, mergedElement, resolutionLog);
    }

    // Применяем общие предпочтения
    if (userPreferences.preferSource) {
      await this.setValueByPath(mergedElement, path, conflict.sourceValue);
      resolutionLog.push(`✅ Конфликт в ${pathStr} разрешен в пользу источника`);
      return true;
    }

    if (userPreferences.preferTarget) {
      await this.setValueByPath(mergedElement, path, conflict.targetValue);
      resolutionLog.push(`✅ Конфликт в ${pathStr} разрешен в пользу цели`);
      return true;
    }

    // Конфликт не разрешен
    resolutionLog.push(`⚠️ Конфликт в ${pathStr} требует ручного разрешения`);
    return false;
  }

  private async applyCustomRule(
    conflict: any,
    mergedElement: CSElement,
    rule: any,
    resolutionLog: string[]
  ): Promise<boolean> {
    const pathStr = conflict.path.join('.');

    try {
      let resolvedValue;

      switch (rule.strategy) {
        case 'source':
          resolvedValue = conflict.sourceValue;
          break;
        case 'target':
          resolvedValue = conflict.targetValue;
          break;
        case 'merge':
          resolvedValue = this.mergeValues(conflict.sourceValue, conflict.targetValue);
          break;
        case 'custom':
          if (rule.customResolver) {
            resolvedValue = rule.customResolver(
              conflict.sourceValue,
              conflict.targetValue,
              conflict.baseValue
            );
          } else {
            return false;
          }
          break;
        default:
          return false;
      }

      await this.setValueByPath(mergedElement, conflict.path, resolvedValue);
      resolutionLog.push(`✅ Конфликт в ${pathStr} разрешен пользовательским правилом (${rule.strategy})`);
      return true;

    } catch (error) {
      resolutionLog.push(`❌ Ошибка применения правила для ${pathStr}: ${error}`);
      return false;
    }
  }

  private async autoResolveSimpleConflict(
    conflict: any,
    mergedElement: CSElement,
    resolutionLog: string[]
  ): Promise<boolean> {
    const pathStr = conflict.path.join('.');

    // Простые стратегии автоматического разрешения
    if (conflict.type === 'content' && typeof conflict.sourceValue === 'string' && typeof conflict.targetValue === 'string') {
      // Объединяем строки
      const mergedValue = `${conflict.sourceValue} ${conflict.targetValue}`;
      await this.setValueByPath(mergedElement, conflict.path, mergedValue);
      resolutionLog.push(`✅ Строковый конфликт в ${pathStr} разрешен объединением`);
      return true;
    }

    if (conflict.type === 'structure' && Array.isArray(conflict.sourceValue) && Array.isArray(conflict.targetValue)) {
      // Объединяем массивы
      const mergedArray = [...new Set([...conflict.sourceValue, ...conflict.targetValue])];
      await this.setValueByPath(mergedElement, conflict.path, mergedArray);
      resolutionLog.push(`✅ Конфликт массивов в ${pathStr} разрешен объединением`);
      return true;
    }

    return false;
  }

  private mergeValues(sourceValue: any, targetValue: any): any {
    if (Array.isArray(sourceValue) && Array.isArray(targetValue)) {
      return [...new Set([...sourceValue, ...targetValue])];
    }

    if (typeof sourceValue === 'object' && typeof targetValue === 'object') {
      return { ...sourceValue, ...targetValue };
    }

    if (typeof sourceValue === 'string' && typeof targetValue === 'string') {
      return `${sourceValue} ${targetValue}`;
    }

    // По умолчанию возвращаем значение цели
    return targetValue;
  }

  private async copyDataToElement(element: CSElement, data: any): Promise<void> {
    if (data.data) {
      for (const [key, value] of Object.entries(data.data)) {
        await element.setData(key, value);
      }
    }
  }

  private async setValueByPath(element: CSElement, path: string[], value: any): Promise<void> {
    if (path.length === 1) {
      await element.setData(path[0], value);
    } else {
      // Для вложенных путей нужна более сложная логика
      // В данном примере упрощено
      await element.setData(path.join('.'), value);
    }
  }
}
```

## Визуализация различий

### Генерация визуального представления

```typescript
// Получение визуализации различий
const diffWithVisualization = diffEngine.computeDiff(sourceElement, targetElement, {
  algorithm: DiffAlgorithm.MYERS,
  includeVisualization: true
});

if (diffWithVisualization.visualization) {
  console.log('📊 Визуализация различий:');
  console.log(diffWithVisualization.visualization);
}

// Создание HTML отчета
class DiffReportGenerator {
  generateHtmlReport(diffResult: DiffResult): string {
    const html = `
      <!DOCTYPE html>
      <html>
      <head>
        <title>Отчет о различиях</title>
        <style>
          body { font-family: Arial, sans-serif; margin: 20px; }
          .summary { background: #f5f5f5; padding: 15px; border-radius: 5px; margin-bottom: 20px; }
          .change { margin: 10px 0; padding: 10px; border-radius: 3px; }
          .addition { background: #d4edda; border-left: 4px solid #28a745; }
          .deletion { background: #f8d7da; border-left: 4px solid #dc3545; }
          .modification { background: #fff3cd; border-left: 4px solid #ffc107; }
          .path { font-weight: bold; color: #495057; }
          .value { font-family: monospace; background: #e9ecef; padding: 2px 4px; border-radius: 2px; }
        </style>
      </head>
      <body>
        <h1>Отчет о различиях</h1>
        
        <div class="summary">
          <h2>Сводка</h2>
          <p>Добавлено: ${diffResult.summary.additions}</p>
          <p>Удалено: ${diffResult.summary.deletions}</p>
          <p>Изменено: ${diffResult.summary.modifications}</p>
        </div>
        
        <div class="changes">
          <h2>Изменения</h2>
          ${diffResult.changes.map(change => `
            <div class="change ${change.type}">
              <div class="path">${change.path.join('.')}</div>
              <div>Тип: ${change.type}</div>
              ${change.oldValue !== undefined ? `<div>Было: <span class="value">${JSON.stringify(change.oldValue)}</span></div>` : ''}
              ${change.newValue !== undefined ? `<div>Стало: <span class="value">${JSON.stringify(change.newValue)}</span></div>` : ''}
              <div>Уверенность: ${(change.confidence * 100).toFixed(1)}%</div>
            </div>
          `).join('')}
        </div>
      </body>
      </html>
    `;

    return html;
  }

  generateMarkdownReport(diffResult: DiffResult): string {
    const markdown = `
# Отчет о различиях

## Сводка

- **Добавлено:** ${diffResult.summary.additions}
- **Удалено:** ${diffResult.summary.deletions}
- **Изменено:** ${diffResult.summary.modifications}

## Изменения

${diffResult.changes.map(change => `
### ${change.path.join('.')}

- **Тип:** ${change.type}
${change.oldValue !== undefined ? `- **Было:** \`${JSON.stringify(change.oldValue)}\`` : ''}
${change.newValue !== undefined ? `- **Стало:** \`${JSON.stringify(change.newValue)}\`` : ''}
- **Уверенность:** ${(change.confidence * 100).toFixed(1)}%

`).join('')}
    `;

    return markdown.trim();
  }
}

// Использование генератора отчетов
const reportGenerator = new DiffReportGenerator();
const htmlReport = reportGenerator.generateHtmlReport(diffResult);
const markdownReport = reportGenerator.generateMarkdownReport(diffResult);

console.log('📄 HTML отчет создан');
console.log('📝 Markdown отчет создан');
```

## Полный пример: Система версионирования

```typescript
class VersionControlSystem {
  private diffEngine: DiffEngine;
  private conflictResolver: ConflictResolver;
  private versions: Map<string, CSElement> = new Map();
  private branches: Map<string, string[]> = new Map(); // branch -> version ids

  constructor() {
    this.diffEngine = new DiffEngine();
    this.conflictResolver = new ConflictResolver();
    this.branches.set('main', []);
  }

  async createVersion(
    documentId: string,
    data: any,
    parentVersionId?: string
  ): Promise<string> {
    const versionId = `${documentId}-v${Date.now()}`;
    
    const element = new CSElement(versionId);
    await element.setData('documentId', documentId);
    await element.setData('versionId', versionId);
    await element.setData('parentVersionId', parentVersionId);
    await element.setData('createdAt', new Date().toISOString());
    await element.setData('data', data);

    this.versions.set(versionId, element);
    
    // Добавляем в основную ветку
    if (!this.branches.get('main')?.includes(versionId)) {
      this.branches.get('main')?.push(versionId);
    }

    console.log(`📄 Создана версия ${versionId}`);
    return versionId;
  }

  async createBranch(branchName: string, fromVersionId: string): Promise<void> {
    if (this.branches.has(branchName)) {
      throw new Error(`Ветка ${branchName} уже существует`);
    }

    this.branches.set(branchName, [fromVersionId]);
    console.log(`🌿 Создана ветка ${branchName} от версии ${fromVersionId}`);
  }

  async commitToBranch(
    branchName: string,
    documentId: string,
    data: any
  ): Promise<string> {
    const branch = this.branches.get(branchName);
    if (!branch) {
      throw new Error(`Ветка ${branchName} не найдена`);
    }

    const parentVersionId = branch[branch.length - 1];
    const versionId = await this.createVersion(documentId, data, parentVersionId);
    
    branch.push(versionId);
    console.log(`💾 Коммит ${versionId} в ветку ${branchName}`);
    
    return versionId;
  }

  async compareVersions(
    version1Id: string,
    version2Id: string
  ): Promise<{
    diffResult: DiffResult;
    htmlReport: string;
    markdownReport: string;
  }> {
    const version1 = this.versions.get(version1Id);
    const version2 = this.versions.get(version2Id);

    if (!version1 || !version2) {
      throw new Error('Одна из версий не найдена');
    }

    const diffResult = this.diffEngine.computeDiff(version1, version2, {
      algorithm: DiffAlgorithm.MYERS,
      includeVisualization: true
    });

    const reportGenerator = new DiffReportGenerator();
    const htmlReport = reportGenerator.generateHtmlReport(diffResult);
    const markdownReport = reportGenerator.generateMarkdownReport(diffResult);

    return {
      diffResult,
      htmlReport,
      markdownReport
    };
  }

  async mergeBranches(
    sourceBranch: string,
    targetBranch: string,
    conflictResolutionStrategy: {
      preferSource?: boolean;
      preferTarget?: boolean;
      autoResolveSimple?: boolean;
    } = {}
  ): Promise<{
    success: boolean;
    mergedVersionId?: string;
    conflicts: number;
    resolutionLog: string[];
  }> {
    const sourceBranchVersions = this.branches.get(sourceBranch);
    const targetBranchVersions = this.branches.get(targetBranch);

    if (!sourceBranchVersions || !targetBranchVersions) {
      throw new Error('Одна из веток не найдена');
    }

    // Находим общего предка
    const commonAncestor = this.findCommonAncestor(sourceBranchVersions, targetBranchVersions);
    if (!commonAncestor) {
      throw new Error('Не найден общий предок веток');
    }

    const baseElement = this.versions.get(commonAncestor)!;
    const sourceElement = this.versions.get(sourceBranchVersions[sourceBranchVersions.length - 1])!;
    const targetElement = this.versions.get(targetBranchVersions[targetBranchVersions.length - 1])!;

    // Выполняем слияние
    const mergeResult = await this.conflictResolver.resolveConflicts(
      baseElement,
      sourceElement,
      targetElement,
      conflictResolutionStrategy
    );

    if (mergeResult.remainingConflicts === 0) {
      // Создаем новую версию с результатом слияния
      const documentId = await sourceElement.getData('documentId') as string;
      const mergedData = await mergeResult.mergedElement.getData('data');
      
      const mergedVersionId = await this.createVersion(
        documentId,
        mergedData,
        targetElement.id
      );

      // Добавляем в целевую ветку
      targetBranchVersions.push(mergedVersionId);

      return {
        success: true,
        mergedVersionId,
        conflicts: mergeResult.resolvedConflicts,
        resolutionLog: mergeResult.resolutionLog
      };
    } else {
      return {
        success: false,
        conflicts: mergeResult.remainingConflicts,
        resolutionLog: mergeResult.resolutionLog
      };
    }
  }

  private findCommonAncestor(branch1: string[], branch2: string[]): string | null {
    // Упрощенная реализация - находим первую общую версию
    for (const version1 of branch1) {
      if (branch2.includes(version1)) {
        return version1;
      }
    }
    return null;
  }

  async getBranchHistory(branchName: string): Promise<Array<{
    versionId: string;
    createdAt: string;
    parentVersionId?: string;
    summary: string;
  }>> {
    const branch = this.branches.get(branchName);
    if (!branch) {
      throw new Error(`Ветка ${branchName} не найдена`);
    }

    const history = [];
    for (const versionId of branch) {
      const version = this.versions.get(versionId);
      if (version) {
        const createdAt = await version.getData('createdAt') as string;
        const parentVersionId = await version.getData('parentVersionId') as string;
        const data = await version.getData('data') as any;
        
        history.push({
          versionId,
          createdAt,
          parentVersionId,
          summary: this.generateVersionSummary(data)
        });
      }
    }

    return history;
  }

  private generateVersionSummary(data: any): string {
    if (data.title) {
      return `Документ: ${data.title}`;
    }
    return `Версия с ${Object.keys(data).length} полями`;
  }

  async exportBranch(branchName: string): Promise<Blob> {
    const history = await this.getBranchHistory(branchName);
    const exportData = {
      branchName,
      history,
      exportedAt: new Date().toISOString()
    };

    return new Blob([JSON.stringify(exportData, null, 2)], {
      type: 'application/json'
    });
  }
}

// Демонстрация использования
async function demonstrateVersionControl() {
  const vcs = new VersionControlSystem();

  try {
    // Создаем начальную версию
    const v1 = await vcs.createVersion('doc-1', {
      title: 'Мой документ',
      content: 'Исходное содержимое',
      tags: ['draft']
    });

    // Создаем ветку для разработки
    await vcs.createBranch('feature', v1);

    // Делаем изменения в основной ветке
    const v2 = await vcs.commitToBranch('main', 'doc-1', {
      title: 'Мой документ',
      content: 'Обновленное содержимое',
      tags: ['draft', 'updated'],
      author: 'Alice'
    });

    // Делаем изменения в ветке feature
    const v3 = await vcs.commitToBranch('feature', 'doc-1', {
      title: 'Мой документ (feature)',
      content: 'Исходное содержимое с новой функцией',
      tags: ['draft', 'feature'],
      feature: 'new-feature'
    });

    // Сравниваем версии
    const comparison = await vcs.compareVersions(v2, v3);
    console.log('📊 Сравнение версий:', comparison.diffResult.summary);

    // Пытаемся слить ветки
    const mergeResult = await vcs.mergeBranches('feature', 'main', {
      autoResolveSimple: true,
      preferTarget: false
    });

    console.log('🔀 Результат слияния:', {
      success: mergeResult.success,
      conflicts: mergeResult.conflicts,
      mergedVersionId: mergeResult.mergedVersionId
    });

    // Получаем историю
    const mainHistory = await vcs.getBranchHistory('main');
    console.log('📋 История main:', mainHistory);

    // Экспортируем ветку
    const exportBlob = await vcs.exportBranch('main');
    console.log(`📦 Экспорт ветки готов, размер: ${exportBlob.size} байт`);

  } catch (error) {
    console.error('❌ Ошибка в системе версионирования:', error);
  }
}

demonstrateVersionControl().catch(console.error);
```

## 🎯 Заключение

Diff Engine в CSElement обеспечивает:

- **🔍 Точное сравнение** - множество алгоритмов для различных сценариев
- **🔀 Умное слияние** - автоматическое и ручное разрешение конфликтов
- **📊 Визуализация** - наглядное представление различий
- **⚡ Производительность** - оптимизированные алгоритмы для больших данных
- **🛠️ Гибкость** - настраиваемые стратегии слияния

---

**Следующий раздел:** [Blueprint система шаблонов →](13-blueprint-system.md) 