diff --git a/pkg/commands/git.go b/pkg/commands/git.go index 402ec3378..0e974b567 100644 --- a/pkg/commands/git.go +++ b/pkg/commands/git.go @@ -221,11 +221,11 @@ func (c *GitCommand) ResetHard() error { // UpstreamDifferenceCount checks how many pushables/pullables there are for the // current branch func (c *GitCommand) UpstreamDifferenceCount() (string, string) { - pushableCount, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..head --count") + pushableCount, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..HEAD --count") if err != nil { return "?", "?" } - pullableCount, err := c.OSCommand.RunCommandWithOutput("git rev-list head..@{u} --count") + pullableCount, err := c.OSCommand.RunCommandWithOutput("git rev-list HEAD..@{u} --count") if err != nil { return "?", "?" } @@ -236,7 +236,7 @@ func (c *GitCommand) UpstreamDifferenceCount() (string, string) { // to the remote branch of the current branch, a map is returned to ease look up func (c *GitCommand) GetCommitsToPush() map[string]bool { pushables := map[string]bool{} - o, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..head --abbrev-commit") + o, err := c.OSCommand.RunCommandWithOutput("git rev-list @{u}..HEAD --abbrev-commit") if err != nil { return pushables } @@ -314,8 +314,12 @@ func (c *GitCommand) usingGpg() bool { } // Commit commits to git -func (c *GitCommand) Commit(message string) (*exec.Cmd, error) { - command := fmt.Sprintf("git commit -m %s", c.OSCommand.Quote(message)) +func (c *GitCommand) Commit(message string, amend bool) (*exec.Cmd, error) { + amendParam := "" + if amend { + amendParam = " --amend" + } + command := fmt.Sprintf("git commit%s -m %s", amendParam, c.OSCommand.Quote(message)) if c.usingGpg() { return c.OSCommand.PrepareSubProcess(c.OSCommand.Platform.shell, c.OSCommand.Platform.shellArg, command), nil } diff --git a/pkg/commands/git_test.go b/pkg/commands/git_test.go index 25820558a..ebb9de136 100644 --- a/pkg/commands/git_test.go +++ b/pkg/commands/git_test.go @@ -561,7 +561,7 @@ func TestGitCommandUpstreamDifferentCount(t *testing.T) { { "Can't retrieve pullable count", func(cmd string, args ...string) *exec.Cmd { - if args[1] == "head..@{u}" { + if args[1] == "HEAD..@{u}" { return exec.Command("test") } @@ -575,7 +575,7 @@ func TestGitCommandUpstreamDifferentCount(t *testing.T) { { "Retrieve pullable and pushable count", func(cmd string, args ...string) *exec.Cmd { - if args[1] == "head..@{u}" { + if args[1] == "HEAD..@{u}" { return exec.Command("echo", "10") } @@ -889,7 +889,76 @@ func TestGitCommandCommit(t *testing.T) { gitCmd := newDummyGitCommand() gitCmd.getGlobalGitConfig = s.getGlobalGitConfig gitCmd.OSCommand.command = s.command - s.test(gitCmd.Commit("test")) + s.test(gitCmd.Commit("test", false)) + }) + } +} + +func TestGitCommandCommitAmendFromFiles(t *testing.T) { + type scenario struct { + testName string + command func(string, ...string) *exec.Cmd + getGlobalGitConfig func(string) (string, error) + test func(*exec.Cmd, error) + } + + scenarios := []scenario{ + { + "Amend commit using gpg", + func(cmd string, args ...string) *exec.Cmd { + assert.EqualValues(t, "bash", cmd) + assert.EqualValues(t, []string{"-c", `git commit --amend -m 'test'`}, args) + + return exec.Command("echo") + }, + func(string) (string, error) { + return "true", nil + }, + func(cmd *exec.Cmd, err error) { + assert.NotNil(t, cmd) + assert.Nil(t, err) + }, + }, + { + "Amend commit without using gpg", + func(cmd string, args ...string) *exec.Cmd { + assert.EqualValues(t, "git", cmd) + assert.EqualValues(t, []string{"commit", "--amend", "-m", "test"}, args) + + return exec.Command("echo") + }, + func(string) (string, error) { + return "false", nil + }, + func(cmd *exec.Cmd, err error) { + assert.Nil(t, cmd) + assert.Nil(t, err) + }, + }, + { + "Amend commit without using gpg with an error", + func(cmd string, args ...string) *exec.Cmd { + assert.EqualValues(t, "git", cmd) + assert.EqualValues(t, []string{"commit", "--amend", "-m", "test"}, args) + + return exec.Command("test") + }, + func(string) (string, error) { + return "false", nil + }, + func(cmd *exec.Cmd, err error) { + assert.Nil(t, cmd) + assert.Error(t, err) + }, + }, + } + + for _, s := range scenarios { + t.Run(s.testName, func(t *testing.T) { + gitCmd := newDummyGitCommand() + gitCmd.getGlobalGitConfig = s.getGlobalGitConfig + gitCmd.OSCommand.command = s.command + s.test(gitCmd.Commit("test", true)) }) } } @@ -1507,7 +1576,7 @@ func TestGitCommandGetCommits(t *testing.T) { switch args[0] { case "rev-list": - assert.EqualValues(t, []string{"rev-list", "@{u}..head", "--abbrev-commit"}, args) + assert.EqualValues(t, []string{"rev-list", "@{u}..HEAD", "--abbrev-commit"}, args) return exec.Command("echo") case "log": assert.EqualValues(t, []string{"log", "--oneline", "-30"}, args) @@ -1534,7 +1603,7 @@ func TestGitCommandGetCommits(t *testing.T) { switch args[0] { case "rev-list": - assert.EqualValues(t, []string{"rev-list", "@{u}..head", "--abbrev-commit"}, args) + assert.EqualValues(t, []string{"rev-list", "@{u}..HEAD", "--abbrev-commit"}, args) return exec.Command("echo", "8a2bb0e") case "log": assert.EqualValues(t, []string{"log", "--oneline", "-30"}, args) @@ -1577,7 +1646,7 @@ func TestGitCommandGetCommits(t *testing.T) { switch args[0] { case "rev-list": - assert.EqualValues(t, []string{"rev-list", "@{u}..head", "--abbrev-commit"}, args) + assert.EqualValues(t, []string{"rev-list", "@{u}..HEAD", "--abbrev-commit"}, args) return exec.Command("echo", "8a2bb0e") case "log": assert.EqualValues(t, []string{"log", "--oneline", "-30"}, args) diff --git a/pkg/gui/commit_message_panel.go b/pkg/gui/commit_message_panel.go index 74e02be90..c26b5573a 100644 --- a/pkg/gui/commit_message_panel.go +++ b/pkg/gui/commit_message_panel.go @@ -12,7 +12,7 @@ func (gui *Gui) handleCommitConfirm(g *gocui.Gui, v *gocui.View) error { if message == "" { return gui.createErrorPanel(g, gui.Tr.SLocalize("CommitWithoutMessageErr")) } - sub, err := gui.GitCommand.Commit(message) + sub, err := gui.GitCommand.Commit(message, false) if err != nil { // TODO need to find a way to send through this error if err != gui.Errors.ErrSubProcess { diff --git a/pkg/gui/files_panel.go b/pkg/gui/files_panel.go index 574e6bc1c..a00bd2843 100644 --- a/pkg/gui/files_panel.go +++ b/pkg/gui/files_panel.go @@ -211,6 +211,28 @@ func (gui *Gui) handleCommitPress(g *gocui.Gui, filesView *gocui.View) error { return nil } +func (gui *Gui) handleAmendCommitPress(g *gocui.Gui, filesView *gocui.View) error { + if len(gui.stagedFiles()) == 0 && !gui.State.HasMergeConflicts { + return gui.createErrorPanel(g, gui.Tr.SLocalize("NoStagedFilesToCommit")) + } + title := strings.Title(gui.Tr.SLocalize("AmendLastCommit")) + question := gui.Tr.SLocalize("SureToAmend") + + if len(gui.State.Commits) == 0 { + return gui.createErrorPanel(g, gui.Tr.SLocalize("NoCommitToAmend")) + } + + return gui.createConfirmationPanel(g, filesView, title, question, func(g *gocui.Gui, v *gocui.View) error { + lastCommitMsg := gui.State.Commits[0].Name + _, err := gui.GitCommand.Commit(lastCommitMsg, true) + if err != nil { + return gui.createErrorPanel(g, err.Error()) + } + + return gui.refreshSidePanels(g) + }, nil) +} + // handleCommitEditorPress - handle when the user wants to commit changes via // their editor rather than via the popup panel func (gui *Gui) handleCommitEditorPress(g *gocui.Gui, filesView *gocui.View) error { diff --git a/pkg/gui/keybindings.go b/pkg/gui/keybindings.go index 1073da68a..78271a3f7 100644 --- a/pkg/gui/keybindings.go +++ b/pkg/gui/keybindings.go @@ -125,6 +125,12 @@ func (gui *Gui) GetKeybindings() []*Binding { Modifier: gocui.ModNone, Handler: gui.handleCommitPress, Description: gui.Tr.SLocalize("CommitChanges"), + }, { + ViewName: "files", + Key: 'A', + Modifier: gocui.ModNone, + Handler: gui.handleAmendCommitPress, + Description: gui.Tr.SLocalize("AmendLastCommit"), }, { ViewName: "files", Key: 'C', @@ -182,7 +188,7 @@ func (gui *Gui) GetKeybindings() []*Binding { Description: gui.Tr.SLocalize("stashFiles"), }, { ViewName: "files", - Key: 'A', + Key: 'M', Modifier: gocui.ModNone, Handler: gui.handleAbortMerge, Description: gui.Tr.SLocalize("abortMerge"), diff --git a/pkg/i18n/dutch.go b/pkg/i18n/dutch.go index cd1282de2..6b24a5174 100644 --- a/pkg/i18n/dutch.go +++ b/pkg/i18n/dutch.go @@ -34,6 +34,15 @@ func addDutch(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "CommitChanges", Other: "Commit Veranderingen", + }, &i18n.Message{ + ID: "AmendLastCommit", + Other: "wijzig laatste commit", + }, &i18n.Message{ + ID: "SureToAmend", + Other: "Weet je zeker dat je de laatste commit wilt wijzigen? U kunt het commit-bericht wijzigen vanuit het commits-paneel.", + }, &i18n.Message{ + ID: "NoCommitToAmend", + Other: "Er is geen verplichting om te wijzigen.", }, &i18n.Message{ ID: "CommitChangesWithEditor", Other: "commit Veranderingen met de git editor", diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index b8be4cfc6..9ead5a54e 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -42,6 +42,15 @@ func addEnglish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "CommitChanges", Other: "commit changes", + }, &i18n.Message{ + ID: "AmendLastCommit", + Other: "amend last commit", + }, &i18n.Message{ + ID: "SureToAmend", + Other: "Are you sure you want to amend last commit? You can change commit message from commits panel.", + }, &i18n.Message{ + ID: "NoCommitToAmend", + Other: "There's no commit to amend.", }, &i18n.Message{ ID: "CommitChangesWithEditor", Other: "commit changes using git editor", diff --git a/pkg/i18n/polish.go b/pkg/i18n/polish.go index c64ab87b8..c37bfe972 100644 --- a/pkg/i18n/polish.go +++ b/pkg/i18n/polish.go @@ -32,6 +32,15 @@ func addPolish(i18nObject *i18n.Bundle) error { }, &i18n.Message{ ID: "CommitChanges", Other: "commituj zmiany", + }, &i18n.Message{ + ID: "AmendLastCommit", + Other: "zmień ostatnie zatwierdzenie", + }, &i18n.Message{ + ID: "SureToAmend", + Other: "Czy na pewno chcesz zmienić ostatnie zatwierdzenie? Możesz zmienić komunikat zatwierdzenia z panelu zatwierdzeń.", + }, &i18n.Message{ + ID: "NoCommitToAmend", + Other: "Nie ma zobowiązania do zmiany.", }, &i18n.Message{ ID: "CommitChangesWithEditor", Other: "commituj zmiany używając edytora z gita",