diff --git a/src/constants.ts b/src/constants.ts index f792ff85..3f0eee1b 100644 --- a/src/constants.ts +++ b/src/constants.ts @@ -41,6 +41,7 @@ export const DEFAULT_SETTINGS: ObsidianGitSettings = { authorInHistoryView: "hide", dateInHistoryView: false, diffStyle: "split", + trackedDirectory: "", lineAuthor: { show: false, followMovement: "inactive", diff --git a/src/gitManager/isomorphicGit.ts b/src/gitManager/isomorphicGit.ts index ee392628..c871bed3 100644 --- a/src/gitManager/isomorphicGit.ts +++ b/src/gitManager/isomorphicGit.ts @@ -862,12 +862,22 @@ export class IsomorphicGit extends GitManager { walkers: Walker[]; dir?: string; }): Promise { + const trackedDir = this.plugin.settings.trackedDirectory; + // eslint-disable-next-line @typescript-eslint/no-unsafe-assignment const res = await this.wrapFS( git.walk({ ...this.getRepo(), trees: walkers, map: async function (filepath, [A, B]) { + // Check if file is in tracked directory (if specified) + if (trackedDir && trackedDir.length > 0 && + filepath !== trackedDir && + !filepath.startsWith(trackedDir + "/")) { + return null; + } + + // Original check with base path if (!worthWalking(filepath, base)) { return null; } @@ -960,7 +970,7 @@ export class IsomorphicGit extends GitManager { } } // match against base path - if (!worthWalking(filepath, base)) { + if (!worthWalking(filepath, base, this.plugin.settings.trackedDirectory)) { return null; } // Late filter against file names diff --git a/src/gitManager/simpleGit.ts b/src/gitManager/simpleGit.ts index 7329cdfc..8f59b94c 100644 --- a/src/gitManager/simpleGit.ts +++ b/src/gitManager/simpleGit.ts @@ -241,25 +241,35 @@ export class SimpleGit extends GitManager { const status = await this.git.status(); this.plugin.setPluginState({ gitAction: CurrentGitAction.idle }); - const allFilesFormatted = status.files.map((e) => { - const res = this.formatPath(e); - return { - path: res.path, - from: res.from, - index: e.index === "?" ? "U" : e.index, - workingDir: e.working_dir === "?" ? "U" : e.working_dir, - vaultPath: this.getRelativeVaultPath(res.path), - }; - }); + // Filter files by tracked directory if specified + const trackedDir = this.plugin.settings.trackedDirectory; + const filterByTrackedDir = (path: string) => { + if (!trackedDir || trackedDir.length === 0) return true; + return path === trackedDir || path.startsWith(trackedDir + "/"); + }; + + const allFilesFormatted = status.files + .filter(e => filterByTrackedDir(e.path)) + .map((e) => { + const res = this.formatPath(e); + return { + path: res.path, + from: res.from, + index: e.index === "?" ? "U" : e.index, + workingDir: e.working_dir === "?" ? "U" : e.working_dir, + vaultPath: this.getRelativeVaultPath(res.path), + }; + }); + return { all: allFilesFormatted, changed: allFilesFormatted.filter((e) => e.workingDir !== " "), staged: allFilesFormatted.filter( (e) => e.index !== " " && e.index != "U" ), - conflicted: status.conflicted.map( - (path) => this.formatPath({ path }).path - ), + conflicted: status.conflicted + .filter(filterByTrackedDir) + .map((path) => this.formatPath({ path }).path), }; } @@ -409,7 +419,16 @@ export class SimpleGit extends GitManager { } this.plugin.setPluginState({ gitAction: CurrentGitAction.add }); - await this.git.add("-A"); + // Add only files that match the tracked directory + if (this.plugin.settings.trackedDirectory) { + const trackedDir = this.plugin.settings.trackedDirectory; + + // We could use git add with path to only add tracked directory + await this.git.add([trackedDir]); + } else { + // Add all files if no tracked directory is specified + await this.git.add("-A"); + } this.plugin.setPluginState({ gitAction: CurrentGitAction.commit }); @@ -502,7 +521,7 @@ export class SimpleGit extends GitManager { } async discardAll({ dir }: { dir?: string }): Promise { - return this.discard(dir ?? "."); + return this.discard(dir ?? (this.plugin.settings.trackedDirectory ? this.plugin.settings.trackedDirectory : ".")); } async pull(): Promise { @@ -577,16 +596,23 @@ export class SimpleGit extends GitManager { "--name-only", ]); - return filesChanged + const files = filesChanged .split(/\r\n|\r|\n/) - .filter((value) => value.length > 0) - .map((e) => { - return { - path: e, - workingDir: "P", - vaultPath: this.getRelativeVaultPath(e), - }; - }); + .filter((value) => value.length > 0); + + // Filter by tracked directory + const trackedDir = this.plugin.settings.trackedDirectory; + const filteredFiles = trackedDir && trackedDir.length > 0 + ? files.filter(file => file === trackedDir || file.startsWith(trackedDir + "/")) + : files; + + return filteredFiles.map((e) => { + return { + path: e, + workingDir: "P", + vaultPath: this.getRelativeVaultPath(e), + }; + }); } else { return []; } @@ -624,6 +650,7 @@ export class SimpleGit extends GitManager { currentBranch, trackingBranch, "--", + ...(this.plugin.settings.trackedDirectory ? [this.plugin.settings.trackedDirectory] : []) ]) ).changed; @@ -645,7 +672,12 @@ export class SimpleGit extends GitManager { } const remoteChangedFiles = ( - await this.git.diffSummary([currentBranch, trackingBranch, "--"]) + await this.git.diffSummary([ + currentBranch, + trackingBranch, + "--", + ...(this.plugin.settings.trackedDirectory ? [this.plugin.settings.trackedDirectory] : []) + ]) ).changed; return remoteChangedFiles; @@ -663,7 +695,12 @@ export class SimpleGit extends GitManager { return false; } const remoteChangedFiles = ( - await this.git.diffSummary([currentBranch, trackingBranch, "--"]) + await this.git.diffSummary([ + currentBranch, + trackingBranch, + "--", + ...(this.plugin.settings.trackedDirectory ? [this.plugin.settings.trackedDirectory] : []) + ]) ).changed; return remoteChangedFiles !== 0; diff --git a/src/setting/settings.ts b/src/setting/settings.ts index dd326bfd..f2ef76ba 100644 --- a/src/setting/settings.ts +++ b/src/setting/settings.ts @@ -827,6 +827,20 @@ export class ObsidianGitSettingsTab extends PluginSettingTab { }) ); + new Setting(containerEl) + .setName("Tracked directory within repository") + .setDesc("Specify a directory within your repository to track. Changes outside this directory will be ignored. Leave empty to track the entire repository.") + .addText((cb) => { + cb.setValue(plugin.settings.trackedDirectory); + cb.setPlaceholder("directory/subdirectory"); + cb.onChange(async (value) => { + plugin.settings.trackedDirectory = value; + await plugin.saveSettings(); + // Trigger a refresh to update the UI + plugin.refresh().catch((e) => plugin.displayError(e)); + }); + }); + new Setting(containerEl).setName("Support").setHeading(); new Setting(containerEl) .setName("Donate") diff --git a/src/types.ts b/src/types.ts index 29b15562..18f80b92 100644 --- a/src/types.ts +++ b/src/types.ts @@ -56,6 +56,7 @@ export interface ObsidianGitSettings { authorInHistoryView: ShowAuthorInHistoryView; dateInHistoryView: boolean; diffStyle: "git_unified" | "split"; + trackedDirectory: string; // Directory within repo to track, empty means track all } /** diff --git a/src/utils.ts b/src/utils.ts index f8dc4137..d101d10c 100644 --- a/src/utils.ts +++ b/src/utils.ts @@ -4,7 +4,15 @@ import type { App, RGB, WorkspaceLeaf } from "obsidian"; import { Keymap, Menu, moment, TFile } from "obsidian"; import { BINARY_EXTENSIONS } from "./constants"; -export const worthWalking = (filepath: string, root?: string) => { +export const worthWalking = (filepath: string, root?: string, trackedDir?: string) => { + // First check if the file is in the tracked directory, if specified + console.log("check tracked", trackedDir) + if (trackedDir && trackedDir.length > 0 && !filepath.startsWith(trackedDir) && filepath !== trackedDir) { + console.log("not tracked", filepath) + return false; + } + + // Then do the original check if (filepath === "." || root == null || root.length === 0 || root === ".") { return true; }