1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2025-06-15 00:15:32 +02:00

add various interactive rebase commands

This commit is contained in:
Jesse Duffield
2019-02-18 23:27:54 +11:00
parent 76a27f417f
commit d44638130c
7 changed files with 178 additions and 39 deletions

View File

@ -276,7 +276,7 @@ func (c *GitCommand) RebaseBranch(onto string) error {
return err
}
return c.OSCommand.RunCommand(fmt.Sprintf("git rebase %s %s ", onto, curBranch))
return c.OSCommand.RunCommand(fmt.Sprintf("git rebase --autoStash %s %s ", onto, curBranch))
}
// Fetch fetch git repo
@ -462,12 +462,22 @@ func (c *GitCommand) IsInMergeState() (bool, error) {
return strings.Contains(output, "conclude merge") || strings.Contains(output, "unmerged paths"), nil
}
func (c *GitCommand) IsInRebaseState() (bool, error) {
// RebaseMode returns "" for non-rebase mode, "normal" for normal rebase
// and "interactive" for interactive rebase
func (c *GitCommand) RebaseMode() (string, error) {
exists, err := c.OSCommand.FileExists(".git/rebase-apply")
if err != nil {
return false, err
return "", err
}
if exists {
return "normal", nil
}
exists, err = c.OSCommand.FileExists(".git/rebase-merge")
if exists {
return "interactive", err
} else {
return "", err
}
return exists, nil
}
// RemoveFile directly
@ -537,14 +547,21 @@ func (c *GitCommand) getMergeBase() (string, error) {
// GetRebasingCommits obtains the commits that we're in the process of rebasing
func (c *GitCommand) GetRebasingCommits() ([]*Commit, error) {
rebasing, err := c.IsInRebaseState()
rebaseMode, err := c.RebaseMode()
if err != nil {
return nil, err
}
if !rebasing {
switch rebaseMode {
case "normal":
return c.GetNormalRebasingCommits()
case "interactive":
return c.GetInteractiveRebasingCommits()
default:
return nil, nil
}
}
func (c *GitCommand) GetNormalRebasingCommits() ([]*Commit, error) {
rewrittenCount := 0
bytesContent, err := ioutil.ReadFile(".git/rebase-apply/rewritten")
if err == nil {
@ -585,6 +602,10 @@ func (c *GitCommand) GetRebasingCommits() ([]*Commit, error) {
return commits, nil
}
func (c *GitCommand) GetInteractiveRebasingCommits() ([]*Commit, error) {
return nil, nil
}
// assuming the file starts like this:
// From e93d4193e6dd45ca9cf3a5a273d7ba6cd8b8fb20 Mon Sep 17 00:00:00 2001
// From: Lazygit Tester <test@example.com>
@ -780,27 +801,55 @@ func (c *GitCommand) GenericMerge(commandType string, command string) error {
return c.OSCommand.RunCommand(gitCommand)
}
func (c *GitCommand) InteractiveRebase(commits []*Commit, index int, action string) (*exec.Cmd, error) {
ex, err := os.Executable() // get the executable path for git to use
func (c *GitCommand) RewordCommit(commits []*Commit, index int) (*exec.Cmd, error) {
todo, err := c.GenerateGenericRebaseTodo(commits, index, "reword")
if err != nil {
ex = os.Args[0] // fallback to the first call argument if needed
return nil, err
}
// assume for now they won't pick the bottom commit
c.Log.Warn(len(commits))
c.Log.Warn(index)
if len(commits) <= index+1 {
return c.PrepareInteractiveRebaseCommand(commits[index+1].Sha, todo)
}
func (c *GitCommand) MoveCommitDown(commits []*Commit, index int) error {
// we must ensure that we have at least two commits after the selected one
if len(commits) <= index+2 {
// assuming they aren't picking the bottom commit
// TODO: support more than say 30 commits and ensure this logic is correct, and i18n
return nil, errors.New("You cannot interactive rebase onto the first commit")
return errors.New("Not enough room")
}
todo := ""
for i, commit := range commits[0 : index+1] {
a := "pick"
if i == index {
a = action
}
todo += a + " " + commit.Sha + "\n"
orderedCommits := append(commits[0:index], commits[index+1], commits[index])
for _, commit := range orderedCommits {
todo = "pick " + commit.Sha + "\n" + todo
}
cmd, err := c.PrepareInteractiveRebaseCommand(commits[index+2].Sha, todo)
if err != nil {
return err
}
return c.OSCommand.RunPreparedCommand(cmd)
}
func (c *GitCommand) InteractiveRebase(commits []*Commit, index int, action string) error {
todo, err := c.GenerateGenericRebaseTodo(commits, index, action)
if err != nil {
return err
}
cmd, err := c.PrepareInteractiveRebaseCommand(commits[index+1].Sha, todo)
if err != nil {
return err
}
return c.OSCommand.RunPreparedCommand(cmd)
}
func (c *GitCommand) PrepareInteractiveRebaseCommand(baseSha string, todo string) (*exec.Cmd, error) {
ex, err := os.Executable() // get the executable path for git to use
if err != nil {
ex = os.Args[0] // fallback to the first call argument if needed
}
debug := "FALSE"
@ -808,7 +857,7 @@ func (c *GitCommand) InteractiveRebase(commits []*Commit, index int, action stri
debug = "TRUE"
}
splitCmd := str.ToArgv(fmt.Sprintf("git rebase --interactive %s", commits[index+1].Sha))
splitCmd := str.ToArgv(fmt.Sprintf("git rebase --autoStash --interactive %s", baseSha))
cmd := exec.Command(splitCmd[0], splitCmd[1:]...)
@ -823,18 +872,27 @@ func (c *GitCommand) InteractiveRebase(commits []*Commit, index int, action stri
"GIT_SEQUENCE_EDITOR="+ex,
)
if true {
return cmd, nil
return cmd, nil
}
func (c *GitCommand) HardReset(baseSha string) error {
return c.OSCommand.RunCommand("git reset --hard " + baseSha)
}
func (v *GitCommand) GenerateGenericRebaseTodo(commits []*Commit, index int, action string) (string, error) {
if len(commits) <= index+1 {
// assuming they aren't picking the bottom commit
// TODO: support more than say 30 commits and ensure this logic is correct, and i18n
return "", errors.New("You cannot interactive rebase onto the first commit")
}
out, err := cmd.CombinedOutput()
outString := string(out)
c.Log.Info(outString)
if err != nil {
if len(outString) == 0 {
return nil, err
todo := ""
for i, commit := range commits[0 : index+1] {
a := "pick"
if i == index {
a = action
}
return nil, errors.New(outString)
todo = a + " " + commit.Sha + "\n" + todo
}
return nil, nil
return todo, nil
}