Skip to main content

diff

codebolt.git.diff(commitHash: string, path: string): Promise<GitDiffResponse>

Retrieves the diff of changes for a specific commit in the Git repository. Shows the differences between the specified commit and its parent, displaying what was added, modified, or deleted.

Parameters​

  • commitHash (string): The SHA hash of the commit to retrieve the diff for (e.g., "abc123def456", "1a2b3c4d").
  • path (string): 'Optional. The file system path of the local Git repository. If not provided, uses the current directory.'

Returns​

  • Promise<GitDiffResponse>: A promise that resolves with a GitDiffResponse object containing the diff data and change statistics.

Response Structure​

The method returns a Promise that resolves to a GitDiffResponse object with the following properties:

  • type (string): Always "gitDiffResponse".
  • data (DiffResult | string, optional): The diff data, which can be either:
    • DiffResult object with properties:
      • files (array): Array of file change objects with:
        • file (string): The file path that was changed.
        • changes (number): Total number of changes in the file.
        • insertions (number): Number of lines added.
        • deletions (number): Number of lines removed.
        • binary (boolean): Whether the file is binary.
      • insertions (number): Total lines inserted across all files.
      • deletions (number): Total lines deleted across all files.
      • changed (number): Total number of files changed.
    • string: Raw diff output in text format.
  • commitHash (string, optional): The commit hash that was analyzed.
  • success (boolean, optional): Indicates if the operation was successful.
  • message (string, optional): A message with additional information about the operation.
  • error (string, optional): Error details if the operation failed.
  • messageId (string, optional): A unique identifier for the message.
  • threadId (string, optional): The thread identifier.

Examples​

// Example 1: Basic diff operation
const diffResult = await codebolt.git.diff('abc123def456');
console.log("Response type:", diffResult.type); // "gitDiffResponse"
console.log("Success:", diffResult.success); // true (if successful)
console.log("Commit hash:", diffResult.commitHash); // "abc123def456"

if (typeof diffResult.data === 'object') {
console.log("Files changed:", diffResult.data.changed);
console.log("Total insertions:", diffResult.data.insertions);
console.log("Total deletions:", diffResult.data.deletions);
} else {
console.log("Raw diff:", diffResult.data);
}

// Example 2: Analyze commit changes
async function analyzeCommitChanges(commitHash) {
try {
const diffResult = await codebolt.git.diff(commitHash);

if (!diffResult.success) {
console.error("āŒ Failed to get diff:", diffResult.error);
return false;
}

console.log(`šŸ“Š Analysis for commit ${commitHash.substring(0, 8)}:`);

if (typeof diffResult.data === 'object' && diffResult.data.files) {
const { files, insertions, deletions, changed } = diffResult.data;

console.log(`šŸ“ Files changed: ${changed}`);
console.log(`āž• Lines added: ${insertions}`);
console.log(`āž– Lines removed: ${deletions}`);
console.log(`šŸ“ˆ Net change: ${insertions - deletions > 0 ? '+' : ''}${insertions - deletions}`);

console.log("\nšŸ“ File breakdown:");
files.forEach(file => {
const netChange = file.insertions - file.deletions;
const changeIndicator = netChange > 0 ? 'šŸ“ˆ' : netChange < 0 ? 'šŸ“‰' : 'šŸ“Š';

console.log(` ${changeIndicator} ${file.file}`);
console.log(` +${file.insertions} -${file.deletions} (${file.changes} changes)`);

if (file.binary) {
console.log(` šŸ“¦ Binary file`);
}
});

return true;
} else {
console.log("šŸ“„ Raw diff output:");
console.log(diffResult.data);
return true;
}
} catch (error) {
console.error("Error analyzing commit changes:", error);
return false;
}
}

// Example 3: Compare multiple commits
async function compareCommits(commitHashes) {
const results = [];

for (const hash of commitHashes) {
try {
const diffResult = await codebolt.git.diff(hash);

if (diffResult.success && typeof diffResult.data === 'object') {
results.push({
hash: hash.substring(0, 8),
files: diffResult.data.changed || 0,
insertions: diffResult.data.insertions || 0,
deletions: diffResult.data.deletions || 0,
netChange: (diffResult.data.insertions || 0) - (diffResult.data.deletions || 0)
});
}
} catch (error) {
console.error(`Error getting diff for ${hash}:`, error);
}
}

console.log("šŸ“Š Commit Comparison:");
console.log("Hash | Files | +Lines | -Lines | Net");
console.log("---------|-------|--------|--------|--------");

results.forEach(result => {
console.log(
`${result.hash} | ${result.files.toString().padStart(5)} | ` +
`${result.insertions.toString().padStart(6)} | ` +
`${result.deletions.toString().padStart(6)} | ` +
`${result.netChange > 0 ? '+' : ''}${result.netChange}`
);
});

return results;
}

// Example 4: Find large commits
async function findLargeCommits(repoPath, threshold = 100) {
try {
// Get commit logs first
const logsResult = await codebolt.git.logs(repoPath);

if (!logsResult.success || !logsResult.data) {
console.error("āŒ Failed to get commit logs");
return [];
}

const largeCommits = [];

for (const commit of logsResult.data) {
try {
const diffResult = await codebolt.git.diff(commit.hash);

if (diffResult.success && typeof diffResult.data === 'object') {
const totalChanges = (diffResult.data.insertions || 0) + (diffResult.data.deletions || 0);

if (totalChanges >= threshold) {
largeCommits.push({
hash: commit.hash.substring(0, 8),
message: commit.message,
author: commit.author_name,
date: commit.date,
changes: totalChanges,
files: diffResult.data.changed || 0
});
}
}
} catch (error) {
console.error(`Error analyzing commit ${commit.hash}:`, error);
}
}

console.log(`šŸ” Found ${largeCommits.length} commits with ${threshold}+ line changes:`);

largeCommits
.sort((a, b) => b.changes - a.changes)
.forEach(commit => {
console.log(` šŸ“ˆ ${commit.hash}: ${commit.changes} changes in ${commit.files} files`);
console.log(` "${commit.message}" by ${commit.author}`);
console.log(` ${new Date(commit.date).toLocaleDateString()}`);
});

return largeCommits;
} catch (error) {
console.error("Error finding large commits:", error);
return [];
}
}

// Example 5: Diff with file filtering
async function analyzeSpecificFiles(commitHash, fileExtensions = []) {
try {
const diffResult = await codebolt.git.diff(commitHash);

if (!diffResult.success || typeof diffResult.data !== 'object' || !diffResult.data.files) {
console.error("āŒ Failed to get diff data");
return false;
}

let filesToAnalyze = diffResult.data.files;

if (fileExtensions.length > 0) {
filesToAnalyze = diffResult.data.files.filter(file =>
fileExtensions.some(ext => file.file.endsWith(ext))
);
}

console.log(`šŸ” Analyzing ${filesToAnalyze.length} files in commit ${commitHash.substring(0, 8)}:`);

const summary = {
totalFiles: filesToAnalyze.length,
totalInsertions: 0,
totalDeletions: 0,
binaryFiles: 0
};

filesToAnalyze.forEach(file => {
summary.totalInsertions += file.insertions;
summary.totalDeletions += file.deletions;
if (file.binary) summary.binaryFiles++;

console.log(` šŸ“„ ${file.file}`);
console.log(` +${file.insertions} -${file.deletions} changes`);
});

console.log("\nšŸ“Š Summary:");
console.log(` Files: ${summary.totalFiles} (${summary.binaryFiles} binary)`);
console.log(` Insertions: ${summary.totalInsertions}`);
console.log(` Deletions: ${summary.totalDeletions}`);
console.log(` Net change: ${summary.totalInsertions - summary.totalDeletions}`);

return summary;
} catch (error) {
console.error("Error analyzing specific files:", error);
return false;
}
}

// Example 6: Diff workflow with commit selection
async function diffWorkflow(repoPath) {
try {
// Get recent commits
const logsResult = await codebolt.git.logs(repoPath);

if (!logsResult.success || !logsResult.data) {
console.error("āŒ Failed to get commit logs");
return false;
}

const recentCommits = logsResult.data.slice(0, 5);

console.log("šŸ•’ Recent commits:");
recentCommits.forEach((commit, index) => {
console.log(`${index + 1}. ${commit.hash.substring(0, 8)} - ${commit.message}`);
});

// Analyze each commit's diff
for (const commit of recentCommits) {
console.log(`\nšŸ“Š Analyzing commit ${commit.hash.substring(0, 8)}:`);
await analyzeCommitChanges(commit.hash);
}

return true;
} catch (error) {
console.error("Error in diff workflow:", error);
return false;
}
}

// Example 7: Error handling
try {
const diffResult = await codebolt.git.diff('abc123def456');

if (diffResult.success) {
console.log('āœ… Diff retrieved successfully');
console.log('Commit:', diffResult.commitHash);

if (typeof diffResult.data === 'object') {
console.log('Files changed:', diffResult.data.changed);
console.log('Lines added:', diffResult.data.insertions);
console.log('Lines removed:', diffResult.data.deletions);
}
} else {
console.error('āŒ Failed to get diff:', diffResult.error);
console.error('Message:', diffResult.message);
}
} catch (error) {
console.error('Error retrieving diff:', error);
}

### Common Use Cases

- **Code Review**: Examine what changes were made in specific commits
- **Change Analysis**: Understand the scope and impact of commits
- **Debugging**: Find what changed when issues were introduced or fixed
- **Release Notes**: Generate change summaries for releases
- **Quality Assurance**: Review commit sizes and file changes
- **Merge Conflict Resolution**: Understand conflicting changes

### Notes

- The diff shows changes between the specified commit and its parent commit.
- The `commitHash` parameter must be a valid Git commit SHA hash.
- The response can contain either structured data (DiffResult) or raw diff text.
- Binary files are marked as such and don't show line-by-line changes.
- Large diffs may take longer to process and return extensive data.
- Use the structured data format for programmatic analysis of changes.
- The operation is read-only and doesn't modify the repository.
- Invalid commit hashes will result in an error response.