Repository: JanDeDobbeleer/oh-my-posh
Pull request #2459 (2022-06-30 16:08:05)

git features
### Prerequisites

- [x] I have read and understood the [contributing guide][CONTRIBUTING.md]
- [x] The commit message follows the [conventional commits][cc] guidelines
- [x] Tests for the changes have been added (for bug fixes/features)
- [x] Docs have been added/updated (for bug fixes/features)

### Description

- feat(git): override untracked mode for all repo's
- feat(git): set ignore-submodules flag


<!---

Tips:

If you're not comfortable with working with Git, we're working a guide (https://ohmyposh.dev/docs/contributing_git) to help you out.
Oh My Posh advises GitKraken (https://www.gitkraken.com/invite/nQmDPR9D) as your preferred cross platform Git GUI power tool.

-->

[CONTRIBUTING.md]: https://github.com/JanDeDobbeleer/oh-my-posh/blob/main/CONTRIBUTING.md
[cc]: https://www.conventionalcommits.org/en/v1.0.0/#summary



Patch:
diff --git a/src/segments/git.go b/src/segments/git.go
index 5d1b4e9d..0e4c0a3b 100644
--- a/src/segments/git.go
+++ b/src/segments/git.go
@@ -98,6 +98,8 @@ const (
 	GitIcon properties.Property = "git_icon"
 	// UntrackedModes list the optional untracked files mode per repo
 	UntrackedModes properties.Property = "untracked_modes"
+	// IgnoreSubmodules list the optional ignore-submodules mode per repo
+	IgnoreSubmodules properties.Property = "ignore_submodules"
 
 	DETACHED     = "(detached)"
 	BRANCHPREFIX = "ref: refs/heads/"
@@ -266,7 +268,12 @@ func (g *Git) setGitStatus() {
 	g.Working = &GitStatus{}
 	g.Staging = &GitStatus{}
 	untrackedMode := g.getUntrackedFilesMode()
-	output := g.getGitCommandOutput("status", untrackedMode, "--branch", "--porcelain=2")
+	args := []string{"status", untrackedMode, "--branch", "--porcelain=2"}
+	ignoreSubmodulesMode := g.getIgnoreSubmodulesMode()
+	if len(ignoreSubmodulesMode) > 0 {
+		args = append(args, ignoreSubmodulesMode)
+	}
+	output := g.getGitCommandOutput(args...)
 	for _, line := range strings.Split(output, "\n") {
 		if strings.HasPrefix(line, HASH) && len(line) >= len(HASH)+7 {
 			g.Hash = line[len(HASH) : len(HASH)+7]
@@ -516,10 +523,25 @@ func (g *Git) getOriginURL(upstream string) string {
 }
 
 func (g *Git) getUntrackedFilesMode() string {
-	mode := "normal"
-	repoModes := g.props.GetKeyValueMap(UntrackedModes, map[string]string{})
+	return g.getSwitchMode(UntrackedModes, "-u", "normal")
+}
+
+func (g *Git) getIgnoreSubmodulesMode() string {
+	return g.getSwitchMode(IgnoreSubmodules, "--ignore-submodules=", "")
+}
+
+func (g *Git) getSwitchMode(property properties.Property, gitSwitch, mode string) string {
+	repoModes := g.props.GetKeyValueMap(property, map[string]string{})
+	// make use of a wildcard for all repo's
+	if val := repoModes["*"]; len(val) != 0 {
+		mode = val
+	}
+	// get the specific repo mode
 	if val := repoModes[g.realFolder]; len(val) != 0 {
 		mode = val
 	}
-	return fmt.Sprintf("-u%s", mode)
+	if len(mode) == 0 {
+		return ""
+	}
+	return fmt.Sprintf("%s%s", gitSwitch, mode)
 }
diff --git a/themes/schema.json b/themes/schema.json
index 8f960116..03495b15 100644
--- a/themes/schema.json
+++ b/themes/schema.json
@@ -786,6 +786,12 @@
                     "title": "Untracked files mode",
                     "description": "Set the untracked files mode for a repository",
                     "default": {}
+                  },
+                  "ignore_submodules": {
+                    "type": "object",
+                    "title": "Ignore submodules",
+                    "description": "Ignore changes to submodules when looking for changes",
+                    "default": {}
                   }
                 }
               }
diff --git a/website/docs/segments/git.mdx b/website/docs/segments/git.mdx
index 2b438ae6..f4049de5 100644
--- a/website/docs/segments/git.mdx
+++ b/website/docs/segments/git.mdx
@@ -66,8 +66,12 @@ You can set the following properties to `true` to enable fetching additional inf
 - fetch_stash_count: `boolean` fetch stash count - defaults to `false`
 - fetch_worktree_count: `boolean` fetch worktree count - defaults to `false`
 - fetch_upstream_icon: `boolean` - fetch upstream icon - defaults to `false`
-- untracked_modes: `map[string]string` - map of repo's where to override the default untracked mode (`no` | `normal` | `all`). For example
-`"untracked_modes": { "/Users/me/repos/repo1": "no" }` - defaults to `normal` for all repo's
+- untracked_modes: `map[string]string` - map of repo's where to override the default [untracked files mode][untracked] (`no` | `normal` | `all`). For example
+`"untracked_modes": { "/Users/me/repos/repo1": "no" }` - defaults to `normal` for all repo's. If you want to override for all repo's, use
+`*` to set the mode instead of the repo path.
+- ignore_submodules: `map[string]string` - map of repo's where to change the [--ignore-submodules][submodules] flag (`none`, `untracked`, `dirty` or `all`).
+For example `"ignore_submodules": { "/Users/me/repos/repo1": "all" }`. If you want to override for all repo's, use `*` to set the mode
+instead of the repo path.
 
 ### Icons
 
@@ -137,3 +141,5 @@ You can set the following properties to `true` to enable fetching additional inf
 [poshgit]: /docs/segments/poshgit
 [templates]: /docs/configuration/templates
 [hyperlinks]: /docs/configuration/templates#helper-functions
+[untracked]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---untracked-filesltmodegt
+[submodules]: https://git-scm.com/docs/git-status#Documentation/git-status.txt---ignore-submodulesltwhengt


Test patch:
diff --git a/src/segments/git_test.go b/src/segments/git_test.go
index 521b89df..e37139b2 100644
--- a/src/segments/git_test.go
+++ b/src/segments/git_test.go
@@ -788,6 +788,13 @@ func TestGitUntrackedMode(t *testing.T) {
 				"bar": "normal",
 			},
 		},
+		{
+			Case:     "Global mode",
+			Expected: "-uno",
+			UntrackedModes: map[string]string{
+				"*": "no",
+			},
+		},
 	}
 
 	for _, tc := range cases {
@@ -803,3 +810,45 @@ func TestGitUntrackedMode(t *testing.T) {
 		assert.Equal(t, tc.Expected, got, tc.Case)
 	}
 }
+
+func TestGitIgnoreSubmodules(t *testing.T) {
+	cases := []struct {
+		Case             string
+		Expected         string
+		IgnoreSubmodules map[string]string
+	}{
+		{
+			Case:     "Overide",
+			Expected: "--ignore-submodules=all",
+			IgnoreSubmodules: map[string]string{
+				"foo": "all",
+			},
+		},
+		{
+			Case: "Default mode - empty",
+			IgnoreSubmodules: map[string]string{
+				"bar": "no",
+			},
+		},
+		{
+			Case:     "Global mode",
+			Expected: "--ignore-submodules=dirty",
+			IgnoreSubmodules: map[string]string{
+				"*": "dirty",
+			},
+		},
+	}
+
+	for _, tc := range cases {
+		g := &Git{
+			scm: scm{
+				props: properties.Map{
+					IgnoreSubmodules: tc.IgnoreSubmodules,
+				},
+				realFolder: "foo",
+			},
+		}
+		got := g.getIgnoreSubmodulesMode()
+		assert.Equal(t, tc.Expected, got, tc.Case)
+	}
+}