Skip to content

feat(gix-url): add path access without query or fragment - #2983

Merged
Sebastian Thiel (Byron) merged 1 commit into
mainfrom
gix-url-no-query-params
Sep 9, 2026
Merged

feat(gix-url): add path access without query or fragment#2983
Sebastian Thiel (Byron) merged 1 commit into
mainfrom
gix-url-no-query-params

Conversation

@Byron

@Byron Sebastian Thiel (Byron) commented Sep 9, 2026

Copy link
Copy Markdown
Member

Tasks

This section is for Byron only. Models continuing this PR must not add, remove, check, uncheck, rename, or reorder checkboxes here.

  • refackiew

Everything below this line was generated by Codex GPT-6.

Created by Codex on behalf of Byron. Byron will review before this is ready to merge.

GitButler needs a repository path without HTTP query or fragment text, while preserving encoded path characters. Add Url::path_without_query_and_fragment() -> &BStr: https://host/repo%23one?query=value#fragment now exposes /repo#one through this accessor.

The method locates literal HTTP/HTTPS delimiters in the validated original spelling and borrows the corresponding decoded bytes from Url::path. Nested escapes are decoded once, empty HTTP paths return /, and constructed or mutated paths follow the existing serialization rules without decoding literal percent text again. Other schemes retain their stored path, including SSH delimiters and SCP-style percent escapes. The addition preserves Url::path, original_path(), serialization, and the Serde representation.

GitButler example

In RemoteUrl::parse(), the scheme-dependent split-and-decode block can become:

let path = std::str::from_utf8(parsed.path_without_query_and_fragment()).ok()?;
let path = path.trim_matches('/');
let path = path.strip_suffix(".git").unwrap_or(path).to_owned();

Forge-specific owner/repository extraction and terminal .git stripping stay with GitButler; example.github.io.git remains intact in the accessor.

Validation

Regressions were written first and reproduced the unwanted suffixes before the implementation. They cover both HTTP schemes, encoded delimiters, nested and multibyte escapes, empty paths, construction, stale cached spelling, scheme changes, arbitrary path bytes, SSH/SCP, and repository names containing .git.

  • GIX_TEST_IGNORE_ARCHIVES=1 cargo test -p gix-url --features gix-testtools/sha1 --test url access::path_without_query_and_fragment — 4 passed.
  • GIX_TEST_IGNORE_ARCHIVES=1 cargo test -p gix-url --features serde,gix-testtools/sha1 — 20 unit tests, 147 integration tests, and 2 doctests passed.
  • cargo fmt --all -- --check and git diff --check — passed.
  • cargo clippy -p gix-url --all-targets --features serde,gix-testtools/sha1 -- -D warnings -A unknown-lints --no-deps — passed; Rust 1.98.1 reports the workspace's existing removed-lint configuration warning.
  • RUSTDOCFLAGS='-D warnings' cargo doc -p gix-url --features serde --no-deps — passed.
  • One codex review --commit a90497beedd8f849c03ae9448ae7ad8ada81cfce — no actionable defects.

Git reference

Inspected connect.c::parse_connect_url() in /Users/byron/dev/github.com/git/git at 1630431f326e15fcde608827b5ff38422528eb59. Its existing binary identifies as 2.55.0.windows.4.17.g15c6308cf7.dirty; fetch-pack --diag-url confirms /repo#one?two for the SSH URL and repo#one?two%23three for SCP syntax, with nested escapes also decoded once. The standalone url-parse -c path returns /repo for these delimiter examples, so it was not used as the SSH transport oracle.

Reported issue

User-provided report (verbatim)
$issue-full-auto Improve gix-url’s path-access API for consumers identifying repositories from Git remote URLs.

Target repository: GitoxideLabs/gitoxide.
Downstream motivation: https://github.com/gitbutlerapp/gitbutler/pull/15739

GitButler’s RemoteUrl::parse() works around gix-url storing HTTP query and fragment text inside the decoded Url::path. It reads original_path(), splits off literal '?' and '#' delimiters, then percent-decodes the remaining path. This ordering preserves encoded path characters such as %23 and %3F. SSH paths require different handling because '?' and '#' are literal path characters.

Investigate the current implementation and add the smallest coherent public API for obtaining the decoded path without HTTP/HTTPS query or fragment components. Choose an appropriate name and document its scheme-specific behavior.

Prefer a non-breaking addition that preserves Url::path, original_path(), and serialization semantics. Breaking changes are acceptable if necessary to fix an underlying architectural issue; explain why and update affected callers together.

Requirements:
- Recognize HTTP query/fragment boundaries before percent-decoding.
- Decode exactly once, preserving nested escapes such as %2523 as literal %23.
- Preserve literal '?' and '#' in SSH paths, and literal percent escapes in SCP-style paths.
- Handle constructed and mutated URLs correctly. original_path() can fall back to already-decoded data, so blindly decoding its result is insufficient.
- Keep paths byte-oriented and reuse existing helpers and dependencies.
- Leave forge-specific owner/repository extraction and terminal '.git' stripping with consumers. gix-url already preserves '.git' within repository names.

Write regression tests before implementation, including:
- https://host/repo%23one?query=value#fragment → /repo#one
- https://host/repo%3Fone?query=value → /repo?one
- https://host/repo%2523one → /repo%23one
- git@host:repo#one?two%23three → repo#one?two%23three
- ssh://git@host/repo%23one?two → /repo#one?two
- https://host/owner/example.github.io.git → /owner/example.github.io.git

Also cover HTTP URLs without an explicit path, multibyte escapes, and construction/mutation behavior.

Inspect /Users/byron/dev/github.com/git/git as the Git reference. Distinguish SSH transport behavior in connect.c from the standalone git url-parse command; its output alone is insufficient for these delimiter cases.

Run focused tests and proportional repository checks. Follow issue-full-auto through commits, review, PR creation, and CI follow-up. Give every commit a substantive body explaining motivation, behavior, design choices, and actual validation. Include a short example in the PR showing how GitButler could replace its manual split-and-decode logic.

<!-- agent -->
Expose the decoded path, query pairs, and fragment of Git remote URLs
separately. Consumers can identify repository paths and inspect HTTP(S)
parameters without implementing scheme-specific splitting and decoding.

Recognize delimiters before decoding and reuse validated original spelling
to borrow decoded bytes. Preserve encoded separators, nested escapes,
ordered duplicate query keys, and literal percent text after construction
or mutation. Query pairs use form decoding (`+` becomes space); SSH/SCP
paths, existing accessors, and serialization keep their behavior.

Reference Git's `connect.c::parse_connect_url()` and `url.c` at
`1630431f326e`. Use `fetch-pack --diag-url` to check SSH delimiters;
standalone `url-parse` does not model that transport.

Assisted-by: GPT 6.0
Co-authored-by: GPT 6.0 <[email protected]>
@Byron
Sebastian Thiel (Byron) marked this pull request as ready for review September 9, 2026 14:02
@Byron
Sebastian Thiel (Byron) merged commit 02100d9 into main Sep 9, 2026
32 checks passed
@Byron
Sebastian Thiel (Byron) deleted the gix-url-no-query-params branch September 9, 2026 14:03
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant