Skip to content

v5: git: submodule, canonical remote for relative URLs#2074

Merged
pjbgf merged 3 commits into
go-git:releases/v5.xfrom
hiddeco:v5/submodule-canonical-remote
May 7, 2026
Merged

v5: git: submodule, canonical remote for relative URLs#2074
pjbgf merged 3 commits into
go-git:releases/v5.xfrom
hiddeco:v5/submodule-canonical-remote

Conversation

@hiddeco

@hiddeco hiddeco commented May 7, 2026

Copy link
Copy Markdown
Member

A relative submodule URL like ../sibling has to be joined onto a base URL — the superproject's remote — to produce the actual URL to clone. Submodule.Repository() picked Repository.Remotes()[0] as the base. That slice is built by iterating a Go map, so its order is randomized: in any superproject with more than one remote (the common origin + upstream fork setup), the chosen base flipped between runs and the same git submodule update could clone the sibling from either namespace.

Canonical Git is deterministic1 2: it uses branch.<HEAD>.remote if configured, the sole remote when there is exactly one, otherwise the literal "origin". The submodule helper3 then joins the relative URL onto that remote's URL.

Mirror that rule in an unexported defaultRemote and call it from the relative-URL branch. Tests cover the rule directly and the end-to-end submodule flow; the integration test loops to catch any future regression that re-introduces map-order dependence.

Backport of #2071; the prerequisite relative-URL detection landed separately in #2070.

A relative submodule URL like `../sibling` has to be joined onto a
base URL — the superproject's remote — to produce the actual URL
to clone. Submodule.Repository() picked `Repository.Remotes()[0]`
as the base. That slice is built by iterating a Go map, so its
order is randomized: in any superproject with more than one
remote (the common `origin` + `upstream` fork setup), the chosen
base flipped between runs and the same `git submodule update`
could clone the sibling from either namespace.

Canonical Git is deterministic[1][2]: it uses
`branch.<HEAD>.remote` if configured, the sole remote when there
is exactly one, otherwise the literal `"origin"`. The submodule
helper[3] then joins the relative URL onto that remote's URL.

Mirror that rule in an unexported `defaultRemote` and call it
from the relative-URL branch. Tests cover the rule directly and
the end-to-end submodule flow; the integration test loops to
catch any future regression that re-introduces map-order
dependence.

Backport of go-git#2071 from main; the prerequisite relative-URL
detection landed separately in go-git#2070.

[1]: https://github.com/git/git/blob/v2.54.0/remote.c#L1801-L1809
[2]: https://github.com/git/git/blob/v2.54.0/remote.c#L655-L669
[3]: https://github.com/git/git/blob/v2.54.0/builtin/submodule--helper.c#L53-L75

Assisted-by: Claude Opus 4.7
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
@hiddeco hiddeco changed the title git: submodule, canonical remote for relative URLs v5: git: submodule, canonical remote for relative URLs May 7, 2026
hiddeco added 2 commits May 7, 2026 11:50
Submodule.Repository() must skip its relative-URL branch when the
configured URL is a native Windows absolute path (`C:\…` or
`\\server\share\…`); otherwise these get wrongly joined onto the
superproject's remote, producing nonsense like
`file:///parent/origin/C:\path\to\repo`.

The v5 source already pairs `path.IsAbs` with `filepath.IsAbs` on
the raw `s.c.URL` since go-git#2070, so the production behaviour is
correct on this branch. Add the Windows-only regression test
from 01c23780 (a follow-up commit on go-git#2071) as a guard, ported
to gocheck to match the existing `*_windows_test.go` convention
(see `repository_windows_test.go`).

Backport (test-only) of 01c23780 from go-git#2071.

Assisted-by: Claude Opus 4.7
Signed-off-by: Hidde Beydals <hidde@hhh.computer>
`MatchesScpLike` accepted any string that fit the regex
`^[user@]host:[port:]path`, but the regex's host class permits
`/` and single ASCII letters, so it matched strings that are
actually local filesystem paths:

  - `./relative:path` and `/abs/with:colon/file` matched with host
    `./relative` or `/abs/with`.
  - On Windows, `C:/path/to/repo` matched with host `C` — a
    Windows drive-letter path treated as SSH to a single-character
    hostname.

`transport.NewEndpoint` then returned an `ssh://` endpoint where
canonical Git would return a local path. The Windows drive-prefix
case is the practical impact: a submodule URL of `C:/path/to/repo`
in .gitmodules is a valid Windows-absolute path, and go-git was
attempting an SSH connection to a host named `C` instead of
opening the local repository.

Mirror canonical Git's `url_is_local_not_ssh`[1]: after the regex
matches, reject the SCP classification when (a) the URL has a `/`
before the first `:`, or (b) on Windows, the URL begins with a
DOS drive prefix. The drive-prefix check is a small byte-wise
helper rather than a regex, mirroring Git's
`win32_has_dos_drive_prefix`[2] and matching the canonical
implementation more closely.

Add positive tests for the rejected forms (portable for (a),
gated by `runtime.GOOS == "windows"` for (b)) and a regression
test verifying that real SCP forms still match.

Backport of 96eb1ba from go-git#2071.

[1]: https://github.com/git/git/blob/v2.54.0/connect.c#L710-L716
[2]: https://github.com/git/git/blob/v2.54.0/compat/win32/path-utils.c#L20-L29

Assisted-by: Claude Opus 4.7
Signed-off-by: Hidde Beydals <hidde@hhh.computer>

@pjbgf pjbgf left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@hiddeco Thanks for working on this. 🙇

@pjbgf pjbgf merged commit f7d48c9 into go-git:releases/v5.x May 7, 2026
9 checks passed
chhe pushed a commit to chhe/act_runner that referenced this pull request May 19, 2026
This PR contains the following updates:

| Package | Change | [Age](https://docs.renovatebot.com/merge-confidence/) | [Confidence](https://docs.renovatebot.com/merge-confidence/) |
|---|---|---|---|
| [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | `v5.19.0` → `v5.19.1` | ![age](https://developer.mend.io/api/mc/badges/age/go/github.com%2fgo-git%2fgo-git%2fv5/v5.19.1?slim=true) | ![confidence](https://developer.mend.io/api/mc/badges/confidence/go/github.com%2fgo-git%2fgo-git%2fv5/v5.19.0/v5.19.1?slim=true) |

---

### Release Notes

<details>
<summary>go-git/go-git (github.com/go-git/go-git/v5)</summary>

### [`v5.19.1`](https://github.com/go-git/go-git/releases/tag/v5.19.1)

[Compare Source](go-git/go-git@v5.19.0...v5.19.1)

#### What's Changed

- v5: plumbing: transport/ssh, Shell-quote path by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2068](go-git/go-git#2068)
- v5: git: submodule, Fix relative URL resolution by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2070](go-git/go-git#2070)
- v5: git: submodule, canonical remote for relative URLs by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2074](go-git/go-git#2074)
- v5: git: submodule, error on remote without URLs by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2078](go-git/go-git#2078)
- v5: plumbing: format/idxfile, Validate offset64 indices by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2084](go-git/go-git#2084)
- v5: \*: Reject malformed variable-length integers by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2092](go-git/go-git#2092)
- v5: plumbing: format/packfile, Tighten delta validation by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2091](go-git/go-git#2091)
- v5: Add `worktreeFilesystem` wrapper for worktree and hardening by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2100](go-git/go-git#2100)
- v5: config: validate submodule names by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2082](go-git/go-git#2082)
- build: Update module github.com/go-git/go-git/v5 to v5.19.0 \[SECURITY] (releases/v5.x) by [@&#8203;go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#&#8203;2111](go-git/go-git#2111)
- v5: git: Allow MkdirAll on worktree-root paths by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2117](go-git/go-git#2117)
- v5: git: Stop validating symlink target paths by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2116](go-git/go-git#2116)
- v5: plumbing: format decoder input bounds and contracts by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2125](go-git/go-git#2125)
- plumbing: format/packfile, cap delta chain depth in parser by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2137](go-git/go-git#2137)

**Full Changelog**: <go-git/go-git@v5.19.0...v5.19.1>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At any time (no schedule defined)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xODIuMSIsInVwZGF0ZWRJblZlciI6IjQzLjE4Mi4xIiwidGFyZ2V0QnJhbmNoIjoibWFpbiIsImxhYmVscyI6W119-->

Reviewed-on: https://gitea.com/gitea/runner/pulls/980
Reviewed-by: Lunny Xiao <xiaolunwen@gmail.com>
Co-authored-by: Renovate Bot <renovate-bot@gitea.com>
Co-committed-by: Renovate Bot <renovate-bot@gitea.com>
Maks1mS pushed a commit to stplr-dev/stplr that referenced this pull request May 20, 2026
This PR contains the following updates:

| Package | Type | Update | Change | OpenSSF |
|---|---|---|---|---|
| [github.com/go-git/go-git/v5](https://github.com/go-git/go-git) | require | patch | `v5.19.0` → `v5.19.1` | [![OpenSSF Scorecard](https://api.securityscorecards.dev/projects/github.com/go-git/go-git/badge)](https://securityscorecards.dev/viewer/?uri=github.com/go-git/go-git) |

---

> ⚠️ **Warning**
>
> Some dependencies could not be looked up. Check the [Dependency Dashboard](issues/23) for more information.

---

### Release Notes

<details>
<summary>go-git/go-git (github.com/go-git/go-git/v5)</summary>

### [`v5.19.1`](https://github.com/go-git/go-git/releases/tag/v5.19.1)

[Compare Source](go-git/go-git@v5.19.0...v5.19.1)

#### What's Changed

- v5: plumbing: transport/ssh, Shell-quote path by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2068](go-git/go-git#2068)
- v5: git: submodule, Fix relative URL resolution by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2070](go-git/go-git#2070)
- v5: git: submodule, canonical remote for relative URLs by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2074](go-git/go-git#2074)
- v5: git: submodule, error on remote without URLs by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2078](go-git/go-git#2078)
- v5: plumbing: format/idxfile, Validate offset64 indices by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2084](go-git/go-git#2084)
- v5: \*: Reject malformed variable-length integers by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2092](go-git/go-git#2092)
- v5: plumbing: format/packfile, Tighten delta validation by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2091](go-git/go-git#2091)
- v5: Add `worktreeFilesystem` wrapper for worktree and hardening by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2100](go-git/go-git#2100)
- v5: config: validate submodule names by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2082](go-git/go-git#2082)
- build: Update module github.com/go-git/go-git/v5 to v5.19.0 \[SECURITY] (releases/v5.x) by [@&#8203;go-git-renovate](https://github.com/go-git-renovate)\[bot] in [#&#8203;2111](go-git/go-git#2111)
- v5: git: Allow MkdirAll on worktree-root paths by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2117](go-git/go-git#2117)
- v5: git: Stop validating symlink target paths by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2116](go-git/go-git#2116)
- v5: plumbing: format decoder input bounds and contracts by [@&#8203;hiddeco](https://github.com/hiddeco) in [#&#8203;2125](go-git/go-git#2125)
- plumbing: format/packfile, cap delta chain depth in parser by [@&#8203;pjbgf](https://github.com/pjbgf) in [#&#8203;2137](go-git/go-git#2137)

**Full Changelog**: <go-git/go-git@v5.19.0...v5.19.1>

</details>

---

### Configuration

📅 **Schedule**: (UTC)

- Branch creation
  - At 12:00 AM through 04:59 AM and 10:00 PM through 11:59 PM, Monday through Friday (`* 0-4,22-23 * * 1-5`)
  - Only on Sunday and Saturday (`* * * * 0,6`)
- Automerge
  - At any time (no schedule defined)

🚦 **Automerge**: Disabled by config. Please merge this manually once you are satisfied.

♻ **Rebasing**: Whenever PR becomes conflicted, or you tick the rebase/retry checkbox.

🔕 **Ignore**: Close this PR and you won't be reminded about this update again.

---

 - [ ] <!-- rebase-check -->If you want to rebase/retry this PR, check this box

---

This PR has been generated by [Mend Renovate](https://github.com/renovatebot/renovate).
<!--renovate-debug:eyJjcmVhdGVkSW5WZXIiOiI0My4xNzAuMjIiLCJ1cGRhdGVkSW5WZXIiOiI0My4xNzAuMjIiLCJ0YXJnZXRCcmFuY2giOiJtYWluIiwibGFiZWxzIjpbIktpbmQvRGVwZW5kZW5jaWVzIl19-->

Reviewed-on: https://altlinux.space/stapler/stplr/pulls/435
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.

2 participants