Skip to content

Commit 485e4cd

Browse files
authored
fix: handle "Add to .gitignore" edgecases and make the added path absolute (#890)
1 parent edbbfb6 commit 485e4cd

File tree

3 files changed

+61
-17
lines changed

3 files changed

+61
-17
lines changed

src/commands.ts

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
1-
import { Notice, Platform, WorkspaceLeaf } from "obsidian";
1+
import { Notice, Platform, TFolder, WorkspaceLeaf } from "obsidian";
22
import { HISTORY_VIEW_CONFIG, SOURCE_CONTROL_VIEW_CONFIG } from "./constants";
3+
import { SimpleGit } from "./gitManager/simpleGit";
34
import ObsidianGit from "./main";
45
import { openHistoryInGitHub, openLineInGitHub } from "./openInGitHub";
56
import { ChangedFilesModal } from "./ui/modals/changedFilesModal";
67
import { GeneralModal } from "./ui/modals/generalModal";
78
import { IgnoreModal } from "./ui/modals/ignoreModal";
8-
import { SimpleGit } from "./gitManager/simpleGit";
99

1010
export function addCommmands(plugin: ObsidianGit) {
1111
const app = plugin.app;
@@ -143,7 +143,7 @@ export function addCommmands(plugin: ObsidianGit) {
143143
return file !== null;
144144
} else {
145145
plugin
146-
.addFileToGitignore(file!.path)
146+
.addFileToGitignore(file!.path, file instanceof TFolder)
147147
.catch((e) => plugin.displayError(e));
148148
}
149149
},

src/main.ts

Lines changed: 33 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import { Errors } from "isomorphic-git";
2-
import * as path from "path";
32
import type { Debouncer, Menu, TAbstractFile, WorkspaceLeaf } from "obsidian";
43
import {
54
debounce,
@@ -10,7 +9,9 @@ import {
109
Platform,
1110
Plugin,
1211
TFile,
12+
TFolder,
1313
} from "obsidian";
14+
import * as path from "path";
1415
import { LineAuthoringFeature } from "src/lineAuthor/lineAuthorIntegration";
1516
import { pluginRef } from "src/pluginGlobalRef";
1617
import { PromiseQueue } from "src/promiseQueue";
@@ -24,13 +25,14 @@ import {
2425
DEFAULT_SETTINGS,
2526
DIFF_VIEW_CONFIG,
2627
HISTORY_VIEW_CONFIG,
27-
SPLIT_DIFF_VIEW_CONFIG,
2828
SOURCE_CONTROL_VIEW_CONFIG,
29+
SPLIT_DIFF_VIEW_CONFIG,
2930
} from "./constants";
3031
import type { GitManager } from "./gitManager/gitManager";
3132
import { IsomorphicGit } from "./gitManager/isomorphicGit";
3233
import { SimpleGit } from "./gitManager/simpleGit";
3334
import { LocalStorageSettings } from "./setting/localStorageSettings";
35+
import Tools from "./tools";
3436
import type {
3537
FileStatusResult,
3638
ObsidianGitSettings,
@@ -39,19 +41,22 @@ import type {
3941
UnstagedFile,
4042
} from "./types";
4143
import {
44+
CurrentGitAction,
4245
mergeSettingsByPriority,
4346
NoNetworkError,
44-
CurrentGitAction,
4547
} from "./types";
4648
import DiffView from "./ui/diff/diffView";
49+
import SplitDiffView from "./ui/diff/splitDiffView";
4750
import HistoryView from "./ui/history/historyView";
4851
import { BranchModal } from "./ui/modals/branchModal";
4952
import { GeneralModal } from "./ui/modals/generalModal";
5053
import GitView from "./ui/sourceControl/sourceControl";
5154
import { BranchStatusBar } from "./ui/statusBar/branchStatusBar";
52-
import { formatRemoteUrl, splitRemoteBranch } from "./utils";
53-
import Tools from "./tools";
54-
import SplitDiffView from "./ui/diff/splitDiffView";
55+
import {
56+
convertPathToAbsoluteGitignoreRule,
57+
formatRemoteUrl,
58+
splitRemoteBranch,
59+
} from "./utils";
5560

5661
export default class ObsidianGit extends Plugin {
5762
gitManager: GitManager;
@@ -319,10 +324,22 @@ export default class ObsidianGit extends Plugin {
319324
);
320325
}
321326

322-
async addFileToGitignore(filePath: string): Promise<void> {
327+
async addFileToGitignore(
328+
filePath: string,
329+
isFolder?: boolean
330+
): Promise<void> {
331+
const gitRelativePath = this.gitManager.getRelativeRepoPath(
332+
filePath,
333+
true
334+
);
335+
// Define an absolute rule that can apply only for this item.
336+
const gitignoreRule = convertPathToAbsoluteGitignoreRule({
337+
isFolder,
338+
gitRelativePath,
339+
});
323340
await this.app.vault.adapter.append(
324341
this.gitManager.getRelativeVaultPath(".gitignore"),
325-
"\n" + this.gitManager.getRelativeRepoPath(filePath, true)
342+
"\n" + gitignoreRule
326343
);
327344
return this.refresh();
328345
}
@@ -389,9 +406,10 @@ export default class ObsidianGit extends Plugin {
389406
.setIcon("file-x")
390407
.setSection("action")
391408
.onClick((_) => {
392-
this.addFileToGitignore(filePath).catch((e) =>
393-
this.displayError(e)
394-
);
409+
this.addFileToGitignore(
410+
filePath,
411+
file instanceof TFolder
412+
).catch((e) => this.displayError(e));
395413
});
396414
});
397415
}
@@ -402,9 +420,10 @@ export default class ObsidianGit extends Plugin {
402420
.setIcon("file-x")
403421
.setSection("action")
404422
.onClick((_) => {
405-
this.addFileToGitignore(filePath).catch((e) =>
406-
this.displayError(e)
407-
);
423+
this.addFileToGitignore(
424+
filePath,
425+
file instanceof TFolder
426+
).catch((e) => this.displayError(e));
408427
});
409428
});
410429
const gitManager = this.app.vault.adapter;

src/utils.ts

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -206,3 +206,28 @@ export function fileOpenableInObsidian(
206206
return true;
207207
}
208208
}
209+
210+
export function convertPathToAbsoluteGitignoreRule({
211+
isFolder,
212+
gitRelativePath,
213+
}: {
214+
isFolder?: boolean;
215+
gitRelativePath: string;
216+
}): string {
217+
// Add a leading slash to set the rule as absolute from root, so it only excludes that exact path
218+
let composedPath = "/";
219+
220+
composedPath += gitRelativePath;
221+
222+
// Add an explicit folder rule, so that the same path doesn't also apply for files with that same name
223+
if (isFolder) {
224+
composedPath += "/";
225+
}
226+
227+
// Escape special characters, so that git treats them as literal characters.
228+
const escaped = composedPath.replace(/([\\!#*?[\]])/g, String.raw`\$1`);
229+
230+
// Then escape each trailing whitespace character individually, because git trims trailing whitespace from the end of the rule.
231+
// Files normally end with a file extension, not whitespace, but a file with trailing whitespace can appear if Obsidian's "Detect all file extensions" setting is turned on.
232+
return escaped.replace(/\s(?=\s*$)/g, String.raw`\ `);
233+
}

0 commit comments

Comments
 (0)