How does Git restore index and wokring directory internally (upon reset/checkout)?

484 Views Asked by At

I understand that when I checkout or reset --hard to a specific commit/branch then I get the relevant contents in my working directory and the index file.

But how does Git internally re-build the index and working directory contents upon checkout or reset --hard.

Is the index restoration done by reading the tree pointed to by the the commit we have checked-out/reset to ?

Is the working directory also restored the same way ?

Does that mean that after reset --hard or checkout <some_branch> the index and working directory will always match the tree of that commit because they were rebuilt from it ?


Editing: What I'm basically asking: is the restoration of the index/WD content done using the tree pointed by the commit we have arrived at ? Because as I see it there is no other way for git to fetch that content rather than from the commit history

2

There are 2 best solutions below

4
On BEST ANSWER

Does that mean that after reset --hard or checkout the index and working directory will always match the tree of that commit because they were rebuilt from it ?

Short answer: YES

Long answer:

git checkout:

Updates files in the working tree to match the version in the index or the specified tree.

https://git-scm.com/docs/git-checkout

git-reset --hard:

Resets the index and working tree. Any changes to tracked files in the working tree since are discarded.

https://git-scm.com/docs/git-reset

Both of these commands move HEAD, which then inspects whatever commit its been moved to, and alters the index and/or WD accordingly. If it doesn't alter one or both, it still acts as the keeper of the state of your files at the time of that commit and allows you to run commands to compare your WD and index to the state of your files at that moment in time.

I hope that is helpful, I was unsure as to exactly what you are looking for with your question.

0
On

Not exactly. At least, not for the working directory.

Honestly it took me a few minutes to figure out what your question could mean. You're asking if the working directory will end up matcing the checked-out commit after running a command that you say you know sets the working directory to match the checked-out commit, so the question is... a little murky.

But there ARE situations where the working directory will end up different from what's in the checked-out commit. For example, ignored (or otherwise untracked) files will generally be undisturbed. In some cases that's not possible; maybe I have an untracked file named foo, but the target tree has a file also named foo at the same path. Different commands handle that differently. (And here it's important to note, checkout commit is a VERY different command from checkout commit -- path.) Some commands will clobber your local untracked data (which will then be unrecoverable, at least as far as any git mechanism is concerned), while others will abort and warn you that local changs would be overwritten.

So, it is not strictly correct to say the working tree is "rebuilt" from the target tree - in that the directory is not entirely rm'd and then recreated from the tree data. Rather, files are added, deleted, or replaced as necessary (which is a more efficient procedure anyway).

For the index: it's harder to show any "symptom" of the index not being fully rebuilt, because there is no analogous concept to untracked files in the index. I would expect git to take advantage of the hashes it stores for everything, so that it again would just change what needs changing instead of fully rebuilding; but I'm not 100% sure in this case and it's an implementation detail that doesn't really matter. If you tell git to set the index to match a commit, the index will match the commit.