1
0
mirror of https://github.com/jesseduffield/lazygit.git synced 2024-12-14 11:23:09 +02:00
lazygit/pkg/commands/branches.go

172 lines
5.8 KiB
Go
Raw Normal View History

2020-09-29 12:03:39 +02:00
package commands
import (
"fmt"
"regexp"
"strings"
"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
"github.com/jesseduffield/lazygit/pkg/utils"
)
// NewBranch create new branch
func (c *GitCommand) NewBranch(name string, base string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj(fmt.Sprintf("git checkout -b %s %s", c.OSCommand.Quote(name), c.OSCommand.Quote(base))))
2020-09-29 12:03:39 +02:00
}
// CurrentBranchName get the current branch name and displayname.
// the first returned string is the name and the second is the displayname
// e.g. name is 123asdf and displayname is '(HEAD detached at 123asdf)'
func (c *GitCommand) CurrentBranchName() (string, string, error) {
2021-12-07 12:59:36 +02:00
branchName, err := c.RunWithOutput(c.NewCmdObj("git symbolic-ref --short HEAD"))
2020-09-29 12:03:39 +02:00
if err == nil && branchName != "HEAD\n" {
trimmedBranchName := strings.TrimSpace(branchName)
return trimmedBranchName, trimmedBranchName, nil
}
2021-12-07 12:59:36 +02:00
output, err := c.RunWithOutput(c.NewCmdObj("git branch --contains"))
2020-09-29 12:03:39 +02:00
if err != nil {
return "", "", err
}
for _, line := range utils.SplitLines(output) {
re := regexp.MustCompile(CurrentBranchNameRegex)
match := re.FindStringSubmatch(line)
if len(match) > 0 {
branchName = match[1]
displayBranchName := match[0][2:]
return branchName, displayBranchName, nil
}
}
return "HEAD", "HEAD", nil
}
// DeleteBranch delete branch
func (c *GitCommand) DeleteBranch(branch string, force bool) error {
command := "git branch -d"
if force {
command = "git branch -D"
}
2021-12-07 12:59:36 +02:00
return c.OSCommand.Run(c.OSCommand.NewCmdObj(fmt.Sprintf("%s %s", command, c.OSCommand.Quote(branch))))
2020-09-29 12:03:39 +02:00
}
// Checkout checks out a branch (or commit), with --force if you set the force arg to true
type CheckoutOptions struct {
Force bool
EnvVars []string
}
func (c *GitCommand) Checkout(branch string, options CheckoutOptions) error {
forceArg := ""
if options.Force {
2021-04-10 09:31:23 +02:00
forceArg = " --force"
2020-09-29 12:03:39 +02:00
}
2021-12-07 12:59:36 +02:00
cmdObj := c.NewCmdObj(fmt.Sprintf("git checkout%s %s", forceArg, c.OSCommand.Quote(branch))).
// prevents git from prompting us for input which would freeze the program
// TODO: see if this is actually needed here
AddEnvVars("GIT_TERMINAL_PROMPT=0").
AddEnvVars(options.EnvVars...)
return c.OSCommand.Run(cmdObj)
2020-09-29 12:03:39 +02:00
}
// GetBranchGraph gets the color-formatted graph of the log for the given branch
// Currently it limits the result to 100 commits, but when we get async stuff
// working we can do lazy loading
func (c *GitCommand) GetBranchGraph(branchName string) (string, error) {
2021-12-07 12:59:36 +02:00
return c.OSCommand.RunWithOutput(c.GetBranchGraphCmdObj(branchName))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) GetUpstreamForBranch(branchName string) (string, error) {
2021-12-07 12:59:36 +02:00
output, err := c.RunWithOutput(c.NewCmdObj(fmt.Sprintf("git rev-parse --abbrev-ref --symbolic-full-name %s@{u}", c.OSCommand.Quote(branchName))))
2020-09-29 12:03:39 +02:00
return strings.TrimSpace(output), err
}
2021-12-07 12:59:36 +02:00
func (c *GitCommand) GetBranchGraphCmdObj(branchName string) oscommands.ICmdObj {
2020-10-03 06:54:55 +02:00
branchLogCmdTemplate := c.Config.GetUserConfig().Git.BranchLogCmd
2020-09-29 12:03:39 +02:00
templateValues := map[string]string{
2021-10-06 16:26:25 +02:00
"branchName": c.OSCommand.Quote(branchName),
2020-09-29 12:03:39 +02:00
}
2021-12-07 12:59:36 +02:00
return c.NewCmdObj(utils.ResolvePlaceholderString(branchLogCmdTemplate, templateValues))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) SetUpstreamBranch(upstream string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj("git branch -u " + c.OSCommand.Quote(upstream)))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) SetBranchUpstream(remoteName string, remoteBranchName string, branchName string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj(fmt.Sprintf("git branch --set-upstream-to=%s/%s %s", c.OSCommand.Quote(remoteName), c.OSCommand.Quote(remoteBranchName), c.OSCommand.Quote(branchName))))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) GetCurrentBranchUpstreamDifferenceCount() (string, string) {
return c.GetCommitDifferences("HEAD", "HEAD@{u}")
}
func (c *GitCommand) GetBranchUpstreamDifferenceCount(branchName string) (string, string) {
return c.GetCommitDifferences(branchName, branchName+"@{u}")
}
// GetCommitDifferences checks how many pushables/pullables there are for the
// current branch
func (c *GitCommand) GetCommitDifferences(from, to string) (string, string) {
command := "git rev-list %s..%s --count"
2021-12-07 12:59:36 +02:00
pushableCount, err := c.RunWithOutput(c.NewCmdObj(fmt.Sprintf(command, to, from)))
2020-09-29 12:03:39 +02:00
if err != nil {
return "?", "?"
}
2021-12-07 12:59:36 +02:00
pullableCount, err := c.RunWithOutput(c.NewCmdObj(fmt.Sprintf(command, from, to)))
2020-09-29 12:03:39 +02:00
if err != nil {
return "?", "?"
}
return strings.TrimSpace(pushableCount), strings.TrimSpace(pullableCount)
}
type MergeOpts struct {
FastForwardOnly bool
}
// Merge merge
func (c *GitCommand) Merge(branchName string, opts MergeOpts) error {
2020-10-03 06:54:55 +02:00
mergeArgs := c.Config.GetUserConfig().Git.Merging.Args
2020-09-29 12:03:39 +02:00
2021-10-06 16:26:25 +02:00
command := fmt.Sprintf("git merge --no-edit %s %s", mergeArgs, c.OSCommand.Quote(branchName))
2020-09-29 12:03:39 +02:00
if opts.FastForwardOnly {
command = fmt.Sprintf("%s --ff-only", command)
}
2021-12-07 12:59:36 +02:00
return c.OSCommand.Run(c.OSCommand.NewCmdObj(command))
2020-09-29 12:03:39 +02:00
}
// AbortMerge abort merge
func (c *GitCommand) AbortMerge() error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj("git merge --abort"))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) IsHeadDetached() bool {
2021-12-07 12:59:36 +02:00
err := c.Run(c.NewCmdObj("git symbolic-ref -q HEAD"))
2020-09-29 12:03:39 +02:00
return err != nil
}
// ResetHardHead runs `git reset --hard`
func (c *GitCommand) ResetHard(ref string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj("git reset --hard " + c.OSCommand.Quote(ref)))
2020-09-29 12:03:39 +02:00
}
// ResetSoft runs `git reset --soft HEAD`
func (c *GitCommand) ResetSoft(ref string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj("git reset --soft " + c.OSCommand.Quote(ref)))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) ResetMixed(ref string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj("git reset --mixed " + c.OSCommand.Quote(ref)))
}
2020-09-29 12:03:39 +02:00
func (c *GitCommand) RenameBranch(oldName string, newName string) error {
2021-12-07 12:59:36 +02:00
return c.Run(c.NewCmdObj(fmt.Sprintf("git branch --move %s %s", c.OSCommand.Quote(oldName), c.OSCommand.Quote(newName))))
2020-09-29 12:03:39 +02:00
}
func (c *GitCommand) GetRawBranches() (string, error) {
return c.RunWithOutput(c.NewCmdObj(`git for-each-ref --sort=-committerdate --format="%(HEAD)|%(refname:short)|%(upstream:short)|%(upstream:track)" refs/heads`))
}