feat: add --upstream to review a fork branch against its upstream repo#137
feat: add --upstream to review a fork branch against its upstream repo#137hetaoBackend wants to merge 8 commits into
--upstream to review a fork branch against its upstream repo#137Conversation
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Local-only default-branch discovery uses `git symbolic-ref` on the remote HEAD symref; `git rev-parse --abbrev-ref --end-of-options` echoes the --end-of-options token and is unsafe to parse. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
| base := p.MergeBase(ctx) | ||
| if base == "" { | ||
| return nil, fmt.Errorf("cannot find merge-base between %s and %s", p.from, p.to) | ||
| return nil, fmt.Errorf("cannot find merge-base between %s and %s (if this is a shallow clone, run: git fetch --unshallow)", p.from, p.to) |
There was a problem hiding this comment.
While adding the shallow clone hint is helpful, the underlying issue is that computeMergeBase (line 259-265) silently discards the actual git merge-base error output. There are multiple possible causes for merge-base failure (unrelated histories, invalid/missing refs, permission issues, etc.), and the real git error message would help users diagnose the root cause.
Consider propagating the error from computeMergeBase so the actual git error can be included in this message, e.g.:
cannot find merge-base between X and Y: <actual git error> (if this is a shallow clone, run: git fetch --unshallow)
This way the shallow clone hint remains as a suggestion while the real error provides actionable diagnostics for all failure modes.
There was a problem hiding this comment.
Fixed in caa3dce. computeMergeBase now returns git's diagnostic instead of discarding it, and the range-mode error includes it when present:
cannot find merge-base between X and Y: <actual git error> (if this is a shallow clone, run: git fetch --unshallow)
The unrelated-histories case (git exits non-zero with empty output) appends no detail, so the message stays clean there. Added TestRangeMergeBaseErrorIncludesGitDetail covering the missing-ref path.
| if !isURL && !upstreamRemoteExists(repoDir, target) { | ||
| return "", "", fmt.Errorf("--upstream %q: no git remote named %q; pass a git URL or run \"git remote add %s <url>\"", target, target, target) | ||
| } |
There was a problem hiding this comment.
Potential issue: When isUpstreamURL returns true for a spec that also happens to be a configured remote name (e.g., someone named their remote https://github.com/orig/repo), the code skips the upstreamRemoteExists check entirely and treats it purely as a URL. This means git will fetch using the raw URL rather than the configured remote, ignoring any custom fetch refspecs or credentials set up for that remote.
Consider checking upstreamRemoteExists first (or additionally) when the spec looks like a URL, and preferring the remote configuration when both match. For example:
if !isURL && !upstreamRemoteExists(repoDir, target) {
...
}could become:
remoteExists := upstreamRemoteExists(repoDir, target)
if !isURL && !remoteExists {
...
}and then later logic could prefer the remote name when remoteExists is true even if isURL is also true.
There was a problem hiding this comment.
I looked into this and the described collision can't actually occur: git rejects every spec shape that isUpstreamURL classifies as a URL as an invalid remote name. Tested locally:
https://github.com/orig/repo→fatal: '...' is not a valid remote name./rel,/abs,../up,~home,git@host:path→ all rejected as remote names
isUpstreamURL only returns true for ://, scp syntax (user@host:path), or path-like prefixes (/, ./, ../, ~) — none of which are valid remote names. A name like a/b is a valid remote but isn't flagged as a URL, so it correctly takes the remote path.
So a configured remote can never have a name that isUpstreamURL treats as a URL, which means the custom-refspec/credentials concern isn't reachable. I'd lean toward not adding the extra branch (dead code), but happy to add an explicit remote-first guard if you'd still prefer the defensive check.
|
Thanks for taking a look! This PR adds A few notes to make review easier:
@lizhengfeng101 could you help review this when you get a chance? Happy to adjust naming, UX, or anything else. 🙏 |
computeMergeBase swallowed git's output on failure, so all merge-base failures looked the same. Propagate the real diagnostic (invalid ref, permission, etc.) while keeping the shallow-clone hint. Addresses review feedback on PR alibaba#137. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
Summary
Adds
ocr review --upstream <remote|url>so a fork user can review their current branch against the original (upstream) repository — directly addressing the case where reviewing a fork against the upstream fails today because the upstream ref isn't present locally (not a valid git ref), and--fromrequires a mandatory--to.ocr review --upstream upstream— auto-discovers the upstream's default branch viagit ls-remote --symrefand fetches it.ocr review --upstream https://github.com/org/repo— anonymous fetch toFETCH_HEAD; no permanent remote is added, so the user's repo config is untouched.--upstream-branch <branch>overrides the upstream branch;--todefaults toHEAD;--no-fetchuses the local remote-tracking ref for offline use.merge-base(upstream, HEAD)..HEADby reusing the existing range mode —--upstreamis purely a front-end resolution step inrunReview, so the diff/agent path is unchanged.git fetch --unshallow(helps shallow clones).--upstreamis mutually exclusive with--from/--commit.Test Plan
go test ./...— new tests incmd/opencodereview/upstream_test.go(URL detection, symref parsing, andfile://integration tests for remote-name / URL /--no-fetchpaths),cmd/opencodereview/flags_test.go(flag validation), andinternal/diff/git_test.go(unshallow hint).ocr review --upstream upstream --preview— configured remote, real fetch.ocr review --upstream https://github.com/alibaba/open-code-review --preview— URL form.ocr review --upstream origin --no-fetch --preview— offline path.🤖 Generated with Claude Code