mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-04-15 11:56:37 +02:00
support setting the author of a commit
update copy
This commit is contained in:
parent
901ab3ac1b
commit
9591cc381a
@ -28,6 +28,12 @@ func (self *CommitCommands) ResetAuthor() error {
|
|||||||
return self.cmd.New("git commit --allow-empty --only --no-edit --amend --reset-author").Run()
|
return self.cmd.New("git commit --allow-empty --only --no-edit --amend --reset-author").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 {
|
||||||
|
commandStr := fmt.Sprintf("git commit --allow-empty --only --no-edit --amend --author=%s", self.cmd.Quote(value))
|
||||||
|
return self.cmd.New(commandStr).Run()
|
||||||
|
}
|
||||||
|
|
||||||
// ResetToCommit reset to commit
|
// ResetToCommit reset to commit
|
||||||
func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars []string) error {
|
func (self *CommitCommands) ResetToCommit(sha string, strength string, envVars []string) error {
|
||||||
return self.cmd.New(fmt.Sprintf("git reset --%s %s", strength, sha)).
|
return self.cmd.New(fmt.Sprintf("git reset --%s %s", strength, sha)).
|
||||||
|
@ -63,9 +63,21 @@ func (self *RebaseCommands) RewordCommitInEditor(commits []*models.Commit, index
|
|||||||
}
|
}
|
||||||
|
|
||||||
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, index int) error {
|
func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, index int) error {
|
||||||
|
return self.GenericAmend(commits, index, func() error {
|
||||||
|
return self.commit.ResetAuthor()
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) SetCommitAuthor(commits []*models.Commit, index int, value string) error {
|
||||||
|
return self.GenericAmend(commits, index, func() error {
|
||||||
|
return self.commit.SetAuthor(value)
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *RebaseCommands) GenericAmend(commits []*models.Commit, index int, f func() error) error {
|
||||||
if index == 0 {
|
if index == 0 {
|
||||||
// we've selected the top commit so no rebase is required
|
// we've selected the top commit so no rebase is required
|
||||||
return self.commit.ResetAuthor()
|
return f()
|
||||||
}
|
}
|
||||||
|
|
||||||
err := self.BeginInteractiveRebaseForCommit(commits, index)
|
err := self.BeginInteractiveRebaseForCommit(commits, index)
|
||||||
@ -73,8 +85,8 @@ func (self *RebaseCommands) ResetCommitAuthor(commits []*models.Commit, index in
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// now the selected commit should be our head so we'll amend it with the new author
|
// now the selected commit should be our head so we'll amend it
|
||||||
err = self.commit.ResetAuthor()
|
err = f()
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
@ -10,6 +10,7 @@ import (
|
|||||||
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
"github.com/jesseduffield/lazygit/pkg/gui/types"
|
||||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||||
"github.com/jesseduffield/minimal/gitignore"
|
"github.com/jesseduffield/minimal/gitignore"
|
||||||
|
"github.com/samber/lo"
|
||||||
"gopkg.in/ozeidan/fuzzy-patricia.v3/patricia"
|
"gopkg.in/ozeidan/fuzzy-patricia.v3/patricia"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -174,6 +175,14 @@ func (self *SuggestionsHelper) GetRefsSuggestionsFunc() func(string) []*types.Su
|
|||||||
return FuzzySearchFunc(refNames)
|
return FuzzySearchFunc(refNames)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func (self *SuggestionsHelper) GetAuthorsSuggestionsFunc() func(string) []*types.Suggestion {
|
||||||
|
authors := lo.Uniq(slices.Map(self.model.Commits, func(commit *models.Commit) string {
|
||||||
|
return fmt.Sprintf("%s <%s>", commit.AuthorName, commit.AuthorEmail)
|
||||||
|
}))
|
||||||
|
|
||||||
|
return FuzzySearchFunc(authors)
|
||||||
|
}
|
||||||
|
|
||||||
func FuzzySearchFunc(options []string) func(string) []*types.Suggestion {
|
func FuzzySearchFunc(options []string) func(string) []*types.Suggestion {
|
||||||
return func(input string) []*types.Suggestion {
|
return func(input string) []*types.Suggestion {
|
||||||
var matches []string
|
var matches []string
|
||||||
|
@ -123,7 +123,7 @@ func (self *LocalCommitsController) GetKeybindings(opts types.KeybindingsOpts) [
|
|||||||
},
|
},
|
||||||
{
|
{
|
||||||
Key: opts.GetKey(opts.Config.Commits.ResetCommitAuthor),
|
Key: opts.GetKey(opts.Config.Commits.ResetCommitAuthor),
|
||||||
Handler: self.checkSelected(self.resetAuthor),
|
Handler: self.checkSelected(self.amendAttribute),
|
||||||
Description: self.c.Tr.LcResetCommitAuthor,
|
Description: self.c.Tr.LcResetCommitAuthor,
|
||||||
},
|
},
|
||||||
{
|
{
|
||||||
@ -423,17 +423,50 @@ func (self *LocalCommitsController) amendTo(commit *models.Commit) error {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
func (self *LocalCommitsController) resetAuthor(commit *models.Commit) error {
|
func (self *LocalCommitsController) amendAttribute(commit *models.Commit) error {
|
||||||
return self.c.Confirm(types.ConfirmOpts{
|
return self.c.Menu(types.CreateMenuOptions{
|
||||||
Title: self.c.Tr.LcResetCommitAuthor,
|
Title: "Amend commit attribute",
|
||||||
Prompt: self.c.Tr.SureResetCommitAuthor,
|
Items: []*types.MenuItem{
|
||||||
HandleConfirm: func() error {
|
{
|
||||||
self.c.LogAction(self.c.Tr.Actions.ResetCommitAuthor)
|
Label: "reset author",
|
||||||
if err := self.git.Rebase.ResetCommitAuthor(self.model.Commits, self.context().GetSelectedLineIdx()); err != nil {
|
OnPress: self.resetAuthor,
|
||||||
return self.c.Error(err)
|
Key: 'a',
|
||||||
}
|
Tooltip: "Reset the commit's author to the currently configured user. This will also renew the author timestamp",
|
||||||
|
},
|
||||||
|
{
|
||||||
|
Label: "set author",
|
||||||
|
OnPress: self.setAuthor,
|
||||||
|
Key: 'A',
|
||||||
|
Tooltip: "Set the author based on a prompt",
|
||||||
|
},
|
||||||
|
},
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
func (self *LocalCommitsController) resetAuthor() error {
|
||||||
|
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.ResetCommitAuthor)
|
||||||
|
if err := self.git.Rebase.ResetCommitAuthor(self.model.Commits, self.context().GetSelectedLineIdx()); err != nil {
|
||||||
|
return self.c.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
func (self *LocalCommitsController) setAuthor() error {
|
||||||
|
return self.c.Prompt(types.PromptOpts{
|
||||||
|
Title: self.c.Tr.SetAuthorPromptTitle,
|
||||||
|
FindSuggestionsFunc: self.helpers.Suggestions.GetAuthorsSuggestionsFunc(),
|
||||||
|
HandleConfirm: func(value string) error {
|
||||||
|
return self.c.WithWaitingStatus(self.c.Tr.AmendingStatus, func() error {
|
||||||
|
self.c.LogAction(self.c.Tr.Actions.SetCommitAuthor)
|
||||||
|
if err := self.git.Rebase.SetCommitAuthor(self.model.Commits, self.context().GetSelectedLineIdx(), value); err != nil {
|
||||||
|
return self.c.Error(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
return self.c.Refresh(types.RefreshOptions{Mode: types.ASYNC})
|
||||||
|
})
|
||||||
},
|
},
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
@ -101,6 +101,7 @@ type TranslationSet struct {
|
|||||||
LcEditCommit string
|
LcEditCommit string
|
||||||
LcAmendToCommit string
|
LcAmendToCommit string
|
||||||
LcResetCommitAuthor string
|
LcResetCommitAuthor string
|
||||||
|
SetAuthorPromptTitle string
|
||||||
SureResetCommitAuthor string
|
SureResetCommitAuthor string
|
||||||
LcRenameCommitEditor string
|
LcRenameCommitEditor string
|
||||||
NoCommitsThisBranch string
|
NoCommitsThisBranch string
|
||||||
@ -537,6 +538,7 @@ type Actions struct {
|
|||||||
EditCommit string
|
EditCommit string
|
||||||
AmendCommit string
|
AmendCommit string
|
||||||
ResetCommitAuthor string
|
ResetCommitAuthor string
|
||||||
|
SetCommitAuthor string
|
||||||
RevertCommit string
|
RevertCommit string
|
||||||
CreateFixupCommit string
|
CreateFixupCommit string
|
||||||
SquashAllAboveFixupCommits string
|
SquashAllAboveFixupCommits string
|
||||||
@ -725,6 +727,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
LcEditCommit: "edit commit",
|
LcEditCommit: "edit commit",
|
||||||
LcAmendToCommit: "amend commit with staged changes",
|
LcAmendToCommit: "amend commit with staged changes",
|
||||||
LcResetCommitAuthor: "reset commit author",
|
LcResetCommitAuthor: "reset commit author",
|
||||||
|
SetAuthorPromptTitle: "Set author (must look like 'Name <Email>')",
|
||||||
SureResetCommitAuthor: "The author field of this commit will be updated to match the configured user. This also renews the author timestamp. Continue?",
|
SureResetCommitAuthor: "The author field of this commit will be updated to match the configured user. This also renews the author timestamp. Continue?",
|
||||||
LcRenameCommitEditor: "reword commit with editor",
|
LcRenameCommitEditor: "reword commit with editor",
|
||||||
Error: "Error",
|
Error: "Error",
|
||||||
@ -1142,6 +1145,7 @@ func EnglishTranslationSet() TranslationSet {
|
|||||||
EditCommit: "Edit commit",
|
EditCommit: "Edit commit",
|
||||||
AmendCommit: "Amend commit",
|
AmendCommit: "Amend commit",
|
||||||
ResetCommitAuthor: "Reset commit author",
|
ResetCommitAuthor: "Reset commit author",
|
||||||
|
SetCommitAuthor: "Set commit 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",
|
||||||
|
@ -0,0 +1 @@
|
|||||||
|
myfile3
|
1
test/integration/setAuthor/expected/repo/.git_keep/HEAD
Normal file
1
test/integration/setAuthor/expected/repo/.git_keep/HEAD
Normal file
@ -0,0 +1 @@
|
|||||||
|
ref: refs/heads/master
|
10
test/integration/setAuthor/expected/repo/.git_keep/config
Normal file
10
test/integration/setAuthor/expected/repo/.git_keep/config
Normal file
@ -0,0 +1,10 @@
|
|||||||
|
[core]
|
||||||
|
repositoryformatversion = 0
|
||||||
|
filemode = true
|
||||||
|
bare = false
|
||||||
|
logallrefupdates = true
|
||||||
|
ignorecase = true
|
||||||
|
precomposeunicode = true
|
||||||
|
[user]
|
||||||
|
email = Author2@example.com
|
||||||
|
name = Author2
|
@ -0,0 +1 @@
|
|||||||
|
Unnamed repository; edit this file 'description' to name the repository.
|
BIN
test/integration/setAuthor/expected/repo/.git_keep/index
Normal file
BIN
test/integration/setAuthor/expected/repo/.git_keep/index
Normal file
Binary file not shown.
@ -0,0 +1,7 @@
|
|||||||
|
# git ls-files --others --exclude-from=.git/info/exclude
|
||||||
|
# Lines that start with '#' are comments.
|
||||||
|
# For a project mostly in C, the following would be a good set of
|
||||||
|
# exclude patterns (uncomment them if you want to use them):
|
||||||
|
# *.[oa]
|
||||||
|
# *~
|
||||||
|
.DS_Store
|
@ -0,0 +1,4 @@
|
|||||||
|
0000000000000000000000000000000000000000 2075aeb39a2a66a9607860a65b2a71c517760254 Author1 <Author1@example.com> 1652008089 +1000 commit (initial): myfile1
|
||||||
|
2075aeb39a2a66a9607860a65b2a71c517760254 d01c8bb001458d0a7c01193813685c658e0355ac Author1 <Author1@example.com> 1652008089 +1000 commit: myfile2
|
||||||
|
d01c8bb001458d0a7c01193813685c658e0355ac 8710ece70b7db9638b9645e93abdbcf210fa4595 Author2 <Author2@example.com> 1652008089 +1000 commit: myfile3
|
||||||
|
8710ece70b7db9638b9645e93abdbcf210fa4595 baf3189129ba8878ba9b4107eaaaf3389287259b Author2 <Author2@example.com> 1652008097 +1000 commit (amend): myfile3
|
@ -0,0 +1,4 @@
|
|||||||
|
0000000000000000000000000000000000000000 2075aeb39a2a66a9607860a65b2a71c517760254 Author1 <Author1@example.com> 1652008089 +1000 commit (initial): myfile1
|
||||||
|
2075aeb39a2a66a9607860a65b2a71c517760254 d01c8bb001458d0a7c01193813685c658e0355ac Author1 <Author1@example.com> 1652008089 +1000 commit: myfile2
|
||||||
|
d01c8bb001458d0a7c01193813685c658e0355ac 8710ece70b7db9638b9645e93abdbcf210fa4595 Author2 <Author2@example.com> 1652008089 +1000 commit: myfile3
|
||||||
|
8710ece70b7db9638b9645e93abdbcf210fa4595 baf3189129ba8878ba9b4107eaaaf3389287259b Author2 <Author2@example.com> 1652008097 +1000 commit (amend): myfile3
|
Binary file not shown.
Binary file not shown.
@ -0,0 +1,2 @@
|
|||||||
|
x•�Q
|
||||||
|
Â0DýÎ)ö_�ݸÝn¡ˆ%M6Xhˆ”z{ƒx¿fx0ob-em@"‡¶›šÄŒA–q2MÌF*IÉÊ#/|NÂ9ÄÁ»ðl÷ºÃíó¯\íÊc³S¬åÒµƒGTÔ Ž„ˆ®Ó~×ìï¡+ï¼nFîÈ‹5'
|
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@ -0,0 +1 @@
|
|||||||
|
baf3189129ba8878ba9b4107eaaaf3389287259b
|
1
test/integration/setAuthor/expected/repo/myfile1
Normal file
1
test/integration/setAuthor/expected/repo/myfile1
Normal file
@ -0,0 +1 @@
|
|||||||
|
test1
|
1
test/integration/setAuthor/expected/repo/myfile2
Normal file
1
test/integration/setAuthor/expected/repo/myfile2
Normal file
@ -0,0 +1 @@
|
|||||||
|
test2
|
1
test/integration/setAuthor/expected/repo/myfile3
Normal file
1
test/integration/setAuthor/expected/repo/myfile3
Normal file
@ -0,0 +1 @@
|
|||||||
|
test3
|
1
test/integration/setAuthor/recording.json
Normal file
1
test/integration/setAuthor/recording.json
Normal file
@ -0,0 +1 @@
|
|||||||
|
{"KeyEvents":[{"Timestamp":1118,"Mod":0,"Key":259,"Ch":0},{"Timestamp":1382,"Mod":0,"Key":259,"Ch":0},{"Timestamp":2654,"Mod":0,"Key":256,"Ch":97},{"Timestamp":3632,"Mod":0,"Key":258,"Ch":0},{"Timestamp":4070,"Mod":0,"Key":13,"Ch":13},{"Timestamp":6702,"Mod":0,"Key":9,"Ch":9},{"Timestamp":7486,"Mod":0,"Key":258,"Ch":0},{"Timestamp":7899,"Mod":0,"Key":13,"Ch":13},{"Timestamp":9141,"Mod":0,"Key":256,"Ch":113}],"ResizeEvents":[{"Timestamp":0,"Width":272,"Height":74}]}
|
24
test/integration/setAuthor/setup.sh
Normal file
24
test/integration/setAuthor/setup.sh
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
set -e
|
||||||
|
|
||||||
|
cd $1
|
||||||
|
|
||||||
|
git init
|
||||||
|
|
||||||
|
git config user.email "Author1@example.com"
|
||||||
|
git config user.name "Author1"
|
||||||
|
|
||||||
|
echo test1 > myfile1
|
||||||
|
git add .
|
||||||
|
git commit -am "myfile1"
|
||||||
|
echo test2 > myfile2
|
||||||
|
git add .
|
||||||
|
git commit -am "myfile2"
|
||||||
|
|
||||||
|
git config user.email "Author2@example.com"
|
||||||
|
git config user.name "Author2"
|
||||||
|
|
||||||
|
echo test3 > myfile3
|
||||||
|
git add .
|
||||||
|
git commit -am "myfile3"
|
4
test/integration/setAuthor/test.json
Normal file
4
test/integration/setAuthor/test.json
Normal file
@ -0,0 +1,4 @@
|
|||||||
|
{
|
||||||
|
"description": "In this test the author of a commit is set to a different name/email.",
|
||||||
|
"speed": 5
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user