简体   繁体   中英

Remove a file from Git history without deleting the file

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.

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.

First of all:

(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.

Why the file also vanishes from your working copy

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.

How you can preserve the file

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/ .)

How you can retrieve the file if you haven't done that

See Schwern's answer .

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM