SVN vs Git — Key Differences
If you're coming from Git, understanding SVN's different model prevents confusion. If SVN is your first VCS, it is simpler to learn but less flexible for parallel work.
| Concept | SVN | Git equivalent |
|---|---|---|
| Repository | Single central server — one source of truth | Distributed — every clone is a full copy |
| Revision | Global integer (r1, r2, r3…) for entire repo | Per-commit SHA hash |
| Checkout | svn checkout — gets working copy from server | git clone |
| Update | svn update — fetch latest from server | git pull |
| Commit | svn commit — directly to server (no local repo) | git commit + git push |
| Branch | Copy of directory in repo (cheap metadata copy) | Lightweight pointer to a commit |
| Offline work | Very limited — most operations need server | Fully offline — commit, branch, log all local |
| Partial checkout | Yes — checkout only a subdirectory | No (sparse checkout is approximate) |
SVN Concepts & Repository Layout
By convention, every SVN repository has a standard three-directory layout at its root:
svn://server/chip_project/
├── trunk/ # main development line (like 'main' in Git)
│ ├── rtl/
│ ├── constraints/
│ ├── scripts/
│ └── tb/
├── branches/ # feature and release branches
│ ├── cdc_fix/
│ └── release_v1.2/
└── tags/ # immutable snapshots for tapeout / releases
├── tapeout_v1.0/
└── tapeout_v2.0/
- trunk: The main integration line. Equivalent to Git's
mainbranch. Stable, working RTL lives here. - branches: Copies of trunk for parallel development, CDC fixes, or customer-specific variants.
- tags: Read-only snapshots of a specific revision — created at tapeout, tape-in, or milestone delivery. Never modify a tag.
- Revision numbers: Every commit increments a single global counter for the entire repository —
r1001,r1002. This makes it easy to reference a specific state: "the RTL at r4532."
Checkout & Working Copy
# Check out the full trunk
svn checkout svn://server/chip_project/trunk chip_project
# Check out only the RTL directory (partial checkout — SVN superpower)
svn checkout svn://server/chip_project/trunk/rtl rtl
# Check out via HTTP/HTTPS
svn checkout https://svn.company.com/repos/chip/trunk chip
# Check out a specific revision
svn checkout svn://server/chip_project/trunk@4532 chip_r4532
# Check out a branch
svn checkout svn://server/chip_project/branches/cdc_fix cdc_fix
# Show working copy information (URL, revision, status)
svn info
# Show info for a specific file
svn info rtl/fifo_ctrl.sv
svn checkout url/rtl to check out only the RTL subdirectory. You can svn update individual paths and never download what you don't need.Daily Workflow
Check Status and Update
# Check what's modified in your working copy
svn status
# M = Modified, A = Added, D = Deleted, ? = Unversioned, C = Conflict
# Fetch latest changes from server
svn update
# Update a single file
svn update rtl/top.sv
# Update to a specific revision
svn update -r 4532
Making Changes
# Edit a file — SVN does NOT require locking before editing (unless lock-modify-unlock is enforced)
vim rtl/fifo_ctrl.sv
# Add a new file to version control
svn add rtl/new_module.sv
# Add a new directory recursively
svn add tb/new_test/
# Schedule a file for deletion
svn delete rtl/old_module.sv
# Move/rename a file (preserves history)
svn move rtl/fifo.sv rtl/fifo_ctrl.sv
# Copy a file (creates a versioned copy with history link)
svn copy rtl/alu_v1.sv rtl/alu_v2.sv
Reviewing and Committing
# See what will be committed
svn diff
# Diff a specific file
svn diff rtl/fifo_ctrl.sv
# Commit ALL modified files
svn commit -m "Fix setup timing violation in fifo_ctrl — add pipeline stage"
# Commit specific files only
svn commit rtl/fifo_ctrl.sv constraints/top.sdc -m "CDC fix: 2FF synchronizer added"
# Revert a file to the last committed state
svn revert rtl/top.sv
# Revert entire working copy
svn revert -R .
svn commit, the change is immediately visible to all team members. Always run svn diff and review your changes before committing.Branching & Tagging
In SVN, branches and tags are both just directory copies in the repository. The difference is convention — tags are never modified after creation.
Creating a Branch
# Create a branch from trunk HEAD
svn copy svn://server/chip/trunk \
svn://server/chip/branches/cdc_rework \
-m "Branch for CDC synchronizer rework"
# Create a branch from a specific revision (e.g., the state before a bad commit)
svn copy svn://server/chip/trunk@4530 \
svn://server/chip/branches/hotfix_r4530 \
-m "Hotfix branch from r4530"
# Switch your working copy to a branch
svn switch svn://server/chip/branches/cdc_rework
Creating a Tag (Tapeout Snapshot)
# Tag the current trunk at tapeout
svn copy svn://server/chip/trunk \
svn://server/chip/tags/tapeout_v2.0 \
-m "Tapeout v2.0 — DC synthesis WNS=-0.01ns, all DRC clean"
# Tag a specific revision
svn copy svn://server/chip/trunk@5200 \
svn://server/chip/tags/freeze_pre_eco \
-m "Pre-ECO freeze at r5200"
svnauthz access control to deny writes to tags/ from all users except the release manager to enforce this technically.Merging Branches
SVN tracks merge history since version 1.5. Use svn merge to bring branch changes back to trunk.
# 1. Switch to trunk working copy
svn switch svn://server/chip/trunk
# 2. Update to latest
svn update
# 3. Merge all changes from the branch into working copy
svn merge svn://server/chip/branches/cdc_rework
# 4. Review the result
svn status
svn diff
# 5. Resolve any conflicts (see below), then commit the merge
svn commit -m "Merge cdc_rework branch — 2FF synchronizers added to all CDC crossings"
# Merge a specific revision range only
svn merge -r 4550:4560 svn://server/chip/branches/cdc_rework
# Preview what will be merged (dry run)
svn merge --dry-run svn://server/chip/branches/cdc_rework
Resolving Conflicts
# SVN marks conflicts with extra files:
# top.sv — the conflicted file (contains <<<< ==== >>>> markers)
# top.sv.mine — your version
# top.sv.rOLD — original base
# top.sv.rNEW — incoming version
# After manually editing top.sv to resolve:
svn resolve --accept working rtl/top.sv
# Accept their version (discard yours)
svn resolve --accept theirs-full rtl/top.sv
# Accept your version (discard incoming)
svn resolve --accept mine-full rtl/top.sv
# List all conflicted files
svn status | grep ^C
svn:externals — Shared IP Blocks
SVN externals are one of its most useful features for VLSI projects. An external lets you include a subdirectory from a different repository path (or even a different revision) inside your working copy — automatically, without copying files. This is the standard way to share verified IP blocks across multiple chip projects.
Setting Up Externals
# Example: Your SoC project wants to include a shared UART IP at a specific revision
# Edit the svn:externals property on the ip/ directory
svn propedit svn:externals ip/
# In the editor, add one external per line:
# local_dir [-r REV] URL
uart_ip -r 1234 svn://server/shared_ip/trunk/uart
i2c_ip -r 5678 svn://server/shared_ip/trunk/i2c
pll_model svn://server/shared_ip/tags/pll_v2.1
# Save and close. Commit the property change.
svn commit -m "Add uart and i2c externals at validated revisions"
# Now svn update populates ip/uart_ip, ip/i2c_ip, ip/pll_model automatically
svn update
Viewing and Managing Externals
# Show all externals defined in working copy
svn propget svn:externals -R .
# Show externals status separately
svn status --show-updates
# Update only a specific external
svn update ip/uart_ip
-r REV. Without pinning, svn update always fetches the latest revision of the external — which could break your project silently when the shared IP team makes a change. Pinned externals = reproducible builds.SVN Properties & Keywords
SVN properties are metadata attached to files or directories. Two properties are especially useful for RTL files.
svn:keywords — Auto-insert Revision Info
# Enable keyword substitution on a file
svn propset svn:keywords "Id Rev Author Date" rtl/top.sv
# Then add a comment line in the file:
// $Id$ — expands to: filename, revision, date, author
// $Rev$ — expands to just the revision number
// $Author$ — expands to committing username
// $Date$ — expands to commit timestamp
# After commit, the comment automatically becomes:
// $Id: top.sv 4532 2025-05-12 09:34:11Z jsmith $
svn:ignore — Per-directory Ignore Patterns
# Set ignore patterns for a directory
svn propedit svn:ignore .
# Add patterns (one per line):
*.log
*.rpt
work/
*.ddc
*.wlf
*.vcd
WORK/
# Commit the ignore property
svn commit -m "Add svn:ignore for EDA output files"
# Check what's being ignored
svn status --no-ignore | grep ^I
History, Log & Blame
# Show commit log for the working copy
svn log
# Compact one-line-ish log (limit to 20 entries)
svn log -l 20
# Log for a specific file
svn log rtl/fifo_ctrl.sv
# Log with diff (shows actual changes)
svn log -v --diff rtl/fifo_ctrl.sv -l 5
# Log between two revisions
svn log -r 4500:4600
# Search log messages
svn log | grep -A 3 "CDC"
# Show who changed each line (blame)
svn blame rtl/alu.sv
# Blame a specific revision of a file
svn blame -r 4532 rtl/alu.sv
# Show diff between two revisions
svn diff -r 4500:4600 rtl/fifo_ctrl.sv
# Show diff between a revision and current working copy
svn diff -r 4532 rtl/top.sv
# Show file content at a specific revision
svn cat -r 4532 rtl/top.sv
Quick Reference
| Command | What it does |
|---|---|
| svn checkout URL | Create a working copy from repository |
| svn update | Fetch latest changes from server |
| svn status | Show local modifications |
| svn diff | Show line-by-line changes |
| svn add file.sv | Schedule file for addition |
| svn delete file.sv | Schedule file for deletion |
| svn move src dst | Rename/move, preserving history |
| svn commit -m "..." | Send changes to server |
| svn revert file.sv | Discard local changes |
| svn log -l 20 | Show last 20 commit messages |
| svn blame file.sv | Show who changed each line |
| svn copy trunk branches/x | Create a branch |
| svn switch URL | Point working copy at a different branch |
| svn merge URL | Merge branch changes into working copy |
| svn info | Show working copy URL, revision, author |
| svn resolve --accept working | Mark conflict as resolved |
Q&A
Use a partial checkout by specifying the subdirectory URL: svn checkout svn://server/chip/trunk/rtl my_rtl. You get a working copy of only the rtl/ subtree. You can also do a sparse checkout of the root and then populate specific directories: svn checkout --depth empty svn://server/chip/trunk chip followed by svn update --set-depth infinity chip/rtl to expand only what you need.
Use a reverse merge to undo a specific commit. If the bad commit is r4561: svn merge -r 4561:4560 svn://server/chip/trunk (note: end revision is one less than start — this merges the reverse of that commit). Review with svn diff, then svn commit -m "Revert r4561 — broken CDC synchronizer". SVN does not delete history; it adds a new commit that undoes the change.
Use SVN's lock-modify-unlock model: set svn:needs-lock property on the file (svn propset svn:needs-lock "" pdk/tech.lib) and commit. Now the file appears read-only in everyone's working copy. To edit it: svn lock pdk/tech.lib -m "Updating for new corner". This gives you an exclusive lock. Others see the lock and know not to edit it. After committing: svn unlock pdk/tech.lib. Access control via svnauthz can additionally restrict who can lock sensitive directories.
Run svn status | grep ^C to list all conflicted files. For each: open the file, find the <<<<<<< markers, edit to the correct content, then run svn resolve --accept working filename.sv. After resolving all conflicts, run svn status again to confirm no C entries remain, then svn commit. SVN will not allow a commit while any conflicts are unresolved.
SVN has no built-in stash. The common workaround is to create a patch file: svn diff > wip.patch, then svn revert -R . to clean the working copy. When ready to return, apply the patch with patch -p0 < wip.patch. Alternatively, create a personal branch, commit your WIP there (svn commit -m "WIP: CDC rework, not for review"), switch to trunk to do the urgent task, then switch back and continue. The branch commit approach is actually more reliable than patches for complex multi-file changes.