{"record":{"id":"7a234942b76f319b","repo":"pcottle/learnGitBranching","slug":"git-error-origin-fetch-no-ff","errorCode":null,"errorMessage":"git-error-origin-fetch-no-ff","messagePattern":"git-error-origin-fetch-no-ff","errorType":"validation","errorClass":"GitError","httpStatus":null,"severity":"error","filePath":"src/js/git/index.js","lineNumber":1030,"sourceCode":" * Origin stuff!\n ************************************/\n\nGitEngine.prototype.checkUpstreamOfSource = function(\n  target,\n  source,\n  targetBranch,\n  sourceBranch,\n  errorMsg\n) {\n  // here we are downloading some X number of commits from source onto\n  // target. Hence target should be strictly upstream of source\n\n  // lets first get the upstream set from source's dest branch\n  var upstream = Graph.getUpstreamSet(source, sourceBranch);\n\n  var targetLocationID = target.getCommitFromRef(targetBranch).get('id');\n  if (!upstream[targetLocationID]) {\n    throw new GitError({\n      msg: errorMsg || intl.str('git-error-origin-fetch-no-ff')\n    });\n  }\n};\n\nGitEngine.prototype.getTargetGraphDifference = function(\n  target,\n  source,\n  targetBranch,\n  sourceBranch,\n  options\n) {\n  options = options || {};\n  sourceBranch = source.resolveID(sourceBranch);\n\n  var targetSet = Graph.getUpstreamSet(target, targetBranch);\n  var sourceStartCommit = source.getCommitFromRef(sourceBranch);\n","sourceCodeStart":1012,"sourceCodeEnd":1048,"githubUrl":"https://github.com/pcottle/learnGitBranching/blob/5b09d0ff9678cad164f5a7488a279a44f90d7256/src/js/git/index.js#L1012-L1048","documentation":"Thrown by GitEngine's fetch/push fast-forward check when the destination branch's current commit is not an ancestor of the source branch's commits. In real git this is the 'fetch first' / non-fast-forward rejection: the remote (or target) has commits that the local source does not contain, so updating the ref would lose history.","triggerScenarios":"Calling fetch or push where target.getCommitFromRef(targetBranch) yields a commit id not in Graph.getUpstreamSet(source, sourceBranch) — e.g. pushing to a remote branch that has diverged, or fetching into a ref that already has newer commits, without force/options to override.","commonSituations":"Someone else (or another level/simulation step) advanced the remote branch and you try to push over it; in LearnGitBranching, attempting a non-FF push after the origin branch moved.","solutions":["Pull or fetch and merge/rebase first so your source contains the target's commit","Push to a different destination branch or reset it to match before pushing","As a library consumer, pass the force/override option the surrounding API supports if history rewrite is intended"],"exampleFix":"// before\nthis.push('main', 'main'); // remote main diverged\n// after\nthis.pull('main', 'main');\nthis.push('main', 'main');","handlingStrategy":"validation","validationCode":"var upstream = Graph.getUpstreamSet(source, sourceBranch);\nvar targetId = target.getCommitFromRef(targetBranch).get('id');\nif (!upstream[targetId]) {\n  // diverged: pull/rebase first instead of pushing","typeGuard":null,"tryCatchPattern":"try { engine.push(src, dest); } catch (e) { if (e instanceof GitError && /fast/i.test(e.msg)) { /* pull then retry */ } else throw e; }","preventionTips":["Always fetch before push in scripts","Check ancestry of target commit before pushing"],"tags":["git","fast-forward","push","fetch","divergent-history"],"backgroundTag":"git-non-fast-forward-rejected","analyzedSha":"5b09d0ff9678cad164f5a7488a279a44f90d7256","analyzedAt":"2026-08-27T13:53:49.057Z","schemaVersion":2},"datasetVersion":"2026-08-27T19:17:21.184Z"}