{"record":{"id":"1e57f109deb640af","repo":"jesseduffield/lazygit","slug":"must-specify-a-remote-if-specifying-a-branch","errorCode":null,"errorMessage":"Must specify a remote if specifying a branch","messagePattern":"Must specify a remote if specifying a branch","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"error","filePath":"pkg/commands/git_commands/sync.go","lineNumber":33,"sourceCode":"func NewSyncCommands(gitCommon *GitCommon) *SyncCommands {\n\treturn &SyncCommands{\n\t\tGitCommon: gitCommon,\n\t}\n}\n\n// Push pushes to a branch\ntype PushOpts struct {\n\tForce          bool\n\tForceWithLease bool\n\tCurrentBranch  string\n\tUpstreamRemote string\n\tUpstreamBranch string\n\tSetUpstream    bool\n}\n\nfunc (self *SyncCommands) PushCmdObj(task gocui.Task, opts PushOpts) (*oscommands.CmdObj, error) {\n\tif opts.UpstreamBranch != \"\" && opts.UpstreamRemote == \"\" {\n\t\treturn nil, errors.New(self.Tr.MustSpecifyOriginError)\n\t}\n\n\tcmdArgs := NewGitCmd(\"push\").\n\t\tArgIf(opts.Force, \"--force\").\n\t\tArgIf(opts.ForceWithLease, \"--force-with-lease\").\n\t\tArgIf(opts.SetUpstream, \"--set-upstream\").\n\t\tArgIf(opts.UpstreamRemote != \"\", opts.UpstreamRemote).\n\t\tArgIf(opts.UpstreamBranch != \"\", fmt.Sprintf(\"refs/heads/%s:%s\", opts.CurrentBranch, opts.UpstreamBranch)).\n\t\tToArgv()\n\n\tcmdObj := self.cmd.New(cmdArgs).PromptOnCredentialRequest(task)\n\treturn cmdObj, nil\n}\n\nfunc (self *SyncCommands) Push(task gocui.Task, opts PushOpts) error {\n\tcmdObj, err := self.PushCmdObj(task, opts)\n\tif err != nil {\n\t\treturn err","sourceCodeStart":15,"sourceCodeEnd":51,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/commands/git_commands/sync.go#L15-L51","documentation":"SyncCommands.PushCmdObj builds a `git push` command and rejects the combination where UpstreamBranch is set but UpstreamRemote is empty: `git push refs/heads/x:y` without a remote is not a valid push. The message (MustSpecifyOriginError) is lazygit's way of saying the push target is underspecified.","triggerScenarios":"Calling Push with opts.UpstreamBranch set and opts.UpstreamRemote left \"\"; UI flows that set a branch override without a remote; programmatic callers assembling PushOpts partially.","commonSituations":"Setting the upstream branch field in the push options prompt without filling the remote; new remotes added after the push dialog was populated.","solutions":["Set both UpstreamRemote and UpstreamBranch (e.g. \"origin\" and \"main\")","Or leave both empty to push to the branch's configured upstream","If the branch has no upstream yet, use SetUpstream with a remote specified, or configure it: `git push -u origin <branch>` once in a terminal"],"exampleFix":"// before\nopts := PushOpts{CurrentBranch: \"main\", UpstreamBranch: \"main\"} // no remote -> error\n\n// after\nopts := PushOpts{CurrentBranch: \"main\", UpstreamRemote: \"origin\", UpstreamBranch: \"main\", SetUpstream: true}","handlingStrategy":"validation","validationCode":"if opts.UpstreamBranch != \"\" && opts.UpstreamRemote == \"\" {\n    return nil, fmt.Errorf(\"UpstreamRemote required when UpstreamBranch is set (got branch %q)\", opts.UpstreamBranch)\n}\ncmdObj, err := syncCmd.PushCmdObj(task, opts)","typeGuard":null,"tryCatchPattern":"Validate PushOpts before calling PushCmdObj; on MustSpecifyOriginError, either fill UpstreamRemote from the branch's tracking config (`git rev-parse --abbrev-ref @{upstream}`) or drop both upstream fields and push to the tracked upstream.","preventionTips":["Always set remote and branch together in push option structs","Set tracking once with `git push -u origin <branch>` so later pushes need neither field","Default UpstreamRemote to \"origin\" in UI glue code"],"tags":["git","push","upstream","validation"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}