Git’s three “trees” are the conceptual anchor that disambiguates restore, reset, and checkout. The trees: HEAD (the last commit), the index (staging area), and the working tree (your files on disk). Each command operates on a different combination of these, and once that’s clear the apparent overlap stops being confusing.
git restore is file-scoped and never moves the branch pointer. git restore file.txt syncs working tree to index; git restore --staged file.txt syncs index to HEAD. git reset is the only one of the three that moves the branch pointer: --soft moves HEAD alone, the default also resets the index, and --hard cascades to the working tree (the only common Git command that silently destroys uncommitted work). git checkout is the legacy do-everything tool. git checkout main switches branches, git checkout -- file.txt discards file changes, git checkout abc123 -- file.txt restores a file from a commit. Same verb, three unrelated operations.
Git 2.23 (2019) split checkout’s responsibilities into git switch (branch operations) and git restore (file operations) because the overloading was a bug magnet: git checkout foo silently does wildly different things depending on whether foo is a branch, file, or commit. The takeaway: file-level edits go through restore, branch movement through switch, and reset is the only command that rewrites history. Reach for checkout only when reading old tutorials.