mirror of
https://github.com/jesseduffield/lazygit.git
synced 2026-09-10 07:36:27 -04:00
add restore upstream branch menu item
Restore an upstream branch that was deleted on the remote by pushing the local branch back to its configured upstream, removing the '(upstream gone)' state.
This commit is contained in:
parent
a133dc0dad
commit
e3cab9777c
|
|
@ -332,6 +332,14 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
Keys: menuKey('s'),
|
||||
}
|
||||
|
||||
restoreUpstreamItem := &types.MenuItem{
|
||||
LabelColumns: []string{self.c.Tr.RestoreUpstreamBranch},
|
||||
OnPress: func() error {
|
||||
return self.pushBranchToUpstream(selectedBranch)
|
||||
},
|
||||
Keys: menuKey('p'),
|
||||
}
|
||||
|
||||
upstreamResetOptions := utils.ResolvePlaceholderString(
|
||||
self.c.Tr.ViewUpstreamResetOptions,
|
||||
map[string]string{"upstream": upstream},
|
||||
|
|
@ -388,11 +396,22 @@ func (self *BranchesController) viewUpstreamOptions(selectedBranch *models.Branc
|
|||
upstreamRebaseItem.DisabledReason = &types.DisabledReason{Text: self.c.Tr.UpstreamNotSetError}
|
||||
}
|
||||
|
||||
// We can only restore an upstream that still has a tracking configuration
|
||||
// but whose remote branch has been deleted (i.e. it shows "upstream gone").
|
||||
if !selectedBranch.UpstreamGone {
|
||||
disabledReason := self.c.Tr.UpstreamNotSetError
|
||||
if selectedBranch.IsTrackingRemote() {
|
||||
disabledReason = self.c.Tr.UpstreamNotGoneError
|
||||
}
|
||||
restoreUpstreamItem.DisabledReason = &types.DisabledReason{Text: disabledReason}
|
||||
}
|
||||
|
||||
options := []*types.MenuItem{
|
||||
viewDivergenceItem,
|
||||
viewDivergenceFromBaseBranchItem,
|
||||
unsetUpstreamItem,
|
||||
setUpstreamItem,
|
||||
restoreUpstreamItem,
|
||||
upstreamResetItem,
|
||||
upstreamRebaseItem,
|
||||
}
|
||||
|
|
@ -754,6 +773,27 @@ func (self *BranchesController) fastForward(branch *models.Branch) error {
|
|||
})
|
||||
}
|
||||
|
||||
// pushBranchToUpstream pushes the given branch to its configured upstream,
|
||||
// recreating a remote branch that was deleted (e.g. on GitHub) so the branch
|
||||
// no longer shows as "upstream gone".
|
||||
func (self *BranchesController) pushBranchToUpstream(branch *models.Branch) error {
|
||||
return self.c.WithInlineStatus(branch, types.ItemOperationPushing, context.LOCAL_BRANCHES_CONTEXT_KEY, func(task gocui.Task) error {
|
||||
self.c.LogAction(self.c.Tr.Actions.RestoreUpstreamBranch)
|
||||
err := self.c.Git().Sync.Push(
|
||||
task,
|
||||
git_commands.PushOpts{
|
||||
CurrentBranch: branch.Name,
|
||||
UpstreamRemote: branch.UpstreamRemote,
|
||||
UpstreamBranch: branch.UpstreamBranch,
|
||||
})
|
||||
if err != nil {
|
||||
return err
|
||||
}
|
||||
self.c.RefreshFromWorker(types.RefreshOptions{Scope: []types.RefreshableView{types.BRANCHES, types.COMMITS}})
|
||||
return nil
|
||||
})
|
||||
}
|
||||
|
||||
func (self *BranchesController) createTag(branch *models.Branch) error {
|
||||
return self.c.Helpers().Tags.OpenCreateTagPrompt(branch.FullRefName(), func() {})
|
||||
}
|
||||
|
|
|
|||
|
|
@ -575,6 +575,7 @@ type TranslationSet struct {
|
|||
SetAsUpstreamTooltip string
|
||||
SetUpstream string
|
||||
UnsetUpstream string
|
||||
RestoreUpstreamBranch string
|
||||
ViewDivergenceFromUpstream string
|
||||
ViewDivergenceFromBaseBranch string
|
||||
CouldNotDetermineBaseBranch string
|
||||
|
|
@ -646,6 +647,7 @@ type TranslationSet struct {
|
|||
ViewBranchUpstreamOptions string
|
||||
ViewBranchUpstreamOptionsTooltip string
|
||||
UpstreamNotSetError string
|
||||
UpstreamNotGoneError string
|
||||
UpstreamsNotSetError string
|
||||
NewGitFlowBranchPrompt string
|
||||
RenameBranchWarning string
|
||||
|
|
@ -1024,6 +1026,7 @@ type Actions struct {
|
|||
RenameBranch string
|
||||
CreateBranch string
|
||||
FastForwardBranch string
|
||||
RestoreUpstreamBranch string
|
||||
AutoForwardBranches string
|
||||
CherryPick string
|
||||
CheckoutFile string
|
||||
|
|
@ -1740,6 +1743,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
SetAsUpstreamTooltip: "Set the selected remote branch as the upstream of the checked-out branch.",
|
||||
SetUpstream: "Set upstream of selected branch",
|
||||
UnsetUpstream: "Unset upstream of selected branch",
|
||||
RestoreUpstreamBranch: "Restore upstream branch",
|
||||
ViewDivergenceFromUpstream: "View divergence from upstream",
|
||||
ViewDivergenceFromBaseBranch: "View divergence from base branch ({{.baseBranch}})",
|
||||
CouldNotDetermineBaseBranch: "Couldn't determine base branch",
|
||||
|
|
@ -1807,6 +1811,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
ViewBranchUpstreamOptions: "View upstream options",
|
||||
ViewBranchUpstreamOptionsTooltip: "View options relating to the branch's upstream e.g. setting/unsetting the upstream and resetting to the upstream.",
|
||||
UpstreamNotSetError: "The selected branch has no upstream (or the upstream is not stored locally)",
|
||||
UpstreamNotGoneError: "The selected branch's upstream still exists",
|
||||
UpstreamsNotSetError: "Some of the selected branches have no upstream (or the upstream is not stored locally)",
|
||||
Upstream: "Upstream",
|
||||
NewBranchNamePrompt: "Enter new branch name for branch",
|
||||
|
|
@ -2241,6 +2246,7 @@ func EnglishTranslationSet() *TranslationSet {
|
|||
MixedReset: "Mixed reset",
|
||||
HardReset: "Hard reset",
|
||||
FastForwardBranch: "Fast forward branch",
|
||||
RestoreUpstreamBranch: "Restore upstream branch",
|
||||
AutoForwardBranches: "Auto-forward branches",
|
||||
Undo: "Undo",
|
||||
Redo: "Redo",
|
||||
|
|
|
|||
|
|
@ -27,6 +27,14 @@ func (self *Git) RemoteTagDeleted(ref string, tagName string) *Git {
|
|||
})
|
||||
}
|
||||
|
||||
// AssertRemoteBranchExists asserts that the given branch still exists on the
|
||||
// given remote, i.e. it has been pushed.
|
||||
func (self *Git) AssertRemoteBranchExists(ref string, branchName string) *Git {
|
||||
return self.expect([]string{"git", "ls-remote", ref, fmt.Sprintf("refs/heads/%s", branchName)}, func(s string) (bool, string) {
|
||||
return len(s) > 0, fmt.Sprintf("Expected branch %s to still exist on %s", branchName, ref)
|
||||
})
|
||||
}
|
||||
|
||||
func (self *Git) assert(cmdArgs []string, expected string) *Git {
|
||||
self.expect(cmdArgs, func(output string) (bool, string) {
|
||||
return output == expected, fmt.Sprintf("Expected current branch name to be '%s', but got '%s'", expected, output)
|
||||
|
|
|
|||
52
pkg/integration/tests/branch/restore_upstream_branch.go
Normal file
52
pkg/integration/tests/branch/restore_upstream_branch.go
Normal file
|
|
@ -0,0 +1,52 @@
|
|||
package branch
|
||||
|
||||
import (
|
||||
"github.com/jesseduffield/lazygit/pkg/config"
|
||||
. "github.com/jesseduffield/lazygit/pkg/integration/components"
|
||||
)
|
||||
|
||||
var RestoreUpstreamBranch = NewIntegrationTest(NewIntegrationTestArgs{
|
||||
Description: "Restore an upstream branch that was deleted on the remote",
|
||||
ExtraCmdArgs: []string{},
|
||||
Skip: false,
|
||||
SetupConfig: func(config *config.AppConfig) {},
|
||||
SetupRepo: func(shell *Shell) {
|
||||
shell.
|
||||
CloneIntoRemote("origin").
|
||||
EmptyCommit("base commit").
|
||||
NewBranch("feature").
|
||||
EmptyCommit("on feature").
|
||||
PushBranchAndSetUpstream("origin", "feature").
|
||||
Checkout("master").
|
||||
RunCommand([]string{"git", "-C", "../origin", "branch", "-D", "feature"}).
|
||||
RunCommand([]string{"git", "fetch", "origin", "--prune"})
|
||||
},
|
||||
Run: func(t *TestDriver, keys config.KeybindingConfig) {
|
||||
t.Views().Branches().
|
||||
Focus().
|
||||
Lines(
|
||||
Contains("master").IsSelected(),
|
||||
Contains("feature").Contains("upstream gone"),
|
||||
)
|
||||
|
||||
t.Views().Branches().
|
||||
NavigateToLine(Contains("feature")).
|
||||
Press(keys.Branches.SetUpstream).
|
||||
Tap(func() {
|
||||
t.ExpectPopup().
|
||||
Menu().
|
||||
Title(Equals("Upstream options")).
|
||||
Select(Contains("Restore upstream branch")).
|
||||
Confirm()
|
||||
})
|
||||
|
||||
// the "upstream gone" message is gone and the remote branch is recreated
|
||||
t.Views().Branches().
|
||||
Lines(
|
||||
Contains("master"),
|
||||
Contains("feature").DoesNotContain("upstream gone"),
|
||||
)
|
||||
|
||||
t.Git().AssertRemoteBranchExists("origin", "feature")
|
||||
},
|
||||
})
|
||||
|
|
@ -81,6 +81,7 @@ var tests = []*components.IntegrationTest{
|
|||
branch.ResetToDuplicateNamedUpstream,
|
||||
branch.ResetToUpstream,
|
||||
branch.RestoreDeletedBranch,
|
||||
branch.RestoreUpstreamBranch,
|
||||
branch.SelectCommitsOfCurrentBranch,
|
||||
branch.SetUpstream,
|
||||
branch.ShowDivergenceFromBaseBranch,
|
||||
|
|
|
|||
Loading…
Reference in a new issue