记录一下GIT的各种删除操作,删除操作用的比较少,经常忘记,每次要用的时候都现搜 ## 删除Git历史提交中的大文件 作者:阿斯蒂芬 链接:https://www.zhihu.com/question/54419234/answer/2538641471 来源:知乎 著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。 - 显示大文件路径与文件名 - - 以便分析文件类型, 后续通过适配符批量删除 - 追查大文件来源 - - 分析来自哪个branch哪个commit, 由谁提交 - 以便预防类似问题二次发生 ### 1.显示当前最大的10个文件: ```sh git verify-pack -v .git/objects/pack/pack-*.idx | sort -k 3 -g | tail -10 ``` 会显示类似如下列表(共10行), 其中第一大段为文件的**ID** **10d4c5bea321160601323af6464277f5c0000000** *blob 7367001 6000049 160008000* **7d48cc9a0000000000abbd55aeda21207db1d4** *blob 7367000 6100048 160008924* ### 2. 根据ID 反查文件名(二选一) #### 2.1 只需要文件名(简单场景) ```sh git rev-list --objects --all |grep 10d4c5bea321160601323af6464277f5c0000000 ``` #### 2.2 反查更详细的文件信息(多branch场景) ```sh git whatchanged --all --find-object=10d4c5bea321160601323af6464277f5c0000000 ``` 输出将会包含以下信息: - commit (branch) - Author - Date - path and file name ### 3. 根据文件名在历史记录中批量删除 替换下列代码中的 path_to_file为希望删除的文件名, 支持*[通配符](https://www.zhihu.com/search?q=通配符&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2538641471}) ```sh git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch path_to_file' --prune-empty --tag-name-filter cat -- --all ``` 举例: ```sh git filter-branch --force --index-filter 'git rm --cached --ignore-unmatch */*/*.png' --prune-empty --tag-name-filter cat -- --all ``` 如果你的文件名包含空格, 则应交替使用单双引号: ```sh git filter-branch --force --index-filter \ "git rm --cached --ignore-unmatch 'src/file name with blank'" ``` 注意: 只能删除当前所在branch的文件, 所以如果文件来自于另一个branch, 应先切换branch: ```sh git checkout that_branch ``` 如果删除文件的所在分支已经不存在,可以通过查看日志恢复那个分支 ```sh #通过git reflog找到最后一次的提交记录 git reflog #进行恢复 比如要恢复的分支名和提交记录id分别为dev-web-config 3c96c99 git checkout -b git checkout -b dev-web-config 3c96c99 ``` #### 预期terminal输出: 少量文件成功被删除: *rm 'some-file.png'* 大量历史commit被重写: *Rewrite 7930b2dd7bff910000000000000000001a8cdf7014 (1512/1721) (41 seconds passed* 最终一些branch可能没有变化: *WARNING: Ref 'a_branch' is unchanged* 但是有些branch被改写了: *b_branch -> b_branch* ### 4. (可选项) 更新本地Git仓库 删除操作之后, 再用第2步的指令查询对应ID不会返回任何值, 表明文件已删除; 但用第1步的指令查询前10的大文件会发现列表并没有变化, 如需要查询经过上一步删除之后的新前10大文件, 则需要更新本地Git仓库 (ps. 也可以将第1步指令末尾改为20, 查看前20的大文件) > 此时你会发现本地目录中的.git文件并不会马上就变小,而是与原来是一样的, > 是因为Git仓库历史有个缓存期,如果不主动回收、清理仓库历史,一般的这些记录还会保存一段时间,以备你突然后悔了,没办法找回删掉的文件。 > 通过以下命令主动回收资源: ```sh rm -rf .git/refs/original/ git reflog expire --expire=now --all git gc --prune=now git gc --aggressive --prune=now ``` 以上仓库更新代码, 合并至一行: ```sh rm -rf .git/refs/original/;git reflog expire --expire=now --all;git gc --prune=now;git gc --aggressive --prune=now ``` ### 5. 更新到远程服务器 ```sh git push --force --all ``` > 如果出现提示remote: GitLab: You are not allowed to force push code to a protected branch on this project. > 需要在[gitlab](https://www.zhihu.com/search?q=gitlab&search_source=Entity&hybrid_search_source=Entity&hybrid_search_extra={"sourceType"%3A"answer"%2C"sourceId"%3A2538641471})里面取消分支protected 在多人共同修改的分支上, 建议改用以下命令进行push, 以预防冲突 ```sh git push --force-with-lease ``` ### 6.(可选项)在其他本地机器上进行强制更新 即如何进行force pull. 这里以master branch为例: ```sh git checkout master git branch new-branch-to-save-current-commits git fetch --all git reset --hard origin/master ``` 如果有删除远程分支操作: ```sh git branch -D git remote update origin --prune ``` ### 删除因为.gitignore未设置忽略上传到远程仓库的文件 有些新项目可能没有设置好.gitignore导致上传一些文件到远程仓库,比如``.vscode`,`.idea`这种文件 一般处理方式我说三种: #### 1.在仓库中添加一个.gitignore文件,可以忽略指定文件夹或文件,从而避免将.idea文件夹提交上去。在.gitignore文件中添加以下代码即可忽略.idea文件夹内容,(删除不掉已经上传到远程的) ```text .idea/ ``` #### 2.使用git filter-branch命令,将.idea文件夹从提交历史中删除。这个方法需要谨慎使用,因为它可以修改提交历史,可能会影响到其他人的工作。如果确定只有自己在使用该仓库,可以使用以下命令: ```sh git filter-branch --tree-filter 'rm -rf .idea' HEAD ``` #### 3.使用git rm命令,删除.idea文件夹,并将删除的操作提交到仓库中。这种方法简单易行,但是需要注意的是,需要先提交一个删除操作,才能生效。具体的步骤如下: ```sh git rm -r --cached .idea git commit -m "remove .idea folder" git push origin master ``` 建议第一种和第二种配合使用