Add option to copy commit body (#4274)

I based this off of the existing `CommitMessage` option in the copy
commit attributes menu.
This commit is contained in:
Stefan Haller 2025-02-17 18:56:44 +01:00 committed by GitHub
commit a7bfeca9c0
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 166 additions and 45 deletions

View file

@ -122,7 +122,24 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
return bindings return bindings
} }
func (self *BasicCommitsController) getCommitMessageBody(hash string) string {
commitMessageBody, err := self.c.Git().Commit.GetCommitMessage(hash)
if err != nil {
return ""
}
_, body := self.c.Helpers().Commits.SplitCommitMessageAndDescription(commitMessageBody)
return body
}
func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) error { func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) error {
commitMessageBody := self.getCommitMessageBody(commit.Hash)
var commitMessageBodyDisabled *types.DisabledReason
if commitMessageBody == "" {
commitMessageBodyDisabled = &types.DisabledReason{
Text: self.c.Tr.CommitHasNoMessageBody,
}
}
items := []*types.MenuItem{ items := []*types.MenuItem{
{ {
Label: self.c.Tr.CommitHash, Label: self.c.Tr.CommitHash,
@ -144,6 +161,14 @@ func (self *BasicCommitsController) copyCommitAttribute(commit *models.Commit) e
}, },
Key: 'm', Key: 'm',
}, },
{
Label: self.c.Tr.CommitMessageBody,
DisabledReason: commitMessageBodyDisabled,
OnPress: func() error {
return self.copyCommitMessageBodyToClipboard(commitMessageBody)
},
Key: 'b',
},
{ {
Label: self.c.Tr.CommitURL, Label: self.c.Tr.CommitURL,
OnPress: func() error { OnPress: func() error {
@ -259,6 +284,16 @@ func (self *BasicCommitsController) copyCommitMessageToClipboard(commit *models.
return nil return nil
} }
func (self *BasicCommitsController) copyCommitMessageBodyToClipboard(commitMessageBody string) error {
self.c.LogAction(self.c.Tr.Actions.CopyCommitMessageBodyToClipboard)
if err := self.c.OS().CopyToClipboard(commitMessageBody); err != nil {
return err
}
self.c.Toast(self.c.Tr.CommitMessageBodyCopiedToClipboard)
return nil
}
func (self *BasicCommitsController) copyCommitSubjectToClipboard(commit *models.Commit) error { func (self *BasicCommitsController) copyCommitSubjectToClipboard(commit *models.Commit) error {
message, err := self.c.Git().Commit.GetCommitSubject(commit.Hash) message, err := self.c.Git().Commit.GetCommitSubject(commit.Hash)
if err != nil { if err != nil {

View file

@ -621,6 +621,7 @@ type TranslationSet struct {
PasteCommitMessageFromClipboard string PasteCommitMessageFromClipboard string
SurePasteCommitMessage string SurePasteCommitMessage string
CommitMessage string CommitMessage string
CommitMessageBody string
CommitSubject string CommitSubject string
CommitAuthor string CommitAuthor string
CommitTags string CommitTags string
@ -685,10 +686,12 @@ type TranslationSet struct {
CommitDiffCopiedToClipboard string CommitDiffCopiedToClipboard string
CommitURLCopiedToClipboard string CommitURLCopiedToClipboard string
CommitMessageCopiedToClipboard string CommitMessageCopiedToClipboard string
CommitMessageBodyCopiedToClipboard string
CommitSubjectCopiedToClipboard string CommitSubjectCopiedToClipboard string
CommitAuthorCopiedToClipboard string CommitAuthorCopiedToClipboard string
CommitTagsCopiedToClipboard string CommitTagsCopiedToClipboard string
CommitHasNoTags string CommitHasNoTags string
CommitHasNoMessageBody string
PatchCopiedToClipboard string PatchCopiedToClipboard string
CopiedToClipboard string CopiedToClipboard string
ErrCannotEditDirectory string ErrCannotEditDirectory string
@ -914,6 +917,7 @@ type Actions struct {
MoveCommitUp string MoveCommitUp string
MoveCommitDown string MoveCommitDown string
CopyCommitMessageToClipboard string CopyCommitMessageToClipboard string
CopyCommitMessageBodyToClipboard string
CopyCommitSubjectToClipboard string CopyCommitSubjectToClipboard string
CopyCommitDiffToClipboard string CopyCommitDiffToClipboard string
CopyCommitHashToClipboard string CopyCommitHashToClipboard string
@ -1653,7 +1657,8 @@ func EnglishTranslationSet() *TranslationSet {
CopyCommitMessageToClipboard: "Copy commit message to clipboard", CopyCommitMessageToClipboard: "Copy commit message to clipboard",
PasteCommitMessageFromClipboard: "Paste commit message from clipboard", PasteCommitMessageFromClipboard: "Paste commit message from clipboard",
SurePasteCommitMessage: "Pasting will overwrite the current commit message, continue?", SurePasteCommitMessage: "Pasting will overwrite the current commit message, continue?",
CommitMessage: "Commit message", CommitMessage: "Commit message (subject and body)",
CommitMessageBody: "Commit message body",
CommitSubject: "Commit subject", CommitSubject: "Commit subject",
CommitAuthor: "Commit author", CommitAuthor: "Commit author",
CommitTags: "Commit tags", CommitTags: "Commit tags",
@ -1717,10 +1722,12 @@ func EnglishTranslationSet() *TranslationSet {
CommitDiffCopiedToClipboard: "Commit diff copied to clipboard", CommitDiffCopiedToClipboard: "Commit diff copied to clipboard",
CommitURLCopiedToClipboard: "Commit URL copied to clipboard", CommitURLCopiedToClipboard: "Commit URL copied to clipboard",
CommitMessageCopiedToClipboard: "Commit message copied to clipboard", CommitMessageCopiedToClipboard: "Commit message copied to clipboard",
CommitMessageBodyCopiedToClipboard: "Commit message body copied to clipboard",
CommitSubjectCopiedToClipboard: "Commit subject copied to clipboard", CommitSubjectCopiedToClipboard: "Commit subject copied to clipboard",
CommitAuthorCopiedToClipboard: "Commit author copied to clipboard", CommitAuthorCopiedToClipboard: "Commit author copied to clipboard",
CommitTagsCopiedToClipboard: "Commit tags copied to clipboard", CommitTagsCopiedToClipboard: "Commit tags copied to clipboard",
CommitHasNoTags: "Commit has no tags", CommitHasNoTags: "Commit has no tags",
CommitHasNoMessageBody: "Commit has no message body",
PatchCopiedToClipboard: "Patch copied to clipboard", PatchCopiedToClipboard: "Patch copied to clipboard",
CopiedToClipboard: "copied to clipboard", CopiedToClipboard: "copied to clipboard",
ErrCannotEditDirectory: "Cannot edit directories: you can only edit individual files", ErrCannotEditDirectory: "Cannot edit directories: you can only edit individual files",
@ -1873,48 +1880,49 @@ func EnglishTranslationSet() *TranslationSet {
Actions: Actions{ Actions: Actions{
// TODO: combine this with the original keybinding descriptions (those are all in lowercase atm) // TODO: combine this with the original keybinding descriptions (those are all in lowercase atm)
CheckoutCommit: "Checkout commit", CheckoutCommit: "Checkout commit",
CheckoutBranchAtCommit: "Checkout branch '%s'", CheckoutBranchAtCommit: "Checkout branch '%s'",
CheckoutCommitAsDetachedHead: "Checkout commit %s as detached head", CheckoutCommitAsDetachedHead: "Checkout commit %s as detached head",
CheckoutTag: "Checkout tag", CheckoutTag: "Checkout tag",
CheckoutBranch: "Checkout branch", CheckoutBranch: "Checkout branch",
ForceCheckoutBranch: "Force checkout branch", ForceCheckoutBranch: "Force checkout branch",
CheckoutBranchOrCommit: "Checkout branch or commit", CheckoutBranchOrCommit: "Checkout branch or commit",
DeleteLocalBranch: "Delete local branch", DeleteLocalBranch: "Delete local branch",
Merge: "Merge", Merge: "Merge",
SquashMerge: "Squash merge", SquashMerge: "Squash merge",
RebaseBranch: "Rebase branch", RebaseBranch: "Rebase branch",
RenameBranch: "Rename branch", RenameBranch: "Rename branch",
CreateBranch: "Create branch", CreateBranch: "Create branch",
CherryPick: "(Cherry-pick) paste commits", CherryPick: "(Cherry-pick) paste commits",
CheckoutFile: "Checkout file", CheckoutFile: "Checkout file",
DiscardOldFileChange: "Discard old file change", DiscardOldFileChange: "Discard old file change",
SquashCommitDown: "Squash commit down", SquashCommitDown: "Squash commit down",
FixupCommit: "Fixup commit", FixupCommit: "Fixup commit",
RewordCommit: "Reword commit", RewordCommit: "Reword commit",
DropCommit: "Drop commit", DropCommit: "Drop commit",
EditCommit: "Edit commit", EditCommit: "Edit commit",
AmendCommit: "Amend commit", AmendCommit: "Amend commit",
ResetCommitAuthor: "Reset commit author", ResetCommitAuthor: "Reset commit author",
SetCommitAuthor: "Set commit author", SetCommitAuthor: "Set commit author",
AddCommitCoAuthor: "Add commit co-author", AddCommitCoAuthor: "Add commit co-author",
RevertCommit: "Revert commit", RevertCommit: "Revert commit",
CreateFixupCommit: "Create fixup commit", CreateFixupCommit: "Create fixup commit",
SquashAllAboveFixupCommits: "Squash all above fixup commits", SquashAllAboveFixupCommits: "Squash all above fixup commits",
CreateLightweightTag: "Create lightweight tag", CreateLightweightTag: "Create lightweight tag",
CreateAnnotatedTag: "Create annotated tag", CreateAnnotatedTag: "Create annotated tag",
CopyCommitMessageToClipboard: "Copy commit message to clipboard", CopyCommitMessageToClipboard: "Copy commit message to clipboard",
CopyCommitSubjectToClipboard: "Copy commit subject to clipboard", CopyCommitMessageBodyToClipboard: "Copy commit message body to clipboard",
CopyCommitTagsToClipboard: "Copy commit tags to clipboard", CopyCommitSubjectToClipboard: "Copy commit subject to clipboard",
CopyCommitDiffToClipboard: "Copy commit diff to clipboard", CopyCommitTagsToClipboard: "Copy commit tags to clipboard",
CopyCommitHashToClipboard: "Copy full commit hash to clipboard", CopyCommitDiffToClipboard: "Copy commit diff to clipboard",
CopyCommitURLToClipboard: "Copy commit URL to clipboard", CopyCommitHashToClipboard: "Copy full commit hash to clipboard",
CopyCommitAuthorToClipboard: "Copy commit author to clipboard", CopyCommitURLToClipboard: "Copy commit URL to clipboard",
CopyCommitAttributeToClipboard: "Copy to clipboard", CopyCommitAuthorToClipboard: "Copy commit author to clipboard",
CopyPatchToClipboard: "Copy patch to clipboard", CopyCommitAttributeToClipboard: "Copy to clipboard",
MoveCommitUp: "Move commit up", CopyPatchToClipboard: "Copy patch to clipboard",
MoveCommitDown: "Move commit down", MoveCommitUp: "Move commit up",
CustomCommand: "Custom command", MoveCommitDown: "Move commit down",
CustomCommand: "Custom command",
// TODO: remove // TODO: remove
DiscardAllChangesInDirectory: "Discard all changes in directory", DiscardAllChangesInDirectory: "Discard all changes in directory",

View file

@ -174,6 +174,10 @@ func (self *Shell) EmptyCommit(message string) *Shell {
return self.RunCommand([]string{"git", "commit", "--allow-empty", "-m", message}) return self.RunCommand([]string{"git", "commit", "--allow-empty", "-m", message})
} }
func (self *Shell) EmptyCommitWithBody(subject string, body string) *Shell {
return self.RunCommand([]string{"git", "commit", "--allow-empty", "-m", subject, "-m", body})
}
func (self *Shell) EmptyCommitDaysAgo(message string, daysAgo int) *Shell { func (self *Shell) EmptyCommitDaysAgo(message string, daysAgo int) *Shell {
return self.RunCommand([]string{"git", "commit", "--allow-empty", "--date", fmt.Sprintf("%d days ago", daysAgo), "-m", message}) return self.RunCommand([]string{"git", "commit", "--allow-empty", "--date", fmt.Sprintf("%d days ago", daysAgo), "-m", message})
} }

View file

@ -0,0 +1,39 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
// We're emulating the clipboard by writing to a file called clipboard
var CopyMessageBodyToClipboard = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Copy a commit message body to the clipboard",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {
config.GetUserConfig().OS.CopyToClipboardCmd = "printf '%s' {{text}} > clipboard"
},
SetupRepo: func(shell *Shell) {
shell.EmptyCommitWithBody("My Subject", "My awesome commit message body")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("My Subject").IsSelected(),
).
Press(keys.Commits.CopyCommitAttributeToClipboard)
t.ExpectPopup().Menu().
Title(Equals("Copy to clipboard")).
Select(Contains("Commit message body")).
Confirm()
t.ExpectToast(Equals("Commit message body copied to clipboard"))
t.FileSystem().FileContent("clipboard", Equals("My awesome commit message body"))
},
})

View file

@ -0,0 +1,33 @@
package commit
import (
"github.com/jesseduffield/lazygit/pkg/config"
. "github.com/jesseduffield/lazygit/pkg/integration/components"
)
var DisableCopyCommitMessageBody = NewIntegrationTest(NewIntegrationTestArgs{
Description: "Disables copy commit message body when there is no body",
ExtraCmdArgs: []string{},
Skip: false,
SetupConfig: func(config *config.AppConfig) {},
SetupRepo: func(shell *Shell) {
shell.EmptyCommit("commit")
},
Run: func(t *TestDriver, keys config.KeybindingConfig) {
t.Views().Commits().
Focus().
Lines(
Contains("commit").IsSelected(),
).
Press(keys.Commits.CopyCommitAttributeToClipboard)
t.ExpectPopup().Menu().
Title(Equals("Copy to clipboard")).
Select(Contains("Commit message body")).
Confirm()
t.ExpectToast(Equals("Disabled: Commit has no message body"))
},
})

View file

@ -26,7 +26,7 @@ var PasteCommitMessage = NewIntegrationTest(NewIntegrationTestArgs{
Press(keys.Commits.CopyCommitAttributeToClipboard) Press(keys.Commits.CopyCommitAttributeToClipboard)
t.ExpectPopup().Menu().Title(Equals("Copy to clipboard")). t.ExpectPopup().Menu().Title(Equals("Copy to clipboard")).
Select(Contains("Commit message")).Confirm() Select(Contains("Commit message (subject and body)")).Confirm()
t.ExpectToast(Equals("Commit message copied to clipboard")) t.ExpectToast(Equals("Commit message copied to clipboard"))

View file

@ -26,7 +26,7 @@ var PasteCommitMessageOverExisting = NewIntegrationTest(NewIntegrationTestArgs{
Press(keys.Commits.CopyCommitAttributeToClipboard) Press(keys.Commits.CopyCommitAttributeToClipboard)
t.ExpectPopup().Menu().Title(Equals("Copy to clipboard")). t.ExpectPopup().Menu().Title(Equals("Copy to clipboard")).
Select(Contains("Commit message")).Confirm() Select(Contains("Commit message (subject and body)")).Confirm()
t.ExpectToast(Equals("Commit message copied to clipboard")) t.ExpectToast(Equals("Commit message copied to clipboard"))

View file

@ -97,10 +97,12 @@ var tests = []*components.IntegrationTest{
commit.CommitWithNonMatchingBranchName, commit.CommitWithNonMatchingBranchName,
commit.CommitWithPrefix, commit.CommitWithPrefix,
commit.CopyAuthorToClipboard, commit.CopyAuthorToClipboard,
commit.CopyMessageBodyToClipboard,
commit.CopyTagToClipboard, commit.CopyTagToClipboard,
commit.CreateAmendCommit, commit.CreateAmendCommit,
commit.CreateFixupCommitInBranchStack, commit.CreateFixupCommitInBranchStack,
commit.CreateTag, commit.CreateTag,
commit.DisableCopyCommitMessageBody,
commit.DiscardOldFileChanges, commit.DiscardOldFileChanges,
commit.FindBaseCommitForFixup, commit.FindBaseCommitForFixup,
commit.FindBaseCommitForFixupDisregardMainBranch, commit.FindBaseCommitForFixupDisregardMainBranch,