* So `git-url-parse` can give us `owner()` and `repo()` through the provider. That's cleaner than manual string parsing.
Let me present the options to you:
**Option 1: `git-url-parse` crate**
- Pros: Specifically designed for git URLs, gives owner/repo directly via provider
- Cons: New dependency (though small)
**Option 2: `gix-url` crate**
- Pros: Part of gitoxide (well-maintained), robust parsing
- Cons: New dependency, still need to extract owner/repo from path
**Option 3: Keep current approach but improve it**
- Use the `url` crate we already have for HTTPS URLs
- Handle SSH URLs as a special case (they use `:` instead of `/`)
- Less string magic, more structured
**Option 4: Use `gh` CLI to parse**
- `gh repo view <url> --json owner,name`
- Pros: No new deps, `gh` handles all edge cases
- Cons: Requires network/auth, slower
Which approach would you prefer? I'd recommend **Option 1 (`git-url-parse`)** since it's purpose-built for this exact use case.
* Cleanup script changes for workspace a07fdbcf-0608-4a84-a012-53d4fee6d115
* Let me provide a summary of all the changes made:
## Summary
Fixed the hardcoded remote handling to support fork workflows. Here's what changed:
### 1. `crates/services/src/services/git.rs`
- **`default_remote_name()`**: Now prefers "origin" (git's convention) instead of arbitrarily picking the first remote
- **`get_remote_url()`**: New helper to get the URL of a specific remote by name
- **`get_remote_url_from_branch_or_default()`**: New helper that gets the remote URL for a branch, falling back to default remote
### 2. `crates/services/src/services/git/cli.rs`
- **`default_remote_name()`**: Same fix as above - prefers "origin"
- **`get_remote_url()`**: New method to get remote URL by name
### 3. `crates/services/src/services/git_host/github/cli.rs`
- **`get_repo_info_from_url()`**: New method that uses `gh repo view <url> --json owner,name` to parse owner/repo from a remote URL (no string magic!)
### 4. `crates/services/src/services/git_host/github/mod.rs`
- **`get_repo_info_from_url()`**: Async wrapper for the new CLI method
- **`create_pr()`**: Now uses `get_repo_info_from_url()` with the `remote_url` parameter to determine which repo to create the PR against
### 5. `crates/server/src/routes/task_attempts/pr.rs`
- **Key fix**: Now extracts the target remote URL from the `target_branch` (e.g., `upstream/main`) instead of from `workspace.branch` (your task branch)
- This enables fork workflows: push to your fork (`origin`), but create PR against upstream (the target branch's remote)
### How fork workflows now work:
1. User selects target branch like `upstream/main`
2. Code pushes task branch to `origin` (your fork)
3. Code extracts remote URL from `upstream` remote (the upstream repo)
4. PR is created against the upstream repo using `gh pr create --repo upstream-owner/repo`
* Cleanup script changes for workspace a07fdbcf-0608-4a84-a012-53d4fee6d115
* Build passes. The response structs are now at module level alongside the other `Gh*` response types, which is cleaner and more consistent with the existing code style.
* Build passes. Now `gh repo view <url>` is run from the repo directory, which helps with GitHub Enterprise authentication context.
* Done. Removed all the redundant comments.
* Build passes.
* Build passes. Now the default remote logic follows git's behavior:
1. Check `remote.pushDefault` config first (user's explicit preference)
2. Fall back to "origin" if it exists (git's convention from `git clone`)
3. Fall back to first remote if no "origin"
4. Default to "origin" if no remotes exist
* I've fixed the bug in `check_remote_branch_exists` at `git.rs:1454-1484`. The issue was that when checking if a remote branch exists, the function was:
1. Using `default_remote_name()` (which returns "origin") to strip the prefix from branch names like `upstream/main`
2. Looking up the URL from the default remote instead of the actual remote the branch belongs to
Now the function:
1. For remote branches (like `upstream/main`), extracts the actual remote name from the branch using `get_remote_name_from_branch_name()`
2. Strips the correct prefix (`upstream/` not `origin/`)
3. Uses the correct remote's URL for the `git ls-remote` check
This allows fork workflows where you select `upstream/main` as the target branch - it will now correctly check if `main` exists on the `upstream` remote's URL.
* Cleanup script changes for workspace a07fdbcf-0608-4a84-a012-53d4fee6d115
* Fix cross-fork PR creation by formatting head branch with fork owner
When creating a PR from a fork to upstream, GitHub requires the head branch
to be formatted as "owner:branch" (e.g., "LSRCT:vk/feature-branch").
Added head_repo_url to CreatePrRequest and updated GitHubProvider to
compare owners and prefix the head branch accordingly.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Refactor PR remote handling: simplify by moving logic to caller
- Delete check_remote_branch_exists() from GitService (caller now composes
the check directly using GitCli)
- Add default_remote_name_for_path() convenience method
- Rewrite pr.rs remote handling to be explicit and linear:
1. Get push_remote and target_remote names
2. Get their URLs
3. Strip prefix to get base_branch
4. Check, push, create PR
The string split happens once, visibly at the call site.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove origin preference in default_remote_name
Use first available remote instead of preferring "origin". The fallback
to "origin" only applies when there are no remotes configured at all.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Fix PR creation when target branch not fetched locally
When the target branch doesn't exist as a local remote-tracking ref
(e.g., user types a branch name that exists on remote but isn't fetched),
fall back to using the push remote instead of failing with BranchNotFound.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Reject cross-fork PRs for Azure DevOps
Azure DevOps fork PRs require different handling (--fork-id parameter).
Return a clear error instead of silently failing.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Remove get_repo_info, always use explicit URL
The parameterless get_repo_info relied on gh CLI guessing the repo from
local git config. This is wrong for fork workflows where we need to
operate on a specific remote's repo. Now list_prs_for_branch and
get_pr_comments use the remote_url they're passed instead of ignoring it.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Format git service default remote helper
* Fix clippy collapsible-if warnings
* Route remote branch checks through git service
* Remove Azure PR comment
* Consolidate git remote helpers
* Consolidate git remote resolution helpers
* Remove unnecessary comments
* Fix git service error match for remote check
* Remove unused GitCli::default_remote_name
GitService::default_remote_name (using git2) is used instead.
Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
* Refactor unused vars
---------
Co-authored-by: Claude Opus 4.5 <noreply@anthropic.com>