diff --git a/commits_panel.go b/commits_panel.go index 88c7b8ebe..b222d346c 100644 --- a/commits_panel.go +++ b/commits_panel.go @@ -65,6 +65,7 @@ func renderCommitsOptions(g *gocui.Gui) error { "s": "squash down", "r": "rename", "g": "reset to this commit", + "f": "fixup commit", "← → ↑ ↓": "navigate", }) } @@ -105,6 +106,25 @@ func handleCommitSquashDown(g *gocui.Gui, v *gocui.View) error { return handleCommitSelect(g, v) } +func handleCommitFixup(g *gocui.Gui, v *gocui.View) error { + if len(state.Commits) == 1 { + return createErrorPanel(g, "You have no commits to squash with") + } + branch := state.Branches[0] + commit, err := getSelectedCommit(g) + if err != nil { + return err + } + if output, err := gitSquashFixupCommit(branch.Name, commit.Sha); err != nil { + return createErrorPanel(g, output) + } + if err := refreshCommits(g); err != nil { + panic(err) + } + refreshStatus(g) + return handleCommitSelect(g, v) +} + func handleRenameCommit(g *gocui.Gui, v *gocui.View) error { if getItemPosition(v) != 0 { return createErrorPanel(g, "Can only rename topmost commit") diff --git a/gitcommands.go b/gitcommands.go index fbe8ddae5..bb49f487c 100644 --- a/gitcommands.go +++ b/gitcommands.go @@ -491,6 +491,40 @@ func gitSquashPreviousTwoCommits(message string) (string, error) { return runDirectCommand("git reset --soft HEAD^ && git commit --amend -m \"" + message + "\"") } +func gitSquashFixupCommit(branchName string, shaValue string) (string, error) { + ret := "" + output, err := runDirectCommand("git checkout -q " + shaValue) + ret += output + if err != nil { + goto FIXUP_ERROR + } + output, err = runDirectCommand("git reset --soft " + shaValue + "^") + ret += output + if err != nil { + goto FIXUP_ERROR + } + output, err = runDirectCommand("git commit --amend -C " + shaValue + "^") + ret += output + if err != nil { + goto FIXUP_ERROR + } + output, err = runDirectCommand("git rebase --onto HEAD " + shaValue + " " + branchName) + ret += output + if err != nil { + goto FIXUP_ERROR + } + return ret, err + +FIXUP_ERROR: + //Failed to perform rebase, back to the original branch + output2, err2 := runDirectCommand("git checkout " + branchName) + ret += output2 + if err2 != nil { + return ret, err2 + } + return ret, err +} + func gitRenameCommit(message string) (string, error) { return runDirectCommand("git commit --allow-empty --amend -m \"" + message + "\"") } diff --git a/keybindings.go b/keybindings.go index 0fb800d6e..292f63007 100644 --- a/keybindings.go +++ b/keybindings.go @@ -55,6 +55,7 @@ func keybindings(g *gocui.Gui) error { Binding{ViewName: "commits", Key: 's', Modifier: gocui.ModNone, Handler: handleCommitSquashDown}, Binding{ViewName: "commits", Key: 'r', Modifier: gocui.ModNone, Handler: handleRenameCommit}, Binding{ViewName: "commits", Key: 'g', Modifier: gocui.ModNone, Handler: handleResetToCommit}, + Binding{ViewName: "commits", Key: 'f', Modifier: gocui.ModNone, Handler: handleCommitFixup}, Binding{ViewName: "stash", Key: gocui.KeySpace, Modifier: gocui.ModNone, Handler: handleStashApply}, Binding{ViewName: "stash", Key: 'g', Modifier: gocui.ModNone, Handler: handleStashPop}, Binding{ViewName: "stash", Key: 'd', Modifier: gocui.ModNone, Handler: handleStashDrop},