diff --git a/src/Commands/GitIgnore.cs b/src/Commands/GitIgnore.cs new file mode 100644 index 00000000..44bb268b --- /dev/null +++ b/src/Commands/GitIgnore.cs @@ -0,0 +1,16 @@ +using System.IO; + +namespace SourceGit.Commands +{ + public static class GitIgnore + { + public static void Add(string repo, string pattern) + { + var file = Path.Combine(repo, ".gitignore"); + if (!File.Exists(file)) + File.WriteAllLines(file, [ pattern ]); + else + File.AppendAllLines(file, [ pattern ]); + } + } +} diff --git a/src/Resources/Icons.axaml b/src/Resources/Icons.axaml index 69907e3a..32124080 100644 --- a/src/Resources/Icons.axaml +++ b/src/Resources/Icons.axaml @@ -99,4 +99,5 @@ M645 448l64 64 220-221L704 64l-64 64 115 115H128v90h628zM375 576l-64-64-220 224L314 960l64-64-116-115H896v-90H262z M248 221a77 77 0 00-30-21c-18-7-40-10-68-5a224 224 0 00-45 13c-5 2-10 5-15 8l-3 2v68l11-9c10-8 21-14 34-19 13-5 26-7 39-7 12 0 21 3 28 10 6 6 9 16 9 29l-62 9c-14 2-26 6-36 11a80 80 0 00-25 20c-7 8-12 17-15 27-6 21-6 44 1 65a70 70 0 0041 43c10 4 21 6 34 6a80 80 0 0063-28v22h64V298c0-16-2-31-6-44a91 91 0 00-18-33zm-41 121v15c0 8-1 15-4 22a48 48 0 01-24 29 44 44 0 01-33 2 29 29 0 01-10-6 25 25 0 01-6-9 30 30 0 01-2-12c0-5 1-9 2-14a21 21 0 015-9 28 28 0 0110-7 83 83 0 0120-5l42-6zm323-68a144 144 0 00-16-42 87 87 0 00-28-29 75 75 0 00-41-11 73 73 0 00-44 14c-6 5-12 11-17 17V64H326v398h59v-18c8 10 18 17 30 21 6 2 13 3 21 3 16 0 31-4 43-11 12-7 23-18 31-31a147 147 0 0019-46 248 248 0 006-57c0-17-2-33-5-49zm-55 49c0 15-1 28-4 39-2 11-6 20-10 27a41 41 0 01-15 15 37 37 0 01-36 1 44 44 0 01-13-12 59 59 0 01-9-18A76 76 0 01384 352v-33c0-10 1-20 4-29 2-8 6-15 10-22a43 43 0 0115-13 37 37 0 0119-5 35 35 0 0132 18c4 6 7 14 9 23 2 9 3 20 3 31zM154 634a58 58 0 0120-15c14-6 35-7 49-1 7 3 13 6 20 12l21 17V572l-6-4a124 124 0 00-58-14c-20 0-38 4-54 11-16 7-30 17-41 30-12 13-20 29-26 46-6 17-9 36-9 57 0 18 3 36 8 52 6 16 14 30 24 42 10 12 23 21 38 28 15 7 32 10 50 10 15 0 28-2 39-5 11-3 21-8 30-14l5-4v-57l-13 6a26 26 0 01-5 2c-3 1-6 2-8 3-2 1-15 6-15 6-4 2-9 3-14 4a63 63 0 01-38-4 53 53 0 01-20-14 70 70 0 01-13-24 111 111 0 01-5-34c0-13 2-26 5-36 3-10 8-19 14-26zM896 384h-256V320h288c21 1 32 12 32 32v384c0 18-12 32-32 32H504l132 133-45 45-185-185c-16-21-16-25 0-45l185-185L637 576l-128 128H896V384z M128 183C128 154 154 128 183 128h521c30 0 55 26 55 55v38c0 17-17 34-34 34s-34-17-34-34v-26H196v495h26c17 0 34 17 34 34s-17 34-34 34h-38c-30 0-55-26-55-55V183zM380 896h-34c-26 0-47-21-47-47v-90h68V828h64V896H380c4 0 0 0 0 0zM759 828V896h90c26 0 47-21 47-47v-90h-68V828h-68zM828 435H896V346c0-26-21-47-47-47h-90v68H828v68zM435 299v68H367V439H299V346C299 320 320 299 346 299h90zM367 649H299v-107h68v107zM546 367V299h107v68h-107zM828 546H896v107h-68v-107zM649 828V896h-107v-68h107zM730 508v188c0 17-17 34-34 34h-188c-17 0-34-17-34-34s17-34 34-34h102l-124-124c-13-13-13-34 0-47 13-13 34-13 47 0l124 124V512c0-17 17-34 34-34 21-4 38 9 38 30z + M590 74 859 342V876c0 38-31 68-68 68H233c-38 0-68-31-68-68V142c0-38 31-68 68-68h357zm-12 28H233a40 40 0 00-40 38L193 142v734a40 40 0 0038 40L233 916h558a40 40 0 0040-38L831 876V354L578 102zM855 371h-215c-46 0-83-36-84-82l0-2V74h28v213c0 30 24 54 54 55l2 0h215v28zM57 489m28 0 853 0q28 0 28 28l0 284q0 28-28 28l-853 0q-28 0-28-28l0-284q0-28 28-28ZM157 717c15 0 29-6 37-13v-51h-41v22h17v18c-2 2-6 3-10 3-21 0-30-13-30-34 0-21 12-34 28-34 9 0 15 4 20 9l14-17C184 610 172 603 156 603c-29 0-54 21-54 57 0 37 24 56 54 56zM245 711v-108h-34v108h34zm69 0v-86H341V603H262v22h28V711h24zM393 711v-108h-34v108h34zm66 6c15 0 29-6 37-13v-51h-41v22h17v18c-2 2-6 3-10 3-21 0-30-13-30-34 0-21 12-34 28-34 9 0 15 4 20 9l14-17C485 610 474 603 458 603c-29 0-54 21-54 57 0 37 24 56 54 56zm88-6v-36c0-13-2-28-3-40h1l10 24 25 52H603v-108h-23v36c0 13 2 28 3 40h-1l-10-24L548 603H523v108h23zM677 717c30 0 51-22 51-57 0-36-21-56-51-56-30 0-51 20-51 56 0 36 21 57 51 57zm3-23c-16 0-26-12-26-32 0-19 10-31 26-31 16 0 26 11 26 31S696 694 680 694zm93 17v-38h13l21 38H836l-25-43c12-5 19-15 19-31 0-26-20-34-44-34H745v108h27zm16-51H774v-34h15c16 0 25 4 25 16s-9 18-25 18zM922 711v-22h-43v-23h35v-22h-35V625h41V603H853v108h68z diff --git a/src/Resources/Locales/en_US.axaml b/src/Resources/Locales/en_US.axaml index ccedbe84..a1b03bf0 100644 --- a/src/Resources/Locales/en_US.axaml +++ b/src/Resources/Locales/en_US.axaml @@ -477,6 +477,11 @@ Search Repositories ... Sort Changes + Add To .gitignore ... + Ignore all *{0} files + Ignore *{0} files in the same folder + Ignore files in the same folder + Ignore this file only Amend You can stage this file now. COMMIT diff --git a/src/Resources/Locales/zh_CN.axaml b/src/Resources/Locales/zh_CN.axaml index faaeb2e5..1de41e04 100644 --- a/src/Resources/Locales/zh_CN.axaml +++ b/src/Resources/Locales/zh_CN.axaml @@ -480,6 +480,11 @@ 快速查找仓库... 排序 本地更改 + 添加至 .gitignore 忽略列表 ... + 忽略所有 *{0} 文件 + 忽略同目录下所有 *{0} 文件 + 忽略同目录下所有文件 + 忽略本文件 修补(--amend) 现在您已可将其加入暂存区中 提交 diff --git a/src/Resources/Locales/zh_TW.axaml b/src/Resources/Locales/zh_TW.axaml index 86c6781b..79c4be87 100644 --- a/src/Resources/Locales/zh_TW.axaml +++ b/src/Resources/Locales/zh_TW.axaml @@ -480,6 +480,11 @@ 快速查詢倉庫... 排序 本地更改 + 添加至 .gitignore 忽略清單 ... + 忽略所有 *{0} 檔案 + 忽略同路徑下所有 *{0} 檔案 + 忽略同路徑下所有檔案 + 忽略本檔案 修補(--amend) 現在您已可將其加入暫存區中 提交 diff --git a/src/ViewModels/WorkingCopy.cs b/src/ViewModels/WorkingCopy.cs index 5612fbbe..464465d7 100644 --- a/src/ViewModels/WorkingCopy.cs +++ b/src/ViewModels/WorkingCopy.cs @@ -527,6 +527,16 @@ namespace SourceGit.ViewModels e.Handled = true; }; + + var assumeUnchanged = new MenuItem(); + assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged"); + assumeUnchanged.Icon = App.CreateMenuIcon("Icons.File.Ignore"); + assumeUnchanged.IsVisible = change.WorkTree != Models.ChangeState.Untracked; + assumeUnchanged.Click += (_, e) => + { + new Commands.AssumeUnchanged(_repo.FullPath).Add(change.Path); + e.Handled = true; + }; var history = new MenuItem(); history.Header = App.Text("FileHistory"); @@ -538,24 +548,67 @@ namespace SourceGit.ViewModels e.Handled = true; }; - var assumeUnchanged = new MenuItem(); - assumeUnchanged.Header = App.Text("FileCM.AssumeUnchanged"); - assumeUnchanged.Icon = App.CreateMenuIcon("Icons.File.Ignore"); - assumeUnchanged.IsEnabled = change.WorkTree != Models.ChangeState.Untracked; - assumeUnchanged.Click += (_, e) => - { - new Commands.AssumeUnchanged(_repo.FullPath).Add(change.Path); - e.Handled = true; - }; - menu.Items.Add(stage); menu.Items.Add(discard); menu.Items.Add(stash); menu.Items.Add(patch); - menu.Items.Add(new MenuItem() { Header = "-" }); - menu.Items.Add(history); menu.Items.Add(assumeUnchanged); menu.Items.Add(new MenuItem() { Header = "-" }); + menu.Items.Add(history); + menu.Items.Add(new MenuItem() { Header = "-" }); + + if (change.WorkTree == Models.ChangeState.Untracked) + { + var isRooted = change.Path.IndexOf('/', StringComparison.Ordinal) <= 0; + var addToIgnore = new MenuItem(); + addToIgnore.Header = App.Text("WorkingCopy.AddToGitIgnore"); + addToIgnore.Icon = App.CreateMenuIcon("Icons.GitIgnore"); + + var singleFile = new MenuItem(); + singleFile.Header = App.Text("WorkingCopy.AddToGitIgnore.SingleFile"); + singleFile.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, change.Path); + e.Handled = true; + }; + addToIgnore.Items.Add(singleFile); + + var byParentFolder = new MenuItem(); + byParentFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.InSameFolder"); + byParentFolder.IsVisible = !isRooted; + byParentFolder.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, Path.GetDirectoryName(change.Path) + "/"); + e.Handled = true; + }; + addToIgnore.Items.Add(byParentFolder); + + var extension = Path.GetExtension(change.Path); + if (!string.IsNullOrEmpty(extension)) + { + var byExtension = new MenuItem(); + byExtension.Header = App.Text("WorkingCopy.AddToGitIgnore.Extension", extension); + byExtension.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, "*" + extension); + e.Handled = true; + }; + addToIgnore.Items.Add(byExtension); + + var byExtensionInSameFolder = new MenuItem(); + byExtensionInSameFolder.Header = App.Text("WorkingCopy.AddToGitIgnore.ExtensionInSameFolder", extension); + byExtensionInSameFolder.IsVisible = !isRooted; + byExtensionInSameFolder.Click += (_, e) => + { + Commands.GitIgnore.Add(_repo.FullPath, Path.GetDirectoryName(change.Path) + "/*" + extension); + e.Handled = true; + }; + addToIgnore.Items.Add(byExtensionInSameFolder); + } + + menu.Items.Add(addToIgnore); + menu.Items.Add(new MenuItem() { Header = "-" }); + } } var copy = new MenuItem();