MCPcopy Index your code
hub / github.com/rilldata/rill / CommitAndSafePush

Method CommitAndSafePush

cli/pkg/cmdutil/helper.go:592–657  ·  view source on GitHub ↗

CommitAndSafePush commits changes and safely pushes them to the remote repository. It fetches the latest remote changes, checks for conflicts, and handles them based on defaultPushChoice: - "1": Pull remote changes and merge (fails on conflicts) - "2": Overwrite remote changes with local changes usi

(ctx context.Context, root string, config *gitutil.Config, commitMsg string, author *object.Signature, defaultPushChoice string)

Source from the content-addressed store, hash-verified

590//
591// If h.Interactive is true and there are remote commits, the user will be prompted to choose how to proceed.
592func (h *Helper) CommitAndSafePush(ctx context.Context, root string, config *gitutil.Config, commitMsg string, author *object.Signature, defaultPushChoice string) error {
593 // Set remote if not set (go-git complains if we try to fetch without setting remote)
594 err := gitutil.SetRemote(root, config)
595 if err != nil {
596 return fmt.Errorf("failed to set git remote: %w", err)
597 }
598
599 // 1. Fetch latest from remote
600 err = gitutil.GitFetch(ctx, root, config)
601 if err != nil {
602 return fmt.Errorf("failed to fetch from remote: %w", err)
603 }
604
605 // 2. Check status of the subpath
606 status, err := gitutil.RunGitStatus(root, config.Subpath, config.RemoteName(), "")
607 if err != nil {
608 return fmt.Errorf("failed to get git status: %w", err)
609 }
610 if status.Branch != config.DefaultBranch {
611 return fmt.Errorf("current branch %q does not match expected branch %q", status.Branch, config.DefaultBranch)
612 }
613
614 // 3. Warn if there are remote commits
615 choice := defaultPushChoice
616 if status.RemoteCommits != 0 {
617 if h.Interactive {
618 h.PrintfWarn("Warning: There are changes on the remote branch that are not in your local branch.")
619 h.PrintfWarn("It's recommended to pull the latest changes before pushing to avoid overwriting remote changes.\n")
620 h.PrintfWarn("Please choose one of the following options to proceed:\n")
621 h.PrintfWarn("1: Pull remote changes to your local branch and fail on conflicts\n")
622 h.PrintfWarn("2: Overwrite remote changes with your local changes(Not supported for monorepos)\n")
623 h.PrintfWarn("3: Abort deploy and merge manually\n")
624 choice, err = SelectPrompt("Choose how to resolve remote changes", []string{"1", "2", "3"}, "1")
625 if err != nil {
626 return err
627 }
628 }
629 }
630
631 // 4. Merge + push
632 // The push can still fail if there were new remote commits since the fetch. But that's okay, the user can just retry.
633 switch choice {
634 case "1":
635 err := gitutil.RunUpstreamMerge(ctx, config.RemoteName(), root, status.Branch, false)
636 if err != nil {
637 return fmt.Errorf("local is behind remote and failed to sync with remote: %w", err)
638 }
639 return gitutil.CommitAndPush(ctx, root, config, commitMsg, author)
640 case "2":
641 // Instead of a force push, we do a merge with favourLocal=true to ensure we don't lose history.
642 // This is not equivalent to a force push but is safer for users.
643 if config.Subpath != "" {
644 // force pushing in a monorepo can overwrite other subpaths
645 // we can check for changes in other subpaths but it is tricky and error prone
646 // monorepo setups are advanced use cases and we can require users to manually resolve remote changes
647 return fmt.Errorf("cannot overwrite remote changes in a monorepo setup. Merge remote changes manually")
648 }
649 err := gitutil.RunUpstreamMerge(ctx, config.RemoteName(), root, status.Branch, true)

Calls 9

SetRemoteFunction · 0.92
GitFetchFunction · 0.92
RunGitStatusFunction · 0.92
RunUpstreamMergeFunction · 0.92
CommitAndPushFunction · 0.92
SelectPromptFunction · 0.85
RemoteNameMethod · 0.80
PrintfWarnMethod · 0.80
ErrorfMethod · 0.65