Why Git for VLSI?
VLSI projects involve dozens of interdependent files — RTL, constraints (SDC), synthesis scripts (TCL), timing reports, UPF, netlists. A single wrong edit to a timing constraint can break a working closure. Git lets you track every change, branch for experiments, and instantly restore any previous state — without copying directories named rtl_backup_v3_FINAL_final2.
- RTL history: Every commit is a snapshot. If synthesis breaks after today's edits,
git diffshows exactly what changed. - Branching for tapeout: Keep a
mainbranch for stable RTL and afeature/cdc-fixbranch for risky changes. Merge only when verified. - Team collaboration: Multiple engineers working on different modules merge cleanly. Git tracks who changed what and when.
- IP versioning: Tag RTL versions that match specific synthesis runs —
git tag v1.3-synth-DC2025— and reproduce any run exactly. - EDA tool scripts: TCL scripts, constraint files, and run scripts deserve version control as much as RTL does.
Core Concepts
Git has four distinct areas where files live:
- Working Directory: Your actual files on disk. Where you edit RTL.
- Staging Area (Index): A preview of your next commit.
git addmoves changes here selectively — you can stage only the RTL file, not the half-finished TCL script. - Local Repository: The full history, stored in
.git/. All commits, branches, and tags live here. - Remote Repository: A server copy (GitHub, GitLab, internal server).
git pushuploads;git pulldownloads. - Branch: A lightweight pointer to a commit. Creating a branch is free — one of Git's biggest advantages over SVN/Perforce.
- Commit: A snapshot of staged changes with a message, author, and timestamp. Permanent and immutable once created.
First-Time Setup
# Set your identity (appears in every commit)
git config --global user.name "Your Name"
git config --global user.email "you@company.com"
# Set default editor (for commit messages)
git config --global core.editor vim
# Set default branch name to 'main'
git config --global init.defaultBranch main
# Better diff output — shows word-level changes
git config --global diff.wordRegex "[^[:space:]]"
# Colorized output
git config --global color.ui auto
# Store credentials (for HTTPS remotes)
git config --global credential.helper store
# View your config
git config --list
Basic Daily Workflow
Starting a Repository
# New project from scratch
git init my_rtl_project
cd my_rtl_project
# Clone an existing remote project
git clone https://github.com/company/chip_top.git
git clone git@internal-server:vlsi/soc_design.git
The Everyday Cycle
# 1. Check current state
git status
# 2. See what changed
git diff # unstaged changes
git diff --staged # staged changes (what will be committed)
# 3. Stage specific files
git add rtl/fifo_ctrl.sv
git add constraints/top.sdc
git add -p # interactive: stage specific hunks, not whole files
# 4. Commit with a clear message
git commit -m "Fix CDC synchronizer in fifo_ctrl — 2FF chain missing"
# 5. Push to remote
git push origin main
# 6. Pull latest from teammates
git pull origin main
Writing Good Commit Messages
# Bad — tells you nothing useful later
git commit -m "fix stuff"
git commit -m "update"
# Good — explains WHAT and WHY
git commit -m "Add reset synchronizer to async_fifo — fixes CDC lint error CDC-003"
git commit -m "Update SDC: tighten hold margin on clk_div2 path to 0.1ns"
git commit -m "Refactor APB slave decode — remove redundant mux for synthesis QoR"
Branching & Merging
Branches are Git's killer feature. Creating a branch for a risky RTL experiment costs nothing — no file copying, no extra disk space. If it doesn't work, delete it. If it works, merge it.
Branch Commands
# List branches (* = current)
git branch
# Create and switch to a new branch
git checkout -b feature/add-pipeline-stage
# Modern syntax:
git switch -c feature/add-pipeline-stage
# Switch between branches
git switch main
git switch feature/add-pipeline-stage
# Delete a branch (after merging)
git branch -d feature/add-pipeline-stage
# Force delete (unmerged)
git branch -D feature/bad-experiment
Merging
# Merge a feature branch into main
git switch main
git merge feature/add-pipeline-stage
# Merge with a commit (no fast-forward) — preserves branch history
git merge --no-ff feature/add-pipeline-stage -m "Merge pipeline stage feature"
Rebase — Clean Linear History
# Rebase feature branch onto latest main
git switch feature/cdc-fix
git rebase main
# Interactive rebase — squash/reorder commits before merging
git rebase -i HEAD~3 # edit last 3 commits
main for tape-out-ready RTL only. All work happens in feature branches (feature/), bug fixes in fix/ branches, and tapeout prep in release/v1.0 branches. Merge to main only after synthesis and lint pass.Resolving Merge Conflicts
# Git marks conflicts in the file like this:
<<<<<<< HEAD
assign data_out = fifo_rd_data; // your version
=======
assign data_out = pipeline_rd_data; // incoming version
>>>>>>> feature/pipeline-stage
# Edit the file to keep the correct version, then:
git add rtl/top.sv
git commit # completes the merge
# Or abort the merge entirely
git merge --abort
Stash — Save Work in Progress
You're mid-way through a CDC fix when your manager asks you to check a synthesis run on the clean branch. Git stash saves your uncommitted changes temporarily so you can switch branches cleanly.
# Save current uncommitted work
git stash
git stash push -m "WIP: cdc synchronizer rework"
# List stashes
git stash list
# Restore the most recent stash
git stash pop
# Restore a specific stash
git stash apply stash@{2}
# Stash including untracked files
git stash -u
# Drop a stash
git stash drop stash@{0}
# Clear all stashes
git stash clear
History, Blame & Diff
git log
# Full log
git log
# Compact one-line view (best for orientation)
git log --oneline
# Graph view — see branching visually
git log --oneline --graph --all
# Log for a specific file (track all changes to a constraint file)
git log --oneline constraints/top.sdc
# Search commit messages
git log --oneline --grep="CDC"
# Show changes introduced in each commit
git log -p rtl/fifo_ctrl.sv
# Log since a date
git log --oneline --since="2 weeks ago"
git blame — Who Wrote This?
# Show who last changed each line
git blame rtl/alu.sv
# Blame a specific line range
git blame -L 45,80 rtl/alu.sv
# Show blame ignoring whitespace changes
git blame -w rtl/top.sv
git blame rtl/top.sv immediately shows who added that line, in which commit, and when — giving you the context behind the decision.git diff
# Diff between two commits
git diff HEAD~1 HEAD rtl/fifo_ctrl.sv
# Diff between two branches
git diff main feature/cdc-fix -- rtl/
# Diff between two tags
git diff v1.2 v1.3 -- constraints/
# Show only file names that changed
git diff --name-only main feature/pipeline
Restore and Reset
# Discard changes to one file (restore from last commit)
git restore rtl/top.sv
# Unstage a file (keep changes in working directory)
git restore --staged rtl/top.sv
# Go back to a previous commit (creates a new commit)
git revert HEAD
# Hard reset to a specific commit — DESTRUCTIVE, loses uncommitted work
git reset --hard abc1234
git reset --hard permanently discards uncommitted changes. Always run git status and git stash first if you have work in progress..gitignore for EDA Projects
EDA tools generate massive output directories — simulation waveforms, synthesis databases, log files. These must never be committed. Place this .gitignore at your project root.
# ── Simulation ──────────────────────────────────────────────
work/ # ModelSim/Questa compiled library
sim_build/
*.wlf # Questa waveform files
*.vcd # VCD waveform dumps
*.fst
vsim.wlf
transcript
*.ucdb # coverage databases
# ── Synthesis (Synopsys DC / Genus) ─────────────────────────
WORK/
alib-52/
*.pvl
*.syn
*.mr
*.svf
DC_SHELL/
work_dir/
mapped/
unmapped/
reports/
*.ddc # Design Compiler checkpoint
# ── Cadence ─────────────────────────────────────────────────
.cadence/
cds.lib
hdl.var
xcelium.d/
*.shm/
*.dsn
# ── Vivado / Quartus ────────────────────────────────────────
*.xpr.bak
.Xil/
vivado*.jou
vivado*.log
*.runs/
*.cache/
*.hw/
*.ip_user_files/
db/
incremental_db/
# ── Logs & Temp ─────────────────────────────────────────────
*.log
*.rpt # synthesis / timing reports — regenerate, don't commit
*.bak
*.tmp
*.orig
*~
\#*\#
# ── OS / Editor ─────────────────────────────────────────────
.DS_Store
Thumbs.db
*.swp
*.swo
.viminfo
.v, .sv, .svh), constraints (.sdc, .upf, .xdc), synthesis scripts (.tcl), testbenches, documentation, and the .gitignore itself. Reports and databases are derived artifacts — regenerate them from the committed source.VLSI-Specific Workflows
Tagging Synthesis Runs
# Tag the exact RTL state used for a synthesis run
git tag -a v2.1-synth-DC-2025-05 -m "DC synthesis run May 2025, WNS=-0.02ns"
git push origin v2.1-synth-DC-2025-05
# Checkout a specific tagged version to reproduce a run
git checkout v2.1-synth-DC-2025-05
Comparing RTL Between Synthesis Runs
# What RTL changed between two synthesis tags?
git diff v2.0-synth v2.1-synth -- rtl/
git diff v2.0-synth v2.1-synth -- constraints/top.sdc
Tracking a File's Full Change History
# Every commit that touched this constraint file
git log --oneline -p constraints/top.sdc
# When was a specific timing exception added?
git log --oneline --all -S "set_multicycle_path" constraints/top.sdc
Working with Large Binary Files (LFS)
# Track large binary files (GDS, LEF, lib) with Git LFS
git lfs install
git lfs track "*.gds"
git lfs track "*.lib"
git lfs track "*.lef"
git add .gitattributes
git commit -m "Track large EDA binary files with Git LFS"
Quick Reference
| Command | What it does |
|---|---|
| git status | Show what's modified, staged, and untracked |
| git diff | Show unstaged changes line by line |
| git add -p | Interactively stage specific hunks |
| git commit -m "..." | Commit staged changes with message |
| git log --oneline --graph | Visual branch history |
| git blame file.sv | Show who last changed each line |
| git switch -c branch | Create and switch to new branch |
| git merge branch | Merge branch into current |
| git stash / git stash pop | Save/restore work in progress |
| git restore file.sv | Discard changes to a file |
| git tag -a v1.0 -m "..." | Create annotated tag for a release |
| git revert HEAD | Undo last commit safely (new commit) |
| git log -S "signal_name" | Find when a specific string was added/removed |
| git diff branch1..branch2 | Show all changes between two branches |
Q&A
Use git filter-repo (preferred) or BFG Repo Cleaner to rewrite history and permanently remove the file from all commits. Then force-push: git push --force-with-lease. Alert all teammates immediately — they must re-clone the repository. Old copies still have the sensitive files. This is why a good .gitignore is critical upfront.
Yes — use git-p4, a bridge tool included with Git. You sync from Perforce into a local Git repository, work in Git branches locally, then submit back to Perforce when ready. This lets you use Git's lightweight branching and stash features for local experiments while keeping the team's Perforce workflow intact. Run git p4 clone //depot/chip/rtl/... @all to create a local Git repo mirroring the Perforce depot.
Use pathspec filtering in git diff: git diff v1.0..v1.1 -- '*.sv' '*.v' '*.sdc'. The -- separates git options from pathspecs. You can also use --name-only to see just the list of changed RTL files, then selectively view individual files with git diff v1.0..v1.1 -- rtl/fifo_ctrl.sv.
Generally do not commit auto-generated netlists — they are derived from the RTL source and synthesis scripts, which you do commit. Committing generated files causes noise in diffs, merge conflicts with no human meaning, and bloated repositories. The exception: a formally released gate-level netlist for handoff (to physical design, for example) can be tagged and archived in a separate delivery directory or with Git LFS to preserve the exact artifact for audit purposes.
Use git log -S (the "pickaxe" option): git log -S "set_multicycle_path 2 -setup -from clk_a -to clk_b" --oneline constraints/top.sdc. This searches through the diff of every commit and shows only commits where the count of that string changed — meaning it was added or removed. Add -p to see the actual change context.