mirror of
https://github.com/jesseduffield/lazygit.git
synced 2025-05-11 04:15:48 +02:00
Drop merge commits (#4094)
- **PR Description** Allow deleting a merge commit. We only allow this when the merge commit is the only selected item, and only outside of a rebase. The reason for this is that we don't show the "label" and "reset" todos in lazygit, so deleting a merge commit would leave the commits from the branch that is being merged in the list as "pick" commits, with no indication that they are going to be dropped because they are on a different branch, and the merge commit that would have brought them in is gone. This could be very confusing. Fixes #3164. - **Please check if the PR fulfills these requirements** * [x] Cheatsheets are up-to-date (run `go generate ./...`) * [x] Code has been formatted (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#code-formatting)) * [x] Tests have been added/updated (see [here](https://github.com/jesseduffield/lazygit/blob/master/pkg/integration/README.md) for the integration test guide) * [x] Text is internationalised (see [here](https://github.com/jesseduffield/lazygit/blob/master/CONTRIBUTING.md#internationalisation)) * [ ] If a new UserConfig entry was added, make sure it can be hot-reloaded (see [here](https://github.com/jesseduffield/lazygit/blob/master/docs/dev/Codebase_Guide.md#using-userconfig)) * [ ] Docs have been updated if necessary * [x] You've read through your own file changes for silly mistakes etc
This commit is contained in:
commit
75121384a3
8 changed files with 194 additions and 45 deletions
|
@ -12,7 +12,6 @@ import (
|
|||
"github.com/jesseduffield/lazygit/pkg/common"
|
||||
"github.com/jesseduffield/lazygit/pkg/utils"
|
||||
"github.com/samber/lo"
|
||||
"github.com/stefanhaller/git-todo-parser/todo"
|
||||
)
|
||||
|
||||
// Sometimes lazygit will be invoked in daemon mode from a parent lazygit process.
|
||||
|
@ -39,6 +38,7 @@ const (
|
|||
DaemonKindMoveTodosDown
|
||||
DaemonKindInsertBreak
|
||||
DaemonKindChangeTodoActions
|
||||
DaemonKindDropMergeCommit
|
||||
DaemonKindMoveFixupCommitDown
|
||||
DaemonKindWriteRebaseTodo
|
||||
)
|
||||
|
@ -58,6 +58,7 @@ func getInstruction() Instruction {
|
|||
DaemonKindRemoveUpdateRefsForCopiedBranch: deserializeInstruction[*RemoveUpdateRefsForCopiedBranchInstruction],
|
||||
DaemonKindCherryPick: deserializeInstruction[*CherryPickCommitsInstruction],
|
||||
DaemonKindChangeTodoActions: deserializeInstruction[*ChangeTodoActionsInstruction],
|
||||
DaemonKindDropMergeCommit: deserializeInstruction[*DropMergeCommitInstruction],
|
||||
DaemonKindMoveFixupCommitDown: deserializeInstruction[*MoveFixupCommitDownInstruction],
|
||||
DaemonKindMoveTodosUp: deserializeInstruction[*MoveTodosUpInstruction],
|
||||
DaemonKindMoveTodosDown: deserializeInstruction[*MoveTodosDownInstruction],
|
||||
|
@ -235,7 +236,6 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
|||
changes := lo.Map(self.Changes, func(c ChangeTodoAction, _ int) utils.TodoChange {
|
||||
return utils.TodoChange{
|
||||
Hash: c.Hash,
|
||||
OldAction: todo.Pick,
|
||||
NewAction: c.NewAction,
|
||||
}
|
||||
})
|
||||
|
@ -244,6 +244,30 @@ func (self *ChangeTodoActionsInstruction) run(common *common.Common) error {
|
|||
})
|
||||
}
|
||||
|
||||
type DropMergeCommitInstruction struct {
|
||||
Hash string
|
||||
}
|
||||
|
||||
func NewDropMergeCommitInstruction(hash string) Instruction {
|
||||
return &DropMergeCommitInstruction{
|
||||
Hash: hash,
|
||||
}
|
||||
}
|
||||
|
||||
func (self *DropMergeCommitInstruction) Kind() DaemonKind {
|
||||
return DaemonKindDropMergeCommit
|
||||
}
|
||||
|
||||
func (self *DropMergeCommitInstruction) SerializedInstructions() string {
|
||||
return serializeInstruction(self)
|
||||
}
|
||||
|
||||
func (self *DropMergeCommitInstruction) run(common *common.Common) error {
|
||||
return handleInteractiveRebase(common, func(path string) error {
|
||||
return utils.DropMergeCommit(path, self.Hash, getCommentChar())
|
||||
})
|
||||
}
|
||||
|
||||
// Takes the hash of some commit, and the hash of a fixup commit that was created
|
||||
// at the end of the branch, then moves the fixup commit down to right after the
|
||||
// original commit, changing its type to "fixup" (only if ChangeToFixup is true)
|
||||
|
@ -296,8 +320,7 @@ func (self *MoveTodosUpInstruction) SerializedInstructions() string {
|
|||
func (self *MoveTodosUpInstruction) run(common *common.Common) error {
|
||||
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
|
||||
return utils.Todo{
|
||||
Hash: hash,
|
||||
Action: todo.Pick,
|
||||
Hash: hash,
|
||||
}
|
||||
})
|
||||
|
||||
|
@ -327,8 +350,7 @@ func (self *MoveTodosDownInstruction) SerializedInstructions() string {
|
|||
func (self *MoveTodosDownInstruction) run(common *common.Common) error {
|
||||
todosToMove := lo.Map(self.Hashes, func(hash string, _ int) utils.Todo {
|
||||
return utils.Todo{
|
||||
Hash: hash,
|
||||
Action: todo.Pick,
|
||||
Hash: hash,
|
||||
}
|
||||
})
|
||||
|
||||
|
|
|
@ -324,9 +324,9 @@ func (self *RebaseCommands) MoveFixupCommitDown(commits []*models.Commit, target
|
|||
|
||||
func todoFromCommit(commit *models.Commit) utils.Todo {
|
||||
if commit.Action == todo.UpdateRef {
|
||||
return utils.Todo{Ref: commit.Name, Action: commit.Action}
|
||||
return utils.Todo{Ref: commit.Name}
|
||||
} else {
|
||||
return utils.Todo{Hash: commit.Hash, Action: commit.Action}
|
||||
return utils.Todo{Hash: commit.Hash}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -335,7 +335,6 @@ func (self *RebaseCommands) EditRebaseTodo(commits []*models.Commit, action todo
|
|||
commitsWithAction := lo.Map(commits, func(commit *models.Commit, _ int) utils.TodoChange {
|
||||
return utils.TodoChange{
|
||||
Hash: commit.Hash,
|
||||
OldAction: commit.Action,
|
||||
NewAction: action,
|
||||
}
|
||||
})
|
||||
|
@ -565,6 +564,13 @@ func (self *RebaseCommands) CherryPickCommitsDuringRebase(commits []*models.Comm
|
|||
return utils.PrependStrToTodoFile(filePath, []byte(todo))
|
||||
}
|
||||
|
||||
func (self *RebaseCommands) DropMergeCommit(commits []*models.Commit, commitIndex int) error {
|
||||
return self.PrepareInteractiveRebaseCommand(PrepareInteractiveRebaseCommandOpts{
|
||||
baseHashOrRoot: getBaseHashOrRoot(commits, commitIndex+1),
|
||||
instruction: daemon.NewDropMergeCommitInstruction(commits[commitIndex].Hash),
|
||||
}).Run()
|
||||
}
|
||||
|
||||
// we can't start an interactive rebase from the first commit without passing the
|
||||
// '--root' arg
|
||||
func getBaseHashOrRoot(commits []*models.Commit, index int) string {
|
||||
|
|
|
@ -497,12 +497,17 @@ func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, start
|
|||
return self.updateTodos(todo.Drop, selectedCommits)
|
||||
}
|
||||
|
||||
isMerge := selectedCommits[0].IsMerge()
|
||||
|
||||
self.c.Confirm(types.ConfirmOpts{
|
||||
Title: self.c.Tr.DropCommitTitle,
|
||||
Prompt: self.c.Tr.DropCommitPrompt,
|
||||
Prompt: lo.Ternary(isMerge, self.c.Tr.DropMergeCommitPrompt, self.c.Tr.DropCommitPrompt),
|
||||
HandleConfirm: func() error {
|
||||
return self.c.WithWaitingStatus(self.c.Tr.DroppingStatus, func(gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.DropCommit)
|
||||
if isMerge {
|
||||
return self.dropMergeCommit(startIdx)
|
||||
}
|
||||
return self.interactiveRebase(todo.Drop, startIdx, endIdx)
|
||||
})
|
||||
},
|
||||
|
@ -511,6 +516,11 @@ func (self *LocalCommitsController) drop(selectedCommits []*models.Commit, start
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) dropMergeCommit(commitIdx int) error {
|
||||
err := self.c.Git().Rebase.DropMergeCommit(self.c.Model().Commits, commitIdx)
|
||||
return self.c.Helpers().MergeAndRebase.CheckMergeOrRebase(err)
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) edit(selectedCommits []*models.Commit, startIdx int, endIdx int) error {
|
||||
if self.isRebasing() {
|
||||
return self.updateTodos(todo.Edit, selectedCommits)
|
||||
|
@ -1358,11 +1368,15 @@ func (self *LocalCommitsController) canFindCommitForSquashFixupsInCurrentBranch(
|
|||
return nil
|
||||
}
|
||||
|
||||
func (self *LocalCommitsController) canSquashOrFixup(_selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||
func (self *LocalCommitsController) canSquashOrFixup(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||
if endIdx >= len(self.c.Model().Commits)-1 {
|
||||
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupFirstCommit}
|
||||
}
|
||||
|
||||
if lo.SomeBy(selectedCommits, func(c *models.Commit) bool { return c.IsMerge() }) {
|
||||
return &types.DisabledReason{Text: self.c.Tr.CannotSquashOrFixupMergeCommit}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1420,6 +1434,10 @@ func (self *LocalCommitsController) midRebaseCommandEnabled(selectedCommits []*m
|
|||
// Ensures that if we are mid-rebase, we're only selecting commits that can be moved
|
||||
func (self *LocalCommitsController) midRebaseMoveCommandEnabled(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||
if !self.isRebasing() {
|
||||
if lo.SomeBy(selectedCommits, func(c *models.Commit) bool { return c.IsMerge() }) {
|
||||
return &types.DisabledReason{Text: self.c.Tr.CannotMoveMergeCommit}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
@ -1440,6 +1458,10 @@ func (self *LocalCommitsController) midRebaseMoveCommandEnabled(selectedCommits
|
|||
|
||||
func (self *LocalCommitsController) canDropCommits(selectedCommits []*models.Commit, startIdx int, endIdx int) *types.DisabledReason {
|
||||
if !self.isRebasing() {
|
||||
if len(selectedCommits) > 1 && lo.SomeBy(selectedCommits, func(c *models.Commit) bool { return c.IsMerge() }) {
|
||||
return &types.DisabledReason{Text: self.c.Tr.DroppingMergeRequiresSingleSelection}
|
||||
}
|
||||
|
||||
return nil
|
||||
}
|
||||
|
||||
|
|
|
@ -140,6 +140,7 @@ type TranslationSet struct {
|
|||
Quit string
|
||||
SquashTooltip string
|
||||
CannotSquashOrFixupFirstCommit string
|
||||
CannotSquashOrFixupMergeCommit string
|
||||
Fixup string
|
||||
FixupTooltip string
|
||||
SureFixupThisCommit string
|
||||
|
@ -160,6 +161,7 @@ type TranslationSet struct {
|
|||
MoveDownCommit string
|
||||
MoveUpCommit string
|
||||
CannotMoveAnyFurther string
|
||||
CannotMoveMergeCommit string
|
||||
EditCommit string
|
||||
EditCommitTooltip string
|
||||
AmendCommitTooltip string
|
||||
|
@ -320,6 +322,7 @@ type TranslationSet struct {
|
|||
YouDied string
|
||||
RewordNotSupported string
|
||||
ChangingThisActionIsNotAllowed string
|
||||
DroppingMergeRequiresSingleSelection string
|
||||
CherryPickCopy string
|
||||
CherryPickCopyTooltip string
|
||||
CherryPickCopyRangeTooltip string
|
||||
|
@ -347,6 +350,7 @@ type TranslationSet struct {
|
|||
DropCommitTitle string
|
||||
DropCommitPrompt string
|
||||
DropUpdateRefPrompt string
|
||||
DropMergeCommitPrompt string
|
||||
PullingStatus string
|
||||
PushingStatus string
|
||||
FetchingStatus string
|
||||
|
@ -1134,6 +1138,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
UpdateRefHere: "Update branch '{{.ref}}' here",
|
||||
ExecCommandHere: "Execute the following command here:",
|
||||
CannotSquashOrFixupFirstCommit: "There's no commit below to squash into",
|
||||
CannotSquashOrFixupMergeCommit: "Cannot squash or fixup a merge commit",
|
||||
Fixup: "Fixup",
|
||||
SureFixupThisCommit: "Are you sure you want to 'fixup' the selected commit(s) into the commit below?",
|
||||
SureSquashThisCommit: "Are you sure you want to squash the selected commit(s) into the commit below?",
|
||||
|
@ -1153,6 +1158,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
MoveDownCommit: "Move commit down one",
|
||||
MoveUpCommit: "Move commit up one",
|
||||
CannotMoveAnyFurther: "Cannot move any further",
|
||||
CannotMoveMergeCommit: "Cannot move a merge commit",
|
||||
EditCommit: "Edit (start interactive rebase)",
|
||||
EditCommitTooltip: "Edit the selected commit. Use this to start an interactive rebase from the selected commit. When already mid-rebase, this will mark the selected commit for editing, which means that upon continuing the rebase, the rebase will pause at the selected commit to allow you to make changes.",
|
||||
AmendCommitTooltip: "Amend commit with staged changes. If the selected commit is the HEAD commit, this will perform `git commit --amend`. Otherwise the commit will be amended via a rebase.",
|
||||
|
@ -1320,6 +1326,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
YouDied: "YOU DIED!",
|
||||
RewordNotSupported: "Rewording commits while interactively rebasing is not currently supported",
|
||||
ChangingThisActionIsNotAllowed: "Changing this kind of rebase todo entry is not allowed",
|
||||
DroppingMergeRequiresSingleSelection: "Dropping a merge commit requires a single selected item",
|
||||
CherryPickCopy: "Copy (cherry-pick)",
|
||||
CherryPickCopyTooltip: "Mark commit as copied. Then, within the local commits view, you can press `{{.paste}}` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `{{.escape}}` to cancel the selection.",
|
||||
CherryPickCopyRangeTooltip: "Mark commits as copied from the last copied commit to the selected commit.",
|
||||
|
@ -1346,6 +1353,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
AmendCommitPrompt: "Are you sure you want to amend this commit with your staged files?",
|
||||
DropCommitTitle: "Drop commit",
|
||||
DropCommitPrompt: "Are you sure you want to drop the selected commit(s)?",
|
||||
DropMergeCommitPrompt: "Are you sure you want to drop the selected merge commit? Note that it will also drop all the commits that were merged in by it.",
|
||||
DropUpdateRefPrompt: "Are you sure you want to delete the selected update-ref todo(s)? This is irreversible except by aborting the rebase.",
|
||||
PullingStatus: "Pulling",
|
||||
PushingStatus: "Pushing",
|
||||
|
|
|
@ -0,0 +1,46 @@
|
|||
package interactive_rebase
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
"github.com/jesseduffield/lazygit/pkg/integration/tests/shared"
|
||||
)
|
||||
|
||||
var DropMergeCommit = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Drops a merge commit outside of an interactive rebase",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
GitVersion: AtLeast("2.22.0"), // first version that supports the --rebase-merges option
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shared.CreateMergeCommit(shell)
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Commits().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("CI ⏣─╮ Merge branch 'second-change-branch' into first-change-branch").IsSelected(),
|
||||
Contains("CI │ ◯ * second-change-branch unrelated change"),
|
||||
Contains("CI │ ◯ second change"),
|
||||
Contains("CI ◯ │ first change"),
|
||||
Contains("CI ◯─╯ * original"),
|
||||
Contains("CI ◯ three"),
|
||||
Contains("CI ◯ two"),
|
||||
Contains("CI ◯ one"),
|
||||
).
|
||||
Press(keys.Universal.Remove).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().Confirmation().
|
||||
Title(Equals("Drop commit")).
|
||||
Content(Equals("Are you sure you want to drop the selected merge commit? Note that it will also drop all the commits that were merged in by it.")).
|
||||
Confirm()
|
||||
}).
|
||||
Lines(
|
||||
Contains("CI ◯ first change").IsSelected(),
|
||||
Contains("CI ◯ * original"),
|
||||
Contains("CI ◯ three"),
|
||||
Contains("CI ◯ two"),
|
||||
Contains("CI ◯ one"),
|
||||
)
|
||||
},
|
||||
})
|
|
@ -208,6 +208,7 @@ var tests = []*components.IntegrationTest{
|
|||
interactive_rebase.DeleteUpdateRefTodo,
|
||||
interactive_rebase.DontShowBranchHeadsForTodoItems,
|
||||
interactive_rebase.DropCommitInCopiedBranchWithUpdateRef,
|
||||
interactive_rebase.DropMergeCommit,
|
||||
interactive_rebase.DropTodoCommitWithUpdateRef,
|
||||
interactive_rebase.DropWithCustomCommentChar,
|
||||
interactive_rebase.EditAndAutoAmend,
|
||||
|
|
|
@ -6,24 +6,18 @@ import (
|
|||
"fmt"
|
||||
"os"
|
||||
"slices"
|
||||
"strings"
|
||||
|
||||
"github.com/samber/lo"
|
||||
"github.com/stefanhaller/git-todo-parser/todo"
|
||||
)
|
||||
|
||||
type Todo struct {
|
||||
Hash string // for todos that have one, e.g. pick, drop, fixup, etc.
|
||||
Ref string // for update-ref todos
|
||||
Action todo.TodoCommand
|
||||
Hash string // for todos that have one, e.g. pick, drop, fixup, etc.
|
||||
Ref string // for update-ref todos
|
||||
}
|
||||
|
||||
// In order to change a TODO in git-rebase-todo, we need to specify the old action,
|
||||
// because sometimes the same hash appears multiple times in the file (e.g. in a pick
|
||||
// and later in a merge)
|
||||
type TodoChange struct {
|
||||
Hash string
|
||||
OldAction todo.TodoCommand
|
||||
NewAction todo.TodoCommand
|
||||
}
|
||||
|
||||
|
@ -40,7 +34,7 @@ func EditRebaseTodo(filePath string, changes []TodoChange, commentChar byte) err
|
|||
t := &todos[i]
|
||||
// This is a nested loop, but it's ok because the number of todos should be small
|
||||
for _, change := range changes {
|
||||
if t.Command == change.OldAction && equalHash(t.Commit, change.Hash) {
|
||||
if equalHash(t.Commit, change.Hash) {
|
||||
matchCount++
|
||||
t.Command = change.NewAction
|
||||
}
|
||||
|
@ -56,18 +50,18 @@ func EditRebaseTodo(filePath string, changes []TodoChange, commentChar byte) err
|
|||
}
|
||||
|
||||
func equalHash(a, b string) bool {
|
||||
return strings.HasPrefix(a, b) || strings.HasPrefix(b, a)
|
||||
if len(a) == 0 && len(b) == 0 {
|
||||
return true
|
||||
}
|
||||
|
||||
commonLength := min(len(a), len(b))
|
||||
return commonLength > 0 && a[:commonLength] == b[:commonLength]
|
||||
}
|
||||
|
||||
func findTodo(todos []todo.Todo, todoToFind Todo) (int, bool) {
|
||||
_, idx, ok := lo.FindIndexOf(todos, func(t todo.Todo) bool {
|
||||
// Comparing just the hash is not enough; we need to compare both the
|
||||
// action and the hash, as the hash could appear multiple times (e.g. in a
|
||||
// pick and later in a merge). For update-ref todos we also must compare
|
||||
// the Ref.
|
||||
return t.Command == todoToFind.Action &&
|
||||
equalHash(t.Commit, todoToFind.Hash) &&
|
||||
t.Ref == todoToFind.Ref
|
||||
// For update-ref todos we also must compare the Ref (they have an empty hash)
|
||||
return equalHash(t.Commit, todoToFind.Hash) && t.Ref == todoToFind.Ref
|
||||
})
|
||||
return idx, ok
|
||||
}
|
||||
|
@ -296,3 +290,29 @@ func RemoveUpdateRefsForCopiedBranch(fileName string, commentChar byte) error {
|
|||
func isRenderedTodo(t todo.Todo) bool {
|
||||
return t.Commit != "" || t.Command == todo.UpdateRef
|
||||
}
|
||||
|
||||
func DropMergeCommit(fileName string, hash string, commentChar byte) error {
|
||||
todos, err := ReadRebaseTodoFile(fileName, commentChar)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
newTodos, err := dropMergeCommit(todos, hash)
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
|
||||
return WriteRebaseTodoFile(fileName, newTodos, commentChar)
|
||||
}
|
||||
|
||||
func dropMergeCommit(todos []todo.Todo, hash string) ([]todo.Todo, error) {
|
||||
isMerge := func(t todo.Todo) bool {
|
||||
return t.Command == todo.Merge && t.Flag == "-C" && equalHash(t.Commit, hash)
|
||||
}
|
||||
if lo.CountBy(todos, isMerge) != 1 {
|
||||
return nil, fmt.Errorf("Expected exactly one merge commit with hash %s", hash)
|
||||
}
|
||||
|
||||
_, idx, _ := lo.FindIndexOf(todos, isMerge)
|
||||
return slices.Delete(todos, idx, idx+1), nil
|
||||
}
|
||||
|
|
|
@ -2,6 +2,7 @@ package utils
|
|||
|
||||
import (
|
||||
"errors"
|
||||
"fmt"
|
||||
"testing"
|
||||
|
||||
"github.com/stefanhaller/git-todo-parser/todo"
|
||||
|
@ -25,7 +26,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveDown: Todo{Hash: "5678", Action: todo.Pick},
|
||||
todoToMoveDown: Todo{Hash: "5678"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "5678"},
|
||||
|
@ -40,7 +41,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveDown: Todo{Hash: "abcd", Action: todo.Pick},
|
||||
todoToMoveDown: Todo{Hash: "abcd"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -55,7 +56,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.UpdateRef, Ref: "refs/heads/some_branch"},
|
||||
},
|
||||
todoToMoveDown: Todo{Ref: "refs/heads/some_branch", Action: todo.UpdateRef},
|
||||
todoToMoveDown: Todo{Ref: "refs/heads/some_branch"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -72,7 +73,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "def0"},
|
||||
},
|
||||
todoToMoveDown: Todo{Hash: "5678", Action: todo.Pick},
|
||||
todoToMoveDown: Todo{Hash: "5678"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -91,7 +92,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveDown: Todo{Hash: "def0", Action: todo.Pick},
|
||||
todoToMoveDown: Todo{Hash: "def0"},
|
||||
expectedErr: "Todo def0 not found in git-rebase-todo",
|
||||
expectedTodos: []todo.Todo{},
|
||||
},
|
||||
|
@ -102,7 +103,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveDown: Todo{Hash: "1234", Action: todo.Pick},
|
||||
todoToMoveDown: Todo{Hash: "1234"},
|
||||
expectedErr: "Destination position for moving todo is out of range",
|
||||
expectedTodos: []todo.Todo{},
|
||||
},
|
||||
|
@ -114,7 +115,7 @@ func TestRebaseCommands_moveTodoDown(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "1234"},
|
||||
{Command: todo.Pick, Commit: "5678"},
|
||||
},
|
||||
todoToMoveDown: Todo{Hash: "1234", Action: todo.Pick},
|
||||
todoToMoveDown: Todo{Hash: "1234"},
|
||||
expectedErr: "Destination position for moving todo is out of range",
|
||||
expectedTodos: []todo.Todo{},
|
||||
},
|
||||
|
@ -151,7 +152,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveUp: Todo{Hash: "5678", Action: todo.Pick},
|
||||
todoToMoveUp: Todo{Hash: "5678"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -166,7 +167,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveUp: Todo{Hash: "1234", Action: todo.Pick},
|
||||
todoToMoveUp: Todo{Hash: "1234"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "5678"},
|
||||
|
@ -181,7 +182,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.UpdateRef, Ref: "refs/heads/some_branch"},
|
||||
{Command: todo.Pick, Commit: "5678"},
|
||||
},
|
||||
todoToMoveUp: Todo{Ref: "refs/heads/some_branch", Action: todo.UpdateRef},
|
||||
todoToMoveUp: Todo{Ref: "refs/heads/some_branch"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -198,7 +199,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "def0"},
|
||||
},
|
||||
todoToMoveUp: Todo{Hash: "abcd", Action: todo.Pick},
|
||||
todoToMoveUp: Todo{Hash: "abcd"},
|
||||
expectedErr: "",
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -217,7 +218,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveUp: Todo{Hash: "def0", Action: todo.Pick},
|
||||
todoToMoveUp: Todo{Hash: "def0"},
|
||||
expectedErr: "Todo def0 not found in git-rebase-todo",
|
||||
expectedTodos: []todo.Todo{},
|
||||
},
|
||||
|
@ -228,7 +229,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todoToMoveUp: Todo{Hash: "abcd", Action: todo.Pick},
|
||||
todoToMoveUp: Todo{Hash: "abcd"},
|
||||
expectedErr: "Destination position for moving todo is out of range",
|
||||
expectedTodos: []todo.Todo{},
|
||||
},
|
||||
|
@ -240,7 +241,7 @@ func TestRebaseCommands_moveTodoUp(t *testing.T) {
|
|||
{Command: todo.Label, Label: "myLabel"},
|
||||
{Command: todo.Reset, Label: "otherlabel"},
|
||||
},
|
||||
todoToMoveUp: Todo{Hash: "5678", Action: todo.Pick},
|
||||
todoToMoveUp: Todo{Hash: "5678"},
|
||||
expectedErr: "Destination position for moving todo is out of range",
|
||||
expectedTodos: []todo.Todo{},
|
||||
},
|
||||
|
@ -416,8 +417,8 @@ func TestRebaseCommands_deleteTodos(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "abcd"},
|
||||
},
|
||||
todosToDelete: []Todo{
|
||||
{Ref: "refs/heads/some_branch", Action: todo.UpdateRef},
|
||||
{Hash: "abcd", Action: todo.Pick},
|
||||
{Ref: "refs/heads/some_branch"},
|
||||
{Hash: "abcd"},
|
||||
},
|
||||
expectedTodos: []todo.Todo{
|
||||
{Command: todo.Pick, Commit: "1234"},
|
||||
|
@ -432,7 +433,7 @@ func TestRebaseCommands_deleteTodos(t *testing.T) {
|
|||
{Command: todo.Pick, Commit: "5678"},
|
||||
},
|
||||
todosToDelete: []Todo{
|
||||
{Hash: "abcd", Action: todo.Pick},
|
||||
{Hash: "abcd"},
|
||||
},
|
||||
expectedTodos: []todo.Todo{},
|
||||
expectedErr: errors.New("Todo abcd not found in git-rebase-todo"),
|
||||
|
@ -453,3 +454,26 @@ func TestRebaseCommands_deleteTodos(t *testing.T) {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
func Test_equalHash(t *testing.T) {
|
||||
scenarios := []struct {
|
||||
a string
|
||||
b string
|
||||
expected bool
|
||||
}{
|
||||
{"", "", true},
|
||||
{"", "123", false},
|
||||
{"123", "", false},
|
||||
{"123", "123", true},
|
||||
{"123", "123abc", true},
|
||||
{"123abc", "123", true},
|
||||
{"123", "a", false},
|
||||
{"1", "abc", false},
|
||||
}
|
||||
|
||||
for _, scenario := range scenarios {
|
||||
t.Run(fmt.Sprintf("'%s' vs. '%s'", scenario.a, scenario.b), func(t *testing.T) {
|
||||
assert.Equal(t, scenario.expected, equalHash(scenario.a, scenario.b))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue