You changed a file and now the test fails. How do you see what changed and get back to the last good version?
You edited the counter, reran the test, and watched it fail. Your memory of the edit is already fading: which line did you touch, and what did it say before? Guessing means retyping, and retyping means new mistakes. Version control answers both questions with evidence instead of memory.
Git is the version control tool this course uses: it records snapshots of your files so you can compare any two moments and return to either. A repository is a folder Git watches, a commit is one snapshot with a message saying why it exists, and the three commands below move changes between the three places a change can live.
Look at the figure first, then read the words under it. A change starts in the working folder, which is your files on disk. git add drafts it into the staging area, which is what the next snapshot will hold. git commit seals the draft into the commit history, which is the permanent record you can return to. git diff compares the first two places, git restore throws away the draft or the edit, and git status --short plus git log --oneline report on each end.
The transcript below runs inside the example project and builds a baseline in two steps. Home paths are shortened the same way as in the shell lesson. These runs were measured on macOS with Git 2.54.0. Commit hashes in your own run will differ from the ones printed here: each hash covers the exact content and moment, so identical commands on your machine produce different letters and numbers, and that difference is expected.
# captured terminal output
$ git init -q -b main && git status --short | head -n 3
?? .gitignore
?? Makefile
?? README.mdThis starts version control and asks what is new. git init -q -b main creates the repository quietly on a branch called main, and git status --short lists untracked names with ??: files Git sees but no snapshot claims yet.
# captured terminal output
$ git add rtl tb docs scripts Makefile .gitignore && git commit -m 'Add mini controller baseline' | head -n 2 && git log --oneline -n 3
[main (root-commit) 8b5bc6b] Add mini controller baseline
10 files changed, 318 insertions(+)
8b5bc6b Add mini controller baselineThis drafts and seals the baseline. git add moves the named source files into the staging area, git commit -m seals them into history with a message, and git log --oneline -n 3 shows the newest snapshots one per line. The line after the commit message counts the files and lines the snapshot holds. Those counts depend on your project, and your commit hash will differ from the one shown.
One setup step comes before your first commit on any machine, and it needs no transcript. Tell Git who you are with git config --global user.name "Your Name" and git config --global user.email "you@example.com", using your real name and address. Every commit you seal carries that identity, so future you and your teammates know whose snapshot they are reading.
Now break the design the way a tired afternoon breaks it: one digit changes and nothing else. The transcript edits the counter so each event adds 2 instead of 1, then asks Git what moved. Read the diff output line by line: it is the whole diagnosis.
# captured terminal output
$ sed -i.bak 's/4.d1;/4'"'"'d2;/' rtl/mini_controller.sv && rm rtl/mini_controller.sv.bak && git status --short && git diff --stat
M rtl/mini_controller.sv
?? README.md
?? constraints/
?? github-workflows/
?? model/
?? tools/
rtl/mini_controller.sv | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)The edit changes count + 4'd1 into count + 4'd2, and git status --short answers with M rtl/mini_controller.sv: one file modified, nothing staged. The --stat summary counts the damage as one insertion and one deletion in one file, which is exactly the size of a one-digit mistake.
# captured terminal output
$ git diff | sed -n 1,16p
diff --git a/rtl/mini_controller.sv b/rtl/mini_controller.sv
index c20f7e9..2a01271 100644
--- a/rtl/mini_controller.sv
+++ b/rtl/mini_controller.sv
@@ -14,6 +14,6 @@ module mini_controller (
else if (clear_count)
count <= 4'd0;
else if (event_valid)
- count <= count + 4'd1;
+ count <= count + 4'd2;
end
endmoduleThe full git diff shows the wound and nothing else. Lines starting with - are the snapshot version, lines starting with + are your working folder, and the @@ header names where in the file to look. The test fails because of this line and only this line: the diagnosis took one command and left no room for guessing.
git restore rtl/mini_controller.sv. What will git status --short show afterwards?The M rtl/mini_controller.sv line will be gone, because the working file matches the snapshot again. The untracked ?? names stay: restore only undoes tracked edits and never touches files no snapshot claims. The transcript below confirms both halves.
# captured terminal output
$ git restore rtl/mini_controller.sv && git status --short && echo clean
?? README.md
?? constraints/
?? github-workflows/
?? model/
?? tools/
cleanThe fix is one command and the proof is immediate. git restore copies the snapshot version back over your edit, the modified line vanishes from the status, and echo clean confirms the design file is back to its baseline. The untracked names remain, which is correct: they were never broken, so there is nothing to heal.
The last transcript block runs a simulation and checks the ignore rules from the previous lesson. Output is discarded with > /dev/null 2>&1 because the verdict is not the point here: the status listing is.
# captured terminal output
$ make sim > /dev/null 2>&1; git status --short; cat .gitignore | head -n 3
?? README.md
?? constraints/
?? github-workflows/
?? model/
?? tools/
# Generated by make: never commit these
build/
*.vcdThe status after a full simulation shows no new tracked or modified files: the compiled output, logs, and waveforms all landed where .gitignore covers them. The cat of the ignore file confirms the first rule doing the work: build/ is generated by make and never committed. A green run that dirties version control is a run with a missing ignore rule, and this check catches it in one line.
Committing build output. You git add a waveform or a compiled binary and seal it into history, where every future download carries it. Fix: keep generated patterns in .gitignore, check git status --short after each build, and never force-add a file the ignore rules cover.
Sweeping with `git add .`. The dot stages everything new, including files you never meant to save, because it cannot tell source from exhaust. Fix: add paths by name, as the transcript does, and read the status before every commit so each snapshot holds exactly what its message claims.
Restoring a file you saved nowhere else. git restore discards your edit permanently: there is no undo for the undo. Fix: commit or copy anything you might want before you restore, and treat restore as the last step of a diagnosis, never the first reflex.
Rule: commit source you can describe, diff before you fix, and restore only what a snapshot already holds.
git status --short first: it names which files moved and whether each change is staged or only in the working folder. git diff second: it shows the changed lines themselves, working folder against the staging area. Status finds the file, diff finds the line.
rtl/mini_controller.sv with a broken experiment and saved nothing. Recover the last good version without touching any other file.Run git restore rtl/mini_controller.sv and rerun git status --short to confirm the M line is gone. If the last good version is older than the newest commit, name that commit: git log --oneline finds its hash, and git checkout <hash> -- rtl/mini_controller.sv brings back that version of the file while leaving everything else alone.
git log --oneline shows your commit but your teammate cannot see it. What is missing?Nothing is broken: a commit lives in your repository until you share it. The lesson seals snapshots locally, and sending them elsewhere is a later step. What matters now is that git log --oneline lists it, which proves the snapshot exists and names its message.
A commit is a snapshot with a message; add drafts into staging, commit seals into history.
Status names what moved, diff shows the changed lines, and log lists the snapshots you can return to.
Restore discards edits permanently, and ignore rules keep generated output out of every snapshot.