summaryrefslogtreecommitdiffstats
path: root/pkg/commands/git_commands/sync.go
blob: 4ab1f336bf09f7234b829b19bafc9ff59f0c2139 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
package git_commands

import (
	"github.com/go-errors/errors"
	"github.com/jesseduffield/gocui"
	"github.com/jesseduffield/lazygit/pkg/commands/oscommands"
)

type SyncCommands struct {
	*GitCommon
}

func NewSyncCommands(gitCommon *GitCommon) *SyncCommands {
	return &SyncCommands{
		GitCommon: gitCommon,
	}
}

// Push pushes to a branch
type PushOpts struct {
	Force          bool
	UpstreamRemote string
	UpstreamBranch string
	SetUpstream    bool
}

func (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (oscommands.ICmdObj, error) {
	if opts.UpstreamBranch != "" && opts.UpstreamRemote == "" {
		return nil, errors.New(self.Tr.MustSpecifyOriginError)
	}

	cmdArgs := NewGitCmd("push").
		ArgIf(opts.Force, "--force-with-lease").
		ArgIf(opts.SetUpstream, "--set-upstream").
		ArgIf(opts.UpstreamRemote != "", opts.UpstreamRemote).
		ArgIf(opts.UpstreamBranch != "", opts.UpstreamBranch).
		ToArgv()

	cmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)
	return cmdObj, nil
}

func (self *SyncCommands) Push(task gocui.Task, opts PushOpts) error {
	cmdObj, err := self.PushCmdObj(task, opts)
	if err != nil {
		return err
	}

	return cmdObj.Run()
}

func (self *SyncCommands) fetchCommandBuilder(fetchAll bool) *GitCommandBuilder {
	return NewGitCmd("fetch").
		ArgIf(fetchAll, "--all").
		// avoid writing to .git/FETCH_HEAD; this allows running a pull
		// concurrently without getting errors
		ArgIf(self.version.IsAtLeast(2, 29, 0), "--no-write-fetch-head")
}

func (self *SyncCommands) FetchCmdObj(task gocui.Task) oscommands.ICmdObj {
	cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv()

	cmdObj := self.cmd.New(cmdArgs)
	cmdObj.PromptOnCredentialRequest(task)
	return cmdObj
}

func (self *SyncCommands) Fetch(task gocui.Task) error {
	return self.FetchCmdObj(task).Run()
}

func (self *SyncCommands) FetchBackgroundCmdObj() oscommands.ICmdObj {
	cmdArgs := self.fetchCommandBuilder(self.UserConfig.Git.FetchAll).ToArgv()

	cmdObj := self.cmd.New(cmdArgs)
	cmdObj.DontLog().FailOnCredentialRequest()
	return cmdObj
}

func (self *SyncCommands) FetchBackground() error {
	return self.FetchBackgroundCmdObj().Run()
}

type PullOptions struct {
	RemoteName      string
	BranchName      string
	FastForwardOnly bool
	WorktreeGitDir  string
}

func (self *SyncCommands) Pull(task gocui.Task, opts PullOptions) error {
	cmdArgs := NewGitCmd("pull").
		Arg("--no-edit").
		ArgIf(opts.FastForwardOnly, "--ff-only").
		ArgIf(opts.RemoteName != "", opts.RemoteName).
		ArgIf(opts.BranchName != "", opts.BranchName).
		GitDirIf(opts.WorktreeGitDir != "", opts.WorktreeGitDir).
		ToArgv()

	// setting GIT_SEQUENCE_EDITOR to ':' as a way of skipping it, in case the user
	// has 'pull.rebase = interactive' configured.
	return self.cmd.New(cmdArgs).AddEnvVars("GIT_SEQUENCE_EDITOR=:").PromptOnCredentialRequest(task).Run()
}

func (self *SyncCommands) FastForward(
	task gocui.Task,
	branchName string,
	remoteName string,
	remoteBranchName string,
) error {
	cmdArgs := self.fetchCommandBuilder(false).
		Arg(remoteName).
		Arg(remoteBranchName + ":" + branchName).
		ToArgv()

	return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}

func (self *SyncCommands) FetchRemote(task gocui.Task, remoteName string) error {
	cmdArgs := self.fetchCommandBuilder(false).
		Arg(remoteName).
		ToArgv()

	return self.cmd.New(cmdArgs).PromptOnCredentialRequest(task).Run()
}