Skip to content

Commit

Permalink
feat: add rename branch
Browse files Browse the repository at this point in the history
  • Loading branch information
João Pedro Magalhães committed Mar 24, 2022
1 parent d85e501 commit 8868b37
Show file tree
Hide file tree
Showing 10 changed files with 254 additions and 94 deletions.
3 changes: 2 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -29,4 +29,5 @@ gh b
| <kbd>Ctrl+d</kbd> | Delete the currently selected branch, with confirmation |
| <kbd>Ctrl+t</kbd> | Track the currently selected branch, with confirmation |
| <kbd>Ctrl+y</kbd> | Merge the currently selected branch, with confirmation |
| <kbd>Ctrl+r</kbd> | Rebase the currently selected branch, with confirmation |
| <kbd>Ctrl+u</kbd> | Rebase the currently selected branch, with confirmation |
| <kbd>Ctrl+r</kbd> | Rename the currently selected branch |
73 changes: 71 additions & 2 deletions git/git.go
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,55 @@ type Branch struct {
Name string
AuthorName string
CommitterDate string
IsRemote bool
}

const format = `branch:%(refname:short)%(HEAD)
authorname:%(authorname)
committerdate:%(committerdate:relative)
`

func GetAllBranches() (branches []Branch, err error) {
func getLocalBranches(branches []Branch) ([]Branch, error) {
cmd := exec.Command(
"git",
"for-each-ref",
"refs/heads",
"--sort",
"-committerdate",
"--sort",
"-upstream",
"--format",
format,
)

out, err := cmd.CombinedOutput()
if err != nil {
return []Branch{}, err
}

s := strings.Split(strings.TrimSpace(string(out)), "\n\n")

for _, branch := range s {
fields := strings.Split(branch, "\n")

branch := strings.TrimPrefix(fields[0], "branch:")
authorname := strings.TrimPrefix(fields[1], "authorname:")
committerdate := strings.TrimPrefix(fields[2], "committerdate:")
branches = append(branches, Branch{
Name: strings.TrimSpace(branch),
AuthorName: strings.TrimSpace(authorname),
CommitterDate: strings.TrimSpace(committerdate),
IsRemote: false,
})
}

return branches, err
}

func getRemoteBranches(branches []Branch) ([]Branch, error) {
cmd := exec.Command(
"git",
"for-each-ref",
"refs/remotes",
"--sort",
"-committerdate",
Expand All @@ -32,7 +69,7 @@ func GetAllBranches() (branches []Branch, err error) {

out, err := cmd.CombinedOutput()
if err != nil {
return
return []Branch{}, err
}

s := strings.Split(strings.TrimSpace(string(out)), "\n\n")
Expand All @@ -47,9 +84,24 @@ func GetAllBranches() (branches []Branch, err error) {
Name: strings.TrimSpace(branch),
AuthorName: strings.TrimSpace(authorname),
CommitterDate: strings.TrimSpace(committerdate),
IsRemote: true,
})
}

return branches, err
}

func GetAllBranches() (branches []Branch, err error) {
branches, err = getLocalBranches(branches)
if err != nil {
return
}

branches, err = getRemoteBranches(branches)
if err != nil {
return
}

return
}

Expand Down Expand Up @@ -100,3 +152,20 @@ func RebaseBranch(branch string) string {

return string(out)
}

func RenameBranch(oldName, newName string) string {
cmd := exec.Command("git", "branch", "-m", oldName, newName)

out, _ := cmd.CombinedOutput()

return string(out)
}

func RenameRemoteBranch(oldName, newName string) string {
exec.Command("git", "push", "origin", "--delete", oldName)

cmd := exec.Command("git", "push", "origin", "-u", newName)
out, _ := cmd.CombinedOutput()

return string(out)
}
1 change: 1 addition & 0 deletions tui/create.go
Original file line number Diff line number Diff line change
Expand Up @@ -90,6 +90,7 @@ func createUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
m.create.inputs[1].Reset()
m.create.showConfirmInput = false
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()

return m, nil
Expand Down
2 changes: 1 addition & 1 deletion tui/delegate.go
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,6 @@ func (d itemDelegate) ShortHelp() []key.Binding {

func (d itemDelegate) FullHelp() [][]key.Binding {
return [][]key.Binding{
{d.keys.Track, d.keys.Create, d.keys.Delete, d.keys.Merge, d.keys.Rebase},
{d.keys.Track, d.keys.Create, d.keys.Delete, d.keys.Merge, d.keys.Rebase, d.keys.Rename},
}
}
3 changes: 3 additions & 0 deletions tui/delete.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,12 +45,14 @@ func deleteUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {

m.updateListItem()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()
}

case "n", "N":
m.delete.confirmInput.Reset()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()

default:
Expand All @@ -60,6 +62,7 @@ func deleteUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
case key.Matches(msg, m.keyMap.Cancel):
m.delete.confirmInput.Reset()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()
}
case tea.WindowSizeMsg:
Expand Down
14 changes: 8 additions & 6 deletions tui/keys/keys.go
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,7 @@ type KeyMap struct {
Track key.Binding
Merge key.Binding
Rebase key.Binding
Rename key.Binding
Cancel key.Binding
Quit key.Binding
ForceQuit key.Binding
Expand All @@ -23,10 +24,7 @@ type KeyMap struct {
func (k KeyMap) ShortHelp() []key.Binding {
var kb []key.Binding

if k.State == "creating" ||
k.State == "deleting" ||
k.State == "merge" ||
k.State == "rebasing" {
if k.State != "browsing" {
kb = append(kb, k.Cancel, k.ForceQuit)
}

Expand Down Expand Up @@ -77,12 +75,16 @@ func NewKeyMap() *KeyMap {
),
),
Rebase: key.NewBinding(
key.WithKeys("ctrl+r"),
key.WithKeys("ctrl+u"),
key.WithHelp(
"ctrl+r",
"ctrl+u",
"Rebase the currently selected branch, with confirmation",
),
),
Rename: key.NewBinding(
key.WithKeys("ctrl+r"),
key.WithHelp("ctrl+r", "Rename the currently selected branch"),
),
Cancel: key.NewBinding(
key.WithKeys("esc"),
key.WithHelp("esc", "Cancel"),
Expand Down
2 changes: 2 additions & 0 deletions tui/merge.go
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,7 @@ func mergeUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
case "n", "N":
m.merge.confirmInput.Reset()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()

default:
Expand All @@ -55,6 +56,7 @@ func mergeUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
case key.Matches(msg, m.keyMap.Cancel):
m.merge.confirmInput.Reset()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()
}

Expand Down
2 changes: 2 additions & 0 deletions tui/rebase.go
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,7 @@ func rebaseUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
case "n", "N":
m.rebase.confirmInput.Reset()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()

default:
Expand All @@ -53,6 +54,7 @@ func rebaseUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
case key.Matches(msg, m.keyMap.Cancel):
m.rebase.confirmInput.Reset()
m.state = browsing
m.keyMap.State = "browsing"
m.updateKeybindins()
}
case tea.WindowSizeMsg:
Expand Down
59 changes: 53 additions & 6 deletions tui/rename.go
Original file line number Diff line number Diff line change
@@ -1,21 +1,33 @@
package tui

import (
"strings"

"github.com/charmbracelet/bubbles/help"
"github.com/charmbracelet/bubbles/key"
"github.com/charmbracelet/bubbles/textinput"
tea "github.com/charmbracelet/bubbletea"
"github.com/charmbracelet/lipgloss"
"github.com/joaom00/gh-b/git"
)

type renameModel struct {
input textinput.Model
input textinput.Model
confirmInput textinput.Model
showConfirmInput bool
help help.Model
}

func newRenameModel() *renameModel {
ti := textinput.New()
ci := textinput.New()
ci.CharLimit = 1

return &renameModel{
input: ti,
input: ti,
confirmInput: ci,
showConfirmInput: false,
help: help.New(),
}
}

Expand All @@ -24,16 +36,51 @@ func renameUpdate(msg tea.Msg, m Model) (tea.Model, tea.Cmd) {
case tea.KeyMsg:
switch {
case key.Matches(msg, m.keyMap.Enter):
return m, nil
if i, ok := m.selectedItem(); ok {
out := git.RenameBranch(i.Name, m.rename.input.Value())

m.state = browsing
m.updateListItem()
m.list.NewStatusMessage(out)

return m, nil
}

case key.Matches(msg, m.keyMap.Cancel):
m.rename.input.Reset()
m.state = browsing
m.updateKeybindins()
}
}

return m, nil
var cmd tea.Cmd
var cmds []tea.Cmd

m.rename.input, cmd = m.rename.input.Update(msg)
cmds = append(cmds, cmd)

m.rename.confirmInput, cmd = m.rename.confirmInput.Update(msg)
cmds = append(cmds, cmd)

return m, tea.Batch(cmds...)
}

func (m Model) renameView() string {
m.rename.input.Placeholder = strings.TrimSuffix(m.list.SelectedItem().(item).Name, "*")

title := m.styles.Title.MarginLeft(2).Render("Rename your branch")
textInput := lipgloss.NewStyle().MarginLeft(4).Render(m.rename.input.View())
help := lipgloss.NewStyle().MarginLeft(4).Render(m.create.help.View(m.keyMap))

if m.rename.showConfirmInput {
confirmInput := lipgloss.NewStyle().
MarginLeft(4).
Render(lipgloss.JoinHorizontal(lipgloss.Left, "You would like rename remote branch? [y/N]", m.rename.confirmInput.View()))

return lipgloss.NewStyle().MarginTop(1).Render(lipgloss.JoinVertical(lipgloss.Left, title, "\n", textInput, "\n", confirmInput, "\n", help))
}

return lipgloss.NewStyle().
MarginTop(1).
MarginLeft(4).
Render(lipgloss.JoinVertical(lipgloss.Left, m.rename.input.View()))
Render(lipgloss.JoinVertical(lipgloss.Left, title, "\n", textInput, "\n", help))
}
Loading

0 comments on commit 8868b37

Please sign in to comment.