Skip to content

Commit a51bf12

Browse files
authored
Commit without pre-commit hooks action is independent on prefix (#4374)
As discussed in #1984, this PR modifies the code such that the `w` command always commits without pre-commit hooks. The `skipHookPrefix` is still considered when starting the commit messaged with the prefix in the regular commit command using `c`. Skipping pre-commits also works when switching to the editor and adding a co author from the the `w` command
2 parents ab9f4af + 728f0d9 commit a51bf12

13 files changed

+254
-35
lines changed

Diff for: pkg/commands/git_commands/commit.go

+4-5
Original file line numberDiff line numberDiff line change
@@ -85,13 +85,11 @@ func (self *CommitCommands) ResetToCommit(hash string, strength string, envVars
8585
Run()
8686
}
8787

88-
func (self *CommitCommands) CommitCmdObj(summary string, description string) oscommands.ICmdObj {
88+
func (self *CommitCommands) CommitCmdObj(summary string, description string, forceSkipHooks bool) oscommands.ICmdObj {
8989
messageArgs := self.commitMessageArgs(summary, description)
90-
9190
skipHookPrefix := self.UserConfig().Git.SkipHookPrefix
92-
9391
cmdArgs := NewGitCmd("commit").
94-
ArgIf(skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix), "--no-verify").
92+
ArgIf(forceSkipHooks || (skipHookPrefix != "" && strings.HasPrefix(summary, skipHookPrefix)), "--no-verify").
9593
ArgIf(self.signoffFlag() != "", self.signoffFlag()).
9694
Arg(messageArgs...).
9795
ToArgv()
@@ -108,8 +106,9 @@ func (self *CommitCommands) RewordLastCommitInEditorWithMessageFileCmdObj(tmpMes
108106
Arg("--allow-empty", "--amend", "--only", "--edit", "--file="+tmpMessageFile).ToArgv())
109107
}
110108

111-
func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string) oscommands.ICmdObj {
109+
func (self *CommitCommands) CommitInEditorWithMessageFileCmdObj(tmpMessageFile string, forceSkipHooks bool) oscommands.ICmdObj {
112110
return self.cmd.New(NewGitCmd("commit").
111+
ArgIf(forceSkipHooks, "--no-verify").
113112
Arg("--edit").
114113
Arg("--file="+tmpMessageFile).
115114
ArgIf(self.signoffFlag() != "", self.signoffFlag()).

Diff for: pkg/commands/git_commands/commit_test.go

+24-2
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
5353
type scenario struct {
5454
testName string
5555
summary string
56+
forceSkipHooks bool
5657
description string
5758
configSignoff bool
5859
configSkipHookPrefix string
@@ -63,20 +64,39 @@ func TestCommitCommitCmdObj(t *testing.T) {
6364
{
6465
testName: "Commit",
6566
summary: "test",
67+
forceSkipHooks: false,
6668
configSignoff: false,
6769
configSkipHookPrefix: "",
6870
expectedArgs: []string{"commit", "-m", "test"},
6971
},
7072
{
71-
testName: "Commit with --no-verify flag",
73+
testName: "Commit with --no-verify flag < only prefix",
7274
summary: "WIP: test",
75+
forceSkipHooks: false,
7376
configSignoff: false,
7477
configSkipHookPrefix: "WIP",
7578
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
7679
},
80+
{
81+
testName: "Commit with --no-verify flag < skip flag and prefix",
82+
summary: "WIP: test",
83+
forceSkipHooks: true,
84+
configSignoff: false,
85+
configSkipHookPrefix: "WIP",
86+
expectedArgs: []string{"commit", "--no-verify", "-m", "WIP: test"},
87+
},
88+
{
89+
testName: "Commit with --no-verify flag < skip flag no prefix",
90+
summary: "test",
91+
forceSkipHooks: true,
92+
configSignoff: false,
93+
configSkipHookPrefix: "WIP",
94+
expectedArgs: []string{"commit", "--no-verify", "-m", "test"},
95+
},
7796
{
7897
testName: "Commit with multiline message",
7998
summary: "line1",
99+
forceSkipHooks: false,
80100
description: "line2",
81101
configSignoff: false,
82102
configSkipHookPrefix: "",
@@ -85,13 +105,15 @@ func TestCommitCommitCmdObj(t *testing.T) {
85105
{
86106
testName: "Commit with signoff",
87107
summary: "test",
108+
forceSkipHooks: false,
88109
configSignoff: true,
89110
configSkipHookPrefix: "",
90111
expectedArgs: []string{"commit", "--signoff", "-m", "test"},
91112
},
92113
{
93114
testName: "Commit with signoff and no-verify",
94115
summary: "WIP: test",
116+
forceSkipHooks: true,
95117
configSignoff: true,
96118
configSkipHookPrefix: "WIP",
97119
expectedArgs: []string{"commit", "--no-verify", "--signoff", "-m", "WIP: test"},
@@ -107,7 +129,7 @@ func TestCommitCommitCmdObj(t *testing.T) {
107129
runner := oscommands.NewFakeRunner(t).ExpectGitArgs(s.expectedArgs, "", nil)
108130
instance := buildCommitCommands(commonDeps{userConfig: userConfig, runner: runner})
109131

110-
assert.NoError(t, instance.CommitCmdObj(s.summary, s.description).Run())
132+
assert.NoError(t, instance.CommitCmdObj(s.summary, s.description, s.forceSkipHooks).Run())
111133
runner.CheckForMissingCalls()
112134
})
113135
}

Diff for: pkg/commands/git_commands/patch.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -303,7 +303,7 @@ func (self *PatchCommands) PullPatchIntoNewCommit(
303303
return err
304304
}
305305

306-
if err := self.commit.CommitCmdObj(commitSummary, commitDescription).Run(); err != nil {
306+
if err := self.commit.CommitCmdObj(commitSummary, commitDescription, false).Run(); err != nil {
307307
return err
308308
}
309309

Diff for: pkg/gui/controllers/helpers/merge_and_rebase_helper.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -481,7 +481,7 @@ func (self *MergeAndRebaseHelper) SquashMergeCommitted(refName, checkedOutBranch
481481
"selectedRef": refName,
482482
"currentBranch": checkedOutBranchName,
483483
})
484-
err = self.c.Git().Commit.CommitCmdObj(message, "").Run()
484+
err = self.c.Git().Commit.CommitCmdObj(message, "", false).Run()
485485
if err != nil {
486486
return err
487487
}

Diff for: pkg/gui/controllers/helpers/working_tree_helper.go

+13-14
Original file line numberDiff line numberDiff line change
@@ -86,7 +86,7 @@ func (self *WorkingTreeHelper) OpenMergeTool() error {
8686
return nil
8787
}
8888

89-
func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage string) error {
89+
func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage string, forceSkipHooks bool) error {
9090
return self.WithEnsureCommittableFiles(func() error {
9191
self.commitsHelper.OpenCommitMessagePanel(
9292
&OpenCommitMessagePanelOpts{
@@ -95,25 +95,29 @@ func (self *WorkingTreeHelper) HandleCommitPressWithMessage(initialMessage strin
9595
SummaryTitle: self.c.Tr.CommitSummaryTitle,
9696
DescriptionTitle: self.c.Tr.CommitDescriptionTitle,
9797
PreserveMessage: true,
98-
OnConfirm: self.handleCommit,
99-
OnSwitchToEditor: self.switchFromCommitMessagePanelToEditor,
98+
OnConfirm: func(summary string, description string) error {
99+
return self.handleCommit(summary, description, forceSkipHooks)
100+
},
101+
OnSwitchToEditor: func(filepath string) error {
102+
return self.switchFromCommitMessagePanelToEditor(filepath, forceSkipHooks)
103+
},
100104
},
101105
)
102106

103107
return nil
104108
})
105109
}
106110

107-
func (self *WorkingTreeHelper) handleCommit(summary string, description string) error {
108-
cmdObj := self.c.Git().Commit.CommitCmdObj(summary, description)
111+
func (self *WorkingTreeHelper) handleCommit(summary string, description string, forceSkipHooks bool) error {
112+
cmdObj := self.c.Git().Commit.CommitCmdObj(summary, description, forceSkipHooks)
109113
self.c.LogAction(self.c.Tr.Actions.Commit)
110114
return self.gpgHelper.WithGpgHandling(cmdObj, self.c.Tr.CommittingStatus, func() error {
111115
self.commitsHelper.OnCommitSuccess()
112116
return nil
113117
})
114118
}
115119

116-
func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath string) error {
120+
func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath string, forceSkipHooks bool) error {
117121
// We won't be able to tell whether the commit was successful, because
118122
// RunSubprocessAndRefresh doesn't return the error (it opens an error alert
119123
// itself and returns nil on error). But even if we could, we wouldn't have
@@ -124,7 +128,7 @@ func (self *WorkingTreeHelper) switchFromCommitMessagePanelToEditor(filepath str
124128

125129
self.c.LogAction(self.c.Tr.Actions.Commit)
126130
return self.c.RunSubprocessAndRefresh(
127-
self.c.Git().Commit.CommitInEditorWithMessageFileCmdObj(filepath),
131+
self.c.Git().Commit.CommitInEditorWithMessageFileCmdObj(filepath, forceSkipHooks),
128132
)
129133
}
130134

@@ -140,12 +144,7 @@ func (self *WorkingTreeHelper) HandleCommitEditorPress() error {
140144
}
141145

142146
func (self *WorkingTreeHelper) HandleWIPCommitPress() error {
143-
skipHookPrefix := self.c.UserConfig().Git.SkipHookPrefix
144-
if skipHookPrefix == "" {
145-
return errors.New(self.c.Tr.SkipHookPrefixNotConfigured)
146-
}
147-
148-
return self.HandleCommitPressWithMessage(skipHookPrefix)
147+
return self.HandleCommitPressWithMessage("", true)
149148
}
150149

151150
func (self *WorkingTreeHelper) HandleCommitPress() error {
@@ -173,7 +172,7 @@ func (self *WorkingTreeHelper) HandleCommitPress() error {
173172
}
174173
}
175174

176-
return self.HandleCommitPressWithMessage(message)
175+
return self.HandleCommitPressWithMessage(message, false)
177176
}
178177

179178
func (self *WorkingTreeHelper) WithEnsureCommittableFiles(handler func() error) error {

Diff for: pkg/i18n/english.go

-2
Original file line numberDiff line numberDiff line change
@@ -449,7 +449,6 @@ type TranslationSet struct {
449449
ExecuteShellCommandTooltip string
450450
ShellCommand string
451451
CommitChangesWithoutHook string
452-
SkipHookPrefixNotConfigured string
453452
ResetTo string
454453
ResetSoftTooltip string
455454
ResetMixedTooltip string
@@ -1500,7 +1499,6 @@ func EnglishTranslationSet() *TranslationSet {
15001499
ExecuteShellCommandTooltip: "Bring up a prompt where you can enter a shell command to execute.",
15011500
ShellCommand: "Shell command:",
15021501
CommitChangesWithoutHook: "Commit changes without pre-commit hook",
1503-
SkipHookPrefixNotConfigured: "You have not configured a commit message prefix for skipping hooks. Set `git.skipHookPrefix = 'WIP'` in your config",
15041502
ResetTo: `Reset to`,
15051503
PressEnterToReturn: "Press enter to return to lazygit",
15061504
ViewStashOptions: "View stash options",

Diff for: pkg/integration/tests/commit/commit_skip_hooks.go

+44
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
package commit
2+
3+
import (
4+
"github.com/jesseduffield/lazygit/pkg/config"
5+
. "github.com/jesseduffield/lazygit/pkg/integration/components"
6+
)
7+
8+
var blockingHook = `#!/bin/bash
9+
10+
# For this test all we need is a hook that always fails
11+
exit 1
12+
`
13+
14+
var CommitSkipHooks = NewIntegrationTest(NewIntegrationTestArgs{
15+
Description: "Commit with skip hook using CommitChangesWithoutHook",
16+
ExtraCmdArgs: []string{},
17+
Skip: false,
18+
SetupConfig: func(config *config.AppConfig) {},
19+
SetupRepo: func(shell *Shell) {
20+
shell.CreateFile(".git/hooks/pre-commit", blockingHook)
21+
shell.MakeExecutable(".git/hooks/pre-commit")
22+
23+
shell.CreateFile("file.txt", "content")
24+
},
25+
Run: func(t *TestDriver, keys config.KeybindingConfig) {
26+
checkBlockingHook(t, keys)
27+
28+
t.Views().Files().
29+
IsFocused().
30+
PressPrimaryAction().
31+
Lines(
32+
Equals("A file.txt"),
33+
).
34+
Press(keys.Files.CommitChangesWithoutHook)
35+
36+
t.ExpectPopup().CommitMessagePanel().
37+
Title(Equals("Commit summary")).
38+
Type("foo bar").
39+
Confirm()
40+
41+
t.Views().Commits().Focus()
42+
t.Views().Main().Content(Contains("foo bar"))
43+
},
44+
})
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
package commit
2+
3+
import (
4+
"github.com/jesseduffield/lazygit/pkg/config"
5+
. "github.com/jesseduffield/lazygit/pkg/integration/components"
6+
)
7+
8+
var CommitSwitchToEditorSkipHooks = NewIntegrationTest(NewIntegrationTestArgs{
9+
Description: "Commit, then switch from built-in commit message panel to editor",
10+
ExtraCmdArgs: []string{},
11+
Skip: false,
12+
SetupConfig: func(config *config.AppConfig) {},
13+
SetupRepo: func(shell *Shell) {
14+
shell.CreateFile(".git/hooks/pre-commit", blockingHook)
15+
shell.MakeExecutable(".git/hooks/pre-commit")
16+
shell.CreateFile("file1", "file1 content")
17+
shell.CreateFile("file2", "file2 content")
18+
19+
// Set an editor that appends a line to the existing message. Since
20+
// git adds all this "# Please enter the commit message for your changes"
21+
// stuff, this will result in an extra blank line before the added line.
22+
shell.SetConfig("core.editor", "sh -c 'echo third line >>.git/COMMIT_EDITMSG'")
23+
},
24+
Run: func(t *TestDriver, keys config.KeybindingConfig) {
25+
t.Views().Commits().
26+
IsEmpty()
27+
28+
checkBlockingHook(t, keys)
29+
30+
t.Views().Files().
31+
IsFocused().
32+
Lines(
33+
Equals("▼ /").IsSelected(),
34+
Equals(" ?? file1"),
35+
Equals(" ?? file2"),
36+
).
37+
SelectNextItem().
38+
PressPrimaryAction(). // stage one of the files
39+
Press(keys.Files.CommitChangesWithoutHook)
40+
41+
t.ExpectPopup().CommitMessagePanel().
42+
Type("first line").
43+
SwitchToDescription().
44+
Type("second line").
45+
SwitchToSummary().
46+
SwitchToEditor()
47+
t.Views().Commits().
48+
Lines(
49+
Contains("first line"),
50+
)
51+
52+
t.Views().Commits().Focus()
53+
t.Views().Main().Content(MatchesRegexp(`first line\n\s*\n\s*second line\n\s*\n\s*third line`))
54+
55+
// Now check that the preserved commit message was cleared:
56+
t.Views().Files().
57+
Focus().
58+
PressPrimaryAction(). // stage the other file
59+
Press(keys.Files.CommitChanges)
60+
61+
t.ExpectPopup().CommitMessagePanel().
62+
InitialText(Equals(""))
63+
},
64+
})

Diff for: pkg/integration/tests/commit/commit_wip_with_prefix.go

+11-7
Original file line numberDiff line numberDiff line change
@@ -13,45 +13,49 @@ var CommitWipWithPrefix = NewIntegrationTest(NewIntegrationTestArgs{
1313
cfg.GetUserConfig().Git.CommitPrefixes = map[string][]config.CommitPrefixConfig{"repo": {{Pattern: "^\\w+\\/(\\w+-\\w+).*", Replace: "[$1]: "}}}
1414
},
1515
SetupRepo: func(shell *Shell) {
16+
shell.CreateFile(".git/hooks/pre-commit", blockingHook)
17+
shell.MakeExecutable(".git/hooks/pre-commit")
18+
1619
shell.NewBranch("feature/TEST-002")
1720
shell.CreateFile("test-wip-commit-prefix", "This is foo bar")
1821
},
1922
Run: func(t *TestDriver, keys config.KeybindingConfig) {
2023
t.Views().Commits().
2124
IsEmpty()
2225

26+
checkBlockingHook(t, keys)
27+
2328
t.Views().Files().
2429
IsFocused().
2530
PressPrimaryAction().
2631
Press(keys.Files.CommitChangesWithoutHook)
2732

2833
t.ExpectPopup().CommitMessagePanel().
2934
Title(Equals("Commit summary")).
30-
InitialText(Equals("WIP")).
31-
Type(" foo").
35+
Type("foo").
3236
Cancel()
3337

3438
t.Views().Files().
3539
IsFocused().
36-
Press(keys.Files.CommitChanges)
40+
Press(keys.Files.CommitChangesWithoutHook)
3741

3842
t.ExpectPopup().CommitMessagePanel().
3943
Title(Equals("Commit summary")).
40-
InitialText(Equals("WIP foo")).
44+
InitialText(Equals("foo")).
4145
Type(" bar").
4246
Cancel()
4347

4448
t.Views().Files().
4549
IsFocused().
46-
Press(keys.Files.CommitChanges)
50+
Press(keys.Files.CommitChangesWithoutHook)
4751

4852
t.ExpectPopup().CommitMessagePanel().
4953
Title(Equals("Commit summary")).
50-
InitialText(Equals("WIP foo bar")).
54+
InitialText(Equals("foo bar")).
5155
Type(". Added something else").
5256
Confirm()
5357

5458
t.Views().Commits().Focus()
55-
t.Views().Main().Content(Contains("WIP foo bar. Added something else"))
59+
t.Views().Main().Content(Contains("foo bar. Added something else"))
5660
},
5761
})

0 commit comments

Comments
 (0)