diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md
index f9887d7e3..13d50012b 100644
--- a/docs/keybindings/Keybindings_en.md
+++ b/docs/keybindings/Keybindings_en.md
@@ -102,7 +102,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
C: commit changes using git editor
e: edit file
o: open file
- i: add to .gitignore
+ i: Ignore or Exclude file
r: refresh files
s: stash all changes
S: view stash options
diff --git a/docs/keybindings/Keybindings_ja.md b/docs/keybindings/Keybindings_ja.md
index b3f11b93f..b001869fd 100644
--- a/docs/keybindings/Keybindings_ja.md
+++ b/docs/keybindings/Keybindings_ja.md
@@ -161,7 +161,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
C: gitエディタを使用して変更をコミット
e: ファイルを編集
o: ファイルを開く
- i: .gitignoreに追加
+ i: ファイルをignore
r: ファイルをリフレッシュ
s: 変更をstash
S: view stash options
diff --git a/docs/keybindings/Keybindings_ko.md b/docs/keybindings/Keybindings_ko.md
index feee935b1..c23e89f52 100644
--- a/docs/keybindings/Keybindings_ko.md
+++ b/docs/keybindings/Keybindings_ko.md
@@ -280,7 +280,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
C: Git 편집기를 사용하여 변경 내용을 커밋합니다.
e: 파일 편집
o: 파일 닫기
- i: .gitignore에 추가
+ i: Ignore file
r: 파일 새로고침
s: 변경사항을 Stash
S: Stash 옵션 보기
diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md
index 72d8d82ed..26e861314 100644
--- a/docs/keybindings/Keybindings_nl.md
+++ b/docs/keybindings/Keybindings_nl.md
@@ -55,7 +55,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
C: commit veranderingen met de git editor
e: verander bestand
o: open bestand
- i: voeg toe aan .gitignore
+ i: Ignore or Exclude file
r: refresh bestanden
s: stash-bestanden
S: bekijk stash opties
diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md
index 99c97e594..53648368e 100644
--- a/docs/keybindings/Keybindings_pl.md
+++ b/docs/keybindings/Keybindings_pl.md
@@ -126,7 +126,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
C: Zatwierdź zmiany używając edytora
e: edytuj plik
o: otwórz plik
- i: dodaj do .gitignore
+ i: Ignore or Exclude file
r: odśwież pliki
s: przechowaj zmiany
S: wyświetl opcje schowka
diff --git a/docs/keybindings/Keybindings_zh.md b/docs/keybindings/Keybindings_zh.md
index b2e05cf44..bc47efbab 100644
--- a/docs/keybindings/Keybindings_zh.md
+++ b/docs/keybindings/Keybindings_zh.md
@@ -167,7 +167,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
C: 提交更改(使用编辑器编辑提交信息)
e: 编辑文件
o: 打开文件
- i: 添加到 .gitignore
+ i: 忽略文件
r: 刷新文件
s: 将所有更改加入贮藏
S: 查看贮藏选项
diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go
index 5986392a8..8fd1fb177 100644
--- a/pkg/commands/git_commands/working_tree.go
+++ b/pkg/commands/git_commands/working_tree.go
@@ -218,6 +218,11 @@ func (self *WorkingTreeCommands) Ignore(filename string) error {
return self.os.AppendLineToFile(".gitignore", filename)
}
+// Exclude adds a file to the .git/info/exclude for the repo
+func (self *WorkingTreeCommands) Exclude(filename string) error {
+ return self.os.AppendLineToFile(".git/info/exclude", filename)
+}
+
// WorktreeFileDiff returns the diff of a file
func (self *WorkingTreeCommands) WorktreeFileDiff(file *models.File, plain bool, cached bool, ignoreWhitespace bool) string {
// for now we assume an error means the file was deleted
diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go
index 0b3a91bf6..22c9c81dd 100644
--- a/pkg/config/user_config.go
+++ b/pkg/config/user_config.go
@@ -210,7 +210,7 @@ type KeybindingFilesConfig struct {
CommitChangesWithoutHook string `yaml:"commitChangesWithoutHook"`
AmendLastCommit string `yaml:"amendLastCommit"`
CommitChangesWithEditor string `yaml:"commitChangesWithEditor"`
- IgnoreFile string `yaml:"ignoreFile"`
+ IgnoreOrExcludeFile string `yaml:"IgnoreOrExcludeFile"`
RefreshFiles string `yaml:"refreshFiles"`
StashAllChanges string `yaml:"stashAllChanges"`
ViewStashOptions string `yaml:"viewStashOptions"`
@@ -487,7 +487,7 @@ func GetDefaultConfig() *UserConfig {
CommitChangesWithoutHook: "w",
AmendLastCommit: "A",
CommitChangesWithEditor: "C",
- IgnoreFile: "i",
+ IgnoreOrExcludeFile: "i",
RefreshFiles: "r",
StashAllChanges: "s",
ViewStashOptions: "S",
diff --git a/pkg/gui/controllers/files_controller.go b/pkg/gui/controllers/files_controller.go
index b413f6f5f..4aed5cf0a 100644
--- a/pkg/gui/controllers/files_controller.go
+++ b/pkg/gui/controllers/files_controller.go
@@ -86,9 +86,9 @@ func (self *FilesController) GetKeybindings(opts types.KeybindingsOpts) []*types
Description: self.c.Tr.LcOpenFile,
},
{
- Key: opts.GetKey(opts.Config.Files.IgnoreFile),
- Handler: self.checkSelectedFileNode(self.ignore),
- Description: self.c.Tr.LcIgnoreFile,
+ Key: opts.GetKey(opts.Config.Files.IgnoreOrExcludeFile),
+ Handler: self.checkSelectedFileNode(self.ignoreOrExcludeMenu),
+ Description: self.c.Tr.Actions.IgnoreExcludeFile,
},
{
Key: opts.GetKey(opts.Config.Files.RefreshFiles),
@@ -302,59 +302,115 @@ func (self *FilesController) stageAll() error {
return self.contexts.Files.HandleFocus()
}
-func (self *FilesController) ignore(node *filetree.FileNode) error {
- if node.GetPath() == ".gitignore" {
- return self.c.ErrorMsg("Cannot ignore .gitignore")
- }
-
- unstageFiles := func() error {
- return node.ForEachFile(func(file *models.File) error {
- if file.HasStagedChanges {
- if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil {
- return err
- }
+func (self *FilesController) unstageFiles(node *filetree.FileNode) error {
+ return node.ForEachFile(func(file *models.File) error {
+ if file.HasStagedChanges {
+ if err := self.git.WorkingTree.UnStageFile(file.Names(), file.Tracked); err != nil {
+ return err
}
+ }
- return nil
- })
- }
+ return nil
+ })
+}
- if node.GetIsTracked() {
- return self.c.Confirm(types.ConfirmOpts{
- Title: self.c.Tr.IgnoreTracked,
- Prompt: self.c.Tr.IgnoreTrackedPrompt,
- HandleConfirm: func() error {
- self.c.LogAction(self.c.Tr.Actions.IgnoreFile)
- // not 100% sure if this is necessary but I'll assume it is
- if err := unstageFiles(); err != nil {
- return err
- }
-
- if err := self.git.WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil {
- return err
- }
-
- if err := self.git.WorkingTree.Ignore(node.GetPath()); err != nil {
- return err
- }
- return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
- },
- })
- }
-
- self.c.LogAction(self.c.Tr.Actions.IgnoreFile)
-
- if err := unstageFiles(); err != nil {
+func (self *FilesController) ignoreOrExcludeTracked(node *filetree.FileNode, trAction string, f func(string) error) error {
+ self.c.LogAction(trAction)
+ // not 100% sure if this is necessary but I'll assume it is
+ if err := self.unstageFiles(node); err != nil {
return err
}
- if err := self.git.WorkingTree.Ignore(node.GetPath()); err != nil {
- return self.c.Error(err)
+ if err := self.git.WorkingTree.RemoveTrackedFiles(node.GetPath()); err != nil {
+ return err
+ }
+
+ if err := f(node.GetPath()); err != nil {
+ return err
}
return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
}
+func (self *FilesController) ignoreOrExcludeUntracked(node *filetree.FileNode, trAction string, f func(string) error) error {
+ self.c.LogAction(trAction)
+
+ if err := f(node.GetPath()); err != nil {
+ return err
+ }
+
+ return self.c.Refresh(types.RefreshOptions{Scope: []types.RefreshableView{types.FILES}})
+}
+
+func (self *FilesController) ignoreOrExcludeFile(node *filetree.FileNode, trText string, trPrompt string, trAction string, f func(string) error) error {
+ if node.GetIsTracked() {
+ return self.c.Confirm(types.ConfirmOpts{
+ Title: trText,
+ Prompt: trPrompt,
+ HandleConfirm: func() error {
+ return self.ignoreOrExcludeTracked(node, trAction, f)
+ },
+ })
+ }
+ return self.ignoreOrExcludeUntracked(node, trAction, f)
+}
+
+func (self *FilesController) ignore(node *filetree.FileNode) error {
+ if node.GetPath() == ".gitignore" {
+ return self.c.ErrorMsg(self.c.Tr.Actions.IgnoreFileErr)
+ }
+ err := self.ignoreOrExcludeFile(node, self.c.Tr.IgnoreTracked, self.c.Tr.IgnoreTrackedPrompt, self.c.Tr.Actions.IgnoreExcludeFile, self.git.WorkingTree.Ignore)
+ if err != nil {
+ return err
+ }
+
+ return nil
+}
+
+func (self *FilesController) exclude(node *filetree.FileNode) error {
+ if node.GetPath() == ".git/info/exclude" {
+ return self.c.ErrorMsg(self.c.Tr.Actions.ExcludeFileErr)
+ }
+
+ if node.GetPath() == ".gitignore" {
+ return self.c.ErrorMsg(self.c.Tr.Actions.ExcludeGitIgnoreErr)
+ }
+
+ err := self.ignoreOrExcludeFile(node, self.c.Tr.ExcludeTracked, self.c.Tr.ExcludeTrackedPrompt, self.c.Tr.Actions.ExcludeFile, self.git.WorkingTree.Exclude)
+ if err != nil {
+ return err
+ }
+ return nil
+}
+
+func (self *FilesController) ignoreOrExcludeMenu(node *filetree.FileNode) error {
+ return self.c.Menu(types.CreateMenuOptions{
+ Title: self.c.Tr.Actions.IgnoreExcludeFile,
+ Items: []*types.MenuItem{
+ {
+ LabelColumns: []string{self.c.Tr.LcIgnoreFile},
+ OnPress: func() error {
+ if err := self.ignore(node); err != nil {
+ return self.c.Error(err)
+ }
+ return nil
+ },
+ Key: 'i',
+ },
+ {
+ LabelColumns: []string{self.c.Tr.LcExcludeFile},
+ OnPress: func() error {
+ if err := self.exclude(node); err != nil {
+ return self.c.Error(err)
+ }
+ return nil
+ },
+ Key: 'e',
+ },
+ },
+ })
+}
+
func (self *FilesController) HandleWIPCommitPress() error {
skipHookPrefix := self.c.UserConfig.Git.SkipHookPrefix
if skipHookPrefix == "" {
diff --git a/pkg/i18n/chinese.go b/pkg/i18n/chinese.go
index 21097f7c4..f39728659 100644
--- a/pkg/i18n/chinese.go
+++ b/pkg/i18n/chinese.go
@@ -507,7 +507,7 @@ func chineseTranslationSet() TranslationSet {
UnstageFile: "取消暂存文件",
UnstageAllFiles: "取消暂存所有文件",
StageAllFiles: "暂存所有文件",
- IgnoreFile: "忽略文件",
+ IgnoreExcludeFile: "忽略文件",
Commit: "提交 (Commit)",
EditFile: "编辑文件",
Push: "推送 (Push)",
diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go
index 975cc9285..138277ab6 100644
--- a/pkg/i18n/english.go
+++ b/pkg/i18n/english.go
@@ -155,6 +155,7 @@ type TranslationSet struct {
LcEditFile string
LcOpenFile string
LcIgnoreFile string
+ LcExcludeFile string
LcRefreshFiles string
LcMergeIntoCurrentBranch string
ConfirmQuit string
@@ -345,7 +346,9 @@ type TranslationSet struct {
NotAGitFlowBranch string
NewBranchNamePrompt string
IgnoreTracked string
+ ExcludeTracked string
IgnoreTrackedPrompt string
+ ExcludeTrackedPrompt string
LcViewResetToUpstreamOptions string
LcNextScreenMode string
LcPrevScreenMode string
@@ -560,7 +563,12 @@ type Actions struct {
UnstageFile string
UnstageAllFiles string
StageAllFiles string
+ IgnoreExcludeFile string
IgnoreFile string
+ IgnoreFileErr string
+ ExcludeFile string
+ ExcludeFileErr string
+ ExcludeGitIgnoreErr string
Commit string
EditFile string
Push string
@@ -780,6 +788,7 @@ func EnglishTranslationSet() TranslationSet {
LcEditFile: `edit file`,
LcOpenFile: `open file`,
LcIgnoreFile: `add to .gitignore`,
+ LcExcludeFile: `add to .git/info/exclude`,
LcRefreshFiles: `refresh files`,
LcMergeIntoCurrentBranch: `merge into currently checked out branch`,
ConfirmQuit: `Are you sure you want to quit?`,
@@ -972,6 +981,8 @@ func EnglishTranslationSet() TranslationSet {
NewGitFlowBranchPrompt: "new {{.branchType}} name:",
IgnoreTracked: "Ignore tracked file",
IgnoreTrackedPrompt: "Are you sure you want to ignore a tracked file?",
+ ExcludeTracked: "Exclude tracked file",
+ ExcludeTrackedPrompt: "Are you sure you want to exclude a tracked file?",
LcViewResetToUpstreamOptions: "view upstream reset options",
LcNextScreenMode: "next screen mode (normal/half/fullscreen)",
LcPrevScreenMode: "prev screen mode",
@@ -1169,7 +1180,12 @@ func EnglishTranslationSet() TranslationSet {
UnstageFile: "Unstage file",
UnstageAllFiles: "Unstage all files",
StageAllFiles: "Stage all files",
- IgnoreFile: "Ignore file",
+ IgnoreExcludeFile: "Ignore or Exclude file",
+ IgnoreFile: "Ignore or Exclude file",
+ IgnoreFileErr: "Cannot ignore .gitignore",
+ ExcludeFile: "Exclude file",
+ ExcludeFileErr: "Cannot exclude .git/info/exclude",
+ ExcludeGitIgnoreErr: "Cannot exclude .gitignore",
Commit: "Commit",
EditFile: "Edit file",
Push: "Push",
diff --git a/pkg/i18n/japanese.go b/pkg/i18n/japanese.go
index 64cf5adc1..34b5adae1 100644
--- a/pkg/i18n/japanese.go
+++ b/pkg/i18n/japanese.go
@@ -533,7 +533,7 @@ func japaneseTranslationSet() TranslationSet {
UnstageFile: "ファイルをアンステージ",
UnstageAllFiles: "すべてのファイルをアンステージ",
StageAllFiles: "すべてのファイルをステージ",
- IgnoreFile: "ファイルをignore",
+ IgnoreExcludeFile: "ファイルをignore",
Commit: "コミット",
EditFile: "ファイルを編集",
Push: "Push",
diff --git a/pkg/i18n/korean.go b/pkg/i18n/korean.go
index f1b1759bd..20000fd2f 100644
--- a/pkg/i18n/korean.go
+++ b/pkg/i18n/korean.go
@@ -536,7 +536,7 @@ func koreanTranslationSet() TranslationSet {
UnstageFile: "Unstage file",
UnstageAllFiles: "Unstage all files",
StageAllFiles: "Stage all files",
- IgnoreFile: "Ignore file",
+ IgnoreExcludeFile: "Ignore file",
Commit: "커밋",
EditFile: "파일 수정",
Push: "푸시",
diff --git a/test/integration/excludeGitIgnore/expected/repo/.git_keep/FETCH_HEAD b/test/integration/excludeGitIgnore/expected/repo/.git_keep/FETCH_HEAD
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/integration/excludeGitIgnore/expected/repo/.git_keep/HEAD b/test/integration/excludeGitIgnore/expected/repo/.git_keep/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/test/integration/excludeGitIgnore/expected/repo/.git_keep/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/test/integration/excludeGitIgnore/expected/repo/.git_keep/config b/test/integration/excludeGitIgnore/expected/repo/.git_keep/config
new file mode 100644
index 000000000..6c9406b7d
--- /dev/null
+++ b/test/integration/excludeGitIgnore/expected/repo/.git_keep/config
@@ -0,0 +1,7 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+ precomposeunicode = true
diff --git a/test/integration/excludeGitIgnore/expected/repo/.git_keep/description b/test/integration/excludeGitIgnore/expected/repo/.git_keep/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/test/integration/excludeGitIgnore/expected/repo/.git_keep/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/test/integration/excludeGitIgnore/expected/repo/.git_keep/info/exclude b/test/integration/excludeGitIgnore/expected/repo/.git_keep/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/test/integration/excludeGitIgnore/expected/repo/.git_keep/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/test/integration/excludeGitIgnore/expected/repo/.gitignore b/test/integration/excludeGitIgnore/expected/repo/.gitignore
new file mode 100644
index 000000000..a5bce3fd2
--- /dev/null
+++ b/test/integration/excludeGitIgnore/expected/repo/.gitignore
@@ -0,0 +1 @@
+test1
diff --git a/test/integration/excludeGitIgnore/recording.json b/test/integration/excludeGitIgnore/recording.json
new file mode 100644
index 000000000..c6decb156
--- /dev/null
+++ b/test/integration/excludeGitIgnore/recording.json
@@ -0,0 +1 @@
+{"KeyEvents":[{"Timestamp":2674,"Mod":0,"Key":256,"Ch":105},{"Timestamp":4846,"Mod":0,"Key":256,"Ch":101},{"Timestamp":8064,"Mod":0,"Key":13,"Ch":13},{"Timestamp":8515,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":170,"Height":55}]}
\ No newline at end of file
diff --git a/test/integration/excludeGitIgnore/setup.sh b/test/integration/excludeGitIgnore/setup.sh
new file mode 100644
index 000000000..ce9563394
--- /dev/null
+++ b/test/integration/excludeGitIgnore/setup.sh
@@ -0,0 +1,14 @@
+#!/bin/sh
+
+set -e
+
+cd $1
+
+git config user.email "CI@example.com"
+git config user.name "CI"
+
+git init
+
+
+echo test1 > .gitignore
+
diff --git a/test/integration/excludeGitIgnore/test.json b/test/integration/excludeGitIgnore/test.json
new file mode 100644
index 000000000..a8ca45bb0
--- /dev/null
+++ b/test/integration/excludeGitIgnore/test.json
@@ -0,0 +1,4 @@
+{
+ "description": "In this test .gitignore is added to .git/info/exclude using the ignore or exclude menu to check that this operation is to allowed",
+ "speed": 5
+}
\ No newline at end of file
diff --git a/test/integration/excludeMenu/expected/repo/.git_keep/FETCH_HEAD b/test/integration/excludeMenu/expected/repo/.git_keep/FETCH_HEAD
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/integration/excludeMenu/expected/repo/.git_keep/HEAD b/test/integration/excludeMenu/expected/repo/.git_keep/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/test/integration/excludeMenu/expected/repo/.git_keep/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/test/integration/excludeMenu/expected/repo/.git_keep/config b/test/integration/excludeMenu/expected/repo/.git_keep/config
new file mode 100644
index 000000000..6c9406b7d
--- /dev/null
+++ b/test/integration/excludeMenu/expected/repo/.git_keep/config
@@ -0,0 +1,7 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+ precomposeunicode = true
diff --git a/test/integration/excludeMenu/expected/repo/.git_keep/description b/test/integration/excludeMenu/expected/repo/.git_keep/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/test/integration/excludeMenu/expected/repo/.git_keep/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/test/integration/excludeMenu/expected/repo/.git_keep/info/exclude b/test/integration/excludeMenu/expected/repo/.git_keep/info/exclude
new file mode 100644
index 000000000..ee02e5c09
--- /dev/null
+++ b/test/integration/excludeMenu/expected/repo/.git_keep/info/exclude
@@ -0,0 +1,8 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
+
+myfile1
\ No newline at end of file
diff --git a/test/integration/excludeMenu/expected/repo/myfile1 b/test/integration/excludeMenu/expected/repo/myfile1
new file mode 100644
index 000000000..a5bce3fd2
--- /dev/null
+++ b/test/integration/excludeMenu/expected/repo/myfile1
@@ -0,0 +1 @@
+test1
diff --git a/test/integration/excludeMenu/recording.json b/test/integration/excludeMenu/recording.json
new file mode 100644
index 000000000..1efef59a6
--- /dev/null
+++ b/test/integration/excludeMenu/recording.json
@@ -0,0 +1 @@
+{"KeyEvents":[{"Timestamp":1418,"Mod":0,"Key":256,"Ch":105},{"Timestamp":1725,"Mod":0,"Key":256,"Ch":101},{"Timestamp":3207,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":170,"Height":55}]}
\ No newline at end of file
diff --git a/test/integration/excludeMenu/setup.sh b/test/integration/excludeMenu/setup.sh
new file mode 100644
index 000000000..9643b2b67
--- /dev/null
+++ b/test/integration/excludeMenu/setup.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+cd $1
+git config user.email "CI@example.com"
+git config user.name "CI"
+
+git init
+
+
+echo test1 > myfile1
+
diff --git a/test/integration/excludeMenu/test.json b/test/integration/excludeMenu/test.json
new file mode 100644
index 000000000..b2ef1f3f4
--- /dev/null
+++ b/test/integration/excludeMenu/test.json
@@ -0,0 +1,4 @@
+{
+ "description": "In this test a file is added to .git/info/exclude using the ignore or exclude menu",
+ "speed": 5
+}
\ No newline at end of file
diff --git a/test/integration/gitignoreMenu/expected/repo/.git_keep/FETCH_HEAD b/test/integration/gitignoreMenu/expected/repo/.git_keep/FETCH_HEAD
new file mode 100644
index 000000000..e69de29bb
diff --git a/test/integration/gitignoreMenu/expected/repo/.git_keep/HEAD b/test/integration/gitignoreMenu/expected/repo/.git_keep/HEAD
new file mode 100644
index 000000000..cb089cd89
--- /dev/null
+++ b/test/integration/gitignoreMenu/expected/repo/.git_keep/HEAD
@@ -0,0 +1 @@
+ref: refs/heads/master
diff --git a/test/integration/gitignoreMenu/expected/repo/.git_keep/config b/test/integration/gitignoreMenu/expected/repo/.git_keep/config
new file mode 100644
index 000000000..6c9406b7d
--- /dev/null
+++ b/test/integration/gitignoreMenu/expected/repo/.git_keep/config
@@ -0,0 +1,7 @@
+[core]
+ repositoryformatversion = 0
+ filemode = true
+ bare = false
+ logallrefupdates = true
+ ignorecase = true
+ precomposeunicode = true
diff --git a/test/integration/gitignoreMenu/expected/repo/.git_keep/description b/test/integration/gitignoreMenu/expected/repo/.git_keep/description
new file mode 100644
index 000000000..498b267a8
--- /dev/null
+++ b/test/integration/gitignoreMenu/expected/repo/.git_keep/description
@@ -0,0 +1 @@
+Unnamed repository; edit this file 'description' to name the repository.
diff --git a/test/integration/gitignoreMenu/expected/repo/.git_keep/info/exclude b/test/integration/gitignoreMenu/expected/repo/.git_keep/info/exclude
new file mode 100644
index 000000000..a5196d1be
--- /dev/null
+++ b/test/integration/gitignoreMenu/expected/repo/.git_keep/info/exclude
@@ -0,0 +1,6 @@
+# git ls-files --others --exclude-from=.git/info/exclude
+# Lines that start with '#' are comments.
+# For a project mostly in C, the following would be a good set of
+# exclude patterns (uncomment them if you want to use them):
+# *.[oa]
+# *~
diff --git a/test/integration/gitignoreMenu/expected/repo/.gitignore b/test/integration/gitignoreMenu/expected/repo/.gitignore
new file mode 100644
index 000000000..959aad479
--- /dev/null
+++ b/test/integration/gitignoreMenu/expected/repo/.gitignore
@@ -0,0 +1,2 @@
+
+myfile1
\ No newline at end of file
diff --git a/test/integration/gitignoreMenu/recording.json b/test/integration/gitignoreMenu/recording.json
new file mode 100644
index 000000000..7b2531e84
--- /dev/null
+++ b/test/integration/gitignoreMenu/recording.json
@@ -0,0 +1 @@
+{"KeyEvents":[{"Timestamp":3418,"Mod":0,"Key":256,"Ch":105},{"Timestamp":3721,"Mod":0,"Key":256,"Ch":105},{"Timestamp":5154,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":170,"Height":55}]}
\ No newline at end of file
diff --git a/test/integration/gitignoreMenu/setup.sh b/test/integration/gitignoreMenu/setup.sh
new file mode 100644
index 000000000..9643b2b67
--- /dev/null
+++ b/test/integration/gitignoreMenu/setup.sh
@@ -0,0 +1,13 @@
+#!/bin/sh
+
+set -e
+
+cd $1
+git config user.email "CI@example.com"
+git config user.name "CI"
+
+git init
+
+
+echo test1 > myfile1
+
diff --git a/test/integration/gitignoreMenu/test.json b/test/integration/gitignoreMenu/test.json
new file mode 100644
index 000000000..de26df98c
--- /dev/null
+++ b/test/integration/gitignoreMenu/test.json
@@ -0,0 +1,4 @@
+{
+ "description": "In this test a file is added to .gitingnore using the ignore or exclude menu",
+ "speed": 5
+}
\ No newline at end of file