Reputation: 13823
I used GitHub's instructions for scrubbing a file from the commit history, but it deleted the file in question from my system. This was surprising to me because the git rm --cached
command itself should leave the file itself untouched. But this behavior can also be seen in the worked example on that page: try running ls
before and after the big git filter-branch ...
command.
I'm using Git 2.6.1.
How can I delete a file from the commit history without deleting the file itself? Obviously I could just make a backup (which I did in my case), but that's a workaround and not a solution.
Upvotes: 3
Views: 352
Reputation: 9994
(It needs to be said.)
When using git filter-branch
you are doing history rewriting in an automated manner according to your own (maybe buggy) specification. Thus you should make a backup of your repo before doing that, anyway, or perform the operation on a fresh separate clone of your repo.
git filter-branch
applies the specified command to each applicable commit. However, it doesn't check out those commits in your working copy to do that. Instead, it checks them out into .git-rewrite/
by default, or to the directory you gave with the -d
option. (See git filter-branch
documentation, option -d <directory>.)
After having rewritten the applicable commits, Git checks out the resulting new branch. As this is a switch from a branch with the file (the pre-rewrite version of that branch) to one without the file (the post-rewrite version of that branch), the file is deleted from your working copy, too.
Well, make a backup.
(Note that a tag or branch won't be an adequate backup if you're rewriting all branches and all tags as is done in the example at https://help.github.com/articles/remove-sensitive-data/.)
See Schwern's answer.
Upvotes: 4
Reputation: 164669
When git-filter-branch
is done it checks out the new branch head. This will update your working directory to a clean state. The file you wanted obliterated from history has been obliterated. Backing up beforehand is the solution.
If you forgot to back it up, you can still get it back! Git takes a long time to throw things out, your original commits are still in there. After git-filter-branch
there will be a branch called original/refs/heads/master
(if you filtered master) which contains the original commits. You can recover the file from there.
In general, you can recover filters and rebases using git reflog
. It's a log of every time HEAD
changes (ie. you checkout or rebase or merge or filter or...). For example, after doing the Github filter example, git reflog
is...
abaabaf (HEAD -> master, origin/master, origin/HEAD) HEAD@{0}: filter-branch: rewrite
8ef0c30 (refs/original/refs/remotes/origin/master, refs/original/refs/heads/master) HEAD@{1}: clone:
I can use 8ef0c30
or HEAD@{1}
(ie. the previous location of HEAD
) or original/refs/remotes/origin/master
or original/refs/heads/master
to get back to where things were before the filter ran.
Upvotes: 4