Subversion source control for Positron
Positron-optimized fork of the SVN extension with enhanced features for data science workflows.
Original extension: JohnstonCode/svn-scm
Prerequisites
Note: This extension leverages your machine's SVN installation,
so you need to install SVN first.
Windows
If you use TortoiseSVN, make sure the option
Command Line Tools is checked during installation and
C:\Program Files\TortoiseSVN\bin is available in PATH.
Feedback & Contributing
- Please report any bugs, suggestions or documentation requests via the
Issues
- Feel free to submit
pull requests
Contributing as a Developer
Want to contribute? Great! See our CONTRIBUTING.md for:
- Development environment setup
- Testing & TDD workflow
- Code style guidelines
- Pull request process
For comprehensive guides, see:
SVN Terminology Quick Reference
When comparing file versions, SVN uses these keywords:
| Term |
Meaning |
Example |
| BASE |
Your last updated version |
What you had after your last svn update |
| HEAD |
Server's latest version |
The newest revision on the repository |
| PREV |
Previous committed version |
The revision before HEAD |
Common scenarios:
- "Open Changes with BASE" - Compare your edits to what you downloaded
- "Open Changes with HEAD" - See if server has newer changes
- "Open File (HEAD)" - View the server's latest without changing your local copy
Features
Checkout
You can checkout a SVN repository with the SVN: Checkout command in the Command Palette (Ctrl+Shift+P). You will be asked for the URL of the repository and the parent directory under which to put the local repository.
- Source Control View
- Quick Diffs in gutter
- Status Bar
- Create changelists
- Add files
- Revert edits
- Remove files
- Create branches
- Switch branches
- Create patches
- Diff changes
- Diff with external tools (Beyond Compare, etc.)
- Commit changes/changelists
- See commit messages
Staging Area (Git-like Workflow)
This extension simulates Git's staging area using SVN changelists, enforcing a "stage before commit" workflow.
How It Works
Files must be staged (or in a changelist) before committing:
- Stage files - Click the
+ button or use "Stage" from context menu
- Review staged - Files appear in "Staged for Commit" group
- Commit - Press
Ctrl+Enter or click the checkmark button
If no files are staged, you'll be prompted to "Stage All" before committing.
Under the Hood
- Staging uses a hidden SVN changelist (
__staged__)
- Files in custom changelists can also be committed directly
- Original changelist membership is restored when unstaging
- SVN automatically clears changelist membership after commit
Why This Workflow?
- Intentional commits - Forces you to review what you're committing
- Partial commits - Commit only specific files, not everything
- Familiar UX - Works like Git for developers switching from Git
- Non-destructive - Original changelists preserved on unstage
Quick Reference
| Action |
Shortcut/Button |
| Stage file |
+ button or context menu |
| Stage all |
+ on Changes group header |
| Unstage file |
- button or context menu |
| Unstage all |
- on Staged group header |
| Commit staged |
Ctrl+Enter or checkmark button |
Configure external diff tools like Beyond Compare for large files (e.g., CSVs) where built-in diff is insufficient.
Setup:
- Set
svn.diff.tool to path of wrapper batch file (e.g., bcsvn.bat)
- Right-click file in Source Control → Diff with External Tool
- For Beyond Compare setup, see: https://www.scootersoftware.com/kb/vcs#svn
File & Folder Decorations
The extension displays status badges and icons on files in the Explorer and Source Control views.
Status Badges
| Badge |
Meaning |
| A |
Added - new file scheduled for commit |
| M |
Modified - file has local changes |
| D |
Deleted - file scheduled for removal |
| R |
Renamed/Replaced - file moved or replaced |
| C |
Conflicted - merge conflict needs resolution |
| U |
Unversioned - new file not yet added to SVN |
| ! |
Missing - file deleted outside SVN |
| I |
Ignored - file matches ignore pattern |
Folder Badges
Folders show the same status with a folder prefix:
- 📁A - Folder added
- 📁M - Folder with modified contents
- 📁D - Folder deleted
Lock Icons
| Icon |
Meaning |
| 🔒 |
File is locked (by you or others) |
| 🔓 |
File has svn:needs-lock property (unlocked, read-only) |
| 🔒M |
Locked and modified |
| 🔒A |
Locked and added |
Tooltip: Hover over the lock icon to see who owns the lock.
Combined Badges
When a file has both a status and lock, badges combine:
- 🔒M - Locked + Modified
- 🔒A - Locked + Added
Smart File Renaming
When you rename tracked files in the Explorer, the extension automatically uses svn move to preserve file history.
How it works:
- Rename a tracked file via Explorer → extension intercepts and converts to
svn move
- File history is preserved across the rename
- Untracked files are renamed normally (no SVN involvement)
What you get:
- Use the normal "Rename" command - no separate "SVN Rename" needed
svn log shows full history including before the rename
- No "missing + unversioned" status after renaming
Limitations:
- Only intercepts renames within VS Code/Positron
- External tools (command line, file manager) won't trigger auto-conversion
- For external renames, manually use
svn move or delete + add (loses history)
Smart File Deletion
When you delete tracked files in the Explorer, the extension automatically runs svn delete to preserve proper version control.
Default behavior:
- Delete a tracked file via Explorer → extension runs
svn delete
- File is immediately marked for deletion (D status)
- Untracked files are deleted normally (no SVN involvement)
Setting: svn.delete.actionForDeletedFiles
remove (default) - Automatically run svn delete
prompt - Ask what to do each time
none - Do nothing (file shows as "missing" status)
Repository History
View commit history for your repository in the dedicated History pane.
Features
- Commit list - Browse all commits with author, date, and message
- File changes - Expand commits to see which files were modified
- BASE indicator - Purple B badge marks your working copy's BASE revision
- Diff view - Click files to see changes in that commit
| Button |
Action |
Description |
| ↻ Refresh |
Refresh from cache |
Quick refresh using cached log data |
| ↓ Fetch |
Fetch from server |
Get latest commits from server, update cache |
| ↓↓ Pull |
Fetch + Update |
Fetch latest AND update working copy to HEAD |
When to use each:
- Refresh - Just redraw the UI (instant, no server contact)
- Fetch - See new commits without changing your files
- Pull - Get new commits AND update your working copy
BASE Revision
The B badge (purple) indicates your working copy's BASE revision - the revision you last updated to.
- Commits above BASE = newer changes on server (not in your working copy yet)
- BASE commit = what your working copy is based on
- Commits below BASE = older history
Tip: If you see commits above BASE, use "Pull" or svn update to get them.
File History
Right-click a file → Show File History to see commits that modified that specific file.
From file history, you can:
- Go to Repository History - Jump to that revision in the full repo log
- Open file at revision - View file contents at that point in time
- Compare revisions - Diff between any two versions
Blame Annotations
View line-by-line revision history directly in the editor.
Features:
- Gutter annotations: colored revision indicators (enabled by default)
- Inline messages: commit details at end of line, GitLens-style (enabled by default)
- Status bar: blame info for current line
- Auto-blame: automatically show blame when files open (enabled by default)
- Hover tooltips: detailed commit info on hover
Configuration:
See all 19 configuration options in Settings → search "svn.blame"
For advanced configuration, see Blame System Documentation.
Positron Integration
Enhanced integration with Posit's Positron IDE for data science workflows.
Connections Pane:
- View SVN repositories alongside database connections
- Quick checkout wizard with URL and directory inputs
- Repository metadata display (branch, revision, remote URL)
Setup: Automatically enabled when running in Positron. No configuration needed.
Privacy: All operations are local. No data sent to Posit or external services. See PRIVACY.md for details.
What is Positron? A next-generation IDE for data science by Posit PBC (creators of RStudio). Fork of VS Code optimized for R, Python, and Julia workflows.
Learn more: https://posit.co/products/ide/positron/
For technical details, see docs/POSITRON_INTEGRATION.md.
Authentication & Security
The extension provides secure authentication with multiple methods and comprehensive credential protection.
Security Warning: Upgrade from v2.17.229 or Earlier
⚠️ CRITICAL: Versions prior to v2.17.230 expose passwords in process listings. Upgrade immediately to v2.17.230+ to eliminate this security risk.
Authentication Methods
Recommended (in priority order):
SSH Key Authentication ⭐ BEST PRACTICE
Password Authentication (Secure with Credential Cache)
- Repository URL:
https://svn.example.com/repo
- Security: Credentials stored in SVN cache (
~/.subversion/auth/, mode 600)
- Setup: Extension prompts for password, automatically caches securely
- When to use: Quick testing, HTTPS-only repositories, personal projects
Public Repository (No Authentication)
- Repository URL:
http://svn.example.com/public-repo
- Security: No credentials needed
- When to use: Open-source projects, publicly accessible repositories
How Credential Caching Works
v2.17.230+ uses SVN's native credential cache for maximum security:
- You enter username/password in VS Code UI prompt
- Extension writes credentials to
~/.subversion/auth/svn.simple/<uuid> (file mode 600)
- SVN commands executed without
--password flag
- SVN reads credentials from cache automatically
- ✅ Result: No password exposure in process list, container logs, or CI/CD logs
Before v2.17.230:
$ ps aux | grep svn
user 12345 svn update --password "MyPassword123" # ❌ EXPOSED
After v2.17.230:
$ ps aux | grep svn
user 12345 svn update --username alice # ✅ SECURE (no password)
Authentication Method Indicators
Extension shows which auth method is active in the Output panel:
[auth: SSH key] - SSH key authentication (most secure)
[auth: password via credential cache] - Cached password (secure)
[auth: none - public repository] - No authentication required
Example output:
[my-project]$ svn update --username alice [auth: password via credential cache]
At revision 1234.
This helps verify your authentication is configured correctly.
Debugging Authentication Issues
Enable Verbose Output
- Open Command Palette (
Ctrl+Shift+P / Cmd+Shift+P)
- Run:
SVN: Show Output
- Check authentication method indicators in logs
Common Issues
Problem: "Authentication failed" but credentials are correct
[repo]$ svn update --username alice [auth: password via credential cache]
svn: E170001: Authentication failed
Solutions:
- Clear credential cache:
rm -rf ~/.subversion/auth/
- Re-enter credentials when prompted
- Verify repository URL is correct
- Check SVN server is accessible:
svn info <repo-url>
Problem: Extension prompts for password repeatedly
ℹ No credentials configured - will prompt if needed
Solutions:
- Ensure credentials are being cached (check
~/.subversion/auth/)
- Verify file permissions:
ls -la ~/.subversion/auth/svn.simple/ (should be 600)
- Try manual SVN command:
svn update (should not prompt if cache works)
Problem: Want to see raw error messages for debugging
Solution: Enable debug mode (⚠️ TEMPORARY ONLY):
{
"svn.debug.disableSanitization": true
}
⚠️ WARNING:
- Debug mode exposes credentials in logs
- Extension shows prominent warning when enabled
- Only enable temporarily for troubleshooting
- Disable immediately after debugging
When enabled, you'll see:
⚠️⚠️⚠️ SECURITY WARNING ⚠️⚠️⚠️
Error sanitization is DISABLED
Credentials WILL BE VISIBLE in logs
Disable: svn.debug.disableSanitization = false
⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️⚠️
Plus a dialog with [Disable Now] button.
Verify Authentication Setup
Check credential cache:
# List cached credentials
ls -la ~/.subversion/auth/svn.simple/
# Should show files with permissions: -rw------- (600)
Check SVN version:
svn --version
# Requires SVN 1.6+ for credential cache
Test repository access:
svn info <your-repo-url>
# Should show repository information without prompting
Best Practices
Production Environments
- ✅ Use SSH keys (
svn+ssh://)
- ✅ Enable MFA on SVN server
- ✅ Keep SVN client updated
- ❌ Never use
svn.debug.disableSanitization in production
- ❌ Avoid HTTP URLs (use HTTPS or svn+ssh://)
Development Workstations
- ✅ Use HTTPS with credential cache for personal projects
- ✅ Use SSH keys for shared/company repositories
- ✅ Protect
~/.subversion/auth/ directory (mode 700)
- ✅ Regularly update extension and SVN client
CI/CD Pipelines
- ✅ Use SSH keys stored in CI/CD secrets
- ✅ Use repository access tokens (if supported by SVN server)
- ❌ Never pass passwords via environment variables
- ❌ Never commit credentials to
.vscode/settings.json
Example GitHub Actions:
- name: Setup SSH key
run: |
mkdir -p ~/.ssh
echo "${{ secrets.SVN_SSH_KEY }}" > ~/.ssh/id_rsa
chmod 600 ~/.ssh/id_rsa
- run: svn checkout svn+ssh://svn.example.com/repo
Security Features
Error Sanitization
- Automatic redaction of passwords, tokens, paths, URLs
- Active by default in all logs and error messages
- Protects against accidental credential exposure
SecretStorage Integration
- Passwords stored in OS keychain (encrypted)
- macOS: Keychain Access
- Windows: Credential Manager
- Linux: Secret Service (gnome-keyring, KWallet)
- Never stored in plaintext in extension settings
Credential Cache Protection
- Files stored with mode 600 (user-only access)
- Automatic cleanup of old credentials
- Isolated per repository/realm
Audit Trail
- All auth operations logged (credentials redacted)
- Authentication method always visible
- Debug mode warnings prevent accidental exposure
Troubleshooting Checklist
- [ ] Check authentication method indicator in Output panel
- [ ] Verify repository URL is correct (HTTPS vs svn+ssh://)
- [ ] Test SVN access outside VS Code:
svn info <repo-url>
- [ ] Check credential cache:
ls ~/.subversion/auth/svn.simple/
- [ ] Verify SVN version:
svn --version (requires 1.6+)
- [ ] Review error messages in Output panel
- [ ] Try clearing cache:
rm -rf ~/.subversion/auth/ and re-enter credentials
- [ ] For persistent issues, enable debug mode temporarily (see above)
Security Resources
For security vulnerabilities, use GitHub Security Advisories.
Credential Storage
The extension supports multiple credential storage modes via svn.auth.credentialMode:
| Mode |
Description |
auto (default) |
System keyring locally, extension storage remotely |
systemKeyring |
Always use OS credential manager |
extensionStorage |
Always use VS Code SecretStorage |
prompt |
Never store credentials |
Auto Mode (Recommended)
The default auto mode automatically selects the best storage:
- Local development: Uses system keyring (macOS Keychain, Windows Credential Manager, gnome-keyring)
- Remote SSH/WSL/Containers: Uses VS Code SecretStorage (works without keyring setup)
System Keyring Mode
Uses native credential managers:
- macOS: Keychain
- Windows: Credential Manager
- Linux: gnome-keyring, gpg-agent
For gpg-agent in SSH sessions, set GPG_TTY:
# Add to ~/.bashrc or ~/.zshrc
export GPG_TTY=$(tty)
Troubleshooting Auth
If password prompts cycle endlessly:
- Try
extensionStorage mode:
{ "svn.auth.credentialMode": "extensionStorage" }
- Restart extension host (Ctrl+Shift+P → "Developer: Restart Extension Host")
- Re-enter credentials when prompted
Auth Method Indicators
Watch the Output panel (SVN) for current mode:
[auth: system keyring (local)] - Using OS credential manager
[auth: extension storage (remote)] - Using VS Code SecretStorage
Settings
Here are all of the extension settings with their default values. To change any of these, add the relevant Config key and value to your VSCode settings.json file. Alternatively search for the config key in the settings UI to change its value.
{
"svn.auth.commandTimeout": 60,
"svn.auth.credentialMode": "auto" // values: ["auto","systemKeyring","extensionStorage","prompt"],
"svn.autorefresh": true,
"svn.blame.autoBlame": true,
"svn.blame.dateFormat": "relative" // values: ["relative","absolute"],
"svn.blame.enableLogs": true,
"svn.blame.enabled": true,
// Date format for gutter annotations
"svn.blame.gutter.dateFormat": "relative" // values: ["relative","absolute"],
"svn.blame.gutter.enabled": true,
// Show colored revision icons in gutter
"svn.blame.gutter.showIcons": true,
// Show author/revision/date text in gutter (verbose)
"svn.blame.gutter.showText": null,
"svn.blame.gutter.template": "${author} (${revision}) ${date}",
// Only show inline annotation on current line (cursor position)
"svn.blame.inline.currentLineOnly": true,
"svn.blame.inline.enabled": true,
// Opacity of inline annotations (0.0 = invisible, 1.0 = solid)
"svn.blame.inline.opacity": 0.5,
"svn.blame.inline.showMessage": null,
"svn.blame.inline.template": " ${author}, ${date} (r${revision}) • ${message}",
// Line count threshold for large file warning (0 to disable)
"svn.blame.largeFileLimit": 3000,
// Show warning before blaming files exceeding line limit
"svn.blame.largeFileWarning": true,
// Highlight uncommitted changes in blame view
"svn.blame.showWorkingCopyChanges": true,
// Show blame info for current line in status bar
"svn.blame.statusBar.enabled": true,
"svn.blame.statusBar.template": "$(person) ${author}, $(clock) ${date} - ${message}",
"svn.commit.autoUpdate": "both" // values: ["both","before","after","none"],
// Select all staged files by default when committing
"svn.commit.changes.selectedAll": true,
// Warn before committing with empty message
"svn.commit.checkEmptyMessage": true,
"svn.commit.conventionalCommits": true,
"svn.commit.useQuickPick": true,
"svn.conflicts.autoResolve": null,
"svn.debug.disableSanitization": null,
"svn.decorator.baseColor": "charts.blue" // values: ["charts.blue","charts.purple","charts.green","charts.yellow","charts.orange","charts.red","editorInfo.foreground","editorWarning.foreground"],
"svn.decorator.serverColor": "charts.orange" // values: ["charts.orange","charts.yellow","charts.red","charts.purple","charts.blue","charts.green","editorWarning.foreground","editorInfo.foreground"],
"svn.default.encoding": null,
// Default folder for new checkouts
"svn.defaultCheckoutDirectory": null,
// Action when tracked files are deleted in Explorer
"svn.delete.actionForDeletedFiles": "remove" // values: ["none","prompt","remove"],
"svn.delete.ignoredRulesForDeletedFiles": [],
// Automatically detect and show svn:externals
"svn.detectExternals": true,
// Scan ignored folders for SVN repositories
"svn.detectIgnored": true,
"svn.diff.tool": null,
"svn.diff.withHead": true,
"svn.enabled": true,
// Experimental: Auto-detect output encoding
"svn.experimental.detect_encoding": null,
// Encoding detection priority order
"svn.experimental.encoding_priority": [],
// Suppress warning when SVN executable not found
"svn.ignoreMissingSvnWarning": null,
"svn.ignoreRepositories": null,
// Suppress warning when working copy needs upgrade
"svn.ignoreWorkingCopyIsTooOld": null,
"svn.layout.branchesRegex": "branches/([^/]+)(/.*)?",
// Regex capture group for branch name
"svn.layout.branchesRegexName": 1,
"svn.layout.showFullName": true,
// Regex capture group for tag name
"svn.layout.tagRegexName": 1,
"svn.layout.tagsRegex": "tags/([^/]+)(/.*)?",
"svn.layout.trunkRegex": "(trunk)(/.*)?",
// Regex capture group for trunk name
"svn.layout.trunkRegexName": 1,
// Show colored dots for different authors in history view
"svn.log.authorColors": true,
"svn.log.length": 50,
// Maximum folder depth to scan for SVN repositories
"svn.multipleFolders.depth": 4,
"svn.multipleFolders.enabled": null,
// Folders to skip when scanning for SVN repositories
"svn.multipleFolders.ignore": ["**/.git","**/.hg","**/vendor","**/node_modules"],
// Auth mode logging frequency in output panel
"svn.output.authLogging": "once" // values: ["once","always","never"],
"svn.path": null,
"svn.performance.maxXmlTags": 500000,
"svn.previousCommitsUser": null,
// Include remote changes check when running Refresh command
"svn.refresh.remoteChanges": null,
"svn.remoteChanges.checkFrequency": 300,
// Show SVN output panel on extension start
"svn.showOutput": null,
// Show notification after update completes
"svn.showUpdateMessage": true,
"svn.sourceControl.changesLeftClick": "open diff" // values: ["open","open diff"],
// Show externals in main repository if from the same server
"svn.sourceControl.combineExternalIfSameServer": null,
// Include unversioned files in the badge count
"svn.sourceControl.countUnversioned": true,
// Hide unversioned files from Source Control view
"svn.sourceControl.hideUnversioned": null,
"svn.sourceControl.ignore": [],
// Changelists to exclude from commit operations
"svn.sourceControl.ignoreOnCommit": ["ignore-on-commit"],
// Changelists to exclude from badge count
"svn.sourceControl.ignoreOnStatusCount": ["ignore-on-commit"],
"svn.sparse.confirmExclude": true,
// Timeout for download operations (minutes). Increase for large folders.
"svn.sparse.downloadTimeoutMinutes": 10,
"svn.sparse.largeFileWarningMb": 10,
// Timeout for folder size estimation (seconds)
"svn.sparse.preScanTimeoutSeconds": 30,
"svn.update.ignoreExternals": true
}