Git永久删除文件和历史记录

造成你想从git存储库中永久删除文件和历史记录的可能有:

  • 你不小心将一个不该加入版本管理的文件加了进去,敏感数据或大文件或别的没用的文件;
  • 你不小心将一个涉及到破解某著名软件的文章加了进Github仓库,这时你就会收到github官方的邮件来提醒你需要完全删除该文件,不然就会遭到git仓库被封禁。
  • 你希望将敏感数据或无用文件从版本库中永久删除不留痕迹,不仅仅在版本历史里看不出来,还要把它占用的空间也释放出来。

参考官方链接,github 的帮助文档:

https://help.github.com/articles/remove-sensitive-data

很详细的说明了步骤和提供了一种使用BFG工具的思路(更便利)

这里我只说使用git命令的方式,以windows平台下为例,linux类似做法:

使用filter-branch

注意: 如果在存储更改后运行git filter-branch,则无法使用其他存储命令检索更改。

在运行git filter-branch之前,建议取消所做的任何更改。要unstash最后一组隐藏的更改,运行git stash show -p | git apply -R。有关更多信息,请参阅https://git-scm.com/book/en/v1/Git-Tools-Stashing。

演示如下:

进入git存储仓库,运行以下命令,用要删除文件的相对路径(而不仅仅是文件名)替换PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA

这行长命令的参数做到的事是:

  • 强制Git处理(但不检出)每个分支和标记的全部历史;

  • 删除指定的文件,以及由此生成的任何空提交;

  • 覆盖你现有的tags

    $ git filter-branch --force --index-filter \
    'git rm --cached --ignore-unmatch PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA' \
    --prune-empty --tag-name-filter cat -- --all

    其中, PATH-TO-YOUR-FILE-WITH-SENSITIVE-DATA 就是你要删除的文件的相对路径(相对于git仓库的根目录), 替换成你要删除的文件路径即可. 注意一点,这里的文件或文件夹,如果以 '/' 开头,则文件或文件夹会被认为是从 git 的安装目录开始。

    如果你要删除的目标不是文件,而是文件夹,那么请在 git rm --cached 命令后面添加 -r 命令,表示递归的删除(子)文件夹和文件夹下的文件,类似于 rm -rf 命令。

    如果你要删除的文件很多, 可以写进一个.sh文件批量执行, 如果文件或路径里有中文, 由于MinGW或CygWin对中文路径设置比较麻烦, 你可以使用通配符*号, 例如: sound/music_*.mp3, 这样就把sound目录下以music_开头的mp3文件都删除了.

    例如:新建一个 bash 脚本文件,del-music-mp3.sh:

    #!/bin/bash
    
    git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch projects/Moon.mp3' --prune-empty --tag-name-filter cat -- --all
    git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch sound/Music_*.mp3' --prune-empty --tag-name-filter cat -- --all

    如果你看到类似下面这样的, 就说明删除成功了:

    Rewrite 48dc599c80e20527ed902928085e7861e6b3cbe6 (266/266)
    # Ref 'refs/heads/master' was rewritten

    如果显示 xxxxx unchanged, 说明repo里没有找到该文件, 请检查路径和文件名是否正确.

实际例子操作如图:

添加到.gitignore文件里并push修改后的repo

如果想以后也不会再上传这个文件或文件夹, 请把这个文件或文件夹添加到.gitignore文件里, 然后再push你的repo.

添加到.gitignore文件:

$ echo "YOUR-FILE-WITH-SENSITIVE-DATA" >> .gitignore
$ git add .gitignore
$ git commit -m "Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore"
[master 051452f] Add YOUR-FILE-WITH-SENSITIVE-DATA to .gitignore
1 files changed, 1 insertions(+), 0 deletions(-)

再次检查是否已经从存储库的历史记录中删除了所有想要删除的内容,以及是否检出了所有分支。

以强制覆盖的方式推送你的repo, 命令如下:

git push origin --force --all
Counting objects: 1074, done.
Delta compression using 2 threads.
Compressing objects: 100% (677/677), done.
Writing objects: 100% (1058/1058), 148.85 KiB, done.
Total 1058 (delta 590), reused 602 (delta 378)
To https://github.com/YOUR-USERNAME/YOUR-REPOSITORY.git
+ 48dc599...051452f master -> master (forced update)

这个过程其实是重新上传我们的repo, 比较耗时, 虽然跟删掉重新建一个repo有些类似, 但是好处是保留了原有的更新记录, 所以还是有些不同的. 如果你实在不在意这些更新记录, 也可以删掉重建, 两者也差不太多, 也许后者还更直观些。

为了能从打了 tag 的版本中也删除你所指定的文件或文件夹,您可以使用这样的命令来强制推送您的 Git tags:

$ git push origin master --force --tags

告诉您的协作者,从您的旧(受污染的)存储库历史中重新创建分支,而不是合并它们。一个合并提交可能会重新引入一些或所有您刚刚陷入清除麻烦的受污染的历史。

清理和回收空间

经过一段时间之后,您确信git filter-branch没有意外的副作用,您可以使用以下命令强制解除对本地存储库中的所有对象的引用和垃圾回收(GC)。

$ git for-each-ref --format='delete %(refname)' refs/original | git update-ref --stdin
$ git reflog expire --expire=now --all
$ git gc --prune=now
Counting objects: 2437, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (1378/1378), done.
Writing objects: 100% (2437/2437), done.
Total 2437 (delta 1461), reused 1802 (delta 1048)

您还可以通过将过滤后的历史推入一个新的或空的存储库,然后从GitHub创建一个新的克隆来实现这一点。

上面命令的第一句也可以换成:

$ rm -rf .git/refs/original/

参考自:

https://help.github.com/articles/removing-sensitive-data-from-a-repository/

https://www.cnblogs.com/shines77/p/3460274.html

文:铁乐与猫

2018-11-17

【end】

Git永久删除文件和历史记录的更多相关文章

  1. Git如何永久删除文件(包括历史记录)

    有些时候不小心上传了一些敏感文件(例如密码), 或者不想上传的文件(没及时或忘了加到.gitignore里的), 而且上传的文件又特别大的时候, 这将导致别人clone你的代码或下载zip包的时候也必 ...

  2. 【Git的基本操作四】永久删除文件后找回

    永久删除文件后找回 1. 已经添加到本地库的文件 使用 reset 命令回退到未删除的历史记录即可 2.添加到缓存区,没有提交到本地库的文件找回 git reset --hard HEAD 命令即可找 ...

  3. git仓库删除所有提交历史记录

    stackoverflow原问题地址:http://stackoverflow.com/questions/13716658/how-to-delete-all-commit-history-in-g ...

  4. git 批量删除文件夹和文件

    git 批量删除文件夹和文件 硬盘删除文件后,执行$ git status   会提示你仍然需要$ git rm <文件>   此时如果是要删除大批量文件,这么一个一个命令下去不得累死人啊 ...

  5. Git学习 -- 删除文件

    1 从版本库删除文件 git rm <file> git commit -m "xxx" 2 工作区中文件被误删,但版本库中没有删除,可以恢复到工作区 git chec ...

  6. git批量删除文件和批量提交

    1. 单个删除文件: ① 通常直接在文件管理器中把没用的文件删了,或者用rm命令删了:(可选操作,可直接执行②删除) $ rm test.txt ② 确实要从版本库中删除该文件,那就用命令git rm ...

  7. Git项目删除文件

    场景:项目中有一个文件test_exam_copy 文件之前提交上去的,现在不想要,本地也不要 方案一(手动图示删除): 直接登录到gitLab上面,进入该文件详情,直接删除,然后本机push下,则库 ...

  8. git 命令删除文件操作

    在github上只能删除仓库,却无法删除文件夹或文件, 所以只能通过命令来解决 1.添加文件并提交命令 2.推送到git服务器命令 3.删除文件并提交命令 4.推送到git服务器 查看下git 是否存 ...

  9. 『现学现忘』Git基础 — 35、Git中删除文件

    目录 1.删除文件说明 2.删除文件操作 (1)仅删除暂存区的文件 (2)完全删除文件 3.本文用到的命令总结 1.删除文件说明 在Git工作目录中要删除某个文件,首先要清楚该文件所处的状态. 若要是 ...

随机推荐

  1. 【NGINX】配置文件

    ######Nginx配置文件nginx.conf中文详解##### #定义Nginx运行的用户和用户组 user www www; #nginx进程数,建议设置为等于CPU总核心数. worker_ ...

  2. Spring Boot + Spring Cloud 实现权限管理系统 后端篇(二十三):配置中心(Config、Bus)

    在线演示 演示地址:http://139.196.87.48:9002/kitty 用户名:admin 密码:admin 技术背景 如今微服务架构盛行,在分布式系统中,项目日益庞大,子项目日益增多,每 ...

  3. rabbitMQ和对应的erlang版本匹配

    来源自https://www.rabbitmq.com/which-erlang.html erlang安装包下载地址 https://packages.erlang-solutions.com/er ...

  4. GTest的安装与使用

    安装GTest 1.安装源代码 下载gtest,release-1.8.0 git clone https://github.com/google/googletest gtest编译 cd goog ...

  5. laravel 制作购物车流程

    ① 购入车数据如何存放? 创建数据表 用户ID 购物时间 缺点: 对服务器有压力. 方案: 定时删除 coolie中: 缺点: 数据不能跨客户端 优点:不会对服务器产生压力 放东西和数量 显示购物车 ...

  6. FCKEditor的使用步骤

    在线发布信息难免要用到在线编辑器,下面就说下在线编辑器的使用步骤: 1.下载FCK,这个不说了 2.把ZZGSEditor文件夹放到网站根目录 3.把FredCK.FCKeditorV2.dll文件放 ...

  7. 【原】PHP从入门到精通2小时【图文并茂】

    原创内容,转载请注明. 主要内容: 搭建PHP开发环境 第一个helloworld程序 变量 全局变量 循环结构 函数 数组 面向对象编程 继承 接口 多态 日志 文件的读写 时间格式和时区 创建图形 ...

  8. java中的序列化

    遇到这个 Java Serializable 序列化这个接口,我们可能会有如下的问题 a,什么叫序列化和反序列化b,作用.为啥要实现这个 Serializable 接口,也就是为啥要序列化c,seri ...

  9. Maven + SSM + Kaptcha 实现用户登录时验证码的获取(问题:302 Found)

    pom.xml(对Kaptcha.jar的引用) <!-- 验证码 jar kaptcha--> <dependency> <groupId>com.github. ...

  10. 网络编程学习二(IP与端口)

    InetAddress类 封装计算机的ip地址,没有端口 // 使用getLocalHost方法创建InetAddress对象 InetAddress addr = InetAddress.getLo ...