Operations for working with Git data including diffs and file content retrieval. These are stream-based functions that return Git data as vinyl files or process existing vinyl files.
Gets Git diff results as vinyl file streams using git diff. Parses raw diff output and optionally reads file contents.
/**
* Gets git diff results as vinyl file streams
* @param compare - Git diff comparison argument (branch, commit, or tag)
* @param opt - Configuration options (optional)
* @returns Stream of vinyl files with git diff information
*/
function diff(compare: string, opt?: DiffOptions): Transform;
interface DiffOptions extends BaseOptions {
/** Base directory for vinyl files */
base?: string;
/** Read file contents via catFile (default: false) */
read?: boolean;
/** Buffer file contents (default: true) */
buffer?: boolean;
/** Strip BOM from file contents (default: true) */
stripBOM?: boolean;
/** Enable logging of diff command */
log?: boolean;
}Usage Examples:
const gulp = require('gulp');
const git = require('gulp-git');
// Basic diff against master
gulp.task('diff-master', function() {
return gulp.src('./*')
.pipe(git.diff('master'))
.pipe(gulp.dest('./diff-output'));
});
// Diff with logging enabled
gulp.task('diff-verbose', function() {
return gulp.src('./*')
.pipe(git.diff('develop', { log: true }))
.pipe(gulp.dest('./diff-output'));
});
// Diff with file contents
gulp.task('diff-with-content', function() {
return gulp.src('./*')
.pipe(git.diff('HEAD~1', {
read: true,
buffer: true
}))
.pipe(gulp.dest('./diff-output'));
});
// Diff against specific commit
gulp.task('diff-commit', function() {
return gulp.src('./*')
.pipe(git.diff('abc1234', { log: true }))
.pipe(gulp.dest('./diff-output'));
});
// Diff with custom base directory
gulp.task('diff-custom-base', function() {
return gulp.src('./src/*')
.pipe(git.diff('master', {
base: './src',
log: true
}))
.pipe(gulp.dest('./diff-output'));
});Reads Git blob contents using git cat-file for vinyl files. Retrieves file contents from Git object database.
/**
* Reads git blob contents using git cat-file for vinyl files
* @param opt - Configuration options (optional)
* @returns Transform stream that reads blob contents for vinyl files
*/
function catFile(opt?: CatFileOptions): Transform;
interface CatFileOptions {
/** Strip BOM from file contents (default: true) */
stripBOM?: boolean;
/** Buffer file contents (default: true) */
buffer?: boolean;
}Usage Examples:
// Read file contents from git objects
// Note: This requires vinyl files with git.hash property set
gulp.task('cat-files', function() {
return gulp.src('./*')
.pipe(/* some operation that sets file.git.hash */)
.pipe(git.catFile())
.pipe(gulp.dest('./output'));
});
// Read without BOM stripping
gulp.task('cat-files-raw', function() {
return gulp.src('./*')
.pipe(/* operation setting git hash */)
.pipe(git.catFile({ stripBOM: false }))
.pipe(gulp.dest('./output'));
});
// Read as streams (unbuffered)
gulp.task('cat-files-stream', function() {
return gulp.src('./*')
.pipe(/* operation setting git hash */)
.pipe(git.catFile({ buffer: false }))
.pipe(gulp.dest('./output'));
});const gulp = require('gulp');
const git = require('gulp-git');
const through = require('through2');
gulp.task('analyze-diff', function() {
let changedFiles = 0;
let additions = 0;
let deletions = 0;
return gulp.src('./*')
.pipe(git.diff('master', { log: true }))
.pipe(through.obj(function(file, enc, cb) {
changedFiles++;
// Analyze diff content (simplified)
if (file.contents) {
const content = file.contents.toString();
const lines = content.split('\n');
lines.forEach(line => {
if (line.startsWith('+') && !line.startsWith('+++')) additions++;
if (line.startsWith('-') && !line.startsWith('---')) deletions++;
});
}
this.push(file);
cb();
}))
.pipe(gulp.dest('./diff-analysis'))
.on('end', function() {
console.log(`Analysis complete:`);
console.log(`Changed files: ${changedFiles}`);
console.log(`Additions: ${additions}`);
console.log(`Deletions: ${deletions}`);
});
});gulp.task('compare-branches', function(done) {
const branch1 = process.env.BRANCH1 || 'master';
const branch2 = process.env.BRANCH2 || 'develop';
console.log(`Comparing ${branch1}...${branch2}`);
return gulp.src('./*')
.pipe(git.diff(`${branch1}...${branch2}`, { log: true }))
.pipe(through.obj(function(file, enc, cb) {
console.log(`Changed: ${file.relative}`);
this.push(file);
cb();
}))
.pipe(gulp.dest(`./comparison-${branch1}-${branch2}`));
});// This pattern would require additional setup to work with catFile
// as it needs git.hash to be set on vinyl files
function getFileAtCommit(filePath, commit, callback) {
git.exec({
args: `rev-parse ${commit}:${filePath}`
}, function(err, hash) {
if (err) return callback(err);
// Create vinyl file with git hash
const file = new (require('vinyl'))({
path: filePath,
git: { hash: hash.trim() }
});
// Use catFile to get content
const stream = git.catFile();
stream.on('data', function(file) {
callback(null, file.contents.toString());
});
stream.on('error', callback);
stream.write(file);
stream.end();
});
}
gulp.task('historical-content', function(done) {
const filePath = process.env.FILE_PATH || 'README.md';
const commit = process.env.COMMIT || 'HEAD~5';
getFileAtCommit(filePath, commit, function(err, content) {
if (err) return done(err);
console.log(`Content of ${filePath} at ${commit}:`);
console.log(content);
done();
});
});function calculateDiffStats(diffContent) {
const lines = diffContent.split('\n');
const stats = {
files: 0,
insertions: 0,
deletions: 0,
binary: 0
};
let currentFile = null;
lines.forEach(line => {
if (line.startsWith('diff --git')) {
stats.files++;
currentFile = line;
} else if (line.startsWith('+') && !line.startsWith('+++')) {
stats.insertions++;
} else if (line.startsWith('-') && !line.startsWith('---')) {
stats.deletions++;
} else if (line.includes('Binary files differ')) {
stats.binary++;
}
});
return stats;
}
gulp.task('diff-stats', function() {
const stats = {
totalFiles: 0,
totalInsertions: 0,
totalDeletions: 0,
totalBinary: 0
};
return gulp.src('./*')
.pipe(git.diff('master', { log: true }))
.pipe(through.obj(function(file, enc, cb) {
if (file.contents) {
const fileStats = calculateDiffStats(file.contents.toString());
stats.totalFiles += fileStats.files;
stats.totalInsertions += fileStats.insertions;
stats.totalDeletions += fileStats.deletions;
stats.totalBinary += fileStats.binary;
}
this.push(file);
cb();
}))
.pipe(gulp.dest('./diff-output'))
.on('end', function() {
console.log('Diff Statistics:');
console.log(`Files changed: ${stats.totalFiles}`);
console.log(`Insertions: +${stats.totalInsertions}`);
console.log(`Deletions: -${stats.totalDeletions}`);
console.log(`Binary files: ${stats.totalBinary}`);
});
});gulp.task('export-patch', function() {
const patchName = process.env.PATCH_NAME || 'changes.patch';
const targetBranch = process.env.TARGET_BRANCH || 'master';
return gulp.src('./*')
.pipe(git.diff(targetBranch, { log: true }))
.pipe(require('gulp-concat')(patchName))
.pipe(gulp.dest('./patches'))
.on('end', function() {
console.log(`Patch exported as ./patches/${patchName}`);
});
});gulp.task('validate-changes', function() {
const allowedExtensions = ['.js', '.json', '.md'];
let hasInvalidFiles = false;
return gulp.src('./*')
.pipe(git.diff('master'))
.pipe(through.obj(function(file, enc, cb) {
const ext = require('path').extname(file.relative);
if (!allowedExtensions.includes(ext)) {
console.warn(`Warning: Modified file ${file.relative} has unexpected extension ${ext}`);
hasInvalidFiles = true;
}
this.push(file);
cb();
}))
.pipe(gulp.dest('./validated-changes'))
.on('end', function() {
if (hasInvalidFiles) {
console.log('❌ Some files have unexpected extensions');
} else {
console.log('✅ All changed files have valid extensions');
}
});
});gulp.task('review-and-commit', function(done) {
// First show what's different
const diffStream = gulp.src('./*')
.pipe(git.diff('HEAD', { log: true }))
.pipe(gulp.dest('./review'));
diffStream.on('end', function() {
console.log('Diff saved to ./review directory');
// Prompt user or automatically commit
gulp.src('./*')
.pipe(git.add())
.pipe(git.commit('Auto-commit after review'))
.on('end', function() {
console.log('Changes committed');
done();
});
});
});