This commit is contained in:
Tobias Deiminger 2026-09-05 10:43:23 +00:00 committed by GitHub
commit 8386dada1a
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
15 changed files with 186 additions and 6 deletions

View file

@ -809,6 +809,7 @@ keybinding:
resetAuthor: a
setAuthor: A
addCoAuthor: c
signOff: s
stash:
popStash: g
renameStash: r

View file

@ -102,7 +102,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` V `` | Paste (cherry-pick) | |
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
| `` A `` | Amend | Amend commit with staged changes. If the selected commit is the HEAD commit, this will perform `git commit --amend`. Otherwise the commit will be amended via a rebase. |
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
| `` a `` | Amend commit attribute | Set/Reset commit author, set co-author, or sign off the commit. |
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
| `` <ctrl+l> `` | View log options | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |

View file

@ -313,7 +313,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` V `` | 커밋을 붙여넣기 (cherry-pick) | |
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
| `` A `` | Amend | Amend commit with staged changes |
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
| `` a `` | Amend commit attribute | Set/Reset commit author, set co-author, or sign off the commit. |
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
| `` T `` | Tag commit | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
| `` <ctrl+l> `` | 로그 메뉴 열기 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |

View file

@ -174,7 +174,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` V `` | Plak commits (cherry-pick) | |
| `` B `` | Markeer als basiscommit voor rebase | Selecteer een basiscommit voor de volgende rebase. Als je rebased op een branch worden alleen commits boven de basiscommit meegenomen. Hiervoor wordt het `git rebase --onto` commando gebruikt. |
| `` A `` | Amend | Wijzig commit met staged veranderingen |
| `` a `` | Amend commit attribute | Set/Reset commit author or set co-author. |
| `` a `` | Amend commit attribute | Set/Reset commit author, set co-author, or sign off the commit. |
| `` t `` | Revert | Maak een revert commit voor de geselecteerde commit, die de wijzigingen in deze commit terugdraait. |
| `` T `` | Tag commit | Maak een nieuwe tag die naar de geselecteerde commit wijst. Je wordt gevraagd om een tag naam en optionele omschrijving. |
| `` <ctrl+l> `` | Log opties weergeven | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |

View file

@ -184,7 +184,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` V `` | Вставить отобранные коммиты (cherry-pick) | |
| `` B `` | Mark as base commit for rebase | Select a base commit for the next rebase. When you rebase onto a branch, only commits above the base commit will be brought across. This uses the `git rebase --onto` command. |
| `` A `` | Amend | Править последний коммит с проиндексированными изменениями |
| `` a `` | Установить/убрать автора коммита | Set/Reset commit author or set co-author. |
| `` a `` | Установить/убрать автора коммита | Set/Reset commit author, set co-author, or sign off the commit. |
| `` t `` | Revert | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
| `` T `` | Пометить коммит тегом | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
| `` <ctrl+l> `` | Открыть меню журнала | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |

View file

@ -198,7 +198,7 @@ _This file is auto-generated. To update, make the changes in the pkg/i18n direct
| `` V `` | 貼上提交 (揀選) | |
| `` B `` | 為了變基已標注提交為基準提交 | 請為了下一次變基選擇一項基準提交;此將執行 `git rebase --onto`。 |
| `` A `` | 修改 | 使用已預存的更改修正提交 |
| `` a `` | 設定/重設提交作者 | Set/Reset commit author or set co-author. |
| `` a `` | 設定/重設提交作者 | Set/Reset commit author, set co-author, or sign off the commit. |
| `` t `` | 還原 | Create a revert commit for the selected commit, which applies the selected commit's changes in reverse. |
| `` T `` | 打標籤到提交 | Create a new tag pointing at the selected commit. You'll be prompted to enter a tag name and optional description. |
| `` <ctrl+l> `` | 開啟記錄選單 | View options for commit log e.g. changing sort order, hiding the git graph, showing the whole git graph. |

View file

@ -29,6 +29,15 @@ func (self *CommitCommands) ResetAuthor() error {
return self.cmd.New(cmdArgs).Run()
}
// Adds a Signed-off-by trailer to the topmost commit
func (self *CommitCommands) SignOff() error {
cmdArgs := NewGitCmd("commit").
Arg("--allow-empty", "--allow-empty-message", "--only", "--no-edit", "--amend", "--signoff").
ToArgv()
return self.cmd.New(cmdArgs).Run()
}
// Sets the commit's author to the supplied value. Value is expected to be of the form 'Name <Email>'
func (self *CommitCommands) SetAuthor(value string) error {
cmdArgs := NewGitCmd("commit").

View file

@ -80,6 +80,12 @@ func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, start, end
})
}
func (self *RebaseCommands) SignOffCommit(commits []*models.Commit, start, end int) error {
return self.GenericAmend(commits, start, end, func(_ *models.Commit) error {
return self.commit.SignOff()
})
}
func (self *RebaseCommands) AddCommitCoAuthor(commits []*models.Commit, start, end int, value string) error {
return self.GenericAmend(commits, start, end, func(commit *models.Commit) error {
return self.commit.AddCoAuthor(commit.Hash(), value)

View file

@ -646,6 +646,7 @@ type KeybindingAmendAttributeConfig struct {
ResetAuthor Keybinding `yaml:"resetAuthor"`
SetAuthor Keybinding `yaml:"setAuthor"`
AddCoAuthor Keybinding `yaml:"addCoAuthor"`
SignOff Keybinding `yaml:"signOff"`
}
type KeybindingStashConfig struct {
@ -1159,6 +1160,7 @@ func GetDefaultConfigForPlatform(platform string) *UserConfig {
ResetAuthor: Keybinding{"a"},
SetAuthor: Keybinding{"A"},
AddCoAuthor: Keybinding{"c"},
SignOff: Keybinding{"s"},
},
Stash: KeybindingStashConfig{
PopStash: Keybinding{"g"},

View file

@ -1301,10 +1301,31 @@ func (self *LocalCommitsController) amendAttribute(_ []*models.Commit, start, en
Keys: opts.GetKeys(opts.Config.AmendAttribute.AddCoAuthor),
Tooltip: self.c.Tr.AddCoAuthorTooltip,
},
{
Label: self.c.Tr.SignOffCommit,
OnPress: func() error { return self.signOffCommit(commits, start, end) },
Keys: opts.GetKeys(opts.Config.AmendAttribute.SignOff),
Tooltip: self.c.Tr.SignOffCommitTooltip,
},
},
})
}
func (self *LocalCommitsController) signOffCommit(commits []*models.Commit, start, end int) error {
return self.c.WithWaitingStatusBlockingInput(types.WaitingStatusOpts{
Message: self.c.Tr.AmendingStatus,
HideWorkingTreeState: true,
}, func(gocui.Task) error {
self.c.LogAction(self.c.Tr.Actions.SignOffCommit)
if err := self.c.Git().Rebase.SignOffCommit(commits, start, end); err != nil {
return err
}
self.c.RefreshFromWorker(types.RefreshOptions{})
return nil
})
}
func (self *LocalCommitsController) resetAuthor(commits []*models.Commit, start, end int) error {
return self.c.WithWaitingStatusBlockingInput(types.WaitingStatusOpts{
Message: self.c.Tr.AmendingStatus,

View file

@ -197,6 +197,8 @@ type TranslationSet struct {
ResetAuthorTooltip string
SetAuthor string
SetAuthorTooltip string
SignOffCommit string
SignOffCommitTooltip string
AddCoAuthor string
AmendCommitAttribute string
AmendCommitAttributeTooltip string
@ -1037,6 +1039,7 @@ type Actions struct {
ResetCommitAuthor string
SetCommitAuthor string
AddCommitCoAuthor string
SignOffCommit string
RevertCommit string
CreateFixupCommit string
SquashAllAboveFixupCommits string
@ -1355,9 +1358,11 @@ func EnglishTranslationSet() *TranslationSet {
ResetAuthorTooltip: "Reset the commit's author to the currently configured user. This will also renew the author timestamp",
SetAuthor: "Set author",
SetAuthorTooltip: "Set the author based on a prompt",
SignOffCommit: "Sign off",
SignOffCommitTooltip: "Add a Signed-off-by trailer to the commit.",
AddCoAuthor: "Add co-author",
AmendCommitAttribute: "Amend commit attribute",
AmendCommitAttributeTooltip: "Set/Reset commit author or set co-author.",
AmendCommitAttributeTooltip: "Set/Reset commit author, set co-author, or sign off the commit.",
SetAuthorPromptTitle: "Set author (must look like 'Name <Email>')",
AddCoAuthorPromptTitle: "Add co-author (must look like 'Name <Email>')",
AddCoAuthorTooltip: "Add co-author using the Github/Gitlab metadata Co-authored-by.",
@ -2154,6 +2159,7 @@ func EnglishTranslationSet() *TranslationSet {
ResetCommitAuthor: "Reset commit author",
SetCommitAuthor: "Set commit author",
AddCommitCoAuthor: "Add commit co-author",
SignOffCommit: "Sign off commit",
RevertCommit: "Revert commit",
CreateFixupCommit: "Create fixup commit",
SquashAllAboveFixupCommits: "Squash all above fixup commits",

View file

@ -0,0 +1,36 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var SignOff = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Sign off a commit",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("initial commit")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("initial commit").IsSelected(),
).
Press(keys.Commits.ResetCommitAuthor).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Amend commit attribute")).
Select(Contains("Sign off")).
Confirm()
})
t.Views().Main().ContainsLines(
Equals(" initial commit"),
Equals(" "),
Equals(" Signed-off-by: CI <CI@example.com>"),
)
},
})

View file

@ -0,0 +1,83 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var SignOffRange = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Sign off a range of commits",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("fourth commit")
shell.EmptyCommit("third commit")
shell.EmptyCommit("second commit")
shell.EmptyCommit("first commit")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("first commit").IsSelected(),
Contains("second commit"),
Contains("third commit"),
Contains("fourth commit"),
).
SelectNextItem().
Press(keys.Universal.ToggleRangeSelect).
SelectNextItem().
SelectedLines(
Contains("second commit"),
Contains("third commit"),
).
Press(keys.Commits.ResetCommitAuthor).
Tap(func() {
t.ExpectPopup().Menu().
Title(Equals("Amend commit attribute")).
Select(Contains("Sign off")).
Confirm()
}).
PressEscape().
SelectNextItem().
SelectedLine(Contains("fourth commit"))
t.Views().Main().Content(
Contains("fourth commit").
DoesNotContain("Signed-off-by: CI <CI@example.com>"),
)
t.Views().Commits().
IsFocused().
SelectPreviousItem().
SelectedLine(Contains("third commit"))
t.Views().Main().ContainsLines(
Equals(" third commit"),
Equals(" "),
Equals(" Signed-off-by: CI <CI@example.com>"),
)
t.Views().Commits().
IsFocused().
SelectPreviousItem().
SelectedLine(Contains("second commit"))
t.Views().Main().ContainsLines(
Equals(" second commit"),
Equals(" "),
Equals(" Signed-off-by: CI <CI@example.com>"),
)
t.Views().Commits().
IsFocused().
SelectPreviousItem().
SelectedLine(Contains("first commit"))
t.Views().Main().Content(
Contains("first commit").
DoesNotContain("Signed-off-by: CI <CI@example.com>"),
)
},
})

View file

@ -158,6 +158,8 @@ var tests = []*components.IntegrationTest{
commit.Search,
commit.SetAuthor,
commit.SetAuthorRange,
commit.SignOff,
commit.SignOffRange,
commit.StageRangeOfLines,
commit.Staged,
commit.StagedWithoutHooks,

View file

@ -986,6 +986,20 @@
}
],
"default": "c"
},
"signOff": {
"oneOf": [
{
"type": "string"
},
{
"items": {
"type": "string"
},
"type": "array"
}
],
"default": "s"
}
},
"additionalProperties": false,