Reputation: 6797
Is it possible to remove a file from git, while keeping the local files for everyone, even after a pull
?
It's a file that was missing from .gitignore
. Is there a way to correct the mistake?
I've seen similar questions, but as far as I know:
--assume-unchanged
is for the local git repo only--skip-worktree
keeps the file in gitgit rm
removes the files for other users after a pull
Edit:
I'm looking for a solution without manually backing up files or rewriting history.
Also I can accept it if it's not possible.
Upvotes: 1
Views: 128
Reputation: 45689
As I understand your constraints, you want the users to keep their files without doing anything special. It isn't really possible. If you can tell them to perform a simple procedure, there's a work-around - but after due consideration, I don't recommend it at all.
First, regarding the methods you mention in the question:
--assume-unchanged
and --skip-worktree
are the wrong answer almost every time they are suggested. They each have a specific purpose for which they were created and shouldn't really be used for other things.
git rm
removes a file from the index (and optionally also your local working tree). In a normal workflow, that means the next commit won't contain the file even if the previous one did. But if, by that or any other means, a file is present in the index and you then check out a commit that doesn't contain that file, the file is removed from the worktree. This is true regardless of the .gitignore status of the file (both in the old and new commit).
Now, previously when I've described this, I've said (somewhat erroneously) "...a file is present in the currently-checked-out commit and you then check out a commit that doesn't contain the file...". In most cases that was close enough to correct as to not matter, but the difference does give us the potential workaround:
Under the correct conditions, each user can remove the file from the index before pulling the new commit, and this should avoid local deletion of the file.
git rm --cached <path/to/file>
git pull
One caveat (and how to deal with it):
The file must be subject to exclusion rules, or git will see the unstaged copy of the file as reason not to allow the checkout. If the user has already pulled a commit with a fixed .gitignore
(which also assumes you fixed .gitignore
in a commit before the one where you remove the file) then this will pose no problem. Otherwise they can temporarily add the file to the .git/info/exclude
file in their local repo.
The problem, if you have more than just the master
branch, is that now you have to worry about the file being deleted every time you move between branches (becaues changing to any given branch might re-add the file to the index, and then moving back to master would delete the file).
Even without branch-switching, every time you restore history from before the file was removed, you risk losing the local copy when returning to a current version. (At this point someone always likes to say how rare it is to check out historical versions... which I find silly, because if I'm not planning for being able to go back in time, what is source control for, really?)
So using this workaround instead of doing a rewrite trades a one-time problem for an ongoing one. Which I can't say I recommend. If you must, then I guess you can mitigate the ongoing issue by creating a local hook that unstages the offending file after every checkout - so that it will always be kept out of the index and subsequent checkouts can't cause the file to be deleted; but
1) I can't guarantee that this won't have other unforeseen side-effects
2) You'll have to communicate to each user that they need to add the hook, and add the file to their local .git/info/exclude
file (because otherwise git will reject checkouts that would've otherwise deleted the file)... and at that point, where you're having to coordinate such effort by every repo user, there's no reason not to just do the rewrite and be done with it.
In fact it's worse than that, because every new clone will need to have the hook set up and the file added to the exclude
file as well, whereas if you do the rewrite once, then you are done with it.
Upvotes: 1