This is entirely normal based on what you said you did.
Files are not tracked-vs-untracked based on branches. Branches, or more precisely, your branch names,1 are entirely irrelevant. Each branch name selects one specific commit, however, and commits are relevant. A commit, once made, is always the same, forever—but the branch names move about, based on what you tell Git to do with them, so the branch names don't matter: it's the commits that matter.
A file you're working with while using Git is said to be tracked if and only if that file is currently in Git's index. The really surprising, and a little mind-bending, part of all of this is that tracked-ness of a file is not even a property of a commit. It tends to be controlled by a commit because we use git checkout
or git switch
to extract a commit. This fills in Git's index from that commit and this is what causes the file to now be a tracked file.
The files you see and work with are not in Git. This is the real key: when people use Git, they tend to think that the files they have in their work-tree are "Git files" or "files in a branch" or something along those lines. This is just wrong. The files you work with—the ones in your work-tree—may have been extracted from a commit. The files stored inside commits are in Git. They get transferred from one Git to another when you use git push
or git fetch
. The files in your work-tree are not in Git.
If Git copied a file out of a commit, to put it into your work-tree, when you ran git checkout master
or git checkout mybranch
or git checkout c0ffee900d
, Git copied that file into Git's index first. (Let's say that all three of these names select commit c0ffee900d
.) So now that file exists in three places (and maybe more commits as well, but at least these three):
- the file is in the commit, which you can see with, e.g.,
git show c0ffee900d:public/foo.html
;
- the file is in Git's index, which you can see with
git show :public/foo.html
;
- and the file is in your work-tree, which you can see because your regular computer programs show you these files, and work with them.
But suppose you now git checkout
some other commit. Pick any other commit, by hash ID, or by branch name. Let's say that this other commit does not store the file public/foo.html
in it. Git now sees that you're moving from some commit that does have public/foo.html
in it, to one that doesn't. So Git:
- removes
:public/foo.html
from Git's index, and
- removes
public/foo.html
from your work-tree
because you told it to.
1See also What exactly do we mean by "branch"? The word branch is ambiguous: sometimes people use it to mean the tip commit of a branch, in which case, the commit itself is relevant, and you found it by using a branch name, so in that sense, your branch name mattered. But tomorrow, you might change the hash ID associated with the branch name, and that could change everything. You cannot change anything about the one specific commit, though, and you can always obtain that commit, using its hash ID.
What you can do about all of this
There is still a copy of c0ffee900d:public/foo.html
in the repository. That copy is as permanent as commit c0ffee900d
: as long as the commit is in the repository, so is that copy of the file. But that file isn't in your work-tree any more because it was tracked—it was in Git's index—and you told Git to switch over to commit badcafe
, or whatever other commit hash ID you chose, and that commit doesn't have that file.
You may wish to go back to having untracked files, and keeping them that way. Untracked files do not get removed or shuffled-about like this. Of course untracked files also are not in each new commit and will not appear in clones, so maybe you don't want to have them untracked. Or maybe you want them to be in some commits and not be in others, and still get them back when you check out one of these other commits.
How to get your files back after switching to some other commit
As long as any given file is untracked—not in Git's index—then switching from this commit to that one won't remove it (though you'll get an interesting gripe):
$ git rm --cached file
rm 'file'
$ git checkout HEAD^
error: The following untracked working tree files would be removed by checkout:
file
Please move or remove them before you switch branches.
Aborting
This happens because the difference between the current commit, in my case 8969ef2
, and the target one bb2af52
, requires removing file file
. I added and committed file file
in commit 8969ef2
.
So, I could now mv file file.keep
, git checkout HEAD^
, and mv file.keep file
. Now it's an untracked file while I work on commit bb2af52
as a detached HEAD.
As an alternative, I can do this:
$ git restore --staged file
$ git status
On branch master
nothing to commit, working tree clean
(This particular git restore
command came straight out of git status
, as its advice for undoing my to-be-committed removal. Other commands, such as git reset -- file
, would have worked as well.)
$ git checkout HEAD^
Note: switching to 'HEAD^'.
You are in 'detached HEAD' state. You can look around, make experimental
...
HEAD is now at bb2af52 initial
My checkout has now succeeded, but I no longer have file file
in my work-tree (nor, of course, in Git's index). Now I get it back using the hash ID 8969ef2
or the branch name master
:
$ git restore --source master file
$ git status
HEAD detached at bb2af52
Untracked files:
(use "git add <file>..." to include in what will be committed)
file
nothing added to commit but untracked files present (use "git add" to track)
There is my file named file
, back in my work-tree as an untracked file, copied out of the commit I chose. If you don't have Git 2.23 or later, use:
git show master:file > file
rather than
git restore --source master file