user3435009
user3435009

Reputation: 859

How do you permanently untrack a file that's already tracked by the repository in git?

How do you untrack permanently a file that's already tracked by your repository (every branch has it). I noticed .gitignore only works when the file is not already tracked by the repository and if it's already included you need to keep changing the file whenever you switch to a branch. I don't want to keep changing the file every time I change the branch. I have hardcoded a variable in order to avoid some problem when debugging during development and I am tired of re-hardcoding the variable every time I switch to a different branch. Also, I don't want to enter git rm --cached in the console after re-hardcoding the file.

Upvotes: 2

Views: 3038

Answers (1)

torek
torek

Reputation: 487745

Definition: In Git, "untracked" simply means "not in the index".

Consequence: The tracked or untracked state of any given file depends on what's in the index at the moment.

Problem: "What's in the index" goes there when you do either git add (which puts things in), git rm (which takes things out), or—this is the kicker—git checkout.1 Now, you, as the user, control when you run git add or git rm, so you can control when and whether you put something in the index yourself. But you have much less control when you git checkout a whole commit.

If the commit you are checking out has the file, the file goes into the index. It is now tracked. You can only "de-track" it by removing it. You can of course use git rm --cached, which removes it only from the index, leaving it untouched in the work-tree. That covers you until you git checkout another commit that also has the file, putting it back into the index.

Workarounds: You can mark an index entry as "Git may, but need not, assume this file is unchanged" or even "Git should, as much as possible, try to keep this file unchanged." The latter is stronger and therefore probably the one to use. However, this does not actually make the file be unchanged: it just makes Git work hard not to change it. This way you can get warnings or errors on attempts to git checkout a commit that would change or remove it, but you must still manually preserve it (getting it out of the way in the process), then change commits, then put it back along with the flag. See Git - Difference Between 'assume-unchanged' and 'skip-worktree' for more.


1That is, the kind of git checkout that changes commits. There's another kind of git checkout that merely changes files. When you use this kind of git checkout you can list which files to check out. It's not really a suitable workaround, though. The ultimate solution is never to switch to a commit that has the file in it—which means, never check it in. If you have already checked it in, you are kind of stuck: you can use commands like git filter-branch or the BFG to rewrite the repository as one that does not have the file committed, but this is a painful solution.

You can of course make, on every branch that has the file, a new commit that has removed the file, so that switching from branch to branch now no longer has the file as tracked. However, checking out any old commit that does have the file, causes the file to go into the index and therefore be tracked.

Worse, listing the file in .gitignore—which is something you generally want, to keep it from becoming tracked again—tells Git to feel free to clobber the file.

Upvotes: 4

Related Questions