Git执行reset/checkout时,内部如何恢复index与工作目录?是否基于提交tree?
checkout/reset --hard: How Index & Working Directory Are Synced to a Commit Great question—let’s break this down clearly, since these commands are all about aligning your working state with a specific commit’s snapshot.
Core Foundation: The Commit’s Tree Object
First, every Git commit points to a root tree object—this is a snapshot of your entire project’s file structure (folders, files, permissions) at the time of the commit. Both git checkout <branch/commit> and git reset --hard <branch/commit> use this tree as the single source of truth to rebuild your index and working directory.
How the Index is Rebuilt
Yes, the index is completely reconstructed from the target commit’s tree object:
- Git starts by wiping the existing index (or replacing it entirely—no partial updates here).
- It traverses every entry in the root tree (including all nested subtrees, which represent folders) and writes each file’s metadata (SHA-1 hash of its content, path, file mode) into the index.
- The end result is an index that’s a perfect mirror of the commit’s tree—no leftover entries from before the command.
How the Working Directory is Restored
The working directory also syncs to the commit’s tree, but the process is a bit more efficient (instead of deleting everything and re-copying):
- Git compares the current state of your working directory against the target tree.
- It will:
- Delete any files that exist in the working directory but not in the target tree.
- Update files whose content doesn’t match the corresponding blob object from the tree.
- Create new files (and folders) that exist in the tree but not in the working directory.
- The end result is identical to if you’d extracted every file from the commit’s snapshot—your working directory will match the tree perfectly.
Do Index & Working Directory Always Match the Commit’s Tree After These Commands?
Absolutely—the moment the command finishes executing, your index and working directory will be 100% aligned with the target commit’s tree.
That said, this alignment only lasts until you make changes: if you edit a file in the working directory, or run git add to stage changes, the index/working directory will start to diverge from the tree. But right after checkout or reset --hard, they’re perfectly in sync.
Do These Restores Depend on the Target Commit’s Tree?
You’re exactly right—Git has no other source to pull this state from. Every commit’s tree is the definitive snapshot of the project at that point in history. Both commands rely entirely on this tree (and the blob objects it points to, which store actual file content) to rebuild the index and working directory. There’s no hidden cache or alternative history source involved—Git only uses the commit’s tree to get the exact state it needs to sync to.
As a quick example: when you run git reset --hard abc123, Git first resolves abc123 to a commit, grabs its root tree SHA-1, then rebuilds the index from that tree, and syncs the working directory to match it. Same goes for git checkout my-branch—it finds the commit that my-branch points to, uses its tree, and syncs everything up.
内容的提问来源于stack exchange,提问作者caffein

