From ecc70f47647aef5243ada33a65e1e99abfd975de Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 2 Apr 2025 14:50:53 +0200 Subject: [PATCH 1/6] Cleanup: remove unnecessary indirection --- pkg/gui/controllers/helpers/merge_and_rebase_helper.go | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index 8505110a0..dc5988757 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -277,7 +277,7 @@ func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { disabledReason = &types.DisabledReason{Text: self.c.Tr.CantRebaseOntoSelf} } - baseBranch, err := self.c.Git().Loaders.BranchLoader.GetBaseBranch(checkedOutBranch, self.refsHelper.c.Model().MainBranches) + baseBranch, err := self.c.Git().Loaders.BranchLoader.GetBaseBranch(checkedOutBranch, self.c.Model().MainBranches) if err != nil { return err } From 483195110a7d4b1251ed892cd3f7c0c551d1ebeb Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 2 Apr 2025 14:59:32 +0200 Subject: [PATCH 2/6] Use Model().Branches[0] instead of refsHelper.GetCheckedOutRef() in MergeAndRebaseHelper It's the same, really, except that GetCheckedOutRef() does a check if any branches exist and returns nil if not. Since we are accessing the returned branch unconditionally without checking for nil, it seems this check is not needed here. (The functions we are touching here are called from handlers that are guarded with itemSelected or singleItemSelected, so we know that at least one branch exists.) The goal is to get rid of the dependency to refsHelper. --- pkg/gui/controllers/helpers/merge_and_rebase_helper.go | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index dc5988757..d5efc72ca 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -270,8 +270,8 @@ func (self *MergeAndRebaseHelper) PromptToContinueRebase() error { } func (self *MergeAndRebaseHelper) RebaseOntoRef(ref string) error { - checkedOutBranch := self.refsHelper.GetCheckedOutRef() - checkedOutBranchName := self.refsHelper.GetCheckedOutRef().Name + checkedOutBranch := self.c.Model().Branches[0] + checkedOutBranchName := checkedOutBranch.Name var disabledReason, baseBranchDisabledReason *types.DisabledReason if checkedOutBranchName == ref { disabledReason = &types.DisabledReason{Text: self.c.Tr.CantRebaseOntoSelf} @@ -383,7 +383,7 @@ func (self *MergeAndRebaseHelper) MergeRefIntoCheckedOutBranch(refName string) e if self.c.Git().Branch.IsHeadDetached() { return errors.New("Cannot merge branch in detached head state. You might have checked out a commit directly or a remote branch, in which case you should checkout the local branch you want to be on") } - checkedOutBranchName := self.refsHelper.GetCheckedOutRef().Name + checkedOutBranchName := self.c.Model().Branches[0].Name if checkedOutBranchName == refName { return errors.New(self.c.Tr.CantMergeBranchIntoItself) } From 9d88d6a44e2c1d3df9dd2996a951d57ebf86a6d5 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Wed, 2 Apr 2025 15:01:52 +0200 Subject: [PATCH 3/6] Remove MergeAndRebaseHelper's dependency on RefsHelper We want to make MergeAndRebaseHelper a dependency of RefsHelper instead. --- pkg/gui/controllers.go | 2 +- pkg/gui/controllers/helpers/merge_and_rebase_helper.go | 7 ++----- 2 files changed, 3 insertions(+), 6 deletions(-) diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index e6f6bbb4e..14c8882b9 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -31,7 +31,7 @@ func (gui *Gui) resetHelpersAndControllers() { suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon) worktreeHelper := helpers.NewWorktreeHelper(helperCommon, reposHelper, refsHelper, suggestionsHelper) - rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon, refsHelper) + rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon) setCommitSummary := gui.getCommitMessageSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }) setCommitDescription := gui.getCommitMessageSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitDescription }) diff --git a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go index d5efc72ca..079e2ab68 100644 --- a/pkg/gui/controllers/helpers/merge_and_rebase_helper.go +++ b/pkg/gui/controllers/helpers/merge_and_rebase_helper.go @@ -17,17 +17,14 @@ import ( ) type MergeAndRebaseHelper struct { - c *HelperCommon - refsHelper *RefsHelper + c *HelperCommon } func NewMergeAndRebaseHelper( c *HelperCommon, - refsHelper *RefsHelper, ) *MergeAndRebaseHelper { return &MergeAndRebaseHelper{ - c: c, - refsHelper: refsHelper, + c: c, } } From 4bf11eae4b290e9763a38a39fa3c913f2285002f Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 30 Aug 2024 14:25:23 +0200 Subject: [PATCH 4/6] Add free-standing function IsWorkingTreeDirty The long story: I want to call this function from RefsHelper; however, I can't make WorkingTreeHelper a field of RefsHelper because RefsHelper is already a field in WorkingTreeHelper, so that would be a circular dependency. The shorter story: there's really little reason to have to instantiate a helper object in order to call a simple function like this. Long term I would like to get to a state where a lot more of these helper functions are free-standing, and you pass in the data they need. While at it, simplify the implementation of AnyStagedFiles and AnyTrackedFiles to one-liners. --- .../helpers/working_tree_helper.go | 29 ++++++++++--------- 1 file changed, 16 insertions(+), 13 deletions(-) diff --git a/pkg/gui/controllers/helpers/working_tree_helper.go b/pkg/gui/controllers/helpers/working_tree_helper.go index a95bdb98e..4d0d1e9da 100644 --- a/pkg/gui/controllers/helpers/working_tree_helper.go +++ b/pkg/gui/controllers/helpers/working_tree_helper.go @@ -10,6 +10,7 @@ import ( "github.com/jesseduffield/lazygit/pkg/config" "github.com/jesseduffield/lazygit/pkg/gui/context" "github.com/jesseduffield/lazygit/pkg/gui/types" + "github.com/samber/lo" ) type WorkingTreeHelper struct { @@ -34,25 +35,27 @@ func NewWorkingTreeHelper( } func (self *WorkingTreeHelper) AnyStagedFiles() bool { - for _, file := range self.c.Model().Files { - if file.HasStagedChanges { - return true - } - } - return false + return AnyStagedFiles(self.c.Model().Files) +} + +func AnyStagedFiles(files []*models.File) bool { + return lo.SomeBy(files, func(f *models.File) bool { return f.HasStagedChanges }) } func (self *WorkingTreeHelper) AnyTrackedFiles() bool { - for _, file := range self.c.Model().Files { - if file.Tracked { - return true - } - } - return false + return AnyTrackedFiles(self.c.Model().Files) +} + +func AnyTrackedFiles(files []*models.File) bool { + return lo.SomeBy(files, func(f *models.File) bool { return f.Tracked }) } func (self *WorkingTreeHelper) IsWorkingTreeDirty() bool { - return self.AnyStagedFiles() || self.AnyTrackedFiles() + return IsWorkingTreeDirty(self.c.Model().Files) +} + +func IsWorkingTreeDirty(files []*models.File) bool { + return AnyStagedFiles(files) || AnyTrackedFiles(files) } func (self *WorkingTreeHelper) FileForSubmodule(submodule *models.SubmoduleConfig) *models.File { From 30868eead8d0c50782b01ba696d195ed36bdefbe Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Fri, 30 Aug 2024 12:27:50 +0200 Subject: [PATCH 5/6] Add new command "Move commits to new branch" --- pkg/commands/git_commands/branch.go | 9 + pkg/config/user_config.go | 2 + pkg/gui/controllers.go | 5 +- .../controllers/basic_commits_controller.go | 11 ++ pkg/gui/controllers/branches_controller.go | 7 + pkg/gui/controllers/helpers/refs_helper.go | 174 +++++++++++++++++- pkg/i18n/english.go | 22 +++ ..._commits_to_new_branch_from_base_branch.go | 66 +++++++ ..._commits_to_new_branch_from_main_branch.go | 61 ++++++ ...move_commits_to_new_branch_keep_stacked.go | 67 +++++++ pkg/integration/tests/test_list.go | 3 + 11 files changed, 423 insertions(+), 4 deletions(-) create mode 100644 pkg/integration/tests/branch/move_commits_to_new_branch_from_base_branch.go create mode 100644 pkg/integration/tests/branch/move_commits_to_new_branch_from_main_branch.go create mode 100644 pkg/integration/tests/branch/move_commits_to_new_branch_keep_stacked.go diff --git a/pkg/commands/git_commands/branch.go b/pkg/commands/git_commands/branch.go index 72473bc14..017792a68 100644 --- a/pkg/commands/git_commands/branch.go +++ b/pkg/commands/git_commands/branch.go @@ -40,6 +40,15 @@ func (self *BranchCommands) NewWithoutTracking(name string, base string) error { return self.cmd.New(cmdArgs).Run() } +// NewWithoutCheckout creates a new branch without checking it out +func (self *BranchCommands) NewWithoutCheckout(name string, base string) error { + cmdArgs := NewGitCmd("branch"). + Arg(name, base). + ToArgv() + + return self.cmd.New(cmdArgs).Run() +} + // CreateWithUpstream creates a new branch with a given upstream, but without // checking it out func (self *BranchCommands) CreateWithUpstream(name string, upstream string) error { diff --git a/pkg/config/user_config.go b/pkg/config/user_config.go index 5e6b150b5..d35e35772 100644 --- a/pkg/config/user_config.go +++ b/pkg/config/user_config.go @@ -482,6 +482,7 @@ type KeybindingBranchesConfig struct { RebaseBranch string `yaml:"rebaseBranch"` RenameBranch string `yaml:"renameBranch"` MergeIntoCurrentBranch string `yaml:"mergeIntoCurrentBranch"` + MoveCommitsToNewBranch string `yaml:"moveCommitsToNewBranch"` ViewGitFlowOptions string `yaml:"viewGitFlowOptions"` FastForward string `yaml:"fastForward"` CreateTag string `yaml:"createTag"` @@ -962,6 +963,7 @@ func GetDefaultConfig() *UserConfig { RebaseBranch: "r", RenameBranch: "R", MergeIntoCurrentBranch: "M", + MoveCommitsToNewBranch: "N", ViewGitFlowOptions: "i", FastForward: "f", CreateTag: "T", diff --git a/pkg/gui/controllers.go b/pkg/gui/controllers.go index 14c8882b9..abbb62155 100644 --- a/pkg/gui/controllers.go +++ b/pkg/gui/controllers.go @@ -27,12 +27,11 @@ func (gui *Gui) resetHelpersAndControllers() { helperCommon := gui.c recordDirectoryHelper := helpers.NewRecordDirectoryHelper(helperCommon) reposHelper := helpers.NewRecentReposHelper(helperCommon, recordDirectoryHelper, gui.onNewRepo) - refsHelper := helpers.NewRefsHelper(helperCommon) + rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon) + refsHelper := helpers.NewRefsHelper(helperCommon, rebaseHelper) suggestionsHelper := helpers.NewSuggestionsHelper(helperCommon) worktreeHelper := helpers.NewWorktreeHelper(helperCommon, reposHelper, refsHelper, suggestionsHelper) - rebaseHelper := helpers.NewMergeAndRebaseHelper(helperCommon) - setCommitSummary := gui.getCommitMessageSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitMessage }) setCommitDescription := gui.getCommitMessageSetTextareaTextFn(func() *gocui.View { return gui.Views.CommitDescription }) getCommitSummary := func() string { diff --git a/pkg/gui/controllers/basic_commits_controller.go b/pkg/gui/controllers/basic_commits_controller.go index 76dd55006..89f0905e5 100644 --- a/pkg/gui/controllers/basic_commits_controller.go +++ b/pkg/gui/controllers/basic_commits_controller.go @@ -80,6 +80,17 @@ func (self *BasicCommitsController) GetKeybindings(opts types.KeybindingsOpts) [ GetDisabledReason: self.require(self.singleItemSelected()), Description: self.c.Tr.CreateNewBranchFromCommit, }, + { + // Putting this in BasicCommitsController even though we really only want it in the commits + // panel. But I find it important that this ends up next to "New Branch", and I couldn't + // find another way to achieve this. It's not such a big deal to have it in subcommits and + // reflog too, I'd say. + Key: opts.GetKey(opts.Config.Branches.MoveCommitsToNewBranch), + Handler: self.c.Helpers().Refs.MoveCommitsToNewBranch, + GetDisabledReason: self.c.Helpers().Refs.CanMoveCommitsToNewBranch, + Description: self.c.Tr.MoveCommitsToNewBranch, + Tooltip: self.c.Tr.MoveCommitsToNewBranchTooltip, + }, { Key: opts.GetKey(opts.Config.Commits.ViewResetOptions), Handler: self.withItem(self.createResetMenu), diff --git a/pkg/gui/controllers/branches_controller.go b/pkg/gui/controllers/branches_controller.go index b164407e7..b3ce28ab8 100644 --- a/pkg/gui/controllers/branches_controller.go +++ b/pkg/gui/controllers/branches_controller.go @@ -57,6 +57,13 @@ func (self *BranchesController) GetKeybindings(opts types.KeybindingsOpts) []*ty Description: self.c.Tr.NewBranch, DisplayOnScreen: true, }, + { + Key: opts.GetKey(opts.Config.Branches.MoveCommitsToNewBranch), + Handler: self.c.Helpers().Refs.MoveCommitsToNewBranch, + GetDisabledReason: self.c.Helpers().Refs.CanMoveCommitsToNewBranch, + Description: self.c.Tr.MoveCommitsToNewBranch, + Tooltip: self.c.Tr.MoveCommitsToNewBranchTooltip, + }, { Key: opts.GetKey(opts.Config.Branches.CreatePullRequest), Handler: self.withItem(self.handleCreatePullRequest), diff --git a/pkg/gui/controllers/helpers/refs_helper.go b/pkg/gui/controllers/helpers/refs_helper.go index 296d66aca..9cc10983b 100644 --- a/pkg/gui/controllers/helpers/refs_helper.go +++ b/pkg/gui/controllers/helpers/refs_helper.go @@ -17,13 +17,17 @@ import ( type RefsHelper struct { c *HelperCommon + + rebaseHelper *MergeAndRebaseHelper } func NewRefsHelper( c *HelperCommon, + rebaseHelper *MergeAndRebaseHelper, ) *RefsHelper { return &RefsHelper{ - c: c, + c: c, + rebaseHelper: rebaseHelper, } } @@ -388,6 +392,174 @@ func (self *RefsHelper) NewBranch(from string, fromFormattedName string, suggest return nil } +func (self *RefsHelper) MoveCommitsToNewBranch() error { + currentBranch := self.c.Model().Branches[0] + baseBranchRef, err := self.c.Git().Loaders.BranchLoader.GetBaseBranch(currentBranch, self.c.Model().MainBranches) + if err != nil { + return err + } + + withNewBranchNamePrompt := func(baseBranchName string, f func(string, string) error) { + prompt := utils.ResolvePlaceholderString( + self.c.Tr.NewBranchNameBranchOff, + map[string]string{ + "branchName": baseBranchName, + }, + ) + + self.c.Prompt(types.PromptOpts{ + Title: prompt, + HandleConfirm: func(response string) error { + self.c.LogAction(self.c.Tr.MoveCommitsToNewBranch) + newBranchName := SanitizedBranchName(response) + return self.c.WithWaitingStatus(self.c.Tr.MovingCommitsToNewBranchStatus, func(gocui.Task) error { + return f(currentBranch.Name, newBranchName) + }) + }, + }) + } + + isMainBranch := lo.Contains(self.c.UserConfig().Git.MainBranches, currentBranch.Name) + if isMainBranch { + prompt := utils.ResolvePlaceholderString( + self.c.Tr.MoveCommitsToNewBranchFromMainPrompt, + map[string]string{ + "baseBranchName": currentBranch.Name, + }, + ) + self.c.Confirm(types.ConfirmOpts{ + Title: self.c.Tr.MoveCommitsToNewBranch, + Prompt: prompt, + HandleConfirm: func() error { + withNewBranchNamePrompt(currentBranch.Name, self.moveCommitsToNewBranchStackedOnCurrentBranch) + return nil + }, + }) + return nil + } + + shortBaseBranchName := ShortBranchName(baseBranchRef) + prompt := utils.ResolvePlaceholderString( + self.c.Tr.MoveCommitsToNewBranchMenuPrompt, + map[string]string{ + "baseBranchName": shortBaseBranchName, + }, + ) + return self.c.Menu(types.CreateMenuOptions{ + Title: self.c.Tr.MoveCommitsToNewBranch, + Prompt: prompt, + Items: []*types.MenuItem{ + { + Label: fmt.Sprintf(self.c.Tr.MoveCommitsToNewBranchFromBaseItem, shortBaseBranchName), + OnPress: func() error { + withNewBranchNamePrompt(shortBaseBranchName, func(currentBranch string, newBranchName string) error { + return self.moveCommitsToNewBranchOffOfMainBranch(currentBranch, newBranchName, baseBranchRef) + }) + return nil + }, + }, + { + Label: fmt.Sprintf(self.c.Tr.MoveCommitsToNewBranchStackedItem, currentBranch.Name), + OnPress: func() error { + withNewBranchNamePrompt(currentBranch.Name, self.moveCommitsToNewBranchStackedOnCurrentBranch) + return nil + }, + }, + }, + }) +} + +func (self *RefsHelper) moveCommitsToNewBranchStackedOnCurrentBranch(currentBranch string, newBranchName string) error { + if err := self.c.Git().Branch.NewWithoutCheckout(newBranchName, "HEAD"); err != nil { + return err + } + + mustStash := IsWorkingTreeDirty(self.c.Model().Files) + if mustStash { + if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + currentBranch); err != nil { + return err + } + } + + if err := self.c.Git().Commit.ResetToCommit("@{u}", "hard", []string{}); err != nil { + return err + } + + if err := self.c.Git().Branch.Checkout(newBranchName, git_commands.CheckoutOptions{}); err != nil { + return err + } + + if mustStash { + if err := self.c.Git().Stash.Pop(0); err != nil { + return err + } + } + + self.c.Contexts().LocalCommits.SetSelection(0) + self.c.Contexts().Branches.SetSelection(0) + + return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true}) +} + +func (self *RefsHelper) moveCommitsToNewBranchOffOfMainBranch(currentBranch string, newBranchName string, baseBranchRef string) error { + commitsToCherryPick := lo.Filter(self.c.Model().Commits, func(commit *models.Commit, _ int) bool { + return commit.Status == models.StatusUnpushed + }) + + mustStash := IsWorkingTreeDirty(self.c.Model().Files) + if mustStash { + if err := self.c.Git().Stash.Push(self.c.Tr.StashPrefix + currentBranch); err != nil { + return err + } + } + + if err := self.c.Git().Commit.ResetToCommit("@{u}", "hard", []string{}); err != nil { + return err + } + + if err := self.c.Git().Branch.NewWithoutTracking(newBranchName, baseBranchRef); err != nil { + return err + } + + err := self.c.Git().Rebase.CherryPickCommits(commitsToCherryPick) + err = self.rebaseHelper.CheckMergeOrRebaseWithRefreshOptions(err, types.RefreshOptions{Mode: types.SYNC}) + if err != nil { + return err + } + + if mustStash { + if err := self.c.Git().Stash.Pop(0); err != nil { + return err + } + } + + self.c.Contexts().LocalCommits.SetSelection(0) + self.c.Contexts().Branches.SetSelection(0) + + return self.c.Refresh(types.RefreshOptions{Mode: types.BLOCK_UI, KeepBranchSelectionIndex: true}) +} + +func (self *RefsHelper) CanMoveCommitsToNewBranch() *types.DisabledReason { + if len(self.c.Model().Branches) == 0 { + return &types.DisabledReason{Text: self.c.Tr.NoBranchesThisRepo} + } + currentBranch := self.GetCheckedOutRef() + if currentBranch.DetachedHead { + return &types.DisabledReason{Text: self.c.Tr.CannotMoveCommitsFromDetachedHead, ShowErrorInPanel: true} + } + if !currentBranch.RemoteBranchStoredLocally() { + return &types.DisabledReason{Text: self.c.Tr.CannotMoveCommitsNoUpstream, ShowErrorInPanel: true} + } + if currentBranch.IsBehindForPull() { + return &types.DisabledReason{Text: self.c.Tr.CannotMoveCommitsBehindUpstream, ShowErrorInPanel: true} + } + if !currentBranch.IsAheadForPull() { + return &types.DisabledReason{Text: self.c.Tr.CannotMoveCommitsNoUnpushedCommits, ShowErrorInPanel: true} + } + + return nil +} + // SanitizedBranchName will remove all spaces in favor of a dash "-" to meet // git's branch naming requirement. func SanitizedBranchName(input string) string { diff --git a/pkg/i18n/english.go b/pkg/i18n/english.go index 3b961e7d1..baf3e20de 100644 --- a/pkg/i18n/english.go +++ b/pkg/i18n/english.go @@ -151,6 +151,16 @@ type TranslationSet struct { CheckoutTypeDetachedHeadTooltip string NewBranch string NewBranchFromStashTooltip string + MoveCommitsToNewBranch string + MoveCommitsToNewBranchTooltip string + MoveCommitsToNewBranchFromMainPrompt string + MoveCommitsToNewBranchMenuPrompt string + MoveCommitsToNewBranchFromBaseItem string + MoveCommitsToNewBranchStackedItem string + CannotMoveCommitsFromDetachedHead string + CannotMoveCommitsNoUpstream string + CannotMoveCommitsBehindUpstream string + CannotMoveCommitsNoUnpushedCommits string NoBranchesThisRepo string CommitWithoutMessageErr string Close string @@ -413,6 +423,7 @@ type TranslationSet struct { RewordingStatus string RevertingStatus string CreatingFixupCommitStatus string + MovingCommitsToNewBranchStatus string CommitFiles string SubCommitsDynamicTitle string CommitFilesDynamicTitle string @@ -1217,6 +1228,16 @@ func EnglishTranslationSet() *TranslationSet { CheckoutTypeDetachedHeadTooltip: "Checkout the remote branch as a detached head, which can be useful if you just want to test the branch but not work on it yourself. You can still create a local branch from it later.", NewBranch: "New branch", NewBranchFromStashTooltip: "Create a new branch from the selected stash entry. This works by git checking out the commit that the stash entry was created from, creating a new branch from that commit, then applying the stash entry to the new branch as an additional commit.", + MoveCommitsToNewBranch: "Move commits to new branch", + MoveCommitsToNewBranchTooltip: "Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first.\n\nNote that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which).", + MoveCommitsToNewBranchFromMainPrompt: "This will take all unpushed commits and move them to a new branch (off of {{.baseBranchName}}). It will then hard-reset the current branch its the upstream branch. Do you want to continue?", + MoveCommitsToNewBranchMenuPrompt: "This will take all unpushed commits and move them to a new branch. This new branch can either be created from the main branch ({{.baseBranchName}}) or stacked on top of the current branch. Which of these would you like to do?", + MoveCommitsToNewBranchFromBaseItem: "New branch from base branch (%s)", + MoveCommitsToNewBranchStackedItem: "New branch stacked on current branch (%s)", + CannotMoveCommitsFromDetachedHead: "Cannot move commits from a detached head", + CannotMoveCommitsNoUpstream: "Cannot move commits from a branch that has no upstream branch", + CannotMoveCommitsBehindUpstream: "Cannot move commits from a branch that is behind its upstream branch", + CannotMoveCommitsNoUnpushedCommits: "There are no unpushed commits to move to a new branch", NoBranchesThisRepo: "No branches for this repo", CommitWithoutMessageErr: "You cannot commit without a commit message", Close: "Close", @@ -1488,6 +1509,7 @@ func EnglishTranslationSet() *TranslationSet { RewordingStatus: "Rewording", RevertingStatus: "Reverting", CreatingFixupCommitStatus: "Creating fixup commit", + MovingCommitsToNewBranchStatus: "Moving commits to new branch", CommitFiles: "Commit files", SubCommitsDynamicTitle: "Commits (%s)", CommitFilesDynamicTitle: "Diff files (%s)", diff --git a/pkg/integration/tests/branch/move_commits_to_new_branch_from_base_branch.go b/pkg/integration/tests/branch/move_commits_to_new_branch_from_base_branch.go new file mode 100644 index 000000000..0b6bd71aa --- /dev/null +++ b/pkg/integration/tests/branch/move_commits_to_new_branch_from_base_branch.go @@ -0,0 +1,66 @@ +package branch + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var MoveCommitsToNewBranchFromBaseBranch = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Create a new branch from the commits that you accidentally made on the wrong branch; choosing base branch", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.EmptyCommit("initial commit") + shell.CloneIntoRemote("origin") + shell.PushBranchAndSetUpstream("origin", "master") + shell.NewBranch("feature") + shell.EmptyCommit("feature branch commit") + shell.PushBranchAndSetUpstream("origin", "feature") + shell.CreateFileAndAdd("file1", "file1 content") + shell.Commit("new commit 1") + shell.EmptyCommit("new commit 2") + shell.UpdateFile("file1", "file1 changed") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + Lines( + Contains("M file1"), + ) + t.Views().Branches(). + Focus(). + Lines( + Contains("feature ↑2").IsSelected(), + Contains("master ✓"), + ). + Press(keys.Branches.MoveCommitsToNewBranch) + + t.ExpectPopup().Menu(). + Title(Equals("Move commits to new branch")). + Select(Contains("New branch from base branch (origin/master)")). + Confirm() + + t.ExpectPopup().Prompt(). + Title(Equals("New branch name (branch is off of 'origin/master')")). + Type("new branch"). + Confirm() + + t.Views().Branches(). + Lines( + Contains("new-branch").DoesNotContain("↑").IsSelected(), + Contains("feature ✓"), + Contains("master ✓"), + ) + + t.Views().Commits(). + Lines( + Contains("new commit 2").IsSelected(), + Contains("new commit 1"), + Contains("initial commit"), + ) + t.Views().Files(). + Lines( + Contains("M file1"), + ) + }, +}) diff --git a/pkg/integration/tests/branch/move_commits_to_new_branch_from_main_branch.go b/pkg/integration/tests/branch/move_commits_to_new_branch_from_main_branch.go new file mode 100644 index 000000000..3373064eb --- /dev/null +++ b/pkg/integration/tests/branch/move_commits_to_new_branch_from_main_branch.go @@ -0,0 +1,61 @@ +package branch + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var MoveCommitsToNewBranchFromMainBranch = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Create a new branch from the commits that you accidentally made on master", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.EmptyCommit("initial commit") + shell.CloneIntoRemote("origin") + shell.PushBranchAndSetUpstream("origin", "master") + shell.CreateFileAndAdd("file1", "file1 content") + shell.Commit("new commit 1") + shell.EmptyCommit("new commit 2") + shell.UpdateFile("file1", "file1 changed") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + Lines( + Contains("M file1"), + ) + t.Views().Branches(). + Focus(). + Lines( + Contains("master ↑2").IsSelected(), + ). + Press(keys.Branches.MoveCommitsToNewBranch) + + t.ExpectPopup().Confirmation(). + Title(Equals("Move commits to new branch")). + Content(Contains("This will take all unpushed commits and move them to a new branch (off of master).")). + Confirm() + + t.ExpectPopup().Prompt(). + Title(Equals("New branch name (branch is off of 'master')")). + Type("new branch"). + Confirm() + + t.Views().Branches(). + Lines( + Contains("new-branch").DoesNotContain("↑").IsSelected(), + Contains("master ✓"), + ) + + t.Views().Commits(). + Lines( + Contains("new commit 2").IsSelected(), + Contains("new commit 1"), + Contains("initial commit"), + ) + t.Views().Files(). + Lines( + Contains("M file1"), + ) + }, +}) diff --git a/pkg/integration/tests/branch/move_commits_to_new_branch_keep_stacked.go b/pkg/integration/tests/branch/move_commits_to_new_branch_keep_stacked.go new file mode 100644 index 000000000..0b9828ef1 --- /dev/null +++ b/pkg/integration/tests/branch/move_commits_to_new_branch_keep_stacked.go @@ -0,0 +1,67 @@ +package branch + +import ( + "github.com/jesseduffield/lazygit/pkg/config" + . "github.com/jesseduffield/lazygit/pkg/integration/components" +) + +var MoveCommitsToNewBranchKeepStacked = NewIntegrationTest(NewIntegrationTestArgs{ + Description: "Create a new branch from the commits that you accidentally made on the wrong branch; choosing stacked on current branch", + ExtraCmdArgs: []string{}, + Skip: false, + SetupConfig: func(config *config.AppConfig) {}, + SetupRepo: func(shell *Shell) { + shell.EmptyCommit("initial commit") + shell.CloneIntoRemote("origin") + shell.PushBranchAndSetUpstream("origin", "master") + shell.NewBranch("feature") + shell.EmptyCommit("feature branch commit") + shell.PushBranchAndSetUpstream("origin", "feature") + shell.CreateFileAndAdd("file1", "file1 content") + shell.Commit("new commit 1") + shell.EmptyCommit("new commit 2") + shell.UpdateFile("file1", "file1 changed") + }, + Run: func(t *TestDriver, keys config.KeybindingConfig) { + t.Views().Files(). + Lines( + Contains("M file1"), + ) + t.Views().Branches(). + Focus(). + Lines( + Contains("feature ↑2").IsSelected(), + Contains("master ✓"), + ). + Press(keys.Branches.MoveCommitsToNewBranch) + + t.ExpectPopup().Menu(). + Title(Equals("Move commits to new branch")). + Select(Contains("New branch stacked on current branch (feature)")). + Confirm() + + t.ExpectPopup().Prompt(). + Title(Equals("New branch name (branch is off of 'feature')")). + Type("new branch"). + Confirm() + + t.Views().Branches(). + Lines( + Contains("new-branch").DoesNotContain("↑").IsSelected(), + Contains("feature ✓"), + Contains("master ✓"), + ) + + t.Views().Commits(). + Lines( + Contains("new commit 2").IsSelected(), + Contains("new commit 1"), + Contains("* feature branch commit"), + Contains("initial commit"), + ) + t.Views().Files(). + Lines( + Contains("M file1"), + ) + }, +}) diff --git a/pkg/integration/tests/test_list.go b/pkg/integration/tests/test_list.go index 96a895798..03d995d92 100644 --- a/pkg/integration/tests/test_list.go +++ b/pkg/integration/tests/test_list.go @@ -47,6 +47,9 @@ var tests = []*components.IntegrationTest{ branch.DeleteRemoteBranchWithDifferentName, branch.DeleteWhileFiltering, branch.DetachedHead, + branch.MoveCommitsToNewBranchFromBaseBranch, + branch.MoveCommitsToNewBranchFromMainBranch, + branch.MoveCommitsToNewBranchKeepStacked, branch.NewBranchAutostash, branch.NewBranchFromRemoteTrackingDifferentName, branch.NewBranchFromRemoteTrackingSameName, From f65166ae91a847d08358040a5d1858eca78ee234 Mon Sep 17 00:00:00 2001 From: Stefan Haller Date: Tue, 1 Apr 2025 13:52:12 +0200 Subject: [PATCH 6/6] Update config docs and schema --- docs/Config.md | 1 + docs/keybindings/Keybindings_en.md | 12 ++++++++++++ docs/keybindings/Keybindings_ja.md | 12 ++++++++++++ docs/keybindings/Keybindings_ko.md | 12 ++++++++++++ docs/keybindings/Keybindings_nl.md | 12 ++++++++++++ docs/keybindings/Keybindings_pl.md | 12 ++++++++++++ docs/keybindings/Keybindings_pt.md | 12 ++++++++++++ docs/keybindings/Keybindings_ru.md | 12 ++++++++++++ docs/keybindings/Keybindings_zh-CN.md | 12 ++++++++++++ docs/keybindings/Keybindings_zh-TW.md | 12 ++++++++++++ schema/config.json | 4 ++++ 11 files changed, 113 insertions(+) diff --git a/docs/Config.md b/docs/Config.md index 26af074ad..8fd1fd960 100644 --- a/docs/Config.md +++ b/docs/Config.md @@ -587,6 +587,7 @@ keybinding: rebaseBranch: r renameBranch: R mergeIntoCurrentBranch: M + moveCommitsToNewBranch: "N" viewGitFlowOptions: i fastForward: f createTag: T diff --git a/docs/keybindings/Keybindings_en.md b/docs/keybindings/Keybindings_en.md index 396459478..f6c622b07 100644 --- a/docs/keybindings/Keybindings_en.md +++ b/docs/keybindings/Keybindings_en.md @@ -109,6 +109,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Create new branch off of commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Open external diff tool (git difftool) | | @@ -166,6 +169,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` i `` | Show git-flow options | | | `` `` | Checkout | Checkout selected item. | | `` n `` | New branch | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | Create pull request | | | `` O `` | View create pull request options | | | `` `` | Copy pull request URL to clipboard | | @@ -266,6 +272,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Create new branch off of commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset copied (cherry-picked) commits selection | | @@ -347,6 +356,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Create new branch off of commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Copy (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset copied (cherry-picked) commits selection | | diff --git a/docs/keybindings/Keybindings_ja.md b/docs/keybindings/Keybindings_ja.md index eff44cbb2..199825c9f 100644 --- a/docs/keybindings/Keybindings_ja.md +++ b/docs/keybindings/Keybindings_ja.md @@ -82,6 +82,9 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | ブラウザでコミットを開く | | | `` n `` | コミットにブランチを作成 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset copied (cherry-picked) commits selection | | @@ -133,6 +136,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | ブラウザでコミットを開く | | | `` n `` | コミットにブランチを作成 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Open external diff tool (git difftool) | | @@ -250,6 +256,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` i `` | Show git-flow options | | | `` `` | チェックアウト | Checkout selected item. | | `` n `` | 新しいブランチを作成 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | Pull Requestを作成 | | | `` O `` | View create pull request options | | | `` `` | Pull RequestのURLをクリップボードにコピー | | @@ -380,6 +389,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | コミットの情報をコピー | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | ブラウザでコミットを開く | | | `` n `` | コミットにブランチを作成 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | コミットをコピー (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset copied (cherry-picked) commits selection | | diff --git a/docs/keybindings/Keybindings_ko.md b/docs/keybindings/Keybindings_ko.md index c1561441b..f5c18a964 100644 --- a/docs/keybindings/Keybindings_ko.md +++ b/docs/keybindings/Keybindings_ko.md @@ -60,6 +60,9 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | 브라우저에서 커밋 열기 | | | `` n `` | 커밋에서 새 브랜치를 만듭니다. | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset cherry-picked (copied) commits selection | | @@ -101,6 +104,9 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | 브라우저에서 커밋 열기 | | | `` n `` | 커밋에서 새 브랜치를 만듭니다. | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset cherry-picked (copied) commits selection | | @@ -200,6 +206,9 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` i `` | Git-flow 옵션 보기 | | | `` `` | 체크아웃 | Checkout selected item. | | `` n `` | 새 브랜치 생성 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | 풀 리퀘스트 생성 | | | `` O `` | 풀 리퀘스트 생성 옵션 | | | `` `` | 풀 리퀘스트 URL을 클립보드에 복사 | | @@ -305,6 +314,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | 커밋 attribute 복사 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | 브라우저에서 커밋 열기 | | | `` n `` | 커밋에서 새 브랜치를 만듭니다. | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | View reset options | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | 커밋을 복사 (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Open external diff tool (git difftool) | | diff --git a/docs/keybindings/Keybindings_nl.md b/docs/keybindings/Keybindings_nl.md index 1752329e7..b0b23d254 100644 --- a/docs/keybindings/Keybindings_nl.md +++ b/docs/keybindings/Keybindings_nl.md @@ -99,6 +99,9 @@ _Legend: `` means ctrl+b, `` means alt+b, `B` means shift+b_ | `` i `` | Laat git-flow opties zien | | | `` `` | Uitchecken | Checkout selected item. | | `` n `` | Nieuwe branch | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | Maak een pull-request | | | `` O `` | Bekijk opties voor pull-aanvraag | | | `` `` | Kopieer de URL van het pull-verzoek naar het klembord | | @@ -177,6 +180,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Creëer nieuwe branch van commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Open external diff tool (git difftool) | | @@ -244,6 +250,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Creëer nieuwe branch van commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset cherry-picked (gekopieerde) commits selectie | | @@ -347,6 +356,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Creëer nieuwe branch van commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Bekijk reset opties | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Kopieer commit (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Reset cherry-picked (gekopieerde) commits selectie | | diff --git a/docs/keybindings/Keybindings_pl.md b/docs/keybindings/Keybindings_pl.md index 67a4ba277..88a886a35 100644 --- a/docs/keybindings/Keybindings_pl.md +++ b/docs/keybindings/Keybindings_pl.md @@ -82,6 +82,9 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, | `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). | | `` o `` | Otwórz commit w przeglądarce | | | `` n `` | Utwórz nową gałąź z commita | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. | | `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć ``, aby anulować zaznaczenie. | | `` `` | Otwórz zewnętrzne narzędzie różnic (git difftool) | | @@ -132,6 +135,9 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, | `` i `` | Pokaż opcje git-flow | | | `` `` | Przełącz | Przełącz wybrany element. | | `` n `` | Nowa gałąź | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | Utwórz żądanie ściągnięcia | | | `` O `` | Zobacz opcje tworzenia pull requesta | | | `` `` | Kopiuj adres URL żądania ściągnięcia do schowka | | @@ -284,6 +290,9 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, | `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). | | `` o `` | Otwórz commit w przeglądarce | | | `` n `` | Utwórz nową gałąź z commita | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. | | `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć ``, aby anulować zaznaczenie. | | `` `` | Resetuj wybrane (cherry-picked) commity | | @@ -327,6 +336,9 @@ Jeśli chcesz zamiast tego rozpocząć interaktywny rebase od wybranego commita, | `` y `` | Kopiuj atrybut commita do schowka | Kopiuj atrybut commita do schowka (np. hash, URL, różnice, wiadomość, autor). | | `` o `` | Otwórz commit w przeglądarce | | | `` n `` | Utwórz nową gałąź z commita | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Reset | Wyświetl opcje resetu (miękki/mieszany/twardy) do wybranego elementu. | | `` C `` | Kopiuj (cherry-pick) | Oznacz commit jako skopiowany. Następnie, w widoku lokalnych commitów, możesz nacisnąć `V`, aby wkleić (cherry-pick) skopiowane commity do sprawdzonej gałęzi. W dowolnym momencie możesz nacisnąć ``, aby anulować zaznaczenie. | | `` `` | Resetuj wybrane (cherry-picked) commity | | diff --git a/docs/keybindings/Keybindings_pt.md b/docs/keybindings/Keybindings_pt.md index ccf5524b0..fc9510e86 100644 --- a/docs/keybindings/Keybindings_pt.md +++ b/docs/keybindings/Keybindings_pt.md @@ -94,6 +94,9 @@ Veja a documentação: | `` i `` | Show git-flow options | | | `` `` | Verificar | Checar item selecionado | | `` n `` | Nova branch | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | Create pull request | | | `` O `` | View create pull request options | | | `` `` | Copiar URL do pull request para área de transferência | | @@ -184,6 +187,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Create new branch off of commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Restaurar | Ver opções de redefinição (soft/mixed/hard) para redefinir para o item selecionado. | | `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `` para cancelar a seleção. | | `` `` | Abrir ferramenta de diff externa (git difftool) | | @@ -298,6 +304,9 @@ Veja a documentação: | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Create new branch off of commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Restaurar | Ver opções de redefinição (soft/mixed/hard) para redefinir para o item selecionado. | | `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `` para cancelar a seleção. | | `` `` | Reset copied (cherry-picked) commits selection | | @@ -360,6 +369,9 @@ Veja a documentação: | `` y `` | Copy commit attribute to clipboard | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Open commit in browser | | | `` n `` | Create new branch off of commit | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Restaurar | Ver opções de redefinição (soft/mixed/hard) para redefinir para o item selecionado. | | `` C `` | Copiar (cherry-pick) | Marcar commit como copiado. Então, dentro da visualização local de commits, você pode pressionar `V` para colar (cherry-pick) o(s) commit(s) copiado(s) em seu branch de check-out. A qualquer momento você pode pressionar `` para cancelar a seleção. | | `` `` | Reset copied (cherry-picked) commits selection | | diff --git a/docs/keybindings/Keybindings_ru.md b/docs/keybindings/Keybindings_ru.md index b75fc0d80..35ce45beb 100644 --- a/docs/keybindings/Keybindings_ru.md +++ b/docs/keybindings/Keybindings_ru.md @@ -141,6 +141,9 @@ _Связки клавиш_ | `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Открыть коммит в браузере | | | `` n `` | Создать новую ветку с этого коммита | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | | @@ -182,6 +185,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Открыть коммит в браузере | | | `` n `` | Создать новую ветку с этого коммита | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Open external diff tool (git difftool) | | @@ -199,6 +205,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` i `` | Показать параметры git-flow | | | `` `` | Переключить | Checkout selected item. | | `` n `` | Новая ветка | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | Создать запрос на принятие изменений | | | `` O `` | Создать параметры запроса принятие изменений | | | `` `` | Скопировать URL запроса на принятие изменений в буфер обмена | | @@ -243,6 +252,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | Скопировать атрибут коммита | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | Открыть коммит в браузере | | | `` n `` | Создать новую ветку с этого коммита | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | Просмотреть параметры сброса | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | Скопировать отобранные коммит (cherry-pick) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | Сбросить отобранную (скопированную | cherry-picked) выборку коммитов | | diff --git a/docs/keybindings/Keybindings_zh-CN.md b/docs/keybindings/Keybindings_zh-CN.md index 4cdda3dd0..eb09f4ca0 100644 --- a/docs/keybindings/Keybindings_zh-CN.md +++ b/docs/keybindings/Keybindings_zh-CN.md @@ -60,6 +60,9 @@ _图例:`` 意味着ctrl+b, `意味着Alt+b, `B` 意味着shift+b_ | `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 | | `` o `` | 在浏览器中打开提交 | | | `` n `` | 从提交创建新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 | | `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `` 来取消选择。 | | `` `` | 重置已拣选(复制)的提交 | | @@ -79,6 +82,9 @@ _图例:`` 意味着ctrl+b, `意味着Alt+b, `B` 意味着shift+b_ | `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 | | `` o `` | 在浏览器中打开提交 | | | `` n `` | 从提交创建新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 | | `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `` 来取消选择。 | | `` `` | 重置已拣选(复制)的提交 | | @@ -144,6 +150,9 @@ _图例:`` 意味着ctrl+b, `意味着Alt+b, `B` 意味着shift+b_ | `` y `` | 复制提交属性到剪贴板 | 复制提交属性到剪贴板(例如,hash、URL、diff、消息、作者)。 | | `` o `` | 在浏览器中打开提交 | | | `` n `` | 从提交创建新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | 查看重置选项 | 查看重置选项 (soft/mixed/hard) 用于重置到选择项 | | `` C `` | 复制提交(拣选) | 标记提交为已复制。然后,在本地提交视图中,你可以按 `V` (Cherry-Pick) 将已复制的提交粘贴到已检出的分支中。任何时候都可以按 `` 来取消选择。 | | `` `` | 使用外部差异比较工具(git difftool) | | @@ -221,6 +230,9 @@ _图例:`` 意味着ctrl+b, `意味着Alt+b, `B` 意味着shift+b_ | `` i `` | 显示 git-flow 选项 | | | `` `` | 检出 | 检出选中的项目 | | `` n `` | 新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | 创建拉取请求 | | | `` O `` | 创建拉取请求选项 | | | `` `` | 将拉取请求 URL 复制到剪贴板 | | diff --git a/docs/keybindings/Keybindings_zh-TW.md b/docs/keybindings/Keybindings_zh-TW.md index 8312ca98b..5715b0230 100644 --- a/docs/keybindings/Keybindings_zh-TW.md +++ b/docs/keybindings/Keybindings_zh-TW.md @@ -131,6 +131,9 @@ _說明:`` 表示 Ctrl+B、`` 表示 Alt+B,`B`表示 Shift+B | `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | 在瀏覽器中開啟提交 | | | `` n `` | 從提交建立新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | 重設選定的揀選 (複製) 提交 | | @@ -196,6 +199,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | 在瀏覽器中開啟提交 | | | `` n `` | 從提交建立新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | 開啟外部差異工具 (git difftool) | | @@ -255,6 +261,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` y `` | 複製提交屬性 | Copy commit attribute to clipboard (e.g. hash, URL, diff, message, author). | | `` o `` | 在瀏覽器中開啟提交 | | | `` n `` | 從提交建立新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` g `` | 檢視重設選項 | View reset options (soft/mixed/hard) for resetting onto selected item. | | `` C `` | 複製提交 (揀選) | Mark commit as copied. Then, within the local commits view, you can press `V` to paste (cherry-pick) the copied commit(s) into your checked out branch. At any time you can press `` to cancel the selection. | | `` `` | 重設選定的揀選 (複製) 提交 | | @@ -273,6 +282,9 @@ If you would instead like to start an interactive rebase from the selected commi | `` i `` | 顯示 git-flow 選項 | | | `` `` | 檢出 | 檢出選定的項目。 | | `` n `` | 新分支 | | +| `` N `` | Move commits to new branch | Create a new branch and move the unpushed commits of the current branch to it. Useful if you meant to start new work and forgot to create a new branch first. + +Note that this disregards the selection, the new branch is always created either from the main branch or stacked on top of the current branch (you get to choose which). | | `` o `` | 建立拉取請求 | | | `` O `` | 建立拉取請求選項 | | | `` `` | 複製拉取請求的 URL 到剪貼板 | | diff --git a/schema/config.json b/schema/config.json index 43fe0f2fc..96a968e4d 100644 --- a/schema/config.json +++ b/schema/config.json @@ -799,6 +799,10 @@ "type": "string", "default": "M" }, + "moveCommitsToNewBranch": { + "type": "string", + "default": "N" + }, "viewGitFlowOptions": { "type": "string", "default": "i"