Files
My-Notes/笔记/Git/清理Git历史中的本地目录模板.md
T

270 lines
5.6 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 清理 Git 历史中的本地目录模板
这份模板用于把某个已经推送过的本地目录,从远端仓库的历史提交中移除。
适用场景:
```text
某个目录已经被 push 到远端
后来发现它不适合公开,例如简历、密码本、密钥、隐私资料
希望远端最新版本和历史提交中都不再包含它
但本地仍然要保留这个目录
```
## 参数
把下面这些参数替换成自己的实际值:
```text
<原仓库路径> 当前正在使用的本地仓库路径
<旧仓库备份路径> 原仓库的备份路径
<清理仓库路径> 新 clone 出来的临时清理仓库路径
<远端地址> GitHub/Gitee 等远端仓库地址
<分支名> 要重写并推送的分支,例如 master 或 main
<目录路径> 要从历史中移除的目录,例如 简历/
```
多个目录可以写多个 `--path`
```powershell
git filter-repo --path "<目录1>/" --path "<目录2>/" --invert-paths
```
## 重要提醒
如果目录里包含密码、Recovery Key、Token 等敏感信息,应先更换或吊销这些信息。
清理 Git 历史只能减少仓库历史中的暴露,不等于保证已经泄露的信息重新安全。
重写历史后,提交 ID 会变化,因此远端需要强推:
```powershell
git push --force-with-lease origin <分支名>
```
`--force-with-lease``--force` 更安全。它会先检查远端分支是否仍停在本地记录的位置,避免覆盖别人新推送的提交。
## 流程
### 1. 检查原仓库状态
进入当前本地仓库:
```powershell
cd "<原仓库路径>"
git status
```
如果有未提交修改,先提交、备份或手动处理。不要在状态混乱时重写历史。
### 2. 备份原仓库
把当前仓库复制或改名保留:
```powershell
cd "<原仓库的上级目录>"
ren "<原仓库文件夹名>" "<旧仓库备份文件夹名>"
```
也可以用资源管理器手动复制一份。
重点是保留本地私有目录,后面要从 old 里复制回新仓库。
### 3. 在非同步目录重新 clone
建议不要在 OneDrive、网盘同步目录里执行历史重写。
```powershell
cd "<临时工作目录>"
git clone <远端地址> "<清理仓库文件夹名>"
cd "<清理仓库路径>"
```
### 4. 清理历史
清理单个目录:
```powershell
git filter-repo --path "<目录路径>/" --invert-paths
```
清理多个目录:
```powershell
git filter-repo --path "<目录1>/" --path "<目录2>/" --invert-paths
```
说明:
```text
--path 指定要匹配的路径
--invert-paths 反转选择,保留其他路径,移除指定路径
```
如果提示不是 fresh clone,可以在确认备份无误后使用:
```powershell
git filter-repo --force --path "<目录路径>/" --invert-paths
```
### 5. 检查并恢复 remote
`git filter-repo` 可能会删除 `origin` remote。
检查:
```powershell
git remote -v
```
如果没有输出,重新添加:
```powershell
git remote add origin <远端地址>
```
### 6. 修改 .gitignore
把本地要保留、但以后不再提交的目录写入 `.gitignore`
```gitignore
/<目录路径>/
```
例如:
```gitignore
/简历/
```
提交 `.gitignore` 修改:
```powershell
git add .gitignore
git commit -m "Ignore local-only directory"
```
### 7. 获取远端状态
执行:
```powershell
git fetch origin
```
`fetch` 不是合并。它只是把远端当前状态下载到本地,例如更新 `origin/<分支名>`
这里的作用是让 `--force-with-lease` 能检查远端分支是否被别人更新过。
### 8. 强推清理后的历史
```powershell
git push --force-with-lease origin <分支名>
```
如果成功,远端 `<分支名>` 会被替换成清理后的新历史。
### 9. 检查清理结果
检查历史中是否还存在目标目录:
```powershell
git log --all -- "<目录路径>/"
```
没有输出,说明当前可见历史里已经找不到这个目录。
也可以检查远端分支:
```powershell
git fetch origin
git log origin/<分支名> -- "<目录路径>/"
```
### 10. 重建日常使用的本地仓库
回到原来的仓库位置,从远端重新 clone:
```powershell
cd "<原仓库的上级目录>"
git clone <远端地址> "<原仓库文件夹名>"
```
### 11. 复制回本地私有目录
从 old 备份中,把本地要保留但不提交的目录复制回新仓库:
```text
<旧仓库备份路径>/<目录路径>
复制到
<原仓库路径>/<目录路径>
```
### 12. 最终验证
进入新仓库:
```powershell
cd "<原仓库路径>"
git status
git check-ignore -v --no-index -- "<目录路径>/任意测试文件.md"
git log --all -- "<目录路径>/"
```
理想结果:
```text
git status 没有异常改动
git check-ignore 能看到 .gitignore 命中规则
git log 没有输出
```
## 常见问题
### filter-repo 不是 Git 命令
报错:
```text
git: 'filter-repo' is not a git command
```
说明还没有安装 `git-filter-repo`
可以尝试:
```powershell
python -m pip install git-filter-repo
```
### push 被拒绝 stale info
如果强推时报:
```text
! [rejected] <分支名> -> <分支名> (stale info)
```
通常是因为本地没有最新的 `origin/<分支名>` 信息。
先执行:
```powershell
git fetch origin
git push --force-with-lease origin <分支名>
```
### .gitignore 不会影响已跟踪文件
`.gitignore` 只影响未被跟踪的新文件。
如果某个文件已经被 Git 跟踪,需要取消跟踪:
```powershell
git rm --cached -r -- "<目录路径>"
git commit -m "Stop tracking local-only directory"
git push
```
这只会从 Git 跟踪列表中移除,不会删除本地实际文件。