Pinning External Code in Subversion with svn:externals and Peg Revisions
Subversion's svn:externals property embeds external repositories at specific revisions. Use peg revisions (URL@REV) to freeze externals at known-good states, repository-relative URLs (^/path) for mirror portability, and understand the commit, authentication, and performance implications.
22 Apr 2026, 18:18 UTC

The Problem: Sharing Code Without Duplication
Teams often need to include a common library or vendor branch inside multiple projects. Copying the code duplicates history, makes updates painful, and breaks traceability. Subversion solves this with the svn:externals property: a versioned directory property that maps a local subdirectory to an external repository URL at a specific revision. The external appears as a nested working copy (pre-1.7) or as part of the parent working copy (1.7+), fetched automatically on svn update and svn checkout.
Useful Takeaway
Define externals with a peg revision (URL@REV) to freeze the external at a known-good state. Use repository-relative URLs (^/path) for portability across mirror servers. Edit the property with svn propedit svn:externals ., then run svn update to materialize changes.
Worked Example: Pinning a Shared Library at Revision 1234
Assume a parent project checked out from https://svn.example.com/repos/main and a shared library living at https://svn.example.com/repos/common/lib. You want the library to appear under libs/common in your working copy, locked to revision 1234.
# From the root of the parent working copy
svn propedit svn:externals .
Your editor opens. Add one line:
^/common/lib@1234 libs/common
Save and exit. Then materialize:
svn update
What each part means:
^/common/lib— repository-relative URL. The^resolves to the repository root of the parent working copy (https://svn.example.com/repos/), so the full URL becomeshttps://svn.example.com/repos/common/lib.@1234— peg revision. This fixes the location of the external at revision 1234. Even ifcommon/libwas moved or renamed after r1234, Subversion will still find it.libs/common— local subdirectory where the external will appear. Created automatically on update.
After svn update, libs/common contains the library exactly as it existed at r1234. The parent working copy now tracks this external definition in its own history.
Why Peg Revisions Matter
Without a peg revision, svn update follows the current path name in the external repository. If the external path was renamed (say common/lib → common/v2/lib) after the revision you care about, a subsequent svn update would either fail with "Repository moved permanently" or pull the new location's content — likely unrelated code.
The peg revision (@REV) tells Subversion: "Find the object that lived at this path at this revision, then give me that object at the operational revision (default HEAD)." This decouples identity from current location.
You can also specify an operational revision separately with -r:
-r 1200 ^/common/lib@1234 libs/common
This says: "Identify the external at r1234, but check it out as it looked at r1200." Rarely needed, but useful for bisecting regressions in the external.
Relative URL Forms and Portability
Subversion supports four relative URL prefixes, resolved against the parent working copy's repository root:
| Prefix | Resolves To | Use Case |
|---|---|---|
^/path | Repository root | Portable across mirrors (recommended) |
/path | Server root (scheme + host) | Cross-repository on same host |
//path | Scheme + host | Same as / but explicit |
../path | Parent directory in repo | Sibling directories |
Caution: ^/ resolves to the scheme and hostname of the parent working copy's URL. If developers check out the parent via svn://internal.example.com/repos/main but the CI server uses https://svn.example.com/repos/main, the ^/common/lib external will resolve to different hosts. Either standardize the access URL or use absolute URLs for externals that live on a different host.
File Externals (Subversion 1.8+)
Starting with 1.8, svn:externals can target a single file instead of a directory. Syntax is identical, but the target must be a file URL and the local name must be a file (not a directory). Example:
^/project/README@HEAD README.txt
Restrictions: file externals do not support the -r operational revision flag; only peg revisions are allowed. They also cannot point to directories.
Common Pitfalls and Limitations
1. Commits Inside an External Go to the External Repo
If you edit a file under libs/common/ and run svn commit from the parent working copy, Subversion commits to the external repository, not the parent. You must cd libs/common && svn commit separately. Forgetting this leaves the external modified but uncommitted, confusing teammates.
2. Externals Ignore Parent Checkout Depth
Even if you check out the parent with --depth=empty or --depth=files, each external is always fetched at infinity depth. You cannot sparse-checkout an external independently.
3. Authentication Prompts on Update
If the external lives in a different authentication realm (different host, path, or realm string), svn update will prompt interactively for credentials unless they are cached in ~/.subversion/auth/ or supplied via --username/--password. Automate with credential caching or a credential helper.
4. Performance with Many Externals
Each external is a separate working copy traversal. Beyond ~50 externals, svn status and svn update become noticeably slower. Consider consolidating related externals into a single repository or using a monorepo layout.
5. svn export Skips Externals by Default
svn export does not materialize externals unless you pass --force. Build scripts that rely on export must account for this.
Verifying the Setup
After adding the external and running svn update:
ls -la libs/common— confirms the directory exists and contains the expected files.svn info libs/common— shows the external's repository URL, revision, and peg revision. VerifyRevision: 1234andURL: https://svn.example.com/repos/common/lib.svn status— should show no local modifications inlibs/commonunless you edited files there.- Change the peg revision in the property (e.g.,
@1235), runsvn update, and confirm the external updates to the new revision.
To test portability, check out the same parent working copy via a different hostname (e.g., localhost vs 127.0.0.1) and run svn update. The ^/ external should resolve correctly if both hostnames serve the same repository root.
Changing or Removing an External
Run svn propedit svn:externals . again. Edit the line (change URL, peg revision, or local path) or delete the line entirely. Save, then run svn update. Deleting a line removes the external directory on the next update. This is a state-changing operation; if you need to roll back, revert the property change with svn revert . before updating.
Summary Checklist
- Use
^/path@REVfor portable, pinned externals. - Always include a peg revision when the external path might move.
- Commit the
svn:externalsproperty change to the parent repo so teammates get it on update. - Commit changes inside the external from within the external's working copy.
- Cache credentials for external realms to avoid interactive prompts in automation.
- Monitor external count; consolidate if
svn statusslows down.
0 replies
A thoughtful contribution can make all the difference. Be the first to share one.