fetchGitDiff function

Future<GitDiffResult?> fetchGitDiff({
  1. String? cwd,
})

Fetch git diff stats comparing working tree to HEAD. Returns null if not in a git repo or during transient git states.

Implementation

Future<GitDiffResult?> fetchGitDiff({String? cwd}) async {
  if (!await getIsGit(cwd: cwd)) return null;

  if (await _isInTransientGitState(cwd: cwd)) return null;

  // Quick probe with --shortstat
  final shortstat = await _runGit([
    '--no-optional-locks',
    'diff',
    'HEAD',
    '--shortstat',
  ], cwd: cwd);
  if (shortstat.code == 0) {
    final quickStats = parseShortstat(shortstat.stdout);
    if (quickStats != null && quickStats.filesCount > _maxFilesForDetails) {
      return GitDiffResult(stats: quickStats, perFileStats: {}, hunks: {});
    }
  }

  // Get stats via --numstat
  final numstat = await _runGit([
    '--no-optional-locks',
    'diff',
    'HEAD',
    '--numstat',
  ], cwd: cwd);
  if (numstat.code != 0) return null;

  final result = parseGitNumstat(numstat.stdout);
  final stats = GitDiffStats(
    filesCount: result.stats.filesCount,
    linesAdded: result.stats.linesAdded,
    linesRemoved: result.stats.linesRemoved,
  );
  final perFileStats = Map<String, PerFileStats>.from(result.perFileStats);

  // Include untracked files
  final remainingSlots = _maxFiles - perFileStats.length;
  if (remainingSlots > 0) {
    final untrackedStats = await _fetchUntrackedFiles(remainingSlots, cwd: cwd);
    if (untrackedStats != null) {
      perFileStats.addAll(untrackedStats);
    }
  }

  return GitDiffResult(
    stats: GitDiffStats(
      filesCount:
          stats.filesCount + (perFileStats.length - result.perFileStats.length),
      linesAdded: stats.linesAdded,
      linesRemoved: stats.linesRemoved,
    ),
    perFileStats: perFileStats,
    hunks: {},
  );
}