{"record":{"id":"9def6fec77e110ba","repo":"jesseduffield/lazygit","slug":"cannot-fast-forward-a-branch-with-commits-to-push","errorCode":null,"errorMessage":"Cannot fast-forward a branch with commits to push","messagePattern":"Cannot fast-forward a branch with commits to push","errorType":"exception","errorClass":null,"httpStatus":null,"severity":"warning","filePath":"pkg/gui/controllers/branches_controller.go","lineNumber":666,"sourceCode":"\nfunc (self *BranchesController) merge() error {\n\tselectedBranchName := self.context().GetSelected().Name\n\treturn self.c.Helpers().MergeAndRebase.MergeRefIntoCheckedOutBranch(selectedBranchName)\n}\n\nfunc (self *BranchesController) rebase(branch *models.Branch) error {\n\treturn self.c.Helpers().MergeAndRebase.RebaseOntoRef(branch.Name)\n}\n\nfunc (self *BranchesController) fastForward(branch *models.Branch) error {\n\tif !branch.IsTrackingRemote() {\n\t\treturn errors.New(self.c.Tr.FwdNoUpstream)\n\t}\n\tif !branch.RemoteBranchStoredLocally() {\n\t\treturn errors.New(self.c.Tr.FwdNoLocalUpstream)\n\t}\n\tif branch.IsAheadForPull() {\n\t\treturn errors.New(self.c.Tr.FwdCommitsToPush)\n\t}\n\n\taction := self.c.Tr.Actions.FastForwardBranch\n\tworktree, ok := self.worktreeForBranch(branch)\n\n\treturn self.c.WithInlineStatus(branch, types.ItemOperationFastForwarding, context.LOCAL_BRANCHES_CONTEXT_KEY, func(task gocui.Task) error {\n\t\tif ok {\n\t\t\tself.c.LogAction(action)\n\n\t\t\tworktreeGitDir := \"\"\n\t\t\tworktreePath := \"\"\n\t\t\t// if it is the current worktree path, no need to specify the path\n\t\t\tif !worktree.IsCurrent {\n\t\t\t\tworktreeGitDir = worktree.GitDir\n\t\t\t\tworktreePath = worktree.Path\n\t\t\t}\n\n\t\t\terr := self.c.Git().Sync.Pull(","sourceCodeStart":648,"sourceCodeEnd":684,"githubUrl":"https://github.com/jesseduffield/lazygit/blob/c477a2959b229fbf3284be0d4d2904ab61ec3c94/pkg/gui/controllers/branches_controller.go#L648-L684","documentation":"Thrown by BranchesController.fastForward when branch.IsAheadForPull() is true, i.e. the branch has commits that exist locally but not on its upstream. Fast-forward only moves a branch forward to match the remote; it never discards or reconciles local commits, so lazygit refuses rather than risk divergence being masked. This guard runs after the no-upstream and no-local-upstream checks.","triggerScenarios":"Pressing 'f' (fast-forward) on a branch that is ahead of its upstream — you committed locally but did not push, or you rebased onto something newer and the remote ref is behind.","commonSituations":"Working offline with local commits, a shared branch you committed to directly, or after amending an already-pushed commit so the branch appears ahead.","solutions":["Push the local commits first ('git push'), then fast-forward is a no-op/succeeds","If the remote moved too, use 'pull' (rebase or merge) instead of fast-forward","If the local commits are unwanted, reset to the upstream: 'git reset --hard @{u}' (destroys local commits)"],"exampleFix":"# before: branch is ahead, pressing 'f' errors\n# after: choose an integration action instead\n git push            # publish local commits\n# or\n git pull --rebase   # integrate remote changes","handlingStrategy":"validation","validationCode":"// Check ahead/behind before fast-forwarding:\nif branch.IsAheadForPull() {\n    // choose push or pull --rebase instead of fast-forward\n    return pushOrRebase(branch)\n}","typeGuard":null,"tryCatchPattern":null,"preventionTips":["Treat fast-forward as remote-only sync: publish local commits with push first","In scripts, compare rev-list counts ahead/behind before 'git merge --ff-only'","Prefer 'git pull --ff-only' semantics and handle divergence explicitly"],"tags":["git","fast-forward","diverged-branch","unpushed-commits"],"backgroundTag":null,"analyzedSha":"c477a2959b229fbf3284be0d4d2904ab61ec3c94","analyzedAt":"2026-08-15T08:34:32.451Z","schemaVersion":2},"datasetVersion":"2026-08-15T17:31:12.345Z"}