Skip to content

Commit 1aef82b

Browse files
feat: enhance GitLoomDiff with commit mode and remote handling
- Add commit hash detection and dedicated commit mode - Implement remote changes fetching before diff generation - Add detailed console output with file tree visualization - Add version display and branding to CLI - Bump version to 0.0.44 Key changes: - New mode parameter to handle commit vs PR diffs differently - Auto-detect commit hashes vs branch names - Fetch remote changes automatically - Improved CLI output with visual file tree
1 parent 8da3972 commit 1aef82b

File tree

4 files changed

+104
-5
lines changed

4 files changed

+104
-5
lines changed

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "gitloom-diff",
3-
"version": "0.0.43",
3+
"version": "0.0.44",
44
"description": "Git diff tool that outputs markdown formatted diffs",
55
"main": "src/sdk/GitLoomDiff.js",
66
"bin": {

src/cli/index.js

Lines changed: 27 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,7 @@
22

33
const { program } = require("commander");
44
const GitLoomDiff = require("../sdk/GitLoomDiff");
5+
const pkg = require("../../package.json");
56

67
/**
78
* Configures and runs the GitLoomDiff CLI program.
@@ -29,9 +30,26 @@ const GitLoomDiff = require("../sdk/GitLoomDiff");
2930
* - Commit history between refs
3031
* - Navigation links between files
3132
*/
33+
34+
// Add this helper function
35+
function isCommitHash(ref) {
36+
// Git commit hashes are 40 chars or abbreviated to at least 7 chars
37+
// and contain only hexadecimal characters
38+
return ref && /^[0-9a-f]{7,40}$/i.test(ref);
39+
}
40+
41+
// Add this branding function
42+
function showBranding() {
43+
console.log(`
44+
🧶 GitLoom Diff v${pkg.version}
45+
===============================
46+
`);
47+
}
48+
3249
program
3350
.name("gitloom-diff")
3451
.description("Generate markdown-formatted git diffs")
52+
.version(pkg.version)
3553
.option("-s, --start-ref <ref>", "Starting reference (commit hash, branch name, or tag)")
3654
.option("-e, --end-ref <ref>", "Ending reference (commit hash, branch name, or tag)")
3755
.option("-o, --output <dir>", "Output directory", "git-diffs")
@@ -50,13 +68,20 @@ Examples:
5068
$ gitloom-diff -s v1.1.0 -e v1.0.0
5169
5270
# Side-by-side diff with custom output
53-
$ gitloom-diff -s main -e develop -o pr-diffs -f side-by-side`)
71+
$ gitloom-diff -s main -e develop -o pr-diffs -f side-by-side
72+
73+
# Compare commit hashes
74+
$ gitloom-diff -s 1234567890abcdef1234567890abcdef12345678 -e 0987654321fedcba0987654321fedcba09876543`)
5475
.action(async (options) => {
76+
showBranding();
77+
5578
const config = {
5679
outputDir: options.output,
5780
exclusions: options.exclude || [],
5881
diffFormat: options.format,
59-
darkMode: !options.lightMode
82+
darkMode: !options.lightMode,
83+
// Auto-detect mode based on ref format
84+
mode: (isCommitHash(options.startRef) && isCommitHash(options.endRef)) ? 'commit' : 'pr'
6085
};
6186

6287
const differ = new GitLoomDiff(config);

src/sdk/GitLoomDiff.js

Lines changed: 42 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ class GitLoomDiff {
1414
* @param {string[]} [options.exclude=[]] - File patterns to exclude from the diff
1515
* @param {string} [options.format='diff'] - Diff format (diff, unified, side-by-side)
1616
* @param {boolean} [options.darkMode=true] - Whether to use dark mode theme
17+
* @param {string} [options.mode='pr'] - Diff mode ('pr' or 'commit')
1718
*/
1819
constructor(options = {}) {
1920
this.config = new Config(options);
@@ -32,6 +33,11 @@ class GitLoomDiff {
3233

3334
try {
3435
await gitUtils.validateGit();
36+
37+
// Add remote fetch handling
38+
spinner.text = "Fetching latest remote changes...";
39+
await this.#fetchRemoteChanges(startRange, endRange);
40+
3541
fsUtils.cleanupOutputDir(this.config.outputDir);
3642

3743
const range = this.#buildGitRange(startRange, endRange);
@@ -45,8 +51,20 @@ class GitLoomDiff {
4551

4652
spinner.text = "Writing index file...";
4753
fsUtils.writeIndexFile(this.config.outputDir, index.join("\n"));
48-
54+
4955
spinner.succeed(`Diffs saved to ${this.config.outputDir}/`);
56+
57+
// Add summary of generated content
58+
console.log('\nGenerated content:');
59+
console.log(`- Index file: ${this.config.outputDir}/DIFF_INDEX.md`);
60+
console.log(`- Total files processed: ${changedFiles.length}`);
61+
console.log(`- Files generated:`);
62+
console.log(` ${this.config.outputDir}/`);
63+
console.log(` ├── DIFF_INDEX.md`);
64+
changedFiles.forEach((file, i) => {
65+
const prefix = i === changedFiles.length - 1 ? ' └──' : ' ├──';
66+
console.log(`${prefix} ${file}.md`);
67+
});
5068
} catch (error) {
5169
spinner.fail("Failed to generate diffs");
5270
console.error(error);
@@ -84,7 +102,11 @@ class GitLoomDiff {
84102
* @private
85103
*/
86104
#buildGitRange(startRange, endRange) {
87-
return startRange && endRange ? `${endRange}..${startRange}` : "";
105+
if (!startRange || !endRange) return "";
106+
107+
return this.config.mode === 'pr'
108+
? `${endRange}..${startRange}` // For PR branches: target..source
109+
: `${startRange}...${endRange}`; // For commit hashes: start...end
88110
}
89111

90112
/**
@@ -155,6 +177,24 @@ class GitLoomDiff {
155177
const stats = fileInfo.match(/(\d+) insertion.+(\d+) deletion/)?.[0] || "No changes";
156178
index.push(`- [${file}](./${file}.md) - ${stats}`);
157179
}
180+
181+
/**
182+
* Fetches latest changes from specified remote
183+
* @param {string} startRange - Starting git reference (commit/branch/tag)
184+
* @param {string} endRange - Ending git reference to compare against
185+
* @returns {Promise<void>}
186+
* @throws {Error} If git fetch fails
187+
*/
188+
async #fetchRemoteChanges(startRange, endRange) {
189+
const remotes = new Set([
190+
await gitUtils.getRemote(startRange),
191+
await gitUtils.getRemote(endRange)
192+
].filter(Boolean));
193+
194+
for (const remote of remotes) {
195+
await gitUtils.fetchRemote(remote);
196+
}
197+
}
158198
}
159199

160200
module.exports = GitLoomDiff;

src/sdk/utils/gitUtils.js

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -99,6 +99,40 @@ const gitUtils = {
9999
`git log --pretty=format:"- %s (%h)" ${endRange}..${startRange}`
100100
);
101101
return stdout;
102+
},
103+
104+
/**
105+
* Fetches latest changes from specified remote
106+
* @param {string} remote - Remote name (e.g. 'origin')
107+
* @returns {Promise<void>}
108+
* @throws {Error} If git fetch fails
109+
*/
110+
async fetchRemote(remote) {
111+
await execAsync(`git fetch ${remote}`);
112+
},
113+
114+
/**
115+
* Checks if reference is a remote branch
116+
* @param {string} ref - Git reference to check
117+
* @returns {string|null} Remote name if remote branch, null otherwise
118+
*/
119+
async getRemote(ref) {
120+
if (!ref) return null;
121+
122+
try {
123+
const { stdout: remotes } = await execAsync('git remote');
124+
const remotesList = remotes.trim().split('\n');
125+
const remoteMatch = ref.match(/^([^/]+)\//);
126+
127+
if (remoteMatch && remotesList.includes(remoteMatch[1])) {
128+
return remoteMatch[1];
129+
}
130+
131+
const { stdout: remote } = await execAsync(`git config --get branch.${ref}.remote`);
132+
return remote.trim() || null;
133+
} catch {
134+
return null;
135+
}
102136
}
103137
};
104138

0 commit comments

Comments
 (0)