在新克隆上使用git-filter-repo从git历史记录中删除文件



我按照这个答案从git历史中删除一个包含凭据的文件。我有git 2.35.1和filter repo 22826b5a68b6。我需要的命令显然是:

git-filter-repo --path auth.json --invert-paths

如果我试图将此应用于我的工作回购,我会收到以下错误:

Aborting: Refusing to destructively overwrite repo history since
this does not look like a fresh clone.
(expected freshly packed repo)

所以我用git clone检查了一个新的副本,命令成功运行:

Parsed 861 commits
New history written in 0.69 seconds; now repacking/cleaning...
Repacking your repo and cleaning out old unneeded objects
HEAD is now at 7212384 Update app.css
Enumerating objects: 8203, done.
Counting objects: 100% (8203/8203), done.
Delta compression using up to 24 threads
Compressing objects: 100% (2310/2310), done.
Writing objects: 100% (8203/8203), done.
Total 8203 (delta 5630), reused 8196 (delta 5623), pack-reused 0
Completely finished after 2.85 seconds.

我可以看到该文件已被删除。但当我去推送时:

git push --force
fatal: No configured push destination.

由于某种原因,它丢失了从中克隆的远程,所以我手动将其添加回:

git remote add origin git@git.example.com:abc/xyz.git

此操作失败:

fatal: The current branch master has no upstream branch.

所以我加上

git push --set-upstream origin master

但这也失败了:

To git.example.com:abc/xyz.git
! [rejected]        master -> master (fetch first)
error: failed to push some refs to 'git.example.com:abc/xyz.git'
hint: Updates were rejected because the remote contains work that you do
hint: not have locally. This is usually caused by another repository pushing
hint: to the same ref. You may want to first integrate the remote changes
hint: (e.g., 'git pull ...') before pushing again.
hint: See the 'Note about fast-forwards' in 'git push --help' for details.

但我知道,自从检查后,没有任何东西被推到回购中。重复该过程会得到相同的结果。如果我执行git pull来更新它,它就会再次失败,并返回this does not look like a fresh clone错误,就在我开始的地方。

我绕了几圈,最终克服了所有的错误,却发现这一切对我的回购没有任何影响——文件仍然在那里。

因此,我的问题是,要使这个过滤过程在新克隆的repo上工作,我应该采取什么确切的步骤?

你离我们太近了。。。

在上一步中需要git push --force的原因是,您将在远程上销毁提交,并用新的提交替换它们。既然你的遥控器不见了,跳过第一个强制推送命令,然后你只需要在最后一个推送命令中添加力:

git push --set-upstream origin master --force

附带说明:我几乎总是更喜欢使用--force-with-lease而不是--force,因为它稍微安全一点,因为如果有人在您上次提取(或在本例中是克隆(和推送之间向远程分支添加了新的提交(您还没有看到(,则会出错。把他们吹走可能是不礼貌的。使用--force-with-lease时,如果出现错误,只需执行git fetch,查看新提交并决定是否可以删除它们。如果是,则再次使用--force-with-lease,它将起作用(除非在提取后的最后一分钟内再次出现的新提交(。

在这种重新添加远程的特殊情况下,必须先获取,否则--force-with-lease将无法工作。如果是我,如果在克隆到将强制推送重写的repo之间,远程上可能出现新的提交,我可能会考虑这样做。在这种情况下,我会将您的最终命令更改为以下步骤:

git fetch
# inspect origin/master to see if new commits appeared after your clone
git push --set-upstream origin master --force-with-lease

或者,在您的情况下,一旦您决定重写分支,就暂时锁定该分支(或删除对它的权限(,并在强制推送后解锁它。然后你就可以确定,在你完成之前,没有人会添加提交。

TTT的回答起到了帮助作用,特别是关于过滤器回购执行git init的评论——问题出在操作顺序上。在它起作用之前,我做了很多次,我把它变成了一个脚本,以明确需要什么以及按照什么顺序:

#!/usr/bin/env bash
set -xv
git clone git@git.example.com:abc/xyz.git project
cd project
git filter-repo --path auth.json --invert-paths
git remote add origin git@git.example.com:abc/xyz.git
git push --set-upstream origin main --force

完成此操作后,我在更新现有克隆时遇到了很多问题,但通常通过接受远程的所有更改来解决这些问题。

要解决此问题,您需要在运行git-filter-repo之前保留.git/config文件,然后将其恢复到原始状态,例如:

git clone <...> .
cp ./.git/config ../
git filter-repo --invert-paths --path <...>
mv -f ../config ./.git
git push --force --all

最新更新