From 40e989467ffcb32e546eebca25b57972b6aac6b5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Mon, 18 Aug 2025 09:20:10 +0200 Subject: [PATCH] Add a user config for using git's external diff command for paging This is similar to using lazygit's Git.Paging.ExternalDiffCommand config, except that the command is configured in git. This can be done either with git's `diff.external` config, or through .gitattributes, so it gives a bit more flexibility. --- docs/Config.md | 3 +++ docs/Custom_Pagers.md | 10 ++++++++++ pkg/commands/git_commands/commit.go | 3 ++- pkg/commands/git_commands/commit_test.go | 11 +++++++++++ pkg/commands/git_commands/diff.go | 3 ++- pkg/commands/git_commands/stash.go | 3 ++- pkg/commands/git_commands/stash_test.go | 11 +++++++++++ pkg/commands/git_commands/working_tree.go | 6 ++++-- pkg/config/user_config.go | 2 ++ schema/config.json | 5 +++++ 10 files changed, 52 insertions(+), 5 deletions(-) diff --git a/docs/Config.md b/docs/Config.md index 588f69fc9..8c4d157c1 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -306,6 +306,9 @@ git: # e.g. 'difft --color=always' externalDiffCommand: "" + # If true, Lazygit will use git's `diff.external` config for paging. The advantage over `externalDiffCommand` is that this can be configured per file type in .gitattributes; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. + useExternalDiffGitConfig: false + # Config relating to committing commit: # If true, pass '--signoff' flag when committing diff --git a/docs/Custom_Pagers.md b/docs/Custom_Pagers.md index bdd695435..77bb25d25 100644 --- a/docs/Custom_Pagers.md +++ b/docs/Custom_Pagers.md @@ -74,3 +74,13 @@ git: paging: externalDiffCommand: difft --color=always --display=inline --syntax-highlight=off ``` + +Instead of setting this command in lazygit's `externalDiffCommand` config, you can also tell lazygit to use the external diff command that is configured in git itself (`diff.external`), by using + +```yaml +git: + paging: + useExternalDiffGitConfig: true +``` + +This can be useful if you also want to use it for diffs on the command line, and it also has the advantage that you can configure it per file type in `.gitattributes`; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. diff --git a/pkg/commands/git_commands/commit.go b/pkg/commands/git_commands/commit.go index 0abb98168..084a6c8d4 100644 --- a/pkg/commands/git_commands/commit.go +++ b/pkg/commands/git_commands/commit.go @@ -257,10 +257,11 @@ func (self *CommitCommands) ShowCmdObj(hash string, filterPaths []string) *oscom contextSize := self.UserConfig().Git.DiffContextSize extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand + useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig cmdArgs := NewGitCmd("show"). Config("diff.noprefix=false"). ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd). - ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff"). + ArgIfElse(extDiffCmd != "" || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). Arg("--color="+self.UserConfig().Git.Paging.ColorArg). Arg(fmt.Sprintf("--unified=%d", contextSize)). diff --git a/pkg/commands/git_commands/commit_test.go b/pkg/commands/git_commands/commit_test.go index 84d3126b5..8460164cc 100644 --- a/pkg/commands/git_commands/commit_test.go +++ b/pkg/commands/git_commands/commit_test.go @@ -256,6 +256,7 @@ func TestCommitShowCmdObj(t *testing.T) { similarityThreshold int ignoreWhitespace bool extDiffCmd string + useExtDiffGitConfig bool expected []string } @@ -314,6 +315,15 @@ func TestCommitShowCmdObj(t *testing.T) { extDiffCmd: "difft --color=always", expected: []string{"-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "-c", "diff.noprefix=false", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--"}, }, + { + testName: "Show diff using git's external diff config", + filterPaths: []string{}, + contextSize: 3, + similarityThreshold: 50, + ignoreWhitespace: false, + useExtDiffGitConfig: true, + expected: []string{"-C", "/path/to/worktree", "-c", "diff.noprefix=false", "show", "--ext-diff", "--submodule", "--color=always", "--unified=3", "--stat", "--decorate", "-p", "1234567890", "--find-renames=50%", "--"}, + }, } for _, s := range scenarios { @@ -323,6 +333,7 @@ func TestCommitShowCmdObj(t *testing.T) { userConfig.Git.IgnoreWhitespaceInDiffView = s.ignoreWhitespace userConfig.Git.DiffContextSize = s.contextSize userConfig.Git.RenameSimilarityThreshold = s.similarityThreshold + userConfig.Git.Paging.UseExternalDiffGitConfig = s.useExtDiffGitConfig runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expected, "", nil) repoPaths := RepoPaths{ diff --git a/pkg/commands/git_commands/diff.go b/pkg/commands/git_commands/diff.go index 5f1db045f..76b677884 100644 --- a/pkg/commands/git_commands/diff.go +++ b/pkg/commands/git_commands/diff.go @@ -21,13 +21,14 @@ func NewDiffCommands(gitCommon *GitCommon) *DiffCommands { func (self *DiffCommands) DiffCmdObj(diffArgs []string) *oscommands.CmdObj { extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" + useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig ignoreWhitespace := self.UserConfig().Git.IgnoreWhitespaceInDiffView return self.cmd.New( NewGitCmd("diff"). Config("diff.noprefix=false"). ConfigIf(useExtDiff, "diff.external="+extDiffCmd). - ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff"). + ArgIfElse(useExtDiff || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). ArgIf(ignoreWhitespace, "--ignore-all-space"). diff --git a/pkg/commands/git_commands/stash.go b/pkg/commands/git_commands/stash.go index 92e5931ca..f6b69ae7d 100644 --- a/pkg/commands/git_commands/stash.go +++ b/pkg/commands/git_commands/stash.go @@ -82,6 +82,7 @@ func (self *StashCommands) Hash(index int) (string, error) { func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj { extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand + useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig // "-u" is the same as "--include-untracked", but the latter fails in older git versions for some reason cmdArgs := NewGitCmd("stash").Arg("show"). @@ -89,7 +90,7 @@ func (self *StashCommands) ShowStashEntryCmdObj(index int) *oscommands.CmdObj { Arg("--stat"). Arg("-u"). ConfigIf(extDiffCmd != "", "diff.external="+extDiffCmd). - ArgIfElse(extDiffCmd != "", "--ext-diff", "--no-ext-diff"). + ArgIfElse(extDiffCmd != "" || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg(fmt.Sprintf("--color=%s", self.UserConfig().Git.Paging.ColorArg)). Arg(fmt.Sprintf("--unified=%d", self.UserConfig().Git.DiffContextSize)). ArgIf(self.UserConfig().Git.IgnoreWhitespaceInDiffView, "--ignore-all-space"). diff --git a/pkg/commands/git_commands/stash_test.go b/pkg/commands/git_commands/stash_test.go index 24049a57f..6b21c0b83 100644 --- a/pkg/commands/git_commands/stash_test.go +++ b/pkg/commands/git_commands/stash_test.go @@ -104,6 +104,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { similarityThreshold int ignoreWhitespace bool extDiffCmd string + useExtDiffGitConfig bool expected []string } @@ -141,6 +142,15 @@ func TestStashStashEntryCmdObj(t *testing.T) { extDiffCmd: "difft --color=always", expected: []string{"git", "-C", "/path/to/worktree", "-c", "diff.external=difft --color=always", "stash", "show", "-p", "--stat", "-u", "--ext-diff", "--color=always", "--unified=3", "--find-renames=50%", "refs/stash@{5}"}, }, + { + testName: "Show diff using git's external diff config", + index: 5, + contextSize: 3, + similarityThreshold: 50, + ignoreWhitespace: false, + useExtDiffGitConfig: true, + expected: []string{"git", "-C", "/path/to/worktree", "stash", "show", "-p", "--stat", "-u", "--ext-diff", "--color=always", "--unified=3", "--find-renames=50%", "refs/stash@{5}"}, + }, { testName: "Default case", index: 5, @@ -158,6 +168,7 @@ func TestStashStashEntryCmdObj(t *testing.T) { userConfig.Git.DiffContextSize = s.contextSize userConfig.Git.RenameSimilarityThreshold = s.similarityThreshold userConfig.Git.Paging.ExternalDiffCommand = s.extDiffCmd + userConfig.Git.Paging.UseExternalDiffGitConfig = s.useExtDiffGitConfig repoPaths := RepoPaths{ worktreePath: "/path/to/worktree", } diff --git a/pkg/commands/git_commands/working_tree.go b/pkg/commands/git_commands/working_tree.go index e4922a4f2..4c4d27b89 100644 --- a/pkg/commands/git_commands/working_tree.go +++ b/pkg/commands/git_commands/working_tree.go @@ -267,10 +267,11 @@ func (self *WorkingTreeCommands) WorktreeFileDiffCmdObj(node models.IFile, plain noIndex := !node.GetIsTracked() && !node.GetHasStagedChanges() && !cached && node.GetIsFile() extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" && !plain + useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig cmdArgs := NewGitCmd("diff"). ConfigIf(useExtDiff, "diff.external="+extDiffCmd). - ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff"). + ArgIfElse(useExtDiff || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). Arg(fmt.Sprintf("--unified=%d", contextSize)). Arg(fmt.Sprintf("--color=%s", colorArg)). @@ -304,11 +305,12 @@ func (self *WorkingTreeCommands) ShowFileDiffCmdObj(from string, to string, reve extDiffCmd := self.UserConfig().Git.Paging.ExternalDiffCommand useExtDiff := extDiffCmd != "" && !plain + useExtDiffGitConfig := self.UserConfig().Git.Paging.UseExternalDiffGitConfig cmdArgs := NewGitCmd("diff"). Config("diff.noprefix=false"). ConfigIf(useExtDiff, "diff.external="+extDiffCmd). - ArgIfElse(useExtDiff, "--ext-diff", "--no-ext-diff"). + ArgIfElse(useExtDiff || useExtDiffGitConfig, "--ext-diff", "--no-ext-diff"). Arg("--submodule"). Arg(fmt.Sprintf("--unified=%d", contextSize)). Arg("--no-renames"). diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 914bf3117..66a5cddd3 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -318,6 +318,8 @@ type PagingConfig struct { Pager PagerType `yaml:"pager"` // e.g. 'difft --color=always' ExternalDiffCommand string `yaml:"externalDiffCommand"` + // If true, Lazygit will use git's `diff.external` config for paging. The advantage over `externalDiffCommand` is that this can be configured per file type in .gitattributes; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver. + UseExternalDiffGitConfig bool `yaml:"useExternalDiffGitConfig"` } type CommitConfig struct { diff --git a/schema/config.json b/schema/config.json index ebf59e98b..47d125e87 100644 --- a/schema/config.json +++ b/schema/config.json @@ -1675,6 +1675,11 @@ "externalDiffCommand": { "type": "string", "description": "e.g. 'difft --color=always'" + }, + "useExternalDiffGitConfig": { + "type": "boolean", + "description": "If true, Lazygit will use git's `diff.external` config for paging. The advantage over `externalDiffCommand` is that this can be configured per file type in .gitattributes; see https://git-scm.com/docs/gitattributes#_defining_an_external_diff_driver.", + "default": false } }, "additionalProperties": false,