mirror of
				https://github.com/jesseduffield/lazygit.git
				synced 2025-10-30 23:57:43 +02:00 
			
		
		
		
	Add new command "Move commits to new branch"
This commit is contained in:
		| @@ -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 { | ||||
|   | ||||
| @@ -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", | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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), | ||||
|   | ||||
| @@ -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), | ||||
|   | ||||
| @@ -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 { | ||||
|   | ||||
| @@ -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)", | ||||
|   | ||||
| @@ -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"), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
| @@ -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"), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
| @@ -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"), | ||||
| 			) | ||||
| 	}, | ||||
| }) | ||||
| @@ -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, | ||||
|   | ||||
		Reference in New Issue
	
	Block a user